Ver código fonte

bacnetmstp: initial BACnet MS/TP implementation

This driver is implemented as a singleton due to it's reliance on the
bacnet-stack implementation.  This implementation does not currently
support multiple BACnet networks at the same time, though in the
future it might, depending on the future of bacnet-stack development.
The version of bacnet-stack used in developing this driver was 0.8.3.

This driver is not intended to be used directly by end users, rather
it is intended for UPM drivers supporting specific BACnet devices,
such as the Veris E50H5 Energy Meter.

Unfortunately, this means that a process can only support a single
RS-485 BACnet network, though you can support multiple devices on that
network.

No examples are provided.  Please look at the E50HX driver for an
example of how to use this class in a BACnet MS/TP device driver if
you want to write one.

When initialized, the bacnet-stack library will attach to your RS-485
based BACnet network, and start a Master Finite State Machine (FSM) in
a separate thread.  This thread will handle the details of token
passing and locating other Masters in the network (Poll For Master).

This driver will appear as a BACnet Master device on the BACnet
network, which supports only the required Device Object and any
required services (readProp) and Device Object properties.

When initializing the driver, it is important to select a Device
Object Instance ID that is unique on your BACnet network.  This is the
unique identifier that will be used to identify your Master to the
rest of the BACnet network.

In addition, it may take some time after initialization before you
will be able to communicate on the network, as the first thing that
has to happen is that all Masters on the network need to be identified
(handled by the Master FSM) and a token needs to be received before
your Master can begin transmitting (making requests).  This may take a
couple of minutes on a large network.

You can speed this process up by specifying a maxMaster (to
initMaster()) that is smaller than the default (127) -- but only if
you are CERTAIN that there are no masters with a MAC address higher
than the value you choose.  If you fail to follow this rule, you may
introduce hard to identify token passing problems on the network for
yourself and other BACnet Masters.

Currently, this driver only supports the readProperty and
writeProperty requests to other BACnet devices.  In addition, array
property reading and writing is not currently supported.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
Jon Trulson 8 anos atrás
pai
commit
c7b5204fe4

+ 24
- 0
src/bacnetmstp/CMakeLists.txt Ver arquivo

