drivers/ninaw10: Add ublox Nina-W10 WiFi/BT module driver.

- Add WiFi/BT drivers for ublox Nina-W10 (esp32 based) module.
- Add ublox Nina-W10 Python module in extmod.
pull/7984/head
iabdalkader 2021-08-15 18:51:15 +02:00 zatwierdzone przez Damien George
rodzic b6dbbbe82f
commit 43079aaf86
7 zmienionych plików z 1950 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,39 @@
/*
* This file is part of the OpenMV project, https://openmv.io.
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* NINA-W10 driver BSP.
*/
#ifndef MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H
#define MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H
int nina_bsp_init(void);
int nina_bsp_deinit(void);
int nina_bsp_read_irq(void);
int nina_bsp_spi_slave_select(uint32_t timeout);
int nina_bsp_spi_slave_deselect(void);
int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size);
#endif // MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H

Wyświetl plik

@ -0,0 +1,150 @@
/*
* This file is part of the OpenMV project, https://openmv.io.
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* NINA-W10 Bluetooth HCI driver.
*/
#include "py/mphal.h"
#if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10
#include <stdio.h>
#include <string.h>
#include "py/runtime.h"
#include "extmod/mpbthci.h"
#define HCI_COMMAND_PACKET (0x01)
#define HCI_ACLDATA_PACKET (0x02)
#define HCI_EVENT_PACKET (0x04)
#define HCI_COMMAND_COMPLETE (0x0e)
#define HCI_COMMAND_TIMEOUT (3000)
#define OGF_LINK_CTL (0x01)
#define OGF_HOST_CTL (0x03)
#define OCF_SET_EVENT_MASK (0x0001)
#define OCF_RESET (0x0003)
#define error_printf(...) mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__)
#define debug_printf(...) // mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__)
// Provided by the port, and also possibly shared with the stack.
extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
static int nina_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) {
uint8_t *buf = mp_bluetooth_hci_cmd_buf;
buf[0] = HCI_COMMAND_PACKET;
buf[1] = ocf;
buf[2] = ogf << 2 | ocf >> 8;
buf[3] = param_len;
if (param_len) {
memcpy(buf + 4, param_buf, param_len);
}
debug_printf("HCI Command: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
mp_bluetooth_hci_uart_write(buf, 4 + param_len);
// Receive HCI event packet, initially reading 3 bytes (HCI Event, Event code, Plen).
for (mp_uint_t start = mp_hal_ticks_ms(), size = 3, i = 0; i < size;) {
while (!mp_bluetooth_hci_uart_any()) {
MICROPY_EVENT_POLL_HOOK
// Timeout.
if ((mp_hal_ticks_ms() - start) > HCI_COMMAND_TIMEOUT) {
error_printf("timeout waiting for HCI packet\n");
return -1;
}
}
buf[i] = mp_bluetooth_hci_uart_readchar();
// There seems to be a sync issue with this fw/module.
if (i == 0 && buf[0] == 0xFF) {
continue;
}
// Check for packet type.
if (i == 0 && buf[0] != HCI_EVENT_PACKET) {
error_printf("unexpected HCI packet: %02x\n", buf[0]);
return -1;
}
// Sanity check the packet parameters length.
if (i == 2 && ((size += buf[2]) > sizeof(mp_bluetooth_hci_cmd_buf))) {
error_printf("unexpected event packet length: %d\n", size);
return -1;
}
i++;
}
// We're only looking for command complete events.
if (buf[1] != HCI_COMMAND_COMPLETE || buf[4] != ocf || buf[5] != (ogf << 2 | ocf >> 8)) {
error_printf("response mismatch: %02x %02x\n", buf[4], buf[5]);
return -1;
}
// Log event.
debug_printf("HCI Event packet: %02x %02x %02x %02x %02x %02x %02x\n",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
// Status code.
return buf[6];
}
int mp_bluetooth_hci_controller_init(void) {
// This is called immediately after the UART is initialised during stack initialisation.
mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
mp_hal_pin_output(MICROPY_HW_NINA_RESET);
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0);
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
mp_hal_delay_ms(100);
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1);
mp_hal_delay_ms(750);
// The UART must be re-initialize here because the GPIO1/RX pin is used initially
// to reset the module in Bluetooth mode. This will change back the pin to UART RX.
mp_bluetooth_hci_uart_init(0, 0);
// Send reset command
return nina_hci_cmd(OGF_HOST_CTL, OCF_RESET, 0, NULL);
// It seems that nothing else is needed for now.
}
int mp_bluetooth_hci_controller_deinit(void) {
// Reset module
mp_hal_pin_output(MICROPY_HW_NINA_RESET);
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
return 0;
}
#endif

Wyświetl plik

@ -0,0 +1,139 @@
/*
* This file is part of the OpenMV project, https://openmv.io.
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* NINA-W10 driver BSP implementation.
*/
#include "py/mphal.h"
#if MICROPY_PY_NETWORK_NINAW10
#include <stdint.h>
#include <string.h>
#include "py/runtime.h"
#include "modmachine.h"
#include "extmod/machine_spi.h"
#include "mpconfigboard.h"
#include "nina_bsp.h"
#include "nina_wifi_drv.h"
#if NINA_DEBUG
#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
#else
#define debug_printf(...)
#endif
int nina_bsp_init(void) {
mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
mp_hal_pin_input(MICROPY_HW_NINA_ACK);
mp_hal_pin_output(MICROPY_HW_NINA_RESET);
mp_hal_pin_output(MICROPY_HW_NINA_GPIO0);
// Reset module in WiFi mode
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1);
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
mp_hal_delay_ms(100);
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1);
mp_hal_delay_ms(750);
mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 0);
mp_hal_pin_input(MICROPY_HW_NINA_GPIO0);
// Initialize SPI.
mp_obj_t args[] = {
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_ID),
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_BAUDRATE),
};
MP_STATE_PORT(mp_wifi_spi) = machine_spi_type.make_new((mp_obj_t)&machine_spi_type, 2, 0, args);
return 0;
}
int nina_bsp_deinit(void) {
mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
mp_hal_pin_output(MICROPY_HW_NINA_RESET);
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
mp_hal_delay_ms(100);
mp_hal_pin_output(MICROPY_HW_NINA_GPIO0);
mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1);
return 0;
}
int nina_bsp_read_irq(void) {
return mp_hal_pin_read(MICROPY_HW_NINA_GPIO0);
}
int nina_bsp_spi_slave_select(uint32_t timeout) {
// Wait for ACK to go low.
for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 1; mp_hal_delay_ms(1)) {
if ((mp_hal_ticks_ms() - start) >= timeout) {
return -1;
}
}
// Chip select.
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0);
// Wait for ACK to go high.
for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 0; mp_hal_delay_ms(1)) {
if ((mp_hal_ticks_ms() - start) >= 100) {
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
return -1;
}
}
return 0;
}
int nina_bsp_spi_slave_deselect(void) {
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
return 0;
}
int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) {
mp_obj_t mp_wifi_spi = MP_STATE_PORT(mp_wifi_spi);
((mp_machine_spi_p_t *)machine_spi_type.protocol)->transfer(mp_wifi_spi, size, tx_buf, rx_buf);
#if NINA_DEBUG
for (int i = 0; i < size; i++) {
if (tx_buf) {
debug_printf("0x%x ", tx_buf[i]);
} else {
debug_printf("0x%x ", rx_buf[i]);
}
}
#endif
return 0;
}
#endif // MICROPY_PY_NETWORK_NINAW10

