1 /*!
2  * \file      CayenneLpp.c
3  *
4  * \brief     Implements the Cayenne Low Power Protocol
5  *
6  * \copyright Revised BSD License, see section \ref LICENSE.
7  *
8  * \code
9  *                ______                              _
10  *               / _____)             _              | |
11  *              ( (____  _____ ____ _| |_ _____  ____| |__
12  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
13  *               _____) ) ____| | | || |_| ____( (___| | | |
14  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
15  *              (C)2013-2018 Semtech
16  *
17  * \endcode
18  *
19  * \author    Miguel Luis ( Semtech )
20  */
21 #include <stdint.h>
22 
23 #include "utilities.h"
24 #include "CayenneLpp.h"
25 
26 #define CAYENNE_LPP_MAXBUFFER_SIZE                  242
27 
28 static uint8_t CayenneLppBuffer[CAYENNE_LPP_MAXBUFFER_SIZE];
29 static uint8_t CayenneLppCursor = 0;
30 
CayenneLppInit(void)31 void CayenneLppInit( void )
32 {
33     CayenneLppCursor = 0;
34 }
35 
CayenneLppReset(void)36 void CayenneLppReset( void )
37 {
38     CayenneLppCursor = 0;
39 }
40 
CayenneLppGetSize(void)41 uint8_t CayenneLppGetSize( void )
42 {
43     return CayenneLppCursor;
44 }
45 
CayenneLppGetBuffer(void)46 uint8_t* CayenneLppGetBuffer( void )
47 {
48     return CayenneLppBuffer;
49 }
50 
CayenneLppCopy(uint8_t * dst)51 uint8_t CayenneLppCopy( uint8_t* dst )
52 {
53     memcpy1( dst, CayenneLppBuffer, CayenneLppCursor );
54 
55     return CayenneLppCursor;
56 }
57 
58 
CayenneLppAddDigitalInput(uint8_t channel,uint8_t value)59 uint8_t CayenneLppAddDigitalInput( uint8_t channel, uint8_t value )
60 {
61     if( ( CayenneLppCursor + LPP_DIGITAL_INPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
62     {
63         return 0;
64     }
65     CayenneLppBuffer[CayenneLppCursor++] = channel;
66     CayenneLppBuffer[CayenneLppCursor++] = LPP_DIGITAL_INPUT;
67     CayenneLppBuffer[CayenneLppCursor++] = value;
68 
69     return CayenneLppCursor;
70 }
71 
CayenneLppAddDigitalOutput(uint8_t channel,uint8_t value)72 uint8_t CayenneLppAddDigitalOutput( uint8_t channel, uint8_t value )
73 {
74     if( ( CayenneLppCursor + LPP_DIGITAL_OUTPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
75     {
76         return 0;
77     }
78     CayenneLppBuffer[CayenneLppCursor++] = channel;
79     CayenneLppBuffer[CayenneLppCursor++] = LPP_DIGITAL_OUTPUT;
80     CayenneLppBuffer[CayenneLppCursor++] = value;
81 
82     return CayenneLppCursor;
83 }
84 
85 
CayenneLppAddAnalogInput(uint8_t channel,float value)86 uint8_t CayenneLppAddAnalogInput( uint8_t channel, float value )
87 {
88     if( ( CayenneLppCursor + LPP_ANALOG_INPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
89     {
90         return 0;
91     }
92 
93     int16_t val = ( int16_t ) ( value * 100 );
94     CayenneLppBuffer[CayenneLppCursor++] = channel;
95     CayenneLppBuffer[CayenneLppCursor++] = LPP_ANALOG_INPUT;
96     CayenneLppBuffer[CayenneLppCursor++] = val >> 8;
97     CayenneLppBuffer[CayenneLppCursor++] = val;
98 
99     return CayenneLppCursor;
100 }
101 
CayenneLppAddAnalogOutput(uint8_t channel,float value)102 uint8_t CayenneLppAddAnalogOutput( uint8_t channel, float value )
103 {
104     if( ( CayenneLppCursor + LPP_ANALOG_OUTPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
105     {
106         return 0;
107     }
108     int16_t val = ( int16_t ) ( value * 100 );
109     CayenneLppBuffer[CayenneLppCursor++] = channel;
110     CayenneLppBuffer[CayenneLppCursor++] = LPP_ANALOG_OUTPUT;
111     CayenneLppBuffer[CayenneLppCursor++] = val >> 8;
112     CayenneLppBuffer[CayenneLppCursor++] = val;
113 
114     return CayenneLppCursor;
115 }
116 
117 
CayenneLppAddLuminosity(uint8_t channel,uint16_t lux)118 uint8_t CayenneLppAddLuminosity( uint8_t channel, uint16_t lux )
119 {
120     if( ( CayenneLppCursor + LPP_LUMINOSITY_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
121     {
122         return 0;
123     }
124     CayenneLppBuffer[CayenneLppCursor++] = channel;
125     CayenneLppBuffer[CayenneLppCursor++] = LPP_LUMINOSITY;
126     CayenneLppBuffer[CayenneLppCursor++] = lux >> 8;
127     CayenneLppBuffer[CayenneLppCursor++] = lux;
128 
129     return CayenneLppCursor;
130 }
131 
CayenneLppAddPresence(uint8_t channel,uint8_t value)132 uint8_t CayenneLppAddPresence( uint8_t channel, uint8_t value )
133 {
134     if( ( CayenneLppCursor + LPP_PRESENCE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
135     {
136         return 0;
137     }
138     CayenneLppBuffer[CayenneLppCursor++] = channel;
139     CayenneLppBuffer[CayenneLppCursor++] = LPP_PRESENCE;
140     CayenneLppBuffer[CayenneLppCursor++] = value;
141 
142     return CayenneLppCursor;
143 }
144 
CayenneLppAddTemperature(uint8_t channel,float celsius)145 uint8_t CayenneLppAddTemperature( uint8_t channel, float celsius )
146 {
147     if( ( CayenneLppCursor + LPP_TEMPERATURE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
148     {
149         return 0;
150     }
151     int16_t val = ( int16_t) ( celsius * 10 );
152     CayenneLppBuffer[CayenneLppCursor++] = channel;
153     CayenneLppBuffer[CayenneLppCursor++] = LPP_TEMPERATURE;
154     CayenneLppBuffer[CayenneLppCursor++] = val >> 8;
155     CayenneLppBuffer[CayenneLppCursor++] = val;
156 
157     return CayenneLppCursor;
158 }
159 
CayenneLppAddRelativeHumidity(uint8_t channel,float rh)160 uint8_t CayenneLppAddRelativeHumidity( uint8_t channel, float rh )
161 {
162     if( ( CayenneLppCursor + LPP_RELATIVE_HUMIDITY_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
163     {
164         return 0;
165     }
166     CayenneLppBuffer[CayenneLppCursor++] = channel;
167     CayenneLppBuffer[CayenneLppCursor++] = LPP_RELATIVE_HUMIDITY;
168     CayenneLppBuffer[CayenneLppCursor++] = (uint8_t ) ( rh * 2 );
169 
170     return CayenneLppCursor;
171 }
172 
CayenneLppAddAccelerometer(uint8_t channel,float x,float y,float z)173 uint8_t CayenneLppAddAccelerometer( uint8_t channel, float x, float y, float z )
174 {
175     if( ( CayenneLppCursor + LPP_ACCELEROMETER_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
176     {
177         return 0;
178     }
179     int16_t vx = ( int16_t ) ( x * 1000 );
180     int16_t vy = ( int16_t ) ( y * 1000 );
181     int16_t vz = ( int16_t ) ( z * 1000 );
182 
183     CayenneLppBuffer[CayenneLppCursor++] = channel;
184     CayenneLppBuffer[CayenneLppCursor++] = LPP_ACCELEROMETER;
185     CayenneLppBuffer[CayenneLppCursor++] = vx >> 8;
186     CayenneLppBuffer[CayenneLppCursor++] = vx;
187     CayenneLppBuffer[CayenneLppCursor++] = vy >> 8;
188     CayenneLppBuffer[CayenneLppCursor++] = vy;
189     CayenneLppBuffer[CayenneLppCursor++] = vz >> 8;
190     CayenneLppBuffer[CayenneLppCursor++] = vz;
191 
192     return CayenneLppCursor;
193 }
194 
CayenneLppAddBarometricPressure(uint8_t channel,float hpa)195 uint8_t CayenneLppAddBarometricPressure( uint8_t channel, float hpa )
196 {
197     if( ( CayenneLppCursor + LPP_BAROMETRIC_PRESSURE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
198     {
199         return 0;
200     }
201     int16_t val = ( int16_t ) ( hpa * 10 );
202 
203     CayenneLppBuffer[CayenneLppCursor++] = channel;
204     CayenneLppBuffer[CayenneLppCursor++] = LPP_BAROMETRIC_PRESSURE;
205     CayenneLppBuffer[CayenneLppCursor++] = val >> 8;
206     CayenneLppBuffer[CayenneLppCursor++] = val;
207 
208     return CayenneLppCursor;
209 }
210 
CayenneLppAddGyrometer(uint8_t channel,float x,float y,float z)211 uint8_t CayenneLppAddGyrometer( uint8_t channel, float x, float y, float z )
212 {
213     if( ( CayenneLppCursor + LPP_GYROMETER_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
214     {
215         return 0;
216     }
217     int16_t vx = ( int16_t ) ( x * 100 );
218     int16_t vy = ( int16_t ) ( y * 100 );
219     int16_t vz = ( int16_t ) ( z * 100 );
220 
221     CayenneLppBuffer[CayenneLppCursor++] = channel;
222     CayenneLppBuffer[CayenneLppCursor++] = LPP_GYROMETER;
223     CayenneLppBuffer[CayenneLppCursor++] = vx >> 8;
224     CayenneLppBuffer[CayenneLppCursor++] = vx;
225     CayenneLppBuffer[CayenneLppCursor++] = vy >> 8;
226     CayenneLppBuffer[CayenneLppCursor++] = vy;
227     CayenneLppBuffer[CayenneLppCursor++] = vz >> 8;
228     CayenneLppBuffer[CayenneLppCursor++] = vz;
229 
230     return CayenneLppCursor;
231 }
232 
CayenneLppAddGps(uint8_t channel,float latitude,float longitude,float meters)233 uint8_t CayenneLppAddGps( uint8_t channel, float latitude, float longitude, float meters )
234 {
235     if( ( CayenneLppCursor + LPP_GPS_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE )
236     {
237         return 0;
238     }
239     int32_t lat = ( int32_t ) ( latitude * 10000 );
240     int32_t lon = ( int32_t ) ( longitude * 10000 );
241     int32_t alt = ( int32_t ) ( meters * 100 );
242 
243     CayenneLppBuffer[CayenneLppCursor++] = channel;
244     CayenneLppBuffer[CayenneLppCursor++] = LPP_GPS;
245 
246     CayenneLppBuffer[CayenneLppCursor++] = lat >> 16;
247     CayenneLppBuffer[CayenneLppCursor++] = lat >> 8;
248     CayenneLppBuffer[CayenneLppCursor++] = lat;
249     CayenneLppBuffer[CayenneLppCursor++] = lon >> 16;
250     CayenneLppBuffer[CayenneLppCursor++] = lon >> 8;
251     CayenneLppBuffer[CayenneLppCursor++] = lon;
252     CayenneLppBuffer[CayenneLppCursor++] = alt >> 16;
253     CayenneLppBuffer[CayenneLppCursor++] = alt >> 8;
254     CayenneLppBuffer[CayenneLppCursor++] = alt;
255 
256     return CayenneLppCursor;
257 }
258