Skip to content

Commit 33a21cd

Browse files
Add architecture comments, cleanup uart.c code
Comments added to UART.c trying to explain (as best as I understand it) the changes done to support GDB and how they interact with standard operation. Fix the uart_uninit to stop the ISR and then free appropriately. Fix uart_isr_handle_data (GDB's shim for sending chars to the 8266 app) to do the exact same thing as the standard UART handler including set the overflow properly and either discard or overwrite in that case. Fix serial reception when GDB enabled by enabling the user recv ISR. Remove commented attributes from gdbstub, leftover from the move to flash. General logic cleanup per comments in the PR.
1 parent fc7012f commit 33a21cd

File tree

2 files changed

+85
-33
lines changed

2 files changed

+85
-33
lines changed

cores/esp8266/uart.c

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,29 @@
4747
#include "user_interface.h"
4848
#include "uart_register.h"
4949

50-
//const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
50+
/*
51+
Some general architecture for GDB integration with the UART to enable
52+
serial debugging.
53+
54+
UART1 is transmit only and can never be used by GDB.
55+
56+
When gdbstub_has_uart_isr_control() (only true in the case GDB is enabled),
57+
UART0 needs to be under the control of the GDB stub for enable/disable/irq
58+
(but speed, parity, etc. still alllowable). Basically, GDB needs to make
59+
sure that UART0 is never really disabled.
60+
61+
GDB sets up UART0 with a fifo and a 2-character timeout during init. This
62+
is required to ensure that GDBStub can check every character coming in, even
63+
if it is not read by the user app or if the commands don't hit the FIFO
64+
interrupt level. It checks every character that comes in, and if GDB isn't
65+
active just passes them to the user RAM FIFO unless it's a Ctrl-C (0x03).
66+
67+
GDBStub doesn't care about the struct uart_*, and allocating it or freeing
68+
it has no effect (so you can do Serial.end() and free the uart...but as
69+
mentioned above even if you Serial.end, the actual UART0 HW will still be
70+
kept running to enable GDB to do commands.
71+
*/
72+
5173
static int s_uart_debug_nr = UART0;
5274

5375

@@ -250,17 +272,41 @@ uart_read(uart_t* uart, char* userbuffer, size_t usersize)
250272
return ret;
251273
}
252274

275+
// When GDB is running, this is called one byte at a time to stuff the user FIFO
276+
// instead of the uart_isr...uart_rx_copy_fifo_to_buffer_unsafe()
277+
// Since we've already read the bytes from the FIFO, can't use that
278+
// function directly and need to implement it bytewise here
253279
static void ICACHE_RAM_ATTR uart_isr_handle_data(void* arg, uint8_t data)
254280
{
255281
uart_t* uart = (uart_t*)arg;
256282
if(uart == NULL || !uart->rx_enabled) {
257283
return;
258284
}
259-
size_t nextPos = (uart->rx_buffer->wpos + 1) % uart->rx_buffer->size;
260-
if(nextPos != uart->rx_buffer->rpos) {
261-
uart->rx_buffer->buffer[uart->rx_buffer->wpos] = data;
262-
uart->rx_buffer->wpos = nextPos;
285+
286+
// Copy all the rx fifo bytes that fit into the rx buffer
287+
// called by ISR
288+
struct uart_rx_buffer_ *rx_buffer = uart->rx_buffer;
289+
290+
size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
291+
if(nextPos == rx_buffer->rpos)
292+
{
293+
uart->rx_overrun = true;
294+
//os_printf_plus(overrun_str);
295+
296+
// a choice has to be made here,
297+
// do we discard newest or oldest data?
298+
#ifdef UART_DISCARD_NEWEST
299+
// discard newest data
300+
// Stop copying if rx buffer is full
301+
return;
302+
#else
303+
// discard oldest data
304+
if (++rx_buffer->rpos == rx_buffer->size)
305+
rx_buffer->rpos = 0;
306+
#endif
263307
}
308+
rx_buffer->buffer[rx_buffer->wpos] = data;
309+
rx_buffer->wpos = nextPos;
264310
}
265311

266312
size_t
@@ -299,7 +345,7 @@ uart_get_rx_buffer_size(uart_t* uart)
299345
return uart && uart->rx_enabled? uart->rx_buffer->size: 0;
300346
}
301347

