USB Serial Baudrate

Hi all!

I’m starting a project in which I need to use the Photon as a USB to Serial converter. Is there any method or callback where I can get the event of the USB serial being opened from a PC? I also need the baudrate in which the PC opened it, because I’m going to need to open the Serial1 or Serial2 in the same baudrate.

Thanks in advance,
Mariano.

If there only was some decent documentation of the Serial function set … but hold on … there is … if I only could think of that acronym that woud fit here :wink:
https://docs.particle.io/reference/device-os/firmware/photon/#isconnected-

But for that there is no straight forward function - but actually the USB Serial connection doesn’t really obey to the baudrate you pass in Serial.begin() anyway - it always uses the USB transfer speed.

YES! Since my original question was about the baudrate, I didn’t check for the isconnected(). Thanks for being patient, though.

That I know. I don’t need the USB to obey the baudrate, I only need the value of the baudrate the PC used to open the CDC serial implementation. I will use that baudrate to open Serial1 or Serial2 ports.

Let me explain a little more about this little tooling project. I have devices that communicate with Current Loop interfaces, not 4-20, but “digital” current loops (current/no-current), like gas pumps or the like.

So, I already have a Photon running on a custom board with that serial hardware interface, and I would like to re-use that hardware to make a serial converter (like an FTDI) to convert USB to Current Loop. Soooo again, I need to know at which baudrate I need to open this other serial port, and thus, I need to know at which baudrate the USB port has been opened.

I know the baudrate is known, because the Device OS uses it to check for “magic baudrates” 14400 and 28800. Is this exposed to the user?

Thanks again!!

It’s not officially supported and hence may undergo changes without warning, hence I said there is no “straight forward way”.
But you can try calling this

void USB_USART_LineCoding_BitRate_Handler(void (*handler)(uint32_t bitRate))

You pass in a function that receives the bitRate and acts upon it.

Great! I’m trying that. I also need the rest of the Serial configuration, so I copied from the Device OS and wrote this, but after trying include different headers I get an undefined reference to “linecoding”.

bool newConnection = false, activeConnection = false;

extern volatile LINE_CODING linecoding;
LINE_CODING serialConfig;

void setup() {
    USB_USART_LineCoding_BitRate_Handler(usb_bitrate_callback);
    Serial.begin();
}

void loop() {
    if (newConnection && Serial.isConnected()) {
        begin_Serial1();
        
        newConnection = false;
        activeConnection = true;
    }
    
    // ports processing
    if (!activeConnection)
    {
        return;
    }

    // Serial -> Serial1
    if (Serial.available() > 0) 
    {
        Serial1.write(Serial.read());
    }

    // Serial1 -> Serial
    if (Serial1.available() > 0) 
    {
        Serial.write(Serial1.read());
    }
}

void begin_Serial1(void)
{
    int conf = 0;
    
    //TODO: try values
    switch(serialConfig.format)
    {
        case 0: conf |= SERIAL_DATA_BITS_7;
        case 1: conf |= SERIAL_DATA_BITS_8;
        case 2: conf |= SERIAL_DATA_BITS_9;
    }
    
    //TODO: try values
    switch(serialConfig.paritytype)
    {
        case 0: conf |= SERIAL_PARITY_NO;
        case 1: conf |= SERIAL_PARITY_EVEN;
        case 2: conf |= SERIAL_PARITY_ODD;
    }
    
    //TODO: try values
    switch(serialConfig.datatype)
    {
        case 0: conf |= SERIAL_STOP_BITS_1;
        case 1: conf |= SERIAL_STOP_BITS_2;
        case 2: conf |= SERIAL_STOP_BITS_0_5;
        case 3: conf |= SERIAL_STOP_BITS_1_5;
    }
    
    Serial1.begin(serialConfig.bitrate, conf);
}

void usb_bitrate_callback(uint32_t bitrate)
{
    memcpy(&serialConfig, (const void*)&linecoding, sizeof(LINE_CODING));
    newConnection = true;
}

Where is linecoding actually defined?
When you declare it extern then you tell the compiler not to bother searching for it but promise that it will be declared somewhere. But is that somewhere actually reachable for the application linker?

Well, I first searched for USB_USART_LineCoding_BitRate_Handler() implementation, found it in usb_hal.c and followed the implementation of SetLineCodingBitRateHandler() to usb_prop.c. There, who calls the bitrate handler uses linecoding.bitrate:

void USB_Status_In(void)
{
#ifdef USB_CDC_ENABLE
  if (Request == SET_LINE_CODING)
  {
    //Callback handler when the host sets a specific linecoding
    if (NULL != APP_LineCodingBitRateHandler)
    {
      APP_LineCodingBitRateHandler(linecoding.bitrate);
    }

    Request = 0;
  }
#endif
}

In usb_prop.c is also declared linecoding:

volatile LINE_CODING linecoding =
  {
    0x00,   /* baud rate*/
    0x00,   /* stop bits-1*/
    0x00,   /* parity - none*/
    0x00    /* no. of bits */
  };

Originally I wanted to use CDC_GetLineCoding(), but somehow I can’t include usb_prop.h:

usb_serial.ino:2:22: fatal error: usb_prop.h: No such file or directory

/*******************************************************************************
* Function Name  : CDC_GetLineCoding.
* Description    : send the linecoding structure to the PC host.
* Input          : Length.
* Output         : None.
* Return         : Linecoding structure base address.
*******************************************************************************/
uint8_t *CDC_GetLineCoding(uint16_t Length)
{
  if (Length == 0)
  {
    pInformation->Ctrl_Info.Usb_wLength = sizeof(linecoding);
    return NULL;
  }

  return(uint8_t *)&linecoding;
}

Sooo again, I went back to usb_hal.c where I found:

extern volatile LINE_CODING linecoding;

You need to know that the open source repo shows you the sources of all modules comprising the entire system but not all of these modules are directly accessible from application code.
Only APIs that get exposed to the application level via dynamic linking are and linecoding apparently is not (it’s not an API either).

So while it is possible for a system function to access linecoding it doesn’t have to be the same for an application level function call when the containing module is not actually linked in.

Oh, ok. I will work with hardcoded values then since it’s going to be lab equipment. I will improve it if I get to know a better way.

Thanks!