Update ESP8266 version
This commit is contained in:
parent
102219f9a7
commit
ff2cd22d9a
42 changed files with 3035 additions and 213 deletions
350
embedded8266/common/commonservices.c
Normal file
350
embedded8266/common/commonservices.c
Normal file
|
@ -0,0 +1,350 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#include "commonservices.h"
|
||||
#include "mem.h"
|
||||
#include "c_types.h"
|
||||
#include "user_interface.h"
|
||||
#include "ets_sys.h"
|
||||
#include "osapi.h"
|
||||
#include "espconn.h"
|
||||
#include "mystuff.h"
|
||||
#include "ip_addr.h"
|
||||
#include "http.h"
|
||||
#include "spi_flash.h"
|
||||
#include "esp8266_rom.h"
|
||||
#include "flash_rewriter.h"
|
||||
|
||||
static struct espconn *pUdpServer;
|
||||
static struct espconn *pHTTPServer;
|
||||
struct espconn *pespconn;
|
||||
|
||||
static int need_to_switch_back_to_soft_ap = 0; //0 = no, 1 = will need to. 2 = do it now.
|
||||
#define MAX_STATIONS 20
|
||||
struct totalscan_t
|
||||
{
|
||||
char name[32];
|
||||
char mac[18]; //string
|
||||
int8_t rssi;
|
||||
uint8_t channel;
|
||||
uint8_t encryption;
|
||||
} totalscan[MAX_STATIONS];
|
||||
int scanplace = 0;
|
||||
static void ICACHE_FLASH_ATTR scandone(void *arg, STATUS status)
|
||||
{
|
||||
scaninfo *c = arg;
|
||||
struct bss_info *inf;
|
||||
|
||||
if( need_to_switch_back_to_soft_ap == 1 )
|
||||
need_to_switch_back_to_soft_ap = 2;
|
||||
|
||||
printf("!%p\n",c->pbss);
|
||||
|
||||
if (!c->pbss) {
|
||||
scanplace = -1;
|
||||
return;
|
||||
}
|
||||
// printf("!%s\n",inf->ssid);
|
||||
STAILQ_FOREACH(inf, c->pbss, next) {
|
||||
printf( "%s\n", inf->ssid );
|
||||
ets_memcpy( totalscan[scanplace].name, inf->ssid, 32 );
|
||||
ets_sprintf( totalscan[scanplace].mac, MACSTR, MAC2STR( inf->bssid ) );
|
||||
//ets_memcpy( totalscan[scanplace].mac, "not implemented", 16 );
|
||||
totalscan[scanplace].rssi = inf->rssi;
|
||||
totalscan[scanplace].channel = inf->channel;
|
||||
totalscan[scanplace].encryption = inf->authmode;
|
||||
inf = (struct bss_info *) &inf->next;
|
||||
scanplace++;
|
||||
if( scanplace == MAX_STATIONS ) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR issue_command(void *arg, char *pusrdata, unsigned short len)
|
||||
{
|
||||
pespconn = (struct espconn *)arg;
|
||||
//We accept commands on this.
|
||||
|
||||
switch( pusrdata[0] )
|
||||
{
|
||||
case 'f': case 'F': //Flashing commands (F_)
|
||||
{
|
||||
flashchip->chip_size = 0x01000000;
|
||||
// ets_printf( "PC%p\n", &pusrdata[2] );
|
||||
const char * colon = (const char *) ets_strstr( (char*)&pusrdata[2], ":" );
|
||||
int nr = my_atoi( &pusrdata[2] );
|
||||
|
||||
switch (pusrdata[1])
|
||||
{
|
||||
case 'e': case 'E': //(FE#\n) <- # = sector.
|
||||
{
|
||||
char __attribute__ ((aligned (16))) buffer[50];
|
||||
char * buffend;
|
||||
buffend = buffer;
|
||||
|
||||
EnterCritical();
|
||||
spi_flash_erase_sector( nr ); //SPI_FLASH_SEC_SIZE 4096
|
||||
ExitCritical();
|
||||
|
||||
buffend += ets_sprintf(buffend, "FE%d\r\n", nr );
|
||||
espconn_sent( pespconn, buffer, ets_strlen( buffer ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b': case 'B': //(FE#\n) <- # = sector.
|
||||
{
|
||||
char __attribute__ ((aligned (16))) buffer[50];
|
||||
char * buffend;
|
||||
buffend = buffer;
|
||||
//spi_flash_erase_sector( nr ); //SPI_FLASH_SEC_SIZE 4096
|
||||
|
||||
EnterCritical();
|
||||
SPIEraseBlock( nr );
|
||||
ExitCritical();
|
||||
|
||||
buffend += ets_sprintf(buffend, "FB%d\r\n", nr );
|
||||
espconn_sent( pespconn, buffer, ets_strlen( buffer ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case 'm': case 'M': //Execute the flash re-writer
|
||||
{
|
||||
char ret[128];
|
||||
int n = ets_sprintf( ret, "FM" );
|
||||
espconn_sent( pespconn, ret, n );
|
||||
int r = (*GlobalRewriteFlash)( &pusrdata[2], len-2 );
|
||||
n = ets_sprintf( ret, "!FM%d", r );
|
||||
espconn_sent( pespconn, ret, n );
|
||||
}
|
||||
case 'w': case 'W': //Flash Write (FW#\n) <- # = byte pos.
|
||||
if( colon )
|
||||
{
|
||||
char __attribute__ ((aligned (32))) buffer[1300];
|
||||
char * buffend;
|
||||
buffend = buffer;
|
||||
buffer[0] = 0;
|
||||
colon++;
|
||||
const char * colon2 = (const char *) ets_strstr( (char*)colon, ":" );
|
||||
if( colon2 )
|
||||
{
|
||||
colon2++;
|
||||
int datlen = (int)len - (colon2 - pusrdata);
|
||||
ets_memcpy( buffer, colon2, datlen );
|
||||
|
||||
EnterCritical();
|
||||
spi_flash_write( nr, (uint32*)buffer, (datlen/4)*4 );
|
||||
ExitCritical();
|
||||
|
||||
//SPIWrite( nr, (uint32_t*)buffer, (datlen/4)*4 );
|
||||
|
||||
buffend = buffer;
|
||||
buffend += ets_sprintf(buffend, "FW%d\r\n", nr );
|
||||
if( ets_strlen( buffer ) )
|
||||
espconn_sent( pespconn, buffer, ets_strlen( buffer ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'r': case 'R': //Flash Read (FR#\n) <- # = sector.
|
||||
if( colon )
|
||||
{
|
||||
char __attribute__ ((aligned (16))) buffer[1300];
|
||||
char * buffend;
|
||||
buffend = buffer;
|
||||
buffer[0] = 0;
|
||||
colon++;
|
||||
int datlen = my_atoi( colon );
|
||||
if( datlen <= 1280 )
|
||||
{
|
||||
buffend += ets_sprintf(buffend, "FR%08d:%04d:", nr, datlen );
|
||||
int frontlen = buffend - buffer;
|
||||
spi_flash_read( nr, (uint32*)buffend, (datlen/4)*4 );
|
||||
espconn_sent( pespconn, buffer, frontlen + datlen );
|
||||
buffer[0] = 0;
|
||||
if( ets_strlen( buffer ) )
|
||||
espconn_sent( pespconn, buffer, ets_strlen( buffer ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
flashchip->chip_size = 0x00080000;
|
||||
break;
|
||||
}
|
||||
case 'w': case 'W': // (W1:SSID:PASSWORD) (To connect) or (W2) to be own base station. ...or WI, to get info... or WS to scan.
|
||||
{
|
||||
char * colon = (char *) ets_strstr( (char*)&pusrdata[2], ":" );
|
||||
char * colon2 = (colon)?((char *)ets_strstr( (char*)(colon+1), ":" )):0;
|
||||
char * extra = colon2;
|
||||
char __attribute__ ((aligned (16))) buffer[1300];
|
||||
char * buffend;
|
||||
buffend = buffer;
|
||||
buffer[0] = 0;
|
||||
|
||||
if( extra )
|
||||
{
|
||||
for( ; *extra; extra++ )
|
||||
{
|
||||
if( *extra < 32 )
|
||||
{
|
||||
*extra = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (pusrdata[1])
|
||||
{
|
||||
case '1': //Station mode
|
||||
if( colon && colon2 )
|
||||
{
|
||||
int c1l = 0;
|
||||
int c2l = 0;
|
||||
struct station_config stationConf;
|
||||
*colon = 0; colon++;
|
||||
*colon2 = 0; colon2++;
|
||||
c1l = ets_strlen( colon );
|
||||
c2l = ets_strlen( colon2 );
|
||||
if( c1l > 32 ) c1l = 32;
|
||||
if( c2l > 32 ) c2l = 32;
|
||||
os_bzero( &stationConf, sizeof( stationConf ) );
|
||||
|
||||
printf( "Switching to: \"%s\"/\"%s\".\n", colon, colon2 );
|
||||
|
||||
os_memcpy(&stationConf.ssid, colon, c1l);
|
||||
os_memcpy(&stationConf.password, colon2, c2l);
|
||||
|
||||
wifi_set_opmode( 1 );
|
||||
wifi_station_set_config(&stationConf);
|
||||
wifi_station_connect();
|
||||
espconn_sent( pespconn, "W1\r\n", 4 );
|
||||
|
||||
printf( "Switching.\n" );
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
{
|
||||
wifi_set_opmode_current( 1 );
|
||||
wifi_set_opmode( 2 );
|
||||
espconn_sent( pespconn, "W2\r\n", 4 );
|
||||
}
|
||||
break;
|
||||
case 'I':
|
||||
{
|
||||
struct station_config sc;
|
||||
int mode = wifi_get_opmode();
|
||||
char buffer[200];
|
||||
char * buffend = &buffer[0];
|
||||
|
||||
buffend += ets_sprintf( buffend, "WI%d", mode );
|
||||
|
||||
wifi_station_get_config( &sc );
|
||||
|
||||
buffend += ets_sprintf( buffend, ":%s:%s", sc.ssid, sc.password );
|
||||
|
||||
espconn_sent( pespconn, buffer, buffend - buffer );
|
||||
}
|
||||
break;
|
||||
case 'S': case 's':
|
||||
{
|
||||
char buffer[1024];
|
||||
char * buffend = &buffer[0];
|
||||
int i, r;
|
||||
|
||||
scanplace = 0;
|
||||
|
||||
if( wifi_get_opmode() == SOFTAP_MODE )
|
||||
{
|
||||
wifi_set_opmode_current( STATION_MODE );
|
||||
need_to_switch_back_to_soft_ap = 1;
|
||||
r = wifi_station_scan(0, scandone );
|
||||
}
|
||||
else
|
||||
{
|
||||
r = wifi_station_scan(0, scandone );
|
||||
}
|
||||
|
||||
buffend += ets_sprintf( buffend, "WS%d\n", r );
|
||||
uart0_sendStr(buffer);
|
||||
|
||||
espconn_sent( pespconn, buffer, buffend - buffer );
|
||||
|
||||
}
|
||||
break;
|
||||
case 'R': case 'r':
|
||||
{
|
||||
char buffer[1024];
|
||||
char * buffend = &buffer[0];
|
||||
int i, r;
|
||||
|
||||
buffend += ets_sprintf( buffend, "WR%d\n", scanplace );
|
||||
|
||||
for( i = 0; i < scanplace; i++ )
|
||||
{
|
||||
buffend += ets_sprintf( buffend, "#%s\t%s\t%d\t%d\t%s\n",
|
||||
totalscan[i].name, totalscan[i].mac, totalscan[i].rssi, totalscan[i].channel, enctypes[totalscan[i].encryption] );
|
||||
}
|
||||
|
||||
espconn_sent( pespconn, buffer, buffend - buffer );
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR CSInit()
|
||||
{
|
||||
pUdpServer = (struct espconn *)os_zalloc(sizeof(struct espconn));
|
||||
ets_memset( pUdpServer, 0, sizeof( struct espconn ) );
|
||||
pUdpServer->type = ESPCONN_UDP;
|
||||
pUdpServer->proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp));
|
||||
pUdpServer->proto.udp->local_port = 7878;
|
||||
espconn_regist_recvcb(pUdpServer, issue_command);
|
||||
espconn_create( pUdpServer );
|
||||
|
||||
pHTTPServer = (struct espconn *)os_zalloc(sizeof(struct espconn));
|
||||
ets_memset( pHTTPServer, 0, sizeof( struct espconn ) );
|
||||
espconn_create( pHTTPServer );
|
||||
pHTTPServer->type = ESPCONN_TCP;
|
||||
pHTTPServer->state = ESPCONN_NONE;
|
||||
pHTTPServer->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
|
||||
pHTTPServer->proto.tcp->local_port = 80;
|
||||
espconn_regist_connectcb(pHTTPServer, httpserver_connectcb);
|
||||
espconn_accept(pHTTPServer);
|
||||
espconn_regist_time(pHTTPServer, 15, 0); //timeout
|
||||
|
||||
}
|
||||
|
||||
void CSTick( int slowtick )
|
||||
{
|
||||
static uint8_t tick_flag = 0;
|
||||
|
||||
if( slowtick )
|
||||
{
|
||||
tick_flag = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if( need_to_switch_back_to_soft_ap == 2 )
|
||||
{
|
||||
need_to_switch_back_to_soft_ap = 0;
|
||||
wifi_set_opmode_current( SOFTAP_MODE );
|
||||
}
|
||||
|
||||
HTTPTick(0);
|
||||
|
||||
//TRICKY! If we use the timer to initiate this, connecting to people's networks
|
||||
//won't work! I don't know why, so I do it here. this does mean sometimes it'll
|
||||
//pause, though.
|
||||
if( tick_flag )
|
||||
{
|
||||
tick_flag = 0;
|
||||
HTTPTick(1);
|
||||
}
|
||||
}
|
||||
|
18
embedded8266/common/commonservices.h
Normal file
18
embedded8266/common/commonservices.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#include "c_types.h"
|
||||
|
||||
//Includes UDP Control + HTTP Interfaces
|
||||
void ICACHE_FLASH_ATTR CSInit();
|
||||
void ICACHE_FLASH_ATTR CSTick( int slowtick );
|
||||
|
||||
//You must provide:
|
||||
void EnterCritical();
|
||||
void ExitCritical();
|
||||
|
||||
#endif
|
||||
|
92
embedded8266/common/esp8266_rom.h
Normal file
92
embedded8266/common/esp8266_rom.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
#ifndef _ESP8266_ROM_FUNCTS
|
||||
#define _ESP8266_ROM_FUNCTS
|
||||
|
||||
//This is my best guess at some of the ROM functions for the ESP8266.
|
||||
//I have no idea if this stuff is correct!
|
||||
|
||||
#include <spi_flash.h>
|
||||
#include <c_types.h>
|
||||
|
||||
void Cache_Read_Disable(); //Can't seem to operate...
|
||||
void Cache_Read_Enable();
|
||||
|
||||
//PROVIDE ( Cache_Read_Disable = 0x400047f0 );
|
||||
//PROVIDE ( Cache_Read_Enable = 0x40004678 );
|
||||
|
||||
typedef struct {
|
||||
uint32_t i[2];
|
||||
uint32_t buf[4];
|
||||
unsigned char in[64];
|
||||
unsigned char digest[16];
|
||||
} MD5_CTX;
|
||||
|
||||
void MD5Init ( MD5_CTX *mdContext);
|
||||
void MD5Update( MD5_CTX *mdContext, const unsigned char *inBuf, unsigned int inLen);
|
||||
void MD5Final ( unsigned char hash[], MD5_CTX *mdContext);
|
||||
|
||||
|
||||
//SHA Stuff from: https://github.com/pvvx/esp8266web/blob/master/app/include/bios/cha1.h
|
||||
#define SHA1_HASH_LEN 20
|
||||
typedef struct {
|
||||
uint32 state[5];
|
||||
uint32 count[2];
|
||||
uint8 buffer[64];
|
||||
uint8 extra[40];
|
||||
} SHA1_CTX;
|
||||
|
||||
void SHA1Init(SHA1_CTX* context);
|
||||
void SHA1Update(SHA1_CTX* context,
|
||||
const uint8 *data,
|
||||
size_t len);
|
||||
void SHA1Final(uint8 digest[SHA1_HASH_LEN], SHA1_CTX* context);
|
||||
void SHA1Transform(uint32 state[5], const uint8 buffer[64]);
|
||||
|
||||
|
||||
|
||||
//SPI_FLASH_SEC_SIZE 4096
|
||||
|
||||
void SPIEraseSector(uint16 sec); //Doesn't work?
|
||||
void SPIEraseArea(uint32 start,uint32 len); //Doesn't work?
|
||||
void SPIEraseBlock(uint16 blk);
|
||||
void SPIWrite(uint32 des_addr, uint32_t *src_addr, uint32_t size);
|
||||
void SPIRead(uint32 src_addr, uint32_t *des_addr, uint16_t size);
|
||||
void SPILock( uint16_t sec ); //??? I don't use this?
|
||||
void SPIUnlock( ); //??? I don't use this? -> Seems to crash.
|
||||
|
||||
extern SpiFlashChip * flashchip; //don't forget: flashchip->chip_size = 0x01000000;
|
||||
|
||||
|
||||
/*
|
||||
flashchip->chip_size = 0x01000000;
|
||||
|
||||
{
|
||||
uint32_t __attribute__ ((aligned (16))) t[1024];
|
||||
t[0] = 0xAABBCCDD;
|
||||
t[1] = 0xEEFF0011;
|
||||
for( i = 0; i < 10000; i++ ) uart0_sendStr("A\n");
|
||||
SPIEraseSector( 1000000/4096 );
|
||||
for( i = 0; i < 10000; i++ ) uart0_sendStr("B\n");
|
||||
SPIWrite( 1000000, t, 8 );
|
||||
}
|
||||
|
||||
for( i = 0; i < 10000; i++ ) uart0_sendStr("C\n");
|
||||
|
||||
while(1)
|
||||
{
|
||||
char ct[32];
|
||||
uint32_t __attribute__ ((aligned (16))) ret = 0x12345678;
|
||||
// SPIRead( 1000000, &ret, 4 );
|
||||
ret = *(uint32_t*)(0x40200000+1000004);
|
||||
ets_sprintf( ct, "%08x\n", ret );
|
||||
printf( ct );
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void software_reset();
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
292
embedded8266/common/flash_rewriter.c
Normal file
292
embedded8266/common/flash_rewriter.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#include "flash_rewriter.h"
|
||||
#include <c_types.h>
|
||||
#include <esp8266_rom.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SRCSIZE 4096
|
||||
|
||||
|
||||
static const char * key = "";
|
||||
static int keylen = 0;
|
||||
|
||||
void SafeMD5Update( MD5_CTX * md5ctx, uint8_t*from, uint32_t size1 )
|
||||
{
|
||||
char __attribute__ ((aligned (32))) buffer[32];
|
||||
|
||||
|
||||
while( size1 > 32 )
|
||||
{
|
||||
ets_memcpy( buffer, from, 32 );
|
||||
MD5Update( md5ctx, buffer, 32 );
|
||||
size1-=32;
|
||||
from+=32;
|
||||
}
|
||||
ets_memcpy( buffer, from, 32 );
|
||||
MD5Update( md5ctx, buffer, size1 );
|
||||
}
|
||||
|
||||
|
||||
static int MyRewriteFlash( char * command, int commandlen )
|
||||
{
|
||||
MD5_CTX md5ctx;
|
||||
char __attribute__ ((aligned (32))) buffer[512];
|
||||
char * colons[8];
|
||||
int i, ipl = 0;
|
||||
int p;
|
||||
//[from_address]:[to_address]:[size]:[MD5(key+data)]:[from_address]:[to_address]:[size]:[MD5(key+data)]
|
||||
command[commandlen] = 0;
|
||||
|
||||
flashchip->chip_size = 0x01000000;
|
||||
|
||||
ets_wdt_disable();
|
||||
|
||||
colons[ipl++] = &command[0];
|
||||
for( i = 0; i < commandlen; i++ )
|
||||
{
|
||||
if( command[i] == 0 ) break;
|
||||
if( command[i] == ':' )
|
||||
{
|
||||
if( ipl >= 8 ) break;
|
||||
command[i] = 0;
|
||||
colons[ipl++] = &command[i+1];
|
||||
}
|
||||
}
|
||||
if( ipl != 8 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
uint32_t from1 = my_atoi( colons[0] );
|
||||
uint32_t to1 = my_atoi( colons[1] );
|
||||
int32_t size1 = my_atoi( colons[2] );
|
||||
char * md51 = colons[3];
|
||||
char md5h1raw[48];
|
||||
char md5h1[48];
|
||||
uint32_t from2 = my_atoi( colons[4] );
|
||||
uint32_t to2 = my_atoi( colons[5] );
|
||||
int32_t size2 = my_atoi( colons[6] );
|
||||
char * md52 = colons[7];
|
||||
char md5h2raw[48];
|
||||
char md5h2[48];
|
||||
|
||||
if( from1 == 0 || from2 == 0 || size1 == 0 )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
if( ( from1 & 0xfff ) || ( from2 & 0xfff ) || ( to1 & 0xfff ) || ( to2 & 0xfff ) )
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
char st[400];
|
||||
/*
|
||||
ets_sprintf( st, "!!%08x", (((uint32_t*)(0x40200000 + from1))) );
|
||||
uart0_sendStr( st );
|
||||
|
||||
for( i = 0; i < 200; i++ )
|
||||
{
|
||||
ets_sprintf( st, "%08x", (uint32_t)(((uint32_t*)(0x40200000 + from1))[i]) );
|
||||
uart0_sendStr( st );
|
||||
}
|
||||
uart0_sendStr( "+\n" );
|
||||
|
||||
/*
|
||||
|
||||
|
||||
uint32_t __attribute__ ((aligned (32))) readr = 0xAAAAAAAA;
|
||||
SPIRead( from1, &readr, 4 );
|
||||
ets_sprintf( st, ":%08x\n", readr );
|
||||
uart0_sendStr( st );
|
||||
readr = 0x12345678;
|
||||
|
||||
SPIRead( from1+4, &readr, 4 );
|
||||
ets_sprintf( st, ":%08x\n", readr );
|
||||
uart0_sendStr( st );
|
||||
uart0_sendStr( "\n" );
|
||||
|
||||
ets_sprintf( st, "TT: %08x ADDY: %08x\n", from1, &readr );
|
||||
uart0_sendStr( st );
|
||||
|
||||
|
||||
|
||||
|
||||
readr = 0xAAAAAAAA;
|
||||
spi_flash_read( from1, &readr, 4 );
|
||||
ets_sprintf( st, "+%08x\n", readr );
|
||||
uart0_sendStr( st );
|
||||
|
||||
readr = 0xbbbbbbbb;
|
||||
spi_flash_read( from1+4, &readr, 4 );
|
||||
ets_sprintf( st, "+%08x\n", readr );
|
||||
uart0_sendStr( st );
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
MD5Init( &md5ctx );
|
||||
MD5Update( &md5ctx, (uint8_t*)0x40200000 + from1, 4 );
|
||||
MD5Final( md5h1raw, &md5ctx );
|
||||
for( i = 0; i < 16; i++ )
|
||||
{
|
||||
ets_sprintf( md5h1+i*2, "%02x", md5h1raw[i] );
|
||||
}
|
||||
uart0_sendStr( "Hash 1:" );
|
||||
uart0_sendStr( md5h1 );
|
||||
uart0_sendStr( "!\n" );
|
||||
*/
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
ets_sprintf( st, "Computing Hash 1: %08x size %d\n", from1, size1 );
|
||||
uart0_sendStr( st );
|
||||
|
||||
MD5Init( &md5ctx );
|
||||
if( keylen )
|
||||
MD5Update( &md5ctx, key, keylen );
|
||||
// MD5Update( &md5ctx, (uint8_t*)0x40200000 + from1, size1 );
|
||||
SafeMD5Update( &md5ctx, (uint8_t*)0x40200000 + from1, size1 );
|
||||
MD5Final( md5h1raw, &md5ctx );
|
||||
for( i = 0; i < 16; i++ )
|
||||
{
|
||||
ets_sprintf( md5h1+i*2, "%02x", md5h1raw[i] );
|
||||
}
|
||||
|
||||
uart0_sendStr( "Hash 1:" );
|
||||
uart0_sendStr( md5h1 );
|
||||
uart0_sendStr( "\n" );
|
||||
|
||||
for( i = 0; i < 32; i++ )
|
||||
{
|
||||
if( md5h1[i] != md51[i] )
|
||||
{
|
||||
//printf( "%s != %s", md5h1, md51 );
|
||||
uart0_sendStr( "File 1 MD5 mismatch\nActual:" );
|
||||
uart0_sendStr( md5h1 );
|
||||
uart0_sendStr( "\nExpected:" );
|
||||
uart0_sendStr( md51 );
|
||||
uart0_sendStr( "\n" );
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
ets_sprintf( st, "Computing Hash 2: %08x size %d\n", from2, size2 );
|
||||
uart0_sendStr( st );
|
||||
|
||||
MD5Init( &md5ctx );
|
||||
if( keylen )
|
||||
MD5Update( &md5ctx, key, keylen );
|
||||
SafeMD5Update( &md5ctx, (uint8_t*)0x40200000 + from2, size2 );
|
||||
MD5Final( md5h2raw, &md5ctx );
|
||||
for( i = 0; i < 16; i++ )
|
||||
{
|
||||
ets_sprintf( md5h2+i*2, "%02x", md5h2raw[i] );
|
||||
}
|
||||
|
||||
uart0_sendStr( "Hash 2:" );
|
||||
uart0_sendStr( md5h2 );
|
||||
uart0_sendStr( "\n" );
|
||||
|
||||
/* for( i = 0; i <= size2/4; i++ )
|
||||
{
|
||||
uint32_t j = ((uint32_t*)(0x40200000 + from2))[i];
|
||||
ets_sprintf( st, "%02x%02x%02x%02x\n", (uint8_t)(j>>0), (uint8_t)(j>>8), (uint8_t)(j>>16), (uint8_t)(j>>24) );
|
||||
uart0_sendStr( st );
|
||||
}*/
|
||||
|
||||
for( i = 0; i < 32; i++ )
|
||||
{
|
||||
if( md5h2[i] != md52[i] )
|
||||
{
|
||||
uart0_sendStr( "File 2 MD5 mismatch\nActual:" );
|
||||
uart0_sendStr( md5h2 );
|
||||
uart0_sendStr( "\nExpected:" );
|
||||
uart0_sendStr( md52 );
|
||||
uart0_sendStr( "\n" );
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
//Need to round sizes up.
|
||||
size1 = ((size1-1)&(~0xfff))+1;
|
||||
size2 = ((size2-1)&(~0xfff))+1;
|
||||
|
||||
ets_sprintf( st, "Copy 1: %08x to %08x, size %d\n", from1, to1, size1 );
|
||||
uart0_sendStr( st );
|
||||
ets_sprintf( st, "Copy 2: %08x to %08x, size %d\n", from2, to2, size2 );
|
||||
uart0_sendStr( st );
|
||||
|
||||
//Everything checked out... Need to move the flashes.
|
||||
|
||||
ets_delay_us( 1000 );
|
||||
|
||||
//Disable all interrupts.
|
||||
ets_intr_lock();
|
||||
|
||||
ipl = (size1/SRCSIZE)+1;
|
||||
p = to1/SRCSIZE;
|
||||
for( i = 0; i < ipl; i++ )
|
||||
{
|
||||
SPIEraseSector( p++ );
|
||||
SPIWrite( to1, (uint32_t*)(0x40200000 + from1), SRCSIZE );
|
||||
to1 += SRCSIZE;
|
||||
from1 += SRCSIZE;
|
||||
}
|
||||
|
||||
uart_tx_one_char( 'B' );
|
||||
|
||||
ipl = (size2/SRCSIZE)+1;
|
||||
p = to2/SRCSIZE;
|
||||
for( i = 0; i < ipl; i++ )
|
||||
{
|
||||
SPIEraseSector( p++ );
|
||||
SPIWrite( to2, (uint32_t*)(0x40200000 + from2), SRCSIZE );
|
||||
to2 += SRCSIZE;
|
||||
from2 += SRCSIZE;
|
||||
|
||||
}
|
||||
|
||||
uart_tx_one_char( 'R' );
|
||||
|
||||
|
||||
void(*rebootme)() = (void(*)())0x40000080;
|
||||
rebootme();
|
||||
|
||||
|
||||
// system_upgrade_reboot();
|
||||
// software_reset(); //Doesn't seem to boot back in.
|
||||
|
||||
|
||||
//Destinations are erased. Copy over the other part.
|
||||
// for( i = 0; i < ; i++ )
|
||||
|
||||
/*Things I know:
|
||||
flashchip->chip_size = 0x01000000;
|
||||
SPIEraseSector( 1000000/4096 );
|
||||
SPIWrite( 1000000, &t, 4 ); <<This looks right.
|
||||
SPIRead( 1000000, &t, 4 ); <<Will read if we just wrote, but not from cache.
|
||||
|
||||
uint32_t * v = (uint32_t*)(0x40200000 + 1000000); //This will read, but from cache.
|
||||
|
||||
//Looks like you can copy this way...
|
||||
// SPIWrite( 1000004, 0x40200000 + 1000000, 4 );
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
MD5Init( &c );
|
||||
MD5Update( &c, "apple", 5 );
|
||||
MD5Final( hash, &c );*/
|
||||
|
||||
|
||||
//Once we hit this stage we cannot do too much, otherwise we'll cause major crashing.
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
int (*GlobalRewriteFlash)( char * command, int commandlen ) = MyRewriteFlash;
|
20
embedded8266/common/flash_rewriter.h
Normal file
20
embedded8266/common/flash_rewriter.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#ifndef _FLASH_REWRITER_H
|
||||
#define _FLASH_REWRITER_H
|
||||
|
||||
//Unusual, but guarentees that the code resides in IRAM.
|
||||
/*
|
||||
Usage:
|
||||
[from_address]:[to_address]:[size]:[MD5(key+data)]:[from_address]:[to_address]:[size]:[MD5(key+data)][extra byte required]
|
||||
|
||||
NOTE: YOU MUST USE 4096-byte-aligned boundaries.
|
||||
|
||||
Note: this will modify the text in "command"
|
||||
*/
|
||||
|
||||
|
||||
extern int (*GlobalRewriteFlash)( char * command, int commandlen );
|
||||
|
||||
#endif
|
560
embedded8266/common/http.c
Normal file
560
embedded8266/common/http.c
Normal file
|
@ -0,0 +1,560 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#include "http.h"
|
||||
#include "mystuff.h"
|
||||
#include "esp8266_rom.h"
|
||||
|
||||
#define HTDEBUG( x... ) printf( x )
|
||||
|
||||
struct HTTPConnection HTTPConnections[HTTP_CONNECTIONS];
|
||||
struct HTTPConnection * curhttp;
|
||||
uint8 * curdata;
|
||||
uint16 curlen;
|
||||
|
||||
ICACHE_FLASH_ATTR void InternalStartHTTP( );
|
||||
ICACHE_FLASH_ATTR void HTTPHandleInternalCallback( );
|
||||
|
||||
ICACHE_FLASH_ATTR void HTTPClose( )
|
||||
{
|
||||
curhttp->state = HTTP_STATE_NONE;
|
||||
espconn_disconnect( curhttp->socket );
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR HTTPGotData( )
|
||||
{
|
||||
uint8 c;
|
||||
curhttp->timeout = 0;
|
||||
|
||||
while( curlen-- )
|
||||
{
|
||||
c = POP;
|
||||
// sendhex2( h->state ); sendchr( ' ' );
|
||||
|
||||
switch( curhttp->state )
|
||||
{
|
||||
case HTTP_STATE_WAIT_METHOD:
|
||||
if( c == ' ' )
|
||||
{
|
||||
curhttp->state = HTTP_STATE_WAIT_PATH;
|
||||
curhttp->state_deets = 0;
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_WAIT_PATH:
|
||||
curhttp->pathbuffer[curhttp->state_deets++] = c;
|
||||
if( curhttp->state_deets == MAX_PATHLEN )
|
||||
{
|
||||
curhttp->state_deets--;
|
||||
}
|
||||
|
||||
if( c == ' ' )
|
||||
{
|
||||
//Tricky: If we're a websocket, we need the whole header.
|
||||
curhttp->pathbuffer[curhttp->state_deets-1] = 0;
|
||||
curhttp->state_deets = 0;
|
||||
|
||||
if( strncmp( (const char*)curhttp->pathbuffer, "/d/ws", 5 ) == 0 )
|
||||
{
|
||||
curhttp->state = HTTP_STATE_DATA_WEBSOCKET;
|
||||
curhttp->state_deets = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
curhttp->state = HTTP_STATE_WAIT_PROTO;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_WAIT_PROTO:
|
||||
if( c == '\n' )
|
||||
{
|
||||
curhttp->state = HTTP_STATE_WAIT_FLAG;
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_WAIT_FLAG:
|
||||
if( c == '\n' )
|
||||
{
|
||||
curhttp->state = HTTP_STATE_DATA_XFER;
|
||||
InternalStartHTTP( );
|
||||
}
|
||||
else if( c != '\r' )
|
||||
{
|
||||
curhttp->state = HTTP_STATE_WAIT_INFLAG;
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_WAIT_INFLAG:
|
||||
if( c == '\n' )
|
||||
{
|
||||
curhttp->state = HTTP_STATE_WAIT_FLAG;
|
||||
curhttp->state_deets = 0;
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_DATA_XFER:
|
||||
//Ignore any further data?
|
||||
curlen = 0;
|
||||
break;
|
||||
case HTTP_STATE_DATA_WEBSOCKET:
|
||||
WebSocketGotData( c );
|
||||
break;
|
||||
case HTTP_WAIT_CLOSE:
|
||||
//printf( "__HTTPCLose1\n" );
|
||||
HTTPClose( );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void DoHTTP( uint8_t timed )
|
||||
{
|
||||
switch( curhttp->state )
|
||||
{
|
||||
case HTTP_STATE_NONE: //do nothing if no state.
|
||||
break;
|
||||
case HTTP_STATE_DATA_XFER:
|
||||
if( TCPCanSend( curhttp->socket, 1024 ) ) //TCPDoneSend
|
||||
{
|
||||
if( curhttp->is_dynamic )
|
||||
{
|
||||
HTTPCustomCallback( );
|
||||
}
|
||||
else
|
||||
{
|
||||
HTTPHandleInternalCallback( );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HTTP_WAIT_CLOSE:
|
||||
if( TCPDoneSend( curhttp->socket ) )
|
||||
{
|
||||
//printf( "HTTPCLose2\n");
|
||||
HTTPClose( );
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_DATA_WEBSOCKET:
|
||||
if( TCPCanSend( curhttp->socket, 1024 ) ) //TCPDoneSend
|
||||
{
|
||||
WebSocketTickInternal();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if( timed )
|
||||
{
|
||||
if( curhttp->timeout++ > HTTP_SERVER_TIMEOUT )
|
||||
{
|
||||
//printf( "HTTPClose3\n" );
|
||||
HTTPClose( );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPTick( uint8_t timed )
|
||||
{
|
||||
uint8_t i;
|
||||
for( i = 0; i < HTTP_CONNECTIONS; i++ )
|
||||
{
|
||||
curhttp = &HTTPConnections[i];
|
||||
DoHTTP( timed );
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR HTTPHandleInternalCallback( )
|
||||
{
|
||||
uint16_t i, bytestoread;
|
||||
|
||||
if( curhttp->isdone )
|
||||
{
|
||||
HTTPClose( );
|
||||
return;
|
||||
}
|
||||
if( curhttp->is404 )
|
||||
{
|
||||
START_PACK
|
||||
PushString("HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\nFile not found.");
|
||||
EndTCPWrite( curhttp->socket );
|
||||
curhttp->isdone = 1;
|
||||
return;
|
||||
}
|
||||
if( curhttp->isfirst )
|
||||
{
|
||||
char stto[10];
|
||||
uint8_t slen = os_strlen( curhttp->pathbuffer );
|
||||
const char * k;
|
||||
|
||||
START_PACK;
|
||||
//TODO: Content Length? MIME-Type?
|
||||
PushString("HTTP/1.1 200 Ok\r\nConnection: close");
|
||||
|
||||
if( curhttp->bytesleft < 0xfffffffe )
|
||||
{
|
||||
PushString("\r\nContent-Length: ");
|
||||
Uint32To10Str( stto, curhttp->bytesleft );
|
||||
PushBlob( stto, os_strlen( stto ) );
|
||||
}
|
||||
PushString( "\r\nContent-Type: " );
|
||||
//Content-Type?
|
||||
while( slen && ( curhttp->pathbuffer[--slen] != '.' ) );
|
||||
k = &curhttp->pathbuffer[slen+1];
|
||||
if( strcmp( k, "mp3" ) == 0 )
|
||||
{
|
||||
PushString( "audio/mpeg3" );
|
||||
}
|
||||
else if( curhttp->bytesleft == 0xfffffffe )
|
||||
{
|
||||
PushString( "text/plain" );
|
||||
}
|
||||
else
|
||||
{
|
||||
PushString( "text/html" );
|
||||
}
|
||||
|
||||
PushString( "\r\n\r\n" );
|
||||
EndTCPWrite( curhttp->socket );
|
||||
curhttp->isfirst = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
START_PACK
|
||||
|
||||
for( i = 0; i < 4 && curhttp->bytesleft; i++ )
|
||||
{
|
||||
int bpt = curhttp->bytesleft;
|
||||
if( bpt > MFS_SECTOR ) bpt = MFS_SECTOR;
|
||||
curhttp->bytesleft = MFSReadSector( generic_ptr, &curhttp->data.filedescriptor );
|
||||
generic_ptr += bpt;
|
||||
}
|
||||
|
||||
EndTCPWrite( curhttp->socket );
|
||||
|
||||
if( !curhttp->bytesleft )
|
||||
curhttp->isdone = 1;
|
||||
}
|
||||
|
||||
void InternalStartHTTP( )
|
||||
{
|
||||
int32_t clusterno;
|
||||
int8_t i;
|
||||
const char * path = &curhttp->pathbuffer[0];
|
||||
|
||||
if( curhttp->pathbuffer[0] == '/' )
|
||||
path++;
|
||||
|
||||
if( path[0] == 'd' && path[1] == '/' )
|
||||
{
|
||||
curhttp->is_dynamic = 1;
|
||||
curhttp->isfirst = 1;
|
||||
curhttp->isdone = 0;
|
||||
curhttp->is404 = 0;
|
||||
HTTPCustomStart();
|
||||
return;
|
||||
}
|
||||
|
||||
if( !path[0] )
|
||||
{
|
||||
path = "index.html";
|
||||
}
|
||||
|
||||
i = MFSOpenFile( path, &curhttp->data.filedescriptor );
|
||||
curhttp->bytessofar = 0;
|
||||
|
||||
if( i < 0 )
|
||||
{
|
||||
HTDEBUG( "404(%s)\n", path );
|
||||
curhttp->is404 = 1;
|
||||
curhttp->isfirst = 1;
|
||||
curhttp->isdone = 0;
|
||||
curhttp->is_dynamic = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
curhttp->isfirst = 1;
|
||||
curhttp->isdone = 0;
|
||||
curhttp->is404 = 0;
|
||||
curhttp->is_dynamic = 0;
|
||||
curhttp->bytesleft = curhttp->data.filedescriptor.filelen;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
LOCAL void ICACHE_FLASH_ATTR
|
||||
http_disconnetcb(void *arg) {
|
||||
struct espconn *pespconn = (struct espconn *) arg;
|
||||
curhttp = (struct HTTPConnection * )pespconn->reverse;
|
||||
curhttp->state = 0;
|
||||
}
|
||||
|
||||
LOCAL void ICACHE_FLASH_ATTR
|
||||
http_recvcb(void *arg, char *pusrdata, unsigned short length)
|
||||
{
|
||||
struct espconn *pespconn = (struct espconn *) arg;
|
||||
|
||||
ets_intr_lock();
|
||||
curhttp = (struct HTTPConnection * )pespconn->reverse;
|
||||
curdata = (uint8*)pusrdata;
|
||||
curlen = length;
|
||||
HTTPGotData();
|
||||
ets_intr_unlock();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
httpserver_connectcb(void *arg)
|
||||
{
|
||||
int i;
|
||||
struct espconn *pespconn = (struct espconn *)arg;
|
||||
|
||||
for( i = 0; i < HTTP_CONNECTIONS; i++ )
|
||||
{
|
||||
if( HTTPConnections[i].state == 0 )
|
||||
{
|
||||
pespconn->reverse = &HTTPConnections[i];
|
||||
HTTPConnections[i].socket = pespconn;
|
||||
HTTPConnections[i].state = HTTP_STATE_WAIT_METHOD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i == HTTP_CONNECTIONS )
|
||||
{
|
||||
espconn_disconnect( pespconn );
|
||||
return;
|
||||
}
|
||||
|
||||
// espconn_set_opt(pespconn, ESPCONN_NODELAY);
|
||||
// espconn_set_opt(pespconn, ESPCONN_COPY);
|
||||
|
||||
espconn_regist_recvcb( pespconn, http_recvcb );
|
||||
espconn_regist_disconcb( pespconn, http_disconnetcb );
|
||||
|
||||
}
|
||||
|
||||
|
||||
int ICACHE_FLASH_ATTR URLDecode( char * decodeinto, int maxlen, const char * buf )
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for( ; buf && *buf; buf++ )
|
||||
{
|
||||
char c = *buf;
|
||||
if( c == '+' )
|
||||
{
|
||||
decodeinto[i++] = ' ';
|
||||
}
|
||||
else if( c == '?' || c == '&' )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if( c == '%' )
|
||||
{
|
||||
if( *(buf+1) && *(buf+2) )
|
||||
{
|
||||
decodeinto[i++] = hex2byte( buf+1 );
|
||||
buf += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
decodeinto[i++] = c;
|
||||
}
|
||||
if( i >= maxlen -1 ) break;
|
||||
|
||||
}
|
||||
decodeinto[i] = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR WebSocketGotData( uint8_t c )
|
||||
{
|
||||
switch( curhttp->state_deets )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
int i = 0;
|
||||
char inkey[120];
|
||||
unsigned char hash[SHA1_HASH_LEN];
|
||||
SHA1_CTX c;
|
||||
int inkeylen = 0;
|
||||
|
||||
curhttp->is_dynamic = 1;
|
||||
while( curlen > 20 )
|
||||
{
|
||||
curdata++; curlen--;
|
||||
if( strncmp( curdata, "Sec-WebSocket-Key: ", 19 ) == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( curlen <= 21 )
|
||||
{
|
||||
HTDEBUG( "No websocket key found.\n" );
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
return;
|
||||
}
|
||||
|
||||
curdata+= 19;
|
||||
curlen -= 19;
|
||||
|
||||
|
||||
#define WS_KEY_LEN 36
|
||||
#define WS_KEY "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
|
||||
while( curlen > 1 )
|
||||
{
|
||||
uint8_t lc = *(curdata++);
|
||||
inkey[i] = lc;
|
||||
curlen--;
|
||||
if( lc == '\r' )
|
||||
{
|
||||
inkey[i] = 0;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
if( i >= sizeof( inkey ) - WS_KEY_LEN - 5 )
|
||||
{
|
||||
HTDEBUG( "Websocket key too big.\n" );
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if( curlen <= 1 )
|
||||
{
|
||||
HTDEBUG( "Invalid websocket key found.\n" );
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if( i + WS_KEY_LEN + 1 >= sizeof( inkey ) )
|
||||
{
|
||||
HTDEBUG( "WSKEY Too Big.\n" );
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
return;
|
||||
}
|
||||
|
||||
ets_memcpy( &inkey[i], WS_KEY, WS_KEY_LEN + 1 );
|
||||
i += WS_KEY_LEN;
|
||||
SHA1_Init( &c );
|
||||
SHA1_Update( &c, inkey, i );
|
||||
SHA1_Final( hash, &c );
|
||||
|
||||
if( SHA1_HASH_LEN * 2 > MAX_PATHLEN )
|
||||
{
|
||||
HTDEBUG( "Pathlen too short.\n" );
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
return;
|
||||
}
|
||||
|
||||
my_base64_encode( hash, SHA1_HASH_LEN, curhttp->pathbuffer );
|
||||
|
||||
//Respond...
|
||||
curhttp->state_deets = 1;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
if( c == '\n' ) curhttp->state_deets = 2;
|
||||
break;
|
||||
case 2:
|
||||
if( c == '\r' ) curhttp->state_deets = 3;
|
||||
else curhttp->state_deets = 1;
|
||||
break;
|
||||
case 3:
|
||||
if( c == '\n' ) curhttp->state_deets = 4;
|
||||
else curhttp->state_deets = 1;
|
||||
break;
|
||||
case 5: //Established connection.
|
||||
{
|
||||
if( curlen < 5 ) //Can't interpret packet.
|
||||
break;
|
||||
|
||||
uint8_t fin = c & 1;
|
||||
uint8_t opcode = c << 4;
|
||||
uint32_t payloadlen = *(curdata++);
|
||||
curlen--;
|
||||
if( !(payloadlen & 0x80) )
|
||||
{
|
||||
HTDEBUG( "Unmasked packet.\n" );
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if( payloadlen == 127 )
|
||||
{
|
||||
//Very long payload.
|
||||
//Not supported.
|
||||
HTDEBUG( "Unsupported payload packet.\n" );
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
break;
|
||||
}
|
||||
else if( payloadlen == 126 )
|
||||
{
|
||||
payloadlen = (curdata[0] << 8) | curdata[1];
|
||||
curdata += 2;
|
||||
curlen -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
payloadlen &= 0x7f;
|
||||
}
|
||||
WebSocketData( curdata, payloadlen );
|
||||
curlen -= payloadlen;
|
||||
curdata += payloadlen;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR WebSocketTickInternal()
|
||||
{
|
||||
switch( curhttp->state_deets )
|
||||
{
|
||||
case 4: //Has key full HTTP header, etc. wants response.
|
||||
START_PACK;
|
||||
PushString( "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: " );
|
||||
PushString( curhttp->pathbuffer );
|
||||
PushString( "\r\n\r\n" );
|
||||
EndTCPWrite( curhttp->socket );
|
||||
curhttp->state_deets = 5;
|
||||
curhttp->bytessofar = 0;
|
||||
curhttp->bytesleft = 0;
|
||||
NewWebSocket();
|
||||
break;
|
||||
case 5:
|
||||
WebSocketTick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR WebSocketSend( uint8_t * data, int size )
|
||||
{
|
||||
START_PACK;
|
||||
PushByte( 0x81 );
|
||||
if( size > 126 )
|
||||
{
|
||||
PushByte( 0x00 | 126 );
|
||||
PushByte( size>>8 );
|
||||
PushByte( size&0xff );
|
||||
}
|
||||
else
|
||||
{
|
||||
PushByte( 0x00 | size );
|
||||
}
|
||||
PushBlob( data, size );
|
||||
EndTCPWrite( curhttp->socket );
|
||||
}
|
||||
|
||||
|
91
embedded8266/common/http.h
Normal file
91
embedded8266/common/http.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#ifndef _HTTP_H
|
||||
#define _HTTP_H
|
||||
|
||||
#include "mem.h"
|
||||
#include "c_types.h"
|
||||
#include "user_interface.h"
|
||||
#include "ets_sys.h"
|
||||
#include "driver/uart.h"
|
||||
#include "osapi.h"
|
||||
#include "espconn.h"
|
||||
#include "mfs.h"
|
||||
#include "mystuff.h"
|
||||
|
||||
#define HTTP_SERVER_TIMEOUT 500
|
||||
#define HTTP_CONNECTIONS 8
|
||||
#define MAX_PATHLEN 80
|
||||
|
||||
//You must provide:
|
||||
void ICACHE_FLASH_ATTR HTTPCustomStart( );
|
||||
void ICACHE_FLASH_ATTR HTTPCustomCallback( ); //called when we can send more data
|
||||
|
||||
void ICACHE_FLASH_ATTR WebSocketData( uint8_t * data, int len );
|
||||
void ICACHE_FLASH_ATTR WebSocketTick( );
|
||||
void ICACHE_FLASH_ATTR WebSocketNew();
|
||||
|
||||
extern struct HTTPConnection * curhttp;
|
||||
extern uint8 * curdata;
|
||||
extern uint16 curlen;
|
||||
|
||||
#define POP (*curdata++)
|
||||
|
||||
#define HTTP_STATE_NONE 0
|
||||
#define HTTP_STATE_WAIT_METHOD 1
|
||||
#define HTTP_STATE_WAIT_PATH 2
|
||||
#define HTTP_STATE_WAIT_PROTO 3
|
||||
|
||||
#define HTTP_STATE_WAIT_FLAG 4
|
||||
#define HTTP_STATE_WAIT_INFLAG 5
|
||||
#define HTTP_STATE_DATA_XFER 7
|
||||
#define HTTP_STATE_DATA_WEBSOCKET 8
|
||||
|
||||
#define HTTP_WAIT_CLOSE 15
|
||||
|
||||
|
||||
struct HTTPConnection
|
||||
{
|
||||
uint8_t state:4;
|
||||
uint8_t state_deets;
|
||||
uint8_t pathbuffer[MAX_PATHLEN]; //Also used for temporary and handshake information when using websockets.
|
||||
uint8_t is_dynamic:1;
|
||||
uint16_t timeout;
|
||||
|
||||
union data_t
|
||||
{
|
||||
struct MFSFileInfo filedescriptor;
|
||||
struct UserData { uint16_t a, b, c; } user;
|
||||
} data;
|
||||
|
||||
void * rcb;
|
||||
|
||||
uint32_t bytesleft;
|
||||
uint32_t bytessofar;
|
||||
|
||||
uint8_t is404:1;
|
||||
uint8_t isdone:1;
|
||||
uint8_t isfirst:1;
|
||||
uint8_t need_resend:1;
|
||||
|
||||
struct espconn * socket;
|
||||
} HTTPConnections[HTTP_CONNECTIONS];
|
||||
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR httpserver_connectcb(void *arg);
|
||||
|
||||
void HTTPTick( uint8_t timedtick );
|
||||
//you can call this a LOT if you want fast transfers, but be sure only to call it with a 1 at the update tick rate.
|
||||
|
||||
int ICACHE_FLASH_ATTR URLDecode( char * decodeinto, int maxlen, const char * buf );
|
||||
|
||||
void ICACHE_FLASH_ATTR WebSocketGotData( uint8_t c );
|
||||
void ICACHE_FLASH_ATTR WebSocketTickInternal();
|
||||
|
||||
void ICACHE_FLASH_ATTR WebSocketSend( uint8_t * data, int size );
|
||||
|
||||
|
||||
#endif
|
||||
|
97
embedded8266/common/http_custom.c
Normal file
97
embedded8266/common/http_custom.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#include "http.h"
|
||||
#include "mystuff.h"
|
||||
#include "commonservices.h"
|
||||
|
||||
static ICACHE_FLASH_ATTR void huge()
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
START_PACK;
|
||||
do
|
||||
{
|
||||
PushByte( 0 );
|
||||
PushByte( i );
|
||||
} while( ++i ); //Tricky: this will roll-over to 0, and thus only execute 256 times.
|
||||
|
||||
EndTCPWrite( curhttp->socket );
|
||||
}
|
||||
|
||||
|
||||
static ICACHE_FLASH_ATTR void echo()
|
||||
{
|
||||
char mydat[128];
|
||||
int len = URLDecode( mydat, 128, curhttp->pathbuffer+8 );
|
||||
|
||||
START_PACK;
|
||||
PushBlob( mydat, len );
|
||||
EndTCPWrite( curhttp->socket );
|
||||
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
}
|
||||
|
||||
static ICACHE_FLASH_ATTR void issue()
|
||||
{
|
||||
char mydat[512];
|
||||
int len = URLDecode( mydat, 512, curhttp->pathbuffer+9 );
|
||||
|
||||
issue_command(curhttp->socket, mydat, len );
|
||||
|
||||
curhttp->state = HTTP_WAIT_CLOSE;
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR HTTPCustomStart( )
|
||||
{
|
||||
if( strncmp( (const char*)curhttp->pathbuffer, "/d/huge", 7 ) == 0 )
|
||||
{
|
||||
curhttp->rcb = (void(*)())&huge;
|
||||
curhttp->bytesleft = 0xffffffff;
|
||||
}
|
||||
else
|
||||
if( strncmp( (const char*)curhttp->pathbuffer, "/d/echo?", 8 ) == 0 )
|
||||
{
|
||||
curhttp->rcb = (void(*)())&echo;
|
||||
curhttp->bytesleft = 0xfffffffe;
|
||||
}
|
||||
else
|
||||
if( strncmp( (const char*)curhttp->pathbuffer, "/d/issue?", 9 ) == 0 )
|
||||
{
|
||||
curhttp->rcb = (void(*)())&issue;
|
||||
curhttp->bytesleft = 0xfffffffe;
|
||||
}
|
||||
else
|
||||
{
|
||||
curhttp->rcb = 0;
|
||||
curhttp->bytesleft = 0;
|
||||
}
|
||||
curhttp->isfirst = 1;
|
||||
HTTPHandleInternalCallback();
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR HTTPCustomCallback( )
|
||||
{
|
||||
if( curhttp->rcb )
|
||||
((void(*)())curhttp->rcb)();
|
||||
else
|
||||
curhttp->isdone = 1;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR WebSocketTick()
|
||||
{
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR WebSocketData( uint8_t * data, int len )
|
||||
{
|
||||
char stout[128];
|
||||
int stl = ets_sprintf( stout, "output.innerHTML = %d; doSend('x' );\n", curhttp->bytessofar++ );
|
||||
WebSocketSend( stout, stl );
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR NewWebSocket()
|
||||
{
|
||||
}
|
||||
|
64
embedded8266/common/mfs.c
Normal file
64
embedded8266/common/mfs.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#include "mystuff.h"
|
||||
#include "mfs.h"
|
||||
#include "spi_flash.h"
|
||||
#include "ets_sys.h"
|
||||
|
||||
extern SpiFlashChip * flashchip;
|
||||
|
||||
//Returns 0 on succses.
|
||||
//Returns size of file if non-empty
|
||||
//If positive, populates mfi.
|
||||
//Returns -1 if can't find file or reached end of file list.
|
||||
int8_t MFSOpenFile( const char * fname, struct MFSFileInfo * mfi )
|
||||
{
|
||||
EnterCritical();
|
||||
flashchip->chip_size = 0x01000000;
|
||||
uint32 ptr = MFS_START;
|
||||
struct MFSFileEntry e;
|
||||
while(1)
|
||||
{
|
||||
spi_flash_read( ptr, (uint32*)&e, sizeof( e ) );
|
||||
ptr += sizeof(e);
|
||||
if( e.name[0] == 0xff || ets_strlen( e.name ) == 0 ) break;
|
||||
|
||||
if( ets_strcmp( e.name, fname ) == 0 )
|
||||
{
|
||||
mfi->offset = e.start;
|
||||
mfi->filelen = e.len;
|
||||
flashchip->chip_size = 0x00080000;
|
||||
ExitCritical();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
flashchip->chip_size = 0x00080000;
|
||||
ExitCritical();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t MFSReadSector( uint8_t* data, struct MFSFileInfo * mfi )
|
||||
{
|
||||
//returns # of bytes left tin file.
|
||||
if( !mfi->filelen )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toread = mfi->filelen;
|
||||
if( toread > MFS_SECTOR ) toread = MFS_SECTOR;
|
||||
|
||||
EnterCritical();
|
||||
flashchip->chip_size = 0x01000000;
|
||||
spi_flash_read( MFS_START+mfi->offset, (uint32*)data, MFS_SECTOR );
|
||||
flashchip->chip_size = 0x00080000;
|
||||
ExitCritical();
|
||||
|
||||
mfi->offset += toread;
|
||||
mfi->filelen -= toread;
|
||||
return mfi->filelen;
|
||||
}
|
||||
|
||||
|
||||
|
51
embedded8266/common/mfs.h
Normal file
51
embedded8266/common/mfs.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
//Not to be confused with MFS for the AVR.
|
||||
|
||||
#ifndef _MFS_H
|
||||
#define _MFS_H
|
||||
|
||||
#include "mem.h"
|
||||
#include "c_types.h"
|
||||
#include "mystuff.h"
|
||||
|
||||
//SPI_FLASH_SEC_SIZE 4096
|
||||
#define MFS_STARTFLASHSECTOR 0x100
|
||||
#define MFS_START (MFS_STARTFLASHSECTOR*SPI_FLASH_SEC_SIZE)
|
||||
#define MFS_SECTOR 256
|
||||
|
||||
|
||||
#define MFS_FILENAMELEN 32-8
|
||||
|
||||
//Format:
|
||||
// [FILE NAME (24)] [Start (4)] [Len (4)]
|
||||
// NOTE: Filename must be null-terminated within the 24.
|
||||
struct MFSFileEntry
|
||||
{
|
||||
char name[MFS_FILENAMELEN];
|
||||
uint32 start; //From beginning of mfs thing.
|
||||
uint32 len;
|
||||
};
|
||||
|
||||
|
||||
struct MFSFileInfo
|
||||
{
|
||||
uint32 offset;
|
||||
uint32 filelen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//Returns 0 on succses.
|
||||
//Returns size of file if non-empty
|
||||
//If positive, populates mfi.
|
||||
//Returns -1 if can't find file or reached end of file list.
|
||||
ICACHE_FLASH_ATTR int8_t MFSOpenFile( const char * fname, struct MFSFileInfo * mfi );
|
||||
ICACHE_FLASH_ATTR int32_t MFSReadSector( uint8_t* data, struct MFSFileInfo * mfi ); //returns # of bytes left in file.
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
169
embedded8266/common/mystuff.c
Normal file
169
embedded8266/common/mystuff.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
//Unless what else is individually marked, all code in this file is
|
||||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#include "mystuff.h"
|
||||
|
||||
const char * enctypes[6] = { "open", "wep", "wpa", "wpa2", "wpa_wpa2", "max" };
|
||||
|
||||
char generic_print_buffer[384];
|
||||
char generic_buffer[1500];
|
||||
char * generic_ptr;
|
||||
|
||||
int32 my_atoi( const char * in )
|
||||
{
|
||||
int positive = 1; //1 if negative.
|
||||
int hit = 0;
|
||||
int val = 0;
|
||||
while( *in && hit < 11 )
|
||||
{
|
||||
if( *in == '-' )
|
||||
{
|
||||
if( positive == -1 ) return val*positive;
|
||||
positive = -1;
|
||||
} else if( *in >= '0' && *in <= '9' )
|
||||
{
|
||||
val *= 10;
|
||||
val += *in - '0';
|
||||
hit++;
|
||||
} else if (!hit && ( *in == ' ' || *in == '\t' ) )
|
||||
{
|
||||
//okay
|
||||
} else
|
||||
{
|
||||
//bad.
|
||||
return val*positive;
|
||||
}
|
||||
in++;
|
||||
}
|
||||
return val*positive;
|
||||
}
|
||||
|
||||
void Uint32To10Str( char * out, uint32 dat )
|
||||
{
|
||||
int tens = 1000000000;
|
||||
int val;
|
||||
int place = 0;
|
||||
|
||||
while( tens > 1 )
|
||||
{
|
||||
if( dat/tens ) break;
|
||||
tens/=10;
|
||||
}
|
||||
|
||||
while( tens )
|
||||
{
|
||||
val = dat/tens;
|
||||
dat -= val*tens;
|
||||
tens /= 10;
|
||||
out[place++] = val + '0';
|
||||
}
|
||||
|
||||
out[place] = 0;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR EndTCPWrite( struct espconn * conn )
|
||||
{
|
||||
if(generic_ptr!=generic_buffer)
|
||||
espconn_sent(conn,generic_buffer,generic_ptr-generic_buffer);
|
||||
}
|
||||
|
||||
|
||||
void PushString( const char * buffer )
|
||||
{
|
||||
char c;
|
||||
while( c = *(buffer++) )
|
||||
PushByte( c );
|
||||
}
|
||||
|
||||
void PushBlob( const uint8 * buffer, int len )
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < len; i++ )
|
||||
PushByte( buffer[i] );
|
||||
}
|
||||
|
||||
|
||||
int8_t TCPCanSend( struct espconn * conn, int size )
|
||||
{
|
||||
struct espconn_packet infoarg;
|
||||
sint8 r = espconn_get_packet_info(conn, &infoarg);
|
||||
|
||||
if( infoarg.snd_buf_size >= size && infoarg.snd_queuelen > 0 )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ICACHE_FLASH_ATTR TCPDoneSend( struct espconn * conn )
|
||||
{
|
||||
return conn->state == ESPCONN_CONNECT;
|
||||
}
|
||||
|
||||
const char * ICACHE_FLASH_ATTR my_strchr( const char * st, char c )
|
||||
{
|
||||
while( *st && *st != c ) st++;
|
||||
if( !*st ) return 0;
|
||||
return st;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR ColonsToInts( const char * str, int32_t * vals, int max_quantity )
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < max_quantity; i++ )
|
||||
{
|
||||
const char * colon = my_strchr( str, ':' );
|
||||
vals[i] = my_atoi( str );
|
||||
if( !colon ) break;
|
||||
str = colon+1;
|
||||
}
|
||||
return i+1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//from http://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c
|
||||
static const char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'};
|
||||
|
||||
static const int mod_table[] = {0, 2, 1};
|
||||
|
||||
void ICACHE_FLASH_ATTR my_base64_encode(const unsigned char *data, size_t input_length, uint8_t * encoded_data )
|
||||
{
|
||||
|
||||
int i, j;
|
||||
int output_length = 4 * ((input_length + 2) / 3);
|
||||
|
||||
if( !encoded_data ) return;
|
||||
if( !data ) { encoded_data[0] = '='; encoded_data[1] = 0; return; }
|
||||
|
||||
for (i = 0, j = 0; i < input_length; ) {
|
||||
|
||||
uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
|
||||
uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
|
||||
uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
|
||||
|
||||
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
|
||||
|
||||
encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
|
||||
encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
|
||||
encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
|
||||
encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
|
||||
}
|
||||
|
||||
for (i = 0; i < mod_table[input_length % 3]; i++)
|
||||
encoded_data[output_length - 1 - i] = '=';
|
||||
|
||||
encoded_data[j] = 0;
|
||||
}
|
||||
|
43
embedded8266/common/mystuff.h
Normal file
43
embedded8266/common/mystuff.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
//Unless what else is individually marked, all code in this file is
|
||||
//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or
|
||||
// ColorChord License. You Choose.
|
||||
|
||||
#ifndef _MYSTUFF_H
|
||||
#define _MYSTUFF_H
|
||||
|
||||
#include <mem.h>
|
||||
#include <c_types.h>
|
||||
#include <user_interface.h>
|
||||
#include <ets_sys.h>
|
||||
#include <espconn.h>
|
||||
|
||||
extern char generic_print_buffer[384];
|
||||
|
||||
extern const char * enctypes[6];// = { "open", "wep", "wpa", "wpa2", "wpa_wpa2", "max" };
|
||||
|
||||
#define printf( ... ) ets_sprintf( generic_print_buffer, __VA_ARGS__ ); uart0_sendStr( generic_print_buffer );
|
||||
|
||||
int32 my_atoi( const char * in );
|
||||
void Uint32To10Str( char * out, uint32 dat );
|
||||
|
||||
//For holding TX packet buffers
|
||||
extern char generic_buffer[1500];
|
||||
extern char * generic_ptr;
|
||||
int8_t ICACHE_FLASH_ATTR TCPCanSend( struct espconn * conn, int size );
|
||||
int8_t ICACHE_FLASH_ATTR TCPDoneSend( struct espconn * conn );
|
||||
void ICACHE_FLASH_ATTR EndTCPWrite( struct espconn * conn );
|
||||
|
||||
#define PushByte( c ) { *(generic_ptr++) = c; }
|
||||
|
||||
void PushString( const char * buffer );
|
||||
void PushBlob( const uint8 * buffer, int len );
|
||||
#define START_PACK {generic_ptr=generic_buffer;}
|
||||
#define PACK_LENGTH (generic_ptr-&generic_buffer[0]}
|
||||
|
||||
int ICACHE_FLASH_ATTR ColonsToInts( const char * str, int32_t * vals, int max_quantity );
|
||||
|
||||
//As much as it pains me, we shouldn't be using the esp8266's base64_encode() function
|
||||
//as it does stuff with dynamic memory.
|
||||
void ICACHE_FLASH_ATTR my_base64_encode(const unsigned char *data, size_t input_length, uint8_t * encoded_data );
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue