AIRcable Logo CompanyProductsTechnologiesSupportOEMsContact Us
BackView CartView Cart
AIRcable Industrial Programming Handbook - Part 9

Support : Industrial : AIRcable AIRmotes Programming Handbook : PART 9

PART 9: MASTER Code Example - A commented programming example

This article describes the implementation of a serial port profile master program for the AIRcable Industrial. It is also a good example to see how to do wireless debugging.

You can download the MASTER code here (zip file).

To program the AIRcable Industrial with this new program see Part 4 of the Industrial Programming Manual.

Operation Principle

The intend is to program the AIRcable in BASIC to do this:

  • discover other Bluetooth devices in range
  • filter out one peer with a particular friendly name
  • connect to the remote device on the serial port (SPP)
  • configure the UART for 9600 baud and odd parity
  • link the wireless SPP port to the UART for streaming data

Debugging

While the AIRcable Industrial is finding other Bluetooth devices and streaming data, it is still accepting slave connections. We use the second wireless serial port (the slave SPP) for debugging. Make a SPP connection to the AIRcable and run a terminal emulator (such as Hyperterminal) on the connected slave SPP port. The BASIC interpreter will write every BASIC line it executes and any debug strings the BASIC program writes to the slave port. This is independent of the data communication between the peer Bluetooth device we connected through the master port and the UART.

Theories of Operation

On the AIRcable Industrial (and other AIRmote based devices) a BASIC program controls the Bluetooth baseband processor. Since all operations (Bluetooth, BASIC, timer etc) are running on the same processor the device is implemented as a multi-tasking system where several tasks perform operations concurrently. The BASIC program controls the multi-tasking system underneath it.

Routines

The BASIC program is organized in routines. Each routine is a section in the BASIC program that starts with @ROUTINE and ends with RETURN. These routines are like interrupt routines in an operating system. The BASIC interpreter knows 11 of these routines:

  1. @INIT
  2. @IDLE
  3. @SLAVE
  4. @ALARM
  5. @SENSOR
  6. @PIO_IRQ
  7. @MASTER
  8. @PIN_CODE
  9. @CONTROL
  10. @MESSAGE
  11. @INQUIRY

The important programming principle is to keep the routines short. This means that routines should not occupy the processor for very long and then it should end quickly. This allows the Bluetooth baseband processor to execute other tasks that are important for the functionality of the whole system. Routines that don't end (even with WAIT) will block the system.

These routines are scheduled for execution either by the system automatically, or by other parts of the program or by external hardware or Bluetooth events. Some of the routines are actually interrupting the execution of other routines because they have higher priority. For example, the @PIN_CODE routine has the highest priority and will interrupt any other routine. Otherwise routines are scheduled to run after the current routine is finished.

The MASTER Program

We will use the implementation of the master program to show the use of the various routines in an example.

The master program starts with @ERASE. This is a command to the BASIC loader in the AIRcable when a new program is transmitted via wireless FTP. It will cause the AIRcable to erase its BASIC memory completely.

The first routine is @INIT. It runs only once when the system is booted or a new BASIC program has been uploaded. In the example we first switch on the green LED to show that the AIRcable boots.

The lines 7 to 19 configure the power to the RS232 level shifter and schedules a hardware interrupt on PIO4. This is DSR input on the RS232 connector.

The PIN code that is used for connections (slave, master and ftp) is configured here in the BASIC program. The application then has more control over security this way. Since we only want to talk to devices with a friendly name starting with "PUMP" we initialize the string variables here too. Debugging is switched on using the special variable Z. A value of 2 means to send debugging to the slave port.

We initialize the state engine and disconnect any pending wireless links. This is helpful when we change programs frequently without rebooting the AIRcable. We don't disconnect slave ports because we would like to see the initialization execution on the slave port when a new version is uploaded.

@ERASE

