Add WiFi programming. (#362)

This commit is contained in:
Ibrahim Abd Elkader 2018-07-30 20:10:55 +02:00 committed by GitHub
parent 5a53991449
commit 4c25cffa7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 240 additions and 161 deletions

View File

@ -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 \

@ -1 +1 @@
Subproject commit a4e78c2b6e493d922a25c00cf458bf443da748af
Subproject commit 857040fe2669ba2a4066e8426cd7732b69cd713d

View File

@ -9,7 +9,7 @@ SRCS += $(addprefix , \
framebuffer.c \
array.c \
usbdbg.c \
wifi_dbg.c \
wifidbg.c \
cambus.c \
ov9650.c \
ov2640.c \

View File

@ -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.

View File

@ -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__ */

View File

@ -1,65 +0,0 @@
/* This file is part of the OpenMV project.
* Copyright (c) 2013-2018 Ibrahim Abdelkader <iabdalkader@openmv.io> & Kwabena W. Agyeman <kwagyeman@openmv.io>
* This work is licensed under the MIT license, see the file LICENSE for details.
*/
#include <stdint.h>
#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.
}

View File

@ -1,41 +0,0 @@
/* This file is part of the OpenMV project.
* Copyright (c) 2013-2018 Ibrahim Abdelkader <iabdalkader@openmv.io> & Kwabena W. Agyeman <kwagyeman@openmv.io>
* 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__ */

147
src/omv/wifidbg.c Normal file
View File

@ -0,0 +1,147 @@
/* This file is part of the OpenMV project.
* Copyright (c) 2013-2018 Ibrahim Abdelkader <iabdalkader@openmv.io> & Kwabena W. Agyeman <kwagyeman@openmv.io>
* This work is licensed under the MIT license, see the file LICENSE for details.
*/
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#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);
}
}
}

19
src/omv/wifidbg.h Normal file
View File

@ -0,0 +1,19 @@
/* This file is part of the OpenMV project.
* Copyright (c) 2013-2018 Ibrahim Abdelkader <iabdalkader@openmv.io> & Kwabena W. Agyeman <kwagyeman@openmv.io>
* 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__ */

View File

@ -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.