cMicroOrp  1.0.0
C code for microcontrollers - provides ORP remote interface
orp_protocol.h
Go to the documentation of this file.
1 /*
2 Copyright <2020> <J Thompson>
3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6 */
7 
8 #ifndef ORP_PROTOCOL_H
9 #define ORP_PROTOCOL_H
10 
11 #ifdef __cplusplus
12 extern "C" {
13 #endif
14 
15 /*
16 * https://docs.octave.dev/references/edge/octave_resource_protocol/#the-octave-resource-protocol
17 * https://docs.octave.dev/docs/octave-resource-protocol#section-response-structure
18 */
19 
20 
21 // 0<packet type[1]>1<status[1]>2<segment[2]>4<contents[variable]>
22 #define ORP_PACKET_TYPE_FIELD 0
23 #define ORP_PACKET_STATUS_FIELD 1
24 #define ORP_PACKET_SEGMENT_START_FIELD 2
25 #define ORP_PACKET_CONTENTS_START_FIELD 4
26 
27 //
28 // Packet type field - byte 0
29 //
30 
31 
32 #define SBR_PKT_RQST_INPUT_CREATE 'I' // type[1] d_type[1] pad[2] path[] units[]
33 #define SBR_PKT_RESP_INPUT_CREATE 'i' // type[1] status[1] pad[2]
34 
35 #define SBR_PKT_RQST_OUTPUT_CREATE 'O' // type[1] d_type[1] pad[2] path[] units[]
36 #define SBR_PKT_RESP_OUTPUT_CREATE 'o' // type[1] status[1] pad[2]
37 
38 #define SBR_PKT_RQST_DELETE 'D' // type[1] pad[1] pad[2] path[]
39 #define SBR_PKT_RESP_DELETE 'd' // type[1] status[1] pad[2]
40 
41 #define SBR_PKT_RQST_HANDLER_ADD 'H' // type[1] pad[1] pad[2] path[]
42 #define SBR_PKT_RESP_HANDLER_ADD 'h' // type[1] status[1] pad[2]
43 
44 #define SBR_PKT_RQST_HANDLER_REMOVE 'K' // type[1] pad[1] pad[2] path[]
45 #define SBR_PKT_RESP_HANDLER_REMOVE 'k' // type[1] status[1] pad[2]
46 
47 #define SBR_PKT_RQST_PUSH 'P' // type[1] d_type[1] pad[2] time[] path[] data[]
48 #define SBR_PKT_RESP_PUSH 'p' // type[1] status[1] pad[2]
49 
50 #define SBR_PKT_RQST_GET 'G' // type[1] pad[1] pad[2] path[]
51 #define SBR_PKT_RESP_GET 'g' // type[1] status[1] pad[2] time[] data[]
52 
53 #define SBR_PKT_RQST_EXAMPLE_SET 'E' // type[1] d_type[1] pad[2] path[] data[]
54 #define SBR_PKT_RESP_EXAMPLE_SET 'e' // type[1] status[1] pad[2]
55 
56 #define SBR_PKT_RQST_SENSOR_CREATE 'S' // type[1] d_type[1] pad[2] path[] units[]
57 #define SBR_PKT_RESP_SENSOR_CREATE 's' // type[1] status[1] pad[2]
58 
59 #define SBR_PKT_RQST_SENSOR_REMOVE 'R' // type[1] pad[1] pad[2] path[]
60 #define SBR_PKT_RESP_SENSOR_REMOVE 'r' // type[1] status[1] pad[2]
61 
62 #define SBR_PKT_NTFY_HANDLER_CALL 'c' // type[1] d_type[1] pad[2] time[] path[] data[]
63 #define SBR_PKT_RESP_HANDLER_CALL 'C' // type[1] status[1] pad[2]
64 
65 #define SBR_PKT_NTFY_SENSOR_CALL 'b' // type[1] pad[1] pad[2] path[]
66 #define SBR_PKT_RESP_SENSOR_CALL 'B' // type[1] status[1] pad[2]
67 
68 #define SBR_PKT_RESP_UNKNOWN_RQST '?' // type[1] status[1] pad[2]
69 
70 
71 //
72 // Data type field - byte 1
73 //
74 
75 
76 #define SBR_DATA_TYPE_TRIGGER 'T' // trigger - no data
77 #define SBR_DATA_TYPE_BOOLEAN 'B' // Boolean - 1 byte: 't' | 'f'
78 #define SBR_DATA_TYPE_NUMERIC 'N' // numeric - null-terminated ASCII string, representing double
79 #define SBR_DATA_TYPE_STRING 'S' // string - null-terminated ASCII string
80 #define SBR_DATA_TYPE_JSON 'J' // JSON - null-terminated ASCII string, representing JSON
81 #define SBR_DATA_TYPE_UNDEF ' ' // not specified
82 
83 #define OK '@' // weird encoding status value = -1 * (<status byte> - 0x40) ==== 0
84 
85 
86 //
87 //
88 //
89 //
90 //
91 typedef enum
92  {
117  UN_INITIALISED = -101
119 
120 //
121 // Variable length field identifiers
122 //
123 #define SBR_FIELD_ID_PATH 'P'
124 #define SBR_FIELD_ID_TIME 'T'
125 #define SBR_FIELD_ID_UNITS 'U'
126 #define SBR_FIELD_ID_DATA 'D'
127 
128 // Variable length field separator
129 #define SBR_VARLENGTH_SEPARATOR ','
130 
131 
132 // public:
133 
134 // prototypes for callback functions
135 typedef void (* orp_hdlc_tx_cb) (uint8_t); // to send data to the physical interface (UART ...)
136 typedef void (* orp_delay100ms_cb) (void); // used for wakeup function
137 
138 
139 /*
140  Current thinking on RX data handling.
141 
142  We have two types of unsolicited data from the Octave Edge device
143  1. Notification Packets - these contain payload data sent by the Octave edge
144  1.1 context is set by the Path 'P' in the example below
145  1.2 and example PushHandler packet "c@01T1585927713.843660,Pval/od/value,D456.000000"
146  1.3 I think one callback handler will be ok - it pumps incoming key/value pairs to the app
147  1.4 Defined as SBR_PKT_NTFY_xxxxx above. For example SBR_PKT_NTFY_HANDLER_CALL and SBR_PKT_NTFY_SENSOR_CALL
148  2. Request response Packets
149  2.1 these contain command ack responses from Octave edge
150  2.2 there is an problem here there is no ack context available - therefore only one Request can be sent at once
151  2.3 I think one callback handler will be ok - we need to save the context (path) when the original call is made
152  2.4 We need to lock the sending interface whilst waiting for a response
153  2.5 Defined as SBR_PKT_RESP_xxxxx above
154 
155 
156  Thinking is we have a orp protocol app which intercepts the incoming packets and
157  splits them into two types.
158  Next question is - what do they call ?
159 
160  At the moment plan is to have 2 application callback functions
161  1. appRequestIn_cbf
162  2. appNotificationIn_cbf
163 
164  Then some helper functions to decode the cb payload
165  Initially I was thinking of mapping outputs to individual callbacks but i think
166  it's better of the user app does this by looking at the key (path)
167 
168  packet structure:
169  <packet type[1]><status[1]><segment[2]><contents[variable]>
170 
171  Fields:
172  packet type : Identifies response, 1-byte
173  status : Identifies status of response. 1-byte
174  segment : Count allowing a responses to span multiple packets. 2-bytes
175  contents : Packet dependent, variable length
176 
177 */
178 // Use the following as a prototype for all app response callbacks
180 (
181  const uint8_t *buffer,
182  uint16_t bufferLength
183 );
184 
185 // Use the following as a prototype for all app notification callbacks
187 (
188  const uint8_t *buffer,
189  uint16_t bufferLength
190 );
191 
192 // pass in buffer references
193 void orp_protocol(
194  char * app_orp_inPayload, // encoder input payload
195  size_t app_orp_inPayloadSize, // encoder input payload size
196 
197  orp_hdlc_tx_cb tx_char_cbh, // encoder - bind TX a byte to UART
198  // decoder - no need to bind RX as the HDLC layer has a direct write input
199 
200  // hdlc_decoder_callback_type hdlc_decoded_callback, // decoder - frame decoded callback with payload
201  uint8_t *hdlc_rx_buffer, // decoder - working buffer
202  uint16_t hdlc_rx_bufferSize, // decoder - length of working buffer
203 
204  orp_protocol_genericRequestResponse_cb appRequestIn_cbf, // app function called by rx decoder when response arrives
205  orp_protocol_genericNotification_cb appNotificationIn_cbf // app function called by rx decoder when Notification arrives
206 );
207 
208 
209 // * Apps sends RAW HDLC data from serial stream in via this function one byte at a time
210 void orp_protocol_processHdlcRx(uint8_t data);
211 
213 
214 
215 int16_t orp_protocol_pushValue(
216  uint8_t dataType,
217  const char *path,
218  const char * data
219 );
220 
222  char packetType,
223  char dataType,
224  const char *path,
225  const char * units
226 );
227 
229  uint8_t dataType,
230  const char *path
231 );
232 
233 
234 
235 
236 // todo:
237 // The serial cycle is one at a time - send and ack.
238 // But with possible unsolicited events as well
239 // ideally we need a way to set a flag whilst waiting for an request response ack
240 // or maybe the app can decide if it wants to ignore the request response (ack)
241 //
242 // We need to implement some Notification and RequestResponse data decode helper functions
243 
244 
245 #ifdef __cplusplus
246 }
247 #endif
248 
249 #endif // ORP_PROTOCOL_H
STATUS_OK
@ STATUS_OK
Definition: orp_protocol.h:93
NOT_PERMITTED
@ NOT_PERMITTED
Definition: orp_protocol.h:98
CLOSED
@ CLOSED
Definition: orp_protocol.h:109
FORMAT_ERROR
@ FORMAT_ERROR
Definition: orp_protocol.h:106
COMM_ERROR
@ COMM_ERROR
Definition: orp_protocol.h:100
orp_protocol_genericNotification_cb
void(* orp_protocol_genericNotification_cb)(const uint8_t *buffer, uint16_t bufferLength)
Definition: orp_protocol.h:187
WOULD_BLOCK
@ WOULD_BLOCK
Definition: orp_protocol.h:104
orp_delay100ms_cb
void(* orp_delay100ms_cb)(void)
Definition: orp_protocol.h:136
DEADLOCK
@ DEADLOCK
Definition: orp_protocol.h:105
WAITING_RESPONSE
@ WAITING_RESPONSE
Definition: orp_protocol.h:116
UN_INITIALISED
@ UN_INITIALISED
Definition: orp_protocol.h:117
TIMEOUT
@ TIMEOUT
Definition: orp_protocol.h:101
OVERFLOW
@ OVERFLOW
Definition: orp_protocol.h:102
orp_protocol_pushValue
int16_t orp_protocol_pushValue(uint8_t dataType, const char *path, const char *data)
Definition: orp_protocol.c:166
orp_protocol_processHdlcRx
void orp_protocol_processHdlcRx(uint8_t data)
Definition: orp_protocol.c:114
FAULT
@ FAULT
Definition: orp_protocol.h:99
orp_protocol_createResource
int16_t orp_protocol_createResource(char packetType, char dataType, const char *path, const char *units)
Definition: orp_protocol.c:126
orp_protocol_genericRequestResponse_cb
void(* orp_protocol_genericRequestResponse_cb)(const uint8_t *buffer, uint16_t bufferLength)
Definition: orp_protocol.h:180
UNSUPPORTED
@ UNSUPPORTED
Definition: orp_protocol.h:111
orp_responseStatusEnum
orp_responseStatusEnum
Definition: orp_protocol.h:92
NOT_FOUND
@ NOT_FOUND
Definition: orp_protocol.h:94
OUT_OF_RANGE
@ OUT_OF_RANGE
Definition: orp_protocol.h:96
orp_protocol_wakeup
void orp_protocol_wakeup(orp_delay100ms_cb)
Definition: orp_protocol.c:120
IO_ERROR
@ IO_ERROR
Definition: orp_protocol.h:112
orp_hdlc_tx_cb
void(* orp_hdlc_tx_cb)(uint8_t)
Definition: orp_protocol.h:135
orp_protocol_addpushHandler
int16_t orp_protocol_addpushHandler(uint8_t dataType, const char *path)
Definition: orp_protocol.c:190
UNDERFLOW
@ UNDERFLOW
Definition: orp_protocol.h:103
NO_MEMORY
@ NO_MEMORY
Definition: orp_protocol.h:97
BUSY
@ BUSY
Definition: orp_protocol.h:110
BAD_PARAMETER
@ BAD_PARAMETER
Definition: orp_protocol.h:108
orp_protocol
void orp_protocol(char *app_orp_inPayload, size_t app_orp_inPayloadSize, orp_hdlc_tx_cb tx_char_cbh, uint8_t *hdlc_rx_buffer, uint16_t hdlc_rx_bufferSize, orp_protocol_genericRequestResponse_cb appRequestIn_cbf, orp_protocol_genericNotification_cb appNotificationIn_cbf)
Definition: orp_protocol.c:78
TERMINATED
@ TERMINATED
Definition: orp_protocol.h:115
DUPLICATE
@ DUPLICATE
Definition: orp_protocol.h:107
NOT_IMPLEMENTED
@ NOT_IMPLEMENTED
Definition: orp_protocol.h:113
NOT_POSSIBLE
@ NOT_POSSIBLE
Definition: orp_protocol.h:95
UNAVAILABLE
@ UNAVAILABLE
Definition: orp_protocol.h:114