diff --git a/F3:F303/Multistepper/Readme.md b/F3:F303/Multistepper/Readme.md index 82939a6..f7789f9 100644 --- a/F3:F303/Multistepper/Readme.md +++ b/F3:F303/Multistepper/Readme.md @@ -390,6 +390,8 @@ Dump command codes. Returns all list of CAN bus command codes. ### dumpconf Dump current configuration. Returns a lot of information both common (like CAN bus speed, ID and so on) and for each motor driver. You can call independeng getters for each of this parameter. +### dumpmotN +Dump configuration of Nth motor only. ### dumpmotflags Dump motor flags' bits (for `motflagsN`) and reaction to limit switches (`eswreact`) values: diff --git a/F3:F303/Multistepper/can.h b/F3:F303/Multistepper/can.h index fa09df4..feb3556 100644 --- a/F3:F303/Multistepper/can.h +++ b/F3:F303/Multistepper/can.h @@ -20,8 +20,8 @@ #include -// amount of filter banks in STM32F0 -#define STM32F0FBANKNO 28 +// amount of filter banks in STM32F +#define STM32FBANKNO 28 // flood period in milliseconds #define FLOOD_PERIOD_MS 5 diff --git a/F3:F303/Multistepper/flash.c b/F3:F303/Multistepper/flash.c index 0553832..f6afdf3 100644 --- a/F3:F303/Multistepper/flash.c +++ b/F3:F303/Multistepper/flash.c @@ -200,6 +200,33 @@ int erase_storage(int npage){ return ret; } +int fn_dumpmot(uint32_t _U_ hash, char _U_ *args){ // "dumpmot" (1224122507) + if(!args || !*args) return RET_WRONGCMD; + uint32_t i; + const char *eq = getnum(args, &i); + if(eq == args || i > STP_STATE_AMOUNT) return RET_WRONGCMD; + char cur = '0' + i; +#define PROPNAME(nm) do{newline(); USB_sendstr(nm); USB_putbyte(cur); USB_putbyte('=');}while(0) + USB_sendstr("microsteps"); USB_putbyte(cur); USB_putbyte('='); + printu(the_conf.microsteps[i]); + PROPNAME("accel"); + printu(the_conf.accel[i]); + PROPNAME("maxspeed"); + printu(the_conf.maxspd[i]); + PROPNAME("minspeed"); + printu(the_conf.minspd[i]); + PROPNAME("maxsteps"); + printu(the_conf.maxsteps[i]); + PROPNAME("motcurrent"); + printu(the_conf.motcurrent[i]); + PROPNAME("motflags"); + printuhex(*((uint8_t*)&the_conf.motflags[i])); + PROPNAME("eswreact"); + printu(the_conf.ESW_reaction[i]); +#undef PROPNAME + newline(); + return RET_GOOD; +} int fn_dumpconf(uint32_t _U_ hash, char _U_ *args){ // "dumpconf" (3271513185) #ifdef EBUG @@ -212,28 +239,12 @@ int fn_dumpconf(uint32_t _U_ hash, char _U_ *args){ // "dumpconf" (3271513185) USB_sendstr("\nuserconf_sz="); printu(the_conf.userconf_sz); USB_sendstr("\ncanspeed="); printu(the_conf.CANspeed); USB_sendstr("\ncanid="); printu(the_conf.CANID); + newline(); + char x[2] = {0}; // motors' data for(int i = 0; i < MOTORSNO; ++i){ - char cur = '0' + i; -#define PROPNAME(nm) do{newline(); USB_sendstr(nm); USB_putbyte(cur); USB_putbyte('=');}while(0) - PROPNAME("microsteps"); - printu(the_conf.microsteps[i]); - PROPNAME("accel"); - printu(the_conf.accel[i]); - PROPNAME("maxspeed"); - printu(the_conf.maxspd[i]); - PROPNAME("minspeed"); - printu(the_conf.minspd[i]); - PROPNAME("maxsteps"); - printu(the_conf.maxsteps[i]); - PROPNAME("motcurrent"); - printu(the_conf.motcurrent[i]); - PROPNAME("motflags"); - printuhex(*((uint8_t*)&the_conf.motflags[i])); - PROPNAME("eswreact"); - printu(the_conf.ESW_reaction[i]); -#undef PROPNAME + x[0] = '0' + i; + fn_dumpmot(0, x); } - newline(); return RET_GOOD; } diff --git a/F3:F303/Multistepper/hashgen/hdr.c b/F3:F303/Multistepper/hashgen/hdr.c index b3a39ba..e4f5cf5 100644 --- a/F3:F303/Multistepper/hashgen/hdr.c +++ b/F3:F303/Multistepper/hashgen/hdr.c @@ -56,6 +56,8 @@ int fn_dumpconf(uint32_t _U_ hash, char _U_ *args) WAL; // "dumpconf" (327151318 int fn_dumperr(uint32_t _U_ hash, char _U_ *args) WAL; // "dumperr" (1223989764) +int fn_dumpmot(uint32_t _U_ hash, char _U_ *args) WAL; // "dumpmot" (1224122507) + int fn_dumpmotflags(uint32_t _U_ hash, char _U_ *args) WAL; // "dumpmotflags" (36159640) int fn_dumpstates(uint32_t _U_ hash, char _U_ *args) WAL; // "dumpstates" (4235564367) @@ -216,6 +218,9 @@ int parsecmd(const char *str){ case CMD_DUMPERR: return fn_dumperr(h, args); break; + case CMD_DUMPMOT: + return fn_dumpmot(h, args); + break; case CMD_DUMPMOTFLAGS: return fn_dumpmotflags(h, args); break; diff --git a/F3:F303/Multistepper/hashgen/hdr.h b/F3:F303/Multistepper/hashgen/hdr.h index 1bd8555..99831e3 100644 --- a/F3:F303/Multistepper/hashgen/hdr.h +++ b/F3:F303/Multistepper/hashgen/hdr.h @@ -38,6 +38,7 @@ extern char lastcmd[]; #define CMD_DUMPCMD (1223955823) #define CMD_DUMPCONF (3271513185) #define CMD_DUMPERR (1223989764) +#define CMD_DUMPMOT (1224122507) #define CMD_DUMPMOTFLAGS (36159640) #define CMD_DUMPSTATES (4235564367) #define CMD_EMSTOP (2965919005) diff --git a/F3:F303/Multistepper/hashgen/helpcmds.in b/F3:F303/Multistepper/hashgen/helpcmds.in index 23e2d78..4a90b0e 100644 --- a/F3:F303/Multistepper/hashgen/helpcmds.in +++ b/F3:F303/Multistepper/hashgen/helpcmds.in @@ -20,6 +20,7 @@ "dumperr - dump error codes\n" "dumpcmd - dump command codes\n" "dumpconf - dump current configuration\n" + "dumpmotN - dump Nth motor configuration\n" "dumpmotflags - dump motor flags' bits\n" "dumpstates - dump motors' state codes\n" "emstop[N] - emergency stop motor N or all\n" diff --git a/F3:F303/Multistepper/hashgen/test b/F3:F303/Multistepper/hashgen/test deleted file mode 100755 index 8fae8fc..0000000 Binary files a/F3:F303/Multistepper/hashgen/test and /dev/null differ diff --git a/F3:F303/Multistepper/hashgen/testdic b/F3:F303/Multistepper/hashgen/testdic index 0fe640b..530ceb7 100644 --- a/F3:F303/Multistepper/hashgen/testdic +++ b/F3:F303/Multistepper/hashgen/testdic @@ -20,6 +20,7 @@ drvtype dumperr dumpcmd dumpconf +dumpmot dumpmotflags dumpstates emstop diff --git a/F3:F303/Multistepper/main.c b/F3:F303/Multistepper/main.c index e76ddcb..04d2427 100644 --- a/F3:F303/Multistepper/main.c +++ b/F3:F303/Multistepper/main.c @@ -45,11 +45,11 @@ int main(void){ hw_setup(); // GPIO, ADC, timers, watchdog etc. USBPU_OFF(); // make a reconnection flashstorage_init(); - init_steppers(); USB_setup(); CAN_setup(the_conf.CANspeed); adc_setup(); pdnuart_setup(); + init_steppers(); USBPU_ON(); uint32_t ctr = 0; CAN_message *can_mesg; @@ -60,10 +60,9 @@ int main(void){ LED_blink(); } CAN_proc(); - USB_proc(); // TODO: remove deprecated trash code! process_steppers(); if(CAN_get_status() == CAN_FIFO_OVERRUN){ - USB_sendstr("CAN bus fifo overrun occured!\n"); + USB_sendstr("CAN_FIFO_OVERRUN\n"); } while((can_mesg = CAN_messagebuf_pop())){ if(can_mesg && isgood(can_mesg->ID)){ @@ -82,8 +81,13 @@ int main(void){ } } int l = USB_receivestr(inbuff, MAXSTRLEN); - if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n"); + if(l < 0) USB_sendstr("USB_BUF_OVERFLOW\n"); else if(l){ +#ifdef EBUG + USB_sendstr("USB GOT:\n"); + USB_sendstr(inbuff); + USB_sendstr("\n--------\n"); +#endif const char *ans = cmd_parser(inbuff); if(ans) USB_sendstr(ans); } diff --git a/F3:F303/Multistepper/multistepper.bin b/F3:F303/Multistepper/multistepper.bin index 77b7923..3c309ec 100755 Binary files a/F3:F303/Multistepper/multistepper.bin and b/F3:F303/Multistepper/multistepper.bin differ diff --git a/F3:F303/Multistepper/proto.c b/F3:F303/Multistepper/proto.c index 38f38c9..8c04193 100644 --- a/F3:F303/Multistepper/proto.c +++ b/F3:F303/Multistepper/proto.c @@ -205,7 +205,7 @@ static void add_filter(const char *str){ USB_sendstr("No bank# given"); return; } - if(N > STM32F0FBANKNO-1){ + if(N > STM32FBANKNO-1){ USB_sendstr("bank# > 27"); return; } diff --git a/F3:F303/Multistepper/ringbuffer.c b/F3:F303/Multistepper/ringbuffer.c index 462d4c6..7f78f8c 100644 --- a/F3:F303/Multistepper/ringbuffer.c +++ b/F3:F303/Multistepper/ringbuffer.c @@ -18,19 +18,21 @@ #include "ringbuffer.h" -// stored data length -int RB_datalen(ringbuffer *b){ +static int datalen(ringbuffer *b){ if(b->tail >= b->head) return (b->tail - b->head); else return (b->length - b->head + b->tail); } -/** - * @brief RB_hasbyte - check if buffer has given byte stored - * @param b - buffer - * @param byte - byte to find - * @return index if found, -1 if none - */ -int RB_hasbyte(ringbuffer *b, uint8_t byte){ +// stored data length +int RB_datalen(ringbuffer *b){ + if(b->busy) return -1; + b->busy = 1; + int l = datalen(b); + b->busy = 0; + return l; +} + +static int hasbyte(ringbuffer *b, uint8_t byte){ if(b->head == b->tail) return -1; // no data in buffer int startidx = b->head; if(b->head > b->tail){ // @@ -43,6 +45,20 @@ int RB_hasbyte(ringbuffer *b, uint8_t byte){ return -1; } +/** + * @brief RB_hasbyte - check if buffer has given byte stored + * @param b - buffer + * @param byte - byte to find + * @return index if found, -1 if none or busy + */ +int RB_hasbyte(ringbuffer *b, uint8_t byte){ + if(b->busy) return -1; + b->busy = 1; + int ret = hasbyte(b, byte); + b->busy = 0; + return ret; +} + // poor memcpy static void mcpy(uint8_t *targ, const uint8_t *src, int l){ while(l--) *targ++ = *src++; @@ -54,15 +70,8 @@ TRUE_INLINE void incr(ringbuffer *b, volatile int *what, int n){ if(*what >= b->length) *what -= b->length; } -/** - * @brief RB_read - read data from ringbuffer - * @param b - buffer - * @param s - array to write data - * @param len - max len of `s` - * @return bytes read - */ -int RB_read(ringbuffer *b, uint8_t *s, int len){ - int l = RB_datalen(b); +static int read(ringbuffer *b, uint8_t *s, int len){ + int l = datalen(b); if(!l) return 0; if(l > len) l = len; int _1st = b->length - b->head; @@ -78,33 +87,49 @@ int RB_read(ringbuffer *b, uint8_t *s, int len){ return _1st; } +/** + * @brief RB_read - read data from ringbuffer + * @param b - buffer + * @param s - array to write data + * @param len - max len of `s` + * @return bytes read or -1 if busy + */ +int RB_read(ringbuffer *b, uint8_t *s, int len){ + if(b->busy) return -1; + b->busy = 1; + int r = read(b, s, len); + b->busy = 0; + return r; +} + +static int readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){ + int idx = hasbyte(b, byte); + if(idx < 0) return 0; + int partlen = idx + 1 - b->head; + // now calculate length of new data portion + if(idx < b->head) partlen += b->length; + if(partlen > len) return -read(b, s, len); + return read(b, s, partlen); +} + /** * @brief RB_readto fill array `s` with data until byte `byte` (with it) * @param b - ringbuffer * @param byte - check byte * @param s - buffer to write data * @param len - length of `s` - * @return amount of bytes written (negative, if lenhead; - // now calculate length of new data portion - if(idx < b->head) partlen += b->length; - if(partlen > len) return -RB_read(b, s, len); - return RB_read(b, s, partlen); + if(b->busy) return -1; + b->busy = 1; + int n = readto(b, byte, s, len); + b->busy = 0; + return n; } -/** - * @brief RB_write - write some data to ringbuffer - * @param b - buffer - * @param str - data - * @param l - length - * @return amount of bytes written - */ -int RB_write(ringbuffer *b, const uint8_t *str, int l){ - int r = b->length - 1 - RB_datalen(b); // rest length +static int write(ringbuffer *b, const uint8_t *str, int l){ + int r = b->length - 1 - datalen(b); // rest length if(l > r) l = r; if(!l) return 0; int _1st = b->length - b->tail; @@ -117,8 +142,27 @@ int RB_write(ringbuffer *b, const uint8_t *str, int l){ return l; } +/** + * @brief RB_write - write some data to ringbuffer + * @param b - buffer + * @param str - data + * @param l - length + * @return amount of bytes written or -1 if busy + */ +int RB_write(ringbuffer *b, const uint8_t *str, int l){ + if(b->busy) return -1; + b->busy = 1; + int w = write(b, str, l); + b->busy = 0; + return w; +} + // just delete all information in buffer `b` -void RB_clearbuf(ringbuffer *b){ +int RB_clearbuf(ringbuffer *b){ + if(b->busy) return -1; + b->busy = 1; b->head = 0; b->tail = 0; + b->busy = 0; + return 1; } diff --git a/F3:F303/Multistepper/ringbuffer.h b/F3:F303/Multistepper/ringbuffer.h index 6d6b5d3..549b5c0 100644 --- a/F3:F303/Multistepper/ringbuffer.h +++ b/F3:F303/Multistepper/ringbuffer.h @@ -25,6 +25,7 @@ typedef struct{ const int length; // its length int head; // head index int tail; // tail index + volatile int busy; // == TRUE if buffer is busy now } ringbuffer; int RB_read(ringbuffer *b, uint8_t *s, int len); @@ -32,4 +33,4 @@ int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len); int RB_hasbyte(ringbuffer *b, uint8_t byte); int RB_write(ringbuffer *b, const uint8_t *str, int l); int RB_datalen(ringbuffer *b); -void RB_clearbuf(ringbuffer *b); +int RB_clearbuf(ringbuffer *b); diff --git a/F3:F303/Multistepper/usb.c b/F3:F303/Multistepper/usb.c index 590a33e..313e723 100644 --- a/F3:F303/Multistepper/usb.c +++ b/F3:F303/Multistepper/usb.c @@ -1,6 +1,6 @@ /* * This file is part of the multistepper project. - * Copyright 2023 Edward V. Emelianov . + * Copyright 2024 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,27 +19,31 @@ #include #include "hardware.h" -#include "ringbuffer.h" #include "usb.h" #include "usb_lib.h" +#ifdef EBUG +#include "strfunc.h" +#endif static volatile uint8_t usbbuff[USB_TXBUFSZ]; // temporary buffer for sending data // ring buffers for incoming and outgoing data static uint8_t obuf[RBOUTSZ], ibuf[RBINSZ]; -static volatile ringbuffer out = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0}; -static volatile ringbuffer in = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0}; -// transmission is succesfull -static volatile uint8_t bufisempty = 1; -static volatile uint8_t bufovrfl = 0; +volatile ringbuffer rbout = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0}; +volatile ringbuffer rbin = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0}; +// inbuf overflow when receiving +volatile uint8_t bufovrfl = 0; +// last send data size +static volatile int lastdsz = 0; -static void send_next(){ - if(bufisempty) return; - static int lastdsz = 0; - int buflen = RB_read((ringbuffer*)&out, (uint8_t*)usbbuff, USB_TXBUFSZ); - if(!buflen){ +// called from transmit EP +void send_next(){ + int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ); + if(buflen == 0){ if(lastdsz == 64) EP_Write(3, NULL, 0); // send ZLP after 64 bits packet when nothing more to send lastdsz = 0; - bufisempty = 1; + return; + }else if(buflen < 0){ + EP_Write(3, NULL, 0); // send ZLP if buffer is in writting state now return; } EP_Write(3, (uint8_t*)usbbuff, buflen); @@ -48,44 +52,42 @@ static void send_next(){ // blocking send full content of ring buffer int USB_sendall(){ - while(!bufisempty){ - if(!usbON) return 0; + while(lastdsz > 0){ + if(!usbON) return FALSE; } - return 1; + return TRUE; } // put `buf` into queue to send int USB_send(const uint8_t *buf, int len){ - if(!buf || !usbON || !len) return 0; + if(!buf || !usbON || !len) return FALSE; while(len){ - int a = RB_write((ringbuffer*)&out, buf, len); - len -= a; - buf += a; - if(bufisempty){ - bufisempty = 0; - send_next(); - } + int a = RB_write((ringbuffer*)&rbout, buf, len); + if(a > 0){ + len -= a; + buf += a; + } else if (a < 0) continue; // do nothing if buffer is in reading state + if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN } - return 1; + return TRUE; } int USB_putbyte(uint8_t byte){ - if(!usbON) return 0; - while(0 == RB_write((ringbuffer*)&out, &byte, 1)){ - if(bufisempty){ - bufisempty = 0; - send_next(); - } + if(!usbON) return FALSE; + int l = 0; + while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){ + if(l < 0) continue; } - return 1; + if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN + return TRUE; } int USB_sendstr(const char *string){ - if(!string || !usbON) return 0; + if(!string || !usbON) return FALSE; int len = 0; const char *b = string; while(*b++) ++len; - if(!len) return 0; + if(!len) return FALSE; return USB_send((const uint8_t*)string, len); } @@ -96,13 +98,14 @@ int USB_sendstr(const char *string){ * @return amount of received bytes (negative, if overfull happened) */ int USB_receive(uint8_t *buf, int len){ - int sz = RB_read((ringbuffer*)&in, buf, len); + chkin(); if(bufovrfl){ - RB_clearbuf((ringbuffer*)&in); - if(!sz) sz = -1; - else sz = -sz; + while(1 != RB_clearbuf((ringbuffer*)&rbin)); bufovrfl = 0; + return -1; } + int sz = RB_read((ringbuffer*)&rbin, buf, len); + if(sz < 0) return 0; // buffer in writting state return sz; } @@ -113,65 +116,25 @@ int USB_receive(uint8_t *buf, int len){ * @return strlen or negative value indicating overflow (if so, string won't be ends with 0 and buffer should be cleared) */ int USB_receivestr(char *buf, int len){ - int l = RB_readto((ringbuffer*)&in, '\n', (uint8_t*)buf, len); - if(l == 0) return 0; - if(--l < 0 || bufovrfl) RB_clearbuf((ringbuffer*)&in); - else buf[l] = 0; // replace '\n' with strend + chkin(); if(bufovrfl){ - if(l > 0) l = -l; - else l = -1; + while(1 != RB_clearbuf((ringbuffer*)&rbin)); bufovrfl = 0; + return -1; } + int l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len); + if(l < 1){ + if(rbin.length == RB_datalen((ringbuffer*)&rbin)){ // buffer is full but no '\n' found + while(1 != RB_clearbuf((ringbuffer*)&rbin)); + return -1; + } + return 0; + } +#ifdef EBUG + USB_sendstr("readto, l="); USB_sendstr(u2str(l)); newline(); +#endif + if(l == 0) return 0; + buf[l-1] = 0; // replace '\n' with strend return l; } -// interrupt IN handler (never used?) -static void EP1_Handler(){ - uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); - if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX - else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX); - // clear CTR - epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)); - USB->EPnR[1] = epstatus; -} - -// data IN/OUT handlers -static void transmit_Handler(){ // EP3IN - uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]); - // clear CTR keep DTOGs & STATs - USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr - send_next(); -} - -static void receive_Handler(){ // EP2OUT - uint8_t buf[USB_RXBUFSZ]; - uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]); - uint8_t sz = EP_Read(2, (uint8_t*)buf); - if(sz){ - if(RB_write((ringbuffer*)&in, buf, sz) != sz) bufovrfl = 1; - } - // keep stat_tx & set ACK rx, clear RX ctr - USB->EPnR[2] = (epstatus & ~USB_EPnR_CTR_RX) ^ USB_EPnR_STAT_RX; -} - -void USB_proc(){ - switch(USB_Dev.USB_Status){ - case USB_STATE_CONFIGURED: - // make new BULK endpoint - // Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features) - EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit - EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data - EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data - USB_Dev.USB_Status = USB_STATE_CONNECTED; - break; - case USB_STATE_DEFAULT: - case USB_STATE_ADDRESSED: - if(usbON){ - usbON = 0; - } - break; - default: // USB_STATE_CONNECTED - send next data portion - // if(!usbON) return; // WTF? - break; - } -} diff --git a/F3:F303/Multistepper/usb.h b/F3:F303/Multistepper/usb.h index 5b62cc5..cd2808e 100644 --- a/F3:F303/Multistepper/usb.h +++ b/F3:F303/Multistepper/usb.h @@ -1,6 +1,6 @@ /* * This file is part of the multistepper project. - * Copyright 2023 Edward V. Emelianov . + * Copyright 2024 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,11 +18,12 @@ #pragma once +#include "ringbuffer.h" #include "usbhw.h" // sizes of ringbuffers for outgoing and incoming data #define RBOUTSZ (512) -#define RBINSZ (512) +#define RBINSZ (256) #define newline() USB_putbyte('\n') #define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) @@ -36,7 +37,10 @@ #define DBG(str) #endif -void USB_proc(); +extern volatile ringbuffer rbout, rbin; +extern volatile uint8_t bufisempty, bufovrfl; + +void send_next(); int USB_sendall(); int USB_send(const uint8_t *buf, int len); int USB_putbyte(uint8_t byte); diff --git a/F3:F303/Multistepper/usb_lib.c b/F3:F303/Multistepper/usb_lib.c index 4db6281..3ced8ec 100644 --- a/F3:F303/Multistepper/usb_lib.c +++ b/F3:F303/Multistepper/usb_lib.c @@ -1,6 +1,6 @@ /* * This file is part of the multistepper project. - * Copyright 2023 Edward V. Emelianov . + * Copyright 2024 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,14 +17,16 @@ */ #include +#include "usb.h" #include "usb_lib.h" +#include "usbhw.h" ep_t endpoints[STM32ENDPOINTS]; -usb_dev_t USB_Dev; +static uint16_t USB_Addr = 0; static usb_LineCoding lineCoding = {115200, 0, 0, 8}; -config_pack_t setup_packet; -uint8_t ep0databuf[EP0DATABUF_SIZE]; +uint8_t ep0databuf[EP0DATABUF_SIZE], setupdatabuf[EP0DATABUF_SIZE]; +config_pack_t *setup_packet = (config_pack_t*) setupdatabuf; usb_LineCoding getLineCoding(){return lineCoding;} @@ -53,9 +55,9 @@ static const uint8_t USB_DeviceDescriptor[] = { 0x23, // idProduct_H 0x00, // bcdDevice_Ver_L 0x03, // bcdDevice_Ver_H - 0x01, // iManufacturer - 0x02, // iProduct - 0x00, // iSerialNumber + iMANUFACTURER_DESCR, // iManufacturer + iPRODUCT_DESCR, // iProduct + iSERIAL_DESCR, // iSerialNumber bNumConfigurations // bNumConfigurations }; @@ -95,7 +97,7 @@ static const uint8_t USB_ConfigDescriptor[] = { 0xff, /* bInterfaceClass */ 0x00, /* bInterfaceSubClass */ 0x00, /* bInterfaceProtocol */ - 0x00, /* iInterface: */ + iINTERFACE_DESCR, /* iInterface: */ /////////////////////////////////////////////////// /*Endpoint 1 Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ @@ -125,11 +127,19 @@ static const uint8_t USB_ConfigDescriptor[] = { 0x00, /* bInterval: ignore for Bulk transfer */ }; -_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US); -// these descriptors are not used in PL2303 emulator! -_USB_STRING_(USB_StringSerialDescriptor, u"0"); -_USB_STRING_(USB_StringManufacturingDescriptor, u"Prolific Technology Inc."); -_USB_STRING_(USB_StringProdDescriptor, u"USB-Serial Controller"); +_USB_LANG_ID_(LD, LANG_US); +_USB_STRING_(SD, u"0.0.1"); +_USB_STRING_(MD, u"Prolific Technology Inc."); +_USB_STRING_(PD, u"USB-Serial Controller"); +_USB_STRING_(ID, u"multistepper"); +static void const *StringDescriptor[iDESCR_AMOUNT] = { + [iLANGUAGE_DESCR] = &LD, + [iMANUFACTURER_DESCR] = &MD, + [iPRODUCT_DESCR] = &PD, + [iSERIAL_DESCR] = &SD, + [iINTERFACE_DESCR] = &ID +}; + /* * default handlers @@ -171,7 +181,7 @@ void WEAK vendor_handler(config_pack_t *packet){ } static void wr0(const uint8_t *buf, uint16_t size){ - if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request + if(setup_packet->wLength < size) size = setup_packet->wLength; // shortened request if(size < endpoints[0].txbufsz){ EP_WriteIRQ(0, buf, size); return; @@ -199,24 +209,18 @@ static void wr0(const uint8_t *buf, uint16_t size){ } static inline void get_descriptor(){ - switch(setup_packet.wValue){ + uint8_t descrtype = setup_packet->wValue >> 8, + descridx = setup_packet->wValue & 0xff; + switch(descrtype){ case DEVICE_DESCRIPTOR: wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor)); break; case CONFIGURATION_DESCRIPTOR: wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor)); break; - case STRING_LANG_DESCRIPTOR: - wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE); - break; - case STRING_MAN_DESCRIPTOR: - wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength); - break; - case STRING_PROD_DESCRIPTOR: - wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength); - break; - case STRING_SN_DESCRIPTOR: - wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength); + case STRING_DESCRIPTOR: + if(descridx < iDESCR_AMOUNT) wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx])); + else EP_WriteIRQ(0, (uint8_t*)0, 0); break; case DEVICE_QUALIFIER_DESCRIPTOR: wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); @@ -229,7 +233,7 @@ static inline void get_descriptor(){ static uint16_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured) static inline void std_d2h_req(){ uint16_t status = 0; // bus powered - switch(setup_packet.bRequest){ + switch(setup_packet->bRequest){ case GET_DESCRIPTOR: get_descriptor(); break; @@ -244,16 +248,61 @@ static inline void std_d2h_req(){ } } +// interrupt IN handler (never used?) +static void EP1_Handler(){ + uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); + if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX + else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX); + // clear CTR + epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)); + USB->EPnR[1] = epstatus; +} + +// data IN/OUT handlers +static void transmit_Handler(){ // EP3IN + uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]); + // clear CTR keep DTOGs & STATs + USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr + send_next(); +} + +static uint8_t rcvbuf[USB_RXBUFSZ]; +static uint8_t volatile rcvbuflen = 0; + +void chkin(){ + if(bufovrfl) return; + if(!rcvbuflen) return; + int w = RB_write((ringbuffer*)&rbin, rcvbuf, rcvbuflen); + if(w < 0) return; + if(w != rcvbuflen) bufovrfl = 1; + rcvbuflen = 0; + uint16_t status = KEEP_DTOG(USB->EPnR[2]); // don't change DTOG + USB->EPnR[2] = status ^ USB_EPnR_STAT_RX; +} + +// receiver reads data from local buffer and only then ACK'ed +static void receive_Handler(){ // EP2OUT + uint16_t status = KEEP_DTOG_STAT(USB->EPnR[2]); // don't change DTOG and NACK + if(rcvbuflen){ + bufovrfl = 1; // lost last data + rcvbuflen = 0; + } + rcvbuflen = EP_Read(2, (uint8_t*)rcvbuf); + USB->EPnR[2] = status & ~USB_EPnR_CTR_RX; +} + static inline void std_h2d_req(){ - switch(setup_packet.bRequest){ + switch(setup_packet->bRequest){ case SET_ADDRESS: // new address will be assigned later - after acknowlegement or request to host - USB_Dev.USB_Addr = setup_packet.wValue; + USB_Addr = setup_packet->wValue; break; case SET_CONFIGURATION: // Now device configured - USB_Dev.USB_Status = USB_STATE_CONFIGURED; - configuration = setup_packet.wValue; + configuration = setup_packet->wValue; + EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit + EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data + EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data break; default: break; @@ -271,8 +320,8 @@ bmRequestType: 76543210 */ void EP0_Handler(){ uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications - uint8_t reqtype = setup_packet.bmRequestType & 0x7f; - uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0; + uint8_t reqtype = setup_packet->bmRequestType & 0x7f; + uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0; int rxflag = RX_FLAG(epstatus); if(rxflag && SETUP_FLAG(epstatus)){ switch(reqtype){ @@ -285,15 +334,15 @@ void EP0_Handler(){ } break; case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request - if(setup_packet.bRequest == CLEAR_FEATURE){ + if(setup_packet->bRequest == CLEAR_FEATURE){ EP_WriteIRQ(0, (uint8_t *)0, 0); } break; case VENDOR_REQUEST_TYPE: - vendor_handler(&setup_packet); + vendor_handler(setup_packet); break; case CONTROL_REQUEST_TYPE: - switch(setup_packet.bRequest){ + switch(setup_packet->bRequest){ case GET_LINE_CODING: EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding)); break; @@ -301,7 +350,7 @@ void EP0_Handler(){ break; case SET_CONTROL_LINE_STATE: usbON = 1; - clstate_handler(setup_packet.wValue); + clstate_handler(setup_packet->wValue); break; case SEND_BREAK: usbON = 0; @@ -310,23 +359,22 @@ void EP0_Handler(){ default: break; } - if(setup_packet.bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement + if(setup_packet->bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement break; default: EP_WriteIRQ(0, (uint8_t *)0, 0); } }else if(rxflag){ // got data over EP0 or host acknowlegement if(endpoints[0].rx_cnt){ - if(setup_packet.bRequest == SET_LINE_CODING){ + if(setup_packet->bRequest == SET_LINE_CODING){ linecoding_handler((usb_LineCoding*)ep0databuf); } } } else if(TX_FLAG(epstatus)){ // package transmitted // now we can change address after enumeration - if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){ - USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; - // change state to ADRESSED - USB_Dev.USB_Status = USB_STATE_ADDRESSED; + if ((USB->DADDR & USB_DADDR_ADD) != USB_Addr){ + USB->DADDR = USB_DADDR_EF | USB_Addr; + usbON = 0; } } epstatus = KEEP_DTOG(USB->EPnR[0]); diff --git a/F3:F303/Multistepper/usb_lib.h b/F3:F303/Multistepper/usb_lib.h index ddfc8b2..f35917d 100644 --- a/F3:F303/Multistepper/usb_lib.h +++ b/F3:F303/Multistepper/usb_lib.h @@ -1,6 +1,6 @@ /* * This file is part of the multistepper project. - * Copyright 2023 Edward V. Emelianov . + * Copyright 2024 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,14 +60,21 @@ #define CONTROL_DTR 0x01 #define CONTROL_RTS 0x02 -// wValue -#define DEVICE_DESCRIPTOR 0x100 -#define CONFIGURATION_DESCRIPTOR 0x200 -#define STRING_LANG_DESCRIPTOR 0x300 -#define STRING_MAN_DESCRIPTOR 0x301 -#define STRING_PROD_DESCRIPTOR 0x302 -#define STRING_SN_DESCRIPTOR 0x303 -#define DEVICE_QUALIFIER_DESCRIPTOR 0x600 +// string descriptors +enum{ + iLANGUAGE_DESCR, + iMANUFACTURER_DESCR, + iPRODUCT_DESCR, + iSERIAL_DESCR, + iINTERFACE_DESCR, + iDESCR_AMOUNT +}; + +// Types of descriptors +#define DEVICE_DESCRIPTOR 0x01 +#define CONFIGURATION_DESCRIPTOR 0x02 +#define STRING_DESCRIPTOR 0x03 +#define DEVICE_QUALIFIER_DESCRIPTOR 0x06 #define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX) #define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX) @@ -77,14 +84,6 @@ #define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) #define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) -// USB state: uninitialized, addressed, ready for use -typedef enum{ - USB_STATE_DEFAULT, - USB_STATE_ADDRESSED, - USB_STATE_CONFIGURED, - USB_STATE_CONNECTED -} USB_state; - // EP types #define EP_TYPE_BULK 0x00 #define EP_TYPE_CONTROL 0x01 @@ -93,6 +92,16 @@ typedef enum{ #define LANG_US (uint16_t)0x0409 +#if 0 +typedef struct{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t *bString; +} string_descriptor_t; + +#define _USB_STRING_(name, str) string_descriptor_t name = {(sizeof(str) + 2), STRING_DESCRIPTOR, str} +#endif + #define _USB_STRING_(name, str) \ static const struct name \ { \ @@ -113,7 +122,6 @@ static const struct name \ \ } \ name = {0x04, 0x03, lng_id} -#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4) // EP0 configuration packet typedef struct { @@ -133,12 +141,6 @@ typedef struct{ unsigned rx_cnt : 10; // received data counter } ep_t; -// USB status & its address -typedef struct { - uint8_t USB_Status; - uint16_t USB_Addr; -}usb_dev_t; - typedef struct { uint32_t dwDTERate; uint8_t bCharFormat; @@ -163,10 +165,9 @@ typedef struct { } __attribute__ ((packed)) usb_cdc_notification; extern ep_t endpoints[]; -extern usb_dev_t USB_Dev; extern volatile uint8_t usbON; -extern config_pack_t setup_packet; -extern uint8_t ep0databuf[]; +extern config_pack_t *setup_packet; +extern uint8_t ep0databuf[], setupdatabuf[]; void EP0_Handler(); @@ -179,3 +180,4 @@ void linecoding_handler(usb_LineCoding *lc); void clstate_handler(uint16_t val); void break_handler(); void vendor_handler(config_pack_t *packet); +void chkin(); diff --git a/F3:F303/Multistepper/usbhw.c b/F3:F303/Multistepper/usbhw.c index 33a3432..9f6dc67 100644 --- a/F3:F303/Multistepper/usbhw.c +++ b/F3:F303/Multistepper/usbhw.c @@ -1,6 +1,6 @@ /* * This file is part of the multistepper project. - * Copyright 2023 Edward V. Emelianov . + * Copyright 2024 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,10 +50,10 @@ static uint16_t lastaddr = LASTADDR_DEFAULT; int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){ if(number >= STM32ENDPOINTS) return 4; // out of configured amount if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large - if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable + if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE/ACCESSZ) return 2; // out of btable USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1; - if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size + if(rxsz & 1 || rxsz > USB_BTABLE_SIZE) return 3; // wrong rx buffer size uint16_t countrx = 0; if(rxsz < 64) countrx = rxsz / 2; else{ @@ -84,7 +84,6 @@ void usb_lp_isr(){ lastaddr = LASTADDR_DEFAULT; // clear address, leave only enable bit USB->DADDR = USB_DADDR_EF; - USB_Dev.USB_Status = USB_STATE_DEFAULT; if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){ return; } @@ -101,10 +100,10 @@ void usb_lp_isr(){ if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit) if(n == 0){ // control endpoint if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack - EP_Read(0, (uint8_t*)&setup_packet); + EP_Read(0, setupdatabuf); // interrupt handler will be called later }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf - EP_Read(0, (uint8_t*)&ep0databuf); + EP_Read(0, ep0databuf); } } } diff --git a/F3:F303/Multistepper/usbhw.h b/F3:F303/Multistepper/usbhw.h index ca6fd25..5915191 100644 --- a/F3:F303/Multistepper/usbhw.h +++ b/F3:F303/Multistepper/usbhw.h @@ -1,6 +1,6 @@ /* * This file is part of the multistepper project. - * Copyright 2023 Edward V. Emelianov . + * Copyright 2024 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/F3:F303/Multistepper/version.inc b/F3:F303/Multistepper/version.inc index d05e2b0..16d71ff 100644 --- a/F3:F303/Multistepper/version.inc +++ b/F3:F303/Multistepper/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "119" -#define BUILD_DATE "2024-08-16" +#define BUILD_NUMBER "160" +#define BUILD_DATE "2024-08-26"