357 lines
9.5 KiB
C
357 lines
9.5 KiB
C
// Module for interfacing with the OneWire interface
|
|
|
|
#include "module.h"
|
|
#include "lauxlib.h"
|
|
#include <stdint.h>
|
|
#include "platform.h"
|
|
|
|
|
|
static int ow_bus_table_ref;
|
|
|
|
// Lua: ow.setup( pin )
|
|
static int ow_setup( lua_State *L )
|
|
{
|
|
int pin = luaL_checkint( L, 1 );
|
|
luaL_argcheck( L, pin >= 0, 1, "invalid pin" );
|
|
|
|
if (platform_onewire_init( pin ) != PLATFORM_OK)
|
|
luaL_error( L, "failed" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Lua: r = ow.reset( pin )
|
|
static int ow_reset( lua_State *L )
|
|
{
|
|
int pin = luaL_checkint( L, 1 );
|
|
luaL_argcheck( L, pin >= 0, 1, "invalid pin" );
|
|
|
|
uint8_t presence;
|
|
if (platform_onewire_reset( pin, &presence ) != PLATFORM_OK)
|
|
luaL_error( L, "failed" );
|
|
|
|
lua_pushinteger( L, presence );
|
|
return 1;
|
|
}
|
|
|
|
// Lua: ow.write( pin, v, power)
|
|
static int ow_write( lua_State *L )
|
|
{
|
|
int stack = 0;
|
|
|
|
int pin = luaL_checkint( L, ++stack );
|
|
luaL_argcheck( L, pin >= 0, stack, "invalid pin" );
|
|
|
|
int data = luaL_checkint( L, ++stack );
|
|
luaL_argcheck( L, data >= 0 && data < 256, stack, "invalid data" );
|
|
|
|
int power = luaL_optint( L, ++stack, 0 ) != 0 ? 1 : 0;
|
|
|
|
uint8_t d = data;
|
|
if (platform_onewire_write_bytes( pin, &d, 1, power ) != PLATFORM_OK)
|
|
luaL_error( L, "failed" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Lua: ow.write_bytes( pin, buf, power)
|
|
static int ow_write_bytes( lua_State *L )
|
|
{
|
|
int stack = 0;
|
|
size_t datalen;
|
|
|
|
int pin = luaL_checkint( L, ++stack );
|
|
luaL_argcheck( L, pin >= 0, stack, "invalid pin" );
|
|
|
|
const char *pdata = luaL_checklstring( L, ++stack, &datalen );
|
|
|
|
int power = luaL_optint( L, ++stack, 0 ) != 0 ? 1 : 0;
|
|
|
|
platform_onewire_write_bytes( pin, (uint8_t *)pdata, datalen, power);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Lua: r = ow.read( pin )
|
|
static int ow_read( lua_State *L )
|
|
{
|
|
int pin = luaL_checkint( L, 1 );
|
|
luaL_argcheck( L, pin >= 0, 1, "invalid pin" );
|
|
|
|
uint8_t data;
|
|
if (platform_onewire_read_bytes( pin, &data, 1 ) != PLATFORM_OK)
|
|
luaL_error( L, "failed" );
|
|
|
|
lua_pushinteger( L, data );
|
|
return 1;
|
|
}
|
|
|
|
// Lua: r = ow.read_bytes( pin, size )
|
|
static int ow_read_bytes( lua_State *L )
|
|
{
|
|
int stack = 0;
|
|
|
|
int pin = luaL_checkint( L, ++stack );
|
|
luaL_argcheck( L, pin >= 0, stack, "invalid pin" );
|
|
|
|
int size = luaL_checkint( L, ++stack );
|
|
if (size == 0)
|
|
return 0;
|
|
luaL_argcheck( L, size <= LUAL_BUFFERSIZE, stack, "Attempt to read too many characters" );
|
|
|
|
luaL_Buffer b;
|
|
luaL_buffinit( L, &b );
|
|
char *p = luaL_prepbuffer( &b );
|
|
|
|
if (platform_onewire_read_bytes( pin, (uint8_t *)p, size ) != PLATFORM_OK)
|
|
luaL_error( L, "failed" );
|
|
|
|
luaL_addsize( &b, size );
|
|
luaL_pushresult( &b );
|
|
return 1;
|
|
}
|
|
|
|
// Lua: ow.select( pin, buf[8] )
|
|
static int ow_select( lua_State *L )
|
|
{
|
|
int stack = 0;
|
|
uint8_t rom[1+8];
|
|
size_t datalen;
|
|
int numdata, i;
|
|
const char *pdata;
|
|
|
|
int pin = luaL_checkint( L, ++stack );
|
|
luaL_argcheck( L, pin >= 0, stack, "invalid pin" );
|
|
|
|
if( lua_istable( L, ++stack ) )
|
|
{
|
|
datalen = lua_objlen( L, stack );
|
|
luaL_argcheck( L, datalen == 8, stack, "wrong arg range" );
|
|
for (i = 0; i < datalen; i ++) {
|
|
lua_rawgeti( L, stack, i + 1 );
|
|
numdata = ( int )luaL_checkinteger( L, -1 );
|
|
lua_pop( L, 1 );
|
|
if (numdata > 255)
|
|
return luaL_error( L, "wrong arg range" );
|
|
rom[1+i] = (uint8_t)numdata;
|
|
}
|
|
} else {
|
|
pdata = luaL_checklstring( L, stack, &datalen );
|
|
luaL_argcheck( L, datalen == 8, stack, "wrong arg range" );
|
|
for (i = 0; i < datalen; i++) {
|
|
rom[1+i] = pdata[i];
|
|
}
|
|
}
|
|
|
|
rom[0] = 0x55; // select command
|
|
if (platform_onewire_write_bytes( pin, rom, 1+8, 0 ) != PLATFORM_OK)
|
|
luaL_error( L, "write failed" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Lua: ow.skip( pin )
|
|
static int ow_skip( lua_State *L )
|
|
{
|
|
int pin = luaL_checkint( L, 1 );
|
|
luaL_argcheck( L, pin >= 0, 1, "invalid pin" );
|
|
|
|
const uint8_t cmd = 0xCC; // skip command
|
|
if (platform_onewire_write_bytes( pin, &cmd, 1, 0 ) != PLATFORM_OK)
|
|
luaL_error( L, "write failed" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Lua: ow.depower( pin )
|
|
static int ow_depower( lua_State *L )
|
|
{
|
|
int pin = luaL_checkint( L, 1 );
|
|
luaL_argcheck( L, pin >= 0, 1, "invalid pin" );
|
|
|
|
platform_onewire_depower( pin );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Clear the search state so that if will start from the beginning again.
|
|
// Lua: ow.reset_search( pin )
|
|
static int ow_reset_search( lua_State *L )
|
|
{
|
|
int pin = luaL_checkint( L, 1 );
|
|
luaL_argcheck( L, pin >= 0, 1, "invalid pin" );
|
|
|
|
// set up new userdata for this pin
|
|
lua_rawgeti( L, LUA_REGISTRYINDEX, ow_bus_table_ref );
|
|
platform_onewire_bus_t *bus = (platform_onewire_bus_t *)lua_newuserdata( L, sizeof( platform_onewire_bus_t ));
|
|
lua_rawseti( L, -2, pin );
|
|
// remove table from stack
|
|
lua_pop( L, 1 );
|
|
|
|
platform_onewire_reset_search( bus );
|
|
return 0;
|
|
}
|
|
|
|
// Setup the search to find the device type 'family_code' on the next call
|
|
// to search(*newAddr) if it is present.
|
|
// Lua: ow.target_search( pin, family_code )
|
|
static int ow_target_search( lua_State *L )
|
|
{
|
|
int stack = 0;
|
|
|
|
int pin = luaL_checkint( L, ++stack );
|
|
luaL_argcheck( L, pin >= 0, stack, "invalid pin" );
|
|
|
|
int code = (int)luaL_checkinteger( L, ++stack );
|
|
luaL_argcheck( L, code >= 0 && code < 256, stack, "wrong arg range" );
|
|
|
|
// set up new userdata for this pin
|
|
lua_rawgeti( L, LUA_REGISTRYINDEX, ow_bus_table_ref );
|
|
platform_onewire_bus_t *bus = (platform_onewire_bus_t *)lua_newuserdata( L, sizeof( platform_onewire_bus_t ));
|
|
lua_rawseti( L, -2, pin );
|
|
// remove table from stack
|
|
lua_pop( L, 1 );
|
|
|
|
platform_onewire_target_search( (uint8_t)code, bus );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Look for the next device. Returns 1 if a new address has been
|
|
// returned. A zero might mean that the bus is shorted, there are
|
|
// no devices, or you have already retrieved all of them. It
|
|
// might be a good idea to check the CRC to make sure you didn't
|
|
// get garbage. The order is deterministic. You will always get
|
|
// the same devices in the same order.
|
|
|
|
// Lua: r = ow.search( pin )
|
|
static int ow_search( lua_State *L )
|
|
{
|
|
int pin = luaL_checkint( L, 1 );
|
|
luaL_argcheck( L, pin >= 0, 1, "invalid pin" );
|
|
|
|
// look-up bus userdata for this pin
|
|
lua_rawgeti( L, LUA_REGISTRYINDEX, ow_bus_table_ref );
|
|
lua_rawgeti( L, -1, pin );
|
|
platform_onewire_bus_t *bus = (platform_onewire_bus_t *)lua_touserdata( L, -1 );
|
|
if (!bus)
|
|
return luaL_error( L, "search not initialized" );
|
|
// removed temps from stack
|
|
lua_pop( L, 2 );
|
|
|
|
luaL_Buffer b;
|
|
luaL_buffinit( L, &b );
|
|
char *p = luaL_prepbuffer( &b );
|
|
|
|
if (platform_onewire_search( pin, (uint8_t *)p, bus )){
|
|
luaL_addsize( &b, 8 );
|
|
luaL_pushresult( &b );
|
|
} else {
|
|
luaL_pushresult( &b ); /* close buffer */
|
|
lua_pop( L, 1 );
|
|
|
|
// remove bus userdata from table
|
|
lua_rawgeti( L, LUA_REGISTRYINDEX, ow_bus_table_ref );
|
|
lua_pushnil( L );
|
|
lua_rawseti( L, -2, pin );
|
|
// remove table from stack
|
|
lua_pop( L, 1 );
|
|
|
|
lua_pushnil( L );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// uint8_t onewire_crc8(const uint8_t *addr, uint8_t len);
|
|
// Lua: r = ow.crc8( buf )
|
|
static int ow_crc8( lua_State *L )
|
|
{
|
|
size_t datalen;
|
|
const char *pdata = luaL_checklstring( L, 1, &datalen );
|
|
if(datalen > 255)
|
|
return luaL_error( L, "wrong arg range" );
|
|
lua_pushinteger( L, platform_onewire_crc8((uint8_t *)pdata, datalen) );
|
|
return 1;
|
|
}
|
|
|
|
// bool onewire_check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc);
|
|
// Lua: b = ow.check_crc16( buf, inverted_crc0, inverted_crc1, crc )
|
|
static int ow_check_crc16( lua_State *L )
|
|
{
|
|
size_t datalen;
|
|
uint8_t inverted_crc[2];
|
|
const char *pdata = luaL_checklstring( L, 1, &datalen );
|
|
if(datalen > 65535)
|
|
return luaL_error( L, "wrong arg range" );
|
|
|
|
int crc = 0;
|
|
crc = luaL_checkinteger( L, 2 );
|
|
if(datalen > 255)
|
|
return luaL_error( L, "wrong arg range" );
|
|
inverted_crc[0] = (uint8_t)crc;
|
|
|
|
crc = luaL_checkinteger( L, 3 );
|
|
if(datalen > 255)
|
|
return luaL_error( L, "wrong arg range" );
|
|
inverted_crc[1] = (uint8_t)crc;
|
|
|
|
crc = 0;
|
|
if(lua_isnumber(L, 4))
|
|
crc = lua_tointeger(L, 4);
|
|
if(crc > 65535)
|
|
return luaL_error( L, "wrong arg range" );
|
|
|
|
lua_pushboolean( L, platform_onewire_check_crc16((uint8_t *)pdata, datalen, inverted_crc, crc) );
|
|
|
|
return 1;
|
|
}
|
|
|
|
// uint16_t onewire_crc16(const uint8_t* input, uint16_t len, uint16_t crc);
|
|
// Lua: r = ow.crc16( buf, crc )
|
|
static int ow_crc16( lua_State *L )
|
|
{
|
|
int stack = 0;
|
|
size_t datalen;
|
|
|
|
const char *pdata = luaL_checklstring( L, ++stack, &datalen );
|
|
luaL_argcheck( L, datalen <= 65535, stack, "wrong arg range" );
|
|
|
|
int crc = 0;
|
|
if(lua_isnumber(L, ++stack))
|
|
crc = lua_tointeger(L, stack);
|
|
luaL_argcheck( L, crc >= 0 && crc <= 65535, stack, "wrong arg range" );
|
|
|
|
lua_pushinteger( L, platform_onewire_crc16((uint8_t *)pdata, datalen, crc) );
|
|
|
|
return 1;
|
|
}
|
|
|
|
LROT_BEGIN(ow, NULL, 0)
|
|
LROT_FUNCENTRY( setup, ow_setup )
|
|
LROT_FUNCENTRY( reset, ow_reset )
|
|
LROT_FUNCENTRY( skip, ow_skip )
|
|
LROT_FUNCENTRY( select, ow_select )
|
|
LROT_FUNCENTRY( write, ow_write )
|
|
LROT_FUNCENTRY( write_bytes, ow_write_bytes )
|
|
LROT_FUNCENTRY( read, ow_read )
|
|
LROT_FUNCENTRY( read_bytes, ow_read_bytes )
|
|
LROT_FUNCENTRY( depower, ow_depower )
|
|
LROT_FUNCENTRY( reset_search, ow_reset_search )
|
|
LROT_FUNCENTRY( target_search, ow_target_search )
|
|
LROT_FUNCENTRY( search, ow_search )
|
|
LROT_FUNCENTRY( crc8, ow_crc8 )
|
|
LROT_FUNCENTRY( check_crc16, ow_check_crc16 )
|
|
LROT_FUNCENTRY( crc16, ow_crc16 )
|
|
LROT_END(ow, NULL, 0)
|
|
|
|
int luaopen_ow( lua_State *L )
|
|
{
|
|
// create the table to store bus userdata for search operations
|
|
lua_newtable( L );
|
|
ow_bus_table_ref = luaL_ref( L, LUA_REGISTRYINDEX );
|
|
|
|
return 0;
|
|
}
|
|
|
|
NODEMCU_MODULE(OW, "ow", ow, luaopen_ow);
|