@INIT 10
0 REM LED output and on
10 A=pioout 2
11 A=pioset 2
0 REM RS232_off set
12 A=pioout 5
13 A=pioset 5
0 REM RS232_on set
14 A=pioout 3
15 A=pioset 3
0 REM DTR output clear
16 A=pioout 6
17 A=pioclr 6
0 REM DSR input
18 A=pioin 4
0 REM set DSR to IRQ so that PIO_IRQ is called
19 A=pioirq "P000100"
0 REM PIN code
20 $1 = "1234"
0 REM connect to devices starting with
21 $2 = "PUMP"
0 REM connection state variable X
0 REM 1=found, 2=connecting, 3=connected, 4=slave restarted
22 X = 0
23 IF $4[0] = 0 THEN 26
0 REM we have a saved connection address, try first
24 $3 = $4
25 X = 1
0 REM switch on debug to the slave port
26 Z = 2
0 REM 25 A = disconnect 0
27 A = disconnect 1
28 A = unlink 1
29 ALARM 2
30 IF Z <> 2 THEN 32
31 PRINTS $3
32 RETURN


Running the Application using the Scheduler

The AIRcable Industrial knows 5 program controlled scheduled routines.

  • @INIT
  • @IDLE, @SLAVE
  • @MASTER
  • @ALARM
  • @SENSOR

and 5 hardware or event scheduled routines.

  • @PIN_CODE
  • @PIO_IRQ
  • @CONTROL
  • @MESSAGE
  • @INQUIRY

Slave Connections

@IDLE is called whenever a slave connection is not available or when a slave connection closed. This routine starts right after @INIT. Normally the BASIC program would open up the incoming serial slave port (SPP) for a number of seconds and then exits. It will be called again when the time is up and no connection was established. At this time the BASIC program will again open up the slave port for incoming connections to SPP.

When a connection to the slave port was successful, meaning another Bluetooth device has initiated a connection to the AIRcable, the @SLAVE routine starts up. The BASIC program can find out who is connecting using the build-in function getconn.

A successful connection requires that the two partners are paired. PIN code is exchanged and then the a unique link key is stored on both ends to indicate a successful pairing. Then the pairing information is stored persistently for future connections that will not need a PIN code anymore. Pairing information can be erased either when more than 8 peers are stored or manually with the unpair function (single peers) or the @UNPAIR command (all peers) at the beginning of a BASIC program upload.

For a simple slave application the program would just link the wireless SPP port to the UART. In this example, that's fundamentally what we do here too.

@IDLE 40
0 REM slave port stopped
40 Y = 0
0 REM give the processor time to
0 REM finish a pending master connection
0 REM this is in state 1, 2 and 3
41 IF X = 1 THEN 46;
42 IF X = 2 THEN 46;
43 IF X = 3 THEN 46;
REM in state 0 and 4: allow slave for 5 seconds
44 A = slave 5
0 REM slave port open now
45 Y = 1
46 RETURN

@SLAVE 90
0 REM slave connection to shell
90 A = pioset 2
91 PRINTS "shell started\r\nTAG$ "
92 RETURN

@PIN_CODE 488
488 $0 = $1
489 RETURN

In our more complex master example we want the program to allow master and slave connections at the same time. Therefore we need to implement a state machine to allow the Bluetooth baseband processor to do master connections without conflicting with the slave connections.

The variable X is used to keep state. The states are as follow, 0 state is initial state.

  1. we have found a peer that matches the criteria
  2. we are in process to connect as master to the peer
  3. we have successfully connected to the peer
  4. we are connected as master

Looking at the @IDLE routine, slave connections are only allowed when either inquiries are still going on or when a master connection has been established. When the slave connection mechanism is scheduled while a master connection is being established it causes conflicts. @IDLE will return in those cases and will have to be rescheduled when a certain state is reached.

The @MASTER routine is called whenever a master connection was successful. This is the second program controlled scheduled routine. The routine is pretty simple. It configures the UART with 9600 baud and odd parity and links the SPP master port to the UART. We also store the address of the peer in $4. When we lose connection we will try to reconnect to this address first before starting the inquiry process. Since a longer master connection timeout has been scheduled (20sec) we reschedule an alarm quicker.