Wyświetl plik

@ -0,0 +1,913 @@
/*
* This file is part of the OpenMV project, https://openmv.io.
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* NINA-W10 WiFi driver.
*/
#include "py/mphal.h"
#if MICROPY_PY_NETWORK_NINAW10
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "nina_bsp.h"
#include "nina_wifi_drv.h"
#define SPI_ACK (1)
#define SPI_ERR (0xFF)
#define NO_SOCKET_AVAIL (255)
#define CMD_START (0xE0)
#define CMD_END (0xEE)
#define CMD_ERROR (0xEF)
#define CMD_REPLY (1 << 7)
#define ARG_8BITS (1)
#define ARG_16BITS (2)
#define ARG_STR(x) {strlen(x), (const void *)x}
#define ARG_BYTE(x) {1, (uint8_t [1]) {x}}
#define ARG_SHORT(x) {2, (uint16_t [1]) {x}}
#define ARG_WORD(x) {4, (uint32_t [1]) {x}}
#define NINA_ARGS(...) (nina_args_t []) {__VA_ARGS__}
#define NINA_VALS(...) (nina_vals_t []) {__VA_ARGS__}
#define NINA_SSELECT_TIMEOUT (10000)
#define NINA_RESPONSE_TIMEOUT (1000)
#define NINA_CONNECT_TIMEOUT (10000)
#if NINA_DEBUG
#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
#else
#define debug_printf(...)
#endif
#ifndef __REVSH
#define __REVSH(x) ((((uint16_t)x) << 8) | (((uint16_t)x) >> 8))
#endif
typedef struct {
uint16_t size;
const void *data;
} nina_args_t;
typedef struct {
uint16_t *size;
void *data;
} nina_vals_t;
typedef enum {
// STA mode commands.
NINA_CMD_CONNECT_OPEN = 0x10,
NINA_CMD_CONNECT_WEP = 0x11,
NINA_CMD_CONNECT_WPA = 0x12,
NINA_CMD_GET_SSID = 0x23,
NINA_CMD_GET_BSSID = 0x24,
NINA_CMD_GET_RSSI = 0x25,
NINA_CMD_GET_ENCRYPT = 0x26,
// AP mode commands.
NINA_CMD_START_AP_OPEN = 0x18,
NINA_CMD_START_AP_WEP = 0x19,
// AP mode scan commands.
NINA_CMD_AP_START_SCAN = 0x36,
NINA_CMD_AP_SCAN_RESULT = 0x27,
NINA_CMD_AP_GET_RSSI = 0x32,
NINA_CMD_AP_GET_ENCRYPT = 0x33,
NINA_CMD_AP_GET_BSSID = 0x3C,
NINA_CMD_AP_GET_CHANNEL = 0x3D,
// Disonnect/status commands.
NINA_CMD_DISCONNECT = 0x30,
NINA_CMD_CONN_STATUS = 0x20,
// Interface config commands.
NINA_CMD_SET_IF_CONFIG = 0x14,
NINA_CMD_GET_IF_CONFIG = 0x21,
NINA_CMD_SET_DNS_CONFIG = 0x15,
// Hostname/Resolv commands.
NINA_CMD_SET_HOSTNAME = 0x16,
NINA_CMD_HOST_BY_NAME = 0x34,
NINA_CMD_GET_HOST_BY_NAME = 0x35,
// Misc commands.
NINA_CMD_SET_POWER = 0x17,
NINA_CMD_PING = 0x3E,
NINA_CMD_GET_TIME = 0x3B,
NINA_CMD_GET_FW_VERSION = 0x37,
NINA_CMD_DEBUG_MODE = 0x1A,
NINA_CMD_TEMP_SENSOR = 0x1B,
NINA_CMD_GET_MAC_ADDR = 0x22,
// Sockets commands.
NINA_CMD_SOCKET_OPEN = 0x3F,
NINA_CMD_SOCKET_CLOSE = 0x2E,
NINA_CMD_SOCKET_CONNECT = 0x2D,
NINA_CMD_SOCKET_ACCEPT = 0x2B,
NINA_CMD_SOCKET_BIND = 0x28,
NINA_CMD_SOCKET_STATE = 0x2F,
NINA_CMD_SOCKET_REMOTE_ADDR = 0x3A,
// TCP commands
NINA_CMD_TCP_SEND = 0x44,
NINA_CMD_TCP_RECV = 0x45,
NINA_CMD_TCP_ACK = 0x2A,
// UDP commands.
NINA_CMD_UDP_SEND = 0x46,
NINA_CMD_UDP_RECV = 0x45,
NINA_CMD_UDP_ACK = 0x39,
// Pin control commands.
NINA_CMD_SET_PIN_MODE = 0x50,
NINA_CMD_SET_DIGITAL_WRITE = 0x51,
NINA_CMD_GET_DIGITAL_READ = 0x53,
NINA_CMD_SET_ANALOG_WRITE = 0x52,
NINA_CMD_GET_ANALOG_READ = 0x54,
// File send/recv commands.
NINA_CMD_CMD_WRITE_FILE = 0x60,
NINA_CMD_CMD_READ_FILE = 0x61,
NINA_CMD_CMD_DELETE_FILE = 0x62,
NINA_CMD_CMD_EXISTS_FILE = 0x63,
NINA_CMD_CMD_DOWNLOAD_FILE = 0x64,
// OTA upgrade commands.
NINA_CMD_CMD_APPLY_OTA = 0x65,
NINA_CMD_CMD_RENAME_FILE = 0x66,
NINA_CMD_CMD_DOWNLOAD_OTA = 0x67,
} nina_cmd_t;
typedef enum {
NINA_STATUS_IDLE = 0,
NINA_STATUS_NO_SSID_AVAIL,
NINA_STATUS_SCAN_COMPLETED,
NINA_STATUS_CONNECTED,
NINA_STATUS_CONNECT_FAILED,
NINA_STATUS_CONNECTION_LOST,
NINA_STATUS_DISCONNECTED,
NINA_STATUS_AP_LISTENING,
NINA_STATUS_AP_CONNECTED,
NINA_STATUS_AP_FAILED
} nina_status_t;
typedef enum {
SOCKET_STATE_CLOSED = 0,
SOCKET_STATE_LISTEN,
SOCKET_STATE_SYN_SENT,
SOCKET_STATE_SYN_RCVD,
SOCKET_STATE_ESTABLISHED,
SOCKET_STATE_FIN_WAIT_1,
SOCKET_STATE_FIN_WAIT_2,
SOCKET_STATE_CLOSE_WAIT,
SOCKET_STATE_CLOSING,
SOCKET_STATE_LAST_ACK,
SOCKET_STATE_TIME_WAIT
} nina_sock_state_t;
static uint8_t nina_bsp_spi_read_byte(void) {
uint8_t byte = 0;
nina_bsp_spi_transfer(NULL, &byte, 1);
return byte;
}
static int nina_wait_for_cmd(uint8_t cmd, uint32_t timeout) {
uint8_t buf = 0;
for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
buf = nina_bsp_spi_read_byte();
if (buf == CMD_ERROR || buf == cmd
|| ((mp_hal_ticks_ms() - start) >= timeout)) {
break;
}
mp_hal_delay_ms(1);
}
return (buf == cmd) ? 0 : -1;
}
static int nina_send_command(uint32_t cmd, uint32_t nargs, uint32_t width, nina_args_t *args) {
int ret = -1;
uint32_t length = 4; // 3 bytes header + 1 end byte
debug_printf("nina_send_command (cmd 0x%x nargs %d width %d): ", cmd, nargs, width);
if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) {
return -1;
}
// Send command header.
uint8_t cmdbuf_hdr[3] = {CMD_START, cmd, nargs};
if (nina_bsp_spi_transfer(cmdbuf_hdr, NULL, sizeof(cmdbuf_hdr)) != 0) {
goto error_out;
}
// Send command arg(s).
for (uint32_t i = 0; i < nargs; i++) {
// Send size MSB first if 2 bytes.
uint16_t size = (width == ARG_8BITS) ? args[i].size : __REVSH(args[i].size);
// Send arg length.
if (nina_bsp_spi_transfer((uint8_t *)&size, NULL, width) != 0) {
goto error_out;
}
// Send arg value.
if (nina_bsp_spi_transfer(args[i].data, NULL, args[i].size) != 0) {
goto error_out;
}
length += args[i].size + width;
}
// Send END byte + padding to multiple of 4.
uint8_t cmdbuf_end[4] = {CMD_END, 0xFF, 0xFF, 0xFF};
if (nina_bsp_spi_transfer(cmdbuf_end, NULL, 1 + (length % 4)) != 0) {
goto error_out;
}
// All good
ret = 0;
error_out:
debug_printf("\n");
nina_bsp_spi_slave_deselect();
return ret;
}
static int nina_read_response(uint32_t cmd, uint32_t nvals, uint32_t width, nina_vals_t *vals) {
int ret = -1;
debug_printf("nina_read_response(cmd 0x%x nvals %d width %d): ", cmd, nvals, width);
// Read reply
if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) {
return -1;
}
// Wait for CMD_START
if (nina_wait_for_cmd(CMD_START, NINA_RESPONSE_TIMEOUT) != 0) {
goto error_out;
}
// Should return CMD + REPLY flag.
if (nina_bsp_spi_read_byte() != (cmd | CMD_REPLY)) {
goto error_out;
}
// Sanity check the number of returned values.
// NOTE: This is to handle the special case for the scan command.
uint32_t rvals = nina_bsp_spi_read_byte();
if (nvals > rvals) {
nvals = rvals;
}
// Read return value(s).
for (uint32_t i = 0; i < nvals; i++) {
// Read return value size.
uint16_t bytes = nina_bsp_spi_read_byte();
if (width == ARG_16BITS) {
bytes = (bytes << 8) | nina_bsp_spi_read_byte();
}
// Check the val fits the buffer.
if (*(vals[i].size) < bytes) {
goto error_out;
}
// Read the returned value.
if (nina_bsp_spi_transfer(NULL, vals[i].data, bytes) != 0) {
goto error_out;
}
// Set the size.
*(vals[i].size) = bytes;
}
if (nina_bsp_spi_read_byte() != CMD_END) {
goto error_out;
}
// All good
ret = 0;
error_out:
debug_printf("\n");
nina_bsp_spi_slave_deselect();
return ret;
}
static int nina_send_command_read_ack(uint32_t cmd, uint32_t nargs, uint32_t width, nina_args_t *args) {
uint16_t size = 1;
uint8_t rval = SPI_ERR;
if (nina_send_command(cmd, nargs, width, args) != 0 ||
nina_read_response(cmd, 1, ARG_8BITS, NINA_VALS({&size, &rval})) != 0) {
return -1;
}
return rval;
}
static int nina_send_command_read_vals(uint32_t cmd, uint32_t nargs,
uint32_t argsw, nina_args_t *args, uint32_t nvals, uint32_t valsw, nina_vals_t *vals) {
if (nina_send_command(cmd, nargs, argsw, args) != 0 ||
nina_read_response(cmd, nvals, valsw, vals) != 0) {
return -1;
}
return 0;
}
int nina_init(void) {
// Initialize the BSP.
nina_bsp_init();
return 0;
}
int nina_deinit(void) {
return nina_bsp_deinit();
}
static int nina_connection_status() {
return nina_send_command_read_ack(NINA_CMD_CONN_STATUS, 0, ARG_8BITS, NULL);
}
static int nina_socket_status(uint8_t fd) {
return nina_send_command_read_ack(NINA_CMD_SOCKET_STATE,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
}
static int nina_server_socket_status(uint8_t fd) {
return nina_send_command_read_ack(NINA_CMD_SOCKET_STATE & 0xF9,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
}
int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
uint8_t status = NINA_STATUS_CONNECT_FAILED;
if (key == NULL && security != NINA_SEC_OPEN) {
return -1;
}
switch (security) {
case NINA_SEC_OPEN:
if (nina_send_command_read_ack(NINA_CMD_CONNECT_OPEN,
1, ARG_8BITS, NINA_ARGS(ARG_STR(ssid))) != SPI_ACK) {
return -1;
}
break;
case NINA_SEC_WEP:
if (nina_send_command_read_ack(NINA_CMD_CONNECT_WEP,
2, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_STR(key))) != SPI_ACK) {
return -1;
}
break;
case NINA_SEC_WPA_PSK:
if (nina_send_command_read_ack(NINA_CMD_CONNECT_WPA,
3, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_BYTE(0), ARG_STR(key))) != SPI_ACK) {
return -1;
}
break;
default:
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
status = nina_connection_status();
if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
break;
}
if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) {
break;
}
}
return (status == NINA_STATUS_CONNECTED) ? 0 : -1;
}
int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
uint8_t status = NINA_STATUS_AP_FAILED;
if ((key == NULL && security != NINA_SEC_OPEN) ||
(security != NINA_SEC_OPEN && security != NINA_SEC_WEP)) {
return -1;
}
switch (security) {
case NINA_SEC_OPEN:
if (nina_send_command_read_ack(NINA_CMD_START_AP_OPEN,
2, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_BYTE(channel))) != SPI_ACK) {
return -1;
}
break;
case NINA_SEC_WEP:
if (nina_send_command_read_ack(NINA_CMD_START_AP_WEP,
3, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_STR(key), ARG_BYTE(channel))) != SPI_ACK) {
return -1;
}
break;
default:
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
status = nina_connection_status();
if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
break;
}
if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) {
break;
}
}
return (status == NINA_STATUS_AP_LISTENING) ? 0 : -1;
}
int nina_disconnect(void) {
if (nina_send_command_read_ack(NINA_CMD_DISCONNECT,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF))) != SPI_ACK) {
return -1;
}
return 0;
}
int nina_isconnected(void) {
int status = nina_connection_status();
if (status == -1) {
return -1;
}
return status == NINA_STATUS_CONNECTED;
}
int nina_connected_sta(uint32_t *sta_ip) {
return -1;
}
int nina_wait_for_sta(uint32_t *sta_ip, uint32_t timeout) {
return NINA_ERROR_TIMEOUT;
}
int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set) {
uint16_t ip_len = NINA_IPV4_ADDR_LEN;
uint16_t sub_len = NINA_IPV4_ADDR_LEN;
uint16_t gw_len = NINA_IPV4_ADDR_LEN;
uint16_t dns_len = NINA_IPV4_ADDR_LEN;
if (set) {
if (nina_send_command_read_ack(NINA_CMD_SET_IF_CONFIG,
4, ARG_8BITS,
NINA_ARGS(
ARG_BYTE(3), // Valid number of args.
{ip_len, ifconfig->ip_addr},
{gw_len, ifconfig->gateway_addr},
{sub_len, ifconfig->subnet_addr})) != SPI_ACK) {
return -1;
}
if (nina_send_command_read_ack(NINA_CMD_SET_DNS_CONFIG,
3, ARG_8BITS,
NINA_ARGS(
ARG_BYTE(1), // Valid number of args.
{dns_len, ifconfig->dns_addr},
{dns_len, ifconfig->dns_addr})) != SPI_ACK) {
return -1;
}
} else {
if (nina_send_command_read_vals(NINA_CMD_GET_IF_CONFIG,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
3, ARG_8BITS,
NINA_VALS(
{&ip_len, ifconfig->ip_addr},
{&sub_len, ifconfig->subnet_addr},
{&gw_len, ifconfig->gateway_addr})) != 0) {
return -1;
}
// No command to get DNS ?
memcpy(ifconfig->dns_addr, ifconfig->gateway_addr, NINA_IPV4_ADDR_LEN);
}
return 0;
}
int nina_netinfo(nina_netinfo_t *netinfo) {
uint16_t rssi_len = 4;
uint16_t sec_len = 1;
uint16_t ssid_len = NINA_MAX_SSID_LEN;
uint16_t bssid_len = NINA_MAC_ADDR_LEN;
if (nina_send_command_read_vals(NINA_CMD_GET_RSSI,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
1, ARG_8BITS, NINA_VALS({&rssi_len, &netinfo->rssi})) != 0) {
return -1;
}
if (nina_send_command_read_vals(NINA_CMD_GET_ENCRYPT,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
1, ARG_8BITS, NINA_VALS({&sec_len, &netinfo->security})) != 0) {
return -1;
}
if (nina_send_command_read_vals(NINA_CMD_GET_SSID,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
1, ARG_8BITS, NINA_VALS({&ssid_len, &netinfo->ssid})) != 0) {
return -1;
}
if (nina_send_command_read_vals(NINA_CMD_GET_BSSID,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
1, ARG_8BITS, NINA_VALS({&bssid_len, &netinfo->bssid})) != 0) {
return -1;
}
return 0;
}
int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout) {
uint16_t sizes[NINA_MAX_NETWORK_LIST];
char ssids[NINA_MAX_NETWORK_LIST][NINA_MAX_SSID_LEN];
nina_vals_t vals[NINA_MAX_NETWORK_LIST];
// Initialize the values list.
for (int i = 0; i < NINA_MAX_NETWORK_LIST; i++) {
sizes[i] = NINA_MAX_SSID_LEN - 1;
memset(ssids[i], 0, NINA_MAX_SSID_LEN);
vals[i].size = &sizes[i];
vals[i].data = ssids[i];
}
if (nina_send_command_read_ack(NINA_CMD_AP_START_SCAN,
0, ARG_8BITS, NULL) != SPI_ACK) {
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
if (nina_send_command_read_vals(NINA_CMD_AP_SCAN_RESULT,
0, ARG_8BITS, NULL,
NINA_MAX_NETWORK_LIST, ARG_8BITS, vals) != 0) {
return -1;
}
if (ssids[0][0] != 0) {
// Found at least 1 network.
break;
}
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
// Timeout, no networks.
return NINA_ERROR_TIMEOUT;
}
mp_hal_delay_ms(100);
}
for (int i = 0; i < NINA_MAX_NETWORK_LIST; i++) {
uint16_t rssi_len = 4;
uint16_t sec_len = 1;
uint16_t chan_len = 1;
uint16_t bssid_len = NINA_MAC_ADDR_LEN;
nina_scan_result_t scan_result;
if (ssids[i][0] == 0) {
break;
}
// Set AP SSID
strncpy(scan_result.ssid, ssids[i], NINA_MAX_SSID_LEN);
// Read AP RSSI
if (nina_send_command_read_vals(NINA_CMD_AP_GET_RSSI,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
1, ARG_8BITS, NINA_VALS({&rssi_len, &scan_result.rssi})) != 0) {
return -1;
}
// Read AP encryption type
if (nina_send_command_read_vals(NINA_CMD_AP_GET_ENCRYPT,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
1, ARG_8BITS, NINA_VALS({&sec_len, &scan_result.security})) != 0) {
return -1;
}
// Read AP channel
if (nina_send_command_read_vals(NINA_CMD_AP_GET_CHANNEL,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
1, ARG_8BITS, NINA_VALS({&chan_len, &scan_result.channel})) != 0) {
return -1;
}
// Read AP bssid
if (nina_send_command_read_vals(NINA_CMD_AP_GET_BSSID,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
1, ARG_8BITS, NINA_VALS({&bssid_len, scan_result.bssid})) != 0) {
return -1;
}
scan_callback(&scan_result, arg);
}
return 0;
}
int nina_get_rssi(void) {
uint16_t size = 4;
int32_t rssi = 0;
if (nina_send_command_read_vals(NINA_CMD_GET_RSSI,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
1, ARG_8BITS, NINA_VALS({&size, &rssi})) != 0) {
return -1;
}
return rssi;
}
int nina_fw_version(uint8_t *fw_ver) {
uint16_t size = NINA_FW_VER_LEN;
if (nina_send_command_read_vals(NINA_CMD_GET_FW_VERSION,
0, ARG_8BITS, NULL,
1, ARG_8BITS, NINA_VALS({&size, fw_ver})) != 0) {
return -1;
}
return 0;
}
int nina_set_hostname(const char *hostname) {
if (nina_send_command_read_ack(NINA_CMD_SET_HOSTNAME,
1, ARG_8BITS, NINA_ARGS(ARG_STR(hostname))) != SPI_ACK) {
return -1;
}
return 0;
}
int nina_gethostbyname(const char *name, uint8_t *out_ip) {
uint16_t size = 4;
if (nina_send_command_read_ack(NINA_CMD_HOST_BY_NAME,
1, ARG_8BITS, NINA_ARGS(ARG_STR(name))) != SPI_ACK) {
return -1;
}
if (nina_send_command_read_vals(NINA_CMD_GET_HOST_BY_NAME,
0, ARG_8BITS, NULL,
1, ARG_8BITS, NINA_VALS({&size, out_ip})) != 0) {
return -1;
}
return 0;
}
int nina_socket_socket(uint8_t type) {
uint16_t size = 1;
uint8_t sock = 0;
if (nina_send_command_read_vals(NINA_CMD_SOCKET_OPEN,
0, ARG_8BITS, NULL,
1, ARG_8BITS, NINA_VALS({&size, &sock})) != 0) {
return -1;
}
return sock;
}
int nina_socket_close(int fd) {
if (fd > 0 && fd < 255) {
if (nina_send_command_read_ack(NINA_CMD_SOCKET_CLOSE,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))) != SPI_ACK) {
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
if (nina_socket_status(fd) == SOCKET_STATE_CLOSED) {
break;
}
if ((mp_hal_ticks_ms() - start) >= 5000) {
return NINA_ERROR_TIMEOUT;
}
}
}
return 0;
}
int nina_socket_bind(int fd, uint8_t *ip, uint16_t port, int type) {
if (nina_send_command_read_ack(NINA_CMD_SOCKET_BIND,
3, ARG_8BITS,
NINA_ARGS(
ARG_SHORT(__REVSH(port)),
ARG_BYTE(fd),
ARG_BYTE(type))) != SPI_ACK) {
return -1;
}
// Only TCP sockets' states should be checked.
if (type == NINA_SOCKET_TYPE_TCP &&
nina_server_socket_status(fd) != SOCKET_STATE_LISTEN) {
return -1;
}
return 0;
}
int nina_socket_listen(int fd, uint32_t backlog) {
return 0; // No listen ?
}
int nina_socket_accept(int fd, uint8_t *ip, uint16_t *port, int *fd_out, uint32_t timeout) {
uint16_t size = 2;
uint16_t sock = NO_SOCKET_AVAIL;
if (nina_server_socket_status(fd) != SOCKET_STATE_LISTEN) {
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); sock == 0 || sock == NO_SOCKET_AVAIL; mp_hal_delay_ms(10)) {
if (nina_send_command_read_vals(NINA_CMD_SOCKET_ACCEPT,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)),
1, ARG_8BITS, NINA_VALS({&size, &sock})) != 0) {
return -1;
}
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
return NINA_ERROR_TIMEOUT;
}
}
uint16_t port_len = 2;
uint16_t ip_len = NINA_IPV4_ADDR_LEN;
if (nina_send_command_read_vals(NINA_CMD_SOCKET_REMOTE_ADDR,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(sock)),
2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) {
return -1;
}
*fd_out = sock;
*port = __REVSH(*port);
return 0;
}
int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout) {
if (nina_send_command_read_ack(NINA_CMD_SOCKET_CONNECT,
4, ARG_8BITS,
NINA_ARGS(
ARG_WORD((*(uint32_t *)ip)),
ARG_SHORT(__REVSH(port)),
ARG_BYTE(fd),
ARG_BYTE(NINA_SOCKET_TYPE_TCP))) != SPI_ACK) {
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
int state = nina_socket_status(fd);
if (state == -1) {
return -1;
}
if (state == SOCKET_STATE_ESTABLISHED) {
break;
}
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
return NINA_ERROR_TIMEOUT;
}
}
return 0;
}
int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout) {
uint16_t size = 2;
uint16_t bytes = 0;
if (nina_socket_status(fd) != SOCKET_STATE_ESTABLISHED) {
return -1;
}
if (nina_send_command_read_vals(NINA_CMD_TCP_SEND,
2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf}),
1, ARG_8BITS, NINA_VALS({&size, &bytes})) != 0 || bytes <= 0) {
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
int resp = nina_send_command_read_ack(NINA_CMD_TCP_ACK,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
if (resp == -1) {
return -1;
}
if (resp == SPI_ACK) {
break;
}
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
return NINA_ERROR_TIMEOUT;
}
mp_hal_delay_ms(1);
}
return bytes;
}
int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout) {
uint16_t bytes = 0;
if (nina_socket_status(fd) != SOCKET_STATE_ESTABLISHED) {
return -1;
}
for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) {
bytes = len;
if (nina_send_command_read_vals(NINA_CMD_TCP_RECV,
2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)),
1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) {
return -1;
}
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
return NINA_ERROR_TIMEOUT;
}
}
return bytes;
}
// Check from the upper layer if the socket is bound, if not then auto-bind it first.
int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout) {
// TODO do we need to split the packet somewhere?
if (nina_send_command_read_ack(NINA_CMD_SOCKET_CONNECT,
4, ARG_8BITS,
NINA_ARGS(
ARG_WORD((*(uint32_t *)ip)),
ARG_SHORT(__REVSH(port)),
ARG_BYTE(fd),
ARG_BYTE(NINA_SOCKET_TYPE_UDP))) != SPI_ACK) {
return -1;
}
// Buffer length and socket number are passed as 16bits.
if (nina_send_command_read_ack(NINA_CMD_UDP_SEND,
2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf})) != SPI_ACK) {
return -1;
}
if (nina_send_command_read_ack(NINA_CMD_UDP_ACK,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))) != SPI_ACK) {
return -1;
}
return 0;
}
// Check from the upper layer if the socket is bound, if not then auto-bind it first.
int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout) {
uint16_t bytes = 0;
uint16_t port_len = 2;
uint16_t ip_len = NINA_IPV4_ADDR_LEN;
for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) {
bytes = len;
if (nina_send_command_read_vals(NINA_CMD_UDP_RECV,
2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)),
1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) {
return -1;
}
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
return NINA_ERROR_TIMEOUT;
}
}
if (nina_send_command_read_vals(NINA_CMD_SOCKET_REMOTE_ADDR,
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)),
2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) {
return -1;
}
return bytes;
}
int nina_socket_setsockopt(int fd, uint32_t level, uint32_t opt, const void *optval, uint32_t optlen) {
return -1;
}
#endif // MICROPY_PY_NINAW10

