I've been running into an odd issue that I wonder if is a bug with the SDK, I can't see where I'm going wrong.
See attached code. It is also at https://gist.github.com/celsworth/4ea8a790df66683496a5 if you prefer.
Code: Select all
#include "esp8266.h"
#include "espconn.h"
#include "gpio.h"
#include "driver/uart.h"
#define WIFI_SSID "xx"
#define WIFI_PASS "xx"
LOCAL const int uart_rx = 14; /* GPIO pin for software serial RX decoding */
LOCAL const int uart_tx = 12; /* GPIO pin for software serial TX (not yet implemented) */
LOCAL const int uart_baud = 9600;
LOCAL uint16_t ts_read_timeout = 7200;
LOCAL struct espconn ts_server;
LOCAL struct espconn *ts_client;
// two buffers, one we're writing into for tx, one is being sent
LOCAL char ts_buf1[256], ts_buf2[256];
// which buffer we're pointing at for writing into
LOCAL char *tx_buffer;
LOCAL int ts_buf_len;
LOCAL bool ts_sending;
void ICACHE_FLASH_ATTR ts_send_buf(void)
{
int r, t_len;
char *t;
// only attempt a send if we're not waiting for a previous espconn_send()
// to return, and we actually have some data to send.
if (ts_client && !ts_sending && ts_buf_len > 0)
{
// swap the buffers with interrupts turned off, so
// ts_append_output() cannot be called while we're in the middle of it
uint32_t savedPS = xt_rsil(15);
t_len = ts_buf_len;
t = tx_buffer;
tx_buffer = (tx_buffer == ts_buf1) ? ts_buf2 : ts_buf1;
ts_buf_len = 0;
xt_wsr_ps(savedPS);
ts_sending = true;
r = espconn_send(ts_client, t, t_len);
if (r != 0)
os_printf("ts_send_buf: len = %d, r = %d\n", t_len, r);
}
}
// queue some output onto our txbuffer
// this is called from interrupt, don't put in flash
void ts_append_output(char c)
{
if (!ts_client) return;
if (ts_buf_len < 256)
{
tx_buffer[ts_buf_len++] = c;
}
else
{
//os_printf("BUFFER FULL, LOSING SERIAL RX DATA!\n");
}
}
LOCAL void ICACHE_FLASH_ATTR ts_disconcb(void *arg)
{
struct espconn *c = (struct espconn *)arg;
ts_client = NULL;
os_printf("tcp connection disconnected\n");
}
LOCAL void ICACHE_FLASH_ATTR ts_recvcb(void *arg, char *pusrdata, unsigned short length)
{
struct espconn *c = (struct espconn *)arg;
// TODO: send pusrdata to the uart
}
LOCAL void ICACHE_FLASH_ATTR ts_sentcb(void *arg)
{
struct espconn *c = (struct espconn *)arg;
int r;
ts_sending = false;
// check if there's any more buffered data to send
ts_send_buf();
}
LOCAL void ICACHE_FLASH_ATTR ts_connectcb(void *arg)
{
struct espconn *c = (struct espconn *)arg;
ts_client = c;
ts_buf_len = 0;
tx_buffer = ts_buf1;
ts_sending = false;
os_printf("tcp connection established\n");
espconn_regist_recvcb(c, ts_recvcb);
// espconn_regist_reconcb(c, ts_recon_cb);
espconn_regist_disconcb(c, ts_disconcb);
espconn_regist_sentcb(c, ts_sentcb);
}
void ICACHE_FLASH_ATTR ts_init(void)
{
ts_server.type = ESPCONN_TCP;
ts_server.state = ESPCONN_NONE;
ts_server.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
ts_server.proto.tcp->local_port = 2001;
espconn_regist_connectcb(&ts_server, ts_connectcb);
espconn_accept(&ts_server);
espconn_regist_time(&ts_server, ts_read_timeout, 0);
// only accept one connection at a time (they get exclusive access to serial console)
espconn_tcp_set_max_con_allow(&ts_server, 1);
os_printf("[%s] ts initialised\n", __func__);
}
LOCAL volatile os_timer_t loop_timer;
LOCAL void ICACHE_FLASH_ATTR loop(os_event_t *events)
{
ts_send_buf();
//os_timer_disarm(&loop_timer); // not sure if needed, sdk doc says yes, doc example says no?
os_timer_arm(&loop_timer, 10, 0);
}
void uart_intr(void *arg)
{
int *gpio_num = arg;
uint8_t i, d = 0, gpio_pin = GPIO_ID_PIN((*gpio_num));
uint32_t start_time, bit_time = (1000000 / uart_baud);
if (! GPIO_INPUT_GET(gpio_pin))
{
// pin is low; we have a start bit. pause for half the expected duration so we can
// sample the next bit right in the middle.
os_delay_us(bit_time / 2);
start_time = 0x7FFFFFFF & system_get_time();
for (i = 0 ; i < 8 ; i++)
{
while ((0x7FFFFFFF & system_get_time()) < (start_time + (bit_time*(i+1))))
{
// abort if timer overflows
if ((0x7FFFFFFF & system_get_time()) < start_time)
break;
}
//shift d to the right
d >>= 1;
// read the bit
if (GPIO_INPUT_GET(gpio_pin))
{
// record the presence of the high bit
d |= 0x80;
}
}
// wait for stop bit
os_delay_us(bit_time);
ts_append_output(d);
}
}
void user_init(void)
{
struct station_config sc;
uart_init(9600, 9600);
// easyintr initialisation
ei_init();
strcpy((char *)&sc.ssid, WIFI_SSID);
strcpy((char *)&sc.password, WIFI_PASS);
wifi_set_opmode_current(STATION_MODE);
wifi_station_set_config_current(&sc);
/* initialise software uart (connected to another serial port) with easyintr */
ei_attach(uart_rx, PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14, uart_intr, &uart_rx);
GPIO_DIS_OUTPUT(GPIO_ID_PIN(uart_rx));
PIN_PULLUP_EN(PERIPHS_IO_MUX_MTMS_U);
os_timer_disarm(&loop_timer);
os_timer_setfn(&loop_timer, loop, NULL);
os_timer_arm(&loop_timer, 1, 0);
ts_init();
os_printf("SDK version:%s\n", system_get_sdk_version());
}
void user_rf_pre_init(void)
{
}
This is basically a serial-to-wifi bridge (only receiving from the serial and sending over tcp works for now).
When running this with some serial data coming into GPIO14, and a client connected which is receiving it, I get "mac 674" after some amount of time - it can vary from seconds to half an hour or more before it triggers.
It happens with SDK 1.3.0, 1.4.0 and 1.5.0.
Code: Select all
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 2
cnt
connected with AirPort, channel 1
dhcp client start...
ip:192.168.0.212,mask:255.255.255.0,gw:192.168.0.1
tcp connection established
pm open,type:2 0
mac 674
Does my code look ok? I have put the full zipfile (its an esp-open-sdk project) here: http://kojan.cae.me.uk/espconn_send_hang.tar.gz
If there is no client connected (so espconn_send does not get called) it runs for hours just fine. No crash.
Would really appreciate any ideas. Thanks!