How to control multiple serial ports at the same time?

I have two custom devices that I am attempting to control via a USB-to-serial connection. Each device will respond with a unique identifier so that I know which is attached to which port. I have some code that is partially working, but when I attempt to issue commands over the ID’d ports, one of the ports receives no data.

In setup:

// Point at a new serial object
ser_ptr = new ofSerial();

// Get a list of all serial devices
vector <ofSerialDeviceInfo> deviceList = ser_ptr->getDeviceList();

// Something to hold the found port names
vector <string> COMPorts;

// Get each port name
while (numCOMs < deviceList.size())
{
    // Setup the port
    ser_ptr->setup(deviceList[numCOMs].getDeviceName(), baud);

    // Send challenge to device
    int retValueOfChallenge = isMyDevice(ser_ptr);  // Done this way for debug
    // This will return whether it's a left (1) or right (2) device
    if (retValueOfChallenge > 0)
    {
        // If the device answered as expected, add this port to the vector
        headlights.push_back(*ser_ptr);
    }

    // We've added that port, so close it
    ser_ptr->close();

    // Done with this port
    numCOMs++;
}

The helper function:

int ofApp::isMyDevice(ofSerial *port_ptr)
{
    uint8_t commandBytes[2] = { 0x01, 0x00 };
    uint8_t returnedBytes[10];
    const uint8_t expectedBytes[10] = { 0x7F, 'M', 'D', 'M', '-', 'X', '\0' };
    bool timedOut = false;
    int deviceFound = 0;

    port_ptr->writeBytes(commandBytes, 2);

    // How long to wait on a read; 200mS is FOREVER
    uint64_t timeOut = ofGetElapsedTimeMillis();

    // Wait for the bytes to come in or timeout
    while (port_ptr->available() < 9)
    {
        if ((ofGetElapsedTimeMillis() - timeOut) > 200)
        {
            timedOut = true;
            break;
        }
    }
    // If we timed out, return false
    if (timedOut)
    {
        deviceFound = 0;
    }
    // Otherwise, get the bytes from the buffer
    else
    {
        ser_ptr->readBytes(returnedBytes, 9);

        // Compare vs. expected; initial 5 chars
        int charsMatch = strncmp((char *)expectedBytes, (char *)returnedBytes, 5);  // Done this way for debug
        if (charsMatch == 0)
        {
            // This is left or right?
            if (returnedBytes[5] == 'L')
            {
                deviceFound = 1;
            }
            else if (returnedBytes[5] == 'R')
            {
                deviceFound = 2;
            }
            else
            {
                deviceFound = 0;
            }
        }
        else
        {
            deviceFound = 0;
        }
    }

    return(deviceFound);
}

//------------------------------------------------------------------------------------

From there, whenever I want to send a command to both devices, I try something like this:

for (int i = 0; i < headlights.size(); i++)
{
    headlights[i].writeBytes(commandBytes, 3);
}

But, the device with the higher “COMx” port number never receives it’s data. Is this the correct way to do this? It seems that when you open an ofSerial instance, it has knowledge of all of the COM ports in the system. So, do I need only a single ofSerial, and then I iterate through the devices under it? Looking for guidance on the best way to approach this.

Note that if hard-code the ports with unique instances, something like this:

serialRight.setup("COM7", baud);
serialLeft.setup("COM9", baud);

And then I use writeBytes on both of those instances, then everything works fine. Any ideas?

Thank you.

No ofSerial only opens a connection to one device, it just holds a vector of available devices to connect to. You would need a separate ofSerial for each object you want to connect to, like you have already done when you hard code the ports.

Certainly take a look at how the setup in ofSerial works

do you know how many devices you will have or do you need a dynamic container like a vector. If you need to have a variable number of connections I would probably iterate through the devices and then make a new serial object rather than passing pointers when the device completes the handshake.

1 Like

I would also recommend taking a look at ofxSerial addon, which I find more convenient sometimes as it gives more information about the serial ports.

Though on Windows, you need a little trick to open correctly the port: have a look at this post.

1 Like