@MASTER 100
0 REM save the address we conn
100 $4 = $3
0 REM debug message
102 IF Z = 0 THEN 105
103 PRINTS "master connected\n"
104 PRINTS $3
0 REM LED on
105 A = pioset 2
0 REM config 9600 baud, odd parity
106 A = uartcfg 35
0 REM link MASTER and UART
107 A = link 2
0 REM set state master connected
108 X = 3
0 REM reschedule ALARM quicker
109 ALARM 1
110 RETURN

Let's take a peek forward to the main control mechanism of the whole application. We use the ALARM scheduler do control the whole application. All execution is initiated by @ALARM, depending on the state described above.

When inquiries are going on, we wait. This is because inquiries are very expensive, in processing time and in power consumption too. We must leave the processor as much time as possible to do inquiries.

The results are scheduled by calls to @INQUIRY. Inquiry routines are sensitive to interrupts by other inquiry results. To prevent interruption a semicolon can be placed after a BASIC instruction. Normally the BASIC interpreter executes one line of BASIC program and then allows other parts of the system to execute before it goes to the next line. At the moment it schedules the execution of each line for every 100ms. With the placement of the semicolon this wait does not happen, the BASIC interpreter executes the next line immediately without going back to the scheduler. You must be careful using the semicolon.

@INQUIRY looks at the result and compares the name of the discovered Bluetooth device with the string in $2. If the name starts with that it sets the state to "found", cancels any further inquiries and prints some debug. See a chapter at the end about debugging.

0 REM process inquiry results
0 REM routine must have ';'
@INQUIRY 200
0 REM found peer, ignore other results
200 IF X >= 1 THEN 224;
201 $3 = $0;
202 $0 = $3[13];
0 REM only devices starting with this
203 B = strcmp $2;
204 IF B <> 0 THEN 220;

0 REM found, no more search
205 A = cancel;
206 X = 1;

0 REM debug
208 IF Z = 0 THEN 212;
209 S = status;
210 IF S = 1 THEN 213;
211 IF S = 10001 THEN 213;
212 RETURN

213 PRINTS "connecting "
214 PRINTS $0
215 PRINTS "\r\n"
216 RETURN

0 REM keep ';'
220 IF Z = 0 THEN 224;
221 S = status;
222 IF S = 1 THEN 225;
223 IF S = 10001 THEN 225;
224 RETURN

225 PRINTS "not "
226 PRINTS $0;
227 PRINTS "\r\n"
228 RETURN

Now to @ALARM. We have a standard state engine switch at the beginning and fan out from there to the different procedures depending on the state. Note that in every state we reschedule another ALARM within a few seconds to keep the system running. Switching state forward is mostly done in these procedures.

0 REM use ALARM routine to make master connections
@ALARM 400
0 REM wait until inquiry stops
400 S = status;
401 IF S < 10000 THEN 410;
0 REM still inquiring, schedule next ALARM
402 ALARM 2;
0 REM blink LED
403 B = pioset 2;
404 B = pioclr 2;
405 RETURN

0 REM state machine
410 IF X = 0 THEN 430;
411 IF X = 1 THEN 440;
412 IF X = 2 THEN 450;
413 IF X = 3 THEN 460;
415 IF X = 4 THEN 470;
0 REM should never happen
416 X = 0
417 GOTO 430

0 REM state 0: init, do inquiries
430 ALARM 6
0 REM blink LED
431 B = pioset 2;
432 B = pioclr 2
433 A = inquiry 11
434 RETURN

0 REM state 1: found
440 $0 = $3
441 IF Z <> 2 THEN 443
442 PRINTS $0
443 A = master $0
0 REM set state to "connecting"
444 X = 2
0 REM give it 20 seconds timeout
445 ALARM 20
0 REM blink LED
446 B = pioset 2;
447 B = pioclr 2
448 RETURN

0 REM state 2: timeout connecting, restart slave
450 X = 0
454 S = status
0 REM if we have a slave connection skip
455 IF S = 1 THEN 458
456 A = slave 1
457 Y = 1
0 REM safety, no master connections
458 A = disconnect 1
459 GOTO 410

0 REM state 3: master connected, restart slave
0 REM only if no slave connected
460 S = status
461 IF S = 11 THEN 464
462 A = slave 1
463 Y = 1
464 X = 4
465 ALARM 5
466 RETURN