302-
348+
// The default ISR handler called when GDB is not enabled
303349
void ICACHE_RAM_ATTR
304350
uart_isr(void * arg)
305351
{
@@ -576,6 +622,7 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
576622
uart->tx_pin = (uart->tx_enabled)?2:255; // GPIO7 as TX not possible! See GPIO pins used by UART
577623
if(uart->tx_enabled)
578624
pinMode(uart->tx_pin, SPECIAL);
625+
579626
break;
580627

581628
case UART_NO:
@@ -595,11 +642,11 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
595642
USIE(uart->uart_nr) = 0;
596643
}
597644
if(uart->uart_nr == UART0) {
598-
if(uart->rx_enabled && !gdbstub_has_uart_isr_control()) {
645+
if(uart->rx_enabled) {
599646
uart_start_isr(uart);
600647
}
601648
if(gdbstub_has_uart_isr_control()) {
602-
ETS_UART_INTR_ENABLE();
649+
ETS_UART_INTR_ENABLE(); // Undo the disable in the switch() above
603650
}
604651
}
605652

@@ -612,6 +659,8 @@ uart_uninit(uart_t* uart)
612659
if(uart == NULL)
613660
return;
614661

662+
uart_stop_isr(uart);
663+
615664
if(uart->tx_enabled && (!gdbstub_has_uart_isr_control() || uart->uart_nr != UART0)) {
616665
switch(uart->tx_pin)
617666
{
@@ -640,7 +689,6 @@ uart_uninit(uart_t* uart)
640689
pinMode(13, INPUT);
641690
break;
642691
}
643-
uart_stop_isr(uart);
644692
}
645693
}
646694
free(uart);
@@ -852,11 +900,15 @@ uart_set_debug(int uart_nr)
852900
func = &uart_ignore_char;
853901
break;
854902
}
855-
if(!gdbstub_has_putc1_control()) {
856-
system_set_os_print((uint8)((uart_nr == UART0 || uart_nr == UART1)?1:0));
857-
ets_install_putc1((void *) func);
858-
} else {
903+
if(gdbstub_has_putc1_control()) {
859904
gdbstub_set_putc1_callback(func);
905+
} else {
906+
if (uart_nr == UART0 || uart_nr == UART1) {
907+
system_set_os_print(1);
908+
} else {
909+
system_set_os_print(0);
910+
}
911+
ets_install_putc1((void *) func);
860912
}
861913
}
862914