Wyświetl plik

@ -0,0 +1,120 @@
/*
* This file is part of the OpenMV project, https://openmv.io.
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* NINA-W10 WiFi driver.
*/
#ifndef MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H
#define MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H
#define NINA_FW_VER_LEN (6)
#define NINA_IPV4_ADDR_LEN (4)
#define NINA_MAC_ADDR_LEN (6)
#define NINA_MAX_SSID_LEN (32)
#define NINA_MAX_WEP_LEN (13)
#define NINA_MAX_WPA_LEN (63)
#define NINA_MAX_NETWORK_LIST (10)
#define NINA_MAX_SOCKET (10)
#define NINA_FW_VER_MAJOR (1)
#define NINA_FW_VER_MINOR (4)
#define NINA_FW_VER_PATCH (8)
#define NINA_FW_VER_MAJOR_OFFS (0)
#define NINA_FW_VER_MINOR_OFFS (2)
#define NINA_FW_VER_PATCH_OFFS (4)
typedef enum {
NINA_SEC_INVALID = 0,
NINA_SEC_OPEN,
NINA_SEC_WPA_PSK,
NINA_SEC_WEP
} nina_security_t;
typedef enum {
NINA_SOCKET_TYPE_TCP = 0,
NINA_SOCKET_TYPE_UDP,
NINA_SOCKET_TYPE_TLS,
NINA_SOCKET_TYPE_UDP_MULTICAST,
NINA_SOCKET_TYPE_TLS_BEARSSL
} nina_socket_type_t;
typedef enum {
NINA_ERROR_IO = -1,
NINA_ERROR_TIMEOUT = -2,
} nina_error_t;
typedef struct {
uint8_t ip_addr[NINA_IPV4_ADDR_LEN];
uint8_t subnet_addr[NINA_IPV4_ADDR_LEN];
uint8_t gateway_addr[NINA_IPV4_ADDR_LEN];
uint8_t dns_addr[NINA_IPV4_ADDR_LEN];
} nina_ifconfig_t;
typedef struct {
int32_t rssi;
uint8_t security;
uint8_t channel;
uint8_t bssid[NINA_MAC_ADDR_LEN];
char ssid[NINA_MAX_SSID_LEN];
} nina_scan_result_t;
typedef struct {
int32_t rssi;
uint8_t security;
char ssid[NINA_MAX_SSID_LEN];
uint8_t bssid[NINA_MAC_ADDR_LEN];
} nina_netinfo_t;
typedef int (*nina_scan_callback_t)(nina_scan_result_t *, void *);
int nina_init(void);
int nina_deinit(void);
int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel);
int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel);
int nina_disconnect(void);
int nina_isconnected(void);
int nina_connected_sta(uint32_t *sta_ip);
int nina_wait_for_sta(uint32_t *sta_ip, uint32_t timeout);
int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set);
int nina_netinfo(nina_netinfo_t *netinfo);
int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout);
int nina_get_rssi(void);
int nina_fw_version(uint8_t *fw_ver);
int nina_set_hostname(const char *name);
int nina_gethostbyname(const char *name, uint8_t *out_ip);
int nina_socket_socket(uint8_t type);
int nina_socket_close(int fd);
int nina_socket_bind(int fd, uint8_t *ip, uint16_t port, int type);
int nina_socket_listen(int fd, uint32_t backlog);
int nina_socket_accept(int fd, uint8_t *ip, uint16_t *port, int *fd_out, uint32_t timeout);
int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout);
int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout);
int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout);
int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout);
int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout);
int nina_socket_setsockopt(int fd, uint32_t level, uint32_t opt, const void *optval, uint32_t optlen);
#endif // MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H

