esp-open-rtos/open_esplibs/libmain/user_interface.c

562 lines
16 KiB
C
Raw Normal View History

/* Recreated Espressif libmain user_interface.o contents.
Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries.
BSD Licensed as described in the file LICENSE
*/
#include "open_esplibs.h"
#if OPEN_LIBMAIN_USER_INTERFACE
// The contents of this file are only built if OPEN_LIBMAIN_USER_INTERFACE is set to true
#include "FreeRTOS.h"
#include "task.h"
#include "string.h"
#include "lwip/dhcp.h"
#include "esp/types.h"
#include "esp/rom.h"
#include "esp/dport_regs.h"
#include "esp/rtcmem_regs.h"
#include "esp/iomux_regs.h"
#include "esp/sar_regs.h"
#include "esp/wdev_regs.h"
#include "etstimer.h"
#include "espressif/sdk_private.h"
#include "espressif/esp_system.h"
#include "espressif/esp_wifi.h"
#include "espressif/esp_sta.h"
#include "espressif/esp_softap.h"
#include "espressif/esp_misc.h"
#include "espressif/osapi.h"
#include "espressif/user_interface.h"
#include "sdk_internal.h"
#include "esplibs/libmain.h"
#include "esplibs/libpp.h"
#include "esplibs/libphy.h"
#include "esplibs/libnet80211.h"
// Structure for the data contained in the last sector of Flash which contains
// meta-info about the saved wifi param sectors.
struct param_dir_st {
uint8_t current_sector; // 0x00
uint32_t cksum_magic; // 0x04
uint32_t save_count; // 0x08
uint32_t cksum_len[2]; // 0x0c
uint32_t cksum_value[2]; // 0x14
};
_Static_assert(sizeof(struct param_dir_st) == 28, "param_dir_st is the wrong size");
enum sdk_dhcp_status sdk_dhcpc_flag = DHCP_STARTED;
bool sdk_cpu_overclock;
struct sdk_rst_info sdk_rst_if;
sdk_wifi_promiscuous_cb_t sdk_promiscuous_cb;
static uint8_t _system_upgrade_flag; // Ldata009
// Timer to execute a second phase of switching to a deep sleep
static ETSTimer deep_sleep_timer;
// Prototypes for static functions
static bool _check_boot_version(void);
static void _deep_sleep_phase2(void *timer_arg);
static struct netif *_get_netif(uint32_t mode);
// Linker-created values used by sdk_system_print_meminfo
extern uint32_t _data_start, _data_end;
extern uint32_t _rodata_start, _rodata_end;
extern uint32_t _bss_start, _bss_end;
extern uint32_t _heap_start;
#define _rom_reset_vector ((void (*)(void))0x40000080)
void IRAM sdk_system_restart_in_nmi(void) {
uint32_t buf[8];
sdk_system_rtc_mem_read(0, buf, 32);
if (buf[0] != 2) {
memset(buf, 0, 32);
buf[0] = 3;
sdk_system_rtc_mem_write(0, buf, 32);
}
if (!sdk_NMIIrqIsOn) {
portENTER_CRITICAL();
do {
DPORT.DPORT0 = SET_FIELD(DPORT.DPORT0, DPORT_DPORT0_FIELD0, 0);
} while (DPORT.DPORT0 & 1);
}
ESPSAR.UNKNOWN_48 |= 3;
DPORT.CLOCKGATE_WATCHDOG |= DPORT_CLOCKGATE_WATCHDOG_UNKNOWN_8;
ESPSAR.UNKNOWN_48 &= ~3;
DPORT.CLOCKGATE_WATCHDOG &= ~DPORT_CLOCKGATE_WATCHDOG_UNKNOWN_8;
Cache_Read_Disable();
DPORT.SPI_CACHE_RAM &= ~(DPORT_SPI_CACHE_RAM_BANK0 | DPORT_SPI_CACHE_RAM_BANK1);
// This calls directly to 0x40000080, the "reset" exception vector address.
_rom_reset_vector();
}
bool IRAM sdk_system_rtc_mem_write(uint32_t des_addr, void *src_addr, uint16_t save_size) {
uint32_t volatile *src_buf = (uint32_t *)src_addr;
if (des_addr > 191) {
return false;
}
if ((intptr_t)src_addr & 3) {
return false;
}
if ((768 - (des_addr * 4)) < save_size) {
return false;
}
if ((save_size & 3) != 0) {
save_size = (save_size & ~3) + 4;
}
for (uint8_t i = 0; i < (save_size >> 2); i++) {
RTCMEM_SYSTEM[i] = src_buf[i];
}
return true;
}
bool IRAM sdk_system_rtc_mem_read(uint32_t src_addr, void *des_addr, uint16_t save_size) {
uint32_t *dest_buf = (uint32_t *)des_addr;
if (src_addr > 191) {
return false;
}
if ((intptr_t)des_addr & 3) {
return false;
}
if ((768 - (src_addr * 4)) < save_size) {
return false;
}
if ((save_size & 3) != 0) {
save_size = (save_size & ~3) + 4;
}
for (uint8_t i = 0; i < (save_size >> 2); i++) {
dest_buf[i] = RTCMEM_SYSTEM[i];
}
return true;
}
void sdk_system_pp_recycle_rx_pkt(void *eb) {
sdk_ppRecycleRxPkt(eb);
}
uint16_t sdk_system_adc_read(void) {
return sdk_test_tout(false);
}
void sdk_system_restart(void) {
if (sdk_wifi_get_opmode() != 2) {
sdk_wifi_station_stop();
}
if (sdk_wifi_get_opmode() != 1) {
sdk_wifi_softap_stop();
}
vTaskDelay(6);
IOMUX_GPIO12 |= IOMUX_PIN_PULLUP;
sdk_wDev_MacTim1SetFunc(sdk_system_restart_in_nmi);
sdk_wDev_MacTim1Arm(3);
}
void sdk_system_restore(void) {
struct sdk_g_ic_saved_st *buf;
buf = malloc(sizeof(struct sdk_g_ic_saved_st));
memset(buf, 0xff, sizeof(struct sdk_g_ic_saved_st));
memcpy(buf, &sdk_g_ic.s, 8);
sdk_wifi_param_save_protect(buf);
free(buf);
}
uint8_t sdk_system_get_boot_version(void) {
return sdk_g_ic.s.boot_info & 0x1f;
}
static bool _check_boot_version(void) {
uint8_t ver = sdk_system_get_boot_version();
if (ver < 3 || ver == 31) {
printf("failed: need boot >= 1.3\n");
return false;
}
return true;
}
int sdk_system_get_test_result(void) {
if (_check_boot_version()) {
return (sdk_g_ic.s.boot_info >> 5) & 1;
} else {
return -1;
}
}
uint32_t sdk_system_get_userbin_addr(void) {
uint8_t buf[8];
uint16_t unknown_var = 0; //FIXME: read but never written?
uint32_t addr;
uint32_t flash_size_code;
if (!(sdk_g_ic.s.boot_info >> 7)) {
if (sdk_g_ic.s._unknown1d8 & 0x4) {
addr = sdk_g_ic.s.user1_addr[0] | (sdk_g_ic.s.user1_addr[1] << 8) |
(sdk_g_ic.s.user1_addr[2] << 16);
} else {
addr = sdk_g_ic.s.user0_addr[0] | (sdk_g_ic.s.user0_addr[1] << 8) | (sdk_g_ic.s.user0_addr[2] << 16);
}
} else {
if (!sdk_system_upgrade_userbin_check()) {
addr = 0x00001000;
} else {
sdk_spi_flash_read(0, (uint32_t *)buf, 8);
flash_size_code = buf[3] >> 4;
if (flash_size_code >= 2 && flash_size_code < 5) {
flash_size_code = 0x81;
} else if (flash_size_code == 1) {
flash_size_code = 0x41;
} else {
// FIXME: In the original code, this loads from a local stack
// variable, which is never actually assigned to anywhere.
// It's unclear what this value is actually supposed to be.
flash_size_code = unknown_var;
}
addr = flash_size_code << 12;
}
}
return addr;
}
uint8_t sdk_system_get_boot_mode(void) {
int boot_version = sdk_g_ic.s.boot_info & 0x1f;
if (boot_version < 3 || boot_version == 0x1f) {
return 1;
}
return sdk_g_ic.s.boot_info >> 7;
}
bool sdk_system_restart_enhance(uint8_t bin_type, uint32_t bin_addr) {
uint32_t current_addr;
if (!_check_boot_version()) {
return false;
}
if (bin_type == 0) {
current_addr = sdk_system_get_userbin_addr();
printf("restart to use user bin @ %x\n", bin_addr);
sdk_g_ic.s.user1_addr[0] = bin_addr;
sdk_g_ic.s.user1_addr[1] = bin_addr >> 8;
sdk_g_ic.s.user1_addr[2] = bin_addr >> 16;
sdk_g_ic.s.user0_addr[0] = current_addr;
sdk_g_ic.s.user0_addr[1] = current_addr >> 8;
sdk_g_ic.s.user0_addr[2] = current_addr >> 16;
sdk_g_ic.s._unknown1d8 = (sdk_g_ic.s._unknown1d8 & 0xfb) | 0x04;
sdk_g_ic.s.boot_info &= 0x7f;
sdk_wifi_param_save_protect(&sdk_g_ic.s);
sdk_system_restart();
return true;
} else {
if (bin_type != 1) {
printf("don't supported type.\n");
return false;
}
if (!sdk_system_get_test_result()) {
printf("test already passed.\n");
return false;
}
printf("reboot to use test bin @ %x\n", bin_addr);
sdk_g_ic.s.user0_addr[0] = bin_addr;
sdk_g_ic.s.user0_addr[1] = bin_addr >> 8;
sdk_g_ic.s.user0_addr[2] = bin_addr >> 16;
sdk_g_ic.s.boot_info &= 0xbf;
sdk_wifi_param_save_protect(&sdk_g_ic.s);
sdk_system_restart();
return true;
}
}
bool sdk_system_upgrade_userbin_set(uint8_t userbin) {
uint8_t userbin_val, userbin_mask;
uint8_t boot_ver = sdk_system_get_boot_version();
if (userbin >= 2) {
return false;
} else {
if (boot_ver == 2 || boot_ver == 0x1f) {
userbin_val = userbin & 0x0f;
userbin_mask = 0xf0;
} else {
userbin_val = userbin & 0x03;
userbin_mask = 0xfc;
}
sdk_g_ic.s._unknown1d8 = (sdk_g_ic.s._unknown1d8 & userbin_mask) | userbin_val;
return true;
}
}
uint8_t sdk_system_upgrade_userbin_check(void) {
uint8_t boot_ver = sdk_system_get_boot_version();
if (boot_ver != 0x1f && boot_ver != 2) {
if ((sdk_g_ic.s._unknown1d8 & 0x03) == 1) {
if (sdk_g_ic.s._unknown1d8 & 0x4) {
return 1;
} else {
return 0;
}
} else {
if (sdk_g_ic.s._unknown1d8 & 0x4) {
return 0;
} else {
return 1;
}
}
} else {
if ((sdk_g_ic.s._unknown1d8 & 0x0f) == 1) {
return 1;
} else {
return 0;
}
}
}
bool sdk_system_upgrade_flag_set(uint8_t flag) {
if (flag < 3) {
_system_upgrade_flag = flag;
return true;
}
return false;
}
uint8_t sdk_system_upgrade_flag_check(void) {
return _system_upgrade_flag;
}
bool sdk_system_upgrade_reboot(void) {
uint8_t boot_ver = sdk_system_get_boot_version();
uint8_t new__unknown1d8;
if (_system_upgrade_flag != 2) {
return false;
}
printf("reboot to use");
if (boot_ver != 2 && boot_ver != 0x1f) {
sdk_g_ic.s.boot_info = (sdk_g_ic.s.boot_info & 0x7f) | 0x80;
sdk_g_ic.s._unknown1d8 = (sdk_g_ic.s._unknown1d8 & 0xfb) | 0x04;
if ((sdk_g_ic.s._unknown1d8 & 0x03) == 1) {
printf("1\n");
new__unknown1d8 = sdk_g_ic.s._unknown1d8 & 0xfc;
} else {
printf("2\n");
new__unknown1d8 = (sdk_g_ic.s._unknown1d8 & 0xfc) | 0x01;
}
} else {
if ((sdk_g_ic.s._unknown1d8 & 0x0f) == 1) {
printf("1\n");
new__unknown1d8 = sdk_g_ic.s._unknown1d8 & 0xf0;
} else {
printf("2\n");
new__unknown1d8 = (sdk_g_ic.s._unknown1d8 & 0xf0) | 0x01;
}
}
sdk_g_ic.s._unknown1d8 = new__unknown1d8;
sdk_wifi_param_save_protect(&sdk_g_ic.s);
sdk_system_restart();
return true;
}
static void _deep_sleep_phase2(void *timer_arg) {
uint32_t time_in_us = (uint32_t)timer_arg;
printf("deep sleep %ds\n\n", time_in_us / 1000000);
while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(0).STATUS)) {}
while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(1).STATUS)) {}
RTC.CTRL0 = 0;
RTC.CTRL0 &= 0xffffbfff;
RTC.CTRL0 |= 0x00000030;
RTC._unknown44 = 0x00000004;
RTC._unknownc = 0x00010010;
RTC._unknown48 = (RTC._unknown48 & 0xffff01ff) | 0x0000fc00;
RTC._unknown48 = (RTC._unknown48 & 0xfffffe00) | 0x00000080;
RTC.COUNTER_ALARM = RTC.COUNTER + 136;
RTC.RESET_REASON2 = 0x00000008;
RTC.RESET_REASON0 = 0x00100000;
sdk_os_delay_us(200);
RTC.GPIO_CFG[2] = 0x00000011;
RTC.GPIO_CFG[3] = 0x00000003;
RTC._unknownc = 0x000640c8;
RTC.CTRL0 &= 0xffffffcf;
sdk_pm_rtc_clock_cali_proc();
sdk_pm_set_sleep_time(time_in_us);
RTC.GPIO_CFG[2] = 0x00000011;
RTC.GPIO_CFG[3] = 0x00000003;
DPORT.INT_ENABLE &= ~(DPORT_INT_ENABLE_WDT);
_xt_isr_mask(1 << ETS_WDT_INUM);
RTC._unknown40 = 0xffffffff;
RTC._unknown44 = 0x00000020;
RTC._unknown10 = 0x00000000;
if (time_in_us == 0) {
RTC.RESET_REASON2 = 0x00000000;
} else {
RTC.RESET_REASON2 = 0x00000008;
}
RTC.RESET_REASON0 = 0x00100000;
}
void sdk_system_deep_sleep(uint32_t time_in_us) {
if (sdk_wifi_get_opmode() != 2) {
sdk_wifi_station_stop();
}
if (sdk_wifi_get_opmode() != 1) {
sdk_wifi_softap_stop();
}
sdk_os_timer_disarm(&sdk_sta_con_timer);
// Originally deep sleep function reused sdk_sta_con_timer
// but we can't mix functions sdk_ets_timer_ with sdk_os_timer_ for the
// same timer. So now deep sleep function uses a separate timer.
sdk_ets_timer_disarm(&deep_sleep_timer);
sdk_ets_timer_setfn(&deep_sleep_timer, _deep_sleep_phase2, (void *)time_in_us);
sdk_ets_timer_arm(&deep_sleep_timer, 100, 0);
}
bool sdk_system_update_cpu_freq(uint8_t freq) {
if (freq == 80) {
DPORT.CPU_CLOCK &= ~(DPORT_CPU_CLOCK_X2);
sdk_os_update_cpu_frequency(80);
} else if (freq == 160) {
DPORT.CPU_CLOCK |= DPORT_CPU_CLOCK_X2;
sdk_os_update_cpu_frequency(160);
} else {
return false;
}
return true;
}
uint8_t sdk_system_get_cpu_freq(void) {
return sdk_os_get_cpu_frequency();
}
bool sdk_system_overclock(void) {
if (sdk_system_get_cpu_freq() == 80) {
sdk_cpu_overclock = true;
sdk_system_update_cpu_freq(160);
return true;
}
return false;
}
bool sdk_system_restoreclock(void) {
if (sdk_system_get_cpu_freq() == 160 && sdk_cpu_overclock) {
sdk_cpu_overclock = false;
sdk_system_update_cpu_freq(80);
return true;
}
return false;
}
uint32_t sdk_system_get_time(void) {
return WDEV.SYS_TIME + sdk_WdevTimOffSet;
}
uint32_t sdk_system_relative_time(uint32_t reltime) {
return WDEV.SYS_TIME - reltime;
}
void sdk_system_station_got_ip_set(struct ip_addr *ip, struct ip_addr *mask, struct ip_addr *gw) {
uint8_t *ip_bytes = (uint8_t *)&ip->addr;
uint8_t *mask_bytes = (uint8_t *)&mask->addr;
uint8_t *gw_bytes = (uint8_t *)&gw->addr;
uint32_t gpio_mask;
sdk_g_ic.v.station_netif_info->connect_status = STATION_GOT_IP;
printf("ip:%d.%d.%d.%d,mask:%d.%d.%d.%d,gw:%d.%d.%d.%d", ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3], mask_bytes[0], mask_bytes[1], mask_bytes[2], mask_bytes[3], gw_bytes[0], gw_bytes[1], gw_bytes[2], gw_bytes[3]);
printf("\n");
if ((sdk_g_ic.s.wifi_led_enable == 1) && (sdk_g_ic.s.wifi_mode == 1)) {
sdk_os_timer_disarm(&sdk_sta_con_timer);
gpio_mask = 1 << sdk_g_ic.s.wifi_led_gpio;
sdk_gpio_output_set(0, gpio_mask, gpio_mask, 0);
}
}
void sdk_system_print_meminfo(void) {
printf("%s: 0x%x ~ 0x%x, len: %d\n", "data ", _data_start, _data_end, _data_end - _data_start);
printf("%s: 0x%x ~ 0x%x, len: %d\n", "rodata", _rodata_start, _rodata_end, _rodata_end - _rodata_start);
printf("%s: 0x%x ~ 0x%x, len: %d\n", "bss ", _bss_start, _bss_end, _bss_end - _bss_start);
printf("%s: 0x%x ~ 0x%x, len: %d\n", "heap ", _heap_start, 0x3fffc000, 0x3fffc000 - _heap_start);
}
uint32_t sdk_system_get_free_heap_size(void) {
return xPortGetFreeHeapSize();
}
uint32_t sdk_system_get_chip_id(void) {
uint32_t mac0 = DPORT.OTP_MAC0 & 0xff000000;
uint32_t mac1 = DPORT.OTP_MAC1 & 0x00ffffff;
return (mac1 << 8) | (mac0 >> 24);
}
uint32_t sdk_system_rtc_clock_cali_proc(void) {
return sdk_pm_rtc_clock_cali_proc();
}
uint32_t sdk_system_get_rtc_time(void) {
return RTC.COUNTER;
}
struct sdk_rst_info *sdk_system_get_rst_info(void) {
return &sdk_rst_if;
}
static struct netif *_get_netif(uint32_t mode) {
struct sdk_g_ic_netif_info *info;
if (mode >= 2) {
return NULL;
}
if (mode == 0) {
info = sdk_g_ic.v.station_netif_info;
} else {
info = sdk_g_ic.v.softap_netif_info;
}
if (info) {
return info->netif;
}
return NULL;
}
bool sdk_wifi_station_dhcpc_start(void) {
struct netif *netif = _get_netif(0);
if (sdk_wifi_get_opmode() == 2) {
return false;
}
if (netif && sdk_dhcpc_flag == DHCP_STOPPED) {
sdk_info.ipaddr.addr = 0;
sdk_info.netmask.addr = 0;
sdk_info.gw.addr = 0;
netif_set_addr(netif, &sdk_info.ipaddr, &sdk_info.netmask, &sdk_info.gw);
if (dhcp_start(netif)) {
return false;
}
}
sdk_dhcpc_flag = DHCP_STARTED;
return true;
}
bool sdk_wifi_station_dhcpc_stop(void) {
struct netif *netif = _get_netif(0);
if (sdk_wifi_get_opmode() == 2) {
return false;
}
if (netif && sdk_dhcpc_flag == DHCP_STARTED) {
dhcp_stop(netif);
}
sdk_dhcpc_flag = DHCP_STOPPED;
return true;
}
enum sdk_dhcp_status sdk_wifi_station_dhcpc_status(void) {
return sdk_dhcpc_flag;
}
#endif /* OPEN_LIBMAIN_USER_INTERFACE */