Examples - Thread Example

Top  Previous  Next

//-----------------------------------------------------------------------------
// thread example.vpl, created 2004-10-15 10:23
//
// Simple program to demonstrate the use of threads, mutexes and I-Button.
// The program creates 3 threads, 1 to read the GPS position and store it
// in persistent memory, 1 to read an I-Button and control I-Button LED and 1 to
// Parse incoming SMS messages.
// By using an I-Button or sending a SMS the program will monitor the 4 inputs
// and send a SMS when one of them is activated. The monitoring must restart
// before another alarm is sent.
// A tracking function is also included, to be activated by a SMS.
//
// The following SMS commands are supported:
//  OWI#,nnnnnnnnnnnn: Register an I-Button ID for validation. #=Index(1..5), nnnnn=I-Button ID
//  AON: Activate alarm monitoring
//  AOFF: Deactivate alarm monitoring
//  TON: Start tracking
//  TOFF: Stop tracking
//  POS: Get position
//  PHONEnnnnnnnn: Tracking and Alarm response phone number
//-----------------------------------------------------------------------------
INCLUDE rtcu.inc
 
VAR_INPUT
  in   : ARRAY[1..4] OF BOOL;
END_VAR;
 
VAR_OUTPUT
  led : BOOL;
END_VAR;
 
VAR
  AlarmState : BOOL := FALSE;
  TrackState : BOOL := FALSE;
 
  mxStateAl : MUTEX;
  mxStateTr : MUTEX;
 
  NextGps   : DINT;
END_VAR;
 
//----------------------------------------------------------------------------
// SetAlarm
// Set the state of the AlarmState flag.
//----------------------------------------------------------------------------
FUNCTION SetAlarm;
VAR_INPUT
  state : BOOL;
END_VAR;
  mxLock(mx:=mxStateAl);
     AlarmState := state;
  mxUnlock(mx:=mxStateAl);
END_FUNCTION;
//----------------------------------------------------------------------------
 
//----------------------------------------------------------------------------
// TestAlarm
// Test the state of the AlarmState flag.
//----------------------------------------------------------------------------
FUNCTION TestAlarm : BOOL;
  mxLock(mx:=mxStateAl);
     TestAlarm := AlarmState;
  mxUnlock(mx:=mxStateAl);
END_FUNCTION;
//----------------------------------------------------------------------------
 
//----------------------------------------------------------------------------
// SetTracking
// Set the state of the TrackState flag.
//----------------------------------------------------------------------------
FUNCTION SetTracking;
VAR_INPUT
  state : BOOL;
END_VAR;
  mxLock(mx:=mxStateTr);
     TrackState := state;
  mxUnlock(mx:=mxStateTr);
END_FUNCTION;
//----------------------------------------------------------------------------
 
//----------------------------------------------------------------------------
// TestTracking
// Test the state of the TrackState flag.
//----------------------------------------------------------------------------
FUNCTION TestTracking : BOOL;
  mxLock(mx:=mxStateTr);
     TestTracking := TrackState;
  mxUnlock(mx:=mxStateTr);
END_FUNCTION;
//----------------------------------------------------------------------------
 
//----------------------------------------------------------------------------
// SetId
// Register or Unregister an I-Button ID
//----------------------------------------------------------------------------
FUNCTION SetId;
VAR_INPUT
  index : INT;
  ID     : STRING;
END_VAR;
VAR
  oldIDs : STRING;
  newIDs : STRING;
  i     : INT;
END_VAR;
  // Verify index
  IF index > 0 AND index < 6 THEN
    // Read Registered IDs
     oldIDs := LoadStringF(index:=3);
    // Insert IDs before new
    IF index > 1 THEN
        FOR i := 1 TO index - 1 BY 1 DO
           newIDs := strConcat(str1:=newIDs,str2:=strToken(str:=oldIDs,delimiter:=",",index:=i));
           newIDs := strConcat(str1:=newIDs,str2:=",");
        END_FOR;
    END_IF;
    // Insert new ID
     newIDs := strConcat(str1:=newIDs,str2:=ID);
     newIDs := strConcat(str1:=newIDs,str2:=",");
    // Insert IDs after new
    IF index < 5 THEN
        FOR i := index + 1 TO 5 BY 1 DO
           newIDs := strConcat(str1:=newIDs,str2:=strToken(str:=oldIDs,delimiter:=",",index:=i));
           newIDs := strConcat(str1:=newIDs,str2:=",");
        END_FOR;
    END_IF;
    // Save Registered IDs
    SaveStringF(index:=3,str:=newIDs);
  END_IF;
END_FUNCTION;
//----------------------------------------------------------------------------
 
//----------------------------------------------------------------------------
// SendPos
// Sends the last position
//----------------------------------------------------------------------------
FUNCTION SendPos;
VAR_INPUT
  phone : STRING;