0 REM state 4: connected, slave restarted
0 REM handle lost master connections
470 IF S < 1000 THEN 472
471 S = S - 1000
472 IF S < 100 THEN 474
473 S = S - 100
474 IF S < 10 THEN 480
0 REM still has master connection, blink reverse
475 ALARM 5
476 B = pioclr 2;
477 B = pioset 2
478 RETURN

0 REM lost master connection, reset state
480 A = unlink 2
481 X = 0
482 IF $4[0] = 0 THEN 485
483 X = 1
484 $3 = $4
485 GOTO 410

The last 2 routines @PIO_IRQ and @CONTROL deal with even change on the RS232 ports. If the DSR input on the DB9 connection changes, @PIO_IRQ is called. Remember we initialized that with the instruction "A=pioirq "P000100" in the @INIT routine.

The function modemctl transmits a message through an established SPP connection to the other end. Receiving this message will schedule the @CONTROL routine to be executed. In this example we set or reset the DTR pin of our RS232 connector.

@PIO_IRQ 490
0 REM local request for DSR
490 IF $0[4] = 48 THEN 483
0 REM modem control to other side
491 A = modemctl 1
492 RETURN
493 A = modemctl 0
494 RETURN

@CONTROL 495
0 REM remote request for DTR
495 IF $0[0] = 49 THEN 498
496 A=pioset 6
497 RETURN
498 A=pioclr 6
499 RETURN

Debugging

Since version 24, debugging is much easier. A special variable Z is used to switch on debugging of the BASIC interpreter. Every line it executes is being printed on one of the 3 data channels, UART, SPP-slave or SPP-master. We use the SPP-slave port to send the BASIC lines executed and additional debugging information.

The debugging code in the program makes sure that we don't send data to a channel that is not connected. The AIRcable will buffer some data when there is no connection but it will reduce memory and will cause unnecessary processing.

The Code

Here attached is the whole program, with debugging switched on. To use the program in production without debugging, change line 26 to "Z = 0".

@ERASE

@INIT 10
0 REM LED output and on
10 A=pioout 2
11 A=pioset 2
0 REM RS232_off set
12 A=pioout 5
13 A=pioset 5
0 REM RS232_on set
14 A=pioout 3
15 A=pioset 3
0 REM DTR output clear
16 A=pioout 6
17 A=pioclr 6
0 REM DSR input
18 A=pioin 4
0 REM set DSR to IRQ so that PIO_IRQ is called
19 A=pioirq "P000100"
0 REM PIN code
20 $1 = "1234"
0 REM connect to devices starting with
21 $2 = "PUMP"
0 REM connection state variable X
0 REM 1=found, 2=connecting, 3=connected, 4=slave restarted
22 X = 0
23 IF $4[0] = 0 THEN 26
0 REM we have a saved connection address, try first
24 $3 = $4
25 X = 1
0 REM switch on debug
26 Z = 2
0 REM 25 A = disconnect 0
27 A = disconnect 1
28 A = unlink 1
29 ALARM 2
30 IF Z <> 2 THEN 32
31 PRINTS $3
32 RETURN

@IDLE 40
0 REM slave port stopped
40 Y = 0
0 REM give the processor time to
0 REM finish a pending master connection
0 REM this is in state 1, 2 and 3
41 IF X = 1 THEN 46;
42 IF X = 2 THEN 46;
43 IF X = 3 THEN 46;
REM in state 0 and 4: allow slave for 5 seconds
44 A = slave 5
0 REM slave port open now
45 Y = 1
46 RETURN

@SLAVE 90
0 REM slave connection to shell
90 A = pioset 2
91 PRINTS "shell started\r\nTAG$ "
92 RETURN

@MASTER 100
0 REM save the address we conn
100 $4 = $3
0 REM debug message
102 IF Z = 0 THEN 105
103 PRINTS "master connected\n"
104 PRINTS $3
0 REM LED on
105 A = pioset 2
0 REM config 9600 baud, odd parity
106 A = uartcfg 35
0 REM link MASTER and UART
107 A = link 2
0 REM set state master connected
108 X = 3
0 REM reschedule ALARM quicker
109 ALARM 1
110 RETURN

