• Software
  • Using Bela's Serial library to pass data to and from a PC

Hello, I’m having troubles using Bela’s ‘Serial’ library and the example source for using it, links at the bottom of this discussion: [(https://forum.bela.io/d/1214-usb-serial)].

From Bela’s IDE, I choose Examples → Communication → Serial. I then Build & run. The project finishes building and is now running, waiting indefinitely for an input that I can’t manage to send from my PC.

The default serial port specified in the setup function part of render.cpp is:
gSerial.setup ("/dev/ttyUSB0", 19200);

  1. Does this mean that Serial::read is polling from the board’s USB host port? Or am I wrong and it’s supposed to be polling from the client port (that’s already connected to get the board & IDE running)?

The example works for me when I’m listening on the target machine, using:
gSerial.setup ("/dev/pts/0", 57600);
Then when I ssh into root@bela.local from my host PC, I will get a response upon hitting “s” or “k” keys.
But I don’t manage to send the data straight from my PC and get a sound response.

On host PC:

$ stty < /dev/ttyACM0
speed 57600 baud; line = 0;

On Bela:

root@bela:~# grep v0 /etc/motd
Bela image, v0.3.8h, 5 January 2023
Built manually by modifying the v0.3.8g image to update the Bela
root@bela:~# who am i
root 	pts/0    	Mar 12 14:20 (192.168.7.1) UPDATE
root@bela:~# dmesg | grep tty
[	0.000000] Kernel command line: console=ttyS0,115200n8 root=/dev/mmcblk1p2 ro rootfstype=ext4 rootwait coherent_pool=1M net.ifnames=0 quiet
[	0.438341] console [ttyS0] disabled
[	0.438440] 44e09000.serial: ttyS0 at MMIO 0x44e09000 (irq = 38, base_baud = 3000000) is a 8250
[	0.450276] console [ttyS0] enabled
root@bela:~# lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
root@bela:~# ls /dev/

Long list of devices, none of which end with “USB” or “ACM”. ttyS0 through ttyS5 are there.

I tried changing the device in the gSerial.setup line to some of them but none worked. Including things i’ve seen elsewhere in the forum:
gSerial.setup ("/dev/ttyS0", 57600); // 57600 to match with /dev/ttyACM0 on host PC
gSerial.setup ("/dev/ttyGS0", 9600); // I configured 9600 on PC’s /dev/ttyACM0 in order to match, couldn’t change

I would then type in a terminal on the host PC:
$ echo "s" > /dev/ttyACM0

But there’s no reaction.

  1. How can I know what device I should specify in gSerial.setup (device, speed) in order to receive data from the PC?
  2. What would sending an ‘s’ or ‘k’ look like on the host PC - using the echo command, some other manner?

When I tried connecting the BBB’s USB host port to one of my PC’s USB host ports using a cable with two standard plugs, none of the command line outputs above changed. I successfully connected a computer mouse to this board’s USB host port so I know it’s active.

Kind regards 🙂

the /dev/ttyUSB0 from the example is a hypothetical USB-UART device that you connect to Bela. Not sure why I put that there, it would have been more meaningful to put one of the /dev/ttySx ports. The /dev/ttySx ports are the physical UART ports on the BBB/PB.

/dev/ttyGS0 is the UART-over-USB showing up on the host. This is by default a getty login terminal set to 115200, so if you open it from the host with e.g.: screen /dev/tty.usbmodem__bela__ 115200 you can log into Bela via shell. Also, if you write anything to it from either side, it may be swallowed up by the getty. To free it up for your use, do:

systemctl stop serial-getty@ttyGS0.service  # stop it right now
systemctl disable serial-getty@ttyGS0.service  # disable it for future boots

Thanks for the response.
I set the line to be:
gSerial.setup ("/dev/ttyGS0", 115200);
I run the program on the board, then on the host PC I use $ echo "s" > /dev/ttyACM0 and get a response!

But getting a response to that echo would only last for several seconds (~ 5-15 secs). After this amount of time, the program is still running but responses are gone. I ran some tests and it seems like a matter of time rather than the amount of chars passed. It would not respond even to a single echo after I wait several seconds.
When I run the program with gSerial.setup ("/dev/pts/0", 57600); and give input from within a Bela via shell everything works perfectly.

  1. What could explain this?

Also, I’m looking for a way to send data from Bela to be stored in a file on the PC. For example, I’d like to add a functionality where every time “snare” is received, a text file on the host PC is concatenated with Bela’s uptime, without damaging the Real time functionality of Bela.

I’ve looked at the read and write functions in ‘Serial.h’ and ‘Pipe.h’. As well documented, the read/write functions in the serial library are used to read/write bytes from/to the serial port. In ‘Pipe.h’ their functionality is to exchange data between a RT and a non-RT thread.

  1. I might be super wrong here but I didn’t manage to find an initiative idea as to how the Serial library can be used to achieve this goal. What would be the best way?

Another thing I noticed is that in render's while(gPipe.readRt(c) > 0), the Pipe’s gPipe.readRt redirects eventually to:

ssize_t Pipe::_readRt(void* ptr, size_t size)
{
    return _readRtNonRt(ptr, size, true);
}

Where Pipe::_readRtNonRt is fully implemented. Hope I’m not mistaken.

  1. It looks like a function that’s supposed to act in RT is immediately redirected to NonRT. Am I missing something here, and it doesn’t really affect any required functionality?

    Barak302 But getting a response to that echo would only last for several seconds (~ 5-15 secs). After this amount of time, the program is still running but responses are gone.

    Does this mean that if you run echo "s" > /dev/ttyACM0 repeatedly on the host, at some point the you no longer get a "response"? What is a response here? To simplify things, if you print the received message from the Bela C++ program, does it keep printing when you perform the echo command on the host?

    What could explain this?

    Did you stop the systemctl serial-getty@ttyGS0 service as explained above?

    Barak302 It looks like a function that’s supposed to act in RT is immediately redirected to NonRT.

    No. _readRtNonRt()'s last argument tells it whether it's RT or non-RT. The two cases are handled in a single place to avoid duplicates https://github.com/BelaPlatform/Bela/blob/master/libraries/Pipe/Pipe.cpp#L124-L151 .

    Barak302 Also, I’m looking for a way to send data from Bela to be stored in a file on the PC. For example, I’d like to add a functionality where every time “snare” is received, a text file on the host PC is concatenated with Bela’s uptime, without damaging the Real time functionality of Bela.

    So you have a host sending some data to the board over USB-serial and you want that whenever such data is received a file on the host is updated with the board's timestamp? Can you not log that on the board and copy it over once the program ends, or every so often?

    Also, if this is all going to be done over the Bela's USB connection, then why not use the ethernet functionality that it provides and do everything via network instead of UART?

      giuliomoro Does this mean that if you run echo "s" > /dev/ttyACM0 repeatedly on the host, at some point the you no longer get a "response"? What is a response here? To simplify things, if you print the received message from the Bela C++ program, does it keep printing when you perform the echo command on the host?

      My idea of response there was the printing and the generation of snare/kick sound according to the input. For example with "s":

      Here's c: sReceived: s
      
      c>0 and c is: s

      I guess that's equivalent to satisfying either one of the conditions:

      if('k' == serialBuffer[n])
      {
      gPipe.writeNonRt('k');
      gSerial.write("kick!\n\r");
      } else if('s' == serialBuffer[n])
      {
      gPipe.writeNonRt('s');
      gSerial.write("snare!\n\r");
      }

      in render.cpp. After several seconds, while repeatedly sending echos on the host, it will stop printing as well as making drum sounds.

      giuliomoro Did you stop the systemctl serial-getty@ttyGS0 service as explained above?

      I tried in both cases, disabled and not disabled, same outcome.
      Removed /etc/systemd/system/getty.target.wants/serial-getty@ttyGS0.service.

      giuliomoro No. _readRtNonRt()'s last argument tells it whether it's RT or non-RT. The two cases are handled in a single place to avoid duplicates

      Sorry I totally missed that boolean.

      giuliomoro So you have a host sending some data to the board over USB-serial and you want that whenever such data is received a file on the host is updated with the board's timestamp? Can you not log that on the board and copy it over once the program ends, or every so often?

      Yes sir. I'm interested in passing info that should be recorded on the board. The idea is to have a connection between Bela and the PC for as much time as needed, that will preserve Bela's RT capabilities, where files on both platforms can be updated with varying information and saved multiple times. Such file modification is not periodic and should occur upon a decision made elsewhere, here for simplicity it's represented by sending "s" or "k" because you made it so comfortable. Modifying files should not meet RT constraints, but only should not interfere with Bela's RT jobs.

      giuliomoro Also, if this is all going to be done over the Bela's USB connection, then why not use the ethernet functionality that it provides and do everything via network instead of UART?

      No prevention from using ethernet, do you recommend using it instead? I went to USB arbitrarily when I saw gSerial.setup ("/dev/ttyUSB0", 19200); and I didn't know what would be the implications of trying to communicate with Bela over ethernet.

      Can't thank you enough for your posts 🙂

        Barak302 I tried in both cases, disabled and not disabled, same outcome.
        Removed /etc/systemd/system/getty.target.wants/serial-getty@ttyGS0.service.

        did you try the systemctl stop serial-getty@ttyGS0.service one ? (I noted just now that my comments were swapped between the two lines. Running, that I can connect with screen from the host (e.g.: screen /dev/tty.usbmodem__bela__ 115200) and I can keep pressing k as much as I want and it will keep working for "ever".

        BTW, writing to file or network or serial from a thread other than the audio thread will not affect the RT characteristics of Belka.

        Barak302 and I didn't know what would be the implications of trying to communicate with Bela over ethernet.

        You can use the UdpClient / UdpServer classes to receive / send data via ethernet. The host will need to receive that data and do something with it.