END_VAR;
VAR
  message : STRING;
END_VAR;
  // Retrieve last valid position from FRAM
  message := LoadStringF(index:=1);
  // Send position
  gsmSendSMS(phonenumber:=phone,message:=message);
END_FUNCTION;
//----------------------------------------------------------------------------
 
//----------------------------------------------------------------------------
// OWIBUTTON
// Thread that reads and validates I-Button IDs, for alarm activation/
// deactivation.
//----------------------------------------------------------------------------
THREAD_BLOCK OWIBUTTON;
VAR
  strID : STRING;
  Valid : BOOL;
  Count : INT := 0;
  Blink : INT := 0;
END_VAR;
  // Init
  OWiButtonEnableLED(enable:=TRUE);
  OWiButtonSetLED(state:=OFF);
  // Do forever
  WHILE TRUE DO
    // Read I-Button ID
     strID := OWiButtonGetID();
    // Is there an I-Button present?
    IF strLen(str:=strID) > 0 THEN
        // Reset timer
        Count := 20;
        Blink := 10;
        // Repetition?
        IF NOT Valid THEN
          // Lookup ID
          IF strFind(str1:=LoadStringF(index:=3),str2:=strID) > 0 THEN
              // Change alarm state
              SetAlarm( state := NOT TestAlarm() );
          END_IF;
          // I-Button has been read
          OWiButtonSetLED(state:=ON);
           Valid := TRUE;
        END_IF;
    ELSE
        Valid := FALSE;
        // Delay for I-Button removed from reader
        IF Count > 0 THEN
          // Delay
           Count := Count - 1;
          Sleep(delay:=100);
        // Is alarm survailance activated?
        ELSIF TestAlarm() THEN
          // Led := ON for 100 ms.
          IF Blink = 0 THEN
              // Reset timer
              Blink := 10;
              // Turn LED on
              OWiButtonSetLED(state:=ON);
          ELSIF Blink = 9 THEN
              // Turn LED off
              OWiButtonSetLED(state:=OFF);
          END_IF;
          // Delay
           Blink := Blink - 1;
          Sleep(delay:=100);
        ELSE
          OWiButtonSetLED(state:=OFF);
          Sleep(delay:=100);
        END_IF;
    END_IF;
  END_WHILE;
END_THREAD_BLOCK;
//----------------------------------------------------------------------------
 
//----------------------------------------------------------------------------
// GPS
// Thread that reads valid GPS positions and save them in FRAM
//----------------------------------------------------------------------------
THREAD_BLOCK GPS;
VAR
  gpspos   : gpsFix;
  str       : STRING;
END_VAR;
  // Init
  gpsPower(power:=ON);
  // Do forever
  WHILE TRUE DO
    // Get GPS position
     gpspos();
    // Valid Position?
    IF gpspos.mode > 1 THEN
        // String
        str := strFormat(format:="Time: \1.\2.\3, ",v1:=gpspos.day,v2:=gpspos.month,v3:=gpspos.year);
        str := strConcat(str1:=str,str2:=strFormat(format:="\1:\2:\3 ",v1:=gpspos.hour,v2:=gpspos.minute,v3:=gpspos.second));
        IF gpspos.latsouth THEN
           str := strConcat(str1:=str,str2:=strFormat(format:="Lat: S\1*\2.\3 ",v1:=gpspos.latdeg,v2:=gpspos.latmin,v3:=gpspos.latdecmin));
        ELSE        
           str := strConcat(str1:=str,str2:=strFormat(format:="Lat: N\1*\2.\3 ",v1:=gpspos.latdeg,v2:=gpspos.latmin,v3:=gpspos.latdecmin));
        END_IF;
        IF gpspos.lonwest THEN
           str := strConcat(str1:=str,str2:=strFormat(format:="Long: W\1*\2.\3 ",v1:=gpspos.londeg,v2:=gpspos.lonmin,v3:=gpspos.londecmin));
        ELSE        
           str := strConcat(str1:=str,str2:=strFormat(format:="Long: E\1*\2.\3 ",v1:=gpspos.londeg,v2:=gpspos.lonmin,v3:=gpspos.londecmin));
        END_IF;
        SaveStringF(index:=1,str:=str);
    END_IF;
    Sleep(delay:=1000);
  END_WHILE;
END_THREAD_BLOCK;
//----------------------------------------------------------------------------
 
//----------------------------------------------------------------------------
// SMS
// Thread that reads incoming SMS messages and executes commands
//----------------------------------------------------------------------------
THREAD_BLOCK SMS;
VAR
  incoming : gsmIncomingSMS;
