SoftUART module fixes and code simplification (#3104)
* SoftUART fixes: - Simplify code by using lua_L* functions and using userdata properly - Fix some edge-cases - Add more examples to documentation * Don't de-register interrupt hook if there is more RX instances * More bug fixes and registering simplification with luaL_reref and unref2 * Correct documentation of SoftUART module
This commit is contained in:
parent
a0d27059bc
commit
e7620b0647
|
@ -14,6 +14,7 @@
|
||||||
#define SOFTUART_GPIO_COUNT 13
|
#define SOFTUART_GPIO_COUNT 13
|
||||||
|
|
||||||
//TODO: Overflow flag as callback function + docs
|
//TODO: Overflow flag as callback function + docs
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char receive_buffer[SOFTUART_MAX_RX_BUFF];
|
char receive_buffer[SOFTUART_MAX_RX_BUFF];
|
||||||
uint8_t buffer_first;
|
uint8_t buffer_first;
|
||||||
|
@ -23,19 +24,15 @@ typedef struct {
|
||||||
} softuart_buffer_t;
|
} softuart_buffer_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t pin_rx;
|
|
||||||
uint8_t pin_tx;
|
|
||||||
volatile softuart_buffer_t buffer;
|
volatile softuart_buffer_t buffer;
|
||||||
uint16_t bit_time;
|
uint16_t bit_time;
|
||||||
uint16_t need_len; // Buffer length needed to run callback function
|
uint16_t need_len; // Buffer length needed to run callback function
|
||||||
char end_char; // Used to run callback if last char in buffer will be the same
|
char end_char; // Used to run callback if last char in buffer will be the same
|
||||||
uint8_t armed;
|
uint8_t armed;
|
||||||
|
uint8_t pin_rx;
|
||||||
|
uint8_t pin_tx;
|
||||||
} softuart_t;
|
} softuart_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
softuart_t *softuart;
|
|
||||||
} softuart_userdata;
|
|
||||||
|
|
||||||
// Array of pointers to SoftUART instances
|
// Array of pointers to SoftUART instances
|
||||||
softuart_t * softuart_gpio_instances[SOFTUART_GPIO_COUNT] = {NULL};
|
softuart_t * softuart_gpio_instances[SOFTUART_GPIO_COUNT] = {NULL};
|
||||||
// Array of callback reference to be able to find which callback is used to which rx pin
|
// Array of callback reference to be able to find which callback is used to which rx pin
|
||||||
|
@ -60,7 +57,7 @@ static inline uint8_t checkbit(uint8_t data, uint8_t bit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status)
|
static uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status)
|
||||||
{
|
{
|
||||||
// Disable all interrupts
|
// Disable all interrupts
|
||||||
ets_intr_lock();
|
ets_intr_lock();
|
||||||
|
@ -74,12 +71,12 @@ uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status)
|
||||||
// Load instance which has rx pin on interrupt pin attached
|
// Load instance which has rx pin on interrupt pin attached
|
||||||
softuart_t *s = softuart_gpio_instances[pin_num_inv[gpio_bit]];
|
softuart_t *s = softuart_gpio_instances[pin_num_inv[gpio_bit]];
|
||||||
if (s == NULL) continue;
|
if (s == NULL) continue;
|
||||||
if (softuart_rx_cb_ref[pin_num_inv[gpio_bit]] == LUA_NOREF) continue;
|
|
||||||
if (!s->armed) continue;
|
|
||||||
// There is SoftUART rx instance on that pin
|
|
||||||
// Clear interrupt status on that pin
|
// Clear interrupt status on that pin
|
||||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & (1 << pin_num[s->pin_rx]));
|
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & (1 << pin_num[s->pin_rx]));
|
||||||
ret_gpio_status &= ~(1 << pin_num[s->pin_rx]);
|
ret_gpio_status &= ~(1 << pin_num[s->pin_rx]);
|
||||||
|
if (softuart_rx_cb_ref[pin_num_inv[gpio_bit]] == LUA_NOREF) continue;
|
||||||
|
if (!s->armed) continue;
|
||||||
|
// There is an armed SoftUART rx instance on that pin
|
||||||
// Start listening to transmission
|
// Start listening to transmission
|
||||||
// TODO: inverted
|
// TODO: inverted
|
||||||
if (! (GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[s->pin_rx])))) {
|
if (! (GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[s->pin_rx])))) {
|
||||||
|
@ -104,7 +101,7 @@ uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status)
|
||||||
|
|
||||||
// Read bit
|
// Read bit
|
||||||
if(GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[s->pin_rx]))) {
|
if(GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[s->pin_rx]))) {
|
||||||
// If high, set msb of 8bit to 1
|
// If high, set MSB of byte to 1
|
||||||
byte |= 0x80;
|
byte |= 0x80;
|
||||||
}
|
}
|
||||||
// Recalculate start time for next bit
|
// Recalculate start time for next bit
|
||||||
|
@ -125,7 +122,7 @@ uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status)
|
||||||
((s->need_len == 0) && ((char)byte == s->end_char))) {
|
((s->need_len == 0) && ((char)byte == s->end_char))) {
|
||||||
// Send the pointer to task handler
|
// Send the pointer to task handler
|
||||||
s->armed = 0;
|
s->armed = 0;
|
||||||
task_post_low(uart_recieve_task, (task_param_t)s);
|
task_post_medium(uart_recieve_task, (task_param_t)s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check for overflow after appending new byte
|
// Check for overflow after appending new byte
|
||||||
|
@ -136,11 +133,11 @@ uint32_t ICACHE_RAM_ATTR softuart_intr_handler(uint32_t ret_gpio_status)
|
||||||
if (s->buffer.buffer_last == SOFTUART_MAX_RX_BUFF) {
|
if (s->buffer.buffer_last == SOFTUART_MAX_RX_BUFF) {
|
||||||
s->buffer.buffer_last = 0;
|
s->buffer.buffer_last = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for stop bit
|
// Wait for stop bit
|
||||||
// TODO: Add config for stop bits and parity bits
|
// TODO: Add config for stop bits and parity bits
|
||||||
while ((uint32_t)(asm_ccount() - start_time) < s->bit_time);
|
while ((uint32_t)(asm_ccount() - start_time) < s->bit_time);
|
||||||
|
// Break the loop after reading of the frame
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// re-enable all interrupts
|
// re-enable all interrupts
|
||||||
|
@ -156,6 +153,7 @@ static void softuart_putchar(softuart_t *s, char data)
|
||||||
// Set start bit
|
// Set start bit
|
||||||
GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), 0);
|
GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), 0);
|
||||||
for (uint32_t i = 0; i < 8; i++) {
|
for (uint32_t i = 0; i < 8; i++) {
|
||||||
|
// Wait to transmit another bit
|
||||||
while ((uint32_t)(asm_ccount() - start_time) < s->bit_time);
|
while ((uint32_t)(asm_ccount() - start_time) < s->bit_time);
|
||||||
|
|
||||||
GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), checkbit(data, 1 << i));
|
GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[s->pin_tx]), checkbit(data, 1 << i));
|
||||||
|
@ -172,25 +170,29 @@ static void softuart_putchar(softuart_t *s, char data)
|
||||||
ets_intr_unlock();
|
ets_intr_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void softuart_init(softuart_t *s)
|
static int softuart_init(softuart_t *s)
|
||||||
{
|
{
|
||||||
NODE_DBG("SoftUART initialize gpio\n");
|
|
||||||
|
|
||||||
// Init tx pin
|
// Init tx pin
|
||||||
if (s->pin_tx != 0xFF){
|
if (s->pin_tx != 0xFF) {
|
||||||
platform_gpio_mode(s->pin_tx, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
|
platform_gpio_mode(s->pin_tx, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
|
||||||
platform_gpio_write(s->pin_tx, PLATFORM_GPIO_HIGH);
|
platform_gpio_write(s->pin_tx, PLATFORM_GPIO_HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init rx pin
|
// Init rx pin
|
||||||
if (s->pin_rx != 0xFF){
|
if (s->pin_rx != 0xFF) {
|
||||||
platform_gpio_mode(s->pin_rx, PLATFORM_GPIO_INT, PLATFORM_GPIO_PULLUP);
|
platform_gpio_mode(s->pin_rx, PLATFORM_GPIO_INT, PLATFORM_GPIO_PULLUP);
|
||||||
uint32_t mask = 1 << pin_num[s->pin_rx];
|
|
||||||
platform_gpio_register_intr_hook(mask, softuart_intr_handler);
|
|
||||||
|
|
||||||
softuart_gpio_instances[s->pin_rx] = s;
|
|
||||||
// Enable interrupt for pin on falling edge
|
// Enable interrupt for pin on falling edge
|
||||||
platform_gpio_intr_init(s->pin_rx, GPIO_PIN_INTR_NEGEDGE);
|
platform_gpio_intr_init(s->pin_rx, GPIO_PIN_INTR_NEGEDGE);
|
||||||
|
softuart_gpio_instances[s->pin_rx] = s;
|
||||||
|
// Preserve other rx gpio pins
|
||||||
|
uint32_t mask = 0;
|
||||||
|
for (uint8_t i = 0; i < SOFTUART_GPIO_COUNT; i++) {
|
||||||
|
if (softuart_gpio_instances[i] != NULL) {
|
||||||
|
mask = mask | (1 << pin_num[softuart_gpio_instances[i]->pin_rx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return platform_gpio_register_intr_hook(mask, softuart_intr_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,70 +201,59 @@ static int softuart_setup(lua_State *L)
|
||||||
{
|
{
|
||||||
uint32_t baudrate;
|
uint32_t baudrate;
|
||||||
uint8_t tx_gpio_id, rx_gpio_id;
|
uint8_t tx_gpio_id, rx_gpio_id;
|
||||||
uint8_t stack = 1;
|
softuart_t *softuart = NULL;
|
||||||
softuart_userdata *suart = NULL;
|
|
||||||
|
|
||||||
NODE_DBG("SoftUART setup called\n");
|
NODE_DBG("[SoftUART]: setup called\n");
|
||||||
|
baudrate = (uint32_t)luaL_checkinteger(L, 1); // Get Baudrate from
|
||||||
if(lua_isnumber(L, stack)) {
|
luaL_argcheck(L, (baudrate > 0 && baudrate < 230400), 1, "Invalid baud rate");
|
||||||
baudrate = (uint32_t)luaL_checkinteger( L, stack);
|
lua_remove(L, 1); // Remove baudrate argument from stack
|
||||||
//230400 Is the max baudrate the author of Arduino-Esp8266-Software-UART tested
|
if (lua_gettop(L) == 2) { // 2 arguments: 1st can be nil
|
||||||
if (baudrate <= 0 || baudrate > 230400) {
|
if (lua_isnil(L, 1)) {
|
||||||
return luaL_error(L, "Invalid baud rate" );
|
|
||||||
}
|
|
||||||
stack++;
|
|
||||||
} else {
|
|
||||||
return luaL_error(L, "Invalid argument type");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(lua_isnumber(L, stack)) {
|
|
||||||
tx_gpio_id = (uint8_t)luaL_checkinteger( L, stack);
|
|
||||||
if (!platform_gpio_exists(tx_gpio_id) || tx_gpio_id == 0) {
|
|
||||||
return luaL_error(L, "SoftUART tx GPIO not valid");
|
|
||||||
}
|
|
||||||
stack++;
|
|
||||||
} else {
|
|
||||||
tx_gpio_id = 0xFF;
|
tx_gpio_id = 0xFF;
|
||||||
stack++;
|
|
||||||
}
|
|
||||||
if (lua_isnumber(L, stack)) {
|
|
||||||
rx_gpio_id = (uint8_t)luaL_checkinteger( L, stack);
|
|
||||||
if (!platform_gpio_exists(rx_gpio_id) || rx_gpio_id == 0) {
|
|
||||||
return luaL_error(L, "SoftUART rx GPIO not valid");
|
|
||||||
}
|
|
||||||
if (softuart_gpio_instances[rx_gpio_id] != NULL) {
|
|
||||||
return luaL_error( L, "SoftUART rx already configured on the pin.");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
tx_gpio_id = (uint8_t)luaL_checkinteger(L, 1);
|
||||||
|
luaL_argcheck(L, (platform_gpio_exists(tx_gpio_id) && tx_gpio_id != 0)
|
||||||
|
, 2, "Invalid SoftUART tx GPIO");
|
||||||
|
}
|
||||||
|
rx_gpio_id = (uint8_t)luaL_checkinteger(L, 2);
|
||||||
|
luaL_argcheck(L, (platform_gpio_exists(rx_gpio_id) && rx_gpio_id != 0)
|
||||||
|
, 3, "Invalid SoftUART rx GPIO");
|
||||||
|
luaL_argcheck(L, softuart_gpio_instances[rx_gpio_id] == NULL
|
||||||
|
, 3, "SoftUART rx already configured on the pin");
|
||||||
|
|
||||||
|
} else if (lua_gettop(L) == 1) { // 1 argument: transmit part only
|
||||||
rx_gpio_id = 0xFF;
|
rx_gpio_id = 0xFF;
|
||||||
|
tx_gpio_id = (uint8_t)luaL_checkinteger(L, 1);
|
||||||
|
luaL_argcheck(L, (platform_gpio_exists(tx_gpio_id) && tx_gpio_id != 0)
|
||||||
|
, 2, "Invalid SoftUART tx GPIO");
|
||||||
|
} else {
|
||||||
|
// SoftUART object without receive and transmit part would be useless
|
||||||
|
return luaL_error(L, "Not enough arguments");
|
||||||
}
|
}
|
||||||
|
|
||||||
suart = (softuart_userdata*)lua_newuserdata(L, sizeof(softuart_userdata));
|
softuart = (softuart_t*)lua_newuserdata(L, sizeof(softuart_t));
|
||||||
suart->softuart = malloc(sizeof(softuart_t));
|
softuart->pin_rx = rx_gpio_id;
|
||||||
if (!suart->softuart) {
|
softuart->pin_tx = tx_gpio_id;
|
||||||
free(suart->softuart);
|
softuart->need_len = SOFTUART_MAX_RX_BUFF;
|
||||||
suart->softuart = NULL;
|
softuart->armed = 0;
|
||||||
return luaL_error(L, "Not enough memory");
|
|
||||||
}
|
|
||||||
suart->softuart->pin_rx = rx_gpio_id;
|
|
||||||
suart->softuart->pin_tx = tx_gpio_id;
|
|
||||||
suart->softuart->need_len = RX_BUFF_SIZE;
|
|
||||||
suart->softuart->armed = 0;
|
|
||||||
|
|
||||||
// Set buffer
|
// Set buffer
|
||||||
suart->softuart->buffer.buffer_first = 0;
|
softuart->buffer.buffer_first = 0;
|
||||||
suart->softuart->buffer.buffer_last = 0;
|
softuart->buffer.buffer_last = 0;
|
||||||
suart->softuart->buffer.bytes_count = 0;
|
softuart->buffer.bytes_count = 0;
|
||||||
suart->softuart->buffer.buffer_overflow = 0;
|
softuart->buffer.buffer_overflow = 0;
|
||||||
|
|
||||||
// Set bit time
|
// Set bit time
|
||||||
suart->softuart->bit_time = system_get_cpu_freq() * 1000000 / baudrate;
|
softuart->bit_time = system_get_cpu_freq() * 1000000 / baudrate;
|
||||||
|
|
||||||
// Set metatable
|
// Set metatable
|
||||||
luaL_getmetatable(L, "softuart.port");
|
luaL_getmetatable(L, "softuart.port");
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
// Init SoftUART
|
// Init SoftUART
|
||||||
softuart_init(suart->softuart);
|
int result = softuart_init(softuart);
|
||||||
|
if (result == 0) {
|
||||||
|
luaL_error(L, "Couldn't register interrupt");
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,13 +262,14 @@ static void softuart_rx_callback(task_param_t arg)
|
||||||
softuart_t *softuart = (softuart_t*)arg; //Receive pointer from ISR
|
softuart_t *softuart = (softuart_t*)arg; //Receive pointer from ISR
|
||||||
lua_State *L = lua_getstate();
|
lua_State *L = lua_getstate();
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[softuart->pin_rx]);
|
lua_rawgeti(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[softuart->pin_rx]);
|
||||||
|
|
||||||
// Clear overflow flag if needed
|
// Clear overflow flag if needed
|
||||||
if(softuart->buffer.bytes_count == SOFTUART_MAX_RX_BUFF) {
|
if(softuart->buffer.bytes_count == SOFTUART_MAX_RX_BUFF) {
|
||||||
softuart->buffer.buffer_overflow = 0;
|
softuart->buffer.buffer_overflow = 0;
|
||||||
}
|
}
|
||||||
// Copy volatile data to static buffer
|
// Copy volatile data to static buffer
|
||||||
uint8_t buffer_lenght = softuart->buffer.bytes_count;
|
uint8_t buffer_length = softuart->buffer.bytes_count;
|
||||||
for (int i = 0; i < buffer_lenght; i++) {
|
for (int i = 0; i < buffer_length; i++) {
|
||||||
softuart_rx_buffer[i] = softuart->buffer.receive_buffer[softuart->buffer.buffer_first];
|
softuart_rx_buffer[i] = softuart->buffer.receive_buffer[softuart->buffer.buffer_first];
|
||||||
softuart->buffer.buffer_first++;
|
softuart->buffer.buffer_first++;
|
||||||
softuart->buffer.bytes_count--;
|
softuart->buffer.bytes_count--;
|
||||||
|
@ -285,111 +277,63 @@ static void softuart_rx_callback(task_param_t arg)
|
||||||
softuart->buffer.buffer_first = 0;
|
softuart->buffer.buffer_first = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_pushlstring(L, softuart_rx_buffer, buffer_lenght);
|
lua_pushlstring(L, softuart_rx_buffer, buffer_length);
|
||||||
softuart->armed = 1;
|
softuart->armed = 1;
|
||||||
luaL_pcallx(L, 1, 0);
|
luaL_pcallx(L, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Arguments: event name, minimum buffer filled to run callback, callback function
|
// Arguments: event name, minimum buffer filled to run callback, callback function
|
||||||
static int softuart_on(lua_State *L)
|
static int softuart_on(lua_State *L)
|
||||||
{
|
{
|
||||||
NODE_DBG("SoftUART on called\n");
|
NODE_DBG("[SoftUART] on: called\n");
|
||||||
softuart_userdata *suart = NULL;
|
|
||||||
size_t name_len, arg_len;
|
size_t name_len, arg_len;
|
||||||
uint8_t stack = 1;
|
|
||||||
|
|
||||||
suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port");
|
softuart_t *softuart = (softuart_t*)luaL_checkudata(L, 1, "softuart.port");
|
||||||
luaL_argcheck(L, suart, stack, "softuart.port expected");
|
const char *method = luaL_checklstring(L, 2, &name_len);
|
||||||
if (suart == NULL) {
|
luaL_argcheck(L, lua_isfunction(L, 4), -1, "No callback function specified");
|
||||||
NODE_DBG("Userdata is nil\n");
|
luaL_argcheck(L, (name_len == 4 && strcmp(method, "data") == 0), 2, "Method not supported");
|
||||||
return 0;
|
luaL_argcheck(L, softuart->pin_rx != 0xFF, 1, "Rx pin was not declared");
|
||||||
}
|
|
||||||
stack++;
|
|
||||||
|
|
||||||
const char *method = luaL_checklstring(L, stack, &name_len);
|
if (lua_isnumber(L, 3)) {
|
||||||
if (method == NULL)
|
luaL_argcheck(L, luaL_checkinteger(L, 3) < SOFTUART_MAX_RX_BUFF,
|
||||||
return luaL_error(L, "Wrong argument type");
|
2, "Argument bigger than SoftUART buffer");
|
||||||
stack++;
|
softuart->end_char = 0;
|
||||||
|
softuart->need_len = (uint16_t) luaL_checkinteger(L, 3);
|
||||||
if (lua_type(L, stack) == LUA_TNUMBER) {
|
} else if (lua_isstring(L, 3)) {
|
||||||
suart->softuart->need_len = (uint16_t)luaL_checkinteger( L, stack );
|
const char *end = luaL_checklstring(L , 3, &arg_len);
|
||||||
stack++;
|
luaL_argcheck(L, arg_len == 1, 3, "Wrong end char length");
|
||||||
suart->softuart->end_char = 0;
|
softuart->end_char = end[0];
|
||||||
if (suart->softuart->need_len > SOFTUART_MAX_RX_BUFF) {
|
softuart->need_len = 0;
|
||||||
suart->softuart->need_len = 0;
|
|
||||||
return luaL_error(L, "Argument bigger than SoftUART buffer");
|
|
||||||
}
|
|
||||||
suart->softuart->armed = 1;
|
|
||||||
} else if (lua_isstring(L, stack)) {
|
|
||||||
const char *end = luaL_checklstring(L , stack, &arg_len);
|
|
||||||
stack++;
|
|
||||||
if ( arg_len != 1) {
|
|
||||||
return luaL_error(L, "Wrong end char length");
|
|
||||||
}
|
|
||||||
suart->softuart->end_char = end[0];
|
|
||||||
suart->softuart->need_len = 0;
|
|
||||||
suart->softuart->armed = 1;
|
|
||||||
} else {
|
} else {
|
||||||
return luaL_error(L, "Wrong argument type");
|
return luaL_error(L, "Wrong argument type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lua_settop(L, 4); // Move to the top of the stack
|
||||||
if (lua_type(L, stack) == LUA_TFUNCTION) {
|
// Register callback or reregister new one
|
||||||
lua_pushvalue(L, stack); // Copy to top of the stack
|
luaL_reref(L, LUA_REGISTRYINDEX, &softuart_rx_cb_ref[softuart->pin_rx]);
|
||||||
} else {
|
// Arm the instance
|
||||||
lua_pushnil(L);
|
softuart->armed = 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (name_len == 4 && strcmp(method, "data") == 0) {
|
|
||||||
|
|
||||||
if(suart->softuart->pin_rx == 0xFF) {
|
|
||||||
return luaL_error(L, "Rx pin was not declared");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (softuart_rx_cb_ref[suart->softuart->pin_rx] != LUA_NOREF) {
|
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[suart->softuart->pin_rx]);
|
|
||||||
softuart_rx_cb_ref[suart->softuart->pin_rx] = LUA_NOREF;
|
|
||||||
}
|
|
||||||
if (! lua_isnil(L, -1)) {
|
|
||||||
softuart_rx_cb_ref[suart->softuart->pin_rx] = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
||||||
} else {
|
|
||||||
lua_pop(L, 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return luaL_error(L, "Method not supported");
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int softuart_write(lua_State *L)
|
static int softuart_write(lua_State *L)
|
||||||
{
|
{
|
||||||
NODE_DBG("SoftUART write called\n");
|
softuart_t *softuart = NULL;
|
||||||
softuart_userdata *suart = NULL;
|
|
||||||
uint8_t stack = 1;
|
|
||||||
size_t str_len;
|
size_t str_len;
|
||||||
suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port");
|
softuart = (softuart_t*) luaL_checkudata(L, 1, "softuart.port");
|
||||||
luaL_argcheck(L, suart, stack, "softuart.port expected");
|
luaL_argcheck(L, softuart->pin_tx != 0xFF, 1, "Tx pin was not declared");
|
||||||
if (suart == NULL) {
|
|
||||||
NODE_DBG("Userdata is nil\n");
|
if (lua_isnumber(L, 2)) {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
stack++;
|
|
||||||
if(suart->softuart->pin_tx == 0xFF) {
|
|
||||||
return luaL_error(L, "Tx pin was not declared");
|
|
||||||
}
|
|
||||||
if (lua_type(L, stack) == LUA_TNUMBER) {
|
|
||||||
// Send byte
|
// Send byte
|
||||||
uint32_t byte = (uint32_t)luaL_checkinteger( L, stack );
|
uint32_t byte = (uint32_t)luaL_checkinteger(L, 2);
|
||||||
if (byte > 255) {
|
luaL_argcheck(L, byte < 256, 2, "Integer too large for a byte");
|
||||||
return luaL_error(L, "Integer too large for a byte");
|
softuart_putchar(softuart, (char)byte);
|
||||||
}
|
} else if (lua_isstring(L, 2)) {
|
||||||
softuart_putchar(suart->softuart, (char)byte);
|
|
||||||
} else if (lua_isstring(L, stack)) {
|
|
||||||
// Send string
|
// Send string
|
||||||
const char *string = luaL_checklstring(L , stack, &str_len);
|
const char *string = luaL_checklstring(L, 2, &str_len);
|
||||||
for (size_t i = 0; i < str_len; i++) {
|
for (size_t i = 0; i < str_len; i++) {
|
||||||
softuart_putchar(suart->softuart, string[i]);
|
softuart_putchar(softuart, string[i]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return luaL_error(L, "Wrong argument type");
|
return luaL_error(L, "Wrong argument type");
|
||||||
|
@ -400,17 +344,18 @@ static int softuart_write(lua_State *L)
|
||||||
static int softuart_gcdelete(lua_State *L)
|
static int softuart_gcdelete(lua_State *L)
|
||||||
{
|
{
|
||||||
NODE_DBG("SoftUART GC called\n");
|
NODE_DBG("SoftUART GC called\n");
|
||||||
softuart_userdata *suart = NULL;
|
softuart_t *softuart = NULL;
|
||||||
suart = (softuart_userdata *)luaL_checkudata(L, 1, "softuart.port");
|
softuart = (softuart_t*) luaL_checkudata(L, 1, "softuart.port");
|
||||||
luaL_argcheck(L, suart, 1, "softuart.port expected");
|
uint8_t last_instance = 1;
|
||||||
if (suart == NULL) {
|
for(uint8_t instance = 0; instance < SOFTUART_GPIO_COUNT; instance++)
|
||||||
NODE_DBG("Userdata is nil\n");
|
if (softuart_gpio_instances[instance] != NULL && instance != softuart->pin_rx)
|
||||||
return 0;
|
last_instance = 0;
|
||||||
}
|
|
||||||
softuart_gpio_instances[suart->softuart->pin_rx] = NULL;
|
softuart_gpio_instances[softuart->pin_rx] = NULL;
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[suart->softuart->pin_rx]);
|
luaL_unref2(L, LUA_REGISTRYINDEX, softuart_rx_cb_ref[softuart->pin_rx]);
|
||||||
softuart_rx_cb_ref[suart->softuart->pin_rx] = LUA_NOREF;
|
// Try to unregister the interrupt hook if this was last or the only instance
|
||||||
free(suart->softuart);
|
if (last_instance)
|
||||||
|
platform_gpio_register_intr_hook(0, softuart_intr_handler);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,17 @@
|
||||||
| :----- | :-------------------- | :---------- | :------ |
|
| :----- | :-------------------- | :---------- | :------ |
|
||||||
|2019-12-27 | [pleningerweb](https://github.com/plieningerweb/), [juancgalvez](https://github.com/juancgalvez/), [crasu](https://github.com/crasu/), [galjonsfigur](https://github.com/galjonsfigur/)| [galjonsfigur](https://github.com/galjonsfigur/) | [softuart.c](../../app/modules/softuart.c) |
|
|2019-12-27 | [pleningerweb](https://github.com/plieningerweb/), [juancgalvez](https://github.com/juancgalvez/), [crasu](https://github.com/crasu/), [galjonsfigur](https://github.com/galjonsfigur/)| [galjonsfigur](https://github.com/galjonsfigur/) | [softuart.c](../../app/modules/softuart.c) |
|
||||||
|
|
||||||
The SoftUART module provides access to multiple software-based UART ports.
|
The SoftUART module offers bit-banged serial ports over GPIO pins.
|
||||||
|
|
||||||
ESP8266 has only 1 full hardware UART port that is used to program the chip and communicate with NodeMCU firmware. The second port is transmit-only. More information can be found in [uart module documentation](uart/). This module provides access to more UART ports and can be used to communicate with devices like GSM or GPS modules. The code is based on [esp8266-software-uart](https://github.com/plieningerweb/esp8266-software-uart) and [Arduino-esp8266-Software-UART](https://github.com/juancgalvez/Arduino-esp8266-Software-UART) projects. Currently doesn't support inverted serial data logic or modes other than 8N1. It's important to notice that this is a software implementation of the serial protocol. There could be some interrupts that make the transmition or reception fail due to invalid timing.
|
!!! warning
|
||||||
|
|
||||||
|
Software implementation of serial port can be unreliable and some reception errors are to be expected.
|
||||||
|
|
||||||
|
ESP8266 has only 1 full hardware UART port that is used to program the chip and communicate with NodeMCU firmware. The second port is transmit-only. More information can be found in [uart module documentation](uart/). This module provides access to more UART ports and can be used to communicate with devices like GSM or GPS modules. The code is based on [esp8266-software-uart](https://github.com/plieningerweb/esp8266-software-uart) and [Arduino-esp8266-Software-UART](https://github.com/juancgalvez/Arduino-esp8266-Software-UART) projects. Currently doesn't support inverted serial data logic or modes other than 8N1. It's important to notice that this is a software implementation of the serial protocol. There could be some interrupts that make the transmission or reception fail due to invalid timing.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
SoftUART cannot be used on D0 pin.
|
|
||||||
|
SoftUART cannot be used on D0 pin.
|
||||||
|
|
||||||
## softuart.setup()
|
## softuart.setup()
|
||||||
|
|
||||||
|
@ -52,6 +57,7 @@ Sets up the callback function to receive data.
|
||||||
```lua
|
```lua
|
||||||
-- Create new software UART with baudrate of 9600, D2 as Tx pin and D3 as Rx pin
|
-- Create new software UART with baudrate of 9600, D2 as Tx pin and D3 as Rx pin
|
||||||
s = softuart.setup(9600, 2, 3)
|
s = softuart.setup(9600, 2, 3)
|
||||||
|
-- Set callback to run when 10 characters show up in the buffer
|
||||||
s:on("data", 10, function(data)
|
s:on("data", 10, function(data)
|
||||||
print("Lua handler called!")
|
print("Lua handler called!")
|
||||||
print(data)
|
print(data)
|
||||||
|
@ -75,4 +81,6 @@ Transmits a byte or sequence of them.
|
||||||
-- Create new software UART with baudrate of 9600, D2 as Tx pin and D3 as Rx pin
|
-- Create new software UART with baudrate of 9600, D2 as Tx pin and D3 as Rx pin
|
||||||
s = softuart.setup(9600, 2, 3)
|
s = softuart.setup(9600, 2, 3)
|
||||||
s:write("Hello!")
|
s:write("Hello!")
|
||||||
|
-- Send character 'a'
|
||||||
|
s:write(97)
|
||||||
```
|
```
|
||||||
|
|
Loading…
Reference in New Issue