Wyświetl plik

@ -0,0 +1,588 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* NINA-W10 Python module.
*/
#include "py/mphal.h"
#if MICROPY_PY_NETWORK && MICROPY_PY_NETWORK_NINAW10
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include "py/objtuple.h"
#include "py/objlist.h"
#include "py/stream.h"
#include "py/runtime.h"
#include "py/misc.h"
#include "py/mperrno.h"
#include "shared/netutils/netutils.h"
#include "extmod/modnetwork.h"
#include "nina_wifi_drv.h"
typedef struct _nina_obj_t {
mp_obj_base_t base;
bool active;
uint32_t itf;
} nina_obj_t;
// For auto-binding UDP sockets
#define BIND_PORT_RANGE_MIN (65000)
#define BIND_PORT_RANGE_MAX (65535)
static uint16_t bind_port = BIND_PORT_RANGE_MIN;
const mod_network_nic_type_t mod_network_nic_type_nina;
static nina_obj_t nina_obj = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
STATIC mp_obj_t network_ninaw10_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
nina_obj.active = false;
if (n_args == 0) {
nina_obj.itf = MOD_NETWORK_STA_IF;
} else {
nina_obj.itf = mp_obj_get_int(args[0]);
}
// Reset autobind port.
bind_port = BIND_PORT_RANGE_MIN;
// Register with network module
mod_network_register_nic(MP_OBJ_FROM_PTR(&nina_obj));
return MP_OBJ_FROM_PTR(&nina_obj);
}
STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) {
nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (n_args == 2) {
bool active = mp_obj_is_true(args[1]);
if (active) {
int error = 0;
if ((error = nina_init()) != 0) {
mp_raise_msg_varg(&mp_type_OSError,
MP_ERROR_TEXT("Failed to initialize Nina-W10 module, error: %d\n"), error);
}
// check firmware version
uint8_t fw_ver[NINA_FW_VER_LEN];
if (nina_fw_version(fw_ver) != 0) {
nina_deinit();
mp_raise_msg_varg(&mp_type_OSError,
MP_ERROR_TEXT("Failed to read firmware version, error: %d\n"), error);
}
// Check fw version matches the driver.
if ((fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48) != NINA_FW_VER_MAJOR ||
(fw_ver[NINA_FW_VER_MINOR_OFFS] - 48) != NINA_FW_VER_MINOR ||
(fw_ver[NINA_FW_VER_PATCH_OFFS] - 48) != NINA_FW_VER_PATCH) {
mp_printf(&mp_plat_print,
"Warning: firmware version mismatch, expected %d.%d.%d found: %d.%d.%d\n",
NINA_FW_VER_MAJOR, NINA_FW_VER_MINOR, NINA_FW_VER_PATCH,
fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48,
fw_ver[NINA_FW_VER_MINOR_OFFS] - 48,
fw_ver[NINA_FW_VER_PATCH_OFFS] - 48);
}
} else {
nina_deinit();
}
self->active = active;
return mp_const_none;
}
return mp_obj_new_bool(self->active);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_active_obj, 1, 2, network_ninaw10_active);
STATIC int nina_scan_callback(nina_scan_result_t *scan_result, void *arg) {
mp_obj_t scan_list = (mp_obj_t)arg;
// Format MAC address
VSTR_FIXED(bssid_vstr, 18);
vstr_printf(&bssid_vstr, "%02X:%02X:%02X:%02X:%02X:%02X",
scan_result->bssid[0], scan_result->bssid[1], scan_result->bssid[2],
scan_result->bssid[3], scan_result->bssid[4], scan_result->bssid[5]);
mp_obj_t ap[5] = {
mp_obj_new_int(scan_result->channel),
mp_obj_new_int(scan_result->rssi),
mp_obj_new_int(scan_result->security),
mp_obj_new_str(bssid_vstr.buf, bssid_vstr.len),
mp_obj_new_str(scan_result->ssid, strlen(scan_result->ssid)),
};
mp_obj_list_append(scan_list, mp_obj_new_tuple(MP_ARRAY_SIZE(ap), ap));
return 0;
}
STATIC mp_obj_t network_ninaw10_scan(mp_obj_t self_in) {
mp_obj_t scan_list;
scan_list = mp_obj_new_list(0, NULL);
nina_scan(nina_scan_callback, scan_list, 10000);
return scan_list;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_scan_obj, network_ninaw10_scan);
STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_essid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_key, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NINA_SEC_WPA_PSK} },
{ MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
};
// parse args
nina_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// get ssid
const char *ssid = mp_obj_str_get_str(args[0].u_obj);
if (strlen(ssid) == 0) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SSID can't be empty!"));
}
// get key and sec
const char *key = NULL;
mp_uint_t security = NINA_SEC_OPEN;
if (args[1].u_obj != mp_const_none) {
key = mp_obj_str_get_str(args[1].u_obj);
security = args[2].u_int;
}
if (security != NINA_SEC_OPEN && strlen(key) == 0) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Key can't be empty!"));
}
if (self->itf == MOD_NETWORK_STA_IF) {
// Initialize WiFi in Station mode.
if (nina_connect(ssid, security, key, 0) != 0) {
mp_raise_msg_varg(&mp_type_OSError,
MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"), ssid, security, key);
}
} else {
mp_uint_t channel = args[3].u_int;
if (security != NINA_SEC_OPEN && security != NINA_SEC_WEP) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("AP mode supports WEP security only."));
}
// Initialize WiFi in AP mode.
if (nina_start_ap(ssid, security, key, channel) != 0) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed to start in AP mode"));
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_connect_obj, 1, network_ninaw10_connect);
STATIC mp_obj_t network_ninaw10_disconnect(mp_obj_t self_in) {
nina_disconnect();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_disconnect_obj, network_ninaw10_disconnect);
STATIC mp_obj_t network_ninaw10_isconnected(mp_obj_t self_in) {
return mp_obj_new_bool(nina_isconnected());
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_isconnected_obj, network_ninaw10_isconnected);
STATIC mp_obj_t network_ninaw10_ifconfig(size_t n_args, const mp_obj_t *args) {
nina_ifconfig_t ifconfig;
if (n_args == 1) {
// get ifconfig info
nina_ifconfig(&ifconfig, false);
mp_obj_t tuple[4] = {
netutils_format_ipv4_addr(ifconfig.ip_addr, NETUTILS_BIG),
netutils_format_ipv4_addr(ifconfig.subnet_addr, NETUTILS_BIG),
netutils_format_ipv4_addr(ifconfig.gateway_addr, NETUTILS_BIG),
netutils_format_ipv4_addr(ifconfig.dns_addr, NETUTILS_BIG),
};
return mp_obj_new_tuple(4, tuple);
} else {
// set ifconfig info
mp_obj_t *items;
mp_obj_get_array_fixed_n(args[1], 4, &items);
netutils_parse_ipv4_addr(items[0], ifconfig.ip_addr, NETUTILS_BIG);
netutils_parse_ipv4_addr(items[1], ifconfig.subnet_addr, NETUTILS_BIG);
netutils_parse_ipv4_addr(items[2], ifconfig.gateway_addr, NETUTILS_BIG);
netutils_parse_ipv4_addr(items[3], ifconfig.dns_addr, NETUTILS_BIG);
nina_ifconfig(&ifconfig, true);
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_ifconfig_obj, 1, 2, network_ninaw10_ifconfig);
STATIC mp_obj_t network_ninaw10_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
(void)self;
if (kwargs->used == 0) {
// Get config value
if (n_args != 2) {
mp_raise_TypeError(MP_ERROR_TEXT("must query one param"));
}
switch (mp_obj_str_get_qstr(args[1])) {
case MP_QSTR_essid: {
nina_netinfo_t netinfo;
nina_netinfo(&netinfo);
return mp_obj_new_str(netinfo.ssid, strlen(netinfo.ssid));
}
case MP_QSTR_security: {
nina_netinfo_t netinfo;
nina_netinfo(&netinfo);
return mp_obj_new_int(netinfo.security);
}
case MP_QSTR_mac:
case MP_QSTR_bssid: {
nina_netinfo_t netinfo;
nina_netinfo(&netinfo);
return mp_obj_new_bytes(netinfo.bssid, 6);
}
case MP_QSTR_fw_version: {
uint8_t fwver[NINA_FW_VER_LEN];
nina_fw_version(fwver);
return mp_obj_new_tuple(3, (mp_obj_t []) {
mp_obj_new_int(fwver[NINA_FW_VER_MAJOR_OFFS] - 48),
mp_obj_new_int(fwver[NINA_FW_VER_MINOR_OFFS] - 48),
mp_obj_new_int(fwver[NINA_FW_VER_PATCH_OFFS] - 48)
});
}
default:
mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
}
} else {
// Set config value(s)
// Not supported.
mp_raise_ValueError(MP_ERROR_TEXT("setting config values is not supported"));
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_config_obj, 1, network_ninaw10_config);
STATIC mp_obj_t network_ninaw10_status(size_t n_args, const mp_obj_t *args) {
nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
(void)self;
if (n_args == 1) {
// no arguments: return link status
return mp_obj_new_bool(nina_isconnected());
}
// Query parameter.
switch (mp_obj_str_get_qstr(args[1])) {
case MP_QSTR_rssi: {
nina_netinfo_t netinfo;
nina_netinfo(&netinfo);
return mp_obj_new_int(netinfo.rssi);
}
case MP_QSTR_stations: {
if (self->itf != MOD_NETWORK_AP_IF) {
mp_raise_ValueError(MP_ERROR_TEXT("AP required"));
}
uint32_t sta_ip = 0;
mp_obj_t sta_list = mp_obj_new_list(0, NULL);
if (nina_connected_sta(&sta_ip) == 0) {
mp_obj_list_append(sta_list,
netutils_format_inet_addr((uint8_t *)&sta_ip, 0, NETUTILS_BIG));
}
return sta_list;
}
}
mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_status_obj, 1, 2, network_ninaw10_status);
STATIC int network_ninaw10_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) {
return nina_gethostbyname(name, out_ip);
}
STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
uint8_t type;
if (socket->domain != MOD_NETWORK_AF_INET) {
*_errno = MP_EAFNOSUPPORT;
return -1;
}
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM:
type = NINA_SOCKET_TYPE_TCP;
break;
case MOD_NETWORK_SOCK_DGRAM:
type = NINA_SOCKET_TYPE_UDP;
break;
default:
*_errno = MP_EINVAL;
return -1;
}
// open socket
int fd = nina_socket_socket(type);
if (fd < 0) {
*_errno = fd;
return -1;
}
// store state of this socket
socket->fileno = fd;
socket->timeout = 0; // blocking
socket->bound = false;
return 0;
}
STATIC void network_ninaw10_socket_close(mod_network_socket_obj_t *socket) {
if (socket->fileno >= 0) {
nina_socket_close(socket->fileno);
socket->fileno = -1; // Mark socket FD as invalid
}
}
STATIC int network_ninaw10_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
uint8_t type;
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM:
type = NINA_SOCKET_TYPE_TCP;
break;
case MOD_NETWORK_SOCK_DGRAM:
type = NINA_SOCKET_TYPE_UDP;
break;
default:
*_errno = MP_EINVAL;
return -1;
}
int ret = nina_socket_bind(socket->fileno, ip, port, type);
if (ret < 0) {
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
// Mark socket as bound to avoid auto-binding.
socket->bound = true;
return 0;
}
STATIC int network_ninaw10_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
int ret = nina_socket_listen(socket->fileno, backlog);
if (ret < 0) {
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
return 0;
}
STATIC int network_ninaw10_socket_accept(mod_network_socket_obj_t *socket,
mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) {
int fd = 0;
// Call accept.
int ret = nina_socket_accept(socket->fileno, ip, (uint16_t *)port, &fd, socket->timeout);
if (ret < 0) {
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
// Set default socket timeout.
socket2->fileno = fd;
socket2->timeout = 0;
socket2->bound = false;
return 0;
}
STATIC int network_ninaw10_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
int ret = nina_socket_connect(socket->fileno, ip, port, socket->timeout);
if (ret < 0) {
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
return 0;
}
STATIC mp_uint_t network_ninaw10_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
int ret = nina_socket_send(socket->fileno, buf, len, socket->timeout);
if (ret == NINA_ERROR_TIMEOUT) {
// The socket is Not closed on timeout when calling functions that accept a timeout.
*_errno = MP_ETIMEDOUT;
return 0;
} else if (ret < 0) {
// Close the socket on any other errors.
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
return ret;
}
STATIC mp_uint_t network_ninaw10_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
int ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout);
if (ret == NINA_ERROR_TIMEOUT) {
// The socket is Not closed on timeout when calling functions that accept a timeout.
*_errno = MP_ETIMEDOUT;
return 0;
} else if (ret < 0) {
// Close the socket on any other errors.
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
return ret;
}
STATIC mp_uint_t network_ninaw10_socket_auto_bind(mod_network_socket_obj_t *socket, int *_errno) {
if (socket->bound == false) {
if (network_ninaw10_socket_bind(socket, NULL, bind_port, _errno) != 0) {
return -1;
}
bind_port++;
bind_port = MIN(MAX(bind_port, BIND_PORT_RANGE_MIN), BIND_PORT_RANGE_MAX);
}
return 0;
}
STATIC mp_uint_t network_ninaw10_socket_sendto(mod_network_socket_obj_t *socket,
const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
// Auto-bind the socket first if the socket is unbound.
if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) {
return -1;
}
int ret = nina_socket_sendto(socket->fileno, buf, len, ip, port, socket->timeout);
if (ret == NINA_ERROR_TIMEOUT) {
// The socket is Not closed on timeout when calling functions that accept a timeout.
*_errno = MP_ETIMEDOUT;
return 0;
} else if (ret < 0) {
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
return ret;
}
STATIC mp_uint_t network_ninaw10_socket_recvfrom(mod_network_socket_obj_t *socket,
byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
// Auto-bind the socket first if the socket is unbound.
if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) {
return -1;
}
int ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, (uint16_t *)port, socket->timeout);
if (ret == NINA_ERROR_TIMEOUT) {
// The socket is Not closed on timeout when calling functions that accept a timeout.
*_errno = MP_ETIMEDOUT;
return 0;
} else if (ret < 0) {
// Close the socket on any other errors.
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
return ret;
}
STATIC int network_ninaw10_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t
level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
int ret = nina_socket_setsockopt(socket->fileno, level, opt, optval, optlen);
if (ret < 0) {
*_errno = ret;
network_ninaw10_socket_close(socket);
return -1;
}
return 0;
}
STATIC int network_ninaw10_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) {
if (timeout_ms == UINT32_MAX) {
// no timeout is given, set the socket to blocking mode.
timeout_ms = 0;
}
socket->timeout = timeout_ms;
return 0;
}
STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
*_errno = MP_EIO;
return -1;
}
static const mp_rom_map_elem_t nina_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_ninaw10_active_obj) },
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_ninaw10_scan_obj) },
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_ninaw10_connect_obj) },
{ MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&network_ninaw10_disconnect_obj) },
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_ninaw10_isconnected_obj) },
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_ninaw10_ifconfig_obj) },
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_ninaw10_config_obj) },
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_ninaw10_status_obj) },
// Network is not secured.
{ MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(NINA_SEC_OPEN) },
// Security type WEP (40 or 104).
{ MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(NINA_SEC_WEP) },
// Network secured with WPA/WPA2 personal(PSK).
{ MP_ROM_QSTR(MP_QSTR_WPA_PSK), MP_ROM_INT(NINA_SEC_WPA_PSK) },
};
static MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
const mod_network_nic_type_t mod_network_nic_type_nina = {
.base = {
{ &mp_type_type },
.name = MP_QSTR_nina,
.make_new = network_ninaw10_make_new,
.locals_dict = (mp_obj_t)&nina_locals_dict,
},
.gethostbyname = network_ninaw10_gethostbyname,
.socket = network_ninaw10_socket_socket,
.close = network_ninaw10_socket_close,
.bind = network_ninaw10_socket_bind,
.listen = network_ninaw10_socket_listen,
.accept = network_ninaw10_socket_accept,
.connect = network_ninaw10_socket_connect,
.send = network_ninaw10_socket_send,
.recv = network_ninaw10_socket_recv,
.sendto = network_ninaw10_socket_sendto,
.recvfrom = network_ninaw10_socket_recvfrom,
.setsockopt = network_ninaw10_socket_setsockopt,
.settimeout = network_ninaw10_socket_settimeout,
.ioctl = network_ninaw10_socket_ioctl,
};
#endif // #if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10

Wyświetl plik

@ -35,6 +35,7 @@ import subprocess
# Relative to top-level repo dir.
PATHS = [
# C
"drivers/ninaw10/*.[ch]",
"extmod/*.[ch]",
"extmod/btstack/*.[ch]",
"extmod/nimble/*.[ch]",