am2320.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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_init(lua_State* L)
  79. {
  80. uint32_t sda;
  81. uint32_t scl;
  82. int ret;
  83. struct {
  84. uint8_t cmd;
  85. uint8_t len;
  86. uint16_t model;
  87. uint8_t version;
  88. uint32_t id;
  89. } nfo;
  90. if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
  91. return luaL_error(L, "wrong arg range");
  92. }
  93. sda = luaL_checkinteger(L, 1);
  94. scl = luaL_checkinteger(L, 2);
  95. if (scl == 0 || sda == 0) {
  96. return luaL_error(L, "no i2c for D0");
  97. }
  98. platform_i2c_setup(am2320_i2c_id, sda, scl, PLATFORM_I2C_SPEED_SLOW);
  99. os_delay_us(1500); // give some time to settle things down
  100. ret = _read(am2320_i2c_id, &nfo, sizeof(nfo)-2, 0x08);
  101. if(ret)
  102. return luaL_error(L, "transmission error");
  103. lua_pushinteger(L, ntohs(nfo.model));
  104. lua_pushinteger(L, nfo.version);
  105. lua_pushinteger(L, ntohl(nfo.id));
  106. return 3;
  107. }
  108. static int am2320_read(lua_State* L)
  109. {
  110. int ret;
  111. struct {
  112. uint8_t cmd;
  113. uint8_t len;
  114. uint16_t rh;
  115. uint16_t temp;
  116. } nfo;
  117. ret = _read(am2320_i2c_id, &nfo, sizeof(nfo)-2, 0x00);
  118. if(ret)
  119. return luaL_error(L, "transmission error");
  120. ret = ntohs(nfo.temp);
  121. if(ret & 0x8000)
  122. ret = -(ret & 0x7fff);
  123. lua_pushinteger(L, ntohs(nfo.rh));
  124. lua_pushinteger(L, ret);
  125. return 2;
  126. }
  127. static const LUA_REG_TYPE am2320_map[] = {
  128. { LSTRKEY( "read" ), LFUNCVAL( am2320_read )},
  129. { LSTRKEY( "init" ), LFUNCVAL( am2320_init )},
  130. { LNILKEY, LNILVAL}
  131. };
  132. NODEMCU_MODULE(AM2320, "am2320", am2320_map, NULL);