mirror of https://github.com/jeelabs/esp-link.git
parent
fd14d7e337
commit
42ba248831
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 48 KiB |
@ -0,0 +1,72 @@ |
||||
<html> |
||||
<head><title>Help - ESP Link</title> |
||||
<link rel="stylesheet" type="text/css" href="style.css"> |
||||
</head> |
||||
<body> |
||||
<div id="main"> |
||||
<p><a href="/index.tpl">Home</a> | <a href="/wifi/wifi.tpl">Wifi</a> | |
||||
Serial | <a href="/led.tpl">LED</a></p> |
||||
|
||||
<h1>ESP Link Help</h1> |
||||
|
||||
The ESP Link functions in two wifi modes: Station+AccessPoint (STA+AP) and Station (STA). |
||||
In the STA+AP mode it presents a network called esp8266 that you can connect to using the |
||||
password jeelabs8266. This mode is intended for initial configuration, but it is |
||||
fully functional. Typically the easiest way to connect to the esp8266 network is using a phone, |
||||
tablet, or laptop.</p> |
||||
<p>The recommended next step is to configure the ESP Link to connect to your "normal" |
||||
Wifi network so you can access it from any of your machines. Once you have connected the ESP Link |
||||
to your network and pointed your browser at it successfully, you should |
||||
switch the ESP Link to STA mode, which is more secure (no canned password).<p> |
||||
<p>In STA mode the ESP Link connects to the configured network (the info is saved in flash). |
||||
If, after a reset, it cannot connect for one minute, it automatically reverts to STA+AP mode |
||||
allowing you to reconnect to the esp8266 network to change configuration.</p> |
||||
<p>In STA mode the most tricky part usually is the IP address. On most networks, the ESP Link |
||||
will get a dynamic IP address assigned via DHCP and you now need to enter that IP address into |
||||
your browser to connect. The good news is that after you reset your ESP Link it will continue to |
||||
have the same IP address. However, if you leave it off for the week-end it will most likely get a |
||||
fresh IP the next time it starts up. On many Wifi routers you can enter a fixed mapping from |
||||
the ESP Link's hardware MAC address to a static IP address so it always gets the same IP |
||||
address. This is the recommended method of operation.</p> |
||||
|
||||
<h1>Using your ESP Serial Programmer</h1> |
||||
The ESP Programmer can used in several distinct ways: |
||||
<ul> |
||||
<li>as a transparent bridge between TCP port 23 and the serial port</li> |
||||
<li>as a web console to see input from the serial port</li> |
||||
<li>as an Arduino, AVR, or ARM processor programmer using serial-over-TCP</li> |
||||
<li>as an Arduino, AVR, or ARM processor programmer by uploading HEX files (not yet functional)</li> |
||||
</ul> |
||||
|
||||
<h2>Transparent bridge</h2> |
||||
<p>The ESP accepts TCP connections to port 23 and "connects" through to the serial port. |
||||
Up to 5 simultaneous TCP connections are supported and characters coming in on the serial |
||||
port get passed through to all connections. Characters coming in on a connection get copied |
||||
through to the serial port.</p> |
||||
<p>When using Linux a simple way to use this is <tt>nc esp8266 23</tt></p> |
||||
|
||||
<h2>Programmer using serial-over-TCP</h2> |
||||
<p>By hooking up the ESP's GPIO lines to the reset line of an Arduino (or AVR in general) that is |
||||
preloaded with the Optiboot bootloader/flasher it is possible to reprogram these processors over |
||||
Wifi. The way is works is that the ESP toggles the reset line each time a connection is established |
||||
and the first characters are the flash programming synchronization sequence.</p> |
||||
<p>When using Linux avrdude can be instructed to program an AVR over TCP by using a special syntax |
||||
for the serial port: <tt>-Pnet:esp8266:23</tt>, where <tt>esp8266</tt> is the hostname of the ESP |
||||
Serial Programmer (an IP address could have been used instead).</p> |
||||
<p>NXP's LPC800-serial ARM processors can be programmed similarly by hooking up GPIO pins to the |
||||
ARM's reset and ISP lines. The ESP Serial Programmer issues the correct reset/isp pulses to put |
||||
the ARM chip into firmware programming mode.</p> |
||||
|
||||
<h2>Web Console</h2> |
||||
<p>The output of an attached Arduino/AVR/ARM can also be monitored via the console web page. |
||||
When connecting, it shows the most recent 10KB of characters received on the serial port and |
||||
then continues to print everything that comes in on the serial port. Eventually the page refreshes |
||||
when it gets very long. (Yes, this could be improved with some javascript...)</p> |
||||
|
||||
<h2>Programmer using HEX upload</h2> |
||||
<p><i>(Not yet functional)</i> Instead of using the wifi-to-serial bridge to program |
||||
microcontrollers it is often faster to upload the HEX file to the ESP Serial Programmer and |
||||
have it perform the actual programming protocol.</p> |
||||
|
||||
</div> |
||||
</body></html> |
@ -1,25 +1,25 @@ |
||||
<html> |
||||
<head><title>Esp8266 web server</title> |
||||
<head><title>ESP Link</title> |
||||
<link rel="stylesheet" type="text/css" href="style.css"> |
||||
</head> |
||||
<body> |
||||
<div id="main"> |
||||
<h1>It Works</h1> |
||||
<p><a href="/index.tpl">Home</a> | <a href="/wifi/wifi.tpl">Wifi</a> | |
||||
Serial | <a href="/led.tpl">LED</a> | <a href="/help.tpl">Help</a></p> |
||||
|
||||
<h1>ESP Link</h1> |
||||
<p> |
||||
If you see this, it means the tiny li'l website in your ESP8266 does actually work. Fyi, this page has |
||||
been loaded <b>%counter%</b> times. |
||||
The ESP Link connects the ESP's serial port to Wifi and it can |
||||
program microcontrollers over the serial port, in particular Arduinos, AVRs, and |
||||
NXP's LPC800-series ARM processors.</p> |
||||
|
||||
<h1>Status</h1> |
||||
<ul> |
||||
<li>If you haven't connected this device to your WLAN network now, you can <a href="/wifi">do so.</a></li> |
||||
<li>You can also control the <a href="led.tpl">LED</a>.</li> |
||||
<li>You can download the raw <a href="flash.bin">contents</a> of the SPI flash rom</li> |
||||
<li>And because I can, here's a link to my <a href="http://spritesmods.com/?f=esphttpd">website</a></ul> |
||||
<li>This page has been loaded <b>%counter%</b> times</li> |
||||
<li>Manage <a href="/wifi">wifi</a></li> |
||||
<li>Control the <a href="led.tpl">LED</a></li> |
||||
</ul> |
||||
</p> |
||||
|
||||
<p>And because we're on the Internets now, here are the required pictures of cats:<br /> |
||||
<!--img src="cats/cross-eyed-cat.jpg"><br /--> |
||||
<img src="cats/junge-katze-iv_01.jpg"><br /> |
||||
<!--img src="cats/kitten-loves-toy.jpg"><br /--> |
||||
</p> |
||||
</div> |
||||
</body></html> |
||||
|
@ -1,24 +0,0 @@ |
||||
|
||||
body { |
||||
background-color: #404040; |
||||
font-family: sans-serif; |
||||
} |
||||
|
||||
#main { |
||||
background-color: #d0d0FF; |
||||
-moz-border-radius: 5px; |
||||
-webkit-border-radius: 5px; |
||||
border-radius: 5px; |
||||
border: 2px solid #000000; |
||||
width: 800px; |
||||
margin: 0 auto; |
||||
padding: 20px |
||||
} |
||||
|
||||
.icon { |
||||
background-image: url("icons.png"); |
||||
background-color: transparent; |
||||
width: 32px; |
||||
height: 32px; |
||||
display: inline-block; |
||||
} |
@ -0,0 +1,224 @@ |
||||
#include "espmissingincludes.h" |
||||
#include "c_types.h" |
||||
#include "user_interface.h" |
||||
#include "espconn.h" |
||||
#include "mem.h" |
||||
#include "osapi.h" |
||||
#include "gpio.h" |
||||
|
||||
#include "uart.h" |
||||
#include "serbridge.h" |
||||
|
||||
#if 1 |
||||
// GPIO for esp-03 module with gpio12->reset, gpio13->isp, gpio2->"ser" LED
|
||||
#define MCU_RESET 12 |
||||
#define MCU_ISP 13 |
||||
#define MCU_LED 2 |
||||
#else |
||||
// GPIO for esp-01 module with gpio0->reset, gpio2->isp
|
||||
#define MCU_RESET 0 |
||||
#define MCU_ISP 2 |
||||
#undef MCU_LED |
||||
#endif |
||||
|
||||
static struct espconn serbridgeConn; |
||||
static esp_tcp serbridgeTcp; |
||||
|
||||
sint8 ICACHE_FLASH_ATTR espbuffsend(serbridgeConnData *conn, const char *data, uint16 len); |
||||
|
||||
// Connection pool
|
||||
serbridgeConnData connData[MAX_CONN]; |
||||
// Transmit buffers for the connection pool
|
||||
static char txbuffer[MAX_CONN][MAX_TXBUFFER]; |
||||
|
||||
// Given a pointer to an espconn struct find the connection that correcponds to it
|
||||
static serbridgeConnData ICACHE_FLASH_ATTR *serbridgeFindConnData(void *arg) { |
||||
for (int i=0; i<MAX_CONN; i++) { |
||||
if (connData[i].conn == (struct espconn *)arg) { |
||||
return &connData[i]; |
||||
} |
||||
} |
||||
//os_printf("FindConnData: Huh? Couldn't find connection for %p\n", arg);
|
||||
return NULL; // not found, may be closed already...
|
||||
} |
||||
|
||||
// Send all data in conn->txbuffer
|
||||
// returns result from espconn_sent if data in buffer or ESPCONN_OK (0)
|
||||
// Use only internally from espbuffsend and serbridgeSentCb
|
||||
static sint8 ICACHE_FLASH_ATTR sendtxbuffer(serbridgeConnData *conn) { |
||||
sint8 result = ESPCONN_OK; |
||||
if (conn->txbufferlen != 0) { |
||||
//os_printf("%d TX %d\n", system_get_time(), conn->txbufferlen);
|
||||
conn->readytosend = false; |
||||
result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen); |
||||
conn->txbufferlen = 0; |
||||
if (result != ESPCONN_OK) { |
||||
os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
// espbuffsend adds data to the send buffer. If the previous send was completed it calls
|
||||
// sendtxbuffer and espconn_sent.
|
||||
// Returns ESPCONN_OK (0) for success, -128 if buffer is full or error from espconn_sent
|
||||
// Use espbuffsend instead of espconn_sent as it solves the problem that espconn_sent must
|
||||
// only be called *after* receiving an espconn_sent_callback for the previous packet.
|
||||
sint8 ICACHE_FLASH_ATTR espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) { |
||||
if (conn->txbufferlen + len > MAX_TXBUFFER) { |
||||
os_printf("espbuffsend: txbuffer full on conn %p\n", conn); |
||||
return -128; |
||||
} |
||||
os_memcpy(conn->txbuffer + conn->txbufferlen, data, len); |
||||
conn->txbufferlen += len; |
||||
if (conn->readytosend) { |
||||
return sendtxbuffer(conn); |
||||
} else { |
||||
//os_printf("%d QU %d\n", system_get_time(), conn->txbufferlen);
|
||||
} |
||||
return ESPCONN_OK; |
||||
} |
||||
|
||||
//callback after the data are sent
|
||||
static void ICACHE_FLASH_ATTR serbridgeSentCb(void *arg) { |
||||
serbridgeConnData *conn = serbridgeFindConnData(arg); |
||||
//os_printf("Sent callback on conn %p\n", conn);
|
||||
if (conn == NULL) return; |
||||
//os_printf("%d ST\n", system_get_time());
|
||||
conn->readytosend = true; |
||||
sendtxbuffer(conn); // send possible new data in txbuffer
|
||||
} |
||||
|
||||
// Receive callback
|
||||
static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned short len) { |
||||
serbridgeConnData *conn = serbridgeFindConnData(arg); |
||||
//os_printf("Receive callback on conn %p\n", conn);
|
||||
if (conn == NULL) return; |
||||
|
||||
// at the start of a connection we're in cmInit mode and we wait for the first few characters
|
||||
// to arrive in order to decide what type of connection this is.. The following if statements
|
||||
// do this dispatch. An issue here is that we assume that the first few characters all arrive
|
||||
// in the same TCP packet, which is true if the sender is a program, but not necessarily
|
||||
// if the sender is a person typing (although in that case the line-oriented TTY input seems
|
||||
// to make it work too). If this becomes a problem we need to buffer the first few chars...
|
||||
if (conn->conn_mode == cmInit) { |
||||
|
||||
// If the connection starts with the Arduino or ARM reset sequence we perform a RESET
|
||||
if ((len == 2 && strncmp(data, "0 ", 2) == 0) || |
||||
(len == 2 && strncmp(data, "?\n", 2) == 0) || |
||||
(len == 3 && strncmp(data, "?\r\n", 3) == 0)) { |
||||
os_printf("MCU Reset=%d ISP=%d\n", MCU_RESET, MCU_ISP); |
||||
// send reset to arduino/ARM
|
||||
GPIO_OUTPUT_SET(MCU_RESET, 0); |
||||
os_delay_us(100L); |
||||
GPIO_OUTPUT_SET(MCU_ISP, 0); |
||||
os_delay_us(1000L); |
||||
GPIO_OUTPUT_SET(MCU_RESET, 1); |
||||
os_delay_us(100L); |
||||
GPIO_OUTPUT_SET(MCU_ISP, 1); |
||||
os_delay_us(1000L); |
||||
//uart0_tx_buffer(data, len);
|
||||
//conn->skip_chars = 2;
|
||||
conn->conn_mode = cmAVR; |
||||
//return;
|
||||
} else { |
||||
conn->conn_mode = cmTransparent; |
||||
} |
||||
} |
||||
|
||||
uart0_tx_buffer(data, len); |
||||
} |
||||
|
||||
// Error callback (it's really poorly named, it's not a "connection reconnected" callback,
|
||||
// it's really a "connection broken, please reconnect" callback)
|
||||
static void ICACHE_FLASH_ATTR serbridgeReconCb(void *arg, sint8 err) { |
||||
serbridgeConnData *conn=serbridgeFindConnData(arg); |
||||
if (conn == NULL) return; |
||||
// Close the connection
|
||||
espconn_disconnect(conn->conn); |
||||
conn->conn = NULL; |
||||
} |
||||
|
||||
// Disconnection callback
|
||||
static void ICACHE_FLASH_ATTR serbridgeDisconCb(void *arg) { |
||||
// Iterate through all the connections and deallocate the ones that are in a state that
|
||||
// indicates that they're closed
|
||||
for (int i=0; i<MAX_CONN; i++) { |
||||
if (connData[i].conn != NULL && |
||||
(connData[i].conn->state == ESPCONN_NONE || connData[i].conn->state == ESPCONN_CLOSE)) |
||||
{ |
||||
connData[i].conn = NULL; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// New connection callback, use one of the connection descriptors, if we have one left.
|
||||
static void ICACHE_FLASH_ATTR serbridgeConnectCb(void *arg) { |
||||
struct espconn *conn = arg; |
||||
//Find empty conndata in pool
|
||||
int i; |
||||
for (i=0; i<MAX_CONN; i++) if (connData[i].conn==NULL) break; |
||||
os_printf("Accept port 23, conn=%p, pool slot %d\n", conn, i); |
||||
|
||||
if (i==MAX_CONN) { |
||||
os_printf("Aiee, conn pool overflow!\n"); |
||||
espconn_disconnect(conn); |
||||
return; |
||||
} |
||||
|
||||
connData[i].conn=conn; |
||||
connData[i].txbufferlen = 0; |
||||
connData[i].readytosend = true; |
||||
connData[i].skip_chars = 0; |
||||
connData[i].conn_mode = cmInit; |
||||
|
||||
espconn_regist_recvcb(conn, serbridgeRecvCb); |
||||
espconn_regist_reconcb(conn, serbridgeReconCb); |
||||
espconn_regist_disconcb(conn, serbridgeDisconCb); |
||||
espconn_regist_sentcb(conn, serbridgeSentCb); |
||||
} |
||||
|
||||
// callback with a buffer of characters that have arrived on the uart
|
||||
void ICACHE_FLASH_ATTR |
||||
serbridgeUartCb(char *buf, int length) { |
||||
// push the buffer into each open connection
|
||||
int s = 0; |
||||
for (int i = 0; i < MAX_CONN; ++i) { |
||||
if (connData[i].conn) { |
||||
s++; |
||||
if (connData[i].skip_chars == 0) { |
||||
espbuffsend(&connData[i], buf, length); |
||||
} else if (connData[i].skip_chars >= length) { |
||||
connData[i].skip_chars -= length; |
||||
} else { // connData[i].skip_chars < length
|
||||
espbuffsend(&connData[i], buf+connData[i].skip_chars, length-connData[i].skip_chars); |
||||
connData[i].skip_chars = 0; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Start transparent serial bridge TCP server on specified port (typ. 23)
|
||||
void ICACHE_FLASH_ATTR serbridgeInit(int port) { |
||||
int i; |
||||
for (i = 0; i < MAX_CONN; i++) { |
||||
connData[i].conn = NULL; |
||||
connData[i].txbuffer = txbuffer[i]; |
||||
} |
||||
serbridgeConn.type = ESPCONN_TCP; |
||||
serbridgeConn.state = ESPCONN_NONE; |
||||
serbridgeTcp.local_port = port; |
||||
serbridgeConn.proto.tcp = &serbridgeTcp; |
||||
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12); |
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U , FUNC_GPIO13); |
||||
GPIO_OUTPUT_SET(MCU_ISP, 1); |
||||
GPIO_OUTPUT_SET(MCU_RESET, 0); |
||||
#ifdef MCU_LED |
||||
//GPIO_OUTPUT_SET(MCU_LED, 1);
|
||||
#endif |
||||
|
||||
espconn_regist_connectcb(&serbridgeConn, serbridgeConnectCb); |
||||
espconn_accept(&serbridgeConn); |
||||
espconn_regist_time(&serbridgeConn, SER_BRIDGE_TIMEOUT, 0); |
||||
} |
@ -0,0 +1,37 @@ |
||||
#ifndef __SER_BRIDGE_H__ |
||||
#define __SER_BRIDGE_H__ |
||||
|
||||
#include <ip_addr.h> |
||||
#include <c_types.h> |
||||
#include <espconn.h> |
||||
|
||||
#define MAX_CONN 5 |
||||
#define SER_BRIDGE_TIMEOUT 28799 |
||||
|
||||
//Max send buffer len
|
||||
#define MAX_TXBUFFER 1024 |
||||
|
||||
typedef struct serbridgeConnData serbridgeConnData; |
||||
|
||||
enum connModes { |
||||
cmInit = 0, // initialization mode: nothing received yet
|
||||
cmTransparent, // transparent mode
|
||||
cmAVR, // Arduino/AVR programming mode
|
||||
cmARM, // ARM (LPC8xx) programming
|
||||
cmEcho, // simply echo characters (used for debugging latency)
|
||||
cmCommand, // AT command mode
|
||||
}; |
||||
|
||||
struct serbridgeConnData { |
||||
struct espconn *conn; |
||||
enum connModes conn_mode; // connection mode
|
||||
char *txbuffer; // buffer for the data to send
|
||||
uint16 txbufferlen; // length of data in txbuffer
|
||||
bool readytosend; // true, if txbuffer can send by espconn_sent
|
||||
uint8 skip_chars; // number of chars to skip from uart, used in Arduino reset sequence
|
||||
}; |
||||
|
||||
void ICACHE_FLASH_ATTR serbridgeInit(int port); |
||||
void ICACHE_FLASH_ATTR serbridgeUartCb(char *buf, int len); |
||||
|
||||
#endif /* __SER_BRIDGE_H__ */ |
@ -0,0 +1,271 @@ |
||||
/*
|
||||
* File : uart.c |
||||
* This file is part of Espressif's AT+ command set program. |
||||
* Copyright (C) 2013 - 2016, Espressif Systems |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of version 3 of the GNU General Public License as |
||||
* published by the Free Software Foundation. |
||||
* |
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
#include "espmissingincludes.h" |
||||
#include "ets_sys.h" |
||||
#include "osapi.h" |
||||
#include "user_interface.h" |
||||
#include "uart.h" |
||||
|
||||
#define recvTaskPrio 0 |
||||
#define recvTaskQueueLen 64 |
||||
|
||||
// UartDev is defined and initialized in rom code.
|
||||
extern UartDevice UartDev; |
||||
|
||||
os_event_t recvTaskQueue[recvTaskQueueLen]; |
||||
|
||||
#define MAX_CB 4 |
||||
static UartRecv_cb uart_recv_cb[4]; |
||||
|
||||
static void uart0_rx_intr_handler(void *para); |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : uart_config |
||||
* Description : Internal used function |
||||
* UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled |
||||
* UART1 just used for debug output |
||||
* Parameters : uart_no, use UART0 or UART1 defined ahead |
||||
* Returns : NONE |
||||
*******************************************************************************/ |
||||
static void ICACHE_FLASH_ATTR |
||||
uart_config(uint8 uart_no) |
||||
{ |
||||
if (uart_no == UART1) { |
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); |
||||
PIN_PULLDWN_DIS(PERIPHS_IO_MUX_GPIO2_U); |
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO2_U); |
||||
} else { |
||||
/* rcv_buff size if 0x100 */ |
||||
ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff)); |
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); |
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); |
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); |
||||
} |
||||
|
||||
uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate)); |
||||
|
||||
if (uart_no == UART1) //UART 1 always 8 N 1
|
||||
WRITE_PERI_REG(UART_CONF0(uart_no), |
||||
CALC_UARTMODE(EIGHT_BITS, NONE_BITS, ONE_STOP_BIT)); |
||||
else |
||||
WRITE_PERI_REG(UART_CONF0(uart_no), |
||||
CALC_UARTMODE(UartDev.data_bits, UartDev.parity, UartDev.stop_bits)); |
||||
|
||||
//clear rx and tx fifo,not ready
|
||||
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); |
||||
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); |
||||
|
||||
if (uart_no == UART0) { |
||||
// Configure RX interrupt conditions as follows: trigger rx-full when there are 80 characters
|
||||
// in the buffer (allows for 64-byte HEX records), trigger rx-timeout when the fifo is
|
||||
// non-empty and nothing further has been received for 4 character period. Also set the
|
||||
// hardware flow-control to trigger when the FIFO holds 100 characters, although we don't
|
||||
// really expect the signals to actually be wired up to anything. It doesn't hurt to set
|
||||
// the threshold here...
|
||||
WRITE_PERI_REG(UART_CONF1(uart_no), |
||||
((80 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | |
||||
((100 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | |
||||
UART_RX_FLOW_EN | |
||||
(4 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S | |
||||
UART_RX_TOUT_EN); |
||||
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | |
||||
UART_RXFIFO_TOUT_INT_ENA | UART_FRM_ERR_INT_ENA); |
||||
} else { |
||||
WRITE_PERI_REG(UART_CONF1(uart_no), |
||||
((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); |
||||
} |
||||
|
||||
//clear all interrupt
|
||||
WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : uart1_tx_one_char |
||||
* Description : Internal used function |
||||
* Use uart1 interface to transfer one char |
||||
* Parameters : uint8 TxChar - character to tx |
||||
* Returns : OK |
||||
*******************************************************************************/ |
||||
static STATUS |
||||
uart_tx_one_char(uint8 uart, uint8 c) |
||||
{ |
||||
//Wait until there is room in the FIFO
|
||||
while (((READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=100) ; |
||||
//Send the character
|
||||
WRITE_PERI_REG(UART_FIFO(uart), c); |
||||
return OK; |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : uart1_write_char |
||||
* Description : Internal used function |
||||
* Do some special deal while tx char is '\r' or '\n' |
||||
* Parameters : char c - character to tx |
||||
* Returns : NONE |
||||
*******************************************************************************/ |
||||
void ICACHE_FLASH_ATTR |
||||
uart1_write_char(char c) |
||||
{ |
||||
if (c == '\n') uart_tx_one_char(UART1, '\r'); |
||||
uart_tx_one_char(UART1, c); |
||||
} |
||||
void ICACHE_FLASH_ATTR |
||||
uart0_write_char(char c) |
||||
{ |
||||
if (c == '\n') uart_tx_one_char(UART0, '\r'); |
||||
uart_tx_one_char(UART0, c); |
||||
} |
||||
/******************************************************************************
|
||||
* FunctionName : uart0_tx_buffer |
||||
* Description : use uart0 to transfer buffer |
||||
* Parameters : uint8 *buf - point to send buffer |
||||
* uint16 len - buffer len |
||||
* Returns : |
||||
*******************************************************************************/ |
||||
void ICACHE_FLASH_ATTR |
||||
uart0_tx_buffer(char *buf, uint16 len) |
||||
{ |
||||
uint16 i; |
||||
|
||||
for (i = 0; i < len; i++) |
||||
{ |
||||
uart_tx_one_char(UART0, buf[i]); |
||||
} |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : uart0_sendStr |
||||
* Description : use uart0 to transfer buffer |
||||
* Parameters : uint8 *buf - point to send buffer |
||||
* uint16 len - buffer len |
||||
* Returns : |
||||
*******************************************************************************/ |
||||
void ICACHE_FLASH_ATTR |
||||
uart0_sendStr(const char *str) |
||||
{ |
||||
while(*str) |
||||
{ |
||||
uart_tx_one_char(UART0, *str++); |
||||
} |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : uart0_rx_intr_handler |
||||
* Description : Internal used function |
||||
* UART0 interrupt handler, add self handle code inside |
||||
* Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg |
||||
* Returns : NONE |
||||
*******************************************************************************/ |
||||
static void // must not use ICACHE_FLASH_ATTR !
|
||||
uart0_rx_intr_handler(void *para) |
||||
{ |
||||
/* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2,
|
||||
* bit0 represents uart1 and uart0 respectively */ |
||||
uint8 uart_no = UART0;//UartDev.buff_uart_no;
|
||||
|
||||
if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) |
||||
{ |
||||
os_printf("FRM_ERR\r\n"); |
||||
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR); |
||||
} |
||||
|
||||
if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) |
||||
{ |
||||
//os_printf("fifo full\r\n");
|
||||
ETS_UART_INTR_DISABLE(); |
||||
|
||||
system_os_post(recvTaskPrio, 0, 0); |
||||
} |
||||
else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) |
||||
{ |
||||
ETS_UART_INTR_DISABLE(); |
||||
//os_printf("stat:%02X",*(uint8 *)UART_INT_ENA(uart_no));
|
||||
system_os_post(recvTaskPrio, 0, 0); |
||||
} |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : uart_recvTask |
||||
* Description : system task triggered on receive interrupt, empties FIFO and calls callbacks |
||||
*******************************************************************************/ |
||||
static void ICACHE_FLASH_ATTR |
||||
uart_recvTask(os_event_t *events) |
||||
{ |
||||
while (READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { |
||||
//WRITE_PERI_REG(0X60000914, 0x73); //WTD // commented out by TvE
|
||||
|
||||
// read a buffer-full from the uart
|
||||
uint16 length = 0; |
||||
char buf[128]; |
||||
while ((READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) && |
||||
(length < 128)) { |
||||
buf[length++] = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; |
||||
} |
||||
//os_printf("%d ix %d\n", system_get_time(), length);
|
||||
|
||||
for (int i=0; i<MAX_CB; i++) { |
||||
if (uart_recv_cb[i] != NULL) (uart_recv_cb[i])(buf, length); |
||||
} |
||||
} |
||||
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR); |
||||
ETS_UART_INTR_ENABLE(); |
||||
} |
||||
|
||||
/******************************************************************************
|
||||
* FunctionName : uart_init |
||||
* Description : user interface for init uart |
||||
* Parameters : UartBautRate uart0_br - uart0 bautrate |
||||
* UartBautRate uart1_br - uart1 bautrate |
||||
* Returns : NONE |
||||
*******************************************************************************/ |
||||
void ICACHE_FLASH_ATTR |
||||
uart_init(UartBautRate uart0_br, UartBautRate uart1_br) |
||||
{ |
||||
// rom use 74880 baut_rate, here reinitialize
|
||||
UartDev.baut_rate = uart0_br; |
||||
uart_config(UART0); |
||||
UartDev.baut_rate = uart1_br; |
||||
uart_config(UART1); |
||||
for (int i=0; i<4; i++) uart_tx_one_char(UART1, '\n'); |
||||
for (int i=0; i<4; i++) uart_tx_one_char(UART0, '\n'); |
||||
ETS_UART_INTR_ENABLE(); |
||||
|
||||
// install uart1 putc callback
|
||||
os_install_putc1((void *)uart0_write_char); |
||||
|
||||
system_os_task(uart_recvTask, recvTaskPrio, recvTaskQueue, recvTaskQueueLen); |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
uart_add_recv_cb(UartRecv_cb cb) { |
||||
for (int i=0; i<MAX_CB; i++) { |
||||
if (uart_recv_cb[i] == NULL) { |
||||
uart_recv_cb[i] = cb; |
||||
return; |
||||
} |
||||
} |
||||
os_printf("UART: max cb count exceeded\n"); |
||||
} |
||||
|
||||
void ICACHE_FLASH_ATTR |
||||
uart_reattach() |
||||
{ |
||||
uart_init(BIT_RATE_74880, BIT_RATE_74880); |
||||
// ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc, &(UartDev.rcv_buff));
|
||||
// ETS_UART_INTR_ENABLE();
|
||||
} |
@ -0,0 +1,21 @@ |
||||
#ifndef __UART_H__ |
||||
#define __UART_H__ |
||||
|
||||
#include "uart_hw.h" |
||||
|
||||
// Receive callback function signature
|
||||
typedef void (*UartRecv_cb)(char *buf, int len); |
||||
|
||||
// Initialize UARTs to the provided baud rates (115200 recommended). This also makes the os_printf
|
||||
// calls use uart1 for output (for debugging purposes)
|
||||
void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br); |
||||
|
||||
// Transmit a buffer of characters on UART0
|
||||
void ICACHE_FLASH_ATTR uart0_tx_buffer(char *buf, uint16 len); |
||||
|
||||
// Add a receive callback function, this is called on the uart receive task each time a chunk
|
||||
// of bytes are received. A small number of callbacks can be added and they are all called
|
||||
// with all new characters.
|
||||
void ICACHE_FLASH_ATTR uart_add_recv_cb(UartRecv_cb cb); |
||||
|
||||
#endif /* __UART_H__ */ |
@ -0,0 +1,30 @@ |
||||
#include <esp8266.h> |
||||
|
||||
#define LEDGPIO 0 |
||||
|
||||
static ETSTimer ledTimer; |
||||
|
||||
void ICACHE_FLASH_ATTR setLed(int on) { |
||||
if (on) { |
||||
gpio_output_set((1<<LEDGPIO), 0, (1<<LEDGPIO), 0); |
||||
} else { |
||||
gpio_output_set(0, (1<<LEDGPIO), (1<<LEDGPIO), 0); |
||||
} |
||||
} |
||||
|
||||
static uint8_t ledState = 0; |
||||
|
||||
static void ICACHE_FLASH_ATTR ledTimerCb(void *arg) { |
||||
//os_printf("Timer Hello\n");
|
||||
setLed((ledState++)&1); |
||||
} |
||||
|
||||
void statusInit() { |
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0); |
||||
gpio_output_set(0, 0, (1<<LEDGPIO), 0); |
||||
os_timer_disarm(&ledTimer); |
||||
os_timer_setfn(&ledTimer, ledTimerCb, NULL); |
||||
os_timer_arm(&ledTimer, 500, 1); |
||||
} |
||||
|
||||
|
@ -0,0 +1,7 @@ |
||||
#ifndef STATUS_H |
||||
#define STATUS_H |
||||
|
||||
void statusInit(void); |
||||
|
||||
#endif |
||||
|
Loading…
Reference in new issue