Examples - SNMP - Client

Top  Previous  Next

//-----------------------------------------------------------------------------
// LEDclient.vpl, created 2020-02-19 13:24
//
// This program demonstrates communication between two RTCU devices, where one
// is the manager (trap listener) and the other a client (publishing agent).
//
// To visualize the communication, the LEDs of both devices are manipulated
// by each other. The manager initiates by setting a pablished integer variable
// on the client, which then updates it's LEDs according to the value written,
// and then sends a trap to the manager, that updates it's LEDs accordingly and
// writes the next value to the other LED on the client, which again responds
// with a trap, which the manager uses to update it's LEDs with and so on.
//-----------------------------------------------------------------------------
INCLUDE rtcu.inc
 
// Use LAN1
#DEFINE SNMP_INTERFACE 2
 
// Exchange this with your real enterprise OID base.
#DEFINE ENTERPRISE_OID "1.3.6.1.4.1.65500."
 
// Put the actual IP address of the manager here.
#DEFINE MANAGER_IP "192.168.1.10" // example IP
 
// Configure the LEDs 1-4 in the job configuration manager
VAR_OUTPUT
  ledAgreen : BOOL; // LED 1
  ledAred   : BOOL; // LED 2
  ledBgreen : BOOL; // LED 3
  ledBred   : BOOL; // LED 4
END_VAR;
 
VAR
netInfo    : netGetInformation;
snmpvar    : snmpVariable;
trapvar    : snmpVariable;
iface      : SINT := SNMP_INTERFACE;
runthread  : BOOL := FALSE;
ledA       : INT;
ledB       : INT;
mancon     : SYSHANDLE;
rouser     : snmpUser;
rwuser     : snmpUser;
END_VAR;
 
FUNCTION authToStr : STRING;
VAR_INPUT
  auth : SINT;
END_VAR;
  CASE auth OF
    0 : authToStr := "";
    _SNMP_USM_MD5 : authToStr := "MD5";
    _SNMP_USM_SHA : authToStr := "SHA";
  ELSE
    authToStr := "Unknown???";
  END_CASE;
END_FUNCTION
 
FUNCTION encToStr : STRING;
VAR_INPUT
  enc : SINT;
END_VAR;
  CASE enc OF
    0 : encToStr := "";
    _SNMP_USM_AES : encToStr := "AES";
    _SNMP_USM_DES : encToStr := "DES";
  ELSE
    encToStr := "Unknown???";
  END_CASE;
END_FUNCTION
 
FUNCTION levelToStr : STRING;
VAR_INPUT
  level : SINT;
END_VAR;
  CASE level OF
    _SNMP_SEC_NONE : levelToStr := "None";
    _SNMP_SEC_AUTH : levelToStr := "AuthOnly";
    _SNMP_SEC_ENC  : levelToStr := "Auth+Enc";
  ELSE
    levelToStr := "Unknown???";
  END_CASE;
END_FUNCTION
 
FUNCTION printUSMUsersInfo;
VAR
  rc : INT;
END_VAR
rc := snmpAgentUsersGet(readonly:=rouser, writable:=rwuser);
DebugFmt(message:="snmpAgentUsersGet (rc=\1)", v1:=rc);
DebugMsg(message:="-----------------------------------------");
DebugMsg(message:="Read-Only user:");
DebugMsg(message:="-----------USM user profile--------------");
DebugMsg(message:="Username is  : "+rouser.username);
DebugMsg(message:="Auth is      : "+authToStr(auth:=rouser.authentication));
DebugMsg(message:="Auth pass is : "+rouser.password);
DebugMsg(message:="Enc is       : "+encToStr(enc:=rouser.encryption));
DebugMsg(message:="Cryptkey is  : "+rouser.cryptkey);
DebugMsg(message:="Sec level is : "+levelToStr(level:=rouser.level));
DebugMsg(message:="-----------------------------------------");
DebugMsg(message:="");
DebugMsg(message:="Read-Write capable user:");
DebugMsg(message:="-----------USM user profile--------------");
DebugMsg(message:="Username is  : "+rwuser.username);
DebugMsg(message:="Auth is      : "+authToStr(auth:=rwuser.authentication));
DebugMsg(message:="Auth pass is : "+rwuser.password);
DebugMsg(message:="Enc is       : "+encToStr(enc:=rwuser.encryption));
DebugMsg(message:="Cryptkey is  : "+rwuser.cryptkey);
DebugMsg(message:="Sec level is : "+levelToStr(level:=rwuser.level));
DebugMsg(message:="-----------------------------------------");
END_FUNCTION;
 
