nodemcu-firmware/app/modules/am2320.c

155 lines
3.9 KiB
C
Raw Normal View History

/*
* app/modules/am2320.c
*
* Copyright (c) 2016 Henk Vergonet <Henk.Vergonet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "lwip/udp.h"
Initial pass at switching to RTOS SDK. This compiles, links, and starts the RTOS without crashing and burning. Lua environment does not yet start due to the different task architecture. Known pain points: - task implementation needs to be rewritten for RTOS (next up on my TODO) - secure espconn does not exist, all secure espconn stuff has been #if 0'd - lwip now built from within the RTOS SDK, but does not appear to include MDNS support. Investigation needed. - there is no access to FRC1 NMI, not sure if we ever actually used that however. Also #if 0'd out for now. - new timing constraints introduced by the RTOS, all use of ets_delay_us() and os_delay_us() needs to be reviewed (the tsl2561 driver in particular). - even more confusion with ets_ vs os_ vs c_ vs non-prefixed versions. In the long run everything should be switched to non-prefixed versions. - system_set_os_print() not available, needs to be reimplemented - all the RTOS rodata is loaded into RAM, as it apparently uses some constants while the flash isn't mapped, so our exception handler can't work its magic. This should be narrowed down to the minimum possible at some point. - with each task having its own stack in RTOS, we probably need change flash-page buffers from the stack to the heap in a bunch of places. A single, shared, page buffer *might* be possible if we limit ourselves to running NodeMCU in a single task. - there's a ton of junk in the sdk-overrides now; over time the core code should be updated to not need those shims
2016-05-24 07:05:01 +02:00
#include "esp_misc.h"
#include <errno.h>
static const uint32_t am2320_i2c_id = 0;
static const uint8_t am2320_i2c_addr = 0xb8 >> 1;
static uint16_t crc16(uint8_t *ptr, unsigned int len)
{
uint16_t crc =0xFFFF;
uint8_t i;
while(len--) {
crc ^= *ptr++;
for(i=0;i<8;i++) {
if(crc & 0x01) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
/* make sure buf has lenght len+2 in order to accommodate for extra bytes */
static int _read(uint32_t id, void *buf, uint8_t len, uint8_t off)
{
int i;
uint8_t *b = (uint8_t *)buf;
uint16_t crc;
// step 1: Wake sensor
platform_i2c_send_start(id);
platform_i2c_send_address(id, am2320_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
os_delay_us(800);
platform_i2c_send_stop(id);
// step 2: Send read command
platform_i2c_send_start(id);
platform_i2c_send_address(id, am2320_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER);
platform_i2c_send_byte(id, 0x03);
platform_i2c_send_byte(id, off);
platform_i2c_send_byte(id, len);
platform_i2c_send_stop(id);
// step 3: Read the data
os_delay_us(1500);
platform_i2c_send_start(id);
platform_i2c_send_address(id, am2320_i2c_addr, PLATFORM_I2C_DIRECTION_RECEIVER);
os_delay_us(30);
for(i=0; i<len+2; i++)
b[i] = platform_i2c_recv_byte(id,1);
crc = platform_i2c_recv_byte(id,1);
crc |= platform_i2c_recv_byte(id,0) << 8;
platform_i2c_send_stop(id);
if(b[0] != 0x3 || b[1] != len)
return -EIO;
if(crc != crc16(b,len+2))
return -EIO;
return 0;
}
static int am2320_init(lua_State* L)
{
uint32_t sda;
uint32_t scl;
int ret;
struct {
uint8_t cmd;
uint8_t len;
uint16_t model;
uint8_t version;
uint32_t id;
} nfo;
if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
return luaL_error(L, "wrong arg range");
}
sda = luaL_checkinteger(L, 1);
scl = luaL_checkinteger(L, 2);
if (scl == 0 || sda == 0) {
return luaL_error(L, "no i2c for D0");
}
platform_i2c_setup(am2320_i2c_id, sda, scl, PLATFORM_I2C_SPEED_SLOW);
os_delay_us(1500); // give some time to settle things down
ret = _read(am2320_i2c_id, &nfo, sizeof(nfo)-2, 0x08);
if(ret)
return luaL_error(L, "transmission error");
lua_pushinteger(L, ntohs(nfo.model));
lua_pushinteger(L, nfo.version);
lua_pushinteger(L, ntohl(nfo.id));
return 3;
}
static int am2320_read(lua_State* L)
{
int ret;
struct {
uint8_t cmd;
uint8_t len;
uint16_t rh;
uint16_t temp;
} nfo;
ret = _read(am2320_i2c_id, &nfo, sizeof(nfo)-2, 0x00);
if(ret)
return luaL_error(L, "transmission error");
ret = ntohs(nfo.temp);
if(ret & 0x8000)
ret = -(ret & 0x7fff);
lua_pushinteger(L, ntohs(nfo.rh));
lua_pushinteger(L, ret);
return 2;
}
static const LUA_REG_TYPE am2320_map[] = {
{ LSTRKEY( "read" ), LFUNCVAL( am2320_read )},
{ LSTRKEY( "init" ), LFUNCVAL( am2320_init )},
{ LNILKEY, LNILVAL}
};
NODEMCU_MODULE(AM2320, "am2320", am2320_map, NULL);