0 REM process inquiry results
0 REM routine must have ';'
@INQUIRY 200
0 REM found peer, ignore other results
200 IF X >= 1 THEN 224;
201 $3 = $0;
202 $0 = $3[13];
0 REM only devices starting with this
203 B = strcmp $2;
204 IF B <> 0 THEN 220;

0 REM found, no more search
205 A = cancel;
206 X = 1;

0 REM debug
208 IF Z = 0 THEN 212;
209 S = status;
210 IF S = 1 THEN 213;
211 IF S = 10001 THEN 213;
212 RETURN

213 PRINTS "connecting "
214 PRINTS $0
215 PRINTS "\r\n"
216 RETURN

0 REM keep ';'
220 IF Z = 0 THEN 224;
221 S = status;
222 IF S = 1 THEN 225;
223 IF S = 10001 THEN 225;
224 RETURN

225 PRINTS "not "
226 PRINTS $0;
227 PRINTS "\r\n"
228 RETURN

0 REM use ALARM routine to make master connections
@ALARM 400
0 REM wait until inquiry stops
400 S = status;
401 IF S < 10000 THEN 410;
0 REM still inquiring, schedule next ALARM
402 ALARM 2;
0 REM blink LED
403 B = pioset 2;
404 B = pioclr 2;
405 RETURN

0 REM state machine
410 IF X = 0 THEN 430;
411 IF X = 1 THEN 440;
412 IF X = 2 THEN 450;
413 IF X = 3 THEN 460;
415 IF X = 4 THEN 470;
0 REM should never happen
416 X = 0
417 GOTO 430

0 REM state 0: init, do inquiries
430 ALARM 6
0 REM blink LED
431 B = pioset 2;
432 B = pioclr 2
433 A = inquiry 11
434 RETURN

0 REM state 1: found
440 $0 = $3
441 IF Z <> 2 THEN 443
442 PRINTS $0
443 A = master $0
0 REM set state to "connecting"
444 X = 2
0 REM give it 20 seconds timeout
445 ALARM 20
0 REM blink LED
446 B = pioset 2;
447 B = pioclr 2
448 RETURN

0 REM state 2: timeout connecting, restart slave
450 X = 0
454 S = status
0 REM if we have a slave connection skip
455 IF S = 1 THEN 458
456 A = slave 1
457 Y = 1
0 REM safety, no master connections
458 A = disconnect 1
459 GOTO 410

0 REM state 3: master connected, restart slave
0 REM only if no slave connected
460 S = status
461 IF S = 11 THEN 464
462 A = slave 1
463 Y = 1
464 X = 4
465 ALARM 5
466 RETURN

0 REM state 4: connected, slave restarted
0 REM handle lost master connections
470 IF S < 1000 THEN 472
471 S = S - 1000
472 IF S < 100 THEN 474
473 S = S - 100
474 IF S < 10 THEN 480
0 REM still has master connection, blink reverse
475 ALARM 5
476 B = pioclr 2;
477 B = pioset 2
478 RETURN

0 REM lost master connection, reset state
480 A = unlink 2
481 X = 0
482 IF $4[0] = 0 THEN 485
483 X = 1
484 $3 = $4
485 GOTO 410

@PIN_CODE 488
488 $0 = $1
489 RETURN

@PIO_IRQ 490
0 REM local request for DSR
490 IF $0[4] = 48 THEN 483
0 REM modem control to other side
491 A = modemctl 1
492 RETURN
493 A = modemctl 0
494 RETURN

@CONTROL 495
0 REM remote request for DTR
495 IF $0[0] = 49 THEN 498
496 A=pioset 6
497 RETURN
498 A=pioclr 6
499 RETURN

www.aircables.net/support-ind-program-manual-mastercode.html
 
company info | products | technologies | support | applications | contact us | site map
© 2005 Wireless Cables Inc. All Rights Reserved. Wireless Cables, Inc., Santa Cruz, California, U.S.A.
privacy policy | terms of use | site design by macdonald design, inc.