Radiocraft Wireless M-Bus extension module  2.18
example.vpl
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // example.vpl created 2018-01-19 10:01
3 //-----------------------------------------------------------------------------
4 INCLUDE rtcu.inc
5 
6 INCLUDE mbus.inc
7 
8 // Input variables that can be configured via the configuration dialog (These are global)
9 VAR_INPUT
10 END_VAR;
11 
12 // Output variables that can be configured via the configuration dialog (These are global)
13 VAR_OUTPUT
14 
15  AOUT : ARRAY[1 .. 4] OF INT; | Analog output
16 END_VAR;
17 
18 //-----------------------------------------------------------------------------
19 // DataToHex
20 //-----------------------------------------------------------------------------
21 FUNCTION DataToHex : STRING;
22 VAR_INPUT
23  data : PTR;
24  datasize : INT;
25  length : INT;
26  reverse : BOOL := FALSE;
27 END_VAR;
28 VAR
29  src : SINT;
30  v : INT;
31  i,j : INT;
32  str_len : INT;
33  bstr : STRING;
34 END_VAR;
35 
36 // copy src to tmp
37 str_len := 0;
38 FOR i := 0 TO (datasize-1) DO
39  // Copy contents of one memory area to another area
40  memcpy(dst:=ADDR(src), src:=(data + i), len:=1);
41  bstr := "";
42  FOR j := 0 TO 1 DO
43  v := SINT(src AND 16#0F);
44  src := shr8(in := src, n := 4);
45  CASE (v) OF
46  0..9: bstr := intToStr(v := v) + bstr;
47  10 : bstr := "A" + bstr;
48  11 : bstr := "B" + bstr;
49  12 : bstr := "C" + bstr;
50  13 : bstr := "D" + bstr;
51  14 : bstr := "E" + bstr;
52  15 : bstr := "F" + bstr;
53  END_CASE;
54 
55  str_len := str_len + 1;
56  IF (str_len >= 254) THEN
57  RETURN;
58  END_IF;
59  END_FOR;
60  IF reverse THEN
61  DataToHex := DataToHex + bstr;
62  ELSE
63  DataToHex := bstr + DataToHex;
64  END_IF;
65 END_FOR;
66 
67 // fill with '0'
68 WHILE ((str_len < 254) AND (str_len < length)) DO
69  IF reverse THEN
70  DataToHex := DataToHex + "0";
71  ELSE
72  DataToHex := "0" + DataToHex;
73  END_IF;
74  str_len := str_len + 1;
75 END_WHILE;
76 END_FUNCTION;
77 
78 //-----------------------------------------------------------------------------
79 // DintToHex2
80 //-----------------------------------------------------------------------------
81 FUNCTION dintToHex2 : STRING;
82 VAR_INPUT
83  v : DINT;
84  length : INT := 8;
85  reverse : BOOL := FALSE;
86 END_VAR;
87 dintToHex2 := DataToHex(data := ADDR(v), datasize:= SIZEOF(v), length := length, reverse := reverse);
88 END_FUNCTION;
89 
90 //-----------------------------------------------------------------------------
91 // IntToHex2
92 //-----------------------------------------------------------------------------
93 FUNCTION intToHex2 : STRING;
94 VAR_INPUT
95  v : INT;
96  length : INT := 4;
97  reverse : BOOL := FALSE;
98 END_VAR;
99 intToHex2 := DataToHex(data := ADDR(v), datasize:= SIZEOF(v), length := length, reverse := reverse);
100 END_FUNCTION;
101 
102 //-----------------------------------------------------------------------------
103 // SintToHex2
104 //-----------------------------------------------------------------------------
105 FUNCTION sintToHex2 : STRING;
106 VAR_INPUT
107  v : SINT;
108  length : INT := 2;
109  reverse : BOOL := FALSE;
110 END_VAR;
111 sintToHex2 := DataToHex(data := ADDR(v), datasize:= SIZEOF(v), length := length, reverse := reverse);
112 END_FUNCTION;
113 
114 //-----------------------------------------------------------------------------
115 // Converts the raw value to a string with the voltage
116 //-----------------------------------------------------------------------------
117 FUNCTION convData:STRING;
118 VAR_INPUT
119  data : PTR;
120 END_VAR;
121 VAR
122  val:DINT := 0;
123  v:FLOAT;
124 END_VAR;
125  // Copy raw value to DINT
126  memcpy(src:=data, dst:=ADDR(val), len:=3);
127  // convert raw value to voltage.
128  v := FLOAT(val) * 2.048*337.3/(exp2(v:=20.0)*67.3);
129  convData := strLeft(str:=floatToStr(v:=v), length := 5)+" V";
130 END_FUNCTION;
131 
132 //-----------------------------------------------------------------------------
133 // Get the three-letter manufaturer code from the raw number
134 //-----------------------------------------------------------------------------
135 FUNCTION convMan : STRING;
136 VAR_INPUT
137  man : INT;
138 END_VAR;
139 VAR
140  str:STRING;
141  data:ARRAY[1..3] OF SINT;
142 END_VAR;
143  data[1] := sinT(((man/(32*32))MOD 32)+64);
144  data[2] := sinT(((man/(32))MOD 32)+64);
145  data[3] := sinT(((man)MOD 32)+64);
146 
147  convMan := strFromMemory(src:=ADDR(data), len := 3);
148 END_FUNCTION;
149 
150 //-----------------------------------------------------------------------------
151 // Parse the ADC data and print the individual fields to the output.
152 //-----------------------------------------------------------------------------
153 FUNCTION ParseADC;
154 VAR_INPUT
155  data : PTR;
156 END_VAR;
157 VAR
158  vals:INT;
159  i:INT;
160  enc: INT;
161 END_VAR;
162  memcpy (src:=data+5, dst:=ADDR(enc),len:=2);
163 
164  DebugFmt(message := "ADC"
165  + ", A# " +DataToHex(data := data+1, datasize := 1, length := 2)
166  + ", St " +DataToHex(data := data+2, datasize := 1, length := 2)
167  + ", Sig " +DataToHex(data := data+3, datasize := 2, length := 4)
168  + ", enc " +intToHex2(v:=enc)
169  );
170  IF enc = 16#2f2f THEN
171  // Data is valid, print it
172  DebugFmt(message:="Data Type: "+DataToHex(data := data+7, datasize := 1, length := 2)
173  +", pVIF: "+DataToHex(data := data+8, datasize := 1, length := 2)
174  +", sVIF: "+DataToHex(data := data+9, datasize := 1, length := 2)
175  +", Value: "+DataToHex(data := data+10, datasize := 3, length := 6)
176  );
177  DebugFmt(message:="Val: "+convData(data:=data+10));
178  END_IF;
179 
180 END_FUNCTION;
181 
182 //-----------------------------------------------------------------------------
183 // Parse the ADC log data and print the individual fields to the output.
184 //-----------------------------------------------------------------------------
185 FUNCTION ParseLog;
186 VAR_INPUT
187  data : PTR;
188 END_VAR;
189 VAR
190  vals:INT;
191  i:INT;
192  enc: INT;
193 END_VAR;
194  memcpy (src:=data+6, dst:=ADDR(enc),len:=2);
195 
196  DebugFmt(message := "Log: "
197  + "Func "+DataToHex(data := data+1, datasize := 1, length := 2)
198  + ", A# " + DataToHex(data := data+2, datasize := 1, length := 2)
199  + ", St " + DataToHex(data := data+3, datasize := 1, length := 2)
200  + ", Sig " +DataToHex(data := data+4, datasize := 2, length := 4)
201  + ", enc " +intToHex2(v:=enc)
202  );
203 
204  IF enc = 16#2f2f THEN
205  DebugFmt(message:="His Type: "+DataToHex(data := data+8, datasize := 1, length := 2)
206  +", pVIF: "+DataToHex(data := data+9, datasize := 1, length := 2)
207  +", sVIF: "+DataToHex(data := data+10, datasize := 1, length := 2)
208  +", ValT: "+DataToHex(data := data+11, datasize := 1, length := 2)
209  +", Smpl: "+DataToHex(data := data+12, datasize := 3, length := 6)
210  );
211 
212  DebugFmt(message:=
213  "His#: "+DataToHex(data := data+15, datasize := 1, length := 2)
214  +", Time: "+DataToHex(data := data+16, datasize := 3, length := 6)
215  +", Part: "+DataToHex(data := data+19, datasize := 1, length := 2)
216  +", Vals: "+DataToHex(data := data+20, datasize := 1, length := 2)
217  );
218  memcpy(src := data+20, dst := ADDR(vals), len := 1);
219  DebugFmt(message:="vals: \1, "+DataToHex(data := ADDR(vals), datasize := 1, length := 2), v1:=vals);
220  for i := 0 to vals-1 DO
221  DebugFmt(message:=
222  " [\1]: "+DataToHex(data := data+21+i*6, datasize := 3, length :=6)
223  +", "+DataToHex(data := data+24+i*6, datasize := 3, length :=6)
224  +", "+convData(data:=data+24+i*6)
225  , v1 := i);
226 
227  END_FOR;
228  END_IF;
229 
230 END_FUNCTION;
231 
232 //-----------------------------------------------------------------------------
233 // The RTCU Application
234 //-----------------------------------------------------------------------------
235 PROGRAM mod_mbus;
236 VAR
237  sms : gsmIncomingSMS;
238  frame : mbusFrame;
239 
240  init : BOOL := TRUE;
241  path : STRING := MBUS_MODULE_PATH;
242  media : SINT := MBUS_MODULE_MEDIA;
243  rc : INT;
244  index : INT;
245 
246  pre : STRING;
247  cmd : STRING;
248  text : STRING;
249  tag : STRING;
250 
251  ci : SINT;
252  type : STRING;
253  key : ARRAY [1..16] OF SINT;
254  error_count : INT := 0;
255 END_VAR;
256 Sleep(delay := 1000);
257 DebugMsg(message := "booting");
258 
259 pre := strFormat(format := "MBUS(\1): ", v1 := thGetID());
260 DebugFmt(message := pre + "Started");
261 IF init THEN
262  init := FALSE;
263 
264  rc := mbusInit();
265  DebugFmt(message := pre + "init = \1", v1 := rc);
266  DebugMsg(message := "Extension: " + path);
267  FOR index := 1 TO 10 DO
268  // Read the name of a tag
269  rc:=extTagEnumerate(path:=path, index:=index, tag:=tag);
270  IF (rc = 1) THEN
271  // Read the text of a tag
272  rc := extTagRead(path:=path,tag:=tag,text:=text);
273  IF (rc = 1) THEN
274  DebugFmt(message := "[\1] : '" + strLeft(str := tag + "' ", length := 13) + "= '" + text + "'", v1 := index);
275  END_IF;
276  ELSIF (rc = -3) THEN
277  // No more tags
278  EXIT;
279  ELSE
280  DebugMsg(message := "Failed to show tags.");
281  END_IF;
282  END_FOR;
283 END_IF;
284 
285 DebugMsg(message := "ready");
286 
287 // Encryption key. It is normally unique for each slave.
288  key[1] := 16#00;
289  key[2] := 16#00;
290  key[3] := 16#00;
291  key[4] := 16#00;
292  key[5] := 16#00;
293  key[6] := 16#00;
294  key[7] := 16#00;
295  key[8] := 16#00;
296  key[9] := 16#00;
297  key[10] := 16#00;
298  key[11] := 16#00;
299  key[12] := 16#00;
300  key[13] := 16#00;
301  key[14] := 16#00;
302  key[15] := 16#00;
303  key[16] := 16#00;
304 
305 BEGIN
306  sms();
307  IF (sms.status > 0) THEN
308  DebugMsg(message := "SMS: '"+sms.message+"'");
309  FOR index := 1 TO 10 DO
310  // Extract a string from another delimited string
311  cmd := strToken(str:=sms.message, delimiter:=";", index:=index);
312  //DebugMsg(message := "cmd = '"+cmd+"'");
313  IF (cmd = "") THEN
314  EXIT;
315  ELSIF (cmd = "start") THEN
316  rc := mbusOpen(mode := MBUS_MODE_T1, RSSI:=ON, max_frames:=100, overwrite:=ON);
317  DebugFmt(message := "MBUS: open = \1", v1 := rc);
318 
319  ELSIF (cmd = "stop") THEN
320  rc := mbusClose();
321  DebugFmt(message := "MBUS: close = \1", v1 := rc);
322 
323  ELSIF (cmd = "lvl") THEN
324  rc := mbusGetBufferLevel();
325  DebugFmt(message := "MBUS: buffer level = \1", v1 := rc);
326 
327  ELSIF (cmd = "read") THEN
328  rc := mbusReceive(frame:=frame, type:=16#ff, timeout:=120000 );
329  IF (rc < 0) THEN
330  DebugFmt(message := pre + "failed to to fetch data (err \1)", v1 := rc);
331  error_count := error_count +1;
332  ELSIF (rc > 0) THEN
333  error_count := 0;
334  DebugFmt(message := "Man : "+ convMan(man:=frame.manufacturer)+" (" + intToHex2(v:=frame.manufacturer, reverse := false) + ")");
335  DebugFmt(message := "Received at: linsec \4", v4:=frame.linsec);
336  DebugFmt(message:="Length: \1, RSSI: \2 ("+floatToStr(v:=-FLOAT(frame.rssi) / 2.0)+" dB)", v1:=frame.length, v2:=frame.rssi);
337  CASE frame.type OF
338  16#19: type := "ADC"; // AD Converter
339  ELSE
340  type := "0x" + DataToHex(data := ADDR(frame.type), datasize := SIZEOF(frame.type), length := 2);
341  END_CASE;
342  DebugFmt(message := type + " : " + dintToHex2(v:=frame.id, reverse := false) + " => " +
343  DataToHex(data := ADDR(frame.data), datasize := frame.length, reverse := true));
344  if frame.type = 16#19 THEN
345  memcpy(dst:=ADDR(ci), src := ADDR(frame.data), len := 1);
346  DebugFmt(message :=
347  " CI-field: " + DataToHex(data := ADDR(ci), datasize := 1, length := 2));
348  case ci OF
349  122://16#7A as decimal
350  ParseADC(data := ADDR(frame.data));
351 
352  -83://16#AD as decimal
353  ParseLog(data := ADDR(frame.data));
354  ELSE
355  DebugFmt(message:="Unknown message");
356  END_CASE;
357  END_IF;
358  ELSE
359  DebugFmt(Message:="No elements in buffer");
360  END_IF;
361 
362  ELSIF (cmd = "send") THEN
363  index := INT(random(lower := -32768, upper := 32767));
364  rc := mbusSend(control := 16#44, data := ADDR(index), length := SIZEOF(index));
365  DebugFmt(message := "MBUS: send '" + intToHex2(v:=index) + "'= \1", v1 := rc);
366 
367  ELSIF (cmd = "ack") THEN
368  rc := mbusSend(control := 0, length := 0);
369  DebugFmt(message := "MBUS: ack = \1", v1 := rc);
370 
371  ELSIF (cmd = "info") THEN
372  rc := mbusInfo();
373  DebugFmt(message := "MBUS: info = \1", v1 := rc);
374 
375  ELSIF (cmd = "reset") THEN
376  DebugMsg(message := "resetting");
377  boardReset();
378  ELSIF (cmd = "reg") THEN
379  DebugMsg(message := "register sensors");
380 
381  rc := mbusRegisterSlave(idx := 1, manufacturer:=16#0646, id:=16#10000530, version:=1, type := 16#19, key := ADDR(key));
382  DebugFmt(message := "MBUS: reg = \1", v1 := rc);
383 
384  rc := mbusRegisterSlave(idx := 2, manufacturer:=16#0646, id:=16#20000530, version:=1, type := 16#19, key := ADDR(key));
385  DebugFmt(message := "MBUS: reg = \1", v1 := rc);
386 
387  ELSIF (cmd = "AOUT[2]") THEN
388  AOUT[2] := AOUT[2] + (1023/4);
389  IF (AOUT[2] > 1023) THEN AOUT[2] := 0; END_IF;
390 
391  ELSIF (cmd = "AOUT[1]") THEN
392  AOUT[1] := AOUT[1] + (1023/4);
393  IF (AOUT[1] > 1023) THEN AOUT[1] := 0; END_IF;
394 
395  END_IF;
396  END_FOR;
397  END_IF;
398 END;
399 DebugMsg(message := "stopped");
400 END_PROGRAM;