//Copyright 2015 <>< Charles Lohr Under the MIT/x11 License, NewBSD License or // ColorChord License. You Choose. #include "mem.h" #include "c_types.h" #include "user_interface.h" #include "ets_sys.h" #include "uart.h" #include "osapi.h" #include "espconn.h" #include "esp82xxutil.h" #include "ws2812_i2s.h" #include "hpatimer.h" #include "DFT32.h" #include "ccconfig.h" #include #include #include #include "ets_sys.h" #include "gpio.h" //#define PROFILE #define PORT 7777 #define SERVER_TIMEOUT 1500 #define MAX_CONNS 5 #define MAX_FRAME 2000 #define procTaskPrio 0 #define procTaskQueueLen 1 struct CCSettings CCS; static os_timer_t some_timer; static struct espconn *pUdpServer; void EnterCritical(); void ExitCritical(); extern volatile uint8_t sounddata[HPABUFFSIZE]; extern volatile uint16_t soundhead; uint16_t soundtail; static uint8_t hpa_running = 0; static uint8_t hpa_is_paused_for_wifi; void ICACHE_FLASH_ATTR CustomStart( ); //Call this once we've stacked together one full colorchord frame. static void NewFrame() { if( !COLORCHORD_ACTIVE ) return; int i; HandleFrameInfo(); switch( COLORCHORD_OUTPUT_DRIVER ) { case 0: UpdateLinearLEDs(); break; case 1: UpdateAllSameLEDs(); break; }; ws2812_push( ledOut, USE_NUM_LIN_LEDS * 3, LED_DRIVER_MODE ); } os_event_t procTaskQueue[procTaskQueueLen]; uint32_t samp_iir = 0; int wf = 0; void fpm_wakup_cb_func1(void) { wifi_fpm_close(); } //Tasks that happen all the time. static void procTask(os_event_t *events) { system_os_post(procTaskPrio, 0, 0 ); if( COLORCHORD_ACTIVE && !hpa_running ) { ExitCritical(); hpa_running = 1; } if( !COLORCHORD_ACTIVE && hpa_running ) { EnterCritical(); hpa_running = 0; } //For profiling so we can see how much CPU is spent in this loop. #ifdef PROFILE WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(0), 1 ); #endif while( soundtail != soundhead ) { int32_t samp = sounddata[soundtail]; samp_iir = samp_iir - (samp_iir>>10) + samp; samp = (samp - (samp_iir>>10))*16; samp = (samp * CCS.gINITIAL_AMP) >> 4; PushSample32( samp ); soundtail = (soundtail+1)&(HPABUFFSIZE-1); wf++; if( wf == 128 ) { NewFrame(); wf = 0; } } #ifdef PROFILE WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(0), 0 ); #endif if( events->sig == 0 && events->par == 0 ) { CSTick( 0 ); } } //Timer event. static void ICACHE_FLASH_ATTR myTimer(void *arg) { CSTick( 1 ); if( GPIO_INPUT_GET( 0 ) == 0 ) { if( system_get_rst_info()->reason != 5 ) //See if we're booting from deep sleep. (5 = deep sleep, 4 = reboot, 0 = fresh boot) { system_deep_sleep_set_option(4); //Option 4 = When rebooting from deep sleep, totally disable wifi. system_deep_sleep(2000); } else { //system_deep_sleep_set_option(1); //Option 1 = Reboot with radio recalibration and wifi on. //system_deep_sleep(2000); system_restart(); } } if( hpa_is_paused_for_wifi && printed_ip ) { StartHPATimer(); //Init the high speed ADC timer. hpa_running = 1; hpa_is_paused_for_wifi = 0; // only need to do once prevents unstable ADC } // uart0_sendStr("."); // printf( "%d/%d\n",soundtail,soundhead ); // printf( "%d/%d\n",soundtail,soundhead ); // uint8_t ledout[] = { 0x00, 0xff, 0xaa, 0x00, 0xff, 0xaa, }; // ws2812_push( ledout, 6, LED_DRIVER_MODE ); } //Called when new packet comes in. static void ICACHE_FLASH_ATTR udpserver_recv(void *arg, char *pusrdata, unsigned short len) { struct espconn *pespconn = (struct espconn *)arg; // uint8_t buffer[MAX_FRAME]; // uint8_t ledout[] = { 0x00, 0xff, 0xaa, 0x00, 0xff, 0xaa, }; uart0_sendStr("X"); ws2812_push( pusrdata+3, len, LED_DRIVER_MODE ); } void ICACHE_FLASH_ATTR charrx( uint8_t c ) { //Called from UART. } void ICACHE_FLASH_ATTR user_init(void) { uart_init(BIT_RATE_115200, BIT_RATE_115200); int wifiMode = wifi_get_opmode(); uart0_sendStr("\r\nColorChord\r\n"); //Uncomment this to force a system restore. // system_restore(); CustomStart(); #ifdef PROFILE GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 0); #endif //Tricky: New recommendation is to connect GPIO14 to vcc for audio circuitry, so we turn this on by default. GPIO_OUTPUT_SET( GPIO_ID_PIN(14), 1); PIN_FUNC_SELECT( PERIPHS_IO_MUX_MTMS_U, 3 ); CSPreInit(); pUdpServer = (struct espconn *)os_zalloc(sizeof(struct espconn)); ets_memset( pUdpServer, 0, sizeof( struct espconn ) ); espconn_create( pUdpServer ); pUdpServer->type = ESPCONN_UDP; pUdpServer->proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp)); pUdpServer->proto.udp->local_port = 7777; espconn_regist_recvcb(pUdpServer, udpserver_recv); if( espconn_create( pUdpServer ) ) { while(1) { uart0_sendStr( "\r\nFAULT\r\n" ); } } CSInit( 1 ); //Add a process system_os_task(procTask, procTaskPrio, procTaskQueue, procTaskQueueLen); //Timer example os_timer_disarm(&some_timer); os_timer_setfn(&some_timer, (os_timer_func_t *)myTimer, NULL); os_timer_arm(&some_timer, 100, 1); //Set GPIO16 for Input #if 0 WRITE_PERI_REG(PAD_XPD_DCDC_CONF, (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); // mux configuration for XPD_DCDC and rtc_gpio0 connection WRITE_PERI_REG(RTC_GPIO_CONF, (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0); //mux configuration for out enable WRITE_PERI_REG(RTC_GPIO_ENABLE, READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe); //out disable #endif system_update_cpu_freq(SYS_CPU_160MHZ); InitColorChord(); //Init colorchord //Tricky: If we are in station mode, wait for that to get resolved before enabling the high speed timer. if( wifi_get_opmode() == 1 ) { hpa_is_paused_for_wifi = 1; } else { StartHPATimer(); //Init the high speed ADC timer. hpa_running = 1; } ws2812_init(); printf( "RST REASON: %d\n", system_get_rst_info()->reason ); // Attempt to make ADC more stable // https://github.com/esp8266/Arduino/issues/2070 // see peripherals https://espressif.com/en/support/explore/faq wifi_set_sleep_type(MODEM_SLEEP_T); // on its own stopped wifi working? //wifi_fpm_set_sleep_type(NONE_SLEEP_T); // with this seemed no difference system_os_post(procTaskPrio, 0, 0 ); } void ICACHE_FLASH_ATTR EnterCritical() { PauseHPATimer(); //ets_intr_lock(); } void ICACHE_FLASH_ATTR ExitCritical() { //ets_intr_unlock(); ContinueHPATimer(); } /*============================================================================== * Partition Map Data *============================================================================*/ #define SYSTEM_PARTITION_OTA_SIZE_OPT2 0x6A000 #define SYSTEM_PARTITION_OTA_2_ADDR_OPT2 0x81000 #define SYSTEM_PARTITION_RF_CAL_ADDR_OPT2 0xfb000 #define SYSTEM_PARTITION_PHY_DATA_ADDR_OPT2 0xfc000 #define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR_OPT2 0xfd000 #define SYSTEM_PARTITION_CUSTOMER_PRIV_PARAM_ADDR_OPT2 0x7c000 #define SPI_FLASH_SIZE_MAP_OPT2 2 #define SYSTEM_PARTITION_OTA_SIZE_OPT3 0x6A000 #define SYSTEM_PARTITION_OTA_2_ADDR_OPT3 0x81000 #define SYSTEM_PARTITION_RF_CAL_ADDR_OPT3 0x1fb000 #define SYSTEM_PARTITION_PHY_DATA_ADDR_OPT3 0x1fc000 #define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR_OPT3 0x1fd000 #define SYSTEM_PARTITION_CUSTOMER_PRIV_PARAM_ADDR_OPT3 0x7c000 #define SPI_FLASH_SIZE_MAP_OPT3 3 #define SYSTEM_PARTITION_OTA_SIZE_OPT4 0x6A000 #define SYSTEM_PARTITION_OTA_2_ADDR_OPT4 0x81000 #define SYSTEM_PARTITION_RF_CAL_ADDR_OPT4 0x3fb000 #define SYSTEM_PARTITION_PHY_DATA_ADDR_OPT4 0x3fc000 #define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR_OPT4 0x3fd000 #define SYSTEM_PARTITION_CUSTOMER_PRIV_PARAM_ADDR_OPT4 0x7c000 #define SPI_FLASH_SIZE_MAP_OPT4 4 #define SYSTEM_PARTITION_CUSTOMER_PRIV_PARAM SYSTEM_PARTITION_CUSTOMER_BEGIN #define EAGLE_FLASH_BIN_ADDR SYSTEM_PARTITION_CUSTOMER_BEGIN + 1 #define EAGLE_IROM0TEXT_BIN_ADDR SYSTEM_PARTITION_CUSTOMER_BEGIN + 2 static const partition_item_t partition_table_opt2[] = { { EAGLE_FLASH_BIN_ADDR, 0x00000, 0x10000}, { EAGLE_IROM0TEXT_BIN_ADDR, 0x10000, 0x60000}, { SYSTEM_PARTITION_RF_CAL, SYSTEM_PARTITION_RF_CAL_ADDR_OPT2, 0x1000}, { SYSTEM_PARTITION_PHY_DATA, SYSTEM_PARTITION_PHY_DATA_ADDR_OPT2, 0x1000}, { SYSTEM_PARTITION_SYSTEM_PARAMETER, SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR_OPT2, 0x3000}, }; static const partition_item_t partition_table_opt3[] = { { EAGLE_FLASH_BIN_ADDR, 0x00000, 0x10000}, { EAGLE_IROM0TEXT_BIN_ADDR, 0x10000, 0x60000}, { SYSTEM_PARTITION_RF_CAL, SYSTEM_PARTITION_RF_CAL_ADDR_OPT3, 0x1000}, { SYSTEM_PARTITION_PHY_DATA, SYSTEM_PARTITION_PHY_DATA_ADDR_OPT3, 0x1000}, { SYSTEM_PARTITION_SYSTEM_PARAMETER, SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR_OPT3, 0x3000}, }; static const partition_item_t partition_table_opt4[] = { { EAGLE_FLASH_BIN_ADDR, 0x00000, 0x10000}, { EAGLE_IROM0TEXT_BIN_ADDR, 0x10000, 0x60000}, { SYSTEM_PARTITION_RF_CAL, SYSTEM_PARTITION_RF_CAL_ADDR_OPT4, 0x1000}, { SYSTEM_PARTITION_PHY_DATA, SYSTEM_PARTITION_PHY_DATA_ADDR_OPT4, 0x1000}, { SYSTEM_PARTITION_SYSTEM_PARAMETER, SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR_OPT4, 0x3000}, }; /** * This is called on boot for versions ESP8266_NONOS_SDK_v1.5.2 to * ESP8266_NONOS_SDK_v2.2.1. system_phy_set_rfoption() may be called here */ void user_rf_pre_init(void) { ; // nothing } /** * Required function as of ESP8266_NONOS_SDK_v3.0.0. Must call * system_partition_table_regist(). This tries to register a few different * partition maps. The ESP should be happy with one of them. */ void ICACHE_FLASH_ATTR user_pre_init(void) { if(system_partition_table_regist( partition_table_opt2, sizeof(partition_table_opt2) / sizeof(partition_table_opt2[0]), SPI_FLASH_SIZE_MAP_OPT2)) { os_printf("system_partition_table_regist 2 success!!\r\n"); } else if(system_partition_table_regist( partition_table_opt4, sizeof(partition_table_opt4) / sizeof(partition_table_opt4[0]), SPI_FLASH_SIZE_MAP_OPT4)) { os_printf("system_partition_table_regist 4 success!!\r\n"); } else if(system_partition_table_regist( partition_table_opt3, sizeof(partition_table_opt3) / sizeof(partition_table_opt3[0]), SPI_FLASH_SIZE_MAP_OPT3)) { os_printf("system_partition_table_regist 3 success!!\r\n"); } else { os_printf("system_partition_table_regist all fail\r\n"); while(1); } }