FUNCTION getledstring : STRING;
VAR_INPUT
  idx : SINT;
END_VAR;
VAR
  str: STRING;
END_VAR
CASE idx OF
  1 :
  IF ledAgreen THEN
    IF ledAred THEN
        str := "A is yellow";
    ELSE
        str := "A is green";
    END_IF;
  ELSE
    IF ledAred THEN
        str := "A is red";
    ELSE
        str := "A is off";
    END_IF;
  END_IF;
  2:
  IF ledBgreen THEN
    IF ledBred THEN
        str := "B is yellow";
    ELSE
        str := "B is green";
    END_IF;
  ELSE
    IF ledBred THEN
        str := "B is red";
    ELSE
        str := "B is off";
    END_IF;
  END_IF;
END_CASE;
getledstring := str;
END_FUNCTION;
 
FUNCTION updateLeds;
VAR_INPUT
  ledA : INT;
  ledB : INT;
END_VAR;
  CASE ledA OF
    0:
    ledAgreen := OFF;
    ledAred := OFF;
    1:
    ledAgreen := ON;
    ledAred := OFF;
    2:
    ledAgreen := OFF;
    ledAred := ON;
    3:
    ledAgreen := ON;
    ledAred := ON;
  END_CASE;
 
  CASE ledB OF
    0:
    ledBgreen := OFF;
    ledBred := OFF;
    1:
    ledBgreen := ON;
    ledBred := OFF;
    2:
    ledBgreen := OFF;
    ledBred := ON;
    3:
    ledBgreen := ON;
    ledBred := ON;
  END_CASE;
  UPDATEIO;
END_FUNCTION;
 
FUNCTION printNetInfo
netInfo(iface:=iface);
DebugFmt(message:="Network interface \1:", v1:=iface);
CASE netInfo.status OF
    0 : DebugMsg(message:="Interface is not present.");
    1 : DebugMsg(message:="Interface is not opened.");
    2 : DebugMsg(message:="Interface is not connected.");
    3 : DebugMsg(message:="Interface is connected.");
    4 : DebugMsg(message:="Interface link is up and waiting for IP configuration.");
ELSE
    DebugFmt(message:="Illegal net status? (\1)", v1:=netInfo.status);
END_CASE;
IF netInfo.status > 1 THEN
  DebugMsg(message:=" Phy addr " + netInfo.phy_addr);
  IF netInfo.dhcp THEN
      DebugMsg(message:=" Dynamic IP address");
  ELSE
      DebugMsg(message:=" Static IP address");
  END_IF;
  DebugMsg(message:=" IP addr " + sockIPToName(ip := netInfo.ip));
  DebugMsg(message:=" Mask    " + sockIPToName(ip := netInfo.subnetMask));
  DebugMsg(message:=" Gateway " + sockIPToName(ip := netInfo.gateway));
  IF netInfo.AutoDNS THEN
      DebugMsg(message:=" Automatic DNS");
  ELSE
      DebugMsg(message:=" Manual DNS");
  END_IF;
  DebugMsg(message:=" DNS1    " + sockIPToName(ip := netInfo.DNS1));
  DebugMsg(message:=" DNS2    " + sockIPToName(ip := netInfo.DNS2));
END_IF;
END_FUNCTION;
 
PROGRAM LEDclient;
VAR
  deleteuser : snmpUser;
  traphandle : SYSHANDLE;
  oid        : STRING;
  vars       : INT;
  eventtype  : USINT;
  rc         : INT;
  str        : STRING;
  ix         : SINT;
END_VAR;
ledAgreen := FALSE;
ledAred := FALSE;
ledBgreen := FALSE;
ledBred := FALSE;
ledA := 0;
ledB := 0;
UPDATEIO;
 
rc := netOpen(iface:=iface);
DebugFmt(message:="netOpen (rc=\1)",v1:=rc);
 
// Preemptively delete persistent users.
deleteuser.username := "";
FOR ix:=1 TO 25 DO
  snmpUserSet(index:=ix, user:=deleteuser);
END_FOR;
 
// Configure read-write user
rwuser.username := "roed";
rwuser.password := "deor1234";
rwuser.cryptkey := "a0b3d543";
rwuser.authentication := _SNMP_USM_MD5;
rwuser.encryption := _SNMP_USM_AES;
rwuser.level := _SNMP_SEC_ENC;
rwuser.engineid := "12345678900001030507";
 
// Set USM user with index 1
snmpUserSet(index:=1, user:=rwuser);
 
WHILE NOT netConnected(iface:=iface) DO
  Sleep(delay:=2000);
END_WHILE;
 
// Output network information
printNetInfo();
 
