|
//-----------------------------------------------------------------------------
// 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;
|