diff --git a/src/Makefile b/src/Makefile index 826880a83..9aeb957d7 100755 --- a/src/Makefile +++ b/src/Makefile @@ -145,7 +145,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/, \ framebuffer.o \ array.o \ usbdbg.o \ - wifi_dbg.o \ + wifidbg.o \ cambus.o \ ov9650.o \ ov2640.o \ diff --git a/src/micropython b/src/micropython index a4e78c2b6..857040fe2 160000 --- a/src/micropython +++ b/src/micropython @@ -1 +1 @@ -Subproject commit a4e78c2b6e493d922a25c00cf458bf443da748af +Subproject commit 857040fe2669ba2a4066e8426cd7732b69cd713d diff --git a/src/omv/Makefile b/src/omv/Makefile index 923399d1a..c0f07fe66 100644 --- a/src/omv/Makefile +++ b/src/omv/Makefile @@ -9,7 +9,7 @@ SRCS += $(addprefix , \ framebuffer.c \ array.c \ usbdbg.c \ - wifi_dbg.c \ + wifidbg.c \ cambus.c \ ov9650.c \ ov2640.c \ diff --git a/src/omv/main.c b/src/omv/main.c index ac29cfc08..b13afb0a4 100644 --- a/src/omv/main.c +++ b/src/omv/main.c @@ -53,7 +53,7 @@ #include "sensor.h" #include "usbdbg.h" -#include "wifi_dbg.h" +#include "wifidbg.h" #include "sdram.h" #include "fb_alloc.h" #include "ff_wrapper.h" @@ -277,7 +277,8 @@ void NORETURN __stack_chk_fail(void) #endif typedef struct openmv_config { - wifi_dbg_config_t wifi_dbg_config; + bool wifidbg; + wifidbg_config_t wifidbg_config; } openmv_config_t; int ini_handler_callback(void *user, const char *section, const char *name, const char *value) @@ -286,7 +287,7 @@ int ini_handler_callback(void *user, const char *section, const char *name, cons #define MATCH(s, n) ((strcmp(section, (s)) == 0) && (strcmp(name, (n)) == 0)) - if (MATCH("BootSettings", "REPLUart")) { + if (MATCH("BoardConfig", "REPLUart")) { if (ini_is_true(value)) { mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(3), // UART Port @@ -295,22 +296,18 @@ int ini_handler_callback(void *user, const char *section, const char *name, cons MP_STATE_PORT(pyb_stdio_uart) = pyb_uart_type.make_new((mp_obj_t) &pyb_uart_type, MP_ARRAY_SIZE(args), 0, args); } - } else if (MATCH("BootSettings", "WiFiMode")) { - openmv_config->wifi_dbg_config.wifi_mode = ini_atoi(value); - } else if (MATCH("BootSettings", "ClientModeSSID")) { - strncpy(openmv_config->wifi_dbg_config.wifi_client_ssid, name, SSID_MAX); - } else if (MATCH("BootSettings", "ClientModePass")) { - strncpy(openmv_config->wifi_dbg_config.wifi_client_pass, name, PASS_MAX); - } else if (MATCH("BootSettings", "ClientModeType")) { - openmv_config->wifi_dbg_config.wifi_client_type = ini_atoi(value); - } else if (MATCH("BootSettings", "AccessPointModeSSID")) { - strncpy(openmv_config->wifi_dbg_config.wifi_ap_ssid, name, SSID_MAX); - } else if (MATCH("BootSettings", "AccessPointModePass")) { - strncpy(openmv_config->wifi_dbg_config.wifi_ap_pass, name, SSID_MAX); - } else if (MATCH("BootSettings", "AccessPointModeType")) { - openmv_config->wifi_dbg_config.wifi_ap_type = ini_atoi(value); - } else if (MATCH("BootSettings", "BoardName")) { - strncpy(openmv_config->wifi_dbg_config.wifi_board_name, name, NAME_MAX); + } else if (MATCH("BoardConfig", "WiFiDebug")) { + openmv_config->wifidbg = ini_is_true(value); + } else if (MATCH("WiFiConfig", "Mode")) { + openmv_config->wifidbg_config.mode = ini_atoi(value); + } else if (MATCH("WiFiConfig", "SSID")) { + strncpy(openmv_config->wifidbg_config.ssid, value, WINC_MAX_SSID_LEN); + } else if (MATCH("WiFiConfig", "Key")) { + strncpy(openmv_config->wifidbg_config.key, value, WINC_MAX_PSK_LEN); + } else if (MATCH("WiFiConfig", "Security")) { + openmv_config->wifidbg_config.security = ini_atoi(value); + } else if (MATCH("WiFiConfig", "Channel")) { + openmv_config->wifidbg_config.channel = ini_atoi(value); } else { return 0; } @@ -446,7 +443,6 @@ soft_reset: py_fir_init0(); servo_init(); usbdbg_init(); - wifi_dbg_init(); sdcard_init(); if (first_soft_reset) { @@ -519,10 +515,15 @@ soft_reset: MP_STATE_PORT(vfs_cur) = vfs; // Parse OpenMV configuration file. + openmv_config_t openmv_config; if (first_soft_reset) { - openmv_config_t openmv_config = {0}; + memset(&openmv_config, 0, sizeof(openmv_config)); + // Parse config, and init wifi if enabled. ini_parse(&vfs_fat->fatfs, "/openmv.config", ini_handler_callback, &openmv_config); - wifi_dbg_apply_config(&openmv_config.wifi_dbg_config); + if (openmv_config.wifidbg == true && + wifidbg_init(&openmv_config.wifidbg_config) != 0) { + openmv_config.wifidbg = false; + } } // Run boot script(s) @@ -549,48 +550,56 @@ soft_reset: led_state(LED_GREEN, 0); led_state(LED_BLUE, 0); + if (openmv_config.wifidbg == true) { + timer_tim5_init(); + } + // Run boot script(s) if (first_soft_reset) { exec_boot_script("/selftest.py", true, false); exec_boot_script("/main.py", false, true); } - // If there's no script ready, just re-exec REPL - while (!usbdbg_script_ready()) { - nlr_buf_t nlr; + do { + usbdbg_init(); - if (nlr_push(&nlr) == 0) { - // enable IDE interrupt - usbdbg_set_irq_enabled(true); + // If there's no script ready, just re-exec REPL + while (!usbdbg_script_ready()) { + nlr_buf_t nlr; - // run REPL - if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { - if (pyexec_raw_repl() != 0) { - break; - } - } else { - if (pyexec_friendly_repl() != 0) { - break; + if (nlr_push(&nlr) == 0) { + // enable IDE interrupt + usbdbg_set_irq_enabled(true); + + // run REPL + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if (pyexec_raw_repl() != 0) { + break; + } + } else { + if (pyexec_friendly_repl() != 0) { + break; + } } + + nlr_pop(); } - - nlr_pop(); } - } - if (usbdbg_script_ready()) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - // Enable IDE interrupt - usbdbg_set_irq_enabled(true); + if (usbdbg_script_ready()) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + // Enable IDE interrupt + usbdbg_set_irq_enabled(true); - // Execute the script. - pyexec_str(usbdbg_get_script()); - nlr_pop(); - } else { - mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + // Execute the script. + pyexec_str(usbdbg_get_script()); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + } } - } + } while (openmv_config.wifidbg == true); // Disable all other IRQs except Systick and Flash IRQs // Note: FS IRQ is disable, since we're going for a soft-reset. diff --git a/src/omv/usbdbg.h b/src/omv/usbdbg.h index 191eeacd7..e76e768a3 100644 --- a/src/omv/usbdbg.h +++ b/src/omv/usbdbg.h @@ -54,4 +54,7 @@ vstr_t *usbdbg_get_script(); bool usbdbg_get_irq_enabled(); void usbdbg_set_irq_enabled(bool enabled); void usbdbg_set_script_running(bool running); +void usbdbg_data_in(void *buffer, int length); +void usbdbg_data_out(void *buffer, int length); +void usbdbg_control(void *buffer, uint8_t brequest, uint32_t wlength); #endif /* __USBDBG_H__ */ diff --git a/src/omv/wifi_dbg.c b/src/omv/wifi_dbg.c deleted file mode 100644 index 05e14229e..000000000 --- a/src/omv/wifi_dbg.c +++ /dev/null @@ -1,65 +0,0 @@ -/* This file is part of the OpenMV project. - * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman - * This work is licensed under the MIT license, see the file LICENSE for details. - */ - -#include -#include "wifi_dbg.h" - -// To avoid writing extra code just re-use the USBDBG code as the interface that does the actual work. -// The only tricky part is that you don't have USB transactions anymore. So, you need to buffer 6 bytes -// in a fifo until you have 6 of them to execute a control phase. Then, push the rest into the data phase -// as described by the length in the control phase header. Buffering on the wifi network will definately -// cause all RX bytes to be in one long giant burst. You have to write the code to handle this... - -extern void usbdbg_data_in(void *buffer, int length); -extern void usbdbg_data_out(void *buffer, int length); -extern void usbdbg_control(void *buffer, uint8_t brequest, uint32_t wlength); - -void wifi_dbg_init() -{ - // Get wifi debug into a known state. Since this is called by all OpenMV Cams you should not toggle any - // pins unless you detect the wifi module was previously setup... - // Also, reset regular USB CDC DBG access if things were setup before. -} - -void wifi_dbg_apply_config(wifi_dbg_config_t *config) -{ - switch(config->wifi_mode) { - case WIFI_DBG_DISABLED: // Don't init anything. - break; - case WIFI_DBG_ENABLED_CLIENT_MODE: - // Start the wifi module up in client mode. - // Additionally, make network.WINC() return a python object of the setup wifi module and make - // winc.connect()/winc.disconnect() do nothing. This should allow the user to use the wifi module - // normally in their scripts in debug mode. - // You should have all the settings you need to init the wifi module in the config struct. - // Disable regular USB CDC DBG if this works... two folks can't share the interface. - // For data transfer create a TCP server after setting up the wifi. You will then UDP broadcast - // your IP address along with the port you chose for the TCP server. OpenMV IDE will connect to this. - break; - case WIFI_DBG_ENABLED_AP_MODE: - // Start the wifi module up in ap mode. - // Additionally, make network.WINC() return a python object of the setup wifi module and make - // winc.connect()/winc.disconnect() do nothing. This should allow the user to use the wifi module - // normally in their scripts in debug mode. - // You should have all the settings you need to init the wifi module in the config struct. - // Disable regular USB CDC DBG if this works... two folks can't share the interface. - // For data transfer create a TCP server after setting up the wifi. You will then UDP broadcast - // your IP address along with the port you chose for the TCP server. OpenMV IDE will connect to this. - break; - default: // Don't init anything. - break; - } -} - -void wifi_dbg_beacon() -{ - // Call this every second via a timer calback or something if wifi is enabled. - // You need to broadcast a UDP message on the OPENMVCAM_BROADCAST_PORT port. - // The contents of the message should be "ip:port:board_name", e.g. "192.168.2.1:4321:Ibrahim's cam". - // OpenMV splits the message using the ":" character. The port can by anything (whatever the module picks randomly). - // The IP address must be in dot format. Finally, the string can have whatever in it. - // If broadcasting is working the IDE should display a new board option to connect to when you hit connect. - // I'd get this working first for both AP and client mode before working on the rest of the code. -} diff --git a/src/omv/wifi_dbg.h b/src/omv/wifi_dbg.h deleted file mode 100644 index 2e5279a1a..000000000 --- a/src/omv/wifi_dbg.h +++ /dev/null @@ -1,41 +0,0 @@ -/* This file is part of the OpenMV project. - * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman - * This work is licensed under the MIT license, see the file LICENSE for details. - */ -#ifndef __WIFI_DBG_H__ -#define __WIFI_DBG_H__ - -#define SSID_MAX 63 -#define PASS_MAX 63 -#define NAME_MAX 63 - -#define OPENMVCAM_BROADCAST_PORT 0xABD1 - -typedef enum wifi_dbg_wifi_mode { - WIFI_DBG_DISABLED = 0, - WIFI_DBG_ENABLED_CLIENT_MODE = 1, - WIFI_DBG_ENABLED_AP_MODE = 2 -} wifi_dbg_wifi_mode_t; - -typedef enum wifi_dbg_wifi_type { - WIFI_DBG_OPEN, - WIFI_DBG_WPA, - WIFI_DBG_WEP -} wifi_dbg_wifi_type_t; - -typedef struct wifi_dbg_config { - wifi_dbg_wifi_mode_t wifi_mode; - char wifi_client_ssid[SSID_MAX+1]; - char wifi_client_pass[PASS_MAX+1]; - wifi_dbg_wifi_type_t wifi_client_type; - char wifi_ap_ssid[SSID_MAX+1]; - char wifi_ap_pass[PASS_MAX+1]; - wifi_dbg_wifi_type_t wifi_ap_type; - char wifi_board_name[NAME_MAX+1]; -} wifi_dbg_config_t; - -void wifi_dbg_init(); -void wifi_dbg_apply_config(wifi_dbg_config_t *config); -void wifi_dbg_beacon(); - -#endif /* __WIFI_DBG_H__ */ diff --git a/src/omv/wifidbg.c b/src/omv/wifidbg.c new file mode 100644 index 000000000..d73717dd2 --- /dev/null +++ b/src/omv/wifidbg.c @@ -0,0 +1,147 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ +#include +#include +#include +#include +#include "winc.h" +#include "socket/include/socket.h" +#include "driver/include/m2m_wifi.h" +#include "mp.h" +#include "irq.h" +#include "lexer.h" +#include "parse.h" +#include "compile.h" +#include "runtime.h" +#include "stackctrl.h" +#include "usbdbg.h" +#include "sensor.h" +#include "framebuffer.h" +#include "omv_boardconfig.h" +#include "lib/utils/pyexec.h" +#include "wifidbg.h" +#include "led.h" + +#include STM32_HAL_H + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +#define SERVER_ADDR ((uint8_t [5]){192, 168, 1, 1}) +#define SERVER_PORT (9000) +#define BUFFER_SIZE (512) + +#define close_all_sockets() \ + do { \ + winc_socket_close(client_fd); \ + winc_socket_close(server_fd); \ + client_fd = -1; \ + server_fd = -1; \ + } while (0) + +#define close_server_socket() \ + do { \ + winc_socket_close(server_fd); \ + server_fd = -1; \ + } while (0) + +#define TIMEDOUT(x) (x == -ETIMEDOUT || x == SOCK_ERR_TIMEOUT) + +static int client_fd = -1; +static int server_fd = -1; + +int wifidbg_init(wifidbg_config_t *config) +{ + client_fd = -1; + server_fd = -1; + + // Initialize WiFi in AP mode. + if (winc_init(WINC_MODE_AP) != 0) { + return -1; + } + + // Start WiFi in AP mode. + if (winc_start_ap(config->ssid, config->security, config->key, config->channel) != 0) { + return -2; + } + + return 0; +} + +void wifidbg_dispatch() +{ + int ret; + uint8_t buf[BUFFER_SIZE]; + sockaddr client_sockaddr; + + if (server_fd < 0) { + // Create server socket + MAKE_SOCKADDR(server_sockaddr, SERVER_ADDR, SERVER_PORT) + + if ((server_fd = winc_socket_socket(SOCK_STREAM)) < 0) { + return; + } + + if ((ret = winc_socket_bind(server_fd, &server_sockaddr)) < 0) { + close_server_socket(); + return; + } + + if ((ret = winc_socket_listen(server_fd, 1)) < 0) { + close_server_socket(); + return; + } + } + + if (client_fd < 0) { + // Call accept. + if ((ret = winc_socket_accept(server_fd, + &client_sockaddr, &client_fd, 10)) < 0) { + if (TIMEDOUT(ret)) { + client_fd = -1; + } else { + close_server_socket(); + } + return; + } + + } + + if ((ret = winc_socket_recv(client_fd, buf, 8, 10)) < 0) { + if (TIMEDOUT(ret)) { + return; + } else { + close_server_socket(); + return; + } + } + + uint8_t request = buf[1]; + uint32_t xfer_length = *((uint32_t*)(buf+2)); + usbdbg_control(buf+6, request, xfer_length); + + while (xfer_length) { + if (request & 0x80) { + // Device-to-host data phase + int bytes = MIN(xfer_length, BUFFER_SIZE); + xfer_length -= bytes; + usbdbg_data_in(buf, bytes); + if ((ret = winc_socket_send(client_fd, buf, bytes, 500)) < 0) { + close_all_sockets(); + return; + } + } else { + // Host-to-device data phase + int bytes = MIN(xfer_length, BUFFER_SIZE); + if ((ret = winc_socket_recv(client_fd, buf, bytes, 500)) < 0) { + close_all_sockets(); + return; + } + xfer_length -= ret; + usbdbg_data_out(buf, ret); + } + } +} diff --git a/src/omv/wifidbg.h b/src/omv/wifidbg.h new file mode 100644 index 000000000..afecf8384 --- /dev/null +++ b/src/omv/wifidbg.h @@ -0,0 +1,19 @@ +/* This file is part of the OpenMV project. + * Copyright (c) 2013-2018 Ibrahim Abdelkader & Kwabena W. Agyeman + * This work is licensed under the MIT license, see the file LICENSE for details. + */ +#ifndef __WIFI_DBG_H__ +#define __WIFI_DBG_H__ +#include "winc.h" + +typedef struct wifidbg_config { + winc_mode_t mode; + winc_security_t security; + char key[WINC_MAX_PSK_LEN + 1]; + char ssid[WINC_MAX_SSID_LEN + 1]; + uint8_t channel; +} wifidbg_config_t; + +void wifidbg_dispatch(); +int wifidbg_init(wifidbg_config_t *config); +#endif /* __WIFIDBG_H__ */ diff --git a/src/winc1500/src/winc.c b/src/winc1500/src/winc.c index e0f43ebd6..3637ada68 100644 --- a/src/winc1500/src/winc.c +++ b/src/winc1500/src/winc.c @@ -160,7 +160,7 @@ static void socket_callback(SOCKET sock, uint8_t msg_type, void *msg) *((int*) async_request_data) = pstrRecv->s16BufferSize; debug_printf("recv %d\n", pstrRecv->s16BufferSize); } else { - *((int*) async_request_data) = -1; + *((int*) async_request_data) = pstrRecv->s16BufferSize; debug_printf("recv error! %d\n", pstrRecv->s16BufferSize); } async_request_done = true; @@ -179,7 +179,7 @@ static void socket_callback(SOCKET sock, uint8_t msg_type, void *msg) debug_printf("recvfrom size: %d addr:%lu port:%d\n", pstrRecv->s16BufferSize, rfrom->addr.sin_addr.s_addr, rfrom->addr.sin_port); } else { - rfrom->size = -1; + rfrom->size = pstrRecv->s16BufferSize; debug_printf("recvfrom error:%d\n", pstrRecv->s16BufferSize); } async_request_done = true; @@ -385,6 +385,13 @@ static int winc_async_request(uint8_t msg_type, void *ret, uint32_t timeout) async_request_data = ret; async_request_done = false; async_request_type = msg_type; + + if (msg_type != SOCKET_MSG_ACCEPT) { + // Only use async timeout for accept since it doesn't have a timeout arg. + // For other calls that have a timeout arg, we use a large async timeout. + timeout = 1000; + } + uint32_t tick_start = HAL_GetTick(); // Wait for async request to finish.