Skip to content

Commit

Permalink
console over SWD
Browse files Browse the repository at this point in the history
uses customized SEGGER RTT
  • Loading branch information
fanoush committed Aug 8, 2024
1 parent 5a91fc7 commit 205a5df
Show file tree
Hide file tree
Showing 8 changed files with 2,887 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,12 @@ ifeq ($(USE_TERMINAL),1)
WRAPPERSOURCES += libs/graphics/jswrap_terminal.c
endif

ifeq ($(USE_SWDCON),1)
DEFINES += -DUSE_SWDCON
WRAPPERSOURCES += libs/swdcon/jswrap_swdcon.c
# directly included so not needed SOURCES += libs/swdcon/SEGGER_RTT_custom.c
endif

endif

ifeq ($(USE_USB_HID),1)
Expand Down
1 change: 1 addition & 0 deletions boards/BANGLEJS2.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
'CRYPTO','SHA256','SHA512',
'LCD_MEMLCD',
'TENSORFLOW',
# 'SWDCON', RTT console over SWD
'JIT' # JIT compiler enabled
],
'makefile' : [
Expand Down
2,142 changes: 2,142 additions & 0 deletions libs/swdcon/SEGGER_RTT_custom.c

Large diffs are not rendered by default.

511 changes: 511 additions & 0 deletions libs/swdcon/SEGGER_RTT_custom.h

Large diffs are not rendered by default.

183 changes: 183 additions & 0 deletions libs/swdcon/jswrap_swdcon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains JavaScript SWD console
* ----------------------------------------------------------------------------
*/
#include "jsvariterator.h"
#include "jsinteractive.h"

#ifdef NRF5X
#include "app_util_platform.h"
#endif
#ifndef CRITICAL_REGION_ENTER
#define CRITICAL_REGION_ENTER jshInterruptOff
#endif
#ifndef CRITICAL_REGION_EXIT
#define CRITICAL_REGION_EXIT jshInterruptOn
#endif

// "SWDCON RTT" header instead of default "SEGGER RTT"
// #define CUSTOM_RTT_HEADER_BACKWARDS "TTR NOCDWS"

// stuff from removed SEGGER_RTT_Conf.h
#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (1)
#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (1) // Max. number of down-buffers (H->T) available on this target (Default: 3)
#define BUFFER_SIZE_UP (128) // Size of the buffer for terminal output of target, up to host (Default: 1k)
#define BUFFER_SIZE_DOWN (32) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)
#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0)
#define SEGGER_RTT_LOCK() CRITICAL_REGION_ENTER()
#define SEGGER_RTT_UNLOCK() CRITICAL_REGION_EXIT()
//#include "SEGGER_RTT_Conf.h"
#include "SEGGER_RTT_custom.c"

// possibly dynamically allocated from variables?
static char swdconUpBuffer[BUFFER_SIZE_UP];
static char swdconDownBuffer[BUFFER_SIZE_DOWN];
const char swdconBufferName[] ="SWDCON"; // visible in "rtt channels" openocd command, SEGGER default for channel 0 is "Terminal"
// Forward function declarations


// console data structures

#define MODE_OFF 0 // console is off
#define MODE_ON 1 // console is on

static uint8_t srvMode = MODE_OFF; ///< current mode

/*JSON{
"type" : "object",
"name" : "SWDCON",
"instanceof" : "Serial",
"ifdef" : "USE_SWDCON"
}
In memory serial I/O device accessible via SWD debugger.
uses SEGGER RTT so it can be used with openocd and other SEGGER compatible tools.
*/


/*JSON{
"type" : "init",
"generate" : "jswrap_swdcon_init"
}
*/
void jswrap_swdcon_init(void) {
SEGGER_RTT_Init();
SEGGER_RTT_ConfigDownBuffer(0, swdconBufferName, swdconDownBuffer, sizeof(swdconDownBuffer), SEGGER_RTT_MODE_DEFAULT);
SEGGER_RTT_ConfigUpBuffer(0, swdconBufferName, swdconUpBuffer, sizeof(swdconUpBuffer), SEGGER_RTT_MODE_DEFAULT);
srvMode = MODE_ON; // hardcoded for now
}

/*JSON{
"type" : "kill",
"generate" : "jswrap_swdcon_kill"
}
*/
void jswrap_swdcon_kill(void) {
srvMode = MODE_OFF;
}

/*JSON{
"type" : "idle",
"generate" : "jswrap_swdcon_idle"
}
*/
bool swdconActivate();
bool swdconRecv();

bool jswrap_swdcon_idle(void) {

if (srvMode == MODE_OFF) {
return false;
}

if (SEGGER_RTT_HasKey()) swdconActivate();
bool active = false;
active |= swdconRecv();
// prevent sleep if SWD console is active, we probably have power attached anyway
// sleeping would work if SWD debugger would trigger interrupt after sending data (it does not)
// however it is possible to trigger interrupt in our own SWD RTT host in future
// e.g. triggering TIMER1 interrupt vie writing STIR register wakes nrf52 espruino device
active |= (jsiGetConsoleDevice() == EV_SWDCON);
return active;
}

//===== Internal functions
bool wasForced=false;
IOEventFlags oldConsole = EV_NONE;
// on Bangle 2 looks like console is always forced to something (bluetooth or null)
// setting to non-programmable forces console to null in .boot0
// allow to override this case
#define shouldOverride (console == EV_NONE)

bool swdconActivate() {
// if the console is not already us, then change it
IOEventFlags console = jsiGetConsoleDevice();
if (console != EV_SWDCON) {
if (!jsiIsConsoleDeviceForced()) {
jsiSetConsoleDevice(EV_SWDCON, false);
//jshHadEvent();
wasForced=false;
} else {
if (shouldOverride){
wasForced=true;
oldConsole=console;
jsiSetConsoleDevice(EV_SWDCON, true);
}
}
}
return true;
}

// Close the connection and release the console device
void swdconRelease() {
IOEventFlags console = jsiGetConsoleDevice();
// only switch away if the current console is us
if (console == EV_SWDCON){
if (wasForced){
jsiSetConsoleDevice(oldConsole, true); // restore previos forced one back
wasForced=false;
} else {
jsiSetConsoleDevice(jsiGetPreferredConsoleDevice(), false);
}
}
}

void swdconSendChar(char ch) {
if (srvMode == MODE_OFF) return;
int timeout = WAIT_UNTIL_N_CYCLES;
while (SEGGER_RTT_GetAvailWriteSpace(0)==0){
// same handling as in jshTransmit
if (jshIsInInterrupt()) {
// if we're printing from an IRQ, don't wait - it's unlikely TX will ever finish
jsErrorFlags |= JSERR_BUFFER_FULL;
return;
}
jshBusyIdle();
if (--timeout == 0) {
// try to switch away if buffer is full and nobody is reading
jsiStatus |= JSIS_ECHO_OFF_FOR_LINE; // we are full, no space for "<-" when switching
swdconRelease();
return;
}
}
SEGGER_RTT_PutChar(0,ch);
}

bool swdconRecv() {
bool gotChar=false;
char c;
while(SEGGER_RTT_Read(0, &c, 1) > 0){
jshPushIOCharEvent(EV_SWDCON, c);
gotChar=true;
}
if (gotChar) jshHadEvent();
return gotChar;
}
28 changes: 28 additions & 0 deletions libs/swdcon/jswrap_swdcon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Thorsten von Eicken
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* Contains JavaScript HTTP Functions
* ----------------------------------------------------------------------------
*/
#ifndef LIBS_SWDCON_H_
#define LIBS_SWDCON_H_

#include "jsvar.h"

void jswrap_swdcon_setOptions(JsVar *options);

void jswrap_swdcon_init(void);
void jswrap_swdcon_kill(void);

// Listen, accept, send, and recv on telnet console connections. Returns true if something
// was done.
bool jswrap_swdcon_idle(void);

#endif
13 changes: 13 additions & 0 deletions src/jsdevices.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,13 @@ void jshTransmit(
return;
}
#endif
#ifdef USE_SWDCON
if (device==EV_SWDCON) {
extern void swdconSendChar(char c);
swdconSendChar((char)data);
return;
}
#endif
#ifndef LINUX
#ifdef USB
if (device==EV_USBSERIAL && !jshIsUSBSERIALConnected()) {
Expand Down Expand Up @@ -613,6 +620,9 @@ const char *jshGetDeviceString(
#ifdef USE_TELNET
case EV_TELNET: return "Telnet";
#endif
#ifdef USE_SWDCON
case EV_SWDCON: return "SWDCON";
#endif
#ifdef USE_TERMINAL
case EV_TERMINAL: return "Terminal";
#endif
Expand Down Expand Up @@ -686,6 +696,9 @@ IOEventFlags jshFromDeviceString(
#endif
}
else if (device[0]=='S') {
#ifdef USE_SWDCON
if (strcmp(&device[1], "WDCON")==0) return EV_SWDCON;
#endif
#if ESPR_USART_COUNT>0
if (device[1]=='e' && device[2]=='r' && device[3]=='i' && device[4]=='a' && device[5]=='l' &&
device[6]>='1' && (device[6]-'1')<ESPR_USART_COUNT &&
Expand Down
3 changes: 3 additions & 0 deletions src/jsdevices.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ typedef enum {
#ifdef USE_TELNET
EV_TELNET,
#endif
#ifdef USE_SWDCON
EV_SWDCON, /// console over in memory buffer accessible via SWD
#endif
#ifdef USE_TERMINAL
EV_TERMINAL, // Built-in VT100 terminal
#endif
Expand Down

0 comments on commit 205a5df

Please sign in to comment.