@@ -0,0 +1,24 @@
1
+set (libname "bacnetmstp")
2
+set (libdescription "upm driver module for BACnet MS/TP devices")
3
+set (module_src ${libname}.cxx device-client.c)
4
+set (module_h ${libname}.h)
5
+
6
+pkg_search_module(BACNET libbacnet)
7
+if (BACNET_FOUND)
8
+  set (reqlibname "libbacnet")
9
+  include_directories(${BACNET_INCLUDE_DIRS})
10
+  upm_module_init()
11
+  add_dependencies(${libname} ${BACNET_LIBRARIES})
12
+  target_link_libraries(${libname} ${BACNET_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
13
+  if (BUILDSWIG)
14
+    if (BUILDSWIGNODE)
15
+      swig_link_libraries (jsupm_${libname} ${BACNET_LIBRARIES} ${MRAA_LIBRARIES} ${NODE_LIBRARIES})
16
+    endif()
17
+    if (BUILDSWIGPYTHON)
18
+      swig_link_libraries (pyupm_${libname} ${BACNET_LIBRARIES} ${PYTHON_LIBRARIES} ${MRAA_LIBRARIES})
19
+    endif()
20
+    if (BUILDSWIGJAVA)
21
+        swig_link_libraries (javaupm_${libname} ${BACNET_LIBRARIES} ${MRAAJAVA_LDFLAGS} ${JAVA_LDFLAGS})
22
+    endif()
23
+  endif()
24
+endif ()

+ 880
- 0
src/bacnetmstp/bacnetmstp.cxx Ver arquivo

@@ -0,0 +1,880 @@
1
+/*
2
+ * Author: Jon Trulson <jtrulson@ics.com>
3
+ * Copyright (c) 2016 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+
25
+#include <unistd.h>
26
+#include <iostream>
27
+#include <stdexcept>
28
+#include <string>
29
+#include <sstream>
30
+
31
+#include "bacnetmstp.h"
32
+#include "handlers.h"
33
+#include "client.h"
34
+#include "txbuf.h"
35
+#include "mstpdef.h"
36
+
37
+using namespace upm;
38
+using namespace std;
39
+
40
+// our singleton instance
41
+BACNETMSTP* BACNETMSTP::m_instance = 0;
42
+
43
+BACNETMSTP::BACNETMSTP()
44
+{
45
+  // set defaults here
46
+  m_maxInfoFrames = DEFAULT_MAX_INFO_FRAMES;
47
+  m_maxMaster = DEFAULT_MAX_MASTER;
48
+  m_baudRate = 38400;
49
+  m_macAddr = DEFAULT_MAX_MASTER;
50
+
51
+  m_initialized = false;
52
+
53
+  // 60 sec, for MS/TP
54
+  m_adpuTimeoutMS = 60000;
55
+
56
+  m_deviceInstanceID = BACNET_MAX_INSTANCE;
57
+
58
+  memset(m_rxBuffer, 0, MAX_MPDU);
59
+
60
+  m_returnedValue = {0};
61
+  m_targetAddress = {0};
62
+  m_invokeID = 0;
63
+  m_errorDetected = false;
64
+
65
+  setDebug(false);
66
+}
67
+
68
+BACNETMSTP::~BACNETMSTP()
69
+{
70
+  if (m_initialized)
71
+    datalink_cleanup();
72
+}
73
+
74
+void BACNETMSTP::setDebug(bool enable)
75
+{
76
+  m_debugging = enable;
77
+}
78
+
79
+void BACNETMSTP::clearErrors()
80
+{
81
+  m_errorType = BACERR_TYPE_NONE;
82
+
83
+  // empty out all of our error/reject/abort info
84
+  m_rejectReason = REJECT_REASON_OTHER;
85
+  m_rejectString.clear();
86
+
87
+  m_abortReason = ABORT_REASON_OTHER;
88
+  m_abortString.clear();
89
+
90
+  m_errorClass = ERROR_CLASS_DEVICE;
91
+  m_errorCode = ERROR_CODE_OTHER;
92
+  m_errorString.clear();
93
+
94
+  m_upmErrorString.clear();
95
+}
96
+
97
+void BACNETMSTP::handlerError(BACNET_ADDRESS* src,
98
+                              uint8_t invoke_id,
99
+                              BACNET_ERROR_CLASS error_class,
100
+                              BACNET_ERROR_CODE error_code)
101
+{
102
+  if (instance()->m_debugging)
103
+    cerr << __FUNCTION__ << ": entered" << endl;
104
+
105
+  if (address_match(&(instance()->m_targetAddress), src) &&
106
+      (invoke_id == instance()->m_invokeID))
107
+    {
108
+      instance()->m_errorType = BACERR_TYPE_ERROR;
109
+      instance()->m_errorClass = error_class;
110
+      instance()->m_errorCode = error_code;
111
+      instance()->m_errorString =
112
+        bactext_error_class_name((int)error_class)
113
+        + string(": ") + bactext_error_code_name((int)error_code);
114
+
115
+      instance()->m_errorDetected = true;
116
+  }
117
+}
118
+
119
+void BACNETMSTP::handlerAbort(BACNET_ADDRESS* src,
120
+                              uint8_t invoke_id,
121
+                              uint8_t abort_reason,
122
+                              bool server)
123
+{
124
+  (void)server; // not used
125
+
126
+  if (instance()->m_debugging)
127
+    cerr << __FUNCTION__ << ": entered" << endl;
128
+
129
+  if (address_match(&(instance()->m_targetAddress), src) &&
130
+      (invoke_id == instance()->m_invokeID))
131
+    {
132
+      instance()->m_errorType = BACERR_TYPE_ABORT;
133
+      instance()->m_abortReason = abort_reason;
134
+      instance()->m_abortString =
135
+        bactext_abort_reason_name((int)abort_reason);
136
+
137
+      instance()->m_errorDetected = true;
138
+    }
139
+}
140
+
141
+void BACNETMSTP::handlerReject(BACNET_ADDRESS* src,
142
+                               uint8_t invoke_id,
143
+                               uint8_t reject_reason)
144
+{
145
+  if (instance()->m_debugging)
146
+    cerr << __FUNCTION__ << ": entered" << endl;
147
+
148
+  if (address_match(&(instance()->m_targetAddress), src) &&
149
+      (invoke_id == instance()->m_invokeID))
150
+    {
151
+      instance()->m_errorType = BACERR_TYPE_REJECT;
152
+      instance()->m_rejectReason = reject_reason;
153
+      instance()->m_rejectString =
154
+        bactext_reject_reason_name((int)reject_reason);
155
+
156
+      instance()->m_errorDetected = true;
157
+    }
158
+}
159
+
160
+void BACNETMSTP::handlerReadPropertyAck(uint8_t* service_request,
161
+                                        uint16_t service_len,
162
+                                        BACNET_ADDRESS* src,
163
+                                        BACNET_CONFIRMED_SERVICE_ACK_DATA* service_data)
164
+{
165
+  int len = 0;
166
+  BACNET_READ_PROPERTY_DATA data;
167
+
168
+  if (address_match(&(instance()->m_targetAddress), src) &&
169
+      (service_data->invoke_id == instance()->m_invokeID))
170
+    {
171
+      if (instance()->m_debugging)
172
+        cerr << __FUNCTION__ << ": got readProp ack" << endl;
173
+
174
+      len = rp_ack_decode_service_request(service_request, service_len,
175
+                                          &data);
176
+      // FIXME: we don't currently handle arrays (len < service_len)
177
+      if (len > 0)
178
+        {
179
+          bacapp_decode_application_data(data.application_data,
180
+                                         data.application_data_len,
181
+                                         &(instance()->m_returnedValue));
182
+        }
183
+      else
184
+        {
185
+          // shouldn't happen?
186
+          cerr << __FUNCTION__ << ": decode app data failed" << endl;
187
+        }
188
+    }
189
+}
190
+
191
+void BACNETMSTP::handlerWritePropertyAck(BACNET_ADDRESS* src,
192
+                                         uint8_t invoke_id)
193
+{
194
+  if (address_match(&(instance()->m_targetAddress), src) &&
195
+      (invoke_id == instance()->m_invokeID))
196
+    {
197
+      if (instance()->m_debugging)
198
+        cerr << __FUNCTION__ << ": got writeProp ack" << endl;
199
+    }
200
+}
201
+
202
+void BACNETMSTP::initServiceHandlers()
203
+{
204
+  // this is in device-client.c
205
+  Device_Init(NULL);
206
+
207
+  // These are service requests we must handle from other masters
208
+
209
+  // we need to handle who-is to support dynamic device binding to us
210
+  apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
211
+
212
+  // handle i-am to support binding to other devices
213
+  apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, handler_i_am_bind);
214
+
215
+  // set the handler for all the services we don't implement
216
+
217
+  // It is required to send the proper reject message...
218
+  apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
219
+
220
+  // we must implement read property (it's required)
221
+  apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
222
+                             handler_read_property);
223
+
224
+  // These are related to requests we make
225
+
226
+  // handle the data coming back from confirmed readProp requests
227
+  apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY,
228
+                                 handlerReadPropertyAck);
229
+
230
+  // handle the simple ack for confirmed writeProp requests
231
+  apdu_set_confirmed_simple_ack_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
232
+                                        handlerWritePropertyAck);
233
+
234
+  // handle any errors coming back
235
+  apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, handlerError);
236
+  apdu_set_abort_handler(handlerAbort);
237
+  apdu_set_reject_handler(handlerReject);
238
+}
239
+
240
+BACNETMSTP* BACNETMSTP::instance()
241
+{
242
+  if (!m_instance)
243
+    m_instance = new BACNETMSTP;
244
+
245
+  return m_instance;
246
+}
247
+
248
+void BACNETMSTP::initMaster(std::string port, int baudRate,
249
+                            int deviceInstanceID, int macAddr, int maxMaster,
250
+                            int maxInfoFrames)
251
+{
252
+  // first some checking
253
+
254
+  // if we are already initialized, then it's too late to change things now
255
+  if (m_initialized)
256
+    {
257
+      if (m_debugging)
258
+        cerr << __FUNCTION__ << ": Instance is already initialized, ignored."
259
+             << endl;
260
+      return;
261
+    }
262
+
263
+  // baudrate
264
+  // The standard allows (as of at least 2010) the following baud rates
265
+  if ( !(baudRate == 9600 || baudRate == 19200 || baudRate == 38400
266
+         || baudRate == 57600 || baudRate == 76800 || baudRate == 115200) )
267
+    {
268
+      throw std::invalid_argument(std::string(__FUNCTION__)
269
+                                  + ": baudRate must be 9600, 19200, 38400, "
270
+                                  + " 57600, 76800, or 115200");
271
+    }
272
+
273
+  // maxMaster
274
+  // maxMaster must be less than or equal to 127
275
+  if (maxMaster < 0 || maxMaster > DEFAULT_MAX_MASTER)
276
+    {
277
+      throw std::out_of_range(std::string(__FUNCTION__)
278
+                              + ": maxMaster must be between 0 and "
279
+                              + std::to_string(DEFAULT_MAX_MASTER));
280
+    }
281
+
282
+  // As a master ourselves, we must have a MAC address also within the
283
+  // constraints of maxMaster
284
+  if (macAddr < 0 || macAddr > DEFAULT_MAX_MASTER)
285
+    {
286
+      throw std::out_of_range(std::string(__FUNCTION__)
287
+                              + ": macAddr must be between 0 and "
288
+                              + std::to_string(DEFAULT_MAX_MASTER));
289
+    }
290
+
291
+  // this should be unique on the network
292
+  if (deviceInstanceID >= BACNET_MAX_INSTANCE)
293
+    {
294
+      throw std::out_of_range(std::string(__FUNCTION__)
295
+                              + ": deviceInstanceID must be less than "
296
+                              + std::to_string(BACNET_MAX_INSTANCE)
297
+                              + ", and must be unique on the network");
298
+    }
299
+
300
+  m_port = port;
301
+  m_baudRate = baudRate;
302
+  m_maxInfoFrames = maxInfoFrames;
303
+  m_macAddr = macAddr;
304
+  m_maxMaster = maxMaster;
305
+  m_deviceInstanceID = deviceInstanceID;
306
+
307
+  // Let the fun begin...
308
+
309
+  // setup our info
310
+  Device_Set_Object_Instance_Number(m_deviceInstanceID);
311
+  address_init();
312
+
313
+  initServiceHandlers();
314
+
315
+  dlmstp_set_max_info_frames(m_maxInfoFrames);
316
+  dlmstp_set_max_master(m_maxMaster);
317
+  dlmstp_set_baud_rate(m_baudRate);
318
+  dlmstp_set_mac_address(m_macAddr);
319
+
320
+  // FIXME - allow to change?
321
+  apdu_timeout_set(m_adpuTimeoutMS);
322
+
323
+  // Ordinarily, I'd like to check the return value of this function,
324
+  // but even in the face of errors, it always returns true :( This
325
+  // function starts the ball rolling, and initializes the Master FSM
326
+  // thread.  Unfortunately, it doesn't appear this can be turned back
327
+  // off without exiting the application.
328
+  datalink_init((char *)port.c_str());
329
+
330
+  m_initialized = true;
331
+}
332
+
333
+bool BACNETMSTP::dispatchRequest()
334
+{
335
+  uint16_t pdu_len = 0;
336
+  unsigned timeout = 100;     // milliseconds
337
+  unsigned max_apdu = 0;
338
+  time_t elapsed_seconds = 0;
339
+  time_t last_seconds = 0;
340
+  time_t current_seconds = 0;
341
+  time_t timeout_seconds = 0;
342
+  bool found = false;
343
+
344
+  // address where message came from
345
+  BACNET_ADDRESS src = {0};
346
+
347
+  clearErrors();
348
+  m_errorDetected = false;
349
+
350
+  uint32_t targetDeviceInstanceID = BACNET_MAX_INSTANCE;
351
+
352
+  switch (m_command.cmd)
353
+    {
354
+    case BACCMD_READ_PROPERTY:
355
+      targetDeviceInstanceID = m_command.readPropArgs.targetDeviceInstanceID;
356
+      break;
357
+
358
+    case BACCMD_WRITE_PROPERTY:
359
+      targetDeviceInstanceID = m_command.writePropArgs.targetDeviceInstanceID;
360
+      break;
361
+
362
+    case BACCMD_NONE:
363
+      {
364
+        m_errorType = BACERR_TYPE_UPM;
365
+        m_upmErrorString = string(__FUNCTION__) +
366
+          ": called with BACCMD_NONE, ignoring";
367
+
368
+        return true; // error
369
+      }
370
+
371
+      break;
372
+
373
+    default:
374
+      {
375
+        // should this throw?
376
+        m_errorType = BACERR_TYPE_UPM;
377
+        m_upmErrorString = string(__FUNCTION__) +
378
+          ": internal error, called with unknown command, ignoring";
379
+
380
+        return true; // error
381
+      }
382
+
383
+      break;
384
+    }
385
+
386
+  // timeouts
387
+  last_seconds = time(NULL);
388
+  timeout_seconds = (apdu_timeout() / 1000) * apdu_retries();
389
+
390
+  // we use 0 to indicate that request hasn't been made yet, so that
391
+  // it will be made once the address is bound.
392
+  m_invokeID = 0;
393
+
394
+  // bind to the device first.
395
+  found = address_bind_request(targetDeviceInstanceID, &max_apdu,
396
+                               &(instance()->m_targetAddress));
397
+
398
+  if (!found)
399
+    {
400
+      if (m_debugging)
401
+        cerr << __FUNCTION__ << ": Address not found, Sending WhoIs..." << endl;
402
+
403
+      Send_WhoIs(targetDeviceInstanceID, targetDeviceInstanceID);
404
+    }
405
+  else
406
+    {
407
+      if (m_debugging)
408
+        cerr << __FUNCTION__ << ": Address was found" << endl;
409
+    }
410
+
411
+  // loop until either we get our data, an error occurs, or we timeout
412
+  while (true)
413
+    {
414
+      current_seconds = time(NULL);
415
+
416
+      // at least one second has passed
417
+      if (current_seconds != last_seconds)
418
+        tsm_timer_milliseconds((uint16_t) ((current_seconds -
419
+                                            last_seconds) * 1000));
420
+      if (m_errorDetected)
421
+        break;
422
+
423
+      // we have to wait until the address is bound before proceeding
424
+      if (!found)
425
+        {
426
+          found =
427
+            address_bind_request(targetDeviceInstanceID, &max_apdu,
428
+                                 &(instance()->m_targetAddress));
429
+        }
430
+
431
+      if (found)
432
+        {
433
+          // address is bound, and we have not sent our request yet.  Make it so.
434
+          if (m_invokeID == 0)
435
+            {
436
+              switch (m_command.cmd)
437
+                {
438
+                case BACCMD_READ_PROPERTY:
439
+                  m_invokeID =
440
+                    Send_Read_Property_Request(targetDeviceInstanceID,
441
+                                               m_command.readPropArgs.objType,
442
+                                               m_command.readPropArgs.objInstance,
443
+                                               m_command.readPropArgs.objProperty,
444
+                                               m_command.readPropArgs.arrayIndex);
445
+                  if (m_debugging)
446
+                    cerr << __FUNCTION__
447
+                         << ": Called Send_Read_Property_Request(), m_invokeID = "
448
+                         << (int)m_invokeID << endl;
449
+
450
+                  break;
451
+
452
+                case BACCMD_WRITE_PROPERTY:
453
+                  m_invokeID =
454
+                    Send_Write_Property_Request(targetDeviceInstanceID,
455
+                                                m_command.writePropArgs.objType,
456
+                                                m_command.writePropArgs.objInstance,
457
+                                                m_command.writePropArgs.objProperty,
458
+                                                m_command.writePropArgs.propValue,
459
+                                                m_command.writePropArgs.propPriority,
460
+                                                m_command.writePropArgs.arrayIndex);
461
+                  if (m_debugging)
462
+                    cerr << __FUNCTION__
463
+                         << ": Called Send_Write_Property_Request(), m_invokeID = "
464
+                         << (int)m_invokeID << endl;
465
+
466
+                  break;
467
+                }
468
+
469
+            }
470
+          else if (tsm_invoke_id_free(m_invokeID))
471
+            {
472
+              // transaction completed successfully
473
+
474
+              if (m_debugging)
475
+                cerr << __FUNCTION__ << ": Success, m_invokeID = "
476
+                     << (int)m_invokeID << endl;
477
+
478
+              break;
479
+            }
480
+          else if (tsm_invoke_id_failed(m_invokeID))
481
+            {
482
+              // transaction state machine failed, most likely timeout
483
+              tsm_free_invoke_id(m_invokeID);
484
+
485
+              m_errorType = BACERR_TYPE_UPM;
486
+              m_upmErrorString = string(__FUNCTION__) +
487
+                ": TSM Timed Out.";
488
+
489
+              if (m_debugging)
490
+                cerr << m_upmErrorString << endl;
491
+
492
+              m_errorDetected = true;
493
+
494
+              break;
495
+            }
496
+        }
497
+      else
498
+        {
499
+          // still waiting to bind.  timeout if we've waited too long.
500
+          elapsed_seconds += (current_seconds - last_seconds);
501
+          if (elapsed_seconds > timeout_seconds)
502
+            {
503
+              m_errorType = BACERR_TYPE_UPM;
504
+              m_upmErrorString = string(__FUNCTION__) +
505
+                ": Timed out waiting to bind address.";
506
+
507
+              // We output this error unconditionally as this is an
508
+              // error you will get if you supply a non-existant
509
+              // Device Obeject Instance ID.
510
+
511
+              cerr << m_upmErrorString << endl;
512
+              cerr << __FUNCTION__
513
+                   << ": Did you supply the correct Device Object Instance ID "
514
+                   << "for your device?"
515
+                   << endl;
516
+
517
+              m_errorDetected = true;
518
+              break;
519
+            }
520
+        }
521
+
522
+      // returns 0 bytes on timeout
523
+      pdu_len = datalink_receive(&src, m_rxBuffer, MAX_MPDU, timeout);
524
+
525
+      // process the packet if valid.  This will call our handlers as needed.
526
+      if (pdu_len)
527
+        npdu_handler(&src, m_rxBuffer, pdu_len);
528
+
529
+      // keep track of time for next check
530
+      last_seconds = current_seconds;
531
+    }
532
+
533
+  return m_errorDetected;
534
+}
535
+
536
+bool BACNETMSTP::readProperty(uint32_t targetDeviceInstanceID,
537
+                              BACNET_OBJECT_TYPE objType,
538
+                              uint32_t objInstance,
539
+                              BACNET_PROPERTY_ID objProperty,
540
+                              uint32_t arrayIndex)
541
+{
542
+  // some sanity checking...
543
+  if (objInstance >= BACNET_MAX_INSTANCE)
544
+    {
545
+      throw std::out_of_range(std::string(__FUNCTION__)
546
+                              + ": objInstance must be less than "
547
+                              + std::to_string(BACNET_MAX_INSTANCE));
548
+    }
549
+
550
+  // fill in the command structure and dispatch
551
+  m_command.cmd = BACCMD_READ_PROPERTY;
552
+  m_command.readPropArgs.targetDeviceInstanceID = targetDeviceInstanceID;
553
+  m_command.readPropArgs.objType = objType;
554
+  m_command.readPropArgs.objInstance = objInstance;
555
+  m_command.readPropArgs.objProperty = objProperty;
556
+  m_command.readPropArgs.arrayIndex = arrayIndex; // not implemented in the ack handler!
557
+
558
+  if (m_debugging)
559
+    cerr << __FUNCTION__  << ": calling dispatchRequest()..." << endl;
560
+
561
+  // send it off
562
+  bool error = dispatchRequest();
563
+
564
+  // clear the command to avoid accidental re-calls
565
+  m_command.cmd = BACCMD_NONE;
566
+
567
+  return error;
568
+}
569
+
570
+bool BACNETMSTP::writeProperty(uint32_t targetDeviceInstanceID,
571
+                               BACNET_OBJECT_TYPE objType,
572
+                               uint32_t objInstance,
573
+                               BACNET_PROPERTY_ID objProperty,
574
+                               BACNET_APPLICATION_DATA_VALUE* propValue,
575
+                               uint8_t propPriority,
576
+                               int32_t arrayIndex)
577
+{
578
+  // some sanity checking...
579
+  if (objInstance >= BACNET_MAX_INSTANCE)
580
+    {
581
+      throw std::out_of_range(std::string(__FUNCTION__)
582
+                              + ": objInstance must be less than "
583
+                              + std::to_string(BACNET_MAX_INSTANCE));
584
+    }
585
+
586
+  // fill in the command structure and dispatch
587
+  m_command.cmd = BACCMD_WRITE_PROPERTY;
588
+  m_command.writePropArgs.targetDeviceInstanceID = targetDeviceInstanceID;
589
+  m_command.writePropArgs.objType = objType;
590
+  m_command.writePropArgs.objInstance = objInstance;
591
+  m_command.writePropArgs.objProperty = objProperty;
592
+  m_command.writePropArgs.propValue = propValue;
593
+  m_command.writePropArgs.propPriority = propPriority;
594
+  m_command.writePropArgs.arrayIndex = arrayIndex; // not implemented!
595
+
596
+  if (m_debugging)
597
+    cerr << __FUNCTION__  << ": calling dispatchRequest()..." << endl;
598
+
599
+  // send it off
600
+  bool error = dispatchRequest();
601
+
602
+  // clear the command to avoid accidental re-calls
603
+  m_command.cmd = BACCMD_NONE;
604
+
605
+  return error;
606
+}
607
+
608
+BACNET_APPLICATION_DATA_VALUE BACNETMSTP::getData()
609
+{
610
+  return m_returnedValue;
611
+}
612
+
613
+uint8_t BACNETMSTP::getDataType()
614
+{
615
+  return m_returnedValue.tag;
616
+}
617
+
618
+float BACNETMSTP::getDataTypeReal()
619
+{
620
+  if (getDataType() == BACNET_APPLICATION_TAG_REAL)
621
+    return m_returnedValue.type.Real;
622
+  else
623
+    {
624
+      if (m_debugging)
625
+        cerr << __FUNCTION__ << ": Not of Real type, trying to convert..." << endl;
626
+
627
+      // try to convert or throw
628
+      switch (getDataType())
629
+        {
630
+        case BACNET_APPLICATION_TAG_BOOLEAN:
631
+          return (getDataTypeBoolean() ? 1.0 : 0.0);
632
+        case BACNET_APPLICATION_TAG_UNSIGNED_INT:
633
+          return float(getDataTypeUnsignedInt());
634
+        case BACNET_APPLICATION_TAG_SIGNED_INT:
635
+          return float(getDataTypeSignedInt());
636
+        default:
637
+          throw std::invalid_argument(std::string(__FUNCTION__)
638
+                                      + ": data type ("
639
+                                      + std::to_string(int(getDataType()))
640
+                                      + ") is not convertible to Real");
641
+        }
642
+    }
643
+}
644
+
645
+bool BACNETMSTP::getDataTypeBoolean()
646
+{
647
+  if (getDataType() == BACNET_APPLICATION_TAG_BOOLEAN)
648
+    return ((m_returnedValue.type.Boolean) ? true : false);
649
+  else
650
+    throw std::invalid_argument(std::string(__FUNCTION__)
651
+                                + ": data type ("
652
+                                + std::to_string(int(getDataType()))
653
+                                + ") is not convertible to Bool");
654
+}
655
+
656
+unsigned int BACNETMSTP::getDataTypeUnsignedInt()
657
+{
658
+  if (getDataType() == BACNET_APPLICATION_TAG_UNSIGNED_INT)
659
+    return m_returnedValue.type.Unsigned_Int;
660
+  else
661
+    throw std::invalid_argument(std::string(__FUNCTION__)
662
+                                + ": data type ("
663
+                                + std::to_string(int(getDataType()))
664
+                                + ") is not convertible to UnsignedInt");
665
+}
666
+
667
+int BACNETMSTP::getDataTypeSignedInt()
668
+{
669
+  if (getDataType() == BACNET_APPLICATION_TAG_SIGNED_INT)
670
+    return m_returnedValue.type.Signed_Int;
671
+  else
672
+    throw std::invalid_argument(std::string(__FUNCTION__)
673
+                                + ": data type ("
674
+                                + std::to_string(int(getDataType()))
675
+                                + ") is not convertible to SignedInt");
676
+}
677
+
678
+#if defined(BACAPP_DOUBLE)
679
+double BACNETMSTP::getDataTypeDouble()
680
+{
681
+  if (getDataType() == BACNET_APPLICATION_TAG_DOUBLE)
682
+    return m_returnedValue.type.Double;
683
+  else
684
+    {
685
+      if (m_debugging)
686
+        cerr << __FUNCTION__ << ": Not of Double type, trying to convert..." << endl;
687
+
688
+      // try to convert or throw
689
+      switch (getDataType())
690
+        {
691
+        case BACNET_APPLICATION_TAG_REAL:
692
+          return double(getDataTypeReal());
693
+        case BACNET_APPLICATION_TAG_BOOLEAN:
694
+          return (getDataTypeBoolean() ? 1.0 : 0.0);
695
+        case BACNET_APPLICATION_TAG_UNSIGNED_INT:
696
+          return double(getDataTypeUnsignedInt());
697
+        case BACNET_APPLICATION_TAG_SIGNED_INT:
698
+          return double(getDataTypeSignedInt());
699
+        default:
700
+          throw std::invalid_argument(std::string(__FUNCTION__)
701
+                                      + ": data type ("
702
+                                      + std::to_string(int(getDataType()))
703
+                                      + ") is not convertible to Double");
704
+        }
705
+    }
706
+}
707
+#endif // BACAPP_DOUBLE
708
+
709
+unsigned int BACNETMSTP::getDataTypeEnum()
710
+{
711
+  if (getDataType() == BACNET_APPLICATION_TAG_ENUMERATED)
712
+    return m_returnedValue.type.Enumerated;
713
+  else
714
+    throw std::invalid_argument(std::string(__FUNCTION__)
715
+                                + ": data type ("
716
+                                + std::to_string(int(getDataType()))
717
+                                + ") is not convertible to Enum");
718
+}
719
+
720
+std::string BACNETMSTP::getDataTypeString()
721
+{
722
+  string retval;
723
+
724
+  // Here, we can try to accomodate all the types
725
+  switch(getDataType())
726
+    {
727
+    case BACNET_APPLICATION_TAG_REAL:
728
+      retval = std::to_string(getDataTypeReal());
729
+      break;
730
+
731
+#if defined(BACAPP_DOUBLE)
732
+    case BACNET_APPLICATION_TAG_DOUBLE:
733
+      retval = std::to_string(getDataTypeDouble());
734
+      break;
735
+#endif // BACAPP_DOUBLE
736
+
737
+    case BACNET_APPLICATION_TAG_UNSIGNED_INT:
738
+      retval = std::to_string(getDataTypeUnsignedInt());
739
+      break;
740
+
741
+    case BACNET_APPLICATION_TAG_SIGNED_INT:
742
+      retval = std::to_string(getDataTypeSignedInt());
743
+      break;
744
+
745
+    case BACNET_APPLICATION_TAG_BOOLEAN:
746
+      retval = (getDataTypeBoolean() ? string("true") : string("false"));
747
+      break;
748
+
749
+    case BACNET_APPLICATION_TAG_CHARACTER_STRING:
750
+      retval = string(characterstring_value(&m_returnedValue.type.Character_String),
751
+
752
+                      characterstring_length(&m_returnedValue.type.Character_String));
753
+      break;
754
+
755
+    case BACNET_APPLICATION_TAG_OCTET_STRING:
756
+      {
757
+        string tmpstr((char *)octetstring_value(&m_returnedValue.type.Octet_String),
758
+
759
+                      octetstring_length(&m_returnedValue.type.Octet_String));
760
+        retval = string2HexString(tmpstr);
761
+      }
762
+
763
+      break;
764
+
765
+    case BACNET_APPLICATION_TAG_BIT_STRING:
766
+      {
767
+        int len = bitstring_bits_used(&m_returnedValue.type.Bit_String);
768
+
769
+        for (int i=0; i<len; i++)
770
+          {
771
+            if (bitstring_bit(&m_returnedValue.type.Bit_String, uint8_t(i)))
772
+              retval += "1";
773
+            else
774
+              retval += "0";
775
+
776
+            if (i != 0 && ((i % 8) == 0))
777
+              retval += " ";
778
+          }
779
+      }
780
+
781
+      break;
782
+
783
+    default:
784
+      throw std::invalid_argument(std::string(__FUNCTION__)
785
+                                  + ": data type ("
786
+                                  + std::to_string(int(getDataType()))
787
+                                  + ") is not convertible to String");
788
+      break;
789
+    }
790
+
791
+  return retval;
792
+}
793
+
794
+BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataReal(float value)
795
+{
796
+  BACNET_APPLICATION_DATA_VALUE data;
797
+
798
+  memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
799
+
800
+  data.tag = BACNET_APPLICATION_TAG_REAL;
801
+  data.type.Real = value;
802
+
803
+  return data;
804
+}
805
+
806
+BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataBool(bool value)
807
+{
808
+  BACNET_APPLICATION_DATA_VALUE data;
809
+
810
+  memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
811
+
812
+  data.tag = BACNET_APPLICATION_TAG_BOOLEAN;
813
+  data.type.Boolean = value;
814
+
815
+  return data;
816
+}
817
+
818
+BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataSignedInt(int value)
819
+{
820
+  BACNET_APPLICATION_DATA_VALUE data;
821
+
822
+  memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
823
+
824
+  data.tag = BACNET_APPLICATION_TAG_SIGNED_INT;
825
+  data.type.Signed_Int = value;
826
+
827
+  return data;
828
+}
829
+
830
+BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataUnsignedInt(unsigned int value)
831
+{
832
+  BACNET_APPLICATION_DATA_VALUE data;
833
+
834
+  memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
835
+
836
+  data.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT;
837
+  data.type.Unsigned_Int = value;
838
+
839
+  return data;
840
+}
841
+
842
+BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataString(string value)
843
+{
844
+  if (value.size() > (MAX_CHARACTER_STRING_BYTES - 1))
845
+    {
846
+      throw std::invalid_argument(std::string(__FUNCTION__)
847
+                                  + ": value must be less than or equal to "
848
+                                  + std::to_string(MAX_CHARACTER_STRING_BYTES - 1)
849
+                                  + " characters long");
850
+    }
851
+
852
+  BACNET_APPLICATION_DATA_VALUE data;
853
+
854
+  memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
855
+
856
+  data.tag = BACNET_APPLICATION_TAG_CHARACTER_STRING;
857
+
858
+  characterstring_init_ansi(&data.type.Character_String, value.c_str());
859
+
860
+  return data;
861
+}
862
+
863
+
864
+string BACNETMSTP::string2HexString(string input)
865
+{
866
+  static const char* const lut = "0123456789abcdef";
867
+  size_t len = input.size();
868
+
869
+  string output;
870
+  output.reserve(3 * len);
871
+  for (size_t i = 0; i < len; ++i)
872
+    {
873
+      const unsigned char c = input[i];
874
+      output.push_back(lut[c >> 4]);
875
+      output.push_back(lut[c & 15]);
876
+      output.push_back(' ');
877
+    }
878
+
879
+  return output;
880
+}

+ 716
- 0
src/bacnetmstp/bacnetmstp.h Ver arquivo

@@ -0,0 +1,716 @@
1
+/*
2
+ * Author: Jon Trulson <jtrulson@ics.com>
3
+ * Copyright (c) 2016 Intel Corporation.
4
+ *
5
+ * Permission is hereby granted, free of charge, to any person obtaining
6
+ * a copy of this software and associated documentation files (the
7
+ * "Software"), to deal in the Software without restriction, including
8
+ * without limitation the rights to use, copy, modify, merge, publish,
9
+ * distribute, sublicense, and/or sell copies of the Software, and to
10
+ * permit persons to whom the Software is furnished to do so, subject to
11
+ * the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be
14
+ * included in all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ */
24
+#pragma once
25
+
26
+#include <string>
27
+
28
+// we only support a BACnet RS-485 MS/TP datalink
29
+#define BACDL_MSTP 1
30
+#undef BACDL_ALL
31
+
32
+// get a variety of bacnet-stack includes...
33
+#include "bacdef.h"
34
+#include "config.h"
35
+#include "bactext.h"
36
+#include "bacerror.h"
37
+#include "iam.h"
38
+#include "arf.h"
39
+#include "tsm.h"
40
+#include "address.h"
41
+#include "npdu.h"
42
+#include "apdu.h"
43
+#include "device.h"
44
+#include "datalink.h"
45
+#include "whois.h"
46
+#include "mstpdef.h"
47
+#include "dlmstp.h"
48
+
49
+
50
+namespace upm {
51
+
52
+  /**
53
+   * @brief BACNETMSTP base class
54
+   * @defgroup bacnetmstp libupm-bacnetmstp
55
+   * @ingroup uart
56
+   */
57
+
58
+  /**
59
+   * @library bacnetmstp
60
+   * @sensor bacnetmstp
61
+   * @comname UPM API for BACNET MS/TP communications
62
+   * @con uart
63
+   * @web http://bacnet.sourceforge.net/
64
+   * @brief UPM API for BACNETMSTP
65
+   *
66
+   * This is a singleton class that provides services to UPM BACnet
67
+   * drivers (like E50HX) based on the bacnet-stack at
68
+   * http://bacnet.sourceforge.net .  This class is implemented as a
69
+   * singleton due to the fact that the bacnet-stack implementation
70
+   * does not currently allow multiple simultaneous datalinks.  We are
71
+   * using 0.8.3 of bacnet-stack.  In the future this restriction may
72
+   * be lifted depending on bacnet-stack, but for now, you are
73
+   * stuck with only a single BACnet MS/TP datalink.
74
+   *
75
+   * This driver is not intended to be used by end users.  It is
76
+   * intended for use with other UPM drivers that require access to a
77
+   * BACnet MS/TP (Master Slave/Token Passing) network over RS-485.
78
+   *
79
+   * For this reason, no examples are provided.  If you wish to
80
+   * implement your own BACnet MS/TP driver, please look at the E50HX
81
+   * driver to see how this class can be used.
82
+   *
83
+   * Currently, only readProperty and writeProperty BACnet requests
84
+   * are supported.  In the future, any other BACnet requests could be
85
+   * supported as well.  readProperty and writeProperty should provide
86
+   * most of what you will need when communicating with BACnet
87
+   * devices.  Since the source code is open, feel free to add other
88
+   * services as you see fit :)
89
+   *
90
+   * In order to make requests over an MS/TP network, you must be a
91
+   * BACnet master.  initMaster() is responsible for configuring your
92
+   * underlying RS-485 network and starting a Master FSM (finite state
93
+   * machine) thread that will be responsible for identifying other
94
+   * Masters on the network and negotiating token passing.  Your
95
+   * master can only transmit when it has the token.
96
+   *
97
+   * Fortunately, all of these messy details are handled for you by
98
+   * this class, or the underlying bacnet-stack library this class
99
+   * relies on.
100
+
101
+   */
102
+
103
+  class BACNETMSTP {
104
+    // Constructor and destructor are protected
105
+
106
+  public:
107
+
108
+    // error types
109
+    typedef enum {
110
+      BACERR_TYPE_NONE                = 0,
111
+      BACERR_TYPE_REJECT,
112
+      BACERR_TYPE_ABORT,
113
+      BACERR_TYPE_ERROR,
114
+      BACERR_TYPE_UPM
115
+    } BACERR_TYPE_T;
116
+
117
+    // command types we currently support
118
+    typedef enum {
119
+      BACCMD_NONE                     = 0,
120
+      BACCMD_READ_PROPERTY,
121
+      BACCMD_WRITE_PROPERTY
122
+    } BACCMD_TYPE_T;
123
+
124
+    /**
125
+     * Get our singleton instance, initializing it if neccessary.  All
126
+     * requests to this class should be done through this instance
127
+     * accessor.
128
+     *
129
+     * @return static pointer to our class instance
130
+     */
131
+    static BACNETMSTP* instance();
132
+
133
+    /**
134
+     * This function initializes the underlying BACNETMSTP Master
135
+     * singleton in the event it has not already been initialized.  If
136
+     * the BACNETMSTP Master singleton has already been initialized,
137
+     * then this call will be ignored.  There can be only one.
138
+     *
139
+     * @param port The serial port that the RS-485 interface is
140
+     * connected to.
141
+     * @param baudRate The baudrate of the RS-485 interface.  All
142
+     * devices on a BACnet RS-485 bus must run at the same baudrate.
143
+     * Valid values are 9600, 19200, 38400, 57600, 76800, and 115200.
144
+     * @param deviceInstanceNumber This is the unique Device Object
145
+     * Instance number that will be used for our BACnet Master in
146
+     * order to communicate over the BACnet interface.  This number
147
+     * must be between 1-4194302 and must be unique on the BACnet
148
+     * network.
149
+     * @param macAddr This is the MAC address of our BACnet Master.
150
+     * It must be unique on the BACnet segment, and must be between
151
+     * 1-127.
152
+     * @param maxMaster This specifies to our Master the maximum MAC
153
+     * address used by any other Masters on the BACnet network.  This
154
+     * must be between 1-127, the default is 127.  Do not change this
155
+     * unless you know what you are doing or you could introduce
156
+     * token passing errors on the BACnet network.
157
+     * @param maxInfoFrames This number specifies the maximum number
158
+     * of transmissions (like requests for data) our Master is allowed
159
+     * to make before passing the token to the next Master.  The
160
+     * default is 1.
161
+     */
162
+    void initMaster(std::string port, int baudRate, int deviceInstanceNumber,
163
+                    int macAddr, int maxMaster=DEFAULT_MAX_MASTER,
164
+                    int maxInfoFrames=1);
165
+
166
+
167
+    /**
168
+     * Perform a BACnet readProperty transaction.  This function will
169
+     * return when either the transaction has completed, or an error
170
+     * has occurred.  It requests the value of a property, belonging
171
+     * to a specific object instance on a specific device.
172
+     *
173
+     * @param targetDeviceInstanceID This is the Device Object
174
+     * Instance ID of the device to send the request to.  This number
175
+     * will be unique for every device on the network.  An address
176
+     * lookup will be performed the first time a request is made to a
177
+     * device using the WhoHas BACnet service.  The result will be
178
+     * cached for further use.
179
+     * @param objType This is the BACnet object type of the object you
180
+     * wish to query.  It should be one of the BACNET_OBJECT_TYPE
181
+     * values.
182
+     * @param objInstance This is the instance number of the Object
183
+     * you wish to access. It is an integer starting from 1.
184
+     * @param objProperty This is the property of the Object and
185
+     * instance you wish to access.  It should be one of the
186
+     * BACNET_PROPERTY_ID values.
187
+     * @param arrayIndex This specifies the index number of an array
188
+     * property.  This is not currently supported.  Until it is, leave
189
+     * the default at BACNET_ARRAY_ALL.
190
+     * @return true if an error occurred, false otherwise.
191
+     */
192
+    bool readProperty(uint32_t targetDeviceInstanceID,
193
+                      BACNET_OBJECT_TYPE objType,
194
+                      uint32_t objInstance,
195
+                      BACNET_PROPERTY_ID objProperty,
196
+                      uint32_t arrayIndex=BACNET_ARRAY_ALL);
197
+
198
+    /**
199
+     * Perform a BACnet writeProperty transaction.  This function will
200
+     * return when either the transaction has completed, or an error
201
+     * has occurred.  It writes the supplied value to a property,
202
+     * belonging to a specific object instance on a specific device.
203
+     *
204
+     * @param targetDeviceInstanceID This is the Device Object
205
+     * Instance ID of the device to send the request to.  This number
206
+     * will be unique for every device on the network.  An address
207
+     * lookup will be performed the first time a request is made to a
208
+     * device using the WhoHas BACnet service.  The result will be
209
+     * cached for further use.
210
+     * @param objType This is the BACnet object type of the object you
211
+     * wish to query.  It should be one of the BACNET_OBJECT_TYPE
212
+     * values.
213
+     * @param objInstance This is the instance number of the Object
214
+     * you wish to access. It is an integer starting from 1.
215
+     * @param objProperty This is the property of the Object and
216
+     * instance you wish to access.  It should be one of the
217
+     * BACNET_PROPERTY_ID values.
218
+     * @param propValue This is a pointer to a
219
+     * BACNET_APPLICATION_DATA_VALUE structure containg the data value
220
+     * to write to the property. Use the createData*() methods to
221
+     * properly create these structures.
222
+     * @param propPriority This specifies the priority of a
223
+     * commandable property.  Leave it at the default unless you know
224
+     * what you are doing.  In addition, there is conflicting
225
+     * information in the bacnet-stack documentation as to whether
226
+     * this is even supported.
227
+     * @param arrayIndex This specifies the index number of an array
228
+     * property.  This is not currently supported.  Until it is, leave
229
+     * the default at BACNET_ARRAY_ALL.
230
+     * @return true if an error occurred, false otherwise.
231
+     */
232
+    bool writeProperty(uint32_t targetDeviceInstanceID,
233
+                       BACNET_OBJECT_TYPE objType,
234
+                       uint32_t objInstance,
235
+                       BACNET_PROPERTY_ID objProperty,
236
+                       BACNET_APPLICATION_DATA_VALUE* propValue,
237
+                       uint8_t propPriority=BACNET_NO_PRIORITY,
238
+                       int32_t arrayIndex=BACNET_ARRAY_ALL);
239
+
240
+    /**
241
+     * After a successful readProperty request, this method can be used
242
+     * to return a BACNET_APPLICATION_DATA_VALUE structure containing
243
+     * the returned data.
244
+     *
245
+     * @return a BACNET_APPLICATION_DATA_VALUE structure containing
246
+     * the returned data.
247
+     */
248
+    BACNET_APPLICATION_DATA_VALUE getData();
249
+
250
+    /**
251
+     * After a successful readProperty request, this method can be
252
+     * used to return the BACnet data type of the returned data.  It
253
+     * will be one of the BACNET_APPLICATION_TAG_* values.
254
+     *
255
+     * @return A BACNET_APPLICATION_TAG_* value
256
+     */
257
+    uint8_t getDataType();
258
+
259
+    /**
260
+     * After a successful readProperty request, this method can be
261
+     * used to return the BACnet dataype of the returned data as a
262
+     * Real.  If the data type (getDataType()) is not a
263
+     * BACNET_APPLICATION_TAG_REAL, and the value returned cannot be
264
+     * safely converted, an exception is thrown.
265
+     *
266
+     * @return A floating point value representing the returned data
267
+     */
268
+    float getDataTypeReal();
269
+
270
+    /**
271
+     * After a successful readProperty request, this method can be
272
+     * used to return the BACnet dataype of the returned data as a
273
+     * Boolean.  If the data type (getDataType()) is not a
274
+     * BACNET_APPLICATION_TAG_BOOLEAN, and the value returned cannot
275
+     * be safely converted, an exception is thrown.
276
+     *
277
+     * @return A boolean value representing the returned data
278
+     */
279
+    bool getDataTypeBoolean();
280
+
281
+    /**
282
+     * After a successful readProperty request, this method can be
283
+     * used to return the BACnet dataype of the returned data as a
284
+     * unsigned int.  If the data type (getDataType()) is not a
285
+     * BACNET_APPLICATION_TAG_UNSIGNED_INT, and the value returned
286
+     * cannot be safely converted, an exception is thrown.
287
+     *
288
+     * @return An unsigned int value representing the returned data
289
+     */
290
+    unsigned int getDataTypeUnsignedInt();
291
+
292
+    /**
293
+     * After a successful readProperty request, this method can be
294
+     * used to return the BACnet dataype of the returned data as a
295
+     * signed int.  If the data type (getDataType()) is not a
296
+     * BACNET_APPLICATION_TAG_SIGNED_INT, and the value returned
297
+     * cannot be safely converted, an exception is thrown.
298
+     *
299
+     * @return A signed int value representing the returned data
300
+     */
301
+    int getDataTypeSignedInt();
302
+
303
+    /**
304
+     * After a successful readProperty request, this method can be
305
+     * used to return the BACnet dataype of the returned data as a
306
+     * string.  Most of the data types except Enum can be converted to
307
+     * a string.  If the data type (getDataType()) is not a
308
+     * BACNET_APPLICATION_TAG_CHARACTER_STRING, and the value returned
309
+     * cannot be safely converted, an exception is thrown.
310
+     *
311
+     * @return A string value representing the returned data
312
+     */
313
+    std::string getDataTypeString();
314
+
315
+    /**
316
+     * After a successful readProperty request, this method can be
317
+     * used to return the BACnet dataype of the returned data as an
318
+     * enumeration.  If the data type (getDataType()) is not a
319
+     * BACNET_APPLICATION_TAG_ENUMERATED an exception is thrown.
320
+     *
321
+     * @return An unsigned int representing a BACnet enumerant
322
+     */
323
+    unsigned int getDataTypeEnum();
324
+
325
+#if defined(BACAPP_DOUBLE)
326
+    /**
327
+     * After a successful readProperty request, this method can be
328
+     * used to return the BACnet dataype of the returned data as a
329
+     * double.  If the data type (getDataType()) is not a
330
+     * BACNET_APPLICATION_TAG_DOUBLE, and the value returned cannot be
331
+     * safely converted, an exception is thrown.
332
+     *
333
+     * @return A double floating point value representing the returned data
334
+     */
335
+    double getDataTypeDouble();
336
+#endif // BACAPP_DOUBLE
337
+
338
+    /**
339
+     * This method is used to create and return an initialized
340
+     * BACNET_APPLICATION_DATA_VALUE containing a real (floating point
341
+     * value).  A pointer to this returned structure can then be used
342
+     * with writeProperty().
343
+     *
344
+     * @param value The floating point value to initialize the structure to.
345
+     * @return An initialized structure containing the value
346
+     */
347
+    BACNET_APPLICATION_DATA_VALUE createDataReal(float Real);
348
+
349
+    /**
350
+     * This method is used to create and return an initialized
351
+     * BACNET_APPLICATION_DATA_VALUE containing a boolean.  A pointer
352
+     * to this returned structure can then be used with
353
+     * writeProperty().
354
+     *
355
+     * @param value The boolean value to initialize the structure to.
356
+     * @return An initialized structure containing the value
357
+     */
358
+    BACNET_APPLICATION_DATA_VALUE createDataBool(bool value);
359
+
360
+    /**
361
+     * This method is used to create and return an initialized
362
+     * BACNET_APPLICATION_DATA_VALUE containing a signed integer.  A
363
+     * pointer to this returned structure can then be used with
364
+     * writeProperty().
365
+     *
366
+     * @param value The signed integer value to initialize the structure to.
367
+     * @return An initialized structure containing the value
368
+     */
369
+    BACNET_APPLICATION_DATA_VALUE createDataSignedInt(int value);
370
+
371
+    /**
372
+     * This method is used to create and return an initialized
373
+     * BACNET_APPLICATION_DATA_VALUE containing a unsigned integer.  A
374
+     * pointer to this returned structure can then be used with
375
+     * writeProperty().
376
+     *
377
+     * @param value The unsigned integer value to initialize the
378
+     * structure to.
379
+     * @return An initialized structure containing the value
380
+     */
381
+    BACNET_APPLICATION_DATA_VALUE createDataUnsignedInt(unsigned int value);
382
+
383
+    /**
384
+     * This method is used to create and return an initialized
385
+     * BACNET_APPLICATION_DATA_VALUE containing a character string.  A
386
+     * pointer to this returned structure can then be used with
387
+     * writeProperty().  Strings are typically limited to 63 characters.
388
+     *
389
+     * @param value The character string value to initialize the
390
+     * structure to.
391
+     * @return An initialized structure containing the value
392
+     */
393
+    BACNET_APPLICATION_DATA_VALUE createDataString(std::string value);
394
+
395
+    /**
396
+     * Return an enumration of the last error type to occur.  The
397
+     * value returned will be one of the BACERR_TYPE_T values.
398
+     *
399
+     * @return The last error type to occur, one of the BACERR_TYPE_T
400
+     * values.
401
+     */
402
+    BACERR_TYPE_T getErrorType()
403
+    {
404
+      return m_errorType;
405
+    };
406
+
407
+    /**
408
+     * In the event of a BACnet Reject error, return the error code.
409
+     *
410
+     * @return The Reject error code.
411
+     */
412
+    uint8_t getRejectReason()
413
+    {
414
+      return m_rejectReason;
415
+    };
416
+
417
+    /**
418
+     * In the event of a BACnet Reject error, return the error string.
419
+     *
420
+     * @return The Reject error string.
421
+     */
422
+    std::string getRejectString()
423
+    {
424
+      return m_rejectString;
425
+    };
426
+
427
+    /**
428
+     * In the event of a BACnet Abort error, return the Abort reason code.
429
+     *
430
+     * @return The Abort reason code.
431
+     */
432
+    uint8_t getAbortReason()
433
+    {
434
+      return m_abortReason;
435
+    };
436
+
437
+    /**
438
+     * In the event of a BACnet Abort error, return the Abort string.
439
+     *
440
+     * @return The Abort error string.
441
+     */
442
+    std::string getAbortString()
443
+    {
444
+      return m_abortString;
445
+    };
446
+
447
+    /**
448
+     * In the event of a general BACnet error, return the BACnet error class.
449
+     *
450
+     * @return One of the BACNET_ERROR_CLASS error class codes
451
+     */
452
+    BACNET_ERROR_CLASS getErrorClass()
453
+    {
454
+      return m_errorClass;
455
+    };
456
+
457
+    /**
458
+     * In the event of a general BACnet error, return the BACnet error code.
459
+     *
460
+     * @return One of the BACNET_ERROR_CODE error codes
461
+     */
462
+    BACNET_ERROR_CODE getErrorCode()
463
+    {
464
+      return m_errorCode;
465
+    };
466
+
467
+    /**
468
+     * In the event of a general BACnet error, return the BACnet error
469
+     * string.
470
+     *
471
+     * @return A string representing the BACnet error class and code.
472
+     */
473
+    std::string getErrorString()
474
+    {
475
+      return m_errorString;
476
+    };
477
+
478
+    /**
479
+     * In the event of a non-BACnet UPM error, return a string
480
+     * describing the error.
481
+     *
482
+     * @return A string representing the UPM error.
483
+     */
484
+    std::string getUPMErrorString()
485
+    {
486
+      return m_upmErrorString;
487
+    };
488
+
489
+    /**
490
+     * Check to see if initMaster) has already been called, and out
491
+     * master is initialized.
492
+     *
493
+     * @return true if the master is initialized, false otherwise
494
+     */
495
+    bool isInitialized()
496
+    {
497
+      return m_initialized;
498
+    };
499
+
500
+    /**
501
+     * Return the port that was specified to initMaster().
502
+     *
503
+     * @return The port specified to initMaster().
504
+     */
505
+    std::string getPort()
506
+    {
507
+      return m_port;
508
+    };
509
+
510
+    /**
511
+     * Return the Object Device Instance ID for our Master was
512
+     * specified to initMaster().
513
+     *
514
+     * @return The Object Device Instance ID for our Master.
515
+     */
516
+    uint32_t getDeviceInstanceID()
517
+    {
518
+      return m_deviceInstanceID;
519
+    };
520
+
521
+    /**
522
+     * Return the maxInfoFrames parameter that was specified to initMaster().
523
+     *
524
+     * @return The maxInfoFrames parameter specified to initMaster().
525
+     */
526
+    int getMaxInfoFrames()
527
+    {
528
+      return m_maxInfoFrames;
529
+    };
530
+
531
+    /**
532
+     * Return the maxMaster parameter that was specified to initMaster().
533
+     *
534
+     * @return The maxMaster parameter specified to initMaster().
535
+     */
536
+    int getMaxMaster()
537
+    {
538
+      return m_maxMaster;
539
+    };
540
+
541
+    /**
542
+     * Return the baud rate parameter that was specified to initMaster().
543
+     *
544
+     * @return The baud rate parameter specified to initMaster().
545
+     */
546
+    int getBaudRate()
547
+    {
548
+      return m_baudRate;
549
+    };
550
+
551
+    /**
552
+     * Return the MAC address parameter that was specified to initMaster().
553
+     *
554
+     * @return The MAC address parameter specified to initMaster().
555
+     */
556
+    int getMACAddress()
557
+    {
558
+      return m_macAddr;
559
+    };
560
+
561
+    /**
562
+     * Enable or disable debugging output.
563
+     *
564
+     * @param enable true to enable debugging, false otherwise
565
+     */
566
+    void setDebug(bool enable);
567
+
568
+  protected:
569
+    /**
570
+     * BACNETMSTP constructor
571
+     */
572
+    BACNETMSTP();
573
+
574
+    /**
575
+     * BACNETMSTP Destructor
576
+     */
577
+    ~BACNETMSTP();
578
+
579
+    // clear/reset error states
580
+    void clearErrors();
581
+
582
+    // error handler
583
+    static void handlerError(BACNET_ADDRESS * src,
584
+                             uint8_t invoke_id,
585
+                             BACNET_ERROR_CLASS error_class,
586
+                             BACNET_ERROR_CODE error_code);
587
+
588
+    // abort handler
589
+    static void handlerAbort(BACNET_ADDRESS * src,
590
+                             uint8_t invoke_id,
591
+                             uint8_t abort_reason,
592
+                             bool server);
593
+
594
+    // reject handler
595
+    static void handlerReject(BACNET_ADDRESS * src,
596
+                              uint8_t invoke_id,
597
+                              uint8_t reject_reason);
598
+
599
+
600
+    // our handler for dealing with return data from a ReadProperty call
601
+    static void handlerReadPropertyAck(uint8_t* service_request,
602
+                                       uint16_t service_len,
603
+                                       BACNET_ADDRESS* src,
604
+                                       BACNET_CONFIRMED_SERVICE_ACK_DATA* service_data);
605
+
606
+    // our handler for writeProp acks
607
+    static void handlerWritePropertyAck(BACNET_ADDRESS* src,
608
+                                        uint8_t invoke_id);
609
+
610
+    // initialize our service handlers
611
+    void initServiceHandlers();
612
+
613
+    // utility function
614
+    std::string string2HexString(std::string input);
615
+
616
+    // responsible for dispatching a request to the BACnet network
617
+    bool dispatchRequest();
618
+
619
+  private:
620
+    // prevent copying and assignment
621
+    BACNETMSTP(BACNETMSTP const &) {};
622
+    BACNETMSTP& operator=(BACNETMSTP const&) {};
623
+
624
+    // our class instance
625
+    static BACNETMSTP* m_instance;
626
+
627
+    // has the class been created yet?
628
+    bool m_initialized;
629
+
630
+    // Some items we can set for our master
631
+    std::string m_port;
632
+    int m_maxInfoFrames;
633
+    int m_maxMaster;
634
+    int m_baudRate;
635
+    int m_macAddr;
636
+
637
+    // the unique Instance Number of our Master Device Object
638
+    uint32_t m_deviceInstanceID;
639
+
640
+    // adpu timeout in milliseconds
641
+    uint16_t m_adpuTimeoutMS;
642
+
643
+    // buffer used for receiving data
644
+    uint8_t m_rxBuffer[MAX_MPDU];
645
+
646
+    // our error classfication
647
+    BACERR_TYPE_T m_errorType;
648
+
649
+    // BACnet reject info
650
+    uint8_t m_rejectReason;
651
+    std::string m_rejectString;
652
+
653
+    // BACnet abort info
654
+    uint8_t m_abortReason;
655
+    std::string m_abortString;
656
+
657
+    // BACnet error info
658
+    BACNET_ERROR_CLASS m_errorClass;
659
+    BACNET_ERROR_CODE  m_errorCode;
660
+    std::string m_errorString;
661
+
662
+    // generic UPM related errors - we just set the error text to
663
+    // something informative.
664
+    std::string m_upmErrorString;
665
+
666
+    // our returned data from readProperty()
667
+    BACNET_APPLICATION_DATA_VALUE m_returnedValue;
668
+
669
+    // current bound target address of dispatched service request
670
+    // (read/write prop, etc)
671
+    BACNET_ADDRESS m_targetAddress;
672
+
673
+    // current invokeID (for transaction handling)
674
+    uint8_t m_invokeID;
675
+
676
+    // error detected flag
677
+    bool m_errorDetected;
678
+
679
+    // Commands - we create a struct to hold the arguments for each
680
+    // command type we support.  Then, we create a command struct
681
+    // which contains the command type and a union containing the
682
+    // relevant arguments.  This is used by dispatchRequest() to issue
683
+    // the correct request.
684
+
685
+    // these may generate SWIG warnings, but they can be ignored as we
686
+    // do not expose these outside the class
687
+    typedef struct {
688
+      uint32_t targetDeviceInstanceID;
689
+      BACNET_OBJECT_TYPE objType;
690
+      uint32_t objInstance;
691
+      BACNET_PROPERTY_ID objProperty;
692
+      uint32_t arrayIndex;
693
+    } READ_PROPERTY_ARGS_T;
694
+
695
+    typedef struct {
696
+      uint32_t targetDeviceInstanceID;
697
+      BACNET_OBJECT_TYPE objType;
698
+      uint32_t objInstance;
699
+      BACNET_PROPERTY_ID objProperty;
700
+      BACNET_APPLICATION_DATA_VALUE* propValue;
701
+      uint8_t propPriority;
702
+      int32_t arrayIndex;
703
+    } WRITE_PROPERTY_ARGS_T;
704
+
705
+    struct {
706
+      BACCMD_TYPE_T cmd;
707
+
708
+      union {
709
+        READ_PROPERTY_ARGS_T readPropArgs;
710
+        WRITE_PROPERTY_ARGS_T writePropArgs;
711
+      };
712
+    } m_command;
713
+
714
+    bool m_debugging;
715
+  };
716
+}

+ 1026
- 0
src/bacnetmstp/device-client.c
Diferenças do arquivo suprimidas por serem muito extensas
Ver arquivo


+ 465
- 0
src/bacnetmstp/device.h Ver arquivo

@@ -0,0 +1,465 @@
1
+/**************************************************************************
2
+*
3
+* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
4
+*
5
+* Permission is hereby granted, free of charge, to any person obtaining
6
+* a copy of this software and associated documentation files (the
7
+* "Software"), to deal in the Software without restriction, including
8
+* without limitation the rights to use, copy, modify, merge, publish,
9
+* distribute, sublicense, and/or sell copies of the Software, and to
10
+* permit persons to whom the Software is furnished to do so, subject to
11
+* the following conditions:
12
+*
13
+* The above copyright notice and this permission notice shall be included
14
+* in all copies or substantial portions of the Software.
15
+*
16
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+*
24
+*********************************************************************/
25
+
26
+/** @file device.h Defines functions for handling all BACnet objects belonging
27
+ *                 to a BACnet device, as well as Device-specific properties. */
28
+
29
+#ifndef DEVICE_H
30
+#define DEVICE_H
31
+
32
+#include <stdbool.h>
33
+#include <stdint.h>
34
+#include "bacdef.h"
35
+#include "bacenum.h"
36
+#include "wp.h"
37
+#include "rd.h"
38
+#include "rp.h"
39
+#include "rpm.h"
40
+#include "readrange.h"
41
+
42
+/** Called so a BACnet object can perform any necessary initialization.
43
+ * @ingroup ObjHelpers
44
+ */
45
+typedef void (
46
+    *object_init_function) (
47
+    void);
48
+
49
+/** Counts the number of objects of this type.
50
+ * @ingroup ObjHelpers
51
+ * @return Count of implemented objects of this type.
52
+ */
53
+typedef unsigned (
54
+    *object_count_function) (
55
+    void);
56
+
57
+/** Maps an object index position to its corresponding BACnet object instance number.
58
+ * @ingroup ObjHelpers
59
+ * @param index [in] The index of the object, in the array of objects of its type.
60
+ * @return The BACnet object instance number to be used in a BACNET_OBJECT_ID.
61
+ */
62
+typedef uint32_t(
63
+    *object_index_to_instance_function)
64
+        (
65
+    unsigned index);
66
+
67
+/** Provides the BACnet Object_Name for a given object instance of this type.
68
+ * @ingroup ObjHelpers
69
+ * @param object_instance [in] The object instance number to be looked up.
70
+ * @param object_name [in,out] Pointer to a character_string structure that
71
+ *         will hold a copy of the object name if this is a valid object_instance.
72
+ * @return True if the object_instance is valid and object_name has been
73
+ *         filled with a copy of the Object's name.
74
+ */
75
+typedef bool(
76
+    *object_name_function)
77
+        (
78
+    uint32_t object_instance,
79
+    BACNET_CHARACTER_STRING * object_name);
80
+
81
+/** Look in the table of objects of this type, and see if this is a valid
82
+ *  instance number.
83
+ * @ingroup ObjHelpers
84
+ * @param [in] The object instance number to be looked up.
85
+ * @return True if the object instance refers to a valid object of this type.
86
+ */
87
+typedef bool(
88
+    *object_valid_instance_function) (
89
+    uint32_t object_instance);
90
+
91
+/** Helper function to step through an array of objects and find either the
92
+ * first one or the next one of a given type. Used to step through an array
93
+ * of objects which is not necessarily contiguious for each type i.e. the
94
+ * index for the 'n'th object of a given type is not necessarily 'n'.
95
+ * @ingroup ObjHelpers
96
+ * @param [in] The index of the current object or a value of ~0 to indicate
97
+ * start at the beginning.
98
+ * @return The index of the next object of the required type or ~0 (all bits
99
+ * == 1) to indicate no more objects found.
100
+ */
101
+typedef unsigned (
102
+    *object_iterate_function) (
103
+    unsigned current_index);
104
+
105
+/** Look in the table of objects of this type, and get the COV Value List.
106
+ * @ingroup ObjHelpers
107
+ * @param [in] The object instance number to be looked up.
108
+ * @param [out] The value list
109
+ * @return True if the object instance supports this feature, and has changed.
110
+ */
111
+typedef bool(
112
+    *object_value_list_function) (
113
+    uint32_t object_instance,
114
+    BACNET_PROPERTY_VALUE * value_list);
115
+
116
+/** Look in the table of objects for this instance to see if value changed.
117
+ * @ingroup ObjHelpers
118
+ * @param [in] The object instance number to be looked up.
119
+ * @return True if the object instance has changed.
120
+ */
121
+typedef bool(
122
+    *object_cov_function) (
123
+    uint32_t object_instance);
124
+
125
+/** Look in the table of objects for this instance to clear the changed flag.
126
+ * @ingroup ObjHelpers
127
+ * @param [in] The object instance number to be looked up.
128
+ */
129
+typedef void (
130
+    *object_cov_clear_function) (
131
+    uint32_t object_instance);
132
+
133
+/** Intrinsic Reporting funcionality.
134
+ * @ingroup ObjHelpers
135
+ * @param [in] Object instance.
136
+ */
137
+typedef void (
138
+    *object_intrinsic_reporting_function) (
139
+    uint32_t object_instance);
140
+
141
+
142
+/** Defines the group of object helper functions for any supported Object.
143
+ * @ingroup ObjHelpers
144
+ * Each Object must provide some implementation of each of these helpers
145
+ * in order to properly support the handlers.  Eg, the ReadProperty handler
146
+ * handler_read_property() relies on the instance of Object_Read_Property
147
+ * for each Object type, or configure the function as NULL.
148
+ * In both appearance and operation, this group of functions acts like
149
+ * they are member functions of a C++ Object base class.
150
+ */
151
+typedef struct object_functions {
152
+    BACNET_OBJECT_TYPE Object_Type;
153
+    object_init_function Object_Init;
154
+    object_count_function Object_Count;
155
+    object_index_to_instance_function Object_Index_To_Instance;
156
+    object_valid_instance_function Object_Valid_Instance;
157
+    object_name_function Object_Name;
158
+    read_property_function Object_Read_Property;
159
+    write_property_function Object_Write_Property;
160
+    rpm_property_lists_function Object_RPM_List;
161
+    rr_info_function Object_RR_Info;
162
+    object_iterate_function Object_Iterator;
163
+    object_value_list_function Object_Value_List;
164
+    object_cov_function Object_COV;
165
+    object_cov_clear_function Object_COV_Clear;
166
+    object_intrinsic_reporting_function Object_Intrinsic_Reporting;
167
+} object_functions_t;
168
+
169
+/* String Lengths - excluding any nul terminator */
170
+#define MAX_DEV_NAME_LEN 32
171
+#define MAX_DEV_LOC_LEN  64
172
+#define MAX_DEV_MOD_LEN  32
173
+#define MAX_DEV_VER_LEN  16
174
+#define MAX_DEV_DESC_LEN 64
175
+
176
+/** Structure to define the Object Properties common to all Objects. */
177
+typedef struct commonBacObj_s {
178
+
179
+    /** The BACnet type of this object (ie, what class is this object from?).
180
+     * This property, of type BACnetObjectType, indicates membership in a
181
+     * particular object type class. Each inherited class will be of one type.
182
+     */
183
+    BACNET_OBJECT_TYPE mObject_Type;
184
+
185
+    /** The instance number for this class instance. */
186
+    uint32_t Object_Instance_Number;
187
+
188
+    /** Object Name; must be unique.
189
+     * This property, of type CharacterString, shall represent a name for
190
+     * the object that is unique within the BACnet Device that maintains it.
191
+     */
192
+    char Object_Name[MAX_DEV_NAME_LEN];
193
+
194
+} COMMON_BAC_OBJECT;
195
+
196
+
197
+/** Structure to define the Properties of Device Objects which distinguish
198
+ *  one instance from another.
199
+ *  This structure only defines fields for properties that are unique to
200
+ *  a given Device object.  The rest may be fixed in device.c or hard-coded
201
+ *  into the read-property encoding.
202
+ *  This may be useful for implementations which manage multiple Devices,
203
+ *  eg, a Gateway.
204
+ */
205
+typedef struct devObj_s {
206
+    /** The BACnet Device Address for this device; ->len depends on DLL type. */
207
+    BACNET_ADDRESS bacDevAddr;
208
+
209
+    /** Structure for the Object Properties common to all Objects. */
210
+    COMMON_BAC_OBJECT bacObj;
211
+
212
+    /** Device Description. */
213
+    char Description[MAX_DEV_DESC_LEN];
214
+
215
+    /** The upcounter that shows if the Device ID or object structure has changed. */
216
+    uint32_t Database_Revision;
217
+} DEVICE_OBJECT_DATA;
218
+
219
+
220
+#ifdef __cplusplus
221
+extern "C" {
222
+#endif /* __cplusplus */
223
+
224
+    void Device_Init(
225
+        object_functions_t * object_table);
226
+
227
+    bool Device_Reinitialize(
228
+        BACNET_REINITIALIZE_DEVICE_DATA * rd_data);
229
+
230
+    BACNET_REINITIALIZED_STATE Device_Reinitialized_State(
231
+        void);
232
+
233
+    rr_info_function Device_Objects_RR_Info(
234
+        BACNET_OBJECT_TYPE object_type);
235
+
236
+    void Device_getCurrentDateTime(
237
+        BACNET_DATE_TIME * DateTime);
238
+    int32_t Device_UTC_Offset(void);
239
+    bool Device_Daylight_Savings_Status(void);
240
+
241
+    void Device_Property_Lists(
242
+        const int **pRequired,
243
+        const int **pOptional,
244
+        const int **pProprietary);
245
+    void Device_Objects_Property_List(
246
+        BACNET_OBJECT_TYPE object_type,
247
+        struct special_property_list_t *pPropertyList);
248
+    /* functions to support COV */
249
+    bool Device_Encode_Value_List(
250
+        BACNET_OBJECT_TYPE object_type,
251
+        uint32_t object_instance,
252
+        BACNET_PROPERTY_VALUE * value_list);
253
+    bool Device_Value_List_Supported(
254
+        BACNET_OBJECT_TYPE object_type);
255
+    bool Device_COV(
256
+        BACNET_OBJECT_TYPE object_type,
257
+        uint32_t object_instance);
258
+    void Device_COV_Clear(
259
+        BACNET_OBJECT_TYPE object_type,
260
+        uint32_t object_instance);
261
+
262
+    uint32_t Device_Object_Instance_Number(
263
+        void);
264
+    bool Device_Set_Object_Instance_Number(
265
+        uint32_t object_id);
266
+    bool Device_Valid_Object_Instance_Number(
267
+        uint32_t object_id);
268
+    unsigned Device_Object_List_Count(
269
+        void);
270
+    bool Device_Object_List_Identifier(
271
+        unsigned array_index,
272
+        int *object_type,
273
+        uint32_t * instance);
274
+
275
+    unsigned Device_Count(
276
+        void);
277
+    uint32_t Device_Index_To_Instance(
278
+        unsigned index);
279
+
280
+    bool Device_Object_Name(
281
+        uint32_t object_instance,
282
+        BACNET_CHARACTER_STRING * object_name);
283
+    bool Device_Set_Object_Name(
284
+        BACNET_CHARACTER_STRING * object_name);
285
+    /* Copy a child object name, given its ID. */
286
+    bool Device_Object_Name_Copy(
287
+        BACNET_OBJECT_TYPE object_type,
288
+        uint32_t object_instance,
289
+        BACNET_CHARACTER_STRING * object_name);
290
+    bool Device_Object_Name_ANSI_Init(const char * value);
291
+
292
+    BACNET_DEVICE_STATUS Device_System_Status(
293
+        void);
294
+    int Device_Set_System_Status(
295
+        BACNET_DEVICE_STATUS status,
296
+        bool local);
297
+
298
+    const char *Device_Vendor_Name(
299
+        void);
300
+
301
+    uint16_t Device_Vendor_Identifier(
302
+        void);
303
+    void Device_Set_Vendor_Identifier(
304
+        uint16_t vendor_id);
305
+
306
+    const char *Device_Model_Name(
307
+        void);
308
+    bool Device_Set_Model_Name(
309
+        const char *name,
310
+        size_t length);
311
+
312
+    const char *Device_Firmware_Revision(
313
+        void);
314
+
315
+    const char *Device_Application_Software_Version(
316
+        void);
317
+    bool Device_Set_Application_Software_Version(
318
+        const char *name,
319
+        size_t length);
320
+
321
+    const char *Device_Description(
322
+        void);
323
+    bool Device_Set_Description(
324
+        const char *name,
325
+        size_t length);
326
+
327
+    const char *Device_Location(
328
+        void);
329
+    bool Device_Set_Location(
330
+        const char *name,
331
+        size_t length);
332
+
333
+    /* some stack-centric constant values - no set methods */
334
+    uint8_t Device_Protocol_Version(
335
+        void);
336
+    uint8_t Device_Protocol_Revision(
337
+        void);
338
+    BACNET_SEGMENTATION Device_Segmentation_Supported(
339
+        void);
340
+
341
+    uint32_t Device_Database_Revision(
342
+        void);
343
+    void Device_Set_Database_Revision(
344
+        uint32_t revision);
345
+    void Device_Inc_Database_Revision(
346
+        void);
347
+
348
+    bool Device_Valid_Object_Name(
349
+        BACNET_CHARACTER_STRING * object_name,
350
+        int *object_type,
351
+        uint32_t * object_instance);
352
+    bool Device_Valid_Object_Id(
353
+        int object_type,
354
+        uint32_t object_instance);
355
+
356
+    int Device_Read_Property(
357
+        BACNET_READ_PROPERTY_DATA * rpdata);
358
+    bool Device_Write_Property(
359
+        BACNET_WRITE_PROPERTY_DATA * wp_data);
360
+
361
+    bool DeviceGetRRInfo(
362
+        BACNET_READ_RANGE_DATA * pRequest,      /* Info on the request */
363
+        RR_PROP_INFO * pInfo);  /* Where to put the information */
364
+
365
+    int Device_Read_Property_Local(
366
+        BACNET_READ_PROPERTY_DATA * rpdata);
367
+    bool Device_Write_Property_Local(
368
+        BACNET_WRITE_PROPERTY_DATA * wp_data);
369
+
370
+#if defined(INTRINSIC_REPORTING)
371
+    void Device_local_reporting(
372
+        void);
373
+#endif
374
+
375
+/* Prototypes for Routing functionality in the Device Object.
376
+ * Enable by defining BAC_ROUTING in config.h and including gw_device.c
377
+ * in the build (lib/Makefile).
378
+ */
379
+    void Routing_Device_Init(
380
+        uint32_t first_object_instance);
381
+
382
+    uint16_t Add_Routed_Device(
383
+        uint32_t Object_Instance,
384
+        BACNET_CHARACTER_STRING * Object_Name,
385
+        const char *Description);
386
+    DEVICE_OBJECT_DATA *Get_Routed_Device_Object(
387
+        int idx);
388
+    BACNET_ADDRESS *Get_Routed_Device_Address(
389
+        int idx);
390
+
391
+    void routed_get_my_address(
392
+        BACNET_ADDRESS * my_address);
393
+
394
+    bool Routed_Device_Address_Lookup(
395
+        int idx,
396
+        uint8_t address_len,
397
+        uint8_t * mac_adress);
398
+    bool Routed_Device_GetNext(
399
+        BACNET_ADDRESS * dest,
400
+        int *DNET_list,
401
+        int *cursor);
402
+    bool Routed_Device_Is_Valid_Network(
403
+        uint16_t dest_net,
404
+        int *DNET_list);
405
+
406
+    uint32_t Routed_Device_Index_To_Instance(
407
+        unsigned index);
408
+    bool Routed_Device_Valid_Object_Instance_Number(
409
+        uint32_t object_id);
410
+    bool Routed_Device_Name(
411
+        uint32_t object_instance,
412
+        BACNET_CHARACTER_STRING * object_name);
413
+    uint32_t Routed_Device_Object_Instance_Number(
414
+        void);
415
+    bool Routed_Device_Set_Object_Instance_Number(
416
+        uint32_t object_id);
417
+    bool Routed_Device_Set_Object_Name(
418
+        uint8_t encoding,
419
+        const char *value,
420
+        size_t length);
421
+    bool Routed_Device_Set_Description(
422
+        const char *name,
423
+        size_t length);
424
+    void Routed_Device_Inc_Database_Revision(
425
+        void);
426
+    int Routed_Device_Service_Approval(
427
+        BACNET_CONFIRMED_SERVICE service,
428
+        int service_argument,
429
+        uint8_t * apdu_buff,
430
+        uint8_t invoke_id);
431
+
432
+
433
+
434
+#ifdef __cplusplus
435
+}
436
+#endif /* __cplusplus */
437
+/** @defgroup ObjFrmwk Object Framework
438
+ * The modules in this section describe the BACnet-stack's framework for
439
+ * BACnet-defined Objects (Device, Analog Input, etc). There are two submodules
440
+ * to describe this arrangement:
441
+ *  - The "object helper functions" which provide C++-like common functionality
442
+ *    to all supported object types.
443
+ *  - The interface between the implemented Objects and the BAC-stack services,
444
+ *    specifically the handlers, which are mediated through function calls to
445
+ *    the Device object.
446
+ *//** @defgroup ObjHelpers Object Helper Functions
447
+ * @ingroup ObjFrmwk
448
+ * This section describes the function templates for the helper functions that
449
+ * provide common object support.
450
+ *//** @defgroup ObjIntf Handler-to-Object Interface Functions
451
+ * @ingroup ObjFrmwk
452
+ * This section describes the fairly limited set of functions that link the
453
+ * BAC-stack handlers to the BACnet Object instances.  All of these calls are
454
+ * situated in the Device Object, which "knows" how to reach its child Objects.
455
+ *
456
+ * Most of these calls have a common operation:
457
+ *  -# Call Device_Objects_Find_Functions( for the desired Object_Type )
458
+ *   - Gets a pointer to the object_functions for this Type of Object.
459
+ *  -# Call the Object's Object_Valid_Instance( for the desired object_instance )
460
+ *     to make sure there is such an instance.
461
+ *  -# Call the Object helper function needed by the handler,
462
+ *     eg Object_Read_Property() for the RP handler.
463
+ *
464
+ */
465
+#endif

+ 23
- 0
src/bacnetmstp/javaupm_bacnetmstp.i Ver arquivo

@@ -0,0 +1,23 @@
1
+%module javaupm_bacnetmstp
2
+%include "../upm.i"
3
+%include "typemaps.i"
4
+%include "cpointer.i"
5
+%include "arrays_java.i";
6
+%include "../java_buffer.i"
7
+
8
+%{
9
+    #include "bacnetmstp.h"
10
+%}
11
+
12
+%include "bacnetmstp.h"
13
+
14
+%pragma(java) jniclasscode=%{
15
+    static {
16
+        try {
17
+            System.loadLibrary("javaupm_bacnetmstp");
18
+        } catch (UnsatisfiedLinkError e) {
19
+            System.err.println("Native code library failed to load. \n" + e);
20
+            System.exit(1);
21
+        }
22
+    }
23
+%}

+ 11
- 0
src/bacnetmstp/jsupm_bacnetmstp.i Ver arquivo

@@ -0,0 +1,11 @@
1
+%module jsupm_bacnetmstp
2
+%include "../upm.i"
3
+%include "stdint.i"
4
+%include "cpointer.i"
5
+
6
+%pointer_functions(float, floatp);
7
+
8
+%include "bacnetmstp.h"
9
+%{
10
+    #include "bacnetmstp.h"
11
+%}

+ 15
- 0
src/bacnetmstp/pyupm_bacnetmstp.i Ver arquivo

@@ -0,0 +1,15 @@
1
+// Include doxygen-generated documentation
2
+%include "pyupm_doxy2swig.i"
3
+%module pyupm_bacnetmstp
4
+%include "../upm.i"
5
+%include "stdint.i"
6
+%include "cpointer.i"
7
+
8
+%feature("autodoc", "3");
9
+
10
+%pointer_functions(float, floatp);
11
+
12
+%include "bacnetmstp.h"
13
+%{
14
+    #include "bacnetmstp.h"
15
+%}

+ 65
- 0
src/bacnetmstp/timer.h Ver arquivo

@@ -0,0 +1,65 @@
1
+/**************************************************************************
2
+*
3
+* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
4
+*
5
+* Permission is hereby granted, free of charge, to any person obtaining
6
+* a copy of this software and associated documentation files (the
7
+* "Software"), to deal in the Software without restriction, including
8
+* without limitation the rights to use, copy, modify, merge, publish,
9
+* distribute, sublicense, and/or sell copies of the Software, and to
10
+* permit persons to whom the Software is furnished to do so, subject to
11
+* the following conditions:
12
+*
13
+* The above copyright notice and this permission notice shall be included
14
+* in all copies or substantial portions of the Software.
15
+*
16
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+*********************************************************************/
24
+#ifndef TIMER_H
25
+#define TIMER_H
26
+
27
+#include <stdbool.h>
28
+#include <stdint.h>
29
+#include <sys/time.h>   /* for timeval */
30
+
31
+/* Timer Module */
32
+#ifndef MAX_MILLISECOND_TIMERS
33
+#define TIMER_SILENCE 0
34
+#define MAX_MILLISECOND_TIMERS 1
35
+#endif
36
+
37
+#ifdef __cplusplus
38
+extern "C" {
39
+#endif /* __cplusplus */
40
+    uint32_t timeGetTime(
41
+        void);
42
+
43
+    void timer_init(
44
+        void);
45
+    uint32_t timer_milliseconds(
46
+        unsigned index);
47
+    bool timer_elapsed_milliseconds(
48
+        unsigned index,
49
+        uint32_t value);
50
+    bool timer_elapsed_seconds(
51
+        unsigned index,
52
+        uint32_t value);
53
+    bool timer_elapsed_minutes(
54
+        unsigned index,
55
+        uint32_t seconds);
56
+    uint32_t timer_milliseconds_set(
57
+        unsigned index,
58
+        uint32_t value);
59
+    uint32_t timer_reset(
60
+        unsigned index);
61
+
62
+#ifdef __cplusplus
63
+}
64
+#endif /* __cplusplus */
65
+#endif