Skip to content

DTR Off blocks USB serial receive #9786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Kabron287 opened this issue Feb 19, 2020 · 2 comments
Open

DTR Off blocks USB serial receive #9786

Kabron287 opened this issue Feb 19, 2020 · 2 comments
Labels
Type: Bug USB: CDC serial Serial interface used by MCUs with native USB (e.g. Leonardo) to communicate with the computer

Comments

@Kabron287
Copy link

Kabron287 commented Feb 19, 2020

Board: Arduino Micro(ATMEGA32U4)
Test Sketch:

void setup() {
	Serial.begin(115200);
	Serial1.begin(115200);  
}
void loop() {
	if (Serial.available()) {
		Serial1.write(Serial.read());
	}
	if (Serial1.available()) {
		Serial.write(Serial1.read());
	}
}

To reproduce the issue make LoopBack connection RX-TX open Terminal Emulator(e.g. CoolTerm) and begin to send something. Switch DTR state ON/OFF.
If DTR OFF transmition stops.
It does not correspond with ordinary USB to serial behavior, e.g. FT232 chip, which transmits and receves regardless DTR state.

The same test runs on Teensy 2.0 with no such issue.

@per1234 per1234 added Type: Bug USB: CDC serial Serial interface used by MCUs with native USB (e.g. Leonardo) to communicate with the computer labels Feb 19, 2020
@Kabron287
Copy link
Author

Kabron287 commented Feb 20, 2020

In fact it is done consciously.
File: CDC.cpp
232

size_t Serial_::write(const uint8_t *buffer, size_t size)

{
	/* only try to send bytes if the high-level CDC connection itself 
	 is open (not just the pipe) - the OS should set lineState when the port
	 is opened and clear lineState when the port is closed.
	 bytes sent before the user opens the connection or after
	 the connection is closed are lost - just like with a UART. */
	
	// TODO - ZE - check behavior on different OSes and test what happens if an
	// open connection isn't broken cleanly (cable is yanked out, host dies
	// or locks up, or host virtual serial port hangs)
////	if (_usbLineInfo.lineState > 0)	
	{
		int r = USB_Send(CDC_TX,buffer,size);
		if (r > 0) {
			return r;
		} else {
			setWriteError();
			return 0;
		}
	}
	setWriteError();
	return 0;
}

Commenting if( ... solved the problem.
IMHO, this functionality should be left to the user's choice.

@GabrielBeraldo
Copy link

Commenting this actually works! This definitively should be a user configurable behavior....
For a more elegant solution i elaborate a simple code snippet that exemplifies the application of a custom serial class (this way we avoid touching arduino sources)

I believe that, as me, someone would struggle with this in the future and hopefully benefits from this approach

USB serial converter application example:

#include <Arduino.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define BAUDRATE 9600

// Custom Serial class to bypass DTR check
class CustomSerial : public Serial_ {
public:
    size_t write(const uint8_t *buffer, size_t size) override {
        return USB_Send(CDC_TX, buffer, size);  // Override to bypass DTR check
    }
};

// Instantiate the custom serial class
CustomSerial UsbSerialPort;

// UART initialization for ATmega32U4
void UART_Init(uint16_t baud) {
    uint16_t ubrr = (F_CPU / 16 / baud) - 1;
    UBRR1H = (ubrr >> 8);
    UBRR1L = ubrr;
    UCSR1B = (1 << TXEN1) | (1 << RXEN1);  // Enable UART TX and RX
}

void UART_SendByte(uint8_t data) {
    while (!(UCSR1A & (1 << UDRE1)));  // Wait for empty transmit buffer
    UDR1 = data;
}

uint8_t UART_ReceiveByte() {
    while (!(UCSR1A & (1 << RXC1)));  // Wait for data to be received
    return UDR1;
}

void setup() {
    UsbSerialPort.begin(BAUDRATE);  // Initialize usb serial port
    UART_Init(BAUDRATE);            // Initialize UART with baud rate 9600
}

void loop() {
    // USB CDC to UART
    if (UsbSerialPort.available()) {
        uint8_t usbData = UsbSerialPort.read();
        UART_SendByte(usbData);
    }

    // UART to USB CDC
    if (UCSR1A & (1 << RXC1)) {  // Check if data is available in UART
        uint8_t uartData = UART_ReceiveByte();
        UsbSerialPort.write(&uartData, 1);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug USB: CDC serial Serial interface used by MCUs with native USB (e.g. Leonardo) to communicate with the computer
Projects
None yet
Development

No branches or pull requests

3 participants