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 }