diff --git a/components/esp8266/Makefile.projbuild b/components/esp8266/Makefile.projbuild index f8de9d8d..469e24df 100644 --- a/components/esp8266/Makefile.projbuild +++ b/components/esp8266/Makefile.projbuild @@ -82,7 +82,7 @@ CFLAGS += -D__ESP_FILE__='"null"' CXXFLAGS += -D__ESP_FILE__='"null"' endif -.PHONY: ota ota-clean +.PHONY: ota ota-clean app2 app2-flash app2-flash-all RAW_BIN := ./build/$(PROJECT_NAME).bin OTA_BIN := ./build/$(PROJECT_NAME).ota.bin @@ -97,6 +97,20 @@ __COMBILE_OTA_BIN := 1 endif endif +app2: all +ifdef CONFIG_ESPTOOLPY_FLASHSIZE_1MB + @rm -f ./build/esp8266/esp8266_out.ld + @export CFLAGS= && export CXXFLAGS= && make APP_OFFSET=$(APP2_OFFSET) APP_SIZE=$(APP2_SIZE) +endif + @echo "To flash all build output, run 'make flash' or:" + @echo $(ESPTOOLPY_WRITE_FLASH) $(APP2_OFFSET) $(APP_BIN) + +app2-flash: app2 + @$(ESPTOOLPY_WRITE_FLASH) $(APP2_OFFSET) $(APP_BIN) + +app2-flash-all: app2 + @$(ESPTOOLPY_WRITE_FLASH) $(patsubst $(APP_OFFSET),$(APP2_OFFSET),$(ESPTOOL_ALL_FLASH_ARGS)) + $(OTA1_BIN): all_binaries @cp $(RAW_BIN) $(OTA1_BIN) @echo [GEN] $(OTA1_BIN) diff --git a/components/freertos/port/esp8266/port.c b/components/freertos/port/esp8266/port.c index 6e4e7091..b0c314d3 100644 --- a/components/freertos/port/esp8266/port.c +++ b/components/freertos/port/esp8266/port.c @@ -248,22 +248,42 @@ void show_critical_info(void) ets_printf("SWReq:%u\n", SWReq); } +#ifdef ESP_DPORT_CLOSE_NMI +static int s_nmi_is_closed; + +void esp_dport_close_nmi(void) +{ + vPortEnterCritical(); + REG_WRITE(PERIPHS_DPORT_BASEADDR, REG_READ(PERIPHS_DPORT_BASEADDR) & ~0x1); + s_nmi_is_closed = 1; + vPortExitCritical(); +} + +#define ESP_NMI_IS_CLOSED() s_nmi_is_closed +#else +#define ESP_NMI_IS_CLOSED() 0 +#endif + void IRAM_ATTR vPortETSIntrLock(void) { if (NMIIrqIsOn == 0) { vPortEnterCritical(); - do { - REG_WRITE(INT_ENA_WDEV, WDEV_TSF0_REACH_INT); - } while(REG_READ(INT_ENA_WDEV) != WDEV_TSF0_REACH_INT); + if (!ESP_NMI_IS_CLOSED()) { + do { + REG_WRITE(INT_ENA_WDEV, WDEV_TSF0_REACH_INT); + } while(REG_READ(INT_ENA_WDEV) != WDEV_TSF0_REACH_INT); + } } } void IRAM_ATTR vPortETSIntrUnlock(void) { if (NMIIrqIsOn == 0) { - extern uint32_t WDEV_INTEREST_EVENT; + if (!ESP_NMI_IS_CLOSED()) { + extern uint32_t WDEV_INTEREST_EVENT; - REG_WRITE(INT_ENA_WDEV, WDEV_INTEREST_EVENT); + REG_WRITE(INT_ENA_WDEV, WDEV_INTEREST_EVENT); + } vPortExitCritical(); } } diff --git a/docs/en/api-guides/factory-test.rst b/docs/en/api-guides/factory-test.rst new file mode 100644 index 00000000..2942c21f --- /dev/null +++ b/docs/en/api-guides/factory-test.rst @@ -0,0 +1,190 @@ +Factory Test +************ + +1. Overview +=========== + +The document introduces how to develop, compile, download and run the factory test firmware. + +The factory test software development kit is also an example of the SDK, and it is located at :example:`examples/system/factory-test`. + +2. Development +============== + +Users can use ready-to-use applications directly, or can also add custom application code into the factory test software development kit. + +More details of adding customer components, please refer to :doc:`Documentation for the GNU Make based build system `. + +Users can just develop the factory test application as normal examples of the SDK. + +2.1 Application code +-------------------- + +Just like other applications, the entry function of factory test application is ``app_main``. It should be added into the source code file of users. +For example, users can add the ``app_main`` into ``main.c`` of the above sample project. + +Users can refer to the source code in file :idf_file:`/examples/system/factory-test/main/main.c` to build custom project. + + +2.2 Linking address +------------------- + +The SDK's partition only supports two applications that named as ``ota_0`` and ``ota_1``. + +In this case, we link the factory test firmware to the partition of ``ota_1``. +So, please do not flash the factory test firmware into the partition of ``ota_0``. + + +3. Compile +========== + +To make the bootloader run the ``ota_1(factory test firmware)``, +please enable the ``GPIO triggers boot from test app partition`` and set the ``correct`` GPIO of your development board in menuconfig:: + + Bootloader config ---> + [*] GPIO triggers boot from test app partition + (12) Number of the GPIO input to boot TEST partition + +Using the partition table file which has two "OTA" definitions partition:: + + Partition Table ---> + Partition Table (Factory app, two OTA definitions) ---> + (X) Factory app, two OTA definitions + +Enable the console which is used for human-computer interaction:: + + Component config ---> + Virtual file system ---> + [*] Using espressif VFS + +Enable pthread for this function:: + + Component config ---> + PThreads ---> + [*] Enable pthread + +Then call command ``make app2`` in the terminal to compile the firmware which is able to run at ``ota_1`` partition. +The ``Make System`` will start compiling bootloader, partition table file, factory test firmware and so on one by one. + + +3.1 Special Commands +==================== + +1. ``make app2``: only compile factory test firmware which is able to run at ``ota_1``, ``with`` bootloader, partition table file and so on + +2. ``make app2-flash``: flash(download) only the factory test firmware which is able to run at ``ota_1``, ``without`` bootloader, partition table file and so on + +3. ``make app2-flash-all``: flash(download) the factory test firmware which is able to run at ``ota_1``, ``with`` bootloader, partition table file and so on + + +4. Download +=========== + +Input command ``make app2-flash-all`` in the terminal to download bootloader, partition table file and factory test firmware which is located at ``ota_1`` one by one. + +If users only want to download factory test firmware, please use command ``make app2-flash`` instead. + + +5. Run +====== + +Please hold the ``correct`` GPIO, which is configured in the menuconfig in Section 3 ``Compile``, to be low level and power on. +Input command ``make monitor`` in the terminal, and then logs will appear like following:: + + ets Jan 8 2013,rst cause:1, boot mode:(3,6) + + load 0x40100000, len 7872, room 16 + 0x40100000: _stext at ??:? + + tail 0 + chksum 0xf1 + load 0x3ffe8408, len 24, room 8 + tail 0 + chksum 0x78 + load 0x3ffe8420, len 3604, room 8 + tail 12 + chksum 0x1b + I (64) boot: ESP-IDF v3.2-dev-354-gba1f90cd-dirty 2nd stage bootloader + I (64) boot: compile time 13:56:17 + I (72) qio_mode: Enabling default flash chip QIO + I (73) boot: SPI Speed : 40MHz + I (80) boot: SPI Mode : QIO + I (86) boot: SPI Flash Size : 2MB + I (92) boot: Partition Table: + I (98) boot: ## Label Usage Type ST Offset Length + I (109) boot: 0 nvs WiFi data 01 02 00009000 00004000 + I (120) boot: 1 otadata OTA data 01 00 0000d000 00002000 + I (132) boot: 2 phy_init RF data 01 01 0000f000 00001000 + I (144) boot: 3 ota_0 OTA app 00 10 00010000 000f0000 + I (155) boot: 4 ota_1 OTA app 00 11 00110000 000f0000 + I (167) boot: End of partition table + I (173) boot: No factory image, trying OTA 0 + I (5180) boot: Detect a boot condition of the test firmware + I (5180) esp_image: segment 0: paddr=0x00110010 vaddr=0x40210010 size=0x37b18 (228120) map + I (5263) esp_image: segment 1: paddr=0x00147b30 vaddr=0x3ffe8000 size=0x00718 ( 1816) load + I (5264) esp_image: segment 2: paddr=0x00148250 vaddr=0x3ffe8718 size=0x0019c ( 412) load + I (5275) esp_image: segment 3: paddr=0x001483f4 vaddr=0x40100000 size=0x084b0 ( 33968) load + 0x40100000: _stext at ??:? + + I (5299) boot: Loaded app from partition at offset 0x110000 + I (5340) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE + I (5340) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE + I (5530) phy_init: phy ver: 1055_12 + I (5530) reset_reason: RTC reset 1 wakeup 0 store 0, reason is 1 + I (5530) factory-test: SDK factory test firmware version:v3.2-dev-354-gba1f90cd-dirty + +Then users can input test commands to start factory testing. + +6. Test Commands +================ + +1. ``rftest_init``:: + + parameters: no + + function: initialize RF to prepare for test + +2. ``tx_contin_func ``:: + + parameter 1: value 1 means that chip transmits packets continuously with 92% duty cycle, + value 0 means that "iqview" test mode + + function: set test mode + +3. ``esp_tx ``:: + + parameter 1: transmit channel which ranges from 1 to 14 + parameter 2: transmit rate which ranges from 0 to 23 + parameter 2: transmit power attenuation which ranges from -127 to 127, unit is 0.25dB + + function: start transmitting Wi-Fi packets + + note 1: command "wifitxout" is the same as "esp_tx" + note 2: the function can be stopped by command "cmdstop" + +4. ``esp_rx ``:: + + parameter 1: transmit channel which ranges from 1 to 14 + parameter 2: transmit rate which ranges from 0 to 23 + + function: start receiving Wi-Fi packets + + note 1: the function can be stopped by command "cmdstop" + +5. ``wifiscwout ``:: + + parameter 1: enable signal, value 1 means enable, value 0 means disable + parameter 2: transmit channel which ranges from 1 to 14 + parameter 3: transmit power attenuation which ranges from -127 to 127, unit is 0.25dB + + function: start transmitting single carrier Wi-Fi packets + + note 1: the function can be stopped by command "cmdstop" + +6. ``cmdstop``:: + + parameters: no + + function: stop transmitting or receiving Wi-Fi packets + + note 1: command "CmdStop" is the same as "cmdstop" diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index a65df392..6757c5e4 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -9,3 +9,4 @@ API Guides System Task PWM and Sniffer Coexists FOTA from an Old SDK to the New ESP8266 RTOS SDK (IDF Style) + Factory Test diff --git a/examples/system/factory-test/Kconfig.projbuild b/examples/system/factory-test/Kconfig.projbuild new file mode 100644 index 00000000..96c07577 --- /dev/null +++ b/examples/system/factory-test/Kconfig.projbuild @@ -0,0 +1,10 @@ +menu "Factory-test config" + +config FACTORY_TEST + bool "Enable factory test" + default n + select BOOTLOADER_INIT_SPI_FLASH + help + Enable this option, project compiling script will generate factory test firmware. + +endmenu diff --git a/examples/system/factory-test/Makefile b/examples/system/factory-test/Makefile new file mode 100644 index 00000000..bf6a55cf --- /dev/null +++ b/examples/system/factory-test/Makefile @@ -0,0 +1,4 @@ + +PROJECT_NAME := factory-test + +include $(IDF_PATH)/make/project.mk diff --git a/examples/system/factory-test/README.md b/examples/system/factory-test/README.md new file mode 100644 index 00000000..f54fca64 --- /dev/null +++ b/examples/system/factory-test/README.md @@ -0,0 +1,4 @@ + +# Important + +Please refer to the document at *docs/en/api-guides/factory-test.rst*. diff --git a/examples/system/factory-test/components/rf_test/Kconfig b/examples/system/factory-test/components/rf_test/Kconfig new file mode 100644 index 00000000..1ed4fc48 --- /dev/null +++ b/examples/system/factory-test/components/rf_test/Kconfig @@ -0,0 +1,9 @@ +menu "Nano Console" + +config NC_ECHO_CMD + bool "echo input command" + default y + help + Enable this option, the console terminal will echo the input command. + +endmenu diff --git a/examples/system/factory-test/components/rf_test/Makefile.projbuild b/examples/system/factory-test/components/rf_test/Makefile.projbuild new file mode 100644 index 00000000..962ded17 --- /dev/null +++ b/examples/system/factory-test/components/rf_test/Makefile.projbuild @@ -0,0 +1,2 @@ + +CFLAGS += -DESP_DPORT_CLOSE_NMI diff --git a/examples/system/factory-test/components/rf_test/component.mk b/examples/system/factory-test/components/rf_test/component.mk new file mode 100644 index 00000000..eaa7ce0b --- /dev/null +++ b/examples/system/factory-test/components/rf_test/component.mk @@ -0,0 +1,8 @@ +# +# Component Makefile +# + +LIBS := rftest + +COMPONENT_ADD_LDFLAGS += -L$(COMPONENT_PATH)/lib $(addprefix -l,$(LIBS)) +COMPONENT_ADD_LINKER_DEPS += $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) diff --git a/examples/system/factory-test/components/rf_test/include/esp_rftest.h b/examples/system/factory-test/components/rf_test/include/esp_rftest.h new file mode 100644 index 00000000..cc2d4b96 --- /dev/null +++ b/examples/system/factory-test/components/rf_test/include/esp_rftest.h @@ -0,0 +1,81 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize RF test module + */ +void rftest_init(void); + +/** + * @brief Set TX testing mode + * + * @param mode testing mode, 1 means continuous Wi-Fi packets transmission with 92% duty cycle + * 0 means default mode for iqview testing + */ +void tx_contin_func(uint8_t mode); + +/** + * @brief TX testing function, continuously sending Wi-Fi packets at "while(1)" loop + * + * @param channel Wi-Fi TX channel, it ranges from 1 to 14 + * @param rate Wi-Fi TX rate, it ranges from 1 to 23 + * @param attenuation Wi-Fi TX power attenuation, it ranges from 1 to 127 and its unit is 0.25dB. + * For example, 1 means 0.25dB, 2 means 0.5 dB and so on. + */ +void esp_tx_func(uint32_t channel, uint32_t rate, uint32_t attenuation); + +/** + * @brief RX testing function, continuously receiving Wi-Fi packets at "while(1)" loop + * + * @param channel Wi-Fi RX channel, it ranges from 1 to 14 + * @param rate Wi-Fi RX rate, it ranges from 1 to 23 + */ +void esp_rx_func(uint32_t channel, uint32_t rate); + +/** + * @brief Single carrier TX testing function + * + * @param enable enable signal, 1 means starting sending, 0 means stopping sending + * @param channel Wi-Fi RX channel, it ranges from 1 to 14 + * @param attenuation Wi-Fi TX power attenuation, it ranges from 1 to 127 and its unit is 0.25dB. + * For example, 1 means 0.25dB, 2 means 0.5 dB and so on. + */ +void wifiscwout_func(uint32_t enable, uint32_t channel, uint32_t attenuation); + +/** + * @brief Stop sending or recieving Wi-Fi packets + * + * @return + * - 0 receiving stop TX commands "cmdstop" or "CmdStop" and TX is stopped + * - 2 receiving error commands and TX will not stop + * - 3 receiving no commands + */ +int cmdstop_callback(void); + +/** + * @brief Register RF test command for console + */ +void esp_console_register_rftest_command(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/system/factory-test/components/rf_test/include/nano_console.h b/examples/system/factory-test/components/rf_test/include/nano_console.h new file mode 100644 index 00000000..10d3dec0 --- /dev/null +++ b/examples/system/factory-test/components/rf_test/include/nano_console.h @@ -0,0 +1,69 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*nc_func_t)(int argc, char **argv); + +/** + * @brief Command data structure + */ +typedef struct _nc_cmd { + SLIST_ENTRY(_nc_cmd) entries; //!< queue entry + const char *name; //!< command name + nc_func_t func; //!< command callback function +} nc_cmd_t; + +typedef nc_cmd_t* nc_cmd_handle_t; + +/** + * @brief Initialize nano console + * + * @return 0 if success or others if fail + */ +int nc_init(void); + +/** + * @brief Register a command to nano console core + * + * @param[out] handle created command handle to users + * @param[in] name command name + * @param[in] func command callback function + * + * @return 0 if success or others if fail + * + * @note The function only can be called before "nc_init" + */ +int nc_register_cmd(nc_cmd_handle_t *handle, const char *name, nc_func_t func); + +/** + * @brief Output formated string through nano console I/O stream + * + * @param[in] fmt format string + * @param[in] ... command arguments' value list + * + * @return output string number or negative value if fail + */ +int nc_printf(const char *fmt, ...); + +#ifdef __cplusplus +} +#endif diff --git a/examples/system/factory-test/components/rf_test/lib/librftest.a b/examples/system/factory-test/components/rf_test/lib/librftest.a new file mode 100644 index 00000000..8feb0222 Binary files /dev/null and b/examples/system/factory-test/components/rf_test/lib/librftest.a differ diff --git a/examples/system/factory-test/components/rf_test/nano_console.c b/examples/system/factory-test/components/rf_test/nano_console.c new file mode 100644 index 00000000..af898526 --- /dev/null +++ b/examples/system/factory-test/components/rf_test/nano_console.c @@ -0,0 +1,296 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define LOG_LOCAL_LEVEL ESP_LOG_NONE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "esp_log.h" +#include "nano_console.h" + +#define TAG "nano_console" +#define NC_READ_BUF 128 + +static SLIST_HEAD(_nc_cmd_head , _nc_cmd) s_nc_cmd = SLIST_HEAD_INITIALIZER(s_nc_cmd); + +static inline nc_cmd_t *get_cmd(const char *buf) +{ + nc_cmd_t *it; + + SLIST_FOREACH(it, &s_nc_cmd, entries) { + if (!strcmp(it->name, buf)) { + ESP_LOGD(TAG, "%s finds command %s", __func__, buf); + return it; + } + } + + ESP_LOGD(TAG, "%s has not found command %s", __func__, buf); + + return NULL; +} + +static void free_args(uintptr_t *argv) +{ + int num = (int)argv[0]; + + for (int i = 1; i < num; i++) { + if (argv[i]) + free((void *)argv[i]); + else { + ESP_LOGD(TAG, "%s checks command input arguments number %d is empty", __func__, i); + } + } + + free(argv); +} + +static uintptr_t *alloc_args(const char *buf, int num) +{ + const char *p = buf; + uintptr_t *argv_buf; + int cnt = 0; + + for (int i = 0; i < num; i++) { + if (p[i] == '\0') + cnt++; + } + + argv_buf = calloc(1, (cnt + 1) * sizeof(uintptr_t)); + if (!argv_buf) { + ESP_LOGE(TAG, "%s allocates memory for arguments table fail", __func__); + return NULL; + } + argv_buf[0] = (uintptr_t)cnt + 1; + + for (int i = 0; i < cnt; i++) { + int len = strlen(p) + 1; + char *s = malloc(len); + if (!s) { + ESP_LOGE(TAG, "%s allocates memory for arguments %d fail", __func__, i); + goto fail; + } + memcpy(s, p, len); + + p += len; + argv_buf[i + 1] = (uintptr_t)s; + } + + return argv_buf; + +fail: + free_args(argv_buf); + return NULL; +} + +static void *nc_thread_entry(void *p) +{ + int num = 0; + char *pbuf; + + pbuf = malloc(NC_READ_BUF); + if (!pbuf) { + ESP_LOGE(TAG, "%s malloc %d bytes buffer fail", __func__, NC_READ_BUF); + goto nomem; + } + + while (1) { + int ret; + size_t rbytes; + char c; + + rbytes = fread(&c, 1, 1, stdin); + if (rbytes != 1) { + ESP_LOGE(TAG, "%s read character fail", __func__); + goto io_err; + } + + if (num >= NC_READ_BUF - 1) { + ESP_LOGD(TAG, "%s input stream overflows, reset the buffer", __func__); + num = 0; + continue; + } + + if (!isascii(c)) { + ESP_LOGD(TAG, "%s input character is not ASCII", __func__); + continue; + } + + if (c == '\r' || c == '\n') { + nc_cmd_t *cmd; + +#ifdef CONFIG_NC_ECHO_CMD + ret = fwrite(&c, 1, 1, stdout); + if (ret != 1) { + ESP_LOGE(TAG, "%s %d write character fail %d", __func__, __LINE__, ret); + goto io_err; + } +#endif + + if (!num) { + ESP_LOGD(TAG, "%s gets command %s argument fail", __func__, cmd->name); + continue; + } + + if (pbuf[num - 1] != '\0') + pbuf[num++] = '\0'; + + cmd = get_cmd(pbuf); + if (cmd) { + uintptr_t *argv; + + argv = alloc_args(pbuf, num); + if (!argv) { + ESP_LOGE(TAG, "%s gets command %s argument fail", __func__, cmd->name); + num = 0; + continue; + } + + cmd->func((int)argv[0] - 1, (char **)(&argv[1])); + + free_args(argv); + } + + num = 0; + } else if (c == ' ') { + if (num && pbuf[num] != ' ') { + pbuf[num++] = '\0'; +#ifdef CONFIG_NC_ECHO_CMD + ret = fwrite(&c, 1, 1, stdout); + if (ret != 1) { + ESP_LOGE(TAG, "%s %d write character fail %d", __func__, __LINE__, ret); + goto io_err; + } +#endif + } + } else if (c == 0x8 || c == 0x7f) { + if (num) { + num--; +#ifdef CONFIG_NC_ECHO_CMD + char tmp[3] = {c, ' ', c}; + + ret = fwrite(&tmp, 1, 3, stdout); + if (ret != 3) { + ESP_LOGE(TAG, "%s %d write character fail %d", __func__, __LINE__, ret); + goto io_err; + } +#endif + } + } else { + pbuf[num++] = c; +#ifdef CONFIG_NC_ECHO_CMD + ret = fwrite(&c, 1, 1, stdout); + if (ret != 1) { + ESP_LOGE(TAG, "%s %d write character fail %d", __func__, __LINE__, ret); + goto io_err; + } +#endif + } + } + +io_err: + free(pbuf); +nomem: + return (void *)(-ENOMEM); +} + +/** + * @brief Initialize nano console + */ +int nc_init(void) +{ + int ret; + pthread_t tid; + + ret = pthread_create(&tid, NULL, nc_thread_entry, NULL); + if (ret) { + ESP_LOGE(TAG, "%s creates thread fail %d", __func__, ret); + return -1; + } + + return 0; +} + +/** + * @brief Register a command to nano console core + */ +int nc_register_cmd(nc_cmd_handle_t *handle, const char *name, nc_func_t func) +{ + int len; + va_list ap; + nc_cmd_t *cmd; + + cmd = malloc(sizeof(nc_cmd_t)); + if (!cmd) { + ESP_LOGE(TAG, "%s alloc memory %d fail", __func__, __LINE__); + return -ENOMEM; + } + + len = strlen(name) + 1; + cmd->name = malloc(len); + if (!cmd->name) { + ESP_LOGE(TAG, "%s alloc memory %d fail", __func__, __LINE__); + goto nomem; + } + + memcpy((char *)cmd->name, name, len); + cmd->func = func; + + SLIST_INSERT_HEAD(&s_nc_cmd, cmd, entries); + + *handle = cmd; + + va_end(ap); + + return 0; + +nomem: + free(cmd); + return -ENOMEM; +} + +/** + * @brief Output formated string through nano console I/O stream + */ +int nc_printf(const char *fmt, ...) +{ + va_list ap; + char *pbuf; + + va_start(ap, fmt); + + int ret = vasprintf(&pbuf, fmt, ap); + if (ret < 0) + goto fail; + + ret = fwrite(pbuf, 1, ret, stdout); + + free(pbuf); + + va_end(ap); + + return ret; + +fail: + va_end(ap); + return -ENOMEM; +} diff --git a/examples/system/factory-test/components/rf_test/rftest_command.c b/examples/system/factory-test/components/rf_test/rftest_command.c new file mode 100644 index 00000000..1241c397 --- /dev/null +++ b/examples/system/factory-test/components/rf_test/rftest_command.c @@ -0,0 +1,417 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include "esp_rftest.h" +#include "esp_log.h" +#include "esp_wifi.h" +#include "esp8266/eagle_soc.h" +#include "FreeRTOS.h" +#include "task.h" +#include "driver/soc.h" +#include "nano_console.h" + +#define TAG "factory-test" + +typedef struct tx_param { + uint32_t channel; + uint32_t rate; + uint32_t attenuation; +} tx_param_t; + +typedef struct rx_param { + uint32_t channel; + uint32_t rate; +} rx_param_t; + +typedef struct wifiscwout_param { + uint32_t en; + uint32_t channel; + uint32_t attenuation; +} wifiscwout_param_t; + +static int s_cmdstop = 0; + +static int set_wifi_work(void) +{ + int ret; + esp_irqflag_t flag; + + flag = soc_save_local_irq(); + + if (s_cmdstop == 0) { + s_cmdstop = 3; + ret = 0; + } else + ret = -EINPROGRESS; + + soc_restore_local_irq(flag); + + return ret; +} + +static int set_wifi_free(void) +{ + esp_irqflag_t flag; + + flag = soc_save_local_irq(); + + s_cmdstop = 0; + + soc_restore_local_irq(flag); + + return 0; +} + +static int test_rftest_init(int argc, char **argv) +{ + if (argc != 1) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + ESP_LOGD(__func__, "%s start initializing WiFi test", __func__); + + if (set_wifi_work()) + goto exit; + + rftest_init(); + + set_wifi_free(); + + ESP_LOGD(__func__, "%s end initializing WiFi test", __func__); + + return 0; + +exit: + ESP_LOGD(__func__, "%s fail to initialize WiFi test", __func__); + + return -EINPROGRESS; +} + +static int test_tx_contin_en(int argc, char **argv) +{ + if (argc != 2) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int mode = atoi(argv[1]); + if (mode < 0 || mode > 1) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + ESP_LOGD(__func__, "%s start setting mode '%d'", __func__ , mode); + + if (set_wifi_work()) + goto exit; + + tx_contin_func(mode); + + set_wifi_free(); + + ESP_LOGD(__func__, "%s end setting mode '%d'", __func__ , mode); + + return 0; + +exit: + ESP_LOGD(__func__, "%s fail to set mode '%d'", __func__ , mode); + + return -EINPROGRESS; +} + +static void test_wifi_tx_thread(void *param) +{ + tx_param_t *tx_param = (tx_param_t *)param; + + esp_tx_func(tx_param->channel, tx_param->rate, tx_param->attenuation); + + free(tx_param); + + set_wifi_free(); + + vTaskDelete(NULL); +} + +static int test_esp_tx_func(int argc, char **argv) +{ + if (argc != 4) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int channel = atoi(argv[1]); + if (channel <= 0 || channel > 14) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int rate = atoi(argv[2]); + if (rate < 0 || rate > 23) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int attenuation = atoi(argv[3]); + if (attenuation < -127 || attenuation > 127) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + ESP_LOGD(__func__, "%s start creating task with channel '%d' rate '%d' attenuation '%d'", __func__, channel, rate, attenuation); + + if (set_wifi_work()) + goto exit; + + tx_param_t *tx_param = malloc(sizeof(tx_param_t)); + if (!tx_param) + goto exit; + + tx_param->channel = channel; + tx_param->rate = rate; + tx_param->attenuation = attenuation; + + const size_t wifi_tx_stk_size = 4096; + const size_t wifi_tx_priority = 3; + + BaseType_t ret = xTaskCreate(test_wifi_tx_thread, "wifi_tx", wifi_tx_stk_size, tx_param, wifi_tx_priority, NULL); + if (ret != pdPASS) + goto task_err; + + ESP_LOGD(__func__, "%s end creating task with channel '%d' rate '%d' attenuation '%d'", __func__, channel, rate, attenuation); + + return 0; + +task_err: + free(tx_param); +exit: + ESP_LOGD(__func__, "%s fail to create task with channel '%d' rate '%d' attenuation '%d'", __func__, channel, rate, attenuation); + + return -ENOMEM; +} + +static void test_wifi_rx_thread(void *param) +{ + rx_param_t *rx_param = (rx_param_t *)param; + + esp_rx_func(rx_param->channel, rx_param->rate); + + free(rx_param); + + set_wifi_free(); + + vTaskDelete(NULL); +} + +static int test_esp_rx_func(int argc, char **argv) +{ + if (argc != 3) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int channel = atoi(argv[1]); + if (channel <= 0 || channel > 14) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int rate = atoi(argv[2]); + if (rate < 0 || rate > 23) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + ESP_LOGD(__func__, "%s start creating task with channel '%d' rate '%d'", __func__, channel, rate); + + if (set_wifi_work()) + goto exit; + + rx_param_t *rx_param = malloc(sizeof(rx_param_t)); + if (!rx_param) + goto exit; + + rx_param->channel = channel; + rx_param->rate = rate; + + const size_t wifi_rx_stk_size = 4096; + const size_t wifi_rx_priority = 3; + + BaseType_t ret = xTaskCreate(test_wifi_rx_thread, "wifi_rx", wifi_rx_stk_size, rx_param, wifi_rx_priority, NULL); + if (ret != pdPASS) + goto task_err; + + ESP_LOGD(__func__, "%s end creating task with channel '%d' rate '%d'", __func__, channel, rate); + + return 0; + +task_err: + free(rx_param); +exit: + ESP_LOGD(__func__, "%s fail to create task with channel '%d' rate '%d'", __func__, channel, rate); + + return -ENOMEM; +} + +static void test_wifi_wifiscwout_thread(void *param) +{ + wifiscwout_param_t *wifiscwout_param = (wifiscwout_param_t *)param; + + wifiscwout_func(wifiscwout_param->en, wifiscwout_param->channel, wifiscwout_param->attenuation); + + free(wifiscwout_param); + + set_wifi_free(); + + vTaskDelete(NULL); +} + +static int test_wifiscwout_func(int argc, char **argv) +{ + if (argc != 4) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int en = atoi(argv[1]); + if (en < 0 || en > 2) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int channel = atoi(argv[2]); + if (channel <= 0 || channel > 14) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + int attenuation = atoi(argv[3]); + if (attenuation < -127 || attenuation > 127) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + ESP_LOGD(__func__, "%s start creating task with enable '%d' channel '%d' attenuation '%d'", __func__, en, channel, attenuation); + + if (set_wifi_work()) + goto exit; + + wifiscwout_param_t *wifiscwout_param = malloc(sizeof(wifiscwout_param_t)); + if (!wifiscwout_param) + goto exit; + + wifiscwout_param->en = en; + wifiscwout_param->channel = channel; + wifiscwout_param->attenuation = attenuation; + + const size_t wifi_wifiscwout_stk_size = 4096; + const size_t wifi_wifiscwout_priority = 3; + + BaseType_t ret = xTaskCreate(test_wifi_wifiscwout_thread, "wifi_tx", wifi_wifiscwout_stk_size, wifiscwout_param, wifi_wifiscwout_priority, NULL); + if (ret != pdPASS) + goto task_err; + + ESP_LOGD(__func__, "%s end creating task with enable '%d' channel '%d' attenuation '%d'", __func__, en, channel, attenuation); + + return 0; + +task_err: + free(wifiscwout_param); +exit: + ESP_LOGD(__func__, "%s fail to create task with enable '%d' channel '%d' attenuation '%d'", __func__, en, channel, attenuation); + + return -ENOMEM; +} + +static int test_cmdstop_func(int argc, char **argv) +{ + if (argc != 1) { + ESP_LOGE(TAG, "%s %d command is error", __func__, __LINE__); + return -EINVAL; + } + + ESP_LOGD(__func__, "%s cmdstop '%d'", __func__, s_cmdstop); + + s_cmdstop = 0; + + ESP_LOGD(__func__, "status is %x\n", REG_READ(INT_ENA_WDEV)); + + return 0; +} + +static void register_rftest_init(void) +{ + nc_cmd_t *nc_cmd; + + ESP_ERROR_CHECK(nc_register_cmd(&nc_cmd, "rftest_init", test_rftest_init)); +} + +static void register_tx_contin_en(void) +{ + nc_cmd_handle_t nc_cmd; + + ESP_ERROR_CHECK(nc_register_cmd(&nc_cmd, "tx_contin_en", test_tx_contin_en)); +} + +static void register_esp_tx_func(void) +{ + nc_cmd_handle_t nc_cmd; + + ESP_ERROR_CHECK(nc_register_cmd(&nc_cmd, "esp_tx", test_esp_tx_func)); + ESP_ERROR_CHECK(nc_register_cmd(&nc_cmd, "wifitxout", test_esp_tx_func)); +} + +static void register_esp_rx_func(void) +{ + nc_cmd_handle_t nc_cmd; + + ESP_ERROR_CHECK(nc_register_cmd(&nc_cmd, "esp_rx", test_esp_rx_func)); +} + +static void register_wifiscwout_func(void) +{ + nc_cmd_handle_t nc_cmd; + + ESP_ERROR_CHECK(nc_register_cmd(&nc_cmd, "wifiscwout", test_wifiscwout_func)); +} + +static void register_cmdstop_func(void) +{ + nc_cmd_handle_t nc_cmd; + + ESP_ERROR_CHECK(nc_register_cmd(&nc_cmd, "cmdstop", test_cmdstop_func)); + ESP_ERROR_CHECK(nc_register_cmd(&nc_cmd, "CmdStop", test_cmdstop_func)); +} + +void esp_console_register_rftest_command(void) +{ + extern void esp_dport_close_nmi(void); + + esp_dport_close_nmi(); + + register_rftest_init(); + register_tx_contin_en(); + register_esp_tx_func(); + register_esp_rx_func(); + register_wifiscwout_func(); + register_cmdstop_func(); +} + +int __attribute__((weak)) cmdstop_callback(void) +{ + return s_cmdstop; +} diff --git a/examples/system/factory-test/main/component.mk b/examples/system/factory-test/main/component.mk new file mode 100644 index 00000000..de55b61f --- /dev/null +++ b/examples/system/factory-test/main/component.mk @@ -0,0 +1,6 @@ +# +# Main factory-test Makefile. +# +# This is basically the same as a component makefile, but in the case of the factory-test +# we pull in factory-test-specific linker arguments. +# diff --git a/examples/system/factory-test/main/main.c b/examples/system/factory-test/main/main.c new file mode 100644 index 00000000..772bd35d --- /dev/null +++ b/examples/system/factory-test/main/main.c @@ -0,0 +1,72 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "esp_system.h" +#include "esp_rftest.h" +#include "esp_log.h" +#include "esp_vfs_dev.h" +#include "FreeRTOS.h" +#include "driver/uart.h" +#include "nano_console.h" +#include "esp_libc.h" + +#ifndef ESP_FACTORY_TEST_EXTRA_COMPONENTS + +#define CONFIG_CONSOLE_UART_NUM 0 + +#define TAG "factory-test" + +static void initialize_console() +{ + /* Disable buffering on stdin */ + setvbuf(stdin, NULL, _IONBF, 0); + + /* Minicom, screen, idf_monitor send CR when ENTER key is pressed */ + esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + /* Move the caret to the beginning of the next line on '\n' */ + esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); + + /* Configure UART. Note that REF_TICK is used so that the baud rate remains + * correct while APB frequency is changing in light sleep mode. + */ + uart_config_t uart_config = { + .baud_rate = CONFIG_CONSOLE_UART_BAUDRATE, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + }; + ESP_ERROR_CHECK(uart_param_config(CONFIG_CONSOLE_UART_NUM, &uart_config)); + + /* Install UART driver for interrupt-driven reads and writes */ + ESP_ERROR_CHECK(uart_driver_install(CONFIG_CONSOLE_UART_NUM, + 256, 0, 0, NULL)); + + /* Tell VFS to use UART driver */ + esp_vfs_dev_uart_use_driver(CONFIG_CONSOLE_UART_NUM); + + esp_console_register_rftest_command(); + + ESP_ERROR_CHECK(nc_init()); +} + +void __attribute__((weak)) app_main(void) +{ + ESP_LOGI(TAG, "SDK factory test firmware version:%s\n", esp_get_idf_version()); + + initialize_console(); +} + +#endif /* ESP_FACTORY_TEST_EXTRA_COMPONENTS */ diff --git a/examples/system/factory-test/sdkconfig.defaults b/examples/system/factory-test/sdkconfig.defaults new file mode 100644 index 00000000..5ca96d27 --- /dev/null +++ b/examples/system/factory-test/sdkconfig.defaults @@ -0,0 +1,21 @@ +# +# Virtual file system +# +CONFIG_USING_ESP_VFS=y + +# +# PThreads +# +CONFIG_ENABLE_PTHREAD=y + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_TWO_OTA=y + +# +# Bootloader config +# +CONFIG_BOOTLOADER_APP_TEST=y +CONFIG_BOOTLOADER_APP_TEST_IN_OTA_1=y +CONFIG_BOOTLOADER_NUM_PIN_APP_TEST=12