LibDriver APM2000
Loading...
Searching...
No Matches
driver_apm2000.c
Go to the documentation of this file.
1
36
37#include "driver_apm2000.h"
38
42#define CHIP_NAME "ASAIR APM2000"
43#define MANUFACTURER_NAME "ASAIR"
44#define SUPPLY_VOLTAGE_MIN 4.75f
45#define SUPPLY_VOLTAGE_MAX 5.25f
46#define MAX_CURRENT 100.0f
47#define TEMPERATURE_MIN -10.0f
48#define TEMPERATURE_MAX 50.0f
49#define DRIVER_VERSION 1000
50
54#define APM2000_ADDRESS (0x08 << 1)
55
59#define APM2000_REG_START 0x0010U
60#define APM2000_REG_STOP 0x0104U
61#define APM2000_REG_READ 0x0300U
62
71static uint8_t a_apm2000_generate_crc(apm2000_handle_t *handle, uint8_t* data, uint8_t count)
72{
73 if (handle->iic_uart == APM2000_INTERFACE_IIC)
74 {
75 uint8_t current_byte;
76 uint8_t crc = 0xFF;
77 uint8_t crc_bit;
78
79 for (current_byte = 0; current_byte < count; current_byte++) /* calculate crc */
80 {
81 crc ^= (data[current_byte]); /* xor data */
82 for (crc_bit = 8; crc_bit > 0; --crc_bit) /* 8 bit */
83 {
84 if ((crc & 0x80) != 0) /* if 7th bit is 1 */
85 {
86 crc = (crc << 1) ^ 0x31; /* xor */
87 }
88 else
89 {
90 crc = crc << 1; /* left shift 1 */
91 }
92 }
93 }
94
95 return crc; /* return crc */
96 }
97 else
98 {
99 uint8_t i;
100 uint32_t sum = 0x00;
101
102 for (i = 0; i < count; i++) /* sum */
103 {
104 sum += data[i]; /* sum */
105 }
106
107 return (uint8_t)((sum & 0xFF)); /* return sum */
108 }
109}
110
122static uint8_t a_apm2000_iic_read(apm2000_handle_t *handle, uint16_t reg, uint8_t *data, uint16_t len)
123{
124 if (handle->iic_read_address16(APM2000_ADDRESS, reg, (uint8_t *)data, len) != 0) /* read data */
125 {
126 return 1; /* return error */
127 }
128
129 return 0; /* success return 0 */
130}
131
143static uint8_t a_apm2000_iic_write(apm2000_handle_t *handle, uint16_t reg, uint8_t *data, uint16_t len)
144{
145 if (handle->iic_write_address16(APM2000_ADDRESS, reg, (uint8_t *)data, len) != 0) /* write data */
146 {
147 return 1; /* return error */
148 }
149
150 return 0; /* success return 0 */
151}
152
166static uint8_t a_apm2000_uart_write_read(apm2000_handle_t *handle, uint8_t *input, uint16_t in_len,
167 uint16_t delay_ms, uint8_t *output, uint16_t out_len)
168{
169 uint16_t len;
170
171 if (handle->uart_flush() != 0) /* uart flush */
172 {
173 return 1; /* return error */
174 }
175 if (handle->uart_write(input, in_len) != 0) /* write data */
176 {
177 return 1; /* return error */
178 }
179 handle->delay_ms(delay_ms); /* delay ms */
180 len = handle->uart_read(output, out_len); /* read data */
181 if (len != out_len) /* check output length */
182 {
183 return 1; /* return error */
184 }
185
186 return 0; /* success return 0 */
187}
188
198static uint16_t a_apm2000_uart_make_frame(apm2000_handle_t *handle, uint8_t cmd, uint8_t *data, uint8_t len)
199{
200 memset(handle->buf, 0, 255 + 5); /* init buffer */
201 handle->buf[0] = 0xFE; /* set 0xFE */
202 handle->buf[1] = 0xA5; /* set 0xA5 */
203 handle->buf[2] = len; /* set length */
204 handle->buf[3] = cmd; /* set command */
205 if (len != 0) /* check length */
206 {
207 memcpy(&handle->buf[4], data, len); /* copy data */
208 }
209 handle->buf[4 + len] = a_apm2000_generate_crc(handle, &handle->buf[1], len + 3); /* generate crc */
210
211 return (uint16_t)(len + 5); /* return crc */
212}
213
226static uint8_t a_apm2000_uart_parse_frame(apm2000_handle_t *handle, uint8_t len, uint8_t *cmd, uint8_t *data, uint8_t *out_len)
227{
228 uint8_t crc;
229
230 if (len < 6) /* check length */
231 {
232 return 1; /* return error */
233 }
234 if (handle->buf[0] != 0xFE) /* check header */
235 {
236 handle->debug_print("apm2000: header is invalid.\n"); /* header is invalid */
237
238 return 1; /* return error */
239 }
240 if (handle->buf[1] != 0xA5) /* check frame code */
241 {
242 handle->debug_print("apm2000: no frame code.\n"); /* no frame code */
243
244 return 1; /* return error */
245 }
246 if (handle->buf[2] != 0x02) /* check length */
247 {
248 handle->debug_print("apm2000: length is invalid.\n"); /* length is invalid */
249
250 return 1; /* return error */
251 }
252 crc = a_apm2000_generate_crc(handle, &handle->buf[1], len - 2); /* generate crc */
253 if (crc != handle->buf[len - 1]) /* check crc */
254 {
255 handle->debug_print("apm2000: crc is invalid.\n"); /* crc is invalid */
256
257 return 1; /* return error */
258 }
259 *cmd = handle->buf[3]; /* set command */
260 if ((len - 5) != (*out_len)) /* check length */
261 {
262 handle->debug_print("apm2000: output length is invalid.\n"); /* output length is invalid */
263
264 return 1; /* return error */
265 }
266 memcpy(data, &handle->buf[4], (*out_len)); /* copy data */
267
268 return 0; /* success return 0 */
269}
270
281{
282 if (handle == NULL) /* check handle */
283 {
284 return 2; /* return error */
285 }
286
287 handle->iic_uart = (uint8_t)interface; /* set interface */
288
289 return 0; /* success return 0 */
290}
291
302{
303 if (handle == NULL) /* check handle */
304 {
305 return 2; /* return error */
306 }
307
308 *interface = (apm2000_interface_t)(handle->iic_uart); /* get interface */
309
310 return 0; /* success return 0 */
311}
312
325{
326 if (handle == NULL) /* check handle */
327 {
328 return 2; /* return error */
329 }
330 if (handle->inited != 1) /* check handle initialization */
331 {
332 return 3; /* return error */
333 }
334
335 if (handle->iic_uart != 0) /* uart */
336 {
337 handle->debug_print("apm2000: uart can't use this function.\n"); /* uart can't use this function */
338
339 return 4; /* return error */
340 }
341 else /* iic */
342 {
343 uint8_t res;
344 uint8_t buf[3];
345
346 buf[0] = 0x05; /* set param0 */
347 buf[1] = 0x00; /* set param1 */
348 buf[2] = 0xF6; /* set param2 */
349 res = a_apm2000_iic_write(handle, APM2000_REG_START, (uint8_t *)buf, 3); /* start measurement command */
350 if (res != 0) /* check result */
351 {
352 handle->debug_print("apm2000: start measurement failed.\n"); /* start measurement failed */
353
354 return 1; /* return error */
355 }
356 }
357
358 return 0; /* success return 0 */
359}
360
373{
374 if (handle == NULL) /* check handle */
375 {
376 return 2; /* return error */
377 }
378 if (handle->inited != 1) /* check handle initialization */
379 {
380 return 3; /* return error */
381 }
382
383 if (handle->iic_uart != 0) /* uart */
384 {
385 handle->debug_print("apm2000: uart can't use this function.\n"); /* uart can't use this function */
386
387 return 4; /* return error */
388 }
389 else /* iic */
390 {
391 uint8_t res;
392
393 res = a_apm2000_iic_write(handle, APM2000_REG_STOP, NULL, 0); /* stop measurement command */
394 if (res != 0) /* check result */
395 {
396 handle->debug_print("apm2000: stop measurement failed.\n"); /* stop measurement failed */
397
398 return 1; /* return error */
399 }
400 }
401
402 return 0; /* success return 0 */
403}
404
418{
419 uint8_t res;
420
421 if ((handle == NULL) || (pm == NULL)) /* check handle */
422 {
423 return 2; /* return error */
424 }
425 if (handle->inited != 1) /* check handle initialization */
426 {
427 return 3; /* return error */
428 }
429
430 if (handle->iic_uart != 0) /* uart */
431 {
432 uint8_t cmd;
433 uint8_t out_len;
434 uint8_t data[6];
435 uint16_t len;
436
437 len = a_apm2000_uart_make_frame(handle, 0x01, NULL, 0); /* make frame */
438 res = a_apm2000_uart_write_read(handle, handle->buf, len,
439 200, handle->buf, 11);
440 if (res != 0) /* check result */
441 {
442 handle->debug_print("apm2000: uart write read failed.\n"); /* uart write read failed */
443
444 return 1; /* return error */
445 }
446 out_len = 6; /* set output length */
447 res = a_apm2000_uart_parse_frame(handle, 11, &cmd, data, &out_len); /* parse frame */
448 if (res != 0) /* check result */
449 {
450 return 1; /* return error */
451 }
452 if (cmd != 0x00) /* check command */
453 {
454 handle->debug_print("apm2000: command is invalid.\n"); /* command is invalid. */
455
456 return 1; /* return error */
457 }
458 pm->pm1p0_ug_m3 = ((uint16_t)data[0]) << 8 | data[1]; /* set data */
459 pm->pm2p5_ug_m3 = ((uint16_t)data[2]) << 8 | data[3]; /* set data */
460 pm->pm10_ug_m3 = ((uint16_t)data[4]) << 8 | data[5]; /* set data */
461 }
462 else /* iic */
463 {
464 uint8_t buf[30];
465
466 res = a_apm2000_iic_read(handle, APM2000_REG_READ, (uint8_t *)buf, 30); /* read data */
467 if (res != 0) /* check result */
468 {
469 handle->debug_print("apm2000: read data failed.\n"); /* read data failed */
470
471 return 1; /* return error */
472 }
473 if (buf[2] != a_apm2000_generate_crc(handle, (uint8_t *)buf + 0, 2)) /* check crc */
474 {
475 handle->debug_print("apm2000: crc check failed.\n"); /* crc check failed */
476
477 return 4; /* return error */
478 }
479 if (buf[5] != a_apm2000_generate_crc(handle, (uint8_t *)buf + 3, 2)) /* check crc */
480 {
481 handle->debug_print("apm2000: crc check failed.\n"); /* crc check failed */
482
483 return 4; /* return error */
484 }
485 if (buf[11] != a_apm2000_generate_crc(handle, (uint8_t *)buf + 9, 2)) /* check crc */
486 {
487 handle->debug_print("apm2000: crc check failed.\n"); /* crc check failed */
488
489 return 4; /* return error */
490 }
491 pm->pm1p0_ug_m3 = ((uint16_t)buf[0]) << 8 | buf[1]; /* set data */
492 pm->pm2p5_ug_m3 = ((uint16_t)buf[3]) << 8 | buf[4]; /* set data */
493 pm->pm10_ug_m3 = ((uint16_t)buf[9]) << 8 | buf[10]; /* set data */
494 }
495
496 return 0; /* success return 0 */
497}
498
511uint8_t apm2000_read_pm2p5(apm2000_handle_t *handle, uint16_t *pm2p5_ug_m3)
512{
513 uint8_t res;
514
515 if (handle == NULL) /* check handle */
516 {
517 return 2; /* return error */
518 }
519 if (handle->inited != 1) /* check handle initialization */
520 {
521 return 3; /* return error */
522 }
523
524 if (handle->iic_uart != 0) /* uart */
525 {
526 uint8_t cmd;
527 uint8_t out_len;
528 uint8_t data[6];
529 uint16_t len;
530
531 len = a_apm2000_uart_make_frame(handle, 0x00, NULL, 0); /* make frame */
532 res = a_apm2000_uart_write_read(handle, handle->buf, len,
533 200, handle->buf, 7);
534 if (res != 0) /* check result */
535 {
536 handle->debug_print("apm2000: uart write read failed.\n"); /* uart write read failed */
537
538 return 1; /* return error */
539 }
540 out_len = 2; /* set output length */
541 res = a_apm2000_uart_parse_frame(handle, 7, &cmd, data, &out_len); /* parse frame */
542 if (res != 0) /* check result */
543 {
544 return 1; /* return error */
545 }
546 if (cmd != 0x00) /* check command */
547 {
548 handle->debug_print("apm2000: command is invalid.\n"); /* command is invalid. */
549
550 return 1; /* return error */
551 }
552 *pm2p5_ug_m3 = ((uint16_t)data[0]) << 8 | data[1]; /* set data */
553 }
554 else /* iic */
555 {
556 handle->debug_print("apm2000: iic can't use this function.\n"); /* iic can't use this function */
557
558 return 4; /* return error */
559 }
560
561 return 0; /* success return 0 */
562}
563
575{
576 if (handle == NULL) /* check handle */
577 {
578 return 2; /* return error */
579 }
580 if (handle->debug_print == NULL) /* check debug_print */
581 {
582 return 3; /* return error */
583 }
584 if (handle->iic_init == NULL) /* check iic_init */
585 {
586 handle->debug_print("apm2000: iic_init is null.\n"); /* iic_init is null */
587
588 return 3; /* return error */
589 }
590 if (handle->iic_deinit == NULL) /* check iic_deinit */
591 {
592 handle->debug_print("apm2000: iic_deinit is null.\n"); /* iic_deinit is null */
593
594 return 3; /* return error */
595 }
596 if (handle->iic_write_address16 == NULL) /* check iic_write_address16 */
597 {
598 handle->debug_print("apm2000: iic_write_address16 is null.\n"); /* iic_write_address16 is null */
599
600 return 3; /* return error */
601 }
602 if (handle->iic_read_address16 == NULL) /* check iic_read_address16 */
603 {
604 handle->debug_print("apm2000: iic_read_address16 is null.\n"); /* iic_read_address16 is null */
605
606 return 3; /* return error */
607 }
608 if (handle->uart_init == NULL) /* check uart_init */
609 {
610 handle->debug_print("apm2000: uart_init is null.\n"); /* uart_init is null */
611
612 return 3; /* return error */
613 }
614 if (handle->uart_deinit == NULL) /* check uart_deinit */
615 {
616 handle->debug_print("apm2000: uart_deinit is null.\n"); /* uart_deinit is null */
617
618 return 3; /* return error */
619 }
620 if (handle->uart_read == NULL) /* check uart_read */
621 {
622 handle->debug_print("apm2000: uart_read is null.\n"); /* uart_read is null */
623
624 return 3; /* return error */
625 }
626 if (handle->uart_write == NULL) /* check uart_write */
627 {
628 handle->debug_print("apm2000: uart_write is null.\n"); /* uart_write is null */
629
630 return 3; /* return error */
631 }
632 if (handle->uart_flush == NULL) /* check uart_flush */
633 {
634 handle->debug_print("apm2000: uart_flush is null.\n"); /* uart_flush is null */
635
636 return 3; /* return error */
637 }
638 if (handle->delay_ms == NULL) /* check delay_ms */
639 {
640 handle->debug_print("apm2000: delay_ms is null.\n"); /* delay_ms is null */
641
642 return 3; /* return error */
643 }
644
645 if (handle->iic_uart != 0) /* uart */
646 {
647 if (handle->uart_init() != 0) /* uart init */
648 {
649 handle->debug_print("apm2000: uart init failed.\n"); /* uart init failed */
650
651 return 1; /* return error */
652 }
653 }
654 else /* iic */
655 {
656 if (handle->iic_init() != 0) /* iic init */
657 {
658 handle->debug_print("apm2000: iic init failed.\n"); /* iic init failed */
659
660 return 1; /* return error */
661 }
662 }
663 handle->inited = 1; /* flag finish initialization */
664
665 return 0; /* success return 0 */
666}
667
679{
680 uint8_t res;
681
682 if (handle == NULL) /* check handle */
683 {
684 return 2; /* return error */
685 }
686 if (handle->inited != 1) /* check handle initialization */
687 {
688 return 3; /* return error */
689 }
690
691 if (handle->iic_uart != 0) /* uart */
692 {
693 if (handle->uart_deinit() != 0) /* uart deinit */
694 {
695 handle->debug_print("apm2000: uart deinit failed.\n"); /* uart deinit failed */
696
697 return 1; /* return error */
698 }
699 }
700 else /* iic */
701 {
702 res = handle->iic_deinit(); /* iic deinit */
703 if (res != 0) /* check result */
704 {
705 handle->debug_print("apm2000: iic deinit failed.\n"); /* iic deinit */
706
707 return 1; /* return error */
708 }
709 }
710 handle->inited = 0; /* flag close initialization */
711
712 return 0; /* success return 0 */
713}
714
727uint8_t apm2000_set_get_reg_uart(apm2000_handle_t *handle, uint8_t *input, uint16_t in_len, uint8_t *output, uint16_t out_len)
728{
729 if (handle == NULL) /* check handle */
730 {
731 return 2; /* return error */
732 }
733 if (handle->inited != 1) /* check handle initialization */
734 {
735 return 3; /* return error */
736 }
737
738 if (handle->iic_uart != 0)
739 {
740 return a_apm2000_uart_write_read(handle, input, in_len, 200, output, out_len); /* write and read with the uart interface */
741 }
742 else
743 {
744 handle->debug_print("apm2000: iic interface is invalid.\n"); /* iic interface is invalid */
745
746 return 1; /* return error */
747 }
748}
749
763uint8_t apm2000_set_reg_iic(apm2000_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
764{
765 if (handle == NULL) /* check handle */
766 {
767 return 2; /* return error */
768 }
769 if (handle->inited != 1) /* check handle initialization */
770 {
771 return 3; /* return error */
772 }
773
774 if (handle->iic_uart != 0)
775 {
776 handle->debug_print("apm2000: uart interface is invalid.\n"); /* uart interface is invalid */
777
778 return 1; /* return error */
779 }
780 else
781 {
782 return a_apm2000_iic_write(handle, reg, buf, len); /* write the data */
783 }
784}
785
799uint8_t apm2000_get_reg_iic(apm2000_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
800{
801 if (handle == NULL) /* check handle */
802 {
803 return 2; /* return error */
804 }
805 if (handle->inited != 1) /* check handle initialization */
806 {
807 return 3; /* return error */
808 }
809
810 if (handle->iic_uart != 0)
811 {
812 handle->debug_print("apm2000: uart interface is invalid.\n"); /* uart interface is invalid */
813
814 return 1;
815 }
816 else
817 {
818 return a_apm2000_iic_read(handle, reg, buf, len); /* read the data */
819 }
820}
821
831{
832 if (info == NULL) /* check handle */
833 {
834 return 2; /* return error */
835 }
836
837 memset(info, 0, sizeof(apm2000_info_t)); /* initialize apm2000 info structure */
838 strncpy(info->chip_name, CHIP_NAME, 32); /* copy chip name */
839 strncpy(info->manufacturer_name, MANUFACTURER_NAME, 32); /* copy manufacturer name */
840 strncpy(info->interface, "UART IIC", 16); /* copy interface name */
841 info->supply_voltage_min_v = SUPPLY_VOLTAGE_MIN; /* set minimal supply voltage */
842 info->supply_voltage_max_v = SUPPLY_VOLTAGE_MAX; /* set maximum supply voltage */
843 info->max_current_ma = MAX_CURRENT; /* set maximum current */
844 info->temperature_max = TEMPERATURE_MAX; /* set minimal temperature */
845 info->temperature_min = TEMPERATURE_MIN; /* set maximum temperature */
846 info->driver_version = DRIVER_VERSION; /* set driver version */
847
848 return 0; /* success return 0 */
849}
#define APM2000_REG_START
chip reg definition
#define APM2000_ADDRESS
chip address definition
#define MAX_CURRENT
#define APM2000_REG_STOP
#define SUPPLY_VOLTAGE_MAX
#define TEMPERATURE_MAX
#define APM2000_REG_READ
#define MANUFACTURER_NAME
#define TEMPERATURE_MIN
#define SUPPLY_VOLTAGE_MIN
#define CHIP_NAME
chip information definition
#define DRIVER_VERSION
driver apm2000 header file
uint8_t apm2000_deinit(apm2000_handle_t *handle)
close the chip
struct apm2000_pm_s apm2000_pm_t
apm2000 pm structure definition
uint8_t apm2000_read_pm2p5(apm2000_handle_t *handle, uint16_t *pm2p5_ug_m3)
read pm2.5
uint8_t apm2000_get_interface(apm2000_handle_t *handle, apm2000_interface_t *interface)
get the chip interface
struct apm2000_info_s apm2000_info_t
apm2000 information structure definition
uint8_t apm2000_set_interface(apm2000_handle_t *handle, apm2000_interface_t interface)
set the chip interface
uint8_t apm2000_stop_measurement(apm2000_handle_t *handle)
stop the measurement
struct apm2000_handle_s apm2000_handle_t
apm2000 handle structure definition
uint8_t apm2000_init(apm2000_handle_t *handle)
initialize the chip
apm2000_interface_t
apm2000 interface enumeration definition
uint8_t apm2000_start_measurement(apm2000_handle_t *handle)
start the measurement
uint8_t apm2000_read(apm2000_handle_t *handle, apm2000_pm_t *pm)
read the result
uint8_t apm2000_info(apm2000_info_t *info)
get chip information
@ APM2000_INTERFACE_IIC
uint8_t apm2000_set_get_reg_uart(apm2000_handle_t *handle, uint8_t *input, uint16_t in_len, uint8_t *output, uint16_t out_len)
set and get the chip register with uart interface
uint8_t apm2000_get_reg_iic(apm2000_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
get the chip register with iic interface
uint8_t apm2000_set_reg_iic(apm2000_handle_t *handle, uint16_t reg, uint8_t *buf, uint16_t len)
set the chip register with iic interface
uint8_t(* uart_flush)(void)
uint8_t(* uart_write)(uint8_t *buf, uint16_t len)
void(* delay_ms)(uint32_t ms)
uint8_t(* uart_deinit)(void)
uint8_t buf[255+5]
uint8_t(* iic_read_address16)(uint8_t addr, uint16_t reg, uint8_t *buf, uint16_t len)
void(* debug_print)(const char *const fmt,...)
uint8_t(* iic_init)(void)
uint16_t(* uart_read)(uint8_t *buf, uint16_t len)
uint8_t(* iic_write_address16)(uint8_t addr, uint16_t reg, uint8_t *buf, uint16_t len)
uint8_t(* uart_init)(void)
uint8_t(* iic_deinit)(void)
uint32_t driver_version
char manufacturer_name[32]
uint16_t pm10_ug_m3
uint16_t pm2p5_ug_m3
uint16_t pm1p0_ug_m3