diff --git a/embedded8266/Makefile b/embedded8266/Makefile index d574ae0..cd99278 100644 --- a/embedded8266/Makefile +++ b/embedded8266/Makefile @@ -13,6 +13,7 @@ SRCS:=driver/uart.c \ common/mfs.c \ user/ws2812_i2s.c \ user/hpatimer.c \ + user/custom_commands.c \ driver/adc.c \ ../embeddedcommon/DFT32.c \ ../embeddedcommon/embeddednf.c \ diff --git a/embedded8266/ccconfig.h b/embedded8266/ccconfig.h index cf0c2de..31a4a64 100644 --- a/embedded8266/ccconfig.h +++ b/embedded8266/ccconfig.h @@ -1,13 +1,63 @@ #ifndef _CCCONFIG_H #define _CCCONFIG_H +#include "c_types.h" + +#define HPABUFFSIZE 512 + #define CCEMBEDDED -#define NUM_LIN_LEDS 24 -#define USE_NUM_LIN_LEDS 24 +#define NUM_LIN_LEDS 255 #define DFREQ 16000 #define memcpy ets_memcpy #define memset ets_memset +extern uint8_t gDFTIIR; //=6 +#define DFTIIR gDFTIIR + +extern uint8_t gFUZZ_IIR_BITS; //=1 +#define FUZZ_IIR_BITS gFUZZ_IIR_BITS + +#define MAXNOTES 12 //MAXNOTES cannot be changed dynamically. + +extern uint8_t gFILTER_BLUR_PASSES; //=2 +#define FILTER_BLUR_PASSES gFILTER_BLUR_PASSES + +extern uint8_t gSEMIBITSPERBIN; //=3 +#define SEMIBITSPERBIN gSEMIBITSPERBIN + +extern uint8_t gMAX_JUMP_DISTANCE; //=4 +#define MAX_JUMP_DISTANCE gMAX_JUMP_DISTANCE + +extern uint8_t gMAX_COMBINE_DISTANCE; //=7 +#define MAX_COMBINE_DISTANCE gMAX_COMBINE_DISTANCE + +extern uint8_t gAMP_1_IIR_BITS; //=4 +#define AMP_1_IIR_BITS gAMP_1_IIR_BITS + +extern uint8_t gAMP_2_IIR_BITS; //=2 +#define AMP_2_IIR_BITS gAMP_2_IIR_BITS + +extern uint8_t gMIN_AMP_FOR_NOTE; //=80 +#define MIN_AMP_FOR_NOTE gMIN_AMP_FOR_NOTE + +extern uint8_t gMINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR; //=64 +#define MINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR gMINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR + +extern uint8_t gNOTE_FINAL_AMP; //=12 +#define NOTE_FINAL_AMP gNOTE_FINAL_AMP + +extern uint8_t gNERF_NOTE_PORP; //=15 +#define NERF_NOTE_PORP gNERF_NOTE_PORP + +extern uint8_t gUSE_NUM_LIN_LEDS; // = NUM_LIN_LEDS +#define USE_NUM_LIN_LEDS gUSE_NUM_LIN_LEDS + +//We are not enabling these for the ESP8266 port. +#define LIN_WRAPAROUND 0 +#define SORT_NOTES 0 + + + #endif diff --git a/embedded8266/common/commonservices.c b/embedded8266/common/commonservices.c index a9948d9..dc01a77 100644 --- a/embedded8266/common/commonservices.c +++ b/embedded8266/common/commonservices.c @@ -13,11 +13,14 @@ #include "http.h" #include "spi_flash.h" #include "esp8266_rom.h" +#include #include "flash_rewriter.h" static struct espconn *pUdpServer; static struct espconn *pHTTPServer; struct espconn *pespconn; +uint16_t g_gpiooutputmask = 0; + static int need_to_switch_back_to_soft_ap = 0; //0 = no, 1 = will need to. 2 = do it now. #define MAX_STATIONS 20 @@ -64,6 +67,7 @@ static void ICACHE_FLASH_ATTR scandone(void *arg, STATUS status) int ICACHE_FLASH_ATTR issue_command(char * buffer, int retsize, char *pusrdata, unsigned short len) { char * buffend = buffer; + pusrdata[len] = 0; switch( pusrdata[0] ) { @@ -271,8 +275,68 @@ int ICACHE_FLASH_ATTR issue_command(char * buffer, int retsize, char *pusrdata, } return buffend - buffer; } - default: - break; + case 'G': case 'g': + { + static const uint32_t AFMapper[16] = { + 0, PERIPHS_IO_MUX_U0TXD_U, 0, PERIPHS_IO_MUX_U0RXD_U, + 0, 0, 1, 1, + 1, 1, 1, 1, + PERIPHS_IO_MUX_MTDI_U, PERIPHS_IO_MUX_MTCK_U, PERIPHS_IO_MUX_MTMS_U, PERIPHS_IO_MUX_MTDO_U }; + + int nr = my_atoi( &pusrdata[2] ); + + + if( AFMapper[nr] == 1 ) + { + buffend += ets_sprintf( buffend, "!G%c%d\n", pusrdata[1], nr ); + return buffend - buffer; + } + else if( AFMapper[nr] ) + { + PIN_FUNC_SELECT( AFMapper[nr], 3); //Select AF pin to be GPIO. + } + + switch( pusrdata[1] ) + { + case '0': + case '1': + GPIO_OUTPUT_SET(GPIO_ID_PIN(nr), pusrdata[1]-'0' ); + buffend += ets_sprintf( buffend, "G%c%d", pusrdata[1], nr ); + g_gpiooutputmask |= (1< +#include +#include +#include +#include +#include + +extern volatile uint8_t sounddata[]; +extern volatile uint16_t soundhead; + + +extern uint8_t RootNoteOffset; //Set to define what the root note is. 0 = A. +uint8_t gDFTIIR = 6; +uint8_t gFUZZ_IIR_BITS = 1; +uint8_t gFILTER_BLUR_PASSES = 2; +uint8_t gSEMIBITSPERBIN = 3; +uint8_t gMAX_JUMP_DISTANCE = 4; +uint8_t gMAX_COMBINE_DISTANCE = 7; +uint8_t gAMP_1_IIR_BITS = 4; +uint8_t gAMP_2_IIR_BITS = 2; +uint8_t gMIN_AMP_FOR_NOTE = 80; +uint8_t gMINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR = 64; +uint8_t gNOTE_FINAL_AMP = 12; +uint8_t gNERF_NOTE_PORP = 15; +uint8_t gUSE_NUM_LIN_LEDS = NUM_LIN_LEDS; + + +uint8_t * gConfigurables[] = { &RootNoteOffset, &gDFTIIR, &gFUZZ_IIR_BITS, &gFILTER_BLUR_PASSES, + &gSEMIBITSPERBIN, &gMAX_JUMP_DISTANCE, &gMAX_COMBINE_DISTANCE, &gAMP_1_IIR_BITS, + &gAMP_2_IIR_BITS, &gMIN_AMP_FOR_NOTE, &gMINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR, &gNOTE_FINAL_AMP, + &gNERF_NOTE_PORP, &gUSE_NUM_LIN_LEDS, 0 }; + +char * gConfigurableNames[] = { "gROOT_NOTE_OFFSET", "gDFTIIR", "gFUZZ_IIR_BITS", "gFILTER_BLUR_PASSES", + "gSEMIBITSPERBIN", "gMAX_JUMP_DISTANCE", "gMAX_COMBINE_DISTANCE", "gAMP_1_IIR_BITS", + "gAMP_2_IIR_BITS", "gMIN_AMP_FOR_NOTE", "gMINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR", "gNOTE_FINAL_AMP", + "gNERF_NOTE_PORP", "gUSE_NUM_LIN_LEDS", 0 }; + +int ICACHE_FLASH_ATTR CustomCommand(char * buffer, int retsize, char *pusrdata, unsigned short len) +{ + char * buffend = buffer; + + switch( pusrdata[1] ) + { + + + case 'b': case 'B': //bins + { + int i; + int whichSel = my_atoi( &pusrdata[2] ); + + uint16_t * which = 0; + switch( whichSel ) + { + case 0: + which = embeddedbins32; break; + case 1: + which = fuzzed_bins; break; + case 2: + which = folded_bins; break; + default: + buffend += ets_sprintf( buffend, "!CB" ); + return buffend-buffer; + } + + buffend += ets_sprintf( buffend, "CB%d:%d:", whichSel, FIXBINS ); + for( i = 0; i < FIXBINS; i++ ) + { + uint16_t samp = which[i]; + *(buffend++) = tohex1( samp>>12 ); + *(buffend++) = tohex1( samp>>8 ); + *(buffend++) = tohex1( samp>>4 ); + *(buffend++) = tohex1( samp>>0 ); + } + return buffend-buffer; + } + + + case 'm': case 'M': //Oscilloscope + { + int i, it = soundhead; + buffend += ets_sprintf( buffend, "CM:512:" ); + for( i = 0; i < 512; i++ ) + { + uint8_t samp = sounddata[it++]; + it = it & (HPABUFFSIZE-1); + *(buffend++) = tohex1( samp>>4 ); + *(buffend++) = tohex1( samp&0x0f ); + } + return buffend-buffer; + } + + case 'n': case 'N': //Notes + { + int i; + buffend += ets_sprintf( buffend, "CN:%d:", MAXNOTES ); + for( i = 0; i < MAXNOTES; i++ ) + { + uint16_t dat; + dat = note_peak_freqs[i]; + *(buffend++) = tohex1( dat>>4 ); + *(buffend++) = tohex1( dat>>0 ); + dat = note_peak_amps[i]; + *(buffend++) = tohex1( dat>>12 ); + *(buffend++) = tohex1( dat>>8 ); + *(buffend++) = tohex1( dat>>4 ); + *(buffend++) = tohex1( dat>>0 ); + dat = note_peak_amps2[i]; + *(buffend++) = tohex1( dat>>12 ); + *(buffend++) = tohex1( dat>>8 ); + *(buffend++) = tohex1( dat>>4 ); + *(buffend++) = tohex1( dat>>0 ); + dat = note_jumped_to[i]; + *(buffend++) = tohex1( dat>>4 ); + *(buffend++) = tohex1( dat>>0 ); + } + return buffend-buffer; + } + + + + case 'v': case 'V': //ColorChord Values + { + if( pusrdata[2] == 'R' || pusrdata[2] == 'r' ) + { + int i; + + buffend += ets_sprintf( buffend, "CVR:rBASE_FREQ=%d:rDFREQ=%d:rOCTAVES=%d:rFIXBPERO=%d:NOTERANGE=%d:", + (int)BASE_FREQ, (int)DFREQ, (int)OCTAVES, (int)FIXBPERO, (int)(NOTERANGE) ); + buffend += ets_sprintf( buffend, "CVR:rMAXNOTES=%d:rNUM_LIN_LEDS=%d:rLIN_WRAPAROUND=%d:rLIN_WRAPAROUND=%d:", + (int)MAXNOTES, (int)NUM_LIN_LEDS, (int)LIN_WRAPAROUND, (int)LIN_WRAPAROUND ); + + i = 0; + while( gConfigurableNames[i] ) + { + buffend += ets_sprintf( buffend, "%s=%d:", gConfigurableNames[i], *gConfigurables[i] ); + i++; + } + + return buffend-buffer; + } + else if( pusrdata[2] == 'W' || pusrdata[2] == 'w' ) + { + char * colon = 0, * colon2 = 0; + do + { + int i = 0; + colon = (char *) ets_strstr( (char*)&pusrdata[2], ":" ); + if( !colon ) break; + *colon = 0; + colon++; + colon2 = (char *) ets_strstr( (char*)colon, ":" ); + if( !colon2 ) break; + *colon2 = 0; + colon2++; + + while( gConfigurableNames[i] ) + { + if( strcmp( colon, gConfigurableNames[i] ) == 0 ) + { + *gConfigurables[i] = my_atoi(colon2); + buffend += ets_sprintf( buffend, "CVW" ); + return buffend-buffer; + } + i++; + } + } while( 0 ); + + buffend += ets_sprintf( buffend, "!CV" ); + return buffend-buffer; + } + else + { + buffend += ets_sprintf( buffend, "!CV" ); + return buffend-buffer; + } + + } + + + } + return -1; +} + diff --git a/embedded8266/user/user_main.c b/embedded8266/user/user_main.c index bc74b53..ef43fd9 100644 --- a/embedded8266/user/user_main.c +++ b/embedded8266/user/user_main.c @@ -12,6 +12,7 @@ #include "ws2812_i2s.h" #include "hpatimer.h" #include +#include "ccconfig.h" #include #include #include "ets_sys.h" @@ -31,7 +32,6 @@ static volatile os_timer_t some_timer; static struct espconn *pUdpServer; -#define HPABUFFSIZE 512 extern volatile uint8_t sounddata[HPABUFFSIZE]; extern volatile uint16_t soundhead; uint16_t soundtail; @@ -49,7 +49,7 @@ static void NewFrame() UpdateLinearLEDs(); //SendSPI2812( ledOut, NUM_LIN_LEDS ); - ws2812_push( ledOut, NUM_LIN_LEDS * 3 ); + ws2812_push( ledOut, USE_NUM_LIN_LEDS * 3 ); } os_event_t procTaskQueue[procTaskQueueLen]; diff --git a/embedded8266/web/page/colorchord.html b/embedded8266/web/page/colorchord.html index e58758d..e3c7494 100644 --- a/embedded8266/web/page/colorchord.html +++ b/embedded8266/web/page/colorchord.html @@ -8,6 +8,7 @@ table { width: 100%; } td { vertical-align: top; } .collapsible { display:none; } +.inbutton { background-color:blue; } @@ -20,18 +21,18 @@ td { vertical-align: top; }
-
-
+
+
System Info...
line2
line3 -
+
- +
Current Configuration:
@@ -43,11 +44,10 @@ Current Configuration: (Ignored in Station mode)
- Scanned Stations:
- +
@@ -58,6 +58,41 @@ Command: + + +
+ + + + + + + + + + + + +
012345...12131415
+ + + + + +
+
+ +
+ + + + +
+
+ +
+ + diff --git a/embedded8266/web/page/colorchord.js b/embedded8266/web/page/colorchord.js index ee3d281..532447a 100644 --- a/embedded8266/web/page/colorchord.js +++ b/embedded8266/web/page/colorchord.js @@ -8,10 +8,17 @@ var commsup = 0; // .callback = function( ref (this object), data ); var workqueue = []; +var workarray = {}; var lastitem; function QueueOperation( command, callback ) { + if( workarray[command] == 1 ) + { + return; + } + + workarray[command] = 1; var vp = new Object(); vp.callback = callback; vp.request = command; @@ -25,16 +32,20 @@ function init() if( localStorage["sh" + this.id] > 0.5 ) { $( this ).show().toggleClass( 'opened' ); +// console.log( "OPEN: " + this.id ); } }); $("#custom_command_response").val( "" ); + output = document.getElementById("output"); Ticker(); - - WifiDataTicker(); + KickWifiTicker(); + GPIODataTickerStart(); + KickOscilloscope(); + KickDFT(); } function StartWebSocket() @@ -98,6 +109,7 @@ function onMessage(evt) if( workqueue.length ) { var elem = workqueue.shift(); + delete workarray[elem.request]; if( elem.request ) { doSend( elem.request ); @@ -121,7 +133,12 @@ function doSend(message) websocket.send(message); } - +function IsTabOpen( objname ) +{ + var obj = $( "#" + objname ); + var opened = obj.is( '.opened' ); + return opened != 0; +} function ShowHideEvent( objname ) { @@ -129,6 +146,7 @@ function ShowHideEvent( objname ) obj.slideToggle( 'fast' ).toggleClass( 'opened' ); var opened = obj.is( '.opened' ); localStorage["sh" + objname] = opened?1:0; + return opened!=0; } @@ -149,49 +167,218 @@ window.addEventListener("load", init, false); ///////// Various functions that are not core appear down here. +is_oscilloscope_running = false; +pause_oscilloscope = false; + +function KickOscilloscope() +{ + $( "#OScopePauseButton" ).css( "background-color", (is_oscilloscope_running&&pause_oscilloscope)?"green":"red" ); + if( !is_oscilloscope_running && !pause_oscilloscope) + OScopeDataTicker(); +} + +function ToggleOScopePause() +{ + pause_oscilloscope = !pause_oscilloscope; + KickOscilloscope(); +} + +function GotOScope(req,data) +{ + var canvas = document.getElementById('OScopeCanvas'); + var ctx = canvas.getContext('2d'); + var h = canvas.height; + var w = canvas.width; + if( ctx.canvas.width != canvas.clientWidth ) ctx.canvas.width = canvas.clientWidth; + if( ctx.canvas.height != canvas.clientHeight ) ctx.canvas.height = canvas.clientHeight; + + $( "#OScopePauseButton" ).css( "background-color", "green" ); + + var secs = data.split( ":" ); + + var samps = Number( secs[1] ); + var data = secs[2]; + var lastsamp = parseInt( data.substr(0,2),16 ); + ctx.clearRect( 0, 0, canvas.width, canvas.height ); + ctx.beginPath(); + for( var i = 0; i < samps; i++ ) + { + var x2 = (i+1) * canvas.clientWidth / samps; + var samp = parseInt( data.substr(i*2+2,2),16 ); + var y2 = ( 1.-samp / 255 ) * canvas.clientHeight; + + if( i == 0 ) + { + var x1 = i * canvas.clientWidth / samps; + var y1 = ( 1.-lastsamp / 255 ) * canvas.clientHeight; + ctx.moveTo( x1, y1 ); + } + + ctx.lineTo( x2, y2 ); + + lastsamp = samp; + } + ctx.stroke(); + + var samp = parseInt( data.substr(i*2,2),16 ); + + OScopeDataTicker(); +} + +function OScopeDataTicker() +{ + if( IsTabOpen('OScope') && !pause_oscilloscope ) + { + is_oscilloscope_running = true; + QueueOperation( "CM", GotOScope ); + } + else + { + is_oscilloscope_running = 0; + } + $( "#OScopePauseButton" ).css( "background-color", (is_oscilloscope_running&&!pause_oscilloscope)?"green":"red" ); +} + + + + + + + + + +is_dft_running = false; + +function KickDFT() +{ + if( !is_dft_running ) + DFTDataTicker(); + +} + +function GotDFT(req,data) +{ + var canvas = document.getElementById('DFTCanvas'); + var ctx = canvas.getContext('2d'); + var h = canvas.height; + var w = canvas.width; + if( ctx.canvas.width != canvas.clientWidth ) ctx.canvas.width = canvas.clientWidth; + if( ctx.canvas.height != canvas.clientHeight ) ctx.canvas.height = canvas.clientHeight; + + var secs = data.split( ":" ); + + var samps = Number( secs[1] ); + var data = secs[2]; + var lastsamp = parseInt( data.substr(0,4),16 ); + ctx.clearRect( 0, 0, canvas.width, canvas.height ); + ctx.beginPath(); + for( var i = 0; i < samps; i++ ) + { + var x2 = (i+1) * canvas.clientWidth / samps; + var samp = parseInt( data.substr(i*4+4,4),16 ); + var y2 = ( 1.-samp / 2047 ) * canvas.clientHeight; + + if( i == 0 ) + { + var x1 = i * canvas.clientWidth / samps; + var y1 = ( 1.-lastsamp / 2047 ) * canvas.clientHeight; + ctx.moveTo( x1, y1 ); + } + + ctx.lineTo( x2, y2 ); + + lastsamp = samp; + } + ctx.stroke(); + + var samp = parseInt( data.substr(i*2,2),16 ); + + DFTDataTicker(); +} + +function DFTDataTicker() +{ + if( IsTabOpen('DFT') ) + { + is_dft_running = true; + QueueOperation( "CB", GotDFT ); + } + else + { + is_dft_running = 0; + } +} + + + + + + + + + + + + + did_wifi_get_config = false; +is_data_ticker_running = false; + +function KickWifiTicker() +{ + if( !is_data_ticker_running ) + WifiDataTicker(); +} function WifiDataTicker() { - if( !did_wifi_get_config ) + if( IsTabOpen('WifiSettings') ) { - QueueOperation( "WI", function(req,data) - { - var params = data.split( "\t" ); - - document.wifisection.wifitype.value = Number( params[0].substr(2) ); - document.wifisection.wificurname.value = params[1]; - document.wifisection.wificurpassword.value = params[2]; - document.wifisection.wificurenctype.value = params[3]; - document.wifisection.wificurchannel.value = Number( params[4] ); + is_data_ticker_running = true; - did_wifi_get_config = true; - } ); - } - - - QueueOperation( "WR", function(req,data) { - var lines = data.split( "\n" ); - var innerhtml; - if( lines.length < 3 ) + if( !did_wifi_get_config ) { - innerhtml = "No APs found. Did you scan?"; - } - else - { - innerhtml = "" - for( i = 1; i < lines.length-1; i++ ) + QueueOperation( "WI", function(req,data) { - var dats = lines[i].split( "\t" ); - innerhtml += ""; - } - } - innerhtml += ""; - document.getElementById("WifiStations").innerHTML = innerhtml; - } ); + var params = data.split( "\t" ); + + document.wifisection.wifitype.value = Number( params[0].substr(2) ); + document.wifisection.wificurname.value = params[1]; + document.wifisection.wificurpassword.value = params[2]; + document.wifisection.wificurenctype.value = params[3]; + document.wifisection.wificurchannel.value = Number( params[4] ); - setTimeout( WifiDataTicker, 1000 ); + did_wifi_get_config = true; + } ); + } + + + QueueOperation( "WR", function(req,data) { + var lines = data.split( "\n" ); + var innerhtml; + if( lines.length < 3 ) + { + innerhtml = "No APs found. Did you scan?"; + } + else + { + innerhtml = "
SSIDMACRSChEnc
" + dats[0] + "" + dats[1] + "" + dats[2] + "" + dats[3] + "" + dats[4] + "
" + for( i = 1; i < lines.length-1; i++ ) + { + var dats = lines[i].split( "\t" ); + innerhtml += ""; + } + } + innerhtml += "
SSIDMACRSChEnc
" + dats[0] + "" + dats[1] + "" + dats[2] + "" + dats[3] + "" + dats[4] + "
"; + document.getElementById("WifiStations").innerHTML = innerhtml; + } ); + setTimeout( WifiDataTicker, 500 ); + } + else + { + is_data_ticker_running = 0; + } } function ChangeWifiConfig() @@ -206,3 +393,85 @@ function ChangeWifiConfig() } + + +function TwiddleGPIO( gp ) +{ + var st = "GF"; + st += gp; + QueueOperation( st ); +} + +function GPIOInput( gp ) +{ + var st = "GI"; + st += gp; + QueueOperation( st ); +} + +function GPIOUpdate(req,data) { + var secs = data.split( ":" ); + var op = 0; + var n = Number(secs[2]); + var m = Number(secs[1]); + + for( op = 0; op < 16; op++ ) + { + var b = $( "#ButtonGPIO" + op ); + if( b ) + { + if( 1<