// Set USM users for the publishing agent
rc := snmpAgentUsersSet(writable:=rwuser, readonly:=rouser);
DebugFmt(message:="snmpAgentUsersSet (rc=\1)", v1:=rc);
 
// Output USM users for the publishing agent
printUSMUsersInfo();
 
// Setup connection to the manager
rc := snmpConnect(
                 handle:=mancon,
                host:=MANAGER_IP,
                port:=162,
                version:=_SNMP_VER_3,
                engineid := "12345678900001030507",
                usmuser:=ADDR(rwuser)
                );
DebugFmt(message:="snmpConnect (rc=\1)", v1:=rc);
 
// Start the publishing agent
rc := snmpStartAgent(
                    engineid := "a9382949f343be38",
                    dtls     := 0, // disable dtls as we use USM
                    secure   := TRUE // only allow secure connections
                   );
DebugFmt(message:="snmpStartAgent (rc=\1)", v1:=rc);
 
// Publish some variables
rc := snmpPublishInteger(v:=ledA, oid:=ENTERPRISE_OID + "1.1", subtype:=1, writable:=TRUE);
DebugFmt(message:="snmpPublishInteger (rc=\1)", v1:=rc);
rc := snmpPublishInteger(v:=ledB, oid:=ENTERPRISE_OID + "1.2", subtype:=1, writable:=TRUE);
DebugFmt(message:="snmpPublishInteger (rc=\1)", v1:=rc);
rc := snmpPublishString(v:=getledstring(idx:=1), oid:=ENTERPRISE_OID + "2.1", subtype:=0, writable:=TRUE);
DebugFmt(message:="snmpPublishString (rc=\1)", v1:=rc);
rc := snmpPublishString(v:=getledstring(idx:=2), oid:=ENTERPRISE_OID + "2.2", subtype:=0, writable:=TRUE);
DebugFmt(message:="snmpPublishString (rc=\1)", v1:=rc);
rc := snmpPublishTimeTicks(v:=boardTimeSinceReset(), oid:=ENTERPRISE_OID + "3", writable:=TRUE);
DebugFmt(message:="snmpPublishTimeTicks (rc=\1)", v1:=rc);
rc := snmpPublishOID(v:="1.3.6.4.1.5.333.32.2", oid:=ENTERPRISE_OID + "4", writable:=TRUE);
DebugFmt(message:="snmpPublishOID (rc=\1)", v1:=rc);
rc := snmpPublishIP(v:="192.168.1.255", oid:=ENTERPRISE_OID + "5", writable:=TRUE);
DebugFmt(message:="snmpPublishIP (rc=\1)", v1:=rc);
rc := snmpPublishFloat(v:=3.1416, oid:=ENTERPRISE_OID + "6", writable:=TRUE);
DebugFmt(message:="snmpPublishFloat (rc=\1)", v1:=rc);
rc := snmpPublishDouble(v:=3.14159265359, oid:=ENTERPRISE_OID + "7", writable:=TRUE);
DebugFmt(message:="snmpPublishDouble (rc=\1)", v1:=rc);
 
