am2320.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /*
  2. * app/modules/am2320.c
  3. *
  4. * Copyright (c) 2016 Henk Vergonet <Henk.Vergonet@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "module.h"
  21. #include "lauxlib.h"
  22. #include "platform.h"
  23. #include "lwip/udp.h"
  24. #include <errno.h>
  25. static const uint32_t am2320_i2c_id = 0;
  26. static const uint8_t am2320_i2c_addr = 0xb8 >> 1;
  27. static uint16_t crc16(uint8_t *ptr, unsigned int len)
  28. {
  29. uint16_t crc =0xFFFF;
  30. uint8_t i;
  31. while(len--) {
  32. crc ^= *ptr++;
  33. for(i=0;i<8;i++) {
  34. if(crc & 0x01) {
  35. crc >>= 1;
  36. crc ^= 0xA001;
  37. } else {
  38. crc >>= 1;
  39. }
  40. }
  41. }
  42. return crc;
  43. }
  44. /* make sure buf has lenght len+2 in order to accommodate for extra bytes */
  45. static int _read(uint32_t id, void *buf, uint8_t len, uint8_t off)
  46. {
  47. int i;
  48. uint8_t *b = (uint8_t *)buf;
  49. uint16_t crc;
  50. // step 1: Wake sensor
  51. platform_i2c_send_start(id);
  52. platform_i2c_send_address(id, am2320_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
  53. os_delay_us(800);
  54. platform_i2c_send_stop(id);
  55. // step 2: Send read command
  56. platform_i2c_send_start(id);
  57. platform_i2c_send_address(id, am2320_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
  58. platform_i2c_send_byte(id, 0x03);
  59. platform_i2c_send_byte(id, off);
  60. platform_i2c_send_byte(id, len);
  61. platform_i2c_send_stop(id);
  62. // step 3: Read the data
  63. os_delay_us(1500);
  64. platform_i2c_send_start(id);
  65. platform_i2c_send_address(id, am2320_i2c_addr, PLATFORM_I2C_DIRECTION_RECEIVER);
  66. os_delay_us(30);
  67. for(i=0; i<len+2; i++)
  68. b[i] = platform_i2c_recv_byte(id,1);
  69. crc = platform_i2c_recv_byte(id,1);
  70. crc |= platform_i2c_recv_byte(id,0) << 8;
  71. platform_i2c_send_stop(id);
  72. if(b[0] != 0x3 || b[1] != len)
  73. return -EIO;
  74. if(crc != crc16(b,len+2))
  75. return -EIO;
  76. return 0;
  77. }
  78. static int am2320_setup(lua_State* L)
  79. {
  80. int ret;
  81. struct {
  82. uint8_t cmd;
  83. uint8_t len;
  84. uint16_t model;
  85. uint8_t version;
  86. uint32_t id;
  87. } nfo;
  88. os_delay_us(1500); // give some time to settle things down
  89. ret = _read(am2320_i2c_id, &nfo, sizeof(nfo)-2, 0x08);
  90. if(ret)
  91. return luaL_error(L, "transmission error");
  92. lua_pushinteger(L, ntohs(nfo.model));
  93. lua_pushinteger(L, nfo.version);
  94. lua_pushinteger(L, ntohl(nfo.id));
  95. return 3;
  96. }
  97. static int am2320_read(lua_State* L)
  98. {
  99. int ret;
  100. struct {
  101. uint8_t cmd;
  102. uint8_t len;
  103. uint16_t rh;
  104. uint16_t temp;
  105. } nfo;
  106. ret = _read(am2320_i2c_id, &nfo, sizeof(nfo)-2, 0x00);
  107. if(ret)
  108. return luaL_error(L, "transmission error");
  109. ret = ntohs(nfo.temp);
  110. if(ret & 0x8000)
  111. ret = -(ret & 0x7fff);
  112. lua_pushinteger(L, ntohs(nfo.rh));
  113. lua_pushinteger(L, ret);
  114. return 2;
  115. }
  116. LROT_BEGIN(am2320, NULL, 0)
  117. LROT_FUNCENTRY( read, am2320_read )
  118. LROT_FUNCENTRY( setup, am2320_setup )
  119. LROT_END(am2320, NULL, 0)
  120. NODEMCU_MODULE(AM2320, "am2320", am2320, NULL);