Examples - Bluetooth Server (NX)

Top  Previous  Next

//-----------------------------------------------------------------------------
// bt_server.vpl, created 2018-03-15 11:01
//
// This example enables the Bluetooth interface and listens for incoming 
// serial port connections.
// To make the device discoverable to enable pairing, the "visible" input must 
// be turned on. It is by default bound to the first DIP switch.
// 
// On NX-400, pairing must be confirmed on the display. 
// On other devices the pairing is accepted automatically.
// 
// When connecting to the serial port provided by the device, it sends back a 
// desciption of the available commands:
//   r      Reads the value of the configured inputs.
//   1-4    Toggles the corresponding output, i.e. writing "1" toggles output 1.
//   A-D    Sets the corresponding output high, i.e. writing "A" turns output 1 on.
//   a-d    Sets the corresponding output low, i.e. writing "a" turns output 1 off.
//
//-----------------------------------------------------------------------------
INCLUDE rtcu.inc
// Uncomment math.inc to add math library support.
//INCLUDE math.inc
 
 
#DEFINE STATE_NOT_CONNECTED   0
#DEFINE STATE_CONNECTING      1
#DEFINE STATE_CONNECTED       2
 
//  Input variables that can be configured via the configuration dialog (These are global)
VAR_INPUT
   in      : ARRAY [1..4] OF BOOL; | Input signals to show to the user
   visible : BOOL;                 | Device is visible while this signal is active
END_VAR;
 
//  Output variables that can be configured via the configuration dialog (These are global)
VAR_OUTPUT
   out     : ARRAY [1..4] OF BOOL; | Output signals that are controllable by the user
END_VAR;
 
//  These are the global variables of the program
VAR
   connection_state : INT := STATE_NOT_CONNECTED;
   port: SINT;
END_VAR;
 
 
 
THREAD_BLOCK btThread
VAR
   rc      : INT;
   address : STRING;
   ch      : SINT;
   pass    : DINT;
END_VAR;
   WHILE TRUE DO
      // 
      rc := btWaitEvent(timeout:=10000, dev := address);
      IF rc <> _BT_ERR_TIMEOUT THEN
         DebugFmt(message:="event \1: "+address, v1:=rc);
         CASE rc OF 
         _BT_EVENT_INCOMING:
            rc := btHandleSerialPortIncomingConnection(ch := ch, port := port);
            DebugFmt(message:="btHandleSerialPortIncomingConnection(\2) : \1, \3", v1:=rc, v2:=ch, v3:=port);
            IF(ch = 6) THEN
               IF connection_state <> STATE_NOT_CONNECTED THEN
                  // Close old port if it is open
                  serClose(port:=port);
               END_IF;
 
               // Open new port
               rc := serOpen(port:=port);
               DebugFmt(message:="serOpen(\2) : \1", v1:=rc, v2:=port);
               IF rc = 0 THEN
                  connection_state := STATE_CONNECTING;
               END_IF;
 
            END_IF;
         _BT_EVENT_DEV_FOUND:
            DebugFmt(message:="Found "+address);
         _BT_EVENT_DEV_LOST:
            DebugFmt(message:="Lost "+address);
         _BT_EVENT_PAIR_REQ:
            DebugFmt(message:="Requested confirm for "+address);
            rc := btHandlePairRequest(passkey:=pass);
            DebugFmt(message:="Pass: \4, \1", v1:=rc, v4:=pass);
            IF boardType() = 204 THEN
               // Ask for confirmation on NX-400
               rc := guiShowMessage(message:="Is the pairing code "+dintToStr(v:=pass)+" correct?", type := 2, timeout := 20);
               DebugFmt(message:="guiShowMessage: \1", v1:=rc);
               // Accept if "Yes" was pressed
               rc := btSendPairResponse(accept:=(rc = 3));
               DebugFmt(message:="btSendPairResponse: \1", v1:=rc);
            ELSE
               // Accept automatically on other devices
               rc := btSendPairResponse(accept:=TRUE);
               DebugFmt(message:="btSendPairResponse: \1", v1:=rc);
            END_IF;
         ELSE
            DebugFmt(message:="unknown event: \1", v1:=rc);
         END_CASE;
         btEventDone();
      END_IF;
 
   END_WHILE;
END_THREAD_BLOCK;
 
 
 
 
PROGRAM bt_server;
// These are the local variables of the program block
VAR
   old_visible : BOOL;
   rc          : INT;
   thEvent     : btThread;  
   RX          : serFrameReceiver;
   rxbuffer    : SINT; // Declare a buffer for receiving frames from the serial port
 
END_VAR;
 
// The next code will only be executed once after the program starts
 
   // Turn on the display for use when pairing
   displayPower(power := ON);
 
   // Turn on power
   rc := btPower();
   DebugFmt(message:="btPower: \1", v1:=rc);
 
 
   thEvent();
 
   // Enable serial port connections
   rc := btSerialPortProfileEnable(ch:=6, max_con := 1);
   DebugFmt(message:="btSerialPortProfileEnable: \1", v1:=rc);
 
   // Make sure discoverable will be set immediately.
   old_visible := NOT visible;
 
BEGIN
// Code from this point until END will be executed repeatedly
 
   IF old_visible <> visible THEN
      rc := btMakeDiscoverable(discoverable := visible, timeout := 0);
      DebugFmt(message:="btMakeDiscoverable(visible = \2): \1", v1:=rc, v2:= INT(visible));
      old_visible := visible;
   END_IF;
 
   IF connection_state = STATE_CONNECTING THEN
      RX(port:=port, enable:=TRUE, frame:=ADDR(rxbuffer), maxSize:=1);
      connection_state := STATE_CONNECTED;
      // Send instructions
      serSendString(port:=port, str:="Send r to read values, 1-4 to toggle output$N");
      serSendString(port:=port, str:="Send A-D to set output high, a-b to set output low$N");
 
   END_IF;
 
   IF connection_state = STATE_CONNECTED THEN
      RX();
      IF RX.ready THEN
         // Indicate a frame has been received, data is available in 'rxbuffer', length in 'RX.size'
         DebugFmt(message:="CMD: \1", v1:=rxbuffer);
         IF rxbuffer = 16#72 THEN
            // "r"
            serSendString(port:=port, str:=strFormat(format:="IN: \1,\2,\3,\4$N",v1:=INT(in[1]),v2:=INT(in[2]),v3:=INT(in[3]),v4:=INT(in[4])));
 
         END_IF;
         IF rxbuffer >= 16#31 AND rxbuffer<= 16#34 THEN
            // "1"-"4"
            // Toggle output
            out[rxbuffer-16#30]:=NOT out[rxbuffer-16#30];
         END_IF;
         IF rxbuffer >= 16#41 AND rxbuffer<= 16#44 THEN
            // "A"-"D"
            // Set output high
            out[rxbuffer-16#40]:= ON;
         END_IF;
         IF rxbuffer >= 16#61 AND rxbuffer<= 16#64 THEN
            // "a"-"d"
            // Set output low
            out[rxbuffer-16#60]:= OFF;
         END_IF;
         // Release the buffer for the receiver as we are now finished with the received data
         serFrameReceiveDone(port:=port);
      END_IF;
   END_IF;
END;
 
END_PROGRAM;