1 //-----------------------------------------------------------------------------
2 // example.vpl created 2018-01-19 10:01
3 //-----------------------------------------------------------------------------
5 // Uncomment math.inc to add math library support.
10 // Input variables that can be configured via the configuration dialog (These are global)
14 // Output variables that can be configured via the configuration dialog (These are global)
17 AOUT : ARRAY[1 .. 4] OF INT; | Analog output
20 //-----------------------------------------------------------------------------
22 //-----------------------------------------------------------------------------
23 FUNCTION DataToHex : STRING;
28 reverse : BOOL := FALSE;
40 FOR i := 0 TO (datasize-1) DO
41 // Copy contents of one memory area to another area
42 memcpy(dst:=ADDR(src), src:=(data + i), len:=1);
45 v := SINT(src AND 16#0F);
46 src := shr8(in := src, n := 4);
48 0..9: bstr := intToStr(v := v) + bstr;
49 10 : bstr := "A" + bstr;
50 11 : bstr := "B" + bstr;
51 12 : bstr := "C" + bstr;
52 13 : bstr := "D" + bstr;
53 14 : bstr := "E" + bstr;
54 15 : bstr := "F" + bstr;
57 str_len := str_len + 1;
58 IF (str_len >= 254) THEN
63 DataToHex := DataToHex + bstr;
65 DataToHex := bstr + DataToHex;
70 WHILE ((str_len < 254) AND (str_len < length)) DO
72 DataToHex := DataToHex + "0";
74 DataToHex := "0" + DataToHex;
76 str_len := str_len + 1;
80 //-----------------------------------------------------------------------------
82 //-----------------------------------------------------------------------------
83 FUNCTION DintToHex : STRING;
87 reverse : BOOL := FALSE;
89 DintToHex := DataToHex(data := ADDR(v), datasize:= SIZEOF(v), length := length, reverse := reverse);
92 //-----------------------------------------------------------------------------
94 //-----------------------------------------------------------------------------
95 FUNCTION IntToHex : STRING;
99 reverse : BOOL := FALSE;
101 IntToHex := DataToHex(data := ADDR(v), datasize:= SIZEOF(v), length := length, reverse := reverse);
104 //-----------------------------------------------------------------------------
106 //-----------------------------------------------------------------------------
107 FUNCTION SintToHex : STRING;
111 reverse : BOOL := FALSE;
113 SintToHex := DataToHex(data := ADDR(v), datasize:= SIZEOF(v), length := length, reverse := reverse);
116 //-----------------------------------------------------------------------------
117 // Converts the raw value to a string with the voltage
118 //-----------------------------------------------------------------------------
119 FUNCTION convData:STRING;
127 // Copy raw value to DINT
128 memcpy(src:=data, dst:=ADDR(val), len:=3);
129 // convert raw value to voltage.
130 v := FLOAT(val) * 2.048*337.3/(exp2(v:=20.0)*67.3);
131 convData := strLeft(str:=floatToStr(v:=v), length := 5)+" V";
134 //-----------------------------------------------------------------------------
135 // Get the three-letter manufaturer code from the raw number
136 //-----------------------------------------------------------------------------
137 FUNCTION convMan : STRING;
143 data:ARRAY[1..3] OF SINT;
145 data[1] := sinT(((man/(32*32))MOD 32)+64);
146 data[2] := sinT(((man/(32))MOD 32)+64);
147 data[3] := sinT(((man)MOD 32)+64);
149 convMan := strFromMemory(src:=ADDR(data), len := 3);
152 //-----------------------------------------------------------------------------
153 // Parse the ADC data and print the individual fields to the output.
154 //-----------------------------------------------------------------------------
164 memcpy (src:=data+5, dst:=ADDR(enc),len:=2);
166 DebugFmt(message := "ADC"
167 + ", A# " +DataToHex(data := data+1, datasize := 1, length := 2)
168 + ", St " +DataToHex(data := data+2, datasize := 1, length := 2)
169 + ", Sig " +DataToHex(data := data+3, datasize := 2, length := 4)
170 + ", enc " +IntToHex(v:=enc)
172 IF enc = 16#2f2f THEN
173 // Data is valid, print it
174 DebugFmt(message:="Data Type: "+DataToHex(data := data+7, datasize := 1, length := 2)
175 +", pVIF: "+DataToHex(data := data+8, datasize := 1, length := 2)
176 +", sVIF: "+DataToHex(data := data+9, datasize := 1, length := 2)
177 +", Value: "+DataToHex(data := data+10, datasize := 3, length := 6)
179 DebugFmt(message:="Val: "+convData(data:=data+10));
184 //-----------------------------------------------------------------------------
185 // Parse the ADC log data and print the individual fields to the output.
186 //-----------------------------------------------------------------------------
196 memcpy (src:=data+6, dst:=ADDR(enc),len:=2);
198 DebugFmt(message := "Log: "
199 + "Func "+DataToHex(data := data+1, datasize := 1, length := 2)
200 + ", A# " + DataToHex(data := data+2, datasize := 1, length := 2)
201 + ", St " + DataToHex(data := data+3, datasize := 1, length := 2)
202 + ", Sig " +DataToHex(data := data+4, datasize := 2, length := 4)
203 + ", enc " +IntToHex(v:=enc)
206 IF enc = 16#2f2f THEN
207 DebugFmt(message:="His Type: "+DataToHex(data := data+8, datasize := 1, length := 2)
208 +", pVIF: "+DataToHex(data := data+9, datasize := 1, length := 2)
209 +", sVIF: "+DataToHex(data := data+10, datasize := 1, length := 2)
210 +", ValT: "+DataToHex(data := data+11, datasize := 1, length := 2)
211 +", Smpl: "+DataToHex(data := data+12, datasize := 3, length := 6)
215 "His#: "+DataToHex(data := data+15, datasize := 1, length := 2)
216 +", Time: "+DataToHex(data := data+16, datasize := 3, length := 6)
217 +", Part: "+DataToHex(data := data+19, datasize := 1, length := 2)
218 +", Vals: "+DataToHex(data := data+20, datasize := 1, length := 2)
220 memcpy(src := data+20, dst := ADDR(vals), len := 1);
221 DebugFmt(message:="vals: \1, "+DataToHex(data := ADDR(vals), datasize := 1, length := 2), v1:=vals);
222 for i := 0 to vals-1 DO
224 " [\1]: "+DataToHex(data := data+21+i*6, datasize := 3, length :=6)
225 +", "+DataToHex(data := data+24+i*6, datasize := 3, length :=6)
226 +", "+convData(data:=data+24+i*6)
234 //-----------------------------------------------------------------------------
235 // Wireless MBUS monitor thread
236 //-----------------------------------------------------------------------------
237 THREAD_BLOCK tbMbusCollector;
239 run : MUTABLE BOOL := TRUE;
240 init : MUTABLE BOOL := TRUE; // load extension module upon start
241 echo : BOOL := FALSE; // echo received data
250 error_count : INT := 0;
252 pre := strFormat(format := "MBUS(\1): ", v1 := thGetID());
253 DebugFmt(message := pre + "Started");
257 rc := mbusInit(showTags := TRUE);
258 DebugFmt(message := pre + "init = \1", v1 := rc);
261 rc := mbusOpen(mode := MBUS_MODE_T1, RSSI:=ON);
262 DebugFmt(message := pre + "open = \1", v1 := rc);
263 // Receive data from all sensors, also sensors that are not configured
264 rc := mbusSetFilter(installed:=FALSE);
265 DebugFmt(message := pre + "set filter = \1", v1 := rc);
268 DebugMsg(message := pre + "received frames are echo'ed");
271 DebugFmt(message := pre + "Running");
273 rc := mbusReceive(frame := frame);
275 DebugFmt(message := pre + "failed to to fetch data (err \1)", v1 := rc);
276 error_count := error_count +1;
277 if error_count > 3 THEN
282 DebugFmt(message := "Man : "+ convMan(man:=frame.manufacturer)+" (" + intToHex(v:=frame.manufacturer, reverse := false) + ")");
283 DebugFmt(message:="Length: \1, RSSI: \2 ("+floatToStr(v:=-FLOAT(frame.rssi) / 2.0)+" dB)", v1:=frame.length, v2:=frame.rssi);
285 16#19: type := "ADC"; // AD Converter
287 type := "0x" + DataToHex(data := ADDR(frame.type), datasize := SIZEOF(frame.type), length := 2);
289 DebugFmt(message := type + " : " + DintToHex(v:=frame.id, reverse := false) + " => " +
290 DataToHex(data := ADDR(frame.data), datasize := frame.length, reverse := true));
291 if frame.type = 16#19 THEN
292 memcpy(dst:=ADDR(ci), src := ADDR(frame.data), len := 1);
294 " CI-field: " + DataToHex(data := ADDR(ci), datasize := 1, length := 2));
296 122://16#7A as decimal
297 ParseADC(data := ADDR(frame.data));
299 -83://16#AD as decimal
300 ParseLog(data := ADDR(frame.data));
302 DebugFmt(message:="Unknown message");
308 //mbusSend(control := frame.control, data := ADDR(frame.data), length := frame.length);
314 DebugFmt(message := pre + "Stopping");
317 DebugFmt(message := pre + "close = \1", v1 := rc);
319 DebugFmt(message := pre + "Stopped");
322 //-----------------------------------------------------------------------------
323 // The RTCU Application
324 //-----------------------------------------------------------------------------
327 collector : tbMbusCollector;
328 sms : gsmIncomingSMS;
337 key : ARRAY [1..16] OF SINT;
339 Sleep(delay := 1000);
340 DebugMsg(message := "booting");
342 collector.run := TRUE;
344 DebugMsg(message := "ready");
346 // Encryption key. It is normally unique for each slave.
366 IF (sms.status > 0) THEN
367 DebugMsg(message := "SMS: '"+sms.message+"'");
368 FOR index := 1 TO 10 DO
369 // Extract a string from another delimited string
370 cmd := strToken(str:=sms.message, delimiter:=";", index:=index);
371 //DebugMsg(message := "cmd = '"+cmd+"'");
374 ELSIF (cmd = "collect") THEN
375 collector.run := NOT collector.run;
377 ELSIF (cmd = "open") THEN
379 DebugFmt(message := "MBUS: open = \1", v1 := rc);
381 ELSIF (cmd = "close") THEN
383 DebugFmt(message := "MBUS: close = \1", v1 := rc);
385 ELSIF (cmd = "send") THEN
386 index := INT(random(lower := -32768, upper := 32767));
387 rc := mbusSend(control := 16#44, data := ADDR(index), length := SIZEOF(index));
388 DebugFmt(message := "MBUS: send '" + intToHex(v:=index) + "'= \1", v1 := rc);
390 ELSIF (cmd = "ack") THEN
391 rc := mbusSend(control := 0, length := 0);
392 DebugFmt(message := "MBUS: ack = \1", v1 := rc);
394 ELSIF (cmd = "info") THEN
396 DebugFmt(message := "MBUS: info = \1", v1 := rc);
398 ELSIF (cmd = "reset") THEN
399 DebugMsg(message := "resetting");
401 ELSIF (cmd = "reg") THEN
402 DebugMsg(message := "register sensors");
404 rc := mbusRegisterSlave(idx := 1, manufacturer:=16#0646, id:=16#10000530, version:=1, type := 16#19, key := ADDR(key));
405 DebugFmt(message := "MBUS: reg = \1", v1 := rc);
407 rc := mbusRegisterSlave(idx := 2, manufacturer:=16#0646, id:=16#20000530, version:=1, type := 16#19, key := ADDR(key));
408 DebugFmt(message := "MBUS: reg = \1", v1 := rc);
410 ELSIF (cmd = "AOUT[2]") THEN
411 AOUT[2] := AOUT[2] + (1023/4);
412 IF (AOUT[2] > 1023) THEN AOUT[2] := 0; END_IF;
414 ELSIF (cmd = "AOUT[1]") THEN
415 AOUT[1] := AOUT[1] + (1023/4);
416 IF (AOUT[1] > 1023) THEN AOUT[1] := 0; END_IF;
422 IF collector.run AND NOT collector._running THEN
426 DebugMsg(message := "stopped");