-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathbacnetnpci.cpp
202 lines (179 loc) · 5.61 KB
/
bacnetnpci.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#include "bacnetnpci.h"
#include "helpercoder.h"
BacnetNpci::BacnetNpci():
_controlOctet(0),
_hopCount(255),
_vendorId(0)
{
}
void BacnetNpci::decodeAddressHlpr(quint8 **netFieldPtr, BacnetAddress *bacAddress)
{
quint8 *&ptr = *netFieldPtr;
//network number is always available, then
ptr += bacAddress->setNetworkNumFromRaw(ptr);
//address is varying, dependant on MAC layer, so encode length first, then address itself
//the length is 2 bytes long
quint8 length = *ptr;
++ptr;
//get address
if (length == 0) {
if (!bacAddress->isGlobalBroadcast())
bacAddress->setIsRemoteBroadcast();
} else {
bacAddress->macAddressFromRaw(*netFieldPtr, length);
(*netFieldPtr) += length;
}
}
void BacnetNpci::encodeAddressHlpr(BacnetAddress &bacAddress, quint8 **netFieldPtr)
{
quint8 *&ptr = *netFieldPtr;
//network number is always available, then
//! \todo This will not work if we were to rout between two irtual networks - no consultation with our routing table
ptr += bacAddress.networkNumToRaw(ptr);
//encode mac addresss length
*ptr = (quint8)bacAddress.macAddrLength();
++ptr;
//ptr += HelperCoder::uin16ToRaw(bacAddress.macAddrLength(), ptr);
/*
if it's not a remote and local broadcast (and it's not a local message (we are sure of that
since network number is present)) we have to encode address as well - this is taken care of
by BacnetAddress class.
*/
ptr += bacAddress.macAddressToRaw(ptr);
}
qint8 BacnetNpci::setFromRaw(quint8 *inDataPrt)
{
quint8 *actualPtr = inDataPrt;
if (*actualPtr != ProtocolVersion) {
#warning "What to do here? Just drop the frame, or send something back."
return NpciBadProtocolVersion;
}
++actualPtr;
//remember control octet
_controlOctet = *actualPtr;
//check conformance with protocol
if (!isSane()) {
return NpciInsaneControlField;
}
//parse NPCI further
++actualPtr;
//do we have info about destination?
if (isDestinationSpecified()) {
//interpret information at inDataPrt as destination address. indataPtr gets updated by helper function.
decodeAddressHlpr(&actualPtr, &_destAddr);
}
//do we have source information?
if (isSourceSpecified()) {
//interpret information at inDataPrt as source address. indataPtr gets updated by helper function.
decodeAddressHlpr(&actualPtr, &_srcAddr);
}
//if there was destination, we have hop count as well - decrease the hop count
if (isDestinationSpecified()) {
_hopCount = *actualPtr;
++actualPtr;
}
//take care of message type and vendor id
if (isNetworkLayerMessage()) {
_messageType = (BacnetNetworkMessageType)*actualPtr;
++actualPtr;
if (_messageType > LastAshraeReserved) {
actualPtr += HelperCoder::uint16FromRaw(actualPtr, &_vendorId);
}
}
return (actualPtr - inDataPrt);
}
qint8 BacnetNpci::setToRaw(quint8 *outDataPtr)
{
quint8 *actPtr(outDataPtr);
//set protocol version
*actPtr = ProtocolVersion;
++actPtr;
//we have to check few things before control octet is ready
if (_destAddr.hasNetworkNumber()) {
_controlOctet |= BitFields::Bit5;
}
if (_srcAddr.hasNetworkNumber()) {
//it is a remote message or broadcast - SNET, SLEN will be present
_controlOctet |= BitFields::Bit3;
}
//expecting reply should be already set
//priority should be already set
//set control octet
*actPtr = _controlOctet;
++actPtr;
//if we have destination set, we need to insert it
if (isDestinationSpecified()) {
encodeAddressHlpr(_destAddr, &actPtr);
}
//if we have source set
if (isSourceSpecified()) {
encodeAddressHlpr(_srcAddr, &actPtr);
}
//hop count
if (isDestinationSpecified()) {
//if it's a routed message - we already decreased
*actPtr = (_hopCount - 1);
++actPtr;
}
//vendor id
if (isNetworkLayerMessage() ) {
*actPtr = (quint8)_messageType;
++actPtr;
if ((networkMessageType() > LastAshraeReserved))
*actPtr += HelperCoder::uin16ToRaw(_vendorId, actPtr);
}
return (actPtr - outDataPtr);
}
BacnetNpci::BacnetNetworkMessageType BacnetNpci::networkMessageType()
{
if (isNetworkLayerMessage())
return _messageType;
else
return LastVendor;
enum NetworkPriority {
PriorityNormal = 0x00,
PriorityUrgent = 0x01,
PriorityCritical = 0x10,
PriorityLifeSafety = 0x11
};
}
void BacnetNpci::setExpectingReply(bool expectReply)
{
if (expectReply)
_controlOctet |= BitFields::Bit2;
else
_controlOctet &= (~BitFields::Bit2);
}
void BacnetNpci::setApduMessage()
{
_controlOctet &= (~BitFields::Bit7);
//maybe shouldn't set this one?
_messageType = LastVendor;
}
void BacnetNpci::setNetworkMessage(BacnetNetworkMessageType netMsgType)
{
//set network message flag in the control octet
_controlOctet |= BitFields::Bit7;
//remember message type
_messageType = netMsgType;
}
BacnetAddress &BacnetNpci::destAddress()
{
//! \todo = maybe I should check if control bit is set?
return _destAddr;
}
void BacnetNpci::setDestAddress(const BacnetAddress &addr)
{
_controlOctet |= BitFields::Bit5;
_destAddr = addr;
}
BacnetAddress &BacnetNpci::srcAddress()
{
//! \todo = maybe I should check if control bit is set?
return _srcAddr;
}
void BacnetNpci::setSrcAddress(const BacnetAddress &addr)
{
_controlOctet |= BitFields::Bit3;
_srcAddr = addr;
}