1 // CayenneLPP Decoder
2 //
3 // Decodes a CayenneLPP binary buffer to JSON format
4 //
5 // https://os.mbed.com/teams/myDevicesIoT/code/Cayenne-LPP
6 // https://github.com/open-source-parsers/jsoncpp
7 //
8 // Copyright (c) 2018 Robbert E. Peters. All rights reserved.
9 // Licensed under the MIT License. See LICENSE file in the project root for full license information.
10 //
11 // 29 April 2018 - Initial Version
12 //
13
14 #include "stdafx.h"
15 #include "CayenneLPP_Dec.h"
16 #include <json/json.h>
17
18 /*
19 Example Usage:
20 CayenneLPP lpp(200);
21
22 lpp.addTemperature(1, 10.4f);
23 lpp.addTemperature(2, -23.5f);
24
25 lpp.addDigitalInput(1, 0);
26 lpp.addDigitalOutput(1, 1);
27
28 lpp.addAnalogInput(1, 1.23f);
29 lpp.addAnalogOutput(1, 3.45f);
30
31 lpp.addLuminosity(1, 20304);
32 lpp.addPresence(1, 1);
33 lpp.addTemperature(3, 26.5f);
34 lpp.addRelativeHumidity(1, 86.6f);
35 lpp.addAccelerometer(1, 1.234f, -1.234f, 0.567f);
36 lpp.addBarometricPressure(1, 1023.4f);
37 lpp.addGyrometer(1, -12.34f, 45.56f, 89.01f);
38 lpp.addGPS(1, 54.184668f, 7.886778f , -6.3f);
39
40 //Decode buffer to JSON
41 Json::Value root;
42
43 if (CayenneLPPDec::ParseLPP(lpp.getBuffer(), lpp.getSize(), root))
44 {
45 std::cout << "Found " << root.size() << " entries:\n\n";
46 std::cout << root.toStyledString();
47 }
48 */
49
ParseLPP(const uint8_t * pBuffer,size_t Len,Json::Value & root)50 bool CayenneLPPDec::ParseLPP(const uint8_t *pBuffer, size_t Len, Json::Value &root)
51 {
52 int iIndex = 0;
53 while (Len > 2)
54 {
55 uint8_t channel = pBuffer[0];
56 uint8_t lpp_type = pBuffer[1];
57
58 if (lpp_type == LPP_DIGITAL_INPUT) {
59 if (Len < LPP_DIGITAL_INPUT_SIZE)
60 return false;
61
62 root[iIndex]["channel"] = channel;
63 root[iIndex]["type"] = "digital_input";
64
65 root[iIndex++]["value"] = pBuffer[2];
66
67 pBuffer += LPP_DIGITAL_INPUT_SIZE;
68 Len -= LPP_DIGITAL_INPUT_SIZE;
69 }
70 else if (lpp_type == LPP_DIGITAL_OUTPUT) {
71 if (Len < LPP_DIGITAL_OUTPUT_SIZE)
72 return false;
73
74 root[iIndex]["channel"] = channel;
75 root[iIndex]["type"] = "digital_output";
76
77 root[iIndex++]["value"] = pBuffer[2];
78
79 pBuffer += LPP_DIGITAL_OUTPUT_SIZE;
80 Len -= LPP_DIGITAL_OUTPUT_SIZE;
81 }
82 else if (lpp_type == LPP_ANALOG_INPUT) {
83 if (Len < LPP_ANALOG_INPUT_SIZE)
84 return false;
85
86 root[iIndex]["channel"] = channel;
87 root[iIndex]["type"] = "analog_input";
88
89 float value = float((pBuffer[2] << 8) | pBuffer[3]) / 100.0f;
90 root[iIndex++]["value"] = value;
91
92 pBuffer += LPP_ANALOG_INPUT_SIZE;
93 Len -= LPP_ANALOG_INPUT_SIZE;
94 }
95 else if (lpp_type == LPP_ANALOG_OUTPUT) {
96 if (Len < LPP_ANALOG_OUTPUT_SIZE)
97 return false;
98
99 root[iIndex]["channel"] = channel;
100 root[iIndex]["type"] = "analog_output";
101
102 float value = float((pBuffer[2] << 8) | pBuffer[3]) / 100.0f;
103 root[iIndex++]["value"] = value;
104
105 pBuffer += LPP_ANALOG_OUTPUT_SIZE;
106 Len -= LPP_ANALOG_OUTPUT_SIZE;
107 }
108 else if (lpp_type == LPP_LUMINOSITY) {
109 if (Len < LPP_LUMINOSITY_SIZE)
110 return false;
111
112 root[iIndex]["channel"] = channel;
113 root[iIndex]["type"] = "luminosity";
114
115 uint16_t value = (pBuffer[2] << 8) | pBuffer[3];
116 root[iIndex++]["value"] = value;
117
118 pBuffer += LPP_LUMINOSITY_SIZE;
119 Len -= LPP_LUMINOSITY_SIZE;
120 }
121 else if (lpp_type == LPP_PRESENCE) {
122 if (Len < LPP_PRESENCE_SIZE)
123 return false;
124
125 root[iIndex]["channel"] = channel;
126 root[iIndex]["type"] = "presence";
127
128 root[iIndex++]["value"] = pBuffer[2];
129
130 pBuffer += LPP_PRESENCE_SIZE;
131 Len -= LPP_PRESENCE_SIZE;
132 }
133 else if (lpp_type == LPP_TEMPERATURE) {
134 if (Len < LPP_TEMPERATURE_SIZE)
135 return false;
136
137 root[iIndex]["channel"] = channel;
138 root[iIndex]["type"] = "temp";
139
140 float value = float(int16_t((pBuffer[2] << 8) | pBuffer[3])) / 10.0f;
141 root[iIndex++]["value"] = value;
142
143 pBuffer += LPP_TEMPERATURE_SIZE;
144 Len -= LPP_TEMPERATURE_SIZE;
145 }
146 else if (lpp_type == LPP_RELATIVE_HUMIDITY) {
147 if (Len < LPP_RELATIVE_HUMIDITY_SIZE)
148 return false;
149
150 root[iIndex]["channel"] = channel;
151 root[iIndex]["type"] = "humidity";
152
153 float value = float(pBuffer[2]) / 2.0f;
154 root[iIndex++]["value"] = value;
155
156 pBuffer += LPP_RELATIVE_HUMIDITY_SIZE;
157 Len -= LPP_RELATIVE_HUMIDITY_SIZE;
158 }
159 else if (lpp_type == LPP_ACCELEROMETER) {
160 if (Len < LPP_ACCELEROMETER_SIZE)
161 return false;
162
163 root[iIndex]["channel"] = channel;
164 root[iIndex]["type"] = "accel";
165
166 int16_t tvalue = (pBuffer[2] << 8) | pBuffer[3];
167 float value = float(tvalue) / 1000.0f;
168 root[iIndex]["X"] = value;
169 tvalue = (pBuffer[4] << 8) | pBuffer[5];
170 value = float(tvalue) / 1000.0f;
171 root[iIndex]["Y"] = value;
172 tvalue = (pBuffer[6] << 8) | pBuffer[7];
173 value = float(tvalue) / 1000.0f;
174 root[iIndex++]["Z"] = value;
175
176 pBuffer += LPP_ACCELEROMETER_SIZE;
177 Len -= LPP_ACCELEROMETER_SIZE;
178 }
179 else if (lpp_type == LPP_BAROMETRIC_PRESSURE) {
180 if (Len < LPP_BAROMETRIC_PRESSURE_SIZE)
181 return false;
182
183 root[iIndex]["channel"] = channel;
184 root[iIndex]["type"] = "baro";
185
186 float value = float(int16_t((pBuffer[2] << 8) | pBuffer[3])) / 10.0f;
187 root[iIndex++]["value"] = value;
188
189 pBuffer += LPP_BAROMETRIC_PRESSURE_SIZE;
190 Len -= LPP_BAROMETRIC_PRESSURE_SIZE;
191 }
192 else if (lpp_type == LPP_UNIXTIME) {
193 if (Len < LPP_UNIXTIME_SIZE)
194 return false;
195
196 root[iIndex]["channel"] = channel;
197 root[iIndex]["type"] = "unixtime";
198
199 uint32_t value = (pBuffer[2] << 24) | (pBuffer[3] << 16) | (pBuffer[4] << 8) | pBuffer[5];
200 root[iIndex++]["value"] = value;
201
202 pBuffer += LPP_UNIXTIME_SIZE;
203 Len -= LPP_UNIXTIME_SIZE;
204 }
205 else if (lpp_type == LPP_GYROMETER) {
206 if (Len < LPP_GYROMETER_SIZE)
207 return false;
208
209 root[iIndex]["channel"] = channel;
210 root[iIndex]["type"] = "gyro";
211
212 int16_t tvalue = (pBuffer[2] << 8) | pBuffer[3];
213 float value = float(tvalue) / 100.0f;
214 root[iIndex]["X"] = value;
215 tvalue = (pBuffer[4] << 8) | pBuffer[5];
216 value = float(tvalue) / 100.0f;
217 root[iIndex]["Y"] = value;
218 tvalue = (pBuffer[6] << 8) | pBuffer[7];
219 value = float(tvalue) / 100.0f;
220 root[iIndex++]["Z"] = value;
221
222 pBuffer += LPP_GYROMETER_SIZE;
223 Len -= LPP_GYROMETER_SIZE;
224 }
225 else if (lpp_type == LPP_GPS) {
226 if (Len < LPP_GPS_SIZE)
227 return false;
228
229 root[iIndex]["channel"] = channel;
230 root[iIndex]["type"] = "gps";
231
232 int32_t tvalue = (int32_t)(pBuffer[2] << 16) | (pBuffer[3] << 8) | pBuffer[4];
233 if ((pBuffer[2]&0xF0) == 0xF0)
234 tvalue |= 0xFF000000;
235 float value = float(tvalue) / 10000.0f;
236 root[iIndex]["lat"] = value;
237 tvalue = (pBuffer[5] << 16) | (pBuffer[6] << 8) | pBuffer[7];
238 if ((pBuffer[5] & 0xF0) == 0xF0)
239 tvalue |= 0xFF000000;
240 value = float(tvalue) / 10000.0f;
241 root[iIndex]["lon"] = value;
242 tvalue = (int32_t)((pBuffer[8] << 16) | (pBuffer[9] << 8) | pBuffer[10]);
243 if ((pBuffer[8] & 0xF0) == 0xF0)
244 tvalue |= 0xFF000000;
245 value = float(tvalue) / 100.0f;
246 root[iIndex++]["alt"] = value;
247
248 pBuffer += LPP_GPS_SIZE;
249 Len -= LPP_GPS_SIZE;
250 }
251 else {
252 return false;
253 }
254 }
255 return (Len==0);
256 }