//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 #include "flash_rewriter.h" static struct espconn *pUdpServer; static struct espconn *pHTTPServer; struct espconn *pespconn; uint16_t g_gpiooutputmask = 0; int ets_str2macaddr(void *, void *); 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; } } int ICACHE_FLASH_ATTR issue_command(char * buffer, int retsize, char *pusrdata, unsigned short len) { char * buffend = buffer; pusrdata[len] = 0; switch( pusrdata[0] ) { case 'e': case 'E': //Echo if( retsize > len ) { ets_memcpy( buffend, pusrdata, len ); return len; } else { return -1; } case 'f': case 'F': //Flashing commands (F_) { flashchip->chip_size = 0x01000000; 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. { EnterCritical(); spi_flash_erase_sector( nr ); //SPI_FLASH_SEC_SIZE 4096 ExitCritical(); buffend += ets_sprintf(buffend, "FE%d\r\n", nr ); break; } case 'b': case 'B': //(FE#\n) <- # = sector. { EnterCritical(); SPIEraseBlock( nr ); ExitCritical(); buffend += ets_sprintf(buffend, "FB%d\r\n", nr ); break; } case 'm': case 'M': //Execute the flash re-writer { int r = (*GlobalRewriteFlash)( &pusrdata[2], len-2 ); buffend += ets_sprintf( buffend, "!FM%d\r\n", r ); break; } case 'w': case 'W': //Flash Write (FW#\n) <- # = byte pos. if( colon ) { 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(); buffend += ets_sprintf(buffend, "FW%d\r\n", nr ); break; } } buffend += ets_sprintf(buffend, "!FW\r\n" ); break; case 'r': case 'R': //Flash Read (FR#\n) <- # = sector. if( colon ) { colon++; int datlen = my_atoi( colon ); datlen = (datlen/4)*4; //Must be multiple of 4 bytes if( datlen <= 1280 ) { buffend += ets_sprintf(buffend, "FR%08d:%04d:", nr, datlen ); //Caution: This string must be a multiple of 4 bytes. spi_flash_read( nr, (uint32*)buffend, datlen ); break; } } buffend += ets_sprintf(buffend, "!FR\r\n" ); break; } flashchip->chip_size = 0x00080000; return buffend - buffer; } case 'i': case 'I': //Respond with device info. { buffend += ets_sprintf(buffend, "I" ); int i; for( i = 0; i < 2 ;i++ ) { struct ip_info ipi; wifi_get_ip_info( i, &ipi ); buffend += ets_sprintf(buffend, "\t"IPSTR, IP2STR(&ipi.ip) ); } buffend += ets_sprintf(buffend, "\r\n" ); return buffend - buffer; } 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. { int c1l = 0; int c2l = 0; char * colon = (char *) ets_strstr( (char*)&pusrdata[2], "\t" ); char * colon2 = (colon)?((char *)ets_strstr( (char*)(colon+1), "\t" )):0; char * colon3 = (colon2)?((char *)ets_strstr( (char*)(colon2+1), "\t" )):0; char * colon4 = (colon3)?((char *)ets_strstr( (char*)(colon3+1), "\t" )):0; char * extra = colon2; char mac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; int bssid_set = 0; if( colon ) { *colon = 0; colon++; } if( colon2 ) { *colon2 = 0; colon2++; } if( colon3 ) { *colon3 = 0; colon3++; } if( colon4 ) { *colon4 = 0; colon4++; } if( colon ) { c1l = ets_strlen( colon ); } if( colon2 ) { c2l = ets_strlen( colon2 ); } if( colon3 ) { bssid_set = ets_str2macaddr( mac, colon3 )?1:0; if( ( mac[0] == 0x00 || mac[0] == 0xff ) && ( mac[1] == 0x00 || mac[1] == 0xff ) && ( mac[2] == 0x00 || mac[2] == 0xff ) && ( mac[3] == 0x00 || mac[3] == 0xff ) && ( mac[4] == 0x00 || mac[4] == 0xff ) && ( mac[5] == 0x00 || mac[5] == 0xff ) ) bssid_set = 0; } if( extra ) { for( ; *extra; extra++ ) { if( *extra < 32 ) { *extra = 0; break; } } } switch (pusrdata[1]) { case '1': //Station mode case '2': //AP Mode if( colon && colon2 && ets_strlen( colon ) > 1 ) { if( c1l > 31 ) c1l = 31; if( c2l > 63 ) c2l = 63; printf( "Switching to: \"%s\"/\"%s\" (%d/%d). BSSID_SET: %d [%c]\n", colon, colon2, c1l, c2l, bssid_set, pusrdata[1] ); if( pusrdata[1] == '1' ) { struct station_config stationConf; wifi_station_get_config(&stationConf); os_memcpy(&stationConf.ssid, colon, c1l); os_memcpy(&stationConf.password, colon2, c2l); stationConf.ssid[c1l] = 0; stationConf.password[c2l] = 0; stationConf.bssid_set = bssid_set; os_memcpy( stationConf.bssid, mac, 6 ); printf( "-->'%s'\n",stationConf.ssid); printf( "-->'%s'\n",stationConf.password); EnterCritical(); // wifi_station_set_config(&stationConf); wifi_set_opmode( 1 ); wifi_station_set_config(&stationConf); wifi_station_connect(); ExitCritical(); // wifi_station_get_config( &stationConf ); buffend += ets_sprintf( buffend, "W1\r\n" ); printf( "Switching.\n" ); } else { struct softap_config config; char macaddr[6]; wifi_softap_get_config( &config ); wifi_get_macaddr(SOFTAP_IF, macaddr); os_memcpy( &config.ssid, colon, c1l ); os_memcpy( &config.password, colon2, c2l ); config.ssid_len = c1l; #if 0 //We don't support encryption. config.ssid[c1l] = 0; config.password[c2l] = 0; config.authmode = 0; if( colon3 ) { int k; for( k = 0; enctypes[k]; k++ ) { if( strcmp( colon3, enctypes[k] ) == 0 ) config.authmode = k; } } #endif int chan = (colon4)?my_atoi(colon4):config.channel; if( chan == 0 || chan > 13 ) chan = 1; config.channel = chan; // printf( "Mode now. %s %s %d %d %d %d %d\n", config.ssid, config.password, config.ssid_len, config.channel, config.authmode, config.max_connection ); // printf( "Mode Set. %d\n", wifi_get_opmode() ); EnterCritical(); wifi_softap_set_config(&config); wifi_set_opmode( 2 ); ExitCritical(); printf( "Switching SoftAP: %d %d.\n", chan, config.authmode ); buffend += ets_sprintf( buffend, "W2\r\n" ); } } break; case 'I': { char macmap[15]; int mode = wifi_get_opmode(); buffend += ets_sprintf( buffend, "WI%d", mode ); if( mode == 2 ) { uint8_t mac[6]; struct softap_config ap; wifi_softap_get_config( &ap ); wifi_get_macaddr( 1, mac ); ets_sprintf( macmap, MACSTR, MAC2STR( mac ) ); buffend += ets_sprintf( buffend, "\t%s\t%s\t%s\t%d", ap.ssid, ap.password, macmap, ap.channel ); } else { struct station_config sc; wifi_station_get_config( &sc ); if( sc.bssid_set ) ets_sprintf( macmap, MACSTR, MAC2STR( sc.bssid ) ); else macmap[0] = 0; buffend += ets_sprintf( buffend, "\t%s\t%s\t%s\t%d", sc.ssid, sc.password, macmap, wifi_get_channel() ); } } break; case 'X': case 'x': buffend += ets_sprintf( buffend, "WX%d", wifi_station_get_rssi() ); break; case 'S': case 's': { int i, r; struct scan_config sc; scanplace = 0; sc.ssid = 0; sc.bssid = 0; sc.channel = 0; sc.show_hidden = 1; EnterCritical(); if( wifi_get_opmode() == SOFTAP_MODE ) { wifi_set_opmode_current( STATION_MODE ); need_to_switch_back_to_soft_ap = 1; } r = wifi_station_scan(&sc, scandone ); ExitCritical(); buffend += ets_sprintf( buffend, "WS%d\n", r ); uart0_sendStr(buffer); break; } break; case 'R': case 'r': { int i, r; buffend += ets_sprintf( buffend, "WR%d\n", scanplace ); for( i = 0; i < scanplace && buffend - buffer < retsize - 64; 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] ); } break; } break; } return buffend - buffer; } 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< 0 ) { espconn_sent( (struct espconn *)arg, retbuf, r ); } } 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_udp); 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; EnterCritical(); wifi_set_opmode_current( SOFTAP_MODE ); ExitCritical(); } 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); } }