libraries/GDBStub/src/internal/gdbstub.c

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ static void ATTR_GDBFN keepWDTalive() {
138138
//of the hex string, as far as the routine has read into it. Bits/4 indicates
139139
//the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much
140140
//hex chars as possible.
141-
static long /*ATTR_GDBFN*/ gdbGetHexVal(unsigned char **ptr, int bits) {
141+
static long gdbGetHexVal(unsigned char **ptr, int bits) {
142142
int i;
143143
int no;
144144
unsigned int v = 0;
@@ -176,22 +176,22 @@ static long /*ATTR_GDBFN*/ gdbGetHexVal(unsigned char **ptr, int bits) {
176176
}
177177

178178
//Swap an int into the form gdb wants it
179-
static int /*ATTR_GDBFN*/ iswap(int i) {
179+
static int iswap(int i) {
180180
return ((i >> 24) & 0xff)
181181
| (((i >> 16) & 0xff) << 8)
182182
| (((i >> 8) & 0xff) << 16)
183183
| (((i >> 0) & 0xff) << 24);
184184
}
185185

186186
//Read a byte from the ESP8266 memory.
187-
static unsigned char /*ATTR_GDBFN*/ readbyte(unsigned int p) {
187+
static unsigned char readbyte(unsigned int p) {
188188
if (p < 0x20000000 || p >= 0x60000000) return -1;
189189
int *i = (int*)(p & ~3);
190190
return *i >> ((p & 3) * 8);
191191
}
192192

193193
//Write a byte to the ESP8266 memory.
194-
static void /*ATTR_GDBFN*/ writeByte(unsigned int p, unsigned char d) {
194+
static void writeByte(unsigned int p, unsigned char d) {
195195
if (p < 0x20000000 || p >= 0x60000000) return;
196196
int *i = (int*)(p & ~3);
197197
if ((p & 3) == 0) *i = (*i & 0xffffff00) | (d << 0);
@@ -201,7 +201,7 @@ static void /*ATTR_GDBFN*/ writeByte(unsigned int p, unsigned char d) {
201201
}
202202

203203
//Returns 1 if it makes sense to write to addr p
204-
static int /*ATTR_GDBFN*/ validWrAddr(int p) {
204+
static int validWrAddr(int p) {
205205
return (p >= 0x3ff00000 && p < 0x40000000)
206206
|| (p >= 0x40100000 && p < 0x40140000)
207207
|| (p >= 0x60000000 && p < 0x60002000);
@@ -217,29 +217,29 @@ static inline bool ATTR_GDBFN gdbTxFifoIsFull() {
217217
}
218218

219219
//Receive a char from the uart. Uses polling and feeds the watchdog.
220-
static inline int /*ATTR_GDBFN*/ gdbRecvChar() {
220+
static inline int gdbRecvChar() {
221221
while (gdbRxFifoIsEmpty()) {
222222
keepWDTalive();
223223
}
224224
return READ_PERI_REG(UART_FIFO(0));
225225
}
226226

227227
//Send a char to the uart.
228-
static void /*ATTR_GDBFN*/ gdbSendChar(char c) {
228+
static void gdbSendChar(char c) {
229229
while (gdbTxFifoIsFull())
230230
;
231231
WRITE_PERI_REG(UART_FIFO(0), c);
232232
}
233233

234234

235235
//Send the start of a packet; reset checksum calculation.
236-
static void /*ATTR_GDBFN*/ gdbPacketStart() {
236+
static void gdbPacketStart() {
237237
chsum = 0;
238238
gdbSendChar('$');
239239
}
240240

241241
//Send a char as part of a packet
242-
static void /*ATTR_GDBFN*/ gdbPacketChar(char c) {
242+
static void gdbPacketChar(char c) {
243243
if (c == '#' || c == '$' || c == '}' || c == '*') {
244244
gdbSendChar('}');
245245
chsum += '}';
@@ -250,7 +250,7 @@ static void /*ATTR_GDBFN*/ gdbPacketChar(char c) {
250250
}
251251

252252
//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent.
253-
static void /*ATTR_GDBFN*/ gdbPacketHex(int val, int bits) {
253+
static void gdbPacketHex(int val, int bits) {
254254
static const char hexChars[] = "0123456789abcdef";
255255
int i;
256256
for (i = bits; i > 0; i -= 4) {
@@ -259,24 +259,24 @@ static void /*ATTR_GDBFN*/ gdbPacketHex(int val, int bits) {
259259
}
260260

261261
//Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent.
262-
static void /*ATTR_GDBFN*/ gdbPacketSwappedHexInt(int val) {
262+
static void gdbPacketSwappedHexInt(int val) {
263263
gdbPacketHex(iswap(val), 32);
264264
}
265265

266-
static void /*ATTR_GDBFN*/ gdbPacketXXXXInt() {
266+
static void gdbPacketXXXXInt() {
267267
for (int i=0; i<8; i++) gdbPacketChar('x');
268268
}
269269

270270
//Finish sending a packet.
271-
static void /*ATTR_GDBFN*/ gdbPacketEnd() {
271+
static void gdbPacketEnd() {
272272
gdbSendChar('#');
273273
//Ok to use packet version here since hex char can never be an
274274
//excape-requiring character
275275
gdbPacketHex(chsum, 8);
276276
}
277277

278278
// Send a complete packet containing str
279-
static void /*ATTR_GDBFN*/ gdbSendPacketStr(const char *c) {
279+
static void gdbSendPacketStr(const char *c) {
280280
gdbPacketStart();
281281
while (*c != 0) {
282282
gdbPacketChar(*c);
@@ -303,13 +303,13 @@ static inline void ATTR_GDBEXTERNFN gdbSendOutputPacketChar(unsigned char c) {
303303
gdbPacketEnd();
304304
}
305305

306-
static long /*ATTR_GDBFN*/ gdbGetSwappedHexInt(unsigned char **ptr) {
306+
static long gdbGetSwappedHexInt(unsigned char **ptr) {
307307
return iswap(gdbGetHexVal(ptr, 32));
308308
}
309309

310310

311311
//Send the reason execution is stopped to GDB.
312-
static void /*ATTR_GDBFN*/ sendReason() {
312+
static void sendReason() {
313313
static const char exceptionSignal[] = {4,31,11,11,2,6,8,0,6,7,0,0,7,7,7,7};
314314
#if 0
315315
char *reason=""; //default
@@ -400,7 +400,7 @@ struct regfile {
400400
*/
401401

402402
//Handle a command as received from GDB.
403-
static inline int /*ATTR_GDBFN*/ gdbHandleCommand() {
403+
static inline int gdbHandleCommand() {
404404
//Handle a command
405405
int i, j, k;
406406
unsigned char *data = cmd + 1;
@@ -537,7 +537,7 @@ static inline int /*ATTR_GDBFN*/ gdbHandleCommand() {
537537
//It is not necessary for gdb to be attached for it to be paused
538538
//For example, during an exception break, the program is
539539
// paused but gdb might not be attached yet
540-
static int /*ATTR_GDBFN*/ gdbReadCommand() {
540+
static int gdbReadCommand() {
541541
unsigned char chsum;
542542
unsigned char sentchs[2];
543543
size_t p;
@@ -606,7 +606,7 @@ static inline void ATTR_GDBFN setaregval(int reg, unsigned int val) {
606606
}
607607

608608
//Emulate the l32i/s32i instruction we're stopped at.
609-
static inline void /*ATTR_GDBFN*/ emulLdSt() {
609+
static inline void emulLdSt() {
610610
unsigned char i0 = readbyte(gdbstub_savedRegs.pc);
611611
unsigned char i1 = readbyte(gdbstub_savedRegs.pc + 1);
612612
unsigned char i2;
@@ -682,7 +682,7 @@ static void __attribute__((noinline)) gdbstub_handle_debug_exception_flash() {
682682
#if GDBSTUB_BREAK_ON_EXCEPTION || GDBSTUB_CTRLC_BREAK
683683

684684
#if !GDBSTUB_FREERTOS
685-
static inline int /*ATTR_GDBFN*/ gdbReadCommandWithFrame(void* frame) {
685+
static inline int gdbReadCommandWithFrame(void* frame) {
686686
//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
687687
os_memcpy(&gdbstub_savedRegs, frame, 5 * 4);
688688
os_memcpy(&gdbstub_savedRegs.a[2], ((uint32_t*)frame) + 5, 14 * 4);

0 commit comments

Comments
 (0)