px-fwlib 0.10.0
Cross-platform embedded library and documentation for 8/16/32-bit microcontrollers generated with Doxygen 1.9.2
px_c1098.c
1/* =============================================================================
2 ____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
3 | _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
4 | |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
5 | __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
6 |_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
7
8 Copyright (c) 2013 Pieter Conradie <https://piconomix.com>
9
10 License: MIT
11 https://github.com/piconomix/px-fwlib/blob/master/LICENSE.md
12
13 Title: COMedia C1098 CMOS Camera Module driver
14 Author(s): Pieter Conradie
15 Creation Date: 2013-03-30
16
17============================================================================= */
18
19/* _____STANDARD INCLUDES____________________________________________________ */
20
21/* _____PROJECT INCLUDES_____________________________________________________ */
22#include "px_c1098.h"
23#include "px_uart.h"
24#include "px_systmr.h"
25#include "px_sysclk.h"
26#include "px_log.h"
27
28/* _____LOCAL DEFINITIONS____________________________________________________ */
29PX_LOG_NAME("px_c1098");
30
31typedef enum
32{
33 PX_C1098_STATE_DONE = 0,
34 PX_C1098_STATE_ERROR,
35 PX_C1098_STATE_WAIT_ACK,
36 PX_C1098_STATE_WAIT_AFTER_ACK,
37 PX_C1098_STATE_SYNC,
38 PX_C1098_STATE_SYNC_WAIT_ACK,
39 PX_C1098_STATE_SYNC_WAIT_SYNC,
40 PX_C1098_STATE_GET_PIC_WAIT_ACK,
41 PX_C1098_STATE_WAIT_DATA_LENGTH,
42 PX_C1098_STATE_WAIT_DATA_PACKAGE,
43} px_c1098_state_t;
44
45/// C1098 Command format
46typedef struct
47{
48 uint8_t start;
49 uint8_t id;
50 uint8_t param1;
51 uint8_t param2;
52 uint8_t param3;
53 uint8_t param4;
55
56/// Package data format
57typedef struct
58{
59 uint8_t id_lo8;
60 uint8_t id_hi8;
61 uint8_t data_size_lo8;
62 uint8_t data_size_hi8;
63 uint8_t image_data[PX_C1098_DATA_BLOCK_SIZE];
64 uint8_t verify_code_lo8;
65 uint8_t verify_code_hi8;
67
68#define PX_C1098_RX_DATA_BUFFER_SIZE 256
69
70// C1098 Start character
71#define PX_C1098_START 0xaa
72
73// C1098 IDs
74#define PX_C1098_ID_INITIAL 0x01
75#define PX_C1098_ID_GET_PICTURE 0x04
76#define PX_C1098_ID_SNAPSHOT 0x05
77#define PX_C1098_ID_SET_PACKAGE_SIZE 0x06
78#define PX_C1098_ID_RESET 0x08
79#define PX_C1098_ID_DATA_LENGTH 0x0a
80#define PX_C1098_ID_SYNC 0x0d
81#define PX_C1098_ID_ACK 0x0e
82#define PX_C1098_ID_NAK 0x0f
83
84/* _____MACROS_______________________________________________________________ */
85
86/* _____GLOBAL VARIABLES_____________________________________________________ */
87
88/* _____LOCAL VARIABLES______________________________________________________ */
89static px_uart_handle_t * px_c1098_uart_handle;
90static px_c1098_state_t px_c1098_state;
91static px_systmr_t px_c1098_state_tmr;
92static px_systmr_ticks_t px_c1098_delay_after_ack_in_ticks;
93static px_c1098_cmd_t px_c1098_tx_cmd_packet;
94static uint8_t px_c1098_retry_cntr;
95
96static union
97{
99 px_c1098_package_data_t package_data;
100 uint8_t data[sizeof(px_c1098_package_data_t)];
101} px_c1098_rx_packet;
102
103static uint16_t px_c1098_rx_data_index;
104static px_c1098_on_rx_data_t px_c1098_on_rx_data;
105static uint32_t px_c1098_data_length;
106static uint16_t px_c1098_package_id;
107
108/* _____LOCAL FUNCTION DECLARATIONS__________________________________________ */
109
110/* _____LOCAL FUNCTIONS______________________________________________________ */
111const char * px_c1098_state_to_str(px_c1098_state_t state)
112{
113 switch(state)
114 {
115 case PX_C1098_STATE_DONE: return "DONE");
116 case PX_C1098_STATE_ERROR: return "ERROR");
117 case PX_C1098_STATE_WAIT_ACK: return "WAIT_ACK");
118 case PX_C1098_STATE_WAIT_AFTER_ACK: return "WAIT_AFTER_ACK");
119 case PX_C1098_STATE_SYNC: return "SYNC");
120 case PX_C1098_STATE_SYNC_WAIT_ACK: return "SYNC_WAIT_ACK");
121 case PX_C1098_STATE_SYNC_WAIT_SYNC: return "SYNC_WAIT_SYNC");
122 case PX_C1098_STATE_GET_PIC_WAIT_ACK: return "GET_PIC_WAIT_ACK");
123 case PX_C1098_STATE_WAIT_DATA_LENGTH: return "WAIT_DATA_LENGTH");
124 case PX_C1098_STATE_WAIT_DATA_PACKAGE: return "WAIT_DATA_PACKAGE");
125 default: return "???");
126 }
127}
128static void px_c1098_tx_data(uint8_t * data, uint8_t nr_of_bytes)
129{
130 while(nr_of_bytes != 0)
131 {
132 px_uart_putchar(px_c1098_uart_handle, *data++);
133 nr_of_bytes--;
134 }
135}
136
137static void px_c1098_tx_cmd(uint8_t id,
138 uint8_t param1,
139 uint8_t param2,
140 uint8_t param3,
141 uint8_t param4)
142{
143 px_c1098_tx_cmd_packet.start = PX_C1098_START;
144 px_c1098_tx_cmd_packet.id = id;
145 px_c1098_tx_cmd_packet.param1 = param1;
146 px_c1098_tx_cmd_packet.param2 = param2;
147 px_c1098_tx_cmd_packet.param3 = param3;
148 px_c1098_tx_cmd_packet.param4 = param4;
149
150 PX_LOG_D("TX %02X %02X %02X %02X %02X %02X", px_c1098_tx_cmd_packet.start,
151 px_c1098_tx_cmd_packet.id,
152 px_c1098_tx_cmd_packet.param1,
153 px_c1098_tx_cmd_packet.param2,
154 px_c1098_tx_cmd_packet.param3,
155 px_c1098_tx_cmd_packet.param4);
156
157 px_c1098_tx_data((uint8_t *)&px_c1098_tx_cmd_packet, sizeof(px_c1098_tx_cmd_packet));
158}
159
160static void px_c1098_change_state(px_c1098_state_t new_state)
161{
162 // Change state
163 px_c1098_state = new_state;
164 // Reset receiver
165 px_c1098_rx_data_index = 0;
166
167 // Report new state
168 PX_LOG_D("%010ul - state %s", (unsigned long)px_sysclk_get_tick_count(),
169 px_c1098_state_to_str(px_c1098_state));
170}
171
172static void px_c1098_ack_data_package(void)
173{
174 // Send ACK
175 px_c1098_tx_cmd(PX_C1098_ID_ACK, 0x00, 0x00, PX_U16_LO8(px_c1098_package_id),
176 PX_U16_HI8(px_c1098_package_id));
177 px_systmr_start(&px_c1098_state_tmr, PX_SYSTMR_MS_TO_TICKS(200));
178 px_c1098_change_state(PX_C1098_STATE_WAIT_DATA_PACKAGE);
179}
180
181static bool px_c1098_package_data_checksum_ok(uint16_t data_size)
182{
183 uint16_t checksum = 0;
184 uint16_t i;
185
186 for(i = 0; i < (data_size + 4); i++)
187 {
188 checksum += px_c1098_rx_packet.data[i];
189 }
190
191 if( (px_c1098_rx_packet.data[i] == PX_U16_LO8(checksum))
192 &&(px_c1098_rx_packet.data[i + 1] == 0x00 ) )
193 {
194 return true;
195 }
196 else
197 {
198 return false;
199 }
200}
201
202static void px_c1098_on_rx_byte(uint8_t data)
203{
204 uint16_t data_size;
205
207 {
208 if(px_c1098_rx_data_index == 0)
209 {
210 PX_LOG_D("RX %02X", data);
211 }
212 else
213 {
214 PX_LOG_TRACE(" %02X", data);
215 }
216 }
217
218 // Buffer full?
219 if(px_c1098_rx_data_index >= sizeof(px_c1098_rx_packet))
220 {
221 // Discard received byte
222 return;
223 }
224 // Buffer received data
225 px_c1098_rx_packet.data[px_c1098_rx_data_index++] = data;
226 // Received command?
227 if( (px_c1098_state != PX_C1098_STATE_WAIT_DATA_PACKAGE)
228 &&(px_c1098_rx_data_index == sizeof(px_c1098_cmd_t) )
229 &&(px_c1098_rx_packet.cmd.start == PX_C1098_START ) )
230 {
231 // Received NAK?
232 if( (px_c1098_rx_packet.cmd.id == PX_C1098_ID_NAK)
233 &&(px_c1098_rx_packet.cmd.param4 == 0x00 ) )
234 {
235 //Error
236 px_c1098_change_state(PX_C1098_STATE_ERROR);
237 return;
238 }
239 // Handle command according to state
240 switch(px_c1098_state)
241 {
242 case PX_C1098_STATE_WAIT_ACK:
243 if( (px_c1098_rx_packet.cmd.id == PX_C1098_ID_ACK )
244 &&(px_c1098_rx_packet.cmd.param1 == px_c1098_tx_cmd_packet.id)
245 &&(px_c1098_rx_packet.cmd.param3 == 0x00 )
246 &&(px_c1098_rx_packet.cmd.param4 == 0x00 ) )
247 {
248 if(px_c1098_delay_after_ack_in_ticks != 0)
249 {
250 px_systmr_start(&px_c1098_state_tmr, px_c1098_delay_after_ack_in_ticks);
251 px_c1098_change_state(PX_C1098_STATE_WAIT_AFTER_ACK);
252 }
253 else
254 {
255 px_c1098_change_state(PX_C1098_STATE_DONE);
256 }
257 }
258 break;
259
260 case PX_C1098_STATE_SYNC_WAIT_ACK:
261 if( (px_c1098_rx_packet.cmd.id == PX_C1098_ID_ACK )
262 &&(px_c1098_rx_packet.cmd.param1 == PX_C1098_ID_SYNC)
263 &&(px_c1098_rx_packet.cmd.param3 == 0x00 )
264 &&(px_c1098_rx_packet.cmd.param4 == 0x00 ) )
265 {
266 px_c1098_change_state(PX_C1098_STATE_SYNC_WAIT_SYNC);
267 }
268 break;
269
270 case PX_C1098_STATE_SYNC_WAIT_SYNC:
271 if( (px_c1098_rx_packet.cmd.id == PX_C1098_ID_SYNC)
272 &&(px_c1098_rx_packet.cmd.param1 == 0x00 )
273 &&(px_c1098_rx_packet.cmd.param2 == 0x00 )
274 &&(px_c1098_rx_packet.cmd.param3 == 0x00 )
275 &&(px_c1098_rx_packet.cmd.param4 == 0x00 ) )
276 {
277 // Send ACK
278 px_c1098_tx_cmd(PX_C1098_ID_ACK, 0x00, 0x00, 0x00, 0x00);
279 px_c1098_change_state(PX_C1098_STATE_DONE);
280
281 }
282 break;
283
284 case PX_C1098_STATE_GET_PIC_WAIT_ACK:
285 if( (px_c1098_rx_packet.cmd.id == PX_C1098_ID_ACK )
286 &&(px_c1098_rx_packet.cmd.param1 == px_c1098_tx_cmd_packet.id)
287 &&(px_c1098_rx_packet.cmd.param3 == 0x00 )
288 &&(px_c1098_rx_packet.cmd.param4 == 0x00 ) )
289 {
290 px_c1098_change_state(PX_C1098_STATE_WAIT_DATA_LENGTH);
291 }
292 break;
293
294 case PX_C1098_STATE_WAIT_DATA_LENGTH:
295 if( (px_c1098_rx_packet.cmd.id == PX_C1098_ID_DATA_LENGTH)
296 &&(px_c1098_rx_packet.cmd.param1 == 0x01 ) )
297 {
298 px_c1098_data_length = PX_U32_CONCAT_U8(0,
299 px_c1098_rx_packet.cmd.param4,
300 px_c1098_rx_packet.cmd.param3,
301 px_c1098_rx_packet.cmd.param2);
302 PX_LOG_D("Data Length = %u bytes", px_c1098_data_length);
303 px_c1098_ack_data_package();
304 }
305 break;
306
307 default:
308 break;
309 }
310 }
311 // Received Package ID and Package Length?
312 if(px_c1098_rx_data_index < 4)
313 {
314 return;
315 }
316 // Package ID correct?
317 if( (px_c1098_rx_packet.package_data.id_hi8 != PX_U16_HI8(px_c1098_package_id))
318 ||(px_c1098_rx_packet.package_data.id_lo8 != PX_U16_LO8(px_c1098_package_id)) )
319 {
320 return;
321 }
322 // Calculate data size
323 data_size = PX_U16_CONCAT_U8(px_c1098_rx_packet.package_data.data_size_hi8,
324 px_c1098_rx_packet.package_data.data_size_lo8);
325 // Data size correct?
326 if(data_size > PX_C1098_DATA_BLOCK_SIZE)
327 {
328 return;
329 }
330 if(data_size != PX_C1098_DATA_BLOCK_SIZE)
331 {
332 if(data_size != px_c1098_data_length)
333 {
334 return;
335 }
336 }
337 // Received whole package?
338 if(px_c1098_rx_data_index < (data_size+6))
339 {
340 return;
341 }
342 // Checksum correct?
343 if(!px_c1098_package_data_checksum_ok(data_size))
344 {
345 PX_LOG_E("Checksum incorrect");
346 return;
347 }
348 // Pass data to handler
349 (*px_c1098_on_rx_data)(px_c1098_rx_packet.package_data.image_data, data_size);
350 // Last package?
351 if(px_c1098_data_length == data_size)
352 {
353 px_c1098_data_length = 0;
354 // Done!
355 px_c1098_change_state(PX_C1098_STATE_DONE);
356 }
357 else
358 {
359 px_c1098_data_length -= data_size;
360 PX_LOG_D("Data Length = %u", px_c1098_data_length);
361 // Next package ID
362 px_c1098_package_id++;
363 // Reset retry counter
364 px_c1098_retry_cntr = 3;
365 // Send ACK
366 px_c1098_ack_data_package();
367 }
368}
369
370
371/* _____GLOBAL FUNCTIONS_____________________________________________________ */
372void px_c1098_init(px_uart_handle_t * handle)
373{
374 px_c1098_uart_handle = handle;
375 px_c1098_state = PX_C1098_STATE_DONE;
376 px_c1098_on_rx_data = NULL;
377 px_c1098_rx_data_index = 0;
378 px_c1098_delay_after_ack_in_ticks = 0;
379 px_systmr_stop(&px_c1098_state_tmr);
380}
381
382void px_c1098_task(void)
383{
384 uint8_t data;
385
386 // Process received data
387 while(px_uart_rd_u8(px_c1098_uart_handle, &data))
388 {
389 px_c1098_on_rx_byte(data);
390 }
391
392 switch(px_c1098_state)
393 {
394 case PX_C1098_STATE_WAIT_ACK:
395 // Fall through...
396 case PX_C1098_STATE_GET_PIC_WAIT_ACK:
397 // Fall through...
398 case PX_C1098_STATE_WAIT_DATA_LENGTH:
399 // Timer expired?
400 if(px_systmr_has_expired(&px_c1098_state_tmr))
401 {
402 // Error
403 px_c1098_change_state(PX_C1098_STATE_ERROR);
404 }
405 break;
406
407 case PX_C1098_STATE_WAIT_DATA_PACKAGE:
408 // Timer expired?
409 if(px_systmr_has_expired(&px_c1098_state_tmr))
410 {
411 // Retry?
412 if(px_c1098_retry_cntr > 0)
413 {
414 // Retry
415 px_c1098_retry_cntr--;
416 px_c1098_ack_data_package();
417 }
418 else
419 {
420 // Error
421 px_c1098_change_state(PX_C1098_STATE_ERROR);
422 }
423 }
424 break;
425
426 case PX_C1098_STATE_WAIT_AFTER_ACK:
427 // Timer expired?
428 if(px_systmr_has_expired(&px_c1098_state_tmr))
429 {
430 // Done
431 px_c1098_change_state(PX_C1098_STATE_DONE);
432 }
433 break;
434
435 case PX_C1098_STATE_SYNC:
436 // Send SYNC command
437 px_c1098_tx_cmd(PX_C1098_ID_SYNC, 0x00, 0x00, 0x00, 0x00);
438
439 // Start timeout and change state
440 px_systmr_start(&px_c1098_state_tmr, PX_SYSTMR_MS_TO_TICKS(200));
441 px_c1098_change_state(PX_C1098_STATE_SYNC_WAIT_ACK);
442 break;
443
444 case PX_C1098_STATE_SYNC_WAIT_ACK:
445 // Timer expired?
446 if(px_systmr_has_expired(&px_c1098_state_tmr))
447 {
448 // Retry?
449 if(px_c1098_retry_cntr > 0)
450 {
451 // Retry
452 px_c1098_retry_cntr--;
453 px_c1098_change_state(PX_C1098_STATE_SYNC);
454 }
455 else
456 {
457 // Error
458 px_c1098_change_state(PX_C1098_STATE_ERROR);
459 }
460 }
461 break;
462
463 default:
464 break;
465 }
466}
467
468bool px_c1098_busy(void)
469{
470 if( (px_c1098_state != PX_C1098_STATE_DONE )
471 &&(px_c1098_state != PX_C1098_STATE_ERROR) )
472 {
473 return true;
474 }
475 else
476 {
477 return false;
478 }
479}
480
481bool px_c1098_error(void)
482{
483 if(px_c1098_state == PX_C1098_STATE_ERROR)
484 {
485 return true;
486 }
487 else
488 {
489 return false;
490 }
491}
492bool px_c1098_task_execute(void)
493{
494 while(px_c1098_busy())
495 {
496 px_c1098_task();
497 }
498
499 return px_c1098_error();
500}
501
502void px_c1098_initial(uint8_t if_speed, uint8_t jpeg_res)
503{
504 PX_LOG_D("INITIAL");
505 // Send INITIAL command
506 px_c1098_tx_cmd(PX_C1098_ID_INITIAL, if_speed, 0x07, 0x00, jpeg_res);
507 // Start timeout
508 px_systmr_start(&px_c1098_state_tmr, PX_SYSTMR_MS_TO_TICKS(200));
509 // post-ACK delay
510 px_c1098_delay_after_ack_in_ticks = PX_SYSTMR_MS_TO_TICKS(50);
511 // Wait for ACK
512 px_c1098_change_state(PX_C1098_STATE_WAIT_ACK);
513}
514
515void px_c1098_set_package_size(void)
516{
517 PX_LOG_D("SET_PACKAGE_SIZE");
518 // Send PACKAGE_SIZE command
519 px_c1098_tx_cmd(PX_C1098_ID_SET_PACKAGE_SIZE, 0x08, PX_U16_LO8(PX_C1098_DATA_BLOCK_SIZE + 6), PX_U16_HI8(PX_C1098_DATA_BLOCK_SIZE + 6), 0x00);
520 // Start timeout
521 px_systmr_start(&px_c1098_state_tmr, PX_SYSTMR_MS_TO_TICKS(200));
522 // No post-ACK delay
523 px_c1098_delay_after_ack_in_ticks = 0;
524 // Wait for ACK
525 px_c1098_change_state(PX_C1098_STATE_WAIT_ACK);
526}
527
528void px_c1098_reset(uint8_t rst_priority)
529{
530 PX_LOG_D("RESET");
531 // Send RESET command
532 px_c1098_tx_cmd(PX_C1098_ID_RESET, 0x00, 0x00, 0x00, rst_priority);
533 // Start timeout
534 px_systmr_start(&px_c1098_state_tmr, PX_SYSTMR_MS_TO_TICKS(200));
535 // post-ACK delay
536 px_c1098_delay_after_ack_in_ticks = PX_SYSTMR_MS_TO_TICKS(20);
537 // Wait for ACK
538 px_c1098_change_state(PX_C1098_STATE_WAIT_ACK);
539}
540
541void px_c1098_sync(void)
542{
543 PX_LOG_D("SYNC");
544 px_c1098_retry_cntr = 10;
545 px_c1098_change_state(PX_C1098_STATE_SYNC);
546}
547
548void px_c1098_snapshot(void)
549{
550 PX_LOG_D("SNAPSHOT");
551 // Send SNAPSHOT command
552 px_c1098_tx_cmd(PX_C1098_ID_SNAPSHOT, 0x00, 0x00, 0x00, 0x00);
553 // Start timeout and change state
554 px_systmr_start(&px_c1098_state_tmr, PX_SYSTMR_MS_TO_TICKS(200));
555 px_c1098_change_state(PX_C1098_STATE_WAIT_ACK);
556}
557
558uint32_t px_c1098_get_picture_size(void)
559{
560 return px_c1098_data_length;
561}
562
563void px_c1098_get_picture(px_c1098_on_rx_data_t on_rx_data)
564{
565 // Set handler to process / store received image data
566 px_c1098_on_rx_data = on_rx_data;
567 // Reset package ID
568 px_c1098_package_id = 0;
569 // Reset retry counter
570 px_c1098_retry_cntr = 3;
571 PX_LOG_D("GET_PICTURE");
572 // Send GET_PICTURE command
573 px_c1098_tx_cmd(PX_C1098_ID_GET_PICTURE, 0x01, 0x00, 0x00, 0x00);
574 // Start timeout and change state
575 px_systmr_start(&px_c1098_state_tmr, PX_SYSTMR_MS_TO_TICKS(200));
576 px_c1098_change_state(PX_C1098_STATE_GET_PIC_WAIT_ACK);
577}
void(* px_c1098_on_rx_data_t)(const uint8_t *data, uint16_t bytes_received)
Definition for a pointer to a function that will be called once a block of data has been received.
Definition: px_c1098.h:72
#define NULL
NULL pointer.
Definition: px_defs.h:49
#define PX_U16_HI8(data)
Extract the high 8 bits of a 16-bit value (Most Significant Byte)
Definition: px_defs.h:225
#define PX_U16_CONCAT_U8(hi8, lo8)
Concatenate 2 x 8 bits to form 16-bit value.
Definition: px_defs.h:268
#define PX_U32_CONCAT_U8(hi8, mh8, ml8, lo8)
Concatenate 4 x 8 bits to form 32-bit value.
Definition: px_defs.h:273
#define PX_U16_LO8(data)
Extract the low 8 bits of a 16-bit value (Least Significant Byte)
Definition: px_defs.h:228
#define PX_LOG_D(format,...)
Macro to display a formatted DEBUG message.
Definition: px_log.h:410
#define PX_LOG_TRACE(format,...)
Macro to output a user format string if PX_LOG=1.
Definition: px_log.h:458
#define PX_LOG_NAME(name)
Macro to declare a log name string once for each file to reduce code size.
Definition: px_log.h:349
#define PX_LOG_LEVEL_IS_D()
Debug level enabled?
Definition: px_log.h:371
#define PX_LOG_E(format,...)
Macro to display a formatted ERROR message.
Definition: px_log.h:377
void px_systmr_stop(px_systmr_t *systmr)
Stop a running timer.
Definition: px_systmr.c:103
void px_systmr_start(px_systmr_t *systmr, const px_systmr_ticks_t delay_in_ticks)
Start a timer.
Definition: px_systmr.c:35
px_sysclk_ticks_t px_systmr_ticks_t
Size definition of the tick counter.
Definition: px_systmr.h:63
#define PX_SYSTMR_MS_TO_TICKS(delay_in_ms)
Macro used to convert a timeout in milliseconds to timer ticks.
Definition: px_systmr.h:177
bool px_systmr_has_expired(px_systmr_t *systmr)
See if a timer has expired.
Definition: px_systmr.c:57
Structure to track state of a timer.
Definition: px_systmr.h:75
px_sysclk_ticks_t px_sysclk_get_tick_count(void)
Return number of ticks since system clock started.
Definition: px_sysclk.c:97
bool px_uart_rd_u8(px_uart_handle_t *handle, uint8_t *data)
See if a received byte is available and store it in the specified location.
Definition: px_uart.c:726
void px_uart_putchar(px_uart_handle_t *handle, char data)
Write one byte.
Definition: px_uart.c:632
Define UART handle.
Definition: px_uart.h:141
C1098 Command format.
Definition: px_c1098.c:47
Package data format.
Definition: px_c1098.c:58