Update ESP8266 version

This commit is contained in:
cnlohr 2015-07-29 01:54:49 -04:00
parent 102219f9a7
commit ff2cd22d9a
42 changed files with 3035 additions and 213 deletions

View 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);
}
}

View 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

View 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

View 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;

View 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
View 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 );
}

View 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

View 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
View 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
View 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

View 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;
}

View 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