From 773381b08b6788fa1ea567e240a51482c63c3a00 Mon Sep 17 00:00:00 2001 From: cnlohr <lohr85@gmail.com> Date: Wed, 21 Jun 2023 06:38:06 -0400 Subject: [PATCH] Add standard input through the debug printf module. Closes #168 --- ch32v003fun/ch32v003fun.c | 45 ++++++++++++++++++++-- ch32v003fun/ch32v003fun.h | 6 +++ examples/debugprintfdemo/debugprintfdemo.c | 15 +++++++- minichlink/minichlink.c | 42 +++++++++++++++----- 4 files changed, 94 insertions(+), 14 deletions(-) diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c index 78fae9b..d030306 100644 --- a/ch32v003fun/ch32v003fun.c +++ b/ch32v003fun/ch32v003fun.c @@ -917,24 +917,61 @@ int putchar(int c) } #else + +void handle_debug_input( int numbytes, uint8_t * data ) __attribute__((weak)); +void handle_debug_input( int numbytes, uint8_t * data ) { } + +static void internal_handle_input( uint32_t * dmdata0 ) +{ + uint32_t dmd0 = *dmdata0; + int bytes = (dmd0 & 0x3f) - 4; + if( bytes > 0 ) + { + handle_debug_input( bytes, ((uint8_t*)dmdata0) + 1 ); + } +} + + +void poll_input() +{ + uint32_t lastdmd = (*DMDATA0); + if( !(lastdmd & 0x80) ) + { + internal_handle_input( (uint32_t*)DMDATA0 ); + *DMDATA0 = 0x84; // Negative + } +} + + // MSB .... LSB // DMDATA0: char3 char2 char1 [status word] // where [status word] is: // b7 = is a "printf" waiting? -// b0..b3 = # of bytes in printf (+4). (4 or higher indicates a print of some kind) +// b0..b3 = # of bytes in printf (+4). (5 or higher indicates a print of some kind) +// note: if b7 is 0 in reply, but b0..b3 have >=4 then we received data from host. int _write(int fd, const char *buf, int size) { char buffer[4] = { 0 }; int place = 0; + uint32_t lastdmd; uint32_t timeout = 160000; // Give up after ~40ms + if( size == 0 ) + { + // Simply seeking input. + lastdmd = (*DMDATA0); + if( lastdmd ) internal_handle_input( (uint32_t*)DMDATA0 ); + } while( place < size ) { int tosend = size - place; if( tosend > 7 ) tosend = 7; - while( ((*DMDATA0) & 0x80) ) + while( ( lastdmd = (*DMDATA0) ) & 0x80 ) if( timeout-- == 0 ) return place; + + if( lastdmd ) internal_handle_input( (uint32_t*)DMDATA0 ); + timeout = 160000; int t = 3; @@ -963,7 +1000,9 @@ int _write(int fd, const char *buf, int size) int putchar(int c) { int timeout = 16000; - while( ((*DMDATA0) & 0x80) ) if( timeout-- == 0 ) return 0; + uint32_t lastdmd = 0; + while( (lastdmd = (*DMDATA0)) & 0x80 ) if( timeout-- == 0 ) return 0; + if( lastdmd ) internal_handle_input( (uint32_t*)DMDATA0 ); *DMDATA0 = 0x85 | ((const char)c<<8); return 1; } diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h index c6ccd39..b65a5a2 100644 --- a/ch32v003fun/ch32v003fun.h +++ b/ch32v003fun/ch32v003fun.h @@ -5080,6 +5080,12 @@ void WaitForDebuggerToAttach(); // Just a definition to the internal _write function. int _write(int fd, const char *buf, int size); +// Call this to busy-wait the polling of input. +void poll_input(); + +// Receiving bytes from host. Override if you wish. +void handle_debug_input( int numbytes, uint8_t * data ); + #endif // xw_ext.inc, thanks to @macyler, @jnk0le, @duk for this reverse engineering. diff --git a/examples/debugprintfdemo/debugprintfdemo.c b/examples/debugprintfdemo/debugprintfdemo.c index 41a153b..df41951 100644 --- a/examples/debugprintfdemo/debugprintfdemo.c +++ b/examples/debugprintfdemo/debugprintfdemo.c @@ -1,11 +1,19 @@ /* Small example showing how to use the SWIO programming pin to do printf through the debug interface */ +#define SYSTEM_CORE_CLOCK 48000000 #include "ch32v003fun.h" #include <stdio.h> uint32_t count; +int last = 0; +void handle_debug_input( int numbytes, uint8_t * data ) +{ + last = data[0]; + count += numbytes; +} + int main() { SystemInit48HSI(); @@ -31,9 +39,14 @@ int main() GPIOD->BSHR = 1 | (1<<4); // Turn on GPIOs GPIOC->BSHR = 1; printf( "+%lu\n", count++ ); + Delay_Ms(100); + int i; + for( i = 0; i < 10000; i++ ) + poll_input(); GPIOD->BSHR = (1<<16) | (1<<(16+4)); // Turn off GPIODs GPIOC->BSHR = (1<<16); - printf( "-%lu\n", count++ ); + printf( "-%lu[%c]\n", count++, last ); + Delay_Ms(100); } } diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c index d3f1a01..7b756d2 100644 --- a/minichlink/minichlink.c +++ b/minichlink/minichlink.c @@ -9,6 +9,7 @@ #include <string.h> #include <stdlib.h> #include <getopt.h> +#include "terminalhelp.h" #include "minichlink.h" #include "../ch32v003fun/ch32v003fun.h" @@ -296,20 +297,42 @@ keep_going: MCF.HaltMode( dev, 2 ); } + CaptureKeyboardInput(); + + uint32_t appendword = 0; do { uint8_t buffer[256]; if( !IsGDBServerInShadowHaltState( dev ) ) { - int r = MCF.PollTerminal( dev, buffer, sizeof( buffer ), 0, 0 ); - if( r < 0 ) + // Handle keyboard input. + if( appendword == 0 ) + { + int i; + for( i = 0; i < 3; i++ ) + { + if( !IsKBHit() ) break; + appendword |= ReadKBByte() << (i*8+8); + } + appendword |= i+4; // Will go into DATA0. + } + int r = MCF.PollTerminal( dev, buffer, sizeof( buffer ), appendword, 0 ); + if( r == -1 ) + { + // Other end ack'd without printf. + appendword = 0; + } + else if( r < 0 ) { fprintf( stderr, "Terminal dead. code %d\n", r ); return -32; } - if( r > 0 ) + else if( r > 0 ) { - fwrite( buffer, r, 1, stdout ); + fwrite( buffer, r, 1, stdout ); + fflush( stdout ); + // Otherwise it's basically just an ack for appendword. + appendword = 0; } } @@ -1644,14 +1667,14 @@ static int DefaultHaltMode( void * dev, int mode ) return 0; } -// Returns positive if received text. +// Returns positive if received text, or request for input. +// Returns -1 if nothing was printed but received data. // Returns negative if error. // Returns 0 if no text waiting. // maxlen MUST be at least 8 characters. We null terminate. int DefaultPollTerminal( void * dev, uint8_t * buffer, int maxlen, uint32_t leaveflagA, int leaveflagB ) { struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); - int r; uint32_t rr; if( iss->statetag != STTAG( "TERM" ) ) @@ -1667,9 +1690,7 @@ int DefaultPollTerminal( void * dev, uint8_t * buffer, int maxlen, uint32_t leav // bit 7 = host-acknowledge. if( rr & 0x80 ) { - int ret = 0; int num_printf_chars = (rr & 0xf)-4; - if( num_printf_chars > 0 && num_printf_chars <= 7) { if( num_printf_chars > 3 ) @@ -1682,11 +1703,12 @@ int DefaultPollTerminal( void * dev, uint8_t * buffer, int maxlen, uint32_t leav if( firstrem > 3 ) firstrem = 3; memcpy( buffer, ((uint8_t*)&rr)+1, firstrem ); buffer[num_printf_chars] = 0; - ret = num_printf_chars; } if( leaveflagA ) MCF.WriteReg32( dev, DMDATA1, leaveflagB ); MCF.WriteReg32( dev, DMDATA0, leaveflagA ); // Write that we acknowledge the data. - return ret; + if( num_printf_chars == 0 ) return -1; // was acked? + if( num_printf_chars < 0 ) num_printf_chars = 0; + return num_printf_chars; } else { -- GitLab