almost working U[S]ARTs

This commit is contained in:
Edward Emelianov
2026-02-16 23:58:29 +03:00
parent 3ff87427ac
commit 73a0eeba8f
8 changed files with 79 additions and 78 deletions

View File

@@ -1,37 +0,0 @@
/*
* This file is part of the multiiface project.
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "usb_dev.h"
// debugging messages on config interface
#ifdef EBUG
#define DBG(str) do{USB_sendstr(ICFG, __FILE__ " (L" STR(__LINE__) "): " str); newline(ICFG);}while(0)
#define DBGmesg(str) do{USB_sendstr(ICFG, str);}while(0)
#define DBGmesgn(str,n) do{USB_send(ICFG, str, n);}while(0)
#define DBGnl() newline(ICFG)
#else
#define DBG(str)
#define DBGmesg(str)
#define DBGmesgn(str,n)
#define DBGnl()
#endif

View File

@@ -16,6 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Debug.h"
#include "flash.h" #include "flash.h"
#include "hardware.h" #include "hardware.h"
#include "proto.h" #include "proto.h"
@@ -44,13 +45,14 @@ int main(void){
USBPU_OFF(); USBPU_OFF();
USB_setup(); USB_setup();
//uint32_t ctr = Tms; //uint32_t ctr = Tms;
//usb_LineCoding lc = {9600, 0, 0, 8}; usb_LineCoding lc = {9600, 0, 0, 8};
//for(int i = 0; i < 5; ++i) usart_config(i, &lc); for(int i = 0; i < 5; ++i) usart_config(i, &lc); // configure all U[S]ARTs for default data
USBPU_ON(); USBPU_ON();
while(1){ while(1){
// Put here code working WITOUT USB connected // Put here code working WITOUT USB connected
if(!usbON) continue; if(!usbON) continue;
usarts_process(); usarts_process();
DBGpri();
/*for(int i = 0; i < 6; ++i){ // just echo for first time /*for(int i = 0; i < 6; ++i){ // just echo for first time
if(!CDCready[i]) continue; if(!CDCready[i]) continue;
int l = USB_receive(i, (uint8_t*)inbuff, MAXSTRLEN); int l = USB_receive(i, (uint8_t*)inbuff, MAXSTRLEN);

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 18.0.2, 2026-02-15T23:30:45. --> <!-- Written by QtCreator 18.0.2, 2026-02-16T23:57:09. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>

View File

@@ -1,4 +1,5 @@
debug.h Debug.c
Debug.h
flash.c flash.c
flash.h flash.h
hardware.c hardware.c

View File

@@ -19,7 +19,7 @@
#include <stm32f3.h> #include <stm32f3.h>
#include <string.h> #include <string.h>
#include "debug.h" #include "Debug.h"
#include "hardware.h" #include "hardware.h"
#include "strfunc.h" #include "strfunc.h"
#include "usart.h" #include "usart.h"
@@ -87,6 +87,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
// Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8. // Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8.
U->BRR = peripheral_clock / lc->dwDTERate; U->BRR = peripheral_clock / lc->dwDTERate;
lc->dwDTERate = peripheral_clock / U->BRR; lc->dwDTERate = peripheral_clock / U->BRR;
DBGs("New speed: "); DBGs(u2str(lc->dwDTERate)); DBGn();
// ----- Data bits & Parity ----- // ----- Data bits & Parity -----
uint32_t cr1 = 0; uint32_t cr1 = 0;
@@ -102,6 +103,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
lc->bParityType = USB_CDC_EVEN_PARITY; lc->bParityType = USB_CDC_EVEN_PARITY;
} }
} }
DBGs("Parity: "); DBGch('0'+lc->bParityType); DBGn();
// Word length (M bits) depends on data bits and parity // Word length (M bits) depends on data bits and parity
// M[1:0] encoding: 00 = 8 bits, 01 = 9 bits, 10 = 7 bits // M[1:0] encoding: 00 = 8 bits, 01 = 9 bits, 10 = 7 bits
@@ -114,7 +116,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
// 7 data + 1 parity = 8 bits total -> M=00 (8-bit mode) // 7 data + 1 parity = 8 bits total -> M=00 (8-bit mode)
// do nothing // do nothing
}else{ }else{
// Unsupported (8 or 9 data bits with parity would be 9/10 bits total) // 8 or 9 data bits with parity would be 9/10 bits total
// Fallback to 8 data + parity // Fallback to 8 data + parity
cr1 |= USART_CR1_M0; cr1 |= USART_CR1_M0;
lc->bDataBits = 8; // ??? need to be tested lc->bDataBits = 8; // ??? need to be tested
@@ -130,6 +132,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
lc->bDataBits = 8; lc->bDataBits = 8;
} }
} }
DBGs("Data bits: "); DBGch('0' + lc->bDataBits); DBGn();
// ----- Stop bits ----- // ----- Stop bits -----
uint32_t cr2 = 0; uint32_t cr2 = 0;
@@ -144,18 +147,21 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
// do nothing: default to 1 stop bit -> CR2=00 // do nothing: default to 1 stop bit -> CR2=00
break; break;
} }
DBGs("Stop bits: "); DBGch('0'+lc->bCharFormat); DBGn();
// Write CR2 (stop bits) // Write CR2 (stop bits)
U->CR2 = cr2; U->CR2 = cr2;
// Enable transmitter, receiver, and interrupts (optional) // Enable transmitter, receiver, and interrupts (optional)
cr1 |= USART_CR1_RE; cr1 |= USART_CR1_RE | USART_CR1_IDLEIE; // enable idle interrupt to force small portions of data into ringbuffer
if(cfg->DEport){ if(cfg->DEport){
DBG("485 -> RX");
RX485(cfg->DEport, cfg->DEpin); RX485(cfg->DEport, cfg->DEpin);
cr1 |= USART_CR1_TCIE; cr1 |= USART_CR1_TCIE;
}else cr1 |= USART_CR1_TE; }else cr1 |= USART_CR1_TE;
// ----- DMA ----- // ----- DMA -----
if(cfg->dma_controller){ // DMA-driven if(cfg->dma_controller){ // DMA-driven
DBG("DMA-driven");
volatile DMA_Channel_TypeDef *T = cfg->dma_tx_channel, *R = cfg->dma_rx_channel; volatile DMA_Channel_TypeDef *T = cfg->dma_tx_channel, *R = cfg->dma_rx_channel;
// Tx DMA // Tx DMA
T->CCR = 0; T->CCR = 0;
@@ -169,8 +175,8 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
R->CCR = DMA_CCR_MINC | DMA_CCR_EN; // | DMA_CCR_TCIE R->CCR = DMA_CCR_MINC | DMA_CCR_EN; // | DMA_CCR_TCIE
// enable U[S]ART DMA // enable U[S]ART DMA
U->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; U->CR3 = USART_CR3_DMAT | USART_CR3_DMAR;
cr1 |= USART_CR1_IDLEIE; // enable idle interrupt to force small portions of data into ringbuffer
}else{ }else{
DBG("IRQ-driven");
cr1 |= USART_CR1_RXNEIE; // interrupt-driven cr1 |= USART_CR1_RXNEIE; // interrupt-driven
inbufidx[ifNo] = 0; inbufidx[ifNo] = 0;
outbufidx[ifNo] = 0; outbufidx[ifNo] = 0;
@@ -183,6 +189,9 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){
if (--tmout == 0) break; if (--tmout == 0) break;
} }
U->ICR = 0xFFFFFFFF; // Clear flags again U->ICR = 0xFFFFFFFF; // Clear flags again
TXrdy[ifNo] = 1;
DBGch('0' + ifNo);
DBG("U[S]ART configured");
} }
// start when received DTR // start when received DTR
@@ -192,6 +201,8 @@ void usart_start(uint8_t ifNo){
cfg->instance->CR1 |= USART_CR1_UE; cfg->instance->CR1 |= USART_CR1_UE;
NVIC_EnableIRQ(cfg->UIRQn); NVIC_EnableIRQ(cfg->UIRQn);
if(cfg->dma_controller) NVIC_EnableIRQ(cfg->DIRQn); if(cfg->dma_controller) NVIC_EnableIRQ(cfg->DIRQn);
DBGch('0' + ifNo);
DBG("U[S]ART started");
} }
/** /**
@@ -201,21 +212,16 @@ void usart_start(uint8_t ifNo){
void usart_stop(uint8_t ifNo){ void usart_stop(uint8_t ifNo){
if(ifNo >= USARTSNO || UC[ifNo].instance == NULL) return; if(ifNo >= USARTSNO || UC[ifNo].instance == NULL) return;
const USART_Config *cfg = &UC[ifNo]; const USART_Config *cfg = &UC[ifNo];
cfg->instance->CR1 = 0; cfg->instance->CR1 &= ~USART_CR1_UE;
if(cfg->DEport) RX485(cfg->DEport, cfg->DEpin); if(cfg->DEport) RX485(cfg->DEport, cfg->DEpin);
/*
if(cfg->dma_controller){ if(cfg->dma_controller){
cfg->dma_tx_channel->CCR = 0;
cfg->dma_rx_channel->CCR = 0;
NVIC_DisableIRQ(cfg->DIRQn); NVIC_DisableIRQ(cfg->DIRQn);
}else{ }
NVIC_DisableIRQ(cfg->UIRQn); NVIC_DisableIRQ(cfg->UIRQn);
} */
} DBGch('0' + ifNo);
DBG("U[S]ART stopped");
static void msg(const char *txt, uint8_t ifno, int l){
if(!Config_mode) return;
CFGWR("IF"); USB_putbyte(ICFG, '1' + ifno); CFGWR(": ");
CFGWR(txt); CFGWR(" ("); CFGWR(i2str(l)); CFGWR(" bytes)\n");
} }
/** /**
@@ -234,12 +240,11 @@ void usarts_process(){
register int l = DMARXBUFSZ - R->CNDTR; register int l = DMARXBUFSZ - R->CNDTR;
if(l){ // have some input data -> send and restart DMA if(l){ // have some input data -> send and restart DMA
if(USB_send(i, inbuffers[i], l)){ if(USB_send(i, inbuffers[i], l)){
msg("USART -> USB over DMA", i, l); DBG("USART -> USB over DMA");
// restart DMA only in case of succesfull sent or if failed, but have ability of buffer overfull // restart DMA only in case of succesfull sent or if failed, but have ability of buffer overfull
R->CMAR = (uint32_t) inbuffers[i]; R->CMAR = (uint32_t) inbuffers[i];
R->CNDTR = DMARXBUFSZ; R->CNDTR = DMARXBUFSZ;
need2send[i] = 0; need2send[i] = 0;
if(cfg->DEport) TX485(cfg->DEport, cfg->DEpin);
} }
} }
R->CCR |= DMA_CCR_EN; // re-enable DMA R->CCR |= DMA_CCR_EN; // re-enable DMA
@@ -254,13 +259,14 @@ void usarts_process(){
T->CMAR = (uint32_t) outbuffers[i]; T->CMAR = (uint32_t) outbuffers[i];
T->CNDTR = got; T->CNDTR = got;
if(cfg->DEport){ // switch to Tx if(cfg->DEport){ // switch to Tx
DBG("485 -> TX");
TX485(cfg->DEport, cfg->DEpin); TX485(cfg->DEport, cfg->DEpin);
cfg->instance->CR1 &= ~USART_CR1_RE; cfg->instance->CR1 &= ~USART_CR1_RE;
cfg->instance->CR1 |= USART_CR1_TE; cfg->instance->CR1 |= USART_CR1_TE;
} }
T->CCR |= DMA_CCR_EN; // start new transmission
TXrdy[i] = 0; TXrdy[i] = 0;
msg("USB -> USART over DMA", i, got); T->CCR |= DMA_CCR_EN; // start new transmission
DBG("USB -> USART over DMA");
} }
} }
}else{ // interrupt-driven }else{ // interrupt-driven
@@ -272,7 +278,7 @@ void usarts_process(){
if(l && USB_send(i, inbuffers[i], l)){ if(l && USB_send(i, inbuffers[i], l)){
need2send[i] = 0; need2send[i] = 0;
inbufidx[i] = 0; inbufidx[i] = 0;
msg("USART -> USB over irq", i, l); DBG("USART -> USB over irq");
} }
} }
U->CR1 |= USART_CR1_RXNEIE; // restore irq reaction U->CR1 |= USART_CR1_RXNEIE; // restore irq reaction
@@ -281,6 +287,7 @@ void usarts_process(){
int got = USB_receive(i, outbuffers[i], DMATXBUFSZ); int got = USB_receive(i, outbuffers[i], DMATXBUFSZ);
if(got > 0){ if(got > 0){
if(cfg->DEport){ // switch to Tx if(cfg->DEport){ // switch to Tx
DBG("485 -> TX");
TX485(cfg->DEport, cfg->DEpin); TX485(cfg->DEport, cfg->DEpin);
U->CR1 &= ~USART_CR1_RE; U->CR1 &= ~USART_CR1_RE;
U->CR1 |= USART_CR1_TE; U->CR1 |= USART_CR1_TE;
@@ -290,7 +297,7 @@ void usarts_process(){
TXrdy[i] = 0; TXrdy[i] = 0;
U->TDR = outbuffers[i][0]; // start transmission U->TDR = outbuffers[i][0]; // start transmission
U->CR1 |= USART_CR1_TXEIE; // enable TXE interrupt U->CR1 |= USART_CR1_TXEIE; // enable TXE interrupt
msg("USB -> USART over irq", i, got); DBG("USB -> USART over irq");
} }
} }
} }
@@ -300,8 +307,8 @@ void usarts_process(){
// Use this function only for debug purpose // Use this function only for debug purpose
int usart_send(uint8_t ifNo, const uint8_t *data, int len){ int usart_send(uint8_t ifNo, const uint8_t *data, int len){
if(ifNo >= USARTSNO || !data || len < 1) return 0; if(ifNo >= USARTSNO || !data || len < 1) return 0;
if(TXrdy[ifNo] == 0) return -1; // busy
const USART_Config *cfg = &UC[ifNo]; const USART_Config *cfg = &UC[ifNo];
if(TXrdy[ifNo] == 0 || (!cfg->instance->CR1 & USART_CR1_UE)) return -1; // busy or not active
if(len > DMATXBUFSZ) len = DMATXBUFSZ; if(len > DMATXBUFSZ) len = DMATXBUFSZ;
memcpy(outbuffers[ifNo], data, len); memcpy(outbuffers[ifNo], data, len);
if(cfg->dma_controller){ if(cfg->dma_controller){
@@ -311,15 +318,17 @@ int usart_send(uint8_t ifNo, const uint8_t *data, int len){
T->CMAR = (uint32_t) outbuffers[ifNo]; T->CMAR = (uint32_t) outbuffers[ifNo];
T->CNDTR = len; T->CNDTR = len;
if(cfg->DEport){ // switch to Tx if(cfg->DEport){ // switch to Tx
DBG("485 -> TX");
TX485(cfg->DEport, cfg->DEpin); TX485(cfg->DEport, cfg->DEpin);
cfg->instance->CR1 &= ~USART_CR1_RE; cfg->instance->CR1 &= ~USART_CR1_RE;
cfg->instance->CR1 |= USART_CR1_TE; cfg->instance->CR1 |= USART_CR1_TE;
} }
T->CCR |= DMA_CCR_EN; // start new transmission
TXrdy[ifNo] = 0; TXrdy[ifNo] = 0;
T->CCR |= DMA_CCR_EN; // start new transmission
}else{ }else{
volatile USART_TypeDef *U = cfg->instance; volatile USART_TypeDef *U = cfg->instance;
if(cfg->DEport){ // switch to Tx if(cfg->DEport){ // switch to Tx
DBG("485 -> TX");
TX485(cfg->DEport, cfg->DEpin); TX485(cfg->DEport, cfg->DEpin);
U->CR1 &= ~USART_CR1_RE; U->CR1 &= ~USART_CR1_RE;
U->CR1 |= USART_CR1_TE; U->CR1 |= USART_CR1_TE;
@@ -339,24 +348,32 @@ int usart_send(uint8_t ifNo, const uint8_t *data, int len){
static void usart_isr(uint8_t ifno){ static void usart_isr(uint8_t ifno){
const USART_Config *cfg = &UC[ifno]; const USART_Config *cfg = &UC[ifno];
volatile USART_TypeDef *U = cfg->instance; volatile USART_TypeDef *U = cfg->instance;
if(U->ISR & USART_ISR_RXNE){ // got new byte // for every flag we should also check if it's IRQ active
if((U->ISR & USART_ISR_RXNE) && (U->CR1 & USART_CR1_RXNEIE)){ // got new byte
DBG("RXNE");
if(inbufidx[ifno] == DMARXBUFSZ) (void) U->RDR; // throw away data: buffer overfull if(inbufidx[ifno] == DMARXBUFSZ) (void) U->RDR; // throw away data: buffer overfull
else inbuffers[ifno][ inbufidx[ifno]++ ] = U->RDR; // put new byte into buffer else inbuffers[ifno][ inbufidx[ifno]++ ] = U->RDR; // put new byte into buffer
} }
if(U->ISR & USART_ISR_IDLE){ // try to send collected data // IDLE active for both DMA- and interrupt-driven transitions
if(U->ISR & USART_ISR_IDLE){ // try to send collected data (DMA-driven)
need2send[ifno] = 1; // seems like data portion is over - try to send it need2send[ifno] = 1; // seems like data portion is over - try to send it
U->ICR = USART_ICR_IDLECF; U->ICR = USART_ICR_IDLECF;
DBG("IDLE");
} }
if(U->ISR & USART_ISR_TXE){ // send next byte if need if((U->ISR & USART_ISR_TXE) && (U->CR1 & USART_CR1_TXEIE)){ // send next byte if need (interrupt-driven)
DBG("TXE");
if(outbuflen[ifno] > outbufidx[ifno]){ if(outbuflen[ifno] > outbufidx[ifno]){
U->TDR = outbuffers[ifno][ outbufidx[ifno]++ ]; U->TDR = outbuffers[ifno][ outbufidx[ifno]++ ];
}else{ }else if(U->CR1 & USART_CR1_TXEIE){
U->CR1 &= ~USART_CR1_TXEIE; // disable interrupt: no data to send U->CR1 &= ~USART_CR1_TXEIE; // disable interrupt: no data to send
TXrdy[ifno] = 1; TXrdy[ifno] = 1;
DBG("TXRDY");
} }
} }
if(U->ISR & USART_ISR_TC){ // switch RS-485 to Rx after transmission complete if(U->ISR & USART_ISR_TC){ // switch RS-485 to Rx after transmission complete
DBG("TC");
if(cfg->DEport){ if(cfg->DEport){
DBG("485 -> RX");
RX485(cfg->DEport, cfg->DEpin); RX485(cfg->DEport, cfg->DEpin);
U->CR1 &= ~USART_CR1_TE; U->CR1 &= ~USART_CR1_TE;
U->CR1 |= USART_CR1_RE; U->CR1 |= USART_CR1_RE;
@@ -373,7 +390,7 @@ void uart4_exti34_isr(){ usart_isr(3); }
void uart5_exti35_isr(){ usart_isr(4); } void uart5_exti35_isr(){ usart_isr(4); }
// DMA Tx interrupts (to arm ready flag) // DMA Tx interrupts (to arm ready flag)
void dma1_channel2_isr(){ TXrdy[1] = 1; DMA1->IFCR = DMA_IFCR_CTCIF2; } void dma1_channel2_isr(){ DBG("DMA1 done"); TXrdy[0] = 1; DMA1->IFCR = DMA_IFCR_CTCIF2; }
void dma1_channel4_isr(){ TXrdy[2] = 1; DMA1->IFCR = DMA_IFCR_CTCIF4; } void dma1_channel4_isr(){ DBG("DMA2 done"); TXrdy[1] = 1; DMA1->IFCR = DMA_IFCR_CTCIF4; }
void dma1_channel7_isr(){ TXrdy[0] = 1; DMA1->IFCR = DMA_IFCR_CTCIF7; } void dma1_channel6_isr(){ DBG("DMA3 done"); TXrdy[2] = 1; DMA1->IFCR = DMA_IFCR_CTCIF6; }
void dma2_channel5_isr(){ TXrdy[3] = 1; DMA2->IFCR = DMA_IFCR_CTCIF5; } void dma2_channel5_isr(){ DBG("DMA4 done"); TXrdy[3] = 1; DMA2->IFCR = DMA_IFCR_CTCIF5; }

View File

@@ -17,6 +17,7 @@
#include <string.h> #include <string.h>
#include "Debug.h"
#include "hardware.h" #include "hardware.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "usart.h" #include "usart.h"
@@ -45,7 +46,7 @@ static volatile uint8_t bufovrfl[InterfacesAmount] = {0};
static uint8_t volatile rcvbuf[InterfacesAmount][USB_RXBUFSZ]; static uint8_t volatile rcvbuf[InterfacesAmount][USB_RXBUFSZ];
static uint8_t volatile rcvbuflen[InterfacesAmount] = {0}; static uint8_t volatile rcvbuflen[InterfacesAmount] = {0};
// line coding // line coding
#define DEFL {115200, 0, 0, 8} #define DEFL {9600, 0, 0, 8}
usb_LineCoding lineCoding[InterfacesAmount] = {DEFL,DEFL,DEFL,DEFL,DEFL,DEFL,DEFL}; usb_LineCoding lineCoding[InterfacesAmount] = {DEFL,DEFL,DEFL,DEFL,DEFL,DEFL,DEFL};
// CDC configured and ready to use // CDC configured and ready to use
volatile uint8_t CDCready[InterfacesAmount] = {0}; volatile uint8_t CDCready[InterfacesAmount] = {0};
@@ -117,9 +118,11 @@ static void rxtx_handler(){
// SET_LINE_CODING // SET_LINE_CODING
void linecoding_handler(uint8_t ifno, usb_LineCoding *lc){ void linecoding_handler(uint8_t ifno, usb_LineCoding *lc){
//DBGch('0' + ifno);
//DBG("Linecoding");
lineCoding[ifno] = *lc; lineCoding[ifno] = *lc;
usart_config(ifno, &lineCoding[ifno]); // lc would be real speed! usart_config(ifno, &lineCoding[ifno]); // lc would be real speed!
usart_start(ifno); usart_start(ifno); // restart again with new configuration
} }
// clear IN/OUT buffers on connection // clear IN/OUT buffers on connection
@@ -136,10 +139,13 @@ static void clearbufs(uint8_t ifno){
// SET_CONTROL_LINE_STATE // SET_CONTROL_LINE_STATE
void clstate_handler(uint8_t ifno, uint16_t val){ void clstate_handler(uint8_t ifno, uint16_t val){
//DBGch('0' + ifno);
//DBG("CLSTATE");
CDCready[ifno] = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected CDCready[ifno] = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected
lastdsz[ifno] = -1; lastdsz[ifno] = -1;
if(val){ if(val){
clearbufs(ifno); clearbufs(ifno);
//usart_config(ifno, &lineCoding[ifno]); // SET_CONTROL_LINE_STATE could be without SET_LINE_CODING
usart_start(ifno); usart_start(ifno);
}else usart_stop(ifno); // turn of USART (if it is @ this interface) }else usart_stop(ifno); // turn of USART (if it is @ this interface)
} }
@@ -147,6 +153,8 @@ void clstate_handler(uint8_t ifno, uint16_t val){
// SEND_BREAK - disconnect interface and clear its buffers // SEND_BREAK - disconnect interface and clear its buffers
// this is a fake handler as classic CDC ACM never receives this // this is a fake handler as classic CDC ACM never receives this
void break_handler(uint8_t ifno){ void break_handler(uint8_t ifno){
//DBGch('0' + ifno);
//DBG("BREAK");
CDCready[ifno] = 0; CDCready[ifno] = 0;
usart_stop(ifno); // turn of USART (if it is @ this interface) usart_stop(ifno); // turn of USART (if it is @ this interface)
} }
@@ -176,11 +184,14 @@ void usb_class_request(config_pack_t *req, uint8_t *data, uint16_t datalen){
case REQ_RECIPIENT_INTERFACE: case REQ_RECIPIENT_INTERFACE:
switch(req->bRequest){ switch(req->bRequest){
case SET_LINE_CODING: case SET_LINE_CODING:
//DBG("SLC");
if(!data || !datalen) break; // wait for data if(!data || !datalen) break; // wait for data
//DBG("test");
if(datalen == sizeof(usb_LineCoding)) if(datalen == sizeof(usb_LineCoding))
linecoding_handler(ifno, (usb_LineCoding*)data); linecoding_handler(ifno, (usb_LineCoding*)data);
break; break;
case GET_LINE_CODING: case GET_LINE_CODING:
DBG("GLC");
EP_WriteIRQ(0, (uint8_t*)&lineCoding[ifno], sizeof(lineCoding)); EP_WriteIRQ(0, (uint8_t*)&lineCoding[ifno], sizeof(lineCoding));
break; break;
case SET_CONTROL_LINE_STATE: case SET_CONTROL_LINE_STATE:
@@ -218,6 +229,7 @@ int USB_sendall(uint8_t ifno){
// put `buf` into queue to send // put `buf` into queue to send
int USB_send(uint8_t ifno, const uint8_t *buf, int len){ int USB_send(uint8_t ifno, const uint8_t *buf, int len){
if(!buf || !CDCready[ifno] || !len) return FALSE; if(!buf || !CDCready[ifno] || !len) return FALSE;
if(ifno != ICFG) DBG("USB_send");
uint32_t T0 = Tms; uint32_t T0 = Tms;
while(len){ while(len){
if(Tms - T0 > DISCONN_TMOUT){ if(Tms - T0 > DISCONN_TMOUT){
@@ -242,7 +254,10 @@ int USB_send(uint8_t ifno, const uint8_t *buf, int len){
if(lastdsz[ifno] < 0) send_next(ifno); if(lastdsz[ifno] < 0) send_next(ifno);
} }
} }
if(buf[len-1] == '\n' && lastdsz[ifno] < 0) send_next(ifno); if(buf[len-1] == '\n' && lastdsz[ifno] < 0){
if(ifno != ICFG) DBG("send_next");
send_next(ifno);
}
return TRUE; return TRUE;
} }
@@ -263,7 +278,10 @@ int USB_putbyte(uint8_t ifno, uint8_t byte){
} }
} }
// send line if got EOL // send line if got EOL
if(byte == '\n' && lastdsz[ifno] < 0) send_next(ifno); if(byte == '\n' && lastdsz[ifno] < 0){
if(ifno != ICFG) DBG("send_next");
send_next(ifno);
}
return TRUE; return TRUE;
} }

View File

@@ -1,2 +1,2 @@
#define BUILD_NUMBER "97" #define BUILD_NUMBER "110"
#define BUILD_DATE "2026-02-15" #define BUILD_DATE "2026-02-16"