RTR logo

BBC BASIC for SDL 2.0

Serial and Parallel I/O



Serial and parallel input/output

You can access device ports from a BBC BASIC for SDL 2.0 program by treating them as files. That is, you must first open a port (using OPENUP) then read and/or write data to that port using the statements and functions provided for file input/output (BGET, BPUT, INPUT#, PRINT# etc.) and finally close the port when you have finished with it (using CLOSE). There are some differences in the way these statements and functions are used when accessing a port rather than a file, which are described below.

Serial and patallel ports can only be accessed by one application at a time, so if a port is currently in use by another program, BBC BASIC will not be able to open it (the OPENUP function will return the value zero).

Opening a port

To open a channel to a serial or parallel port you use the OPENUP function, but instead of providing a filename you should specify a string representing the name of the device to be opened. Typically in Windows a serial device will be called "COM1:", "COM2:" etc., in Linux something similar to "/dev/ttyACM1", "/dev/ttyACM2" etc. and in MacOS "/dev/cuACM1/", "/dev/cuACM2" etc.

Because BBC BASIC automatically appends a ".bbc" extension to a filename, by default, you will need to add a "." suffix to suppress this:

device$ = "COM3:" : REM Windows
device$ = "/dev/ttyACM0" : REM Linux
device$ = "/dev/cuACM0" : REM MacOS
port% = OPENUP(device$ + ".")

Setting serial port parameters

In the case of a serial port, you may need to set the communication parameters such as baud rate etc. (this may not be necessary when it is, for example, a USB connection emulating a serial link).

A complication is that in Linux-based Operating systerms it is necessary to set the serial parameters before opening the device but in Windows it is done after opening the device. The following code takes account of this and sets the baud rate to 9600:

CASE @platform% AND &F OF
  WHEN 1: REM Linux
    OSCLI "stty -F " + device$ + " 9600 -echo raw"
  WHEN 2: REM MacOS
    OSCLI "stty -f " + device$ + " 9600 -echo raw"
ENDCASE

port% = OPENUP(device$ + ".")
IF port% = 0 THEN REM Handle failure to open device

CASE @platform% AND &F OF
  WHEN 0:
    IF @platform% AND &40 f%% = ](@hfile%(port%)+56) ELSE f%% = !(@hfile%(port%)+28)
    DIM cto{d%(4)}
    SYS "SetCommTimeouts", f%%, cto{} TO res%
    SYS "PurgeComm", f%%, &F TO res%
    DIM dcb{d%(6)}
    SYS "BuildCommDCBA", "9600,n,8,1", dcb{}
    SYS "SetCommState", f%%, dcb{} TO res%
ENDCASE
For setting additional parameters (parity, number of stop bits, handshaking etc.) see the description of the mode command in Windows and the stty command in Linux or MacOS.

Writing to a port

You can write data to a device port using any of the statements provided for writing to a file. i.e. BPUT and PRINT#. These statements will not return until the data has been sent, and depending on the data rate this can take a significant time (at 9600 baud each character takes a little over one millisecond to transmit).
PRINT #port%, mydata$
The above code appends a Carriage Return (&0D) to the string, to suppress that use:
BPUT #port%, mydata$;

Reading from a port

You can read data from a device port using any of the statements and functions provided for reading from a file, i.e. BGET, INPUT# and GET$#. These will wait until the requested amount of data has been received (one byte for BGET, multiple bytes for INPUT# and GET$#) which can, of course, be an indefinite period if no data is incoming.

To avoid your program 'hanging up' while waiting for data on a serial port, you can use the EXT# function to discover how many characters (if any) are waiting to be read. If you read only that number of characters you can guarantee that your program will never be waiting a long time for data to arrive:

REPEAT
  chars% = EXT#port%
  IF chars% THEN
    FOR count% = 1 TO chars%
      mydata& = BGET#port%
      REM. Do something with the data
    NEXT
  ENDIF
  REM. Do something useful here
UNTIL FALSE
If reading into a string you can read exactly the number of characters waiting:
REPEAT
  chars% = EXT#port%
  IF chars% THEN mydata$ += GET$#port% BY chars%
UNTIL FALSE

Closing a port

Once you have finished with a device port it should be closed, using the standard CLOSE statement. This makes the port available to another process. As usual, executing the END statement (or an untrapped error occurring) causes all open files and ports to be closed.
CLOSE #port%
The EOF# function and the PTR# pseudo-variable are not meaningful in the case of a port, and if used will result in the Invalid channel error.

Left CONTENTS

CONTINUE Right


Best viewed with Any Browser Valid HTML 3.2!
© Richard Russell 2023