END_VAR;
  // Init
  gsmPower(power:=ON);
  DebugMsg(message:="Ready to receive SMS");
  // Do forever
  WHILE TRUE DO
     incoming();
    // GSM connection status
     led := gsmConnected();
    // Check for incoming SMS
    IF incoming.status > 0 THEN
        DebugMsg(message:=strConcat(str1:="SMS recieved => ",str2:=strConcat(str1:=incoming.phonenumber,str2:=strConcat(str1:=",",str2:=incoming.message))));
        // Set I-Button ID
        IF strCompare(str1:="OWI",str2:=strLeft(str:=incoming.message,length:=3)) = 0 THEN
          // Insert new ID
           SetId( index := strToInt(str:=strMid(str:=incoming.message,start:=4,length:=1)), ID := strMid(str:=incoming.message,start:=6) );
          gsmSendSMS(phonenumber:=incoming.phonenumber,message:=strConcat(str1:=strMid(str:=incoming.message,start:=4,length:=1),
                                                                           str2:=strMid(str:=incoming.message,start:=6)));
      // Activate Alarm
        ELSIF strCompare(str1:="AON",str2:=incoming.message) = 0 THEN
          // Change alarm state
           SetAlarm(state:=ON);
          gsmSendSMS(phonenumber:=incoming.phonenumber,message:="Alarm=ON");
        // Deactivate Alarm
        ELSIF strCompare(str1:="AOFF",str2:=incoming.message) = 0 THEN
          // Change alarm state
           SetAlarm(state:=OFF);
          gsmSendSMS(phonenumber:=incoming.phonenumber,message:="Alarm=OFF");
        // Activate Tracking
        ELSIF strCompare(str1:="TON",str2:=incoming.message) = 0 THEN
          // synchronize tracking timer
           NextGps := clockNow();
          // Change tracking state
           SetTracking(state:=ON);
          gsmSendSMS(phonenumber:=incoming.phonenumber,message:="Tracking=ON");
        // Deactivate Tracking
        ELSIF strCompare(str1:="TOFF",str2:=incoming.message) = 0 THEN
          // Change tracking state
           SetTracking(state:=OFF);
          gsmSendSMS(phonenumber:=incoming.phonenumber,message:="Tracking=OFF");
        // Retrieve Position
        ELSIF strCompare(str1:="POS",str2:=incoming.message) = 0 THEN
          // Send last position
           SendPos(phone:=incoming.phonenumber);
        // Set reply phone number
        ELSIF strCompare(str1:="PHONE",str2:=strLeft(str:=incoming.message,length:=5)) = 0 THEN
          SaveStringF(index:=4,str:=strMid(str:=incoming.message,start:=6));
          gsmSendSMS(phonenumber:=incoming.phonenumber,message:=strConcat(str1:="Phone=",str2:=strMid(str:=incoming.message,start:=6)));
        END_IF;
    END_IF;
    Sleep(delay:=2000);
  END_WHILE;
END_THREAD_BLOCK;
//----------------------------------------------------------------------------
 
PROGRAM thread_example;
VAR
  thIbutton : OWIBUTTON;
  thGps     : GPS;
  thSms     : SMS;
 
  Valid     : BOOL;
END_VAR;
 
  // Init MUTEX
  DebugMsg(message:="Initializing Mutex");
  mxStateAl := mxInit();
  mxStateTr := mxInit();
  IF mxStatus(mx:=mxStateAl) = 1 THEN DebugMsg(message:="mxStateAl failed to init!"); END_IF;
  IF mxStatus(mx:=mxStateTr) = 1 THEN DebugMsg(message:="mxStateTr failed to init!"); END_IF;
 
  // Init THREAD
  DebugMsg(message:="Starting Threads");
  thIbutton();
  thGps();
  thSms();
  IF NOT thIbutton._running THEN DebugMsg(message:="thIbutton failed to start!"); END_IF;
  IF NOT thGps._running THEN DebugMsg(message:="thGps failed to start!"); END_IF;
  IF NOT thSms._running THEN DebugMsg(message:="thSms failed to start!"); END_IF;
 
BEGIN
  // Are we monitoring Alarm inputs?
  IF TestAlarm() THEN
    // Test alarm inputs
    IF (in[1] OR in[2] OR in[3] OR in[4]) AND NOT Valid THEN
        gsmSendSMS(phonenumber:=LoadStringF(index:=4),message:="ALARM!");
        Valid := TRUE;
    END_IF;
  ELSE
     Valid := FALSE;
  END_IF;
 
  // Are we tracking device?
  IF TestTracking() THEN
    // Time for next position?
    IF clockNow() >= NextGps THEN
        // Send last position
        SendPos(phone:=LoadStringF(index:=4));
        // Time for next position
        NextGps := clockNow() + 60; // 1 Min.
    END_IF;
  END_IF;
END;
 
END_PROGRAM;