BEGIN
// Handle events
  rc := snmpWaitEvent(timeout:=-1, event:=eventtype, oid:=oid, vars:=vars);
  CASE eventtype OF
    _SNMP_EVENT_NOEVENT :
        CASE rc OF
            0: DebugMsg(message:="ERROR: The function is not supported!");
          -2: DebugMsg(message:="ERROR: Invalid input");
          -5: DebugMsg(message:="WARNING: Event buffer overflow.");
        ELSE
          DebugFmt(message:="ERROR: unknown return code from snmpReadEvent (rc=\1)", v1:=rc);
        END_CASE;
    _SNMP_EVENT_TIMEOUT :
    DebugMsg(message:="snmpWaitEvent: Timeout!");
    _SNMP_EVENT_TRAP :
    DebugMsg(message:="Trap received!");
    DebugMsg(message:="Trap oid is: " + oid);
    DebugFmt(message:="Vars to read : \1", v1:=vars);
    _SNMP_EVENT_SET :
    DebugMsg(message:="Set request received on OID " + oid);
  ELSE
    DebugFmt(message:="ERROR: snmpWaitEvent - unknown event type \1!", v1:=eventtype);
  END_CASE;
  rc := 0;
  WHILE NOT(rc = -11) DO
    rc := snmpGetNextVar(data:=snmpvar);
    CASE rc OF
      0: DebugMsg(message:="snmpGetNextVar: Function not implemented!");
      -2: DebugMsg(message:="Invalid parameter.");
      -9: DebugFmt(message:="Invalid variable type \1", v1:=snmpvar.type);
    -11: DebugMsg(message:="No more data available.");
      1: DebugFmt(message:="Type found is \1", v1:=snmpvar.type);
        CASE snmpvar.type OF
          1: DebugFmt(message:="TimeTicks received = \4", v4:=snmpvar.time_value);
          2: DebugFmt(message:="INTEGER received = \4", v4:=snmpvar.int_value);
          3: DebugFmt(message:="UNSIGNED INTEGER received = \4", v4:=snmpvar.uint_value);
          4: DebugFmt(message:="STRING received = " + snmpvar.str_value);
          5: DebugFmt(message:="Hex STRING received = " + snmpvar.hex_value);
          6: DebugFmt(message:="OID received = " + snmpvar.oid_value);
          7: DebugFmt(message:="IP Address received = " + snmpvar.ip_value);
          8: DebugFmt(message:="FLOAT received = " + floatToStr(v:=snmpvar.float_value) );
          9: DebugFmt(message:="DOUBLE received = " + doubleToStr(v:=snmpvar.double_value) );
        ELSE
          DebugFmt(message:="Unknown var type received : \1", v1:=snmpvar.type);
        END_CASE;
        DebugMsg(message:="Variable OID was : " + snmpvar.oid);
        IF strCompare(str1:=snmpvar.oid, str2:=ENTERPRISE_OID + "1.1") = 0 THEN
          ledA := INT(snmpvar.int_value);
          updateLeds(ledA:=ledA, ledB:=ledB);
          rc := snmpPublishString(v:=getledstring(idx:=1), oid:=ENTERPRISE_OID + "2.1", subtype:=0, writable:=TRUE);
          IF rc <> 1 THEN
              DebugFmt(message:="snmpPublishString error, rc=\1", v1:=rc);
          END_IF;
          rc := snmpcreateTrap(trap:=traphandle, oid:=ENTERPRISE_OID + "100", uptime:=100);
          trapvar.type := 2;
          trapvar.oid:=ENTERPRISE_OID + "100.1";
          trapvar.int_value := snmpvar.int_value;
          rc := snmpAddTrapVariable(trap:=traphandle, data:=trapvar);
          IF rc <> 1 THEN
              DebugFmt(message:="snmpAddTrapVariable error, rc=\1", v1:=rc);
          END_IF;
          rc := snmpSendTrap(trap:=traphandle, connection:=mancon);
          IF rc <> 1 THEN
              DebugFmt(message:="Sending of trap failed (rc=\1)", v1:=rc);
          ELSE
              DebugFmt(message:="Successfully sendt trap!", v1:=rc);
          END_IF;
          rc := snmpDestroyTrap(trap:=traphandle);
          IF rc <> 1 THEN
              DebugFmt(message:="snmpDestroyTrap failed (rc=\1)", v1:=rc);
          END_IF;
        END_IF;
        IF strCompare(str1:=snmpvar.oid, str2:=ENTERPRISE_OID + "1.2") = 0 THEN
          ledB := INT(snmpvar.int_value);
          updateLeds(ledA:=ledA, ledB:=ledB);
          rc := snmpPublishString(v:=getledstring(idx:=2), oid:=ENTERPRISE_OID + "2.2", subtype:=0, writable:=TRUE);
          IF rc <> 1 THEN
              DebugFmt(message:="snmpPublishString error, rc=\1", v1:=rc);
          END_IF;
          rc := snmpcreateTrap(trap:=traphandle, oid:=ENTERPRISE_OID + "101", uptime:=boardTimeSinceReset());
          trapvar.type := 2;
          trapvar.oid:=ENTERPRISE_OID + "100.2";
          trapvar.int_value := snmpvar.int_value;
          rc := snmpAddTrapVariable(trap:=traphandle, data:=trapvar);
          IF rc <> 1 THEN
              DebugFmt(message:="snmpAddTrapVariable error, rc=\1", v1:=rc);
          END_IF;
          rc := snmpSendTrap(trap:=traphandle, connection:=mancon);
          IF rc <> 1 THEN
              DebugFmt(message:="Sending of trap failed (rc=\1)", v1:=rc);
          ELSE
              DebugFmt(message:="Successfully sendt trap!", v1:=rc);
          END_IF;
          rc := snmpDestroyTrap(trap:=traphandle);
          IF rc <> 1 THEN
              DebugFmt(message:="snmpDestroyTrap failed (rc=\1)", v1:=rc);
          END_IF;
        END_IF;
    ELSE
        DebugFmt(message:="snmpGetNextVar (rc=\1)", v1:=rc);
    END_CASE;
  END_WHILE;
END;
END_PROGRAM;