diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 06ca75db..6f84a3db 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(esp32spi) add_subdirectory(st7789) add_subdirectory(msa301) add_subdirectory(rv3028) diff --git a/drivers/esp32spi/CMakeLists.txt b/drivers/esp32spi/CMakeLists.txt new file mode 100644 index 00000000..c9dfb723 --- /dev/null +++ b/drivers/esp32spi/CMakeLists.txt @@ -0,0 +1 @@ +include(esp32spi.cmake) \ No newline at end of file diff --git a/drivers/esp32spi/esp32spi.cmake b/drivers/esp32spi/esp32spi.cmake new file mode 100644 index 00000000..2150df42 --- /dev/null +++ b/drivers/esp32spi/esp32spi.cmake @@ -0,0 +1,13 @@ +set(DRIVER_NAME esp32spi) +add_library(${DRIVER_NAME} INTERFACE) + +target_sources(${DRIVER_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/spi_drv.cpp + ${CMAKE_CURRENT_LIST_DIR}/ip_address.cpp +) + +target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_spi) \ No newline at end of file diff --git a/drivers/esp32spi/esp32spi.cpp b/drivers/esp32spi/esp32spi.cpp new file mode 100644 index 00000000..dda5d036 --- /dev/null +++ b/drivers/esp32spi/esp32spi.cpp @@ -0,0 +1,1405 @@ +#include "esp32spi.hpp" + +namespace pimoroni { + + enum cmd { + // 0x10 -> 0x1f + SET_NET = 0x10, + SET_PASSPHRASE = 0x11, + SET_KEY = 0x12, + //NULL + SET_IP_CONFIG = 0x14, + SET_DNS_CONFIG = 0x15, + SET_HOSTNAME = 0x16, + SET_POWER_MODE = 0x17, + SET_AP_NET = 0x18, + SET_AP_PASSPHRASE = 0x19, + SET_DEBUG = 0x1a, + GET_TEMPERATURE = 0x1b, + //NULL, NULL, NULL, NULL, + + // 0x20 -> 0x2f + GET_CONN_STATUS = 0x20, + GET_IP_ADDR = 0x21, + GET_MAC_ADDR = 0x22, + GET_CURR_SSID = 0x23, + GET_CURR_BSSID = 0x24, + GET_CURR_RSSI = 0x25, + GET_CURR_ENCT = 0x26, + SCAN_NETWORKS = 0x27, + START_SERVER_TCP = 0x28, + GET_STATE_TCP = 0x29, + DATA_SENT_TCP = 0x2a, + AVAIL_DATA_TCP = 0x2b, + GET_DATA_TCP = 0x2c, + START_CLIENT_TCP = 0x2d, + STOP_CLIENT_TCP = 0x2e, + GET_CLIENT_STATE_TCP = 0x2f, + + // 0x30 -> 0x3f + DISCONNECT = 0x30, + //NULL, + GET_IDX_RSSI = 0x32, + GET_IDX_ENCT = 0x33, + REQ_HOST_BY_NAME = 0x34, + GET_HOST_BY_NAME = 0x35, + START_SCAN_NETWORKS = 0x36, + GET_FW_VERSION = 0x37, + //NULL, + SEND_DATA_UDP = 0x39, + GET_REMOTE_DATA = 0x3a, + GET_TIME = 0x3b, + GET_IDX_BSSID = 0x3c, + GET_IDX_CHANNEL = 0x3d, + PING = 0x3e, + GET_SOCKET = 0x3f, + + // 0x40 -> 0x4f + SET_CLIENT_CERT = 0x40, //NOTE No matching function + SET_CERT_KEY = 0x41, //NOTE No matching function + //NULL, NULL, + SEND_DATA_TCP = 0x44, + GET_DATABUF_TCP = 0x45, + INSERT_DATABUF = 0x46, + //NULL, NULL, NULL, + WPA2_ENT_SET_IDENTITY = 0x4a, + WPA2_ENT_SET_USERNAME = 0x4b, + WPA2_ENT_SET_PASSWORD = 0x4c, + WPA2_ENT_SET_CA_CERT = 0x4d, //NOTE Not functional in Nina FW + WPA2_ENT_SET_CERT_KEY = 0x4e, //NOTE Not functional in Nina FW + WPA2_ENT_ENABLE = 0x4f, + + // 0x50 -> 0x5f + SET_PIN_MODE = 0x50, + SET_DIGITAL_WRITE = 0x51, + SET_ANALOG_WRITE = 0x52, + SET_DIGITAL_READ = 0x53, + SET_ANALOG_READ = 0x54, + }; + + bool Esp32Spi::init() { + driver.init(); + driver.reset(); + + return true; + } + + void Esp32Spi::get_network_data(uint8_t *ip_out, uint8_t *mask_out, uint8_t *gwip_out) { + SpiDrv::tParam params[SpiDrv::PARAM_NUMS_3] = { {0, ip_out}, + {0, mask_out}, + {0, gwip_out} }; + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_IP_ADDR, SpiDrv::PARAM_NUMS_1); + driver.send_byte_param(SpiDrv::DUMMY_DATA, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + driver.wait_response_params(GET_IP_ADDR, SpiDrv::PARAM_NUMS_3, params); + driver.esp_deselect(); + } + + void Esp32Spi::get_remote_data(uint8_t sock, uint8_t *ip_out, uint8_t *port_out) { + SpiDrv::tParam params[SpiDrv::PARAM_NUMS_2] = { {0, ip_out}, + {0, port_out} }; + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_REMOTE_DATA, SpiDrv::PARAM_NUMS_1); + driver.send_param(&sock, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + //Wait for reply + driver.wait_response_params(GET_REMOTE_DATA, SpiDrv::PARAM_NUMS_2, params); + driver.esp_deselect(); + } + + int8_t Esp32Spi::wifi_set_network(const std::string ssid) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_NET, SpiDrv::PARAM_NUMS_1); + driver.send_param((const uint8_t*)ssid.data(), ssid.length(), SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(5 + ssid.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_NET, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_NET\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + + return (data == WIFI_SPI_ACK) ? WL_SUCCESS : WL_FAILURE; + } + + int8_t Esp32Spi::wifi_set_passphrase(const std::string ssid, const std::string passphrase) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_PASSPHRASE, SpiDrv::PARAM_NUMS_2); + driver.send_param((const uint8_t*)ssid.data(), ssid.length(), SpiDrv::NO_LAST_PARAM); + driver.send_param((const uint8_t*)passphrase.data(), passphrase.length(), SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(6 + ssid.length() + passphrase.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + //Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_PASSPHRASE, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_PASSPHRASE\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + + return data; + } + + int8_t Esp32Spi::wifi_set_key(const std::string ssid, uint8_t key_idx, const std::string key) { + driver.wait_for_esp_select(); + + //Send Command + driver.send_cmd(SET_KEY, SpiDrv::PARAM_NUMS_3); + driver.send_param((uint8_t*)ssid.data(), ssid.length(), SpiDrv::NO_LAST_PARAM); + driver.send_param(&key_idx, KEY_IDX_LEN, SpiDrv::NO_LAST_PARAM); + driver.send_param((uint8_t*)key.data(), key.length(), SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(8 + ssid.length() + key.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + //Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_KEY, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_KEY\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + + return data; + } + + void Esp32Spi::config(uint8_t valid_params, uint32_t local_ip, uint32_t gateway, uint32_t subnet) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_IP_CONFIG, SpiDrv::PARAM_NUMS_4); + driver.send_param((uint8_t*)&valid_params, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param((uint8_t*)&local_ip, 4, SpiDrv::NO_LAST_PARAM); + driver.send_param((uint8_t*)&gateway, 4, SpiDrv::NO_LAST_PARAM); + driver.send_param((uint8_t*)&subnet, 4, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_IP_CONFIG, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_IP_CONFIG\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + } + + void Esp32Spi::set_dns(uint8_t valid_params, uint32_t dns_server1, uint32_t dns_server2) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_DNS_CONFIG, SpiDrv::PARAM_NUMS_3); + driver.send_param((uint8_t*)&valid_params, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param((uint8_t*)&dns_server1, 4, SpiDrv::NO_LAST_PARAM); + driver.send_param((uint8_t*)&dns_server2, 4, SpiDrv::LAST_PARAM); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_DNS_CONFIG, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_DNS_CONFIG\n"); + data = WL_FAILURE; + } + + driver.esp_deselect(); + } + + void Esp32Spi::set_hostname(const std::string hostname) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_HOSTNAME, SpiDrv::PARAM_NUMS_1); + driver.send_param((uint8_t*)hostname.data(), hostname.length(), SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(5 + hostname.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0 , data_len = 0; + if(!driver.wait_response_cmd(SET_HOSTNAME, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_HOSTNAME\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + } + + int8_t Esp32Spi::disconnect() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(DISCONNECT, SpiDrv::PARAM_NUMS_1); + driver.send_byte_param(SpiDrv::DUMMY_DATA, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + int8_t result = driver.wait_response_cmd(DISCONNECT, SpiDrv::PARAM_NUMS_1, &data, &data_len); + driver.esp_deselect(); + + return result; + } + + uint8_t Esp32Spi::get_connection_status() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_CONN_STATUS, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = WL_FAILURE, data_len = 0; + driver.wait_response_cmd(GET_CONN_STATUS, SpiDrv::PARAM_NUMS_1, &data, &data_len); + + driver.esp_deselect(); + + return data; + } + + uint8_t* Esp32Spi::get_mac_address() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_MAC_ADDR, SpiDrv::PARAM_NUMS_1); + driver.send_byte_param(SpiDrv::DUMMY_DATA, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data_len = 0; + driver.wait_response_cmd(GET_MAC_ADDR, SpiDrv::PARAM_NUMS_1, mac, &data_len); + + driver.esp_deselect(); + + return mac; + } + + void Esp32Spi::get_ip_address(IPAddress &ip_out) { + get_network_data(local_ip, subnet_mask, gateway_ip); + ip_out = local_ip; + } + + void Esp32Spi::get_subnet_mask(IPAddress &mask_out) { + get_network_data(local_ip, subnet_mask, gateway_ip); + mask_out = subnet_mask; + } + + void Esp32Spi::get_gateway_ip(IPAddress &ip_out) { + get_network_data(local_ip, subnet_mask, gateway_ip); + ip_out = gateway_ip; + } + + std::string Esp32Spi::get_current_ssid() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_CURR_SSID, SpiDrv::PARAM_NUMS_1); + driver.send_byte_param(SpiDrv::DUMMY_DATA, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + memset(ssid, 0x00, sizeof(ssid)); + + // Wait for reply + uint8_t data_len = 0; + driver.wait_response_cmd(GET_CURR_SSID, SpiDrv::PARAM_NUMS_1, (uint8_t*)ssid, &data_len); + driver.esp_deselect(); + + return ssid; + } + + uint8_t* Esp32Spi::get_current_bssid() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_CURR_BSSID, SpiDrv::PARAM_NUMS_1); + driver.send_byte_param(SpiDrv::DUMMY_DATA, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data_len = 0; + driver.wait_response_cmd(GET_CURR_BSSID, SpiDrv::PARAM_NUMS_1, bssid, &data_len); + driver.esp_deselect(); + + return bssid; + } + + int32_t Esp32Spi::get_current_rssi() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_CURR_RSSI, SpiDrv::PARAM_NUMS_1); + driver.send_byte_param(SpiDrv::DUMMY_DATA, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + int32_t rssi = 0; + uint8_t data_len = 0; + driver.wait_response_cmd(GET_CURR_RSSI, SpiDrv::PARAM_NUMS_1, (uint8_t*)&rssi, &data_len); + driver.esp_deselect(); + + return rssi; + } + + uint8_t Esp32Spi::get_current_encryption_type() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_CURR_ENCT, SpiDrv::PARAM_NUMS_1); + driver.send_byte_param(SpiDrv::DUMMY_DATA, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t enc_type = 0, data_len = 0; + driver.wait_response_cmd(GET_CURR_ENCT, SpiDrv::PARAM_NUMS_1, &enc_type, &data_len); + driver.esp_deselect(); + + return enc_type; + } + + int8_t Esp32Spi::start_scan_networks() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(START_SCAN_NETWORKS, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(START_SCAN_NETWORKS, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: START_SCAN_NETWORKS\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + + return ((int8_t)data == WL_FAILURE) ? data : (int8_t)WL_SUCCESS; + } + + uint8_t Esp32Spi::get_scan_networks() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SCAN_NETWORKS, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t ssid_list_num = 0; + driver.wait_response(SCAN_NETWORKS, &ssid_list_num, (uint8_t**)network_ssid, WL_NETWORKS_LIST_MAXNUM); + driver.esp_deselect(); + + return ssid_list_num; + } + + const char* Esp32Spi::get_ssid_networks(uint8_t network_item) { + if(network_item >= WL_NETWORKS_LIST_MAXNUM) + return nullptr; + + return network_ssid[network_item]; + } + + uint8_t Esp32Spi::get_enc_type_networks(uint8_t network_item) { + if(network_item >= WL_NETWORKS_LIST_MAXNUM) + return ENC_TYPE_UNKNOWN; + + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_IDX_ENCT, SpiDrv::PARAM_NUMS_1); + driver.send_param(&network_item, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t enc_type = 0, data_len = 0; + driver.wait_response_cmd(GET_IDX_ENCT, SpiDrv::PARAM_NUMS_1, &enc_type, &data_len); + driver.esp_deselect(); + + return enc_type; + } + + uint8_t* Esp32Spi::get_bssid_networks(uint8_t network_item, uint8_t* bssid_out) { + if(network_item >= WL_NETWORKS_LIST_MAXNUM) + return nullptr; + + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_IDX_BSSID, SpiDrv::PARAM_NUMS_1); + driver.send_param(&network_item, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data_len = 0; + driver.wait_response_cmd(GET_IDX_BSSID, SpiDrv::PARAM_NUMS_1, (uint8_t*)bssid_out, &data_len); + driver.esp_deselect(); + + return bssid_out; + } + + uint8_t Esp32Spi::get_channel_networks(uint8_t network_item) { + if(network_item >= WL_NETWORKS_LIST_MAXNUM) + return 0; + + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_IDX_CHANNEL, SpiDrv::PARAM_NUMS_1); + driver.send_param(&network_item, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t channel = 0, data_len = 0; + driver.wait_response_cmd(GET_IDX_CHANNEL, SpiDrv::PARAM_NUMS_1, &channel, &data_len); + driver.esp_deselect(); + + return channel; + } + + int32_t Esp32Spi::get_rssi_networks(uint8_t network_item) { + if(network_item >= WL_NETWORKS_LIST_MAXNUM) + return 0; + + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_IDX_RSSI, SpiDrv::PARAM_NUMS_1); + driver.send_param(&network_item, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + int32_t network_rssi = 0; + uint8_t data_len = 0; + driver.wait_response_cmd(GET_IDX_RSSI, SpiDrv::PARAM_NUMS_1, (uint8_t*)&network_rssi, &data_len); + driver.esp_deselect(); + + return network_rssi; + } + + bool Esp32Spi::req_host_by_name(const std::string hostname) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(REQ_HOST_BY_NAME, SpiDrv::PARAM_NUMS_1); + driver.send_param((uint8_t*)hostname.data(), hostname.length(), SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(5 + hostname.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + bool result = driver.wait_response_cmd(REQ_HOST_BY_NAME, SpiDrv::PARAM_NUMS_1, &data, &data_len); + driver.esp_deselect(); + + if(result) { + result = (data == 1); + } + + return result; + } + + bool Esp32Spi::get_host_by_name(IPAddress& ip_out) { + IPAddress dummy(0xFF,0xFF,0xFF,0xFF); + bool result = false; + + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_HOST_BY_NAME, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t ip_addr[WL_IPV4_LENGTH]; + uint8_t data_len = 0; + if(!driver.wait_response_cmd(GET_HOST_BY_NAME, SpiDrv::PARAM_NUMS_1, ip_addr, &data_len)) { + WARN("Response Err: GET_HOST_BY_NAME\n"); + } + else { + ip_out = ip_addr; + result = (ip_out != dummy); + } + driver.esp_deselect(); + + return result; + } + + bool Esp32Spi::get_host_by_name(const std::string hostname, IPAddress& ip_out) { + if(req_host_by_name(hostname)) { + return get_host_by_name(ip_out); + } + else { + return false; + } + } + + const char* Esp32Spi::get_fw_version() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_FW_VERSION, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data_len = 0; + if(!driver.wait_response_cmd(GET_FW_VERSION, SpiDrv::PARAM_NUMS_1, (uint8_t*)fw_version, &data_len)) { + WARN("Response Err: GET_FW_VERSION\n"); + } + driver.esp_deselect(); + + return fw_version; + } + + uint32_t Esp32Spi::get_time() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_TIME, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint32_t data = 0; + uint8_t data_len = 0; + if(!driver.wait_response_cmd(GET_TIME, SpiDrv::PARAM_NUMS_1, (uint8_t*)&data, &data_len)) { + WARN("Response Err: GET_TIME\n"); + } + driver.esp_deselect(); + + return data; + } + + void Esp32Spi::set_power_mode(uint8_t mode) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_POWER_MODE, SpiDrv::PARAM_NUMS_1); + driver.send_param(&mode, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + driver.wait_response_cmd(SET_POWER_MODE, SpiDrv::PARAM_NUMS_1, &data, &data_len); + driver.esp_deselect(); + } + + int8_t Esp32Spi::wifi_set_ap_network(const std::string ssid, uint8_t channel) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_AP_NET, SpiDrv::PARAM_NUMS_2); + driver.send_param((uint8_t*)ssid.data(), ssid.length(), SpiDrv::NO_LAST_PARAM); + driver.send_param(&channel, 1, SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(3 + ssid.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_AP_NET, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_AP_NET\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + + return (data == WIFI_SPI_ACK) ? WL_SUCCESS : WL_FAILURE; + } + + int8_t Esp32Spi::wifi_set_ap_passphrase(const std::string ssid, const std::string passphrase, uint8_t channel) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_AP_PASSPHRASE, SpiDrv::PARAM_NUMS_3); + driver.send_param((uint8_t*)ssid.data(), ssid.length(), SpiDrv::NO_LAST_PARAM); + driver.send_param((uint8_t*)passphrase.data(), passphrase.length(), SpiDrv::NO_LAST_PARAM); + driver.send_param(&channel, 1, SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(4 + ssid.length() + passphrase.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_AP_PASSPHRASE, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_AP_PASSPHRASE\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + + return data; + } + + int16_t Esp32Spi::ping(uint32_t ip_address, uint8_t ttl) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(PING, SpiDrv::PARAM_NUMS_2); + driver.send_param((uint8_t*)&ip_address, sizeof(ip_address), SpiDrv::NO_LAST_PARAM); + driver.send_param(&ttl, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint16_t data; + uint8_t data_len = 0; + if(!driver.wait_response_cmd(PING, SpiDrv::PARAM_NUMS_1, (uint8_t*)&data, &data_len)) { + WARN("Response Err: PING\n"); + data = WL_PING_ERROR; + } + driver.esp_deselect(); + + return data; + } + + void Esp32Spi::debug(uint8_t on) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_DEBUG, SpiDrv::PARAM_NUMS_1); + driver.send_param(&on, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + driver.wait_response_cmd(SET_DEBUG, SpiDrv::PARAM_NUMS_1, &data, &data_len); + driver.esp_deselect(); + } + + float Esp32Spi::get_temperature() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_TEMPERATURE, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + float data = 0; + uint8_t data_len = 0; + if(!driver.wait_response_cmd(GET_TEMPERATURE, SpiDrv::PARAM_NUMS_1, (uint8_t*)&data, &data_len)) { + WARN("Response Err: GET_TEMPERATURE\n"); + } + driver.esp_deselect(); + + return data; + } + + void Esp32Spi::pin_mode(uint8_t pin, uint8_t mode) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_PIN_MODE, SpiDrv::PARAM_NUMS_2); + driver.send_param(&pin, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(&mode, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_PIN_MODE, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_PIN_MODE\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + } + + void Esp32Spi::digital_write(uint8_t pin, uint8_t value) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_DIGITAL_WRITE, SpiDrv::PARAM_NUMS_2); + driver.send_param(&pin, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(&value, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_DIGITAL_WRITE, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_DIGITAL_WRITE\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + } + + void Esp32Spi::analog_write(uint8_t pin, uint8_t value) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_ANALOG_WRITE, SpiDrv::PARAM_NUMS_2); + driver.send_param(&pin, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(&value, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_ANALOG_WRITE, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_ANALOG_WRITE\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + } + + bool Esp32Spi::digital_read(uint8_t pin) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_DIGITAL_READ, SpiDrv::PARAM_NUMS_1); + driver.send_param(&pin, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(SET_DIGITAL_READ, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: SET_DIGITAL_READ\n"); + } + driver.esp_deselect(); + + return (data == 1); + } + + uint16_t Esp32Spi::analog_read(uint8_t pin, uint8_t atten) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SET_ANALOG_READ, SpiDrv::PARAM_NUMS_2); + driver.send_param(&pin, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(&atten, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint32_t data = 0; + uint8_t data_len = 0; + if(!driver.wait_response_cmd(SET_ANALOG_READ, SpiDrv::PARAM_NUMS_1, (uint8_t*)&data, &data_len)) { + WARN("Response Err: SET_ANALOG_READ\n"); + } + driver.esp_deselect(); + + return (uint16_t)data; //ESP only has a 12-bit ADC + } + + void Esp32Spi::start_server(uint16_t port, uint8_t sock, uint8_t protocol_mode) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(START_SERVER_TCP, SpiDrv::PARAM_NUMS_3); + driver.send_param(port, SpiDrv::NO_LAST_PARAM); + driver.send_param(&sock, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(&protocol_mode, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(START_SERVER_TCP, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: START_SERVER_TCP\n"); + } + driver.esp_deselect(); + } + + void Esp32Spi::start_server(uint32_t ip_address, uint16_t port, uint8_t sock, uint8_t protocol_mode) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(START_SERVER_TCP, SpiDrv::PARAM_NUMS_4); + driver.send_param((uint8_t*)&ip_address, sizeof(ip_address), SpiDrv::NO_LAST_PARAM); + driver.send_param(port, SpiDrv::NO_LAST_PARAM); + driver.send_param(&sock, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(&protocol_mode, 1, SpiDrv::LAST_PARAM); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(START_SERVER_TCP, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: START_SERVER_TCP\n"); + } + driver.esp_deselect(); + } + + void Esp32Spi::start_client(uint32_t ip_address, uint16_t port, uint8_t sock, uint8_t protocol_mode) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(START_CLIENT_TCP, SpiDrv::PARAM_NUMS_4); + driver.send_param((uint8_t*)&ip_address, sizeof(ip_address), SpiDrv::NO_LAST_PARAM); + driver.send_param(port, SpiDrv::NO_LAST_PARAM); + driver.send_param(&sock, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(&protocol_mode, 1, SpiDrv::LAST_PARAM); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(START_CLIENT_TCP, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: START_CLIENT_TCP\n"); + } + driver.esp_deselect(); + } + + void Esp32Spi::start_client(const std::string host, uint32_t ip_address, uint16_t port, uint8_t sock, uint8_t protocol_mode) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(START_CLIENT_TCP, SpiDrv::PARAM_NUMS_5); + driver.send_param((uint8_t*)host.data(), host.length(), SpiDrv::NO_LAST_PARAM); + driver.send_param((uint8_t*)&ip_address, sizeof(ip_address), SpiDrv::NO_LAST_PARAM); + driver.send_param(port, SpiDrv::NO_LAST_PARAM); + driver.send_param(&sock, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(&protocol_mode, 1, SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(17 + host.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(START_CLIENT_TCP, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: START_CLIENT_TCP\n"); + } + driver.esp_deselect(); + } + + void Esp32Spi::stop_client(uint8_t sock) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(STOP_CLIENT_TCP, SpiDrv::PARAM_NUMS_1); + driver.send_param(&sock, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(STOP_CLIENT_TCP, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: STOP_CLIENT_TCP\n"); + } + driver.esp_deselect(); + } + + uint8_t Esp32Spi::get_server_state(uint8_t sock) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_STATE_TCP, SpiDrv::PARAM_NUMS_1); + driver.send_param(&sock, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(GET_STATE_TCP, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: GET_STATE_TCP\n"); + } + driver.esp_deselect(); + + return data; + } + + uint8_t Esp32Spi::get_client_state(uint8_t sock) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_CLIENT_STATE_TCP, SpiDrv::PARAM_NUMS_1); + driver.send_param(&sock, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(GET_CLIENT_STATE_TCP, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: GET_CLIENT_STATE_TCP\n"); + } + driver.esp_deselect(); + + return data; + } + + uint16_t Esp32Spi::avail_data(uint8_t sock) { + if(!driver.available()) { + return 0; + } + + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(AVAIL_DATA_TCP, SpiDrv::PARAM_NUMS_1); + driver.send_param(&sock, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint16_t len = 0; + uint8_t data_len = 0; + driver.wait_response_cmd(AVAIL_DATA_TCP, SpiDrv::PARAM_NUMS_1, (uint8_t*)&len, &data_len); + driver.esp_deselect(); + + return len; + } + + + uint8_t Esp32Spi::avail_server(uint8_t sock) { + if(!driver.available()) { + return 255; + } + + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(AVAIL_DATA_TCP, SpiDrv::PARAM_NUMS_1); + driver.send_param(&sock, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint16_t socket = 0; + uint8_t data_len = 0; + driver.wait_response_cmd(AVAIL_DATA_TCP, SpiDrv::PARAM_NUMS_1, (uint8_t*)&socket, &data_len); + driver.esp_deselect(); + + return socket; + } + + bool Esp32Spi::get_data(uint8_t sock, uint8_t *data_out, uint8_t peek) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_DATA_TCP, SpiDrv::PARAM_NUMS_2); + driver.send_param(&sock, 1, SpiDrv::NO_LAST_PARAM); + driver.send_param(peek, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_data8(GET_DATA_TCP, &data, &data_len)) { + WARN("Response Err: GET_DATA_TCP\n"); + } + driver.esp_deselect(); + + if(data_len != 0) { + *data_out = data; + return true; + } + return false; + } + + bool Esp32Spi::get_data_buf(uint8_t sock, uint8_t *data_out, uint16_t *data_len_out) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_DATABUF_TCP, SpiDrv::PARAM_NUMS_2); + driver.send_buffer(&sock, 1); + driver.send_buffer((uint8_t *)data_len_out, sizeof(*data_len_out), SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + if(!driver.wait_response_data16(GET_DATABUF_TCP, data_out, data_len_out)) { + WARN("Response Err: GET_DATABUF_TCP\n"); + } + driver.esp_deselect(); + + if(*data_len_out != 0) { + return true; + } + return false; + } + + bool Esp32Spi::insert_data_buf(uint8_t sock, const uint8_t *data_in, uint16_t len) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(INSERT_DATABUF, SpiDrv::PARAM_NUMS_2); + driver.send_buffer(&sock, 1, SpiDrv::NO_LAST_PARAM); + driver.send_buffer((uint8_t *)data_in, len, SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(9 + len); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_data8(INSERT_DATABUF, &data, &data_len)) { + WARN("Response Err: INSERT_DATABUF\n"); + } + driver.esp_deselect(); + + if(data_len != 0) { + return (data == 1); + } + return false; + } + + bool Esp32Spi::send_udp_data(uint8_t sock) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SEND_DATA_UDP, SpiDrv::PARAM_NUMS_1); + driver.send_param(&sock, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_data8(SEND_DATA_UDP, &data, &data_len)) { + WARN("Response Err: SEND_DATA_UDP\n"); + } + driver.esp_deselect(); + + if(data_len != 0) { + return (data == 1); + } + return false; + } + + uint16_t Esp32Spi::send_data(uint8_t sock, const uint8_t *data_in, uint16_t len) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(SEND_DATA_TCP, SpiDrv::PARAM_NUMS_2); + driver.send_buffer(&sock, sizeof(sock)); + driver.send_buffer((uint8_t *)data_in, len, SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(9 + len); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint16_t data = 0; + uint8_t data_len = 0; + if(!driver.wait_response_data8(SEND_DATA_TCP, (uint8_t*)&data, &data_len)) { + WARN("Response Err: SEND_DATA_TCP\n"); + } + driver.esp_deselect(); + + return data; + } + + uint8_t Esp32Spi::check_data_sent(uint8_t sock) { + const uint16_t TIMEOUT_DATA_SENT = 25; + + uint16_t timeout = 0; + uint8_t data = 0, data_len = 0; + do { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(DATA_SENT_TCP, SpiDrv::PARAM_NUMS_1); + driver.send_param(&sock, 1, SpiDrv::LAST_PARAM); + + // Pad to multiple of 4 + driver.read_byte(); + driver.read_byte(); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + if(!driver.wait_response_cmd(DATA_SENT_TCP, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: DATA_SENT_TCP/n"); + } + driver.esp_deselect(); + + if(data) + timeout = 0; + else { + ++timeout; + sleep_ms(100); + } + + } while((data == 0) && (timeout < TIMEOUT_DATA_SENT)); + + return (timeout == TIMEOUT_DATA_SENT) ? 0 : 1; + } + + uint8_t Esp32Spi::get_socket() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(GET_SOCKET, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = -1, data_len = 0; + driver.wait_response_cmd(GET_SOCKET, SpiDrv::PARAM_NUMS_1, &data, &data_len); + driver.esp_deselect(); + + return data; + } + + void Esp32Spi::wifi_set_ent_identity(const std::string identity) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(WPA2_ENT_SET_IDENTITY, SpiDrv::PARAM_NUMS_1); + driver.send_param((uint8_t*)identity.data(), identity.length(), SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(5 + identity.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0 , data_len = 0; + if(!driver.wait_response_cmd(WPA2_ENT_SET_IDENTITY, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: WPA2_ENT_SET_IDENTITY\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + } + + void Esp32Spi::wifi_set_ent_username(const std::string username) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(WPA2_ENT_SET_USERNAME, SpiDrv::PARAM_NUMS_1); + driver.send_param((uint8_t*)username.data(), username.length(), SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(5 + username.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0 , data_len = 0; + if(!driver.wait_response_cmd(WPA2_ENT_SET_USERNAME, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: WPA2_ENT_SET_USERNAME\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + } + + void Esp32Spi::wifi_set_ent_password(const std::string password) { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(WPA2_ENT_SET_PASSWORD, SpiDrv::PARAM_NUMS_1); + driver.send_param((uint8_t*)password.data(), password.length(), SpiDrv::LAST_PARAM); + driver.pad_to_multiple_of_4(5 + password.length()); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0 , data_len = 0; + if(!driver.wait_response_cmd(WPA2_ENT_SET_PASSWORD, SpiDrv::PARAM_NUMS_1, &data, &data_len)) { + WARN("Response Err: WPA2_ENT_SET_PASSWORD\n"); + data = WL_FAILURE; + } + driver.esp_deselect(); + } + + void Esp32Spi::wifi_set_ent_enable() { + driver.wait_for_esp_select(); + + // Send Command + driver.send_cmd(WPA2_ENT_ENABLE, SpiDrv::PARAM_NUMS_0); + + driver.esp_deselect(); + driver.wait_for_esp_select(); + + // Wait for reply + uint8_t data = 0, data_len = 0; + if(!driver.wait_response_cmd(WPA2_ENT_ENABLE, SpiDrv::PARAM_NUMS_1, (uint8_t*)&data, &data_len)) { + WARN("Response Err: WPA2_ENT_ENABLE\n"); + } + driver.esp_deselect(); + } +} \ No newline at end of file diff --git a/drivers/esp32spi/esp32spi.hpp b/drivers/esp32spi/esp32spi.hpp new file mode 100644 index 00000000..fb30b9f2 --- /dev/null +++ b/drivers/esp32spi/esp32spi.hpp @@ -0,0 +1,222 @@ +#pragma once + +#include +#include +#include "pico/stdlib.h" +#include "spi_drv.hpp" +#include "ip_address.hpp" + + +#define WARN(message) {} + +#define WL_FW_VER_LENGTH 6 + +#define WIFI_SPI_ACK 1 +#define WIFI_SPI_ERR 0xFF + +// Maxmium number of socket +#define WIFI_MAX_SOCK_NUM 10 +// Socket not available constant +#define SOCK_NOT_AVAIL 255 +// Default state value for Wifi state field +#define NA_STATE -1 +//Maximum number of attempts to establish wifi connection +#define WL_MAX_ATTEMPT_CONNECTION 10 + +enum wl_ping_result_t { + WL_PING_DEST_UNREACHABLE = -1, + WL_PING_TIMEOUT = -2, + WL_PING_UNKNOWN_HOST = -3, + WL_PING_ERROR = -4 +}; + +enum wl_status_t { + WL_NO_SHIELD = 255, + WL_NO_MODULE = WL_NO_SHIELD, + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL, + WL_SCAN_COMPLETED, + WL_CONNECTED, + WL_CONNECT_FAILED, + WL_CONNECTION_LOST, + WL_DISCONNECTED, + WL_AP_LISTENING, + WL_AP_CONNECTED, + WL_AP_FAILED +}; + + +enum wl_tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + +enum wl_enc_type { /* Values map to 802.11 encryption suites... */ + ENC_TYPE_WEP = 5, + ENC_TYPE_TKIP = 2, + ENC_TYPE_CCMP = 4, + /* ... except these two, 7 and 8 are reserved in 802.11-2007 */ + ENC_TYPE_NONE = 7, + ENC_TYPE_AUTO = 8, + + ENC_TYPE_UNKNOWN = 255 +}; + +enum wl_error_code_t { + WL_FAILURE = -1, + WL_SUCCESS = 1, +}; + +enum sv_protocol_mode { + TCP_MODE, + UDP_MODE, + TLS_MODE, + UDP_MULTICAST_MODE, + TLS_BEARSSL_MODE +}; + + +#define KEY_IDX_LEN 1 + + + +namespace pimoroni { + + class Esp32Spi { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const uint8_t INPUT = 0; + static const uint8_t OUTPUT = 1; + static const uint8_t INPUT_PULLUP = 2; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + SpiDrv driver; + + char network_ssid[WL_NETWORKS_LIST_MAXNUM][WL_SSID_MAX_LENGTH]; + + // Firmware version string in the format a.b.c + char fw_version[WL_FW_VER_LENGTH]; + + // Settings of current selected network + char ssid[WL_SSID_MAX_LENGTH]; + uint8_t bssid[WL_MAC_ADDR_LENGTH]; + uint8_t mac[WL_MAC_ADDR_LENGTH]; + uint8_t local_ip[WL_IPV4_LENGTH]; + uint8_t subnet_mask[WL_IPV4_LENGTH]; + uint8_t gateway_ip[WL_IPV4_LENGTH]; + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + virtual bool init(); + + //-------------------------------------------------- + //From https://github.com/adafruit/WiFiNINA/blob/master/src/utility/wifi_drv.cpp + //-------------------------------------------------- + + void get_network_data(uint8_t *ip_out, uint8_t *mask_out, uint8_t *gwip_out); + void get_remote_data(uint8_t sock, uint8_t *ip_out, uint8_t *port_out); + + int8_t wifi_set_network(const std::string ssid); + int8_t wifi_set_passphrase(const std::string ssid, const std::string passphrase); + int8_t wifi_set_key(const std::string ssid, uint8_t key_idx, const std::string key); + + void config(uint8_t valid_params, uint32_t local_ip, uint32_t gateway, uint32_t subnet); + + void set_dns(uint8_t valid_params, uint32_t dns_server1, uint32_t dns_server2); + void set_hostname(std::string hostname); + int8_t disconnect(); + + uint8_t get_connection_status(); + uint8_t* get_mac_address(); + + void get_ip_address(IPAddress &ip_out); + void get_subnet_mask(IPAddress &mask_out); + void get_gateway_ip(IPAddress &ip_out); + + std::string get_current_ssid(); + uint8_t* get_current_bssid(); + int32_t get_current_rssi(); + uint8_t get_current_encryption_type(); + + int8_t start_scan_networks(); + uint8_t get_scan_networks(); + const char* get_ssid_networks(uint8_t network_item); + + uint8_t get_enc_type_networks(uint8_t network_item); + uint8_t* get_bssid_networks(uint8_t network_item, uint8_t* bssid_out); + uint8_t get_channel_networks(uint8_t network_item); + int32_t get_rssi_networks(uint8_t network_item); + + bool req_host_by_name(const std::string hostname); + bool get_host_by_name(IPAddress& ip_out); + bool get_host_by_name(const std::string hostname, IPAddress& ip_out); + + const char* get_fw_version(); + uint32_t get_time(); + void set_power_mode(uint8_t mode); + + int8_t wifi_set_ap_network(const std::string ssid, uint8_t channel); + int8_t wifi_set_ap_passphrase(const std::string ssid, const std::string passphrase, uint8_t channel); + + int16_t ping(uint32_t ip_address, uint8_t ttl); + + void debug(uint8_t on); + float get_temperature(); + void pin_mode(uint8_t pin, uint8_t mode); + + void digital_write(uint8_t pin, uint8_t value); + void analog_write(uint8_t pin, uint8_t value); + bool digital_read(uint8_t pin); + uint16_t analog_read(uint8_t pin, uint8_t atten = 3); + + //-------------------------------------------------- + //From https://github.com/adafruit/WiFiNINA/blob/master/src/utility/server_drv.cpp + //-------------------------------------------------- + + void start_server(uint16_t port, uint8_t sock, uint8_t protocol_mode = TCP_MODE); + void start_server(uint32_t ip_address, uint16_t port, uint8_t sock, uint8_t protocol_mode = TCP_MODE); + void start_client(uint32_t ip_address, uint16_t port, uint8_t sock, uint8_t protocol_mode = TCP_MODE); + void start_client(const std::string host, uint32_t ip_address, uint16_t port, uint8_t sock, uint8_t protocol_mode = TCP_MODE); + void stop_client(uint8_t sock); + + uint8_t get_server_state(uint8_t sock); + uint8_t get_client_state(uint8_t sock); + uint16_t avail_data(uint8_t sock); + uint8_t avail_server(uint8_t sock); + + bool get_data(uint8_t sock, uint8_t *data_out, uint8_t peek); + bool get_data_buf(uint8_t sock, uint8_t *data_out, uint16_t *data_len_out); + bool insert_data_buf(uint8_t sock, const uint8_t *data_in, uint16_t len); + bool send_udp_data(uint8_t sock); + + uint16_t send_data(uint8_t sock, const uint8_t *data_in, uint16_t len); + uint8_t check_data_sent(uint8_t sock); + uint8_t get_socket(); + + //-------------------------------------------------- + + void wifi_set_ent_identity(const std::string identity); + void wifi_set_ent_username(const std::string username); + void wifi_set_ent_password(const std::string password); + void wifi_set_ent_enable(); + }; + +} \ No newline at end of file diff --git a/drivers/esp32spi/ip_address.cpp b/drivers/esp32spi/ip_address.cpp new file mode 100644 index 00000000..b6bba189 --- /dev/null +++ b/drivers/esp32spi/ip_address.cpp @@ -0,0 +1,62 @@ +#include "ip_address.hpp" + +namespace pimoroni { + + IPAddress::IPAddress() { + addr.dword = 0; + } + + IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { + addr.bytes[0] = first_octet; + addr.bytes[1] = second_octet; + addr.bytes[2] = third_octet; + addr.bytes[3] = fourth_octet; + } + + IPAddress::IPAddress(uint32_t address) { + addr.dword = address; + } + + IPAddress::IPAddress(const uint8_t *address) { + addr.bytes[0] = address[0]; + addr.bytes[1] = address[1]; + addr.bytes[2] = address[2]; + addr.bytes[3] = address[3]; + } + + bool IPAddress::operator==(const IPAddress &address) const { + return (addr.dword == address.addr.dword); + } + + bool IPAddress::operator==(const uint32_t &address) const { + return (addr.dword == address); + } + + uint8_t IPAddress::operator[](int index) const { + return addr.bytes[index]; + } + + uint8_t& IPAddress::operator[](int index) { + return addr.bytes[index]; + } + + IPAddress& IPAddress::operator=(uint32_t address) { + addr.dword = address; + return *this; + } + + IPAddress::operator uint32_t() const { + return addr.dword; + } + + std::string IPAddress::to_string() const { + char buf[16] = {0}; + snprintf(buf, 16, "%d.%d.%d.%d", addr.bytes[0], addr.bytes[1], addr.bytes[2], addr.bytes[3]); + return std::string(buf, 16); + } + + const uint8_t* IPAddress::to_bytes() const { + return addr.bytes; + } + +} \ No newline at end of file diff --git a/drivers/esp32spi/ip_address.hpp b/drivers/esp32spi/ip_address.hpp new file mode 100644 index 00000000..08abf2af --- /dev/null +++ b/drivers/esp32spi/ip_address.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "pico/stdlib.h" +#include +#include "spi_drv.hpp" + +namespace pimoroni { + + class IPAddress { + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + union { + uint8_t bytes[WL_IPV4_LENGTH]; + uint32_t dword; + } addr; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + + //-------------------------------------------------- + // Operators + //-------------------------------------------------- + public: + bool operator==(const IPAddress &address) const; + bool operator==(const uint32_t &address) const; + uint8_t operator[](int index) const; + uint8_t& operator[](int index); + IPAddress& operator=(uint32_t address); + operator uint32_t() const; + std::string to_string() const; + const uint8_t* to_bytes() const; + }; + +} \ No newline at end of file diff --git a/drivers/esp32spi/spi_drv.cpp b/drivers/esp32spi/spi_drv.cpp new file mode 100644 index 00000000..8270e89e --- /dev/null +++ b/drivers/esp32spi/spi_drv.cpp @@ -0,0 +1,314 @@ +#include "spi_drv.hpp" + +namespace pimoroni { + + void SpiDrv::init() { + spi_init(spi, 8000000); + gpio_set_function(miso, GPIO_FUNC_SPI); + gpio_set_function(sck, GPIO_FUNC_SPI); + gpio_set_function(mosi, GPIO_FUNC_SPI); + + // Chip select is active-low, so we'll initialise it to a driven-high state + gpio_init(cs); + gpio_set_dir(cs, GPIO_OUT); + gpio_put(cs, true); + + gpio_init(gpio0); + gpio_set_dir(gpio0, GPIO_OUT); + + gpio_init(resetn); + gpio_set_dir(resetn, GPIO_OUT); + } + + void SpiDrv::reset() { + gpio_put(gpio0, true); + gpio_put(cs, true); + gpio_put(resetn, false); + sleep_ms(10); + gpio_put(resetn, true); + sleep_ms(750); + } + + bool SpiDrv::available() { + return gpio_get(gpio0); + } + + void SpiDrv::esp_select() { + gpio_put(cs, false); + } + + void SpiDrv::esp_deselect() { + gpio_put(cs, true); + } + + bool SpiDrv::get_esp_ready() { + return !gpio_get(ack); + } + + bool SpiDrv::get_esp_ack() { + return gpio_get(ack); + } + + void SpiDrv::wait_for_esp_ack() { + while(!get_esp_ack()) { + tight_loop_contents(); + } + } + + void SpiDrv::wait_for_esp_ready() { + while(!get_esp_ready()) { + tight_loop_contents(); + } + } + + void SpiDrv::wait_for_esp_select() { + wait_for_esp_ready(); + esp_select(); + wait_for_esp_ack(); + } + + int SpiDrv::wait_for_byte(uint8_t wait_byte) { + int timeout = BYTE_TIMEOUT; + uint8_t byte_read = 0; + do{ + byte_read = read_byte(); //get data byte + if (byte_read == ERR_CMD) { + printf("Err cmd received\n"); + return -1; + } + } while((timeout-- > 0) && (byte_read != wait_byte)); + return (byte_read == wait_byte); + } + + bool SpiDrv::read_and_check_byte(uint8_t check_byte, uint8_t *byte_out) { + get_param(byte_out); + return (*byte_out == check_byte); + } + + uint8_t SpiDrv::read_byte() { + uint8_t byte_read = 0; + get_param(&byte_read); + return byte_read; + } + + bool SpiDrv::wait_response_params(uint8_t cmd, uint8_t num_param, tParam *params_out) { + uint8_t data = 0; + int i = 0; + + IF_CHECK_START_CMD() { + CHECK_DATA(cmd | REPLY_FLAG, data){}; + + uint8_t num_param_read = read_byte(); + if(num_param_read != 0) { + for(i = 0; i < num_param_read; ++i) { + params_out[i].param_len = read_param_len8(); + spi_read_blocking(spi, DUMMY_DATA, params_out[i].param, params_out[i].param_len); + } + } + else { + printf("Error num_param == 0\n"); + return false; + } + + if(num_param != num_param_read) { + printf("Mismatch num_param\n"); + return false; + } + + read_and_check_byte(END_CMD, &data); + } + return true; + } + + bool SpiDrv::wait_response_cmd(uint8_t cmd, uint8_t num_param, uint8_t *param_out, uint8_t *param_len_out) { + uint8_t data = 0; + int ii = 0; + + IF_CHECK_START_CMD() { + CHECK_DATA(cmd | REPLY_FLAG, data){}; + + CHECK_DATA(num_param, data) { + read_param_len8(param_len_out); + for(ii = 0; ii < (*param_len_out); ++ii) { + get_param(¶m_out[ii]); + } + } + + read_and_check_byte(END_CMD, &data); + } + + return true; + } + + bool SpiDrv::wait_response_data8(uint8_t cmd, uint8_t *param_out, uint8_t *param_len_out) { + uint8_t data = 0; + + IF_CHECK_START_CMD() { + CHECK_DATA(cmd | REPLY_FLAG, data){}; + + uint8_t num_param_read = read_byte(); + if(num_param_read != 0) { + read_param_len8(param_len_out); + spi_read_blocking(spi, DUMMY_DATA, param_out, *param_len_out); + } + + read_and_check_byte(END_CMD, &data); + } + + return true; + } + + bool SpiDrv::wait_response_data16(uint8_t cmd, uint8_t* param_out, uint16_t *param_len_out) { + uint8_t data = 0; + + IF_CHECK_START_CMD() { + CHECK_DATA(cmd | REPLY_FLAG, data){}; + + uint8_t num_param_read = read_byte(); + if(num_param_read != 0) { + read_param_len16(param_len_out); + spi_read_blocking(spi, DUMMY_DATA, param_out, *param_len_out); + } + + read_and_check_byte(END_CMD, &data); + } + + return false; + } + + bool SpiDrv::wait_response(uint8_t cmd, uint8_t *num_param_out, uint8_t **params_out, uint8_t max_num_params) { + uint8_t data = 0; + int i = 0; + + uint8_t* index[WL_SSID_MAX_LENGTH]; + + for(i = 0 ; i < WL_NETWORKS_LIST_MAXNUM; i++) + index[i] = (uint8_t*)params_out + (WL_SSID_MAX_LENGTH * i); + + IF_CHECK_START_CMD() { + CHECK_DATA(cmd | REPLY_FLAG, data){}; + + uint8_t num_param_read = read_byte(); + + if(num_param_read > max_num_params) { + num_param_read = max_num_params; + } + *num_param_out = num_param_read; + if(num_param_read != 0) { + for(i = 0; i < num_param_read; ++i) { + uint8_t param_len = read_param_len8(); + spi_read_blocking(spi, DUMMY_DATA, index[i], param_len); + index[i][param_len] = 0; + } + } + else { + printf("Error numParams == 0\n"); + read_and_check_byte(END_CMD, &data); + return false; + } + read_and_check_byte(END_CMD, &data); + } + return true; + } + + void SpiDrv::send_param(const uint8_t *param, uint8_t param_len, lastParam last_param) { + send_param_len8(param_len); + + spi_write_blocking(spi, param, param_len); + + if(last_param) { + uint8_t buf = END_CMD; + spi_write_blocking(spi, &buf, 1); + } + } + + void SpiDrv::send_param_len8(uint8_t param_len) { + spi_write_blocking(spi, ¶m_len, 1); + } + + void SpiDrv::send_param_len16(uint16_t param_len) { + uint8_t buf[2]; + buf[0] = (uint8_t)((param_len & 0xff00) >> 8); + buf[1] = (uint8_t)(param_len & 0xff); + spi_write_blocking(spi, buf, 2); + } + + uint8_t SpiDrv::read_param_len8(uint8_t *param_len_out) { + uint8_t param_len; + get_param(¶m_len); + if(param_len_out != nullptr) { + *param_len_out = param_len; + } + return param_len; + } + + uint16_t SpiDrv::read_param_len16(uint16_t *param_len_out) { + uint8_t buf[2]; + spi_read_blocking(spi, DUMMY_DATA, buf, 2); + uint16_t param_len = (buf[0] << 8) | (buf[1] & 0xff); + if(param_len_out != nullptr) { + *param_len_out = param_len; + } + return param_len; + } + + void SpiDrv::send_buffer(const uint8_t* param, uint16_t param_len, lastParam last_param) { + send_param_len16(param_len); + + spi_write_blocking(spi, param, param_len); + + if(last_param) { + uint8_t buf = END_CMD; + spi_write_blocking(spi, &buf, 1); + } + } + + void SpiDrv::send_param(uint16_t param, lastParam last_param) { + send_param_len8(2); + + uint8_t buf[2]; + buf[0] = (uint8_t)((param & 0xff00) >> 8); + buf[1] = (uint8_t)(param & 0xff); + spi_write_blocking(spi, buf, 2); + + if(last_param) { + uint8_t buf = END_CMD; + spi_write_blocking(spi, &buf, 1); + } + } + + void SpiDrv::send_byte_param(uint8_t param, lastParam last_param) { + send_param_len8(1); + + spi_write_blocking(spi, ¶m, 1); + + if(last_param) { + uint8_t buf = END_CMD; + spi_write_blocking(spi, &buf, 1); + } + } + + void SpiDrv::send_cmd(uint8_t cmd, uint8_t num_param) { + uint8_t buf[3]; + buf[0] = START_CMD; + buf[1] = cmd & ~(REPLY_FLAG); + buf[2] = num_param; + spi_write_blocking(spi, buf, 3); + + if(num_param == 0) { + uint8_t buf = END_CMD; + spi_write_blocking(spi, &buf, 1); + } + } + + void SpiDrv::pad_to_multiple_of_4(int command_size) { + while(command_size % 4) { + read_byte(); + command_size++; + } + } + + void SpiDrv::get_param(uint8_t* param_out) { + spi_read_blocking(spi, DUMMY_DATA, param_out, 1); + } +} \ No newline at end of file diff --git a/drivers/esp32spi/spi_drv.hpp b/drivers/esp32spi/spi_drv.hpp new file mode 100644 index 00000000..13610016 --- /dev/null +++ b/drivers/esp32spi/spi_drv.hpp @@ -0,0 +1,171 @@ +#pragma once + +#include +#include "pico/stdlib.h" +#include "hardware/spi.h" + +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 +// Length of passphrase. Valid lengths are 8-63. +#define WL_WPA_KEY_MAX_LENGTH 63 +// Length of key in bytes. Valid values are 5 and 13. +#define WL_WEP_KEY_MAX_LENGTH 13 +// Size of a MAC-address or BSSID +#define WL_MAC_ADDR_LENGTH 6 +// Size of a IP address +#define WL_IPV4_LENGTH 4 +// Maximum size of a SSID list +#define WL_NETWORKS_LIST_MAXNUM 10 + + +#define IF_CHECK_START_CMD() \ +if(!wait_for_byte(START_CMD)) { \ + printf("Error waiting START_CMD\n"); \ + return false; \ +} \ +else \ + + +#define CHECK_DATA(check, x) \ +if(!read_and_check_byte(check, &x)) { \ + printf("Reply error\n"); \ + return false; \ +} \ +else \ + +namespace pimoroni { + + class SpiDrv { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const uint8_t DEFAULT_CS_PIN = 7; + static const uint8_t DEFAULT_SCK_PIN = 18; + static const uint8_t DEFAULT_MOSI_PIN = 19; + static const uint8_t DEFAULT_MISO_PIN = 16; + static const uint8_t DEFAULT_RESETN_PIN = 11; + static const uint8_t DEFAULT_GPIO0_PIN = 2; + static const uint8_t DEFAULT_ACK_PIN = 10; + + static const uint8_t DUMMY_DATA = 0xFF; + + private: + static const uint8_t START_CMD = 0xE0; + static const uint8_t END_CMD = 0xEE; + static const uint8_t ERR_CMD = 0xEF; + + static const uint8_t CMD_FLAG = 0; + static const uint8_t REPLY_FLAG = 1 << 7; + static const uint8_t DATA_FLAG = 0x40; + + static const uint8_t CMD_POS = 1; // Position of Command OpCode on SPI stream + static const uint8_t PARAM_LEN_POS = 2; // Position of Param len on SPI stream + + static const int BYTE_TIMEOUT = 1000; + + + //-------------------------------------------------- + // Enums + //-------------------------------------------------- + public: + enum numParams : uint8_t { + PARAM_NUMS_0 = 0, + PARAM_NUMS_1, + PARAM_NUMS_2, + PARAM_NUMS_3, + PARAM_NUMS_4, + PARAM_NUMS_5 + }; + + enum lastParam : bool { + NO_LAST_PARAM = false, + LAST_PARAM = true, + }; + + + //-------------------------------------------------- + // Substructures + //-------------------------------------------------- + public: + struct tParam { + uint8_t param_len; + uint8_t* param; + }; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + spi_inst_t *spi = spi0; + + int8_t cs = DEFAULT_CS_PIN; + int8_t sck = DEFAULT_SCK_PIN; + int8_t mosi = DEFAULT_MOSI_PIN; + int8_t miso = DEFAULT_MISO_PIN; + int8_t resetn = DEFAULT_RESETN_PIN; + int8_t gpio0 = DEFAULT_GPIO0_PIN; + int8_t ack = DEFAULT_ACK_PIN; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + SpiDrv() {} + + SpiDrv(spi_inst_t *spi, + uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t miso, + uint8_t resetn, uint8_t gpio0, uint8_t ack) : + spi(spi), cs(cs), sck(sck), mosi(mosi), miso(miso), + resetn(resetn), gpio0(gpio0), ack(ack) {} + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + void init(); + void reset(); + + bool available(); + + void esp_select(); + void esp_deselect(); + + bool get_esp_ready(); + bool get_esp_ack(); + + void wait_for_esp_ack(); + void wait_for_esp_ready(); + void wait_for_esp_select(); + int wait_for_byte(uint8_t wait_byte); + + bool read_and_check_byte(uint8_t check_byte, uint8_t *byte_out); + uint8_t read_byte(); + + bool wait_response_params(uint8_t cmd, uint8_t num_param, tParam *params_out); + bool wait_response_cmd(uint8_t cmd, uint8_t num_param, uint8_t *param_out, uint8_t *param_len_out); + bool wait_response_data8(uint8_t cmd, uint8_t *param_out, uint8_t *param_len_out); + bool wait_response_data16(uint8_t cmd, uint8_t *param_out, uint16_t *param_len_out); + bool wait_response(uint8_t cmd, uint8_t *num_param_out, uint8_t **params_out, uint8_t max_num_params); + + void send_param(const uint8_t* param, uint8_t param_len, lastParam last_param = NO_LAST_PARAM); + void send_param_len8(uint8_t param_len); + void send_param_len16(uint16_t param_len); + + uint8_t read_param_len8(uint8_t *param_len_out = nullptr); + uint16_t read_param_len16(uint16_t *param_len_out = nullptr); + + void send_buffer(const uint8_t *param, uint16_t param_len, lastParam last_param = NO_LAST_PARAM); + void send_param(uint16_t param, lastParam last_param = NO_LAST_PARAM); + void send_byte_param(uint8_t param, lastParam last_param = NO_LAST_PARAM); + void send_cmd(uint8_t cmd, uint8_t num_param); + + void pad_to_multiple_of_4(int command_size); + + private: + void get_param(uint8_t *param_out); + }; +} \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7d110caa..d3886bfb 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -7,4 +7,5 @@ add_subdirectory(pico_explorer) add_subdirectory(pico_rgb_keypad) add_subdirectory(pico_rtc_display) add_subdirectory(pico_tof_display) -add_subdirectory(pico_audio) \ No newline at end of file +add_subdirectory(pico_audio) +add_subdirectory(pico_wireless) diff --git a/examples/pico_wireless/.gitignore b/examples/pico_wireless/.gitignore new file mode 100644 index 00000000..92001b55 --- /dev/null +++ b/examples/pico_wireless/.gitignore @@ -0,0 +1 @@ +secrets.h \ No newline at end of file diff --git a/examples/pico_wireless/CMakeLists.txt b/examples/pico_wireless/CMakeLists.txt new file mode 100644 index 00000000..9178b942 --- /dev/null +++ b/examples/pico_wireless/CMakeLists.txt @@ -0,0 +1,3 @@ +include("${CMAKE_CURRENT_LIST_DIR}/demo.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/rgb_http.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/cheerlights.cmake") diff --git a/examples/pico_wireless/cheerlights.cmake b/examples/pico_wireless/cheerlights.cmake new file mode 100644 index 00000000..08e16595 --- /dev/null +++ b/examples/pico_wireless/cheerlights.cmake @@ -0,0 +1,14 @@ +add_executable( + wireless_cheerlights + cheerlights.cpp +) + +# enable usb output, disable uart output +pico_enable_stdio_usb(wireless_cheerlights 1) +pico_enable_stdio_uart(wireless_cheerlights 1) + +# Pull in pico libraries that we need +target_link_libraries(wireless_cheerlights pico_stdlib pico_wireless) + +# create map/bin/hex file etc. +pico_add_extra_outputs(wireless_cheerlights) diff --git a/examples/pico_wireless/cheerlights.cpp b/examples/pico_wireless/cheerlights.cpp new file mode 100644 index 00000000..e11886e1 --- /dev/null +++ b/examples/pico_wireless/cheerlights.cpp @@ -0,0 +1,258 @@ +#include +#include "pico/stdlib.h" +#include "hardware/uart.h" +#include "hardware/gpio.h" +#include "hardware/spi.h" +#include "pico_wireless.hpp" +#include "secrets.h" + +#include +#include + +#define HTTP_PORT 80 +#define HTTP_REQUEST_BUF_SIZE 2048 + +#define DNS_CLOUDFLARE IPAddress(1, 1, 1, 1) +#define DNS_GOOGLE IPAddress(8, 8, 8, 8) +#define USE_DNS DNS_CLOUDFLARE + +#define HTTP_REQUEST_DELAY 30 // Seconds between requests +#define HTTP_REQUEST_HOST "api.thingspeak.com" +#define HTTP_REQUEST_PATH "/channels/1417/field/2/last.txt" +#define HTTP_RESPONSE_BUF_SIZE 1024 + +using namespace pimoroni; + +PicoWireless wireless; +uint8_t r, g, b; +uint8_t response_buf[HTTP_RESPONSE_BUF_SIZE]; +typedef void(*http_handler)(unsigned int status_code, std::vector response_head, std::vector esponse_body); + +enum HTTP_REQUEST_STATUS { + HTTP_REQUEST_OK = 0, + HTTP_REQUEST_TIMEOUT, + HTTP_REQUEST_RESPONSE_INVALID, + HTTP_REQUEST_RESPONSE_UNHANDLED, + HTTP_REQUEST_CONNECTION_FAILED, + HTTP_REQUEST_RESPONSE_OVERFLOW, + HTTP_REQUEST_NO_RESPONSE +}; + +std::vector split(std::string_view str, std::string delim="\r\n") { + std::vector result; + size_t offset = 0; + while (offset < str.size()) { + const auto pos = str.find_first_of(delim, offset); + // Emit an empty view even if two adjacent delimiters are found + // this ensurs the HTTP "blank line" start of content is found + result.emplace_back(str.substr(offset, pos - offset)); + if (pos == std::string_view::npos) break; + offset = pos + delim.length(); + } + return result; +} + +uint32_t millis() { + return to_us_since_boot(get_absolute_time()) / 1000; +} + +bool wifi_connect(std::string network, std::string password, IPAddress dns_server, uint32_t timeout=10000) { + printf("Connecting to %s...\n", network.c_str()); + wireless.wifi_set_passphrase(network, password); + + uint32_t t_start = millis(); + + while(millis() - t_start < timeout) { + if(wireless.get_connection_status() == WL_CONNECTED) { + printf("Connected!\n"); + wireless.set_dns(1, dns_server, 0); + return true; + } + wireless.set_led(255, 0, 0); + sleep_ms(500); + wireless.set_led(0, 0, 0); + sleep_ms(500); + printf("...\n"); + } + + return false; +} + +/* Basic function to connect to a client IP:PORT and poll for an established connection */ +bool connect(IPAddress host_address, uint16_t port, uint8_t client_sock, uint32_t timeout = 1000) { + wireless.start_client(host_address, port, client_sock, TCP_MODE); + + uint32_t t_start = millis(); + + while(millis() - t_start < timeout) { + uint8_t state = wireless.get_client_state(client_sock); + if(state == ESTABLISHED) return true; + sleep_ms(100); + } + + return false; +} + +/* Basic DNS lookup */ +IPAddress dns_lookup(std::string request_host) { + IPAddress host_address(0, 0, 0, 0); + printf("DNS lookup for: %s\n", request_host.c_str()); + if(!wireless.get_host_by_name(request_host.c_str(), host_address)) { + printf("DNS lookup failed!\n"); + } + return host_address; +} + +/* This is pretty much the simplest HTTP request function I could get away with. + It accepts a client socket ID, IP address, hostname, request path and handler function, + and calls the handler with the status code (only 200 & 404 at the moment), head + and body as `std::vector` into the underlying buffer. + */ +HTTP_REQUEST_STATUS http_request(uint8_t client_sock, IPAddress host_address, uint16_t port, std::string request_host, std::string request_path, http_handler handler, uint32_t timeout = 1000) { + if(!connect(host_address, port, client_sock)) { + printf("Connection failed!\n"); + return HTTP_REQUEST_CONNECTION_FAILED; + } + + // HTTP request to grab our API endpoint + const std::string http_request = "GET " + request_path + " HTTP/1.1\r\n\ +Host: " + request_host + "\r\n\ +Connection: close\r\n\r\n"; + + // Clear the response buffer + memset(response_buf, 0, HTTP_RESPONSE_BUF_SIZE); + + wireless.send_data(client_sock, (const uint8_t *)http_request.data(), http_request.length()); + + uint16_t response_length = 0; + uint16_t avail_length = 0; + uint32_t t_start = millis(); + + // Keep receiving data until our designated timeout + // There's no guarantee that `wireless.avail_data` will have the *whole* response in one shot + // and I *really* don't want to parse the HTTP response for a `Content-Length` header. + while(millis() - t_start < timeout) { + sleep_ms(50); + avail_length = wireless.avail_data(client_sock); + if(avail_length > 0) break; + } + + // Read the full response + // Sometimes the bytes read is less than the bytes we request, so loop until we get the data we expect + while(response_length < avail_length) { + uint16_t read_length = avail_length; // Request the full buffer + wireless.get_data_buf(client_sock, response_buf + response_length, &read_length); + response_length += read_length; // Increment the response_length by the amount we actually read + + // Also check for timeouts here, too + if(millis() - t_start >= timeout) break; + } + + // Explicitly stop our client, and don't leave it dangling! + wireless.stop_client(client_sock); + + // Bail if we timed out. + if(millis() - t_start >= timeout) return HTTP_REQUEST_TIMEOUT; + + if(response_length > 0) { + std::vector response = split(std::string_view((char *)response_buf, response_length)); + std::vector response_body; + uint32_t status_code = 0; + + // Bail early on an invalid HTTP request + if(response[0].compare(0, 8, "HTTP/1.1") != 0) return HTTP_REQUEST_RESPONSE_INVALID; + + // Scan for the blank line indicating content start + auto body_start = std::find(response.begin(), response.end(), ""); + + // Split the body from the head (ow!) + if(body_start != response.end()) { + response_body = std::vector(body_start + 1, response.end()); + response = std::vector(response.begin(), body_start); + } + + // Parse out the HTTP status code + status_code = std::stoul(std::string(response[0].substr(9, 12)), nullptr); + + if(status_code != 0) { + handler(status_code, response, response_body); + return HTTP_REQUEST_OK; + } + + return HTTP_REQUEST_RESPONSE_UNHANDLED; + } + + return HTTP_REQUEST_NO_RESPONSE; +} + +/* As above, but does DNS resolving for us, probably don't use this... */ +int http_request(uint8_t client_sock, std::string request_host, uint16_t port, std::string request_path, http_handler handler, uint32_t timeout = 1000) { + IPAddress host_address = dns_lookup(request_host); + return http_request(client_sock, host_address, port, request_host, request_path, handler, timeout); +} + +int main() { + stdio_init_all(); + + wireless.init(); + sleep_ms(500); + + printf("Firmware version Nina %s\n", wireless.get_fw_version()); + + if(!wifi_connect(NETWORK, PASSWORD, USE_DNS)) { + return 0; + } + + g = 255; + wireless.set_led(r, g, b); + + // Get a free client socket + uint8_t client_sock = wireless.get_socket(); + + // Be a good DNS citizen and cache our lookup + IPAddress host_address = dns_lookup(HTTP_REQUEST_HOST); + + while(1) { + printf("Requesting: %s\n", HTTP_REQUEST_PATH); + + HTTP_REQUEST_STATUS status = http_request(client_sock, host_address, HTTP_PORT, HTTP_REQUEST_HOST, HTTP_REQUEST_PATH, []( + unsigned int status_code, + std::vector response_head, + std::vector response_body) { + // Check for valid status + if(status_code != 200) return; + // Check for empty body + if(response_body.size() == 0) return; + // Check for our 7 chars "#000000" + if(response_body[0].length() != 7) return; + // Check for at least a *hopefully* valid hex colour + if(response_body[0].compare(0, 1, "#") != 0) return; + + // Convert the hex colour to an unsigned int + uint32_t rgb = std::stoul(std::string(response_body[0].substr(1)), nullptr, 16); + + // Unpack to RGB + r = (rgb >> 16) & 0xff; + g = (rgb >> 8) & 0xff; + b = (rgb >> 0) & 0xff; + printf("RGB: %i %i %i\n", r, g, b); + wireless.set_led(r, g, b); + }); + + if(status == HTTP_REQUEST_NO_RESPONSE) { + printf("No response :(\n"); + } + + if(status == HTTP_REQUEST_TIMEOUT) { + printf("Request timed out :(\n"); + } + + if(status == HTTP_REQUEST_RESPONSE_UNHANDLED) { + // Something unexpected happened! + } + + sleep_ms(HTTP_REQUEST_DELAY * 1000); // Sensible delay + } + + return 0; +} \ No newline at end of file diff --git a/examples/pico_wireless/demo.cmake b/examples/pico_wireless/demo.cmake new file mode 100644 index 00000000..74f7786f --- /dev/null +++ b/examples/pico_wireless/demo.cmake @@ -0,0 +1,14 @@ +add_executable( + wireless_time + demo.cpp +) + +# enable usb output, disable uart output +pico_enable_stdio_usb(wireless_time 1) +pico_enable_stdio_uart(wireless_time 0) + +# Pull in pico libraries that we need +target_link_libraries(wireless_time pico_stdlib pico_wireless) + +# create map/bin/hex file etc. +pico_add_extra_outputs(wireless_time) diff --git a/examples/pico_wireless/demo.cpp b/examples/pico_wireless/demo.cpp new file mode 100644 index 00000000..f220b5ab --- /dev/null +++ b/examples/pico_wireless/demo.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include "pico/stdlib.h" +#include "hardware/uart.h" +#include "hardware/gpio.h" +#include "hardware/spi.h" +#include "pico_wireless.hpp" +#include +#include +#include +#include "secrets.h" + +using namespace pimoroni; + +#define UART_ID uart1 //uart0 +#define BAUD_RATE 115200 +#define DATA_BITS 8 +#define STOP_BITS 1 +#define PARITY UART_PARITY_NONE + +// We are using pins 0 and 1, but see the GPIO function select table in the +// datasheet for information on which other pins can be used. +#define UART_TX_PIN 8 //0 +#define UART_RX_PIN 9 //1 + + + +// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel +// Outputs are rgb in the range 0-255 for each channel +void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) { + float i = floor(h * 6.0f); + float f = h * 6.0f - i; + v *= 255.0f; + uint8_t p = v * (1.0f - s); + uint8_t q = v * (1.0f - f * s); + uint8_t t = v * (1.0f - (1.0f - f) * s); + + switch (int(i) % 6) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } +} + +PicoWireless wireless; + +#define PICO_LED 25 + +int main() { + stdio_init_all(); + //stdio_set_translate_crlf(&stdio_usb, false); + + gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART); + gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART); + uart_init(UART_ID, BAUD_RATE); + + gpio_put(PICO_LED, true); + + printf("Initialised\n"); + + wireless.init(); + + sleep_ms(1000); + + uint8_t r, g, b; + uint8_t a = 0; + while(!wireless.is_pressed(PicoWireless::A)) { + from_hsv((float)a/256.0f, 1, 1, r, g, b); + + wireless.set_led(0, 0, b); + sleep_ms(10); + a++; + } + wireless.set_led(16, 16, 0); + + printf("firmware version Nina %s\n", wireless.get_fw_version()); + uint8_t* mac = wireless.get_mac_address(); + printf("mac address ", wireless.get_mac_address()[0]); + for(uint i =0; i < WL_MAC_ADDR_LENGTH; i++) { + printf("%d:", mac[i]); + } + printf("\n"); + + printf("starting connection\n"); + + bool connected = wireless.wifi_set_passphrase(NETWORK, PASSWORD); + + printf("waiting to establish connection status\n"); + while(wireless.get_connection_status() != WL_CONNECTED) { + sleep_ms(1000); + printf("still waiting\n"); + } + + IPAddress ip; + wireless.get_ip_address(ip); + printf("ip address: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + + IPAddress gateway; + wireless.get_gateway_ip(gateway); + printf("gateway address: %d.%d.%d.%d\n", gateway[0], gateway[1], gateway[2], gateway[3]); + + printf("SSID = %s\n", wireless.get_current_ssid()); + printf("RSSI = %d\n", wireless.get_current_rssi()); + + uint8_t t = 0; + while (true) { + from_hsv((float)t/256.0f, 1, 1, r, g, b); + wireless.set_led(r, g, b); + sleep_ms(10); + t++; + if(t == 0) { + //printf("time: %d, temp: %f\n", wireless.get_time(), wireless.get_temperature()); + std::uint32_t time_date_stamp = wireless.get_time(); + std::time_t temp = time_date_stamp; + std::tm* t = std::gmtime(&temp); + std::stringstream ss; // or if you're going to print, just input directly into the output stream + ss << std::put_time(t, "%Y-%m-%d %I:%M:%S %p\n"); + std::string output = ss.str(); + printf(output.c_str()); + } + } + return 0; +} \ No newline at end of file diff --git a/examples/pico_wireless/rgb_http.cmake b/examples/pico_wireless/rgb_http.cmake new file mode 100644 index 00000000..80cb3e00 --- /dev/null +++ b/examples/pico_wireless/rgb_http.cmake @@ -0,0 +1,14 @@ +add_executable( + wireless_rgb_http + rgb_http.cpp +) + +# enable usb output, enable uart output +pico_enable_stdio_usb(wireless_rgb_http 1) +pico_enable_stdio_uart(wireless_rgb_http 1) + +# Pull in pico libraries that we need +target_link_libraries(wireless_rgb_http pico_stdlib pico_wireless) + +# create map/bin/hex file etc. +pico_add_extra_outputs(wireless_rgb_http) diff --git a/examples/pico_wireless/rgb_http.cpp b/examples/pico_wireless/rgb_http.cpp new file mode 100644 index 00000000..23454b59 --- /dev/null +++ b/examples/pico_wireless/rgb_http.cpp @@ -0,0 +1,244 @@ +#include +#include "pico/stdlib.h" +#include "hardware/uart.h" +#include "hardware/gpio.h" +#include "hardware/spi.h" +#include "pico_wireless.hpp" +#include "secrets.h" + +#include +#include + +#define HTTP_PORT 80 +#define HTTP_REQUEST_BUF_SIZE 2048 + +#define DNS_CLOUDFLARE IPAddress(1, 1, 1, 1) +#define DNS_GOOGLE IPAddress(8, 8, 8, 8) +#define USE_DNS DNS_CLOUDFLARE + +using namespace pimoroni; + +PicoWireless wireless; +uint8_t r, g, b; +uint8_t request_buf[HTTP_REQUEST_BUF_SIZE]; +const std::string response_501 = "HTTP/1.1 501 Not Implemented\nContent-Length: 19\n\n501 Not Implemented"; + +enum http_request_method_t { + GET, + POST +}; +typedef std::string_view(*http_request_handler)(http_request_method_t method, std::string_view path, std::vector request_head, std::vector request_body); + +std::vector split(std::string_view str, std::string delim="\r\n") { + std::vector result; + size_t offset = 0; + while (offset < str.size()) { + const auto pos = str.find_first_of(delim, offset); + // Emit an empty view even if two adjacent delimiters are found + // this ensurs the HTTP "blank line" start of content is found + result.emplace_back(str.substr(offset, pos - offset)); + if (pos == std::string_view::npos) break; + offset = pos + delim.length(); + } + return result; +} + +uint32_t millis() { + return to_us_since_boot(get_absolute_time()) / 1000; +} + +bool wifi_connect(std::string network, std::string password, IPAddress dns_server, uint32_t timeout=10000) { + printf("Connecting to %s...\n", network.c_str()); + wireless.wifi_set_passphrase(network, password); + + uint32_t t_start = millis(); + + while(millis() - t_start < timeout) { + if(wireless.get_connection_status() == WL_CONNECTED) { + printf("Connected!\n"); + wireless.set_dns(1, dns_server, 0); + return true; + } + wireless.set_led(255, 0, 0); + sleep_ms(500); + wireless.set_led(0, 0, 0); + sleep_ms(500); + printf("...\n"); + } + + return false; +} + +int socket_accept(int8_t server_sock) { + uint8_t new_sock = wireless.avail_server(server_sock); + if(new_sock != server_sock + && new_sock != 255) { + return new_sock; + } + return -1; +} + +uint8_t start_server(uint16_t http_port) { + printf("Starting server...\n", NETWORK); + // Get a socket for our server + uint8_t server_sock = wireless.get_socket(); + wireless.start_server(http_port, server_sock); + while(1){ + uint8_t state = wireless.get_server_state(server_sock); + if(state == LISTEN) break; + } + IPAddress ip; + wireless.get_ip_address(ip); + printf("Server listening on %s:%i\n", ip.to_string().c_str(), http_port); + return server_sock; +} + +bool poll_http_requests(uint8_t server_sock, http_request_handler request_handler, uint32_t timeout = 1000) { + uint16_t request_length = 0; + uint16_t avail_length = 0; + uint32_t t_start = millis(); + + // Clear the request buffer + memset(request_buf, 0, HTTP_REQUEST_BUF_SIZE); + + // Try to accept an incoming connection + int client_sock = socket_accept(server_sock); + if(client_sock == -1) return false; + + printf("Got client: %d\n", client_sock); + + // Any data? This *usually* seems to be available immediately, + // so we can dispense with any ongoing polling and hope for the best. + avail_length = wireless.avail_data(client_sock); + if(avail_length == 0) return false; + + printf("Got request: %i bytes\n", avail_length); + + // Read the full response + // Sometimes the bytes read is less than the bytes we request, so loop until we get the data we expect + while(request_length < avail_length) { + uint16_t read_length = avail_length; // Request the full buffer + wireless.get_data_buf(client_sock, request_buf + request_length, &read_length); + request_length += read_length; // Increment the response_length by the amount we actually read + + // Also check for timeouts here, too + if(millis() - t_start >= timeout) break; + } + + // Bail if we timed out. + if(millis() - t_start >= timeout) { + wireless.stop_client(client_sock); + }; + + if(request_length > 0) { + std::vector request = split(std::string_view((char *)request_buf, request_length)); + std::vector request_body; + std::vector request_detail = split(request[0], " "); + http_request_method_t method; + + // Bail early on an invalid HTTP request + if(request_detail[0].compare("POST") == 0) { + method = POST; + } else if (request_detail[0].compare("GET") == 0) { + method = GET; + } else { // PUT, DELETE, HEAD? + // Return a 501 unimplemented + wireless.send_data(client_sock, (const uint8_t *)response_501.data(), response_501.length()); + wireless.stop_client(client_sock); + return false; + } + + // Get the request path so we can handle routes + std::string_view path = request_detail[1]; + + // Scan for the blank line indicating content start for form post data + auto body_start = std::find(request.begin(), request.end(), ""); + + // Split the body from the head (ow!) + if(body_start != request.end()) { + request_body = std::vector(body_start + 1, request.end()); + request = std::vector(request.begin(), body_start); + } + + std::string_view response_body = request_handler(method, path, request, request_body); + std::string response_head = "HTTP/1.1 200 OK\nContent-Length: " + std::to_string(response_body.length()) + "\nContent-Type: text/html\n\n"; + wireless.send_data(client_sock, (const uint8_t *)response_head.data(), response_head.length()); + wireless.send_data(client_sock, (const uint8_t *)response_body.data(), response_body.length()); + wireless.stop_client(client_sock); + + return true; + } + + return false; +} + +int main() { + stdio_init_all(); + + wireless.init(); + sleep_ms(500); + + printf("Firmware version Nina %s\n", wireless.get_fw_version()); + + if(!wifi_connect(NETWORK, PASSWORD, USE_DNS)) { + return 0; + } + + uint8_t server_sock = start_server(HTTP_PORT); + + g = 255; + wireless.set_led(r, g, b); + + while(1) { + // Handle any incoming HTTP requests + poll_http_requests(server_sock, []( + http_request_method_t request_method, + std::string_view request_path, + std::vector request_head, + std::vector request_body) -> std::string_view { + + if(request_method == POST) { + // Split the URL-encoded POST data and parse the RGB values + std::vector post_data = split(request_body[0], "&"); + for(auto &data : post_data) { + // Must be at least 3 chars for "x=y" + if(data.length() < 3) continue; + // Must be in the form "x=y" + if(data[1] != '=') continue; + // "v" will be 0 on a parse failure, which isn't so bad. + int v = atoi((const char *)(data.data() + 2)); + switch(data[0]) { + case 'r': + r = v; + printf("Got R: %i\n", r); + break; + case 'g': + g = v; + printf("Got G: %i\n", g); + break; + case 'b': + b = v; + printf("Got B: %i\n", b); + break; + } + wireless.set_led(r, g, b); + } + } else { // GET + if(request_path.compare("/hello") == 0) { + return "Hello World!"; + } + } + + return "\ +
\ + \ + \ + \ + \ +
"; + }); + sleep_ms(10); + } + + return 0; +} diff --git a/examples/pico_wireless/secrets.h b/examples/pico_wireless/secrets.h new file mode 100644 index 00000000..f273e9b2 --- /dev/null +++ b/examples/pico_wireless/secrets.h @@ -0,0 +1,7 @@ +#include "pico/stdlib.h" + +//DO NOT COMMIT THIS FILE!!! + +//Your wireless network's name and password +#define NETWORK "network name here" +#define PASSWORD "network password here" diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 283f3501..42167b00 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -4,4 +4,5 @@ add_subdirectory(pico_display) add_subdirectory(pico_unicorn) add_subdirectory(pico_scroll) add_subdirectory(pico_explorer) -add_subdirectory(pico_rgb_keypad) \ No newline at end of file +add_subdirectory(pico_rgb_keypad) +add_subdirectory(pico_wireless) \ No newline at end of file diff --git a/libraries/pico_wireless/CMakeLists.txt b/libraries/pico_wireless/CMakeLists.txt new file mode 100644 index 00000000..a2dd0b42 --- /dev/null +++ b/libraries/pico_wireless/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(pico_wireless INTERFACE) + +target_sources(pico_wireless INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/pico_wireless.cpp +) + +target_include_directories(pico_wireless INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(pico_wireless INTERFACE pico_stdlib hardware_spi esp32spi) diff --git a/libraries/pico_wireless/pico_wireless.cmake b/libraries/pico_wireless/pico_wireless.cmake new file mode 100644 index 00000000..0d7d73e4 --- /dev/null +++ b/libraries/pico_wireless/pico_wireless.cmake @@ -0,0 +1,11 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/esp32wireless/esp32wireless.cmake) +add_library(pico_wireless INTERFACE) + +target_sources(pico_wireless INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/pico_wireless.cpp +) + +target_include_directories(pico_wireless INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(pico_wireless INTERFACE pico_stdlib hardware_spi esp32spi) diff --git a/libraries/pico_wireless/pico_wireless.cpp b/libraries/pico_wireless/pico_wireless.cpp new file mode 100644 index 00000000..4c6df7da --- /dev/null +++ b/libraries/pico_wireless/pico_wireless.cpp @@ -0,0 +1,35 @@ +#include "pico_wireless.hpp" +#include "../../drivers/esp32spi/spi_drv.hpp" + +namespace pimoroni { + + bool PicoWireless::init() { + bool success = parent::init(); + + // setup button input + gpio_init(A); + gpio_set_dir(A, GPIO_IN); + gpio_pull_up(A); + + set_led(0, 0, 0); + + pin_mode(ESP_SD_DETECT, Esp32Spi::INPUT_PULLUP); + + return success; + } + + void PicoWireless::set_led(uint8_t r, uint8_t g, uint8_t b) { + analog_write(ESP_LED_R, 255 - r); + analog_write(ESP_LED_G, 255 - g); + analog_write(ESP_LED_B, 255 - b); + } + + bool PicoWireless::is_pressed(uint8_t button) { + return !gpio_get(button); + } + + bool PicoWireless::is_sdcard_detected() { + return digital_read(ESP_SD_DETECT); + } + +} \ No newline at end of file diff --git a/libraries/pico_wireless/pico_wireless.hpp b/libraries/pico_wireless/pico_wireless.hpp new file mode 100644 index 00000000..387e5527 --- /dev/null +++ b/libraries/pico_wireless/pico_wireless.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "pico/stdlib.h" +#include "../../drivers/esp32spi/esp32spi.hpp" + +namespace pimoroni { + + class PicoWireless : public Esp32Spi { + typedef Esp32Spi parent; + + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const uint8_t A = 12; + + static const uint8_t ESP_LED_R = 25; + static const uint8_t ESP_LED_G = 26; + static const uint8_t ESP_LED_B = 27; + + static const uint8_t ESP_SD_DETECT = 15; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: + + + public: + //PicoWireless(); + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + virtual bool init(); + + void set_led(uint8_t r, uint8_t g, uint8_t b); + bool is_pressed(uint8_t button); + bool is_sdcard_detected(); + }; + +} \ No newline at end of file diff --git a/micropython/examples/pico_wireless/cheerlights.py b/micropython/examples/pico_wireless/cheerlights.py new file mode 100644 index 00000000..7efe3b81 --- /dev/null +++ b/micropython/examples/pico_wireless/cheerlights.py @@ -0,0 +1,112 @@ +import time +import picowireless +from micropython import const + +WIFI_SSID = "your SSID here!" +WIFI_PASS = "Your PSK here!" + +CLOUDFLARE_DNS = (1, 1, 1, 1) +GOOGLE_DNS = (8, 8, 8, 8) +USE_DNS = CLOUDFLARE_DNS + +TCP_MODE = const(0) +HTTP_REQUEST_DELAY = const(30) +HTTP_PORT = 80 +HTTP_REQUEST_HOST = "api.thingspeak.com" +HTTP_REQUEST_PATH = "/channels/1417/field/2/last.txt" + + +def connect(host_address, port, client_sock, timeout=1000): + picowireless.client_start(host_address, port, client_sock, TCP_MODE) + + t_start = time.time() + timeout /= 1000.0 + + while time.time() - t_start < timeout: + state = picowireless.get_client_state(client_sock) + if state == 4: + return True + time.sleep(1.0) + + return False + + +def http_request(client_sock, host_address, port, request_host, request_path, handler): + print("Connecting to {1}.{2}.{3}.{4}:{0}...".format(port, *host_address)) + if not connect(host_address, port, client_sock): + print("Connection failed!") + return False + print("Connected!") + + http_request = """GET {} HTTP/1.1 +Host: {} +Connection: close + +""".format(request_path, request_host).replace("\n", "\r\n") + + picowireless.send_data(client_sock, http_request) + + while True: + avail_length = picowireless.avail_data(client_sock) + if avail_length > 0: + break + + print("Got response: {} bytes".format(avail_length)) + + response = b"" + + while len(response) < avail_length: + data = picowireless.get_data_buf(client_sock) + response += data + + response = response.decode("utf-8") + + head, body = response.split("\r\n\r\n", 1) + dhead = {} + + for line in head.split("\r\n")[1:]: + key, value = line.split(": ", 1) + dhead[key] = value + + handler(dhead, body) + + picowireless.client_stop(client_sock) + + +picowireless.init() + +print("Connecting to {}...".format(WIFI_SSID)) +picowireless.wifi_set_passphrase(WIFI_SSID, WIFI_PASS) + +while True: + if picowireless.get_connection_status() == 3: + break +print("Connected!") + +# Get our own local IP! +my_ip = picowireless.get_ip_address() +print("Local IP: {}.{}.{}.{}".format(*my_ip)) + +# Resolve and cache the IP address +picowireless.set_dns(USE_DNS) +http_address = picowireless.get_host_by_name(HTTP_REQUEST_HOST) +print("Resolved {} to {}.{}.{}.{}".format(HTTP_REQUEST_HOST, *http_address)) + +client_sock = picowireless.get_socket() + + +def handler(head, body): + if head["Status"] == "200 OK": + color = body[1:] + r = int(color[0:2], 16) + g = int(color[3:4], 16) + b = int(color[5:6], 16) + picowireless.set_led(r, g, b) + print("Set LED to {} {} {}".format(r, g, b)) + else: + print("Error: {}".format(head["Status"])) + + +while True: + http_request(client_sock, http_address, HTTP_PORT, HTTP_REQUEST_HOST, HTTP_REQUEST_PATH, handler) + time.sleep(60.0) diff --git a/micropython/examples/pico_wireless/rgb_http.py b/micropython/examples/pico_wireless/rgb_http.py new file mode 100644 index 00000000..60db461c --- /dev/null +++ b/micropython/examples/pico_wireless/rgb_http.py @@ -0,0 +1,182 @@ +import time +import picowireless +from micropython import const + +WIFI_SSID = "your SSID here!" +WIFI_PASS = "Your PSK here!" + +TCP_CLOSED = 0 +TCP_LISTEN = 1 + +CLOUDFLARE_DNS = (1, 1, 1, 1) +GOOGLE_DNS = (8, 8, 8, 8) + +TCP_MODE = const(0) +HTTP_REQUEST_DELAY = const(30) +HTTP_PORT = 80 + +routes = {} + +r = 0 +g = 0 +b = 0 + + +def start_wifi(): + picowireless.init() + + print("Connecting to {}...".format(WIFI_SSID)) + picowireless.wifi_set_passphrase(WIFI_SSID, WIFI_PASS) + + while True: + if picowireless.get_connection_status() == 3: + break + print("Connected!") + + +def start_server(http_port, timeout=1.0): + my_ip = picowireless.get_ip_address() + print("Starting server...") + server_sock = picowireless.get_socket() + picowireless.server_start(http_port, server_sock, 0) + + t_start = time.time() + + while time.time() - t_start < timeout: + state = picowireless.get_server_state(server_sock) + if state == TCP_LISTEN: + print("Server listening on {1}.{2}.{3}.{4}:{0}".format(http_port, *my_ip)) + return server_sock + + return None + + +def handle_http_request(server_sock, timeout=1.0): + t_start = time.time() + + client_sock = picowireless.avail_server(server_sock) + if client_sock in [server_sock, 255, -1]: + return False + + print("Client connected!") + + avail_length = picowireless.avail_data(client_sock) + if avail_length == 0: + picowireless.client_stop(client_sock) + return False + + request = b"" + + while len(request) < avail_length: + data = picowireless.get_data_buf(client_sock) + request += data + if time.time() - t_start > timeout: + print("Client timed out getting data!") + picowireless.client_stop(client_sock) + return False + + request = request.decode("utf-8") + + if len(request) > 0: + head, body = request.split("\r\n\r\n", 1) + dhead = {} + + for line in head.split("\r\n")[1:]: + key, value = line.split(": ", 1) + dhead[key] = value + + method, url, _ = head.split("\r\n", 1)[0].split(" ") + + print("Serving {} on {}...".format(method, url)) + + response = None + + # Dispatch the request to the relevant route + if url in routes and method in routes[url] and callable(routes[url][method]): + if method == "POST": + data = {} + for var in body.split("&"): + key, value = var.split("=") + data[key] = value + response = routes[url][method](method, url, data) + else: + response = routes[url][method](method, url) + + if response is not None: + response = "HTTP/1.1 200 OK\r\nContent-Length: {}\r\nContent-Type: text/html\r\n\r\n".format(len(response)) + response + picowireless.send_data(client_sock, response) + picowireless.client_stop(client_sock) + print("Success! Sending 200 OK") + return True + else: + picowireless.send_data(client_sock, "HTTP/1.1 501 Not Implemented\r\nContent-Length: 19\r\n\r\n501 Not Implemented") + picowireless.client_stop(client_sock) + print("Unhandled Request! Sending 501 OK") + return False + + +def route(url, methods="GET"): + if type(methods) is str: + methods = [methods] + + def decorate(handler): + for method in methods: + if url not in routes: + routes[url] = {} + routes[url][method] = handler + + return decorate + + +# Edit your routes here +# Nothing fancy is supported, just plain ol' URLs and GET/POST methods +@route("/", methods=["GET", "POST"]) +def get_home(method, url, data=None): + if method == "POST": + global r, g, b + r = int(data.get("r", 0)) + g = int(data.get("g", 0)) + b = int(data.get("b", 0)) + picowireless.set_led(r, g, b) + print("Set LED to {} {} {}".format(r, g, b)) + + return """
+ + + + +
""".format(r=r, g=g, b=b) + + +@route("/test", methods="GET") +def get_test(method, url): + return "Hello World!" + + +start_wifi() + +server_sock = start_server(HTTP_PORT) +while True: + handle_http_request(server_sock) + time.sleep(0.01) + + +# Whoa there! Did you know you could run the server polling loop +# on Pico's *other* core!? Here's how: +# +# import _thread +# +# def server_loop_forever(): +# # Start a server and continuously poll for HTTP requests +# server_sock = start_server(HTTP_PORT) +# while True: +# handle_http_request(server_sock) +# time.sleep(0.01) +# +# Handle the server polling loop on the other core! +# _thread.start_new_thread(server_loop_forever, ()) +# +# # Your very own main loop for fun and profit! +# while True: +# print("Colour: {} {} {}".format(r, g, b)) +# time.sleep(5.0) diff --git a/micropython/modules/micropython.cmake b/micropython/modules/micropython.cmake index 642f7001..4ad44870 100644 --- a/micropython/modules/micropython.cmake +++ b/micropython/modules/micropython.cmake @@ -4,4 +4,5 @@ include(${CMAKE_CURRENT_LIST_DIR}/pico_rgb_keypad/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/pico_unicorn/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/pico_display/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/pico_explorer/micropython.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/pico_wireless/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/ulab/code/micropython.cmake) diff --git a/micropython/modules/pico_wireless/micropython.cmake b/micropython/modules/pico_wireless/micropython.cmake new file mode 100644 index 00000000..3743343c --- /dev/null +++ b/micropython/modules/pico_wireless/micropython.cmake @@ -0,0 +1,28 @@ +set(MOD_NAME pico_wireless) +string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) +add_library(usermod_${MOD_NAME} INTERFACE) + +target_sources(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/esp32spi/esp32spi.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/esp32spi/spi_drv.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/esp32spi/ip_address.cpp +) + +target_include_directories(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_${MOD_NAME} INTERFACE + -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) + +set_source_files_properties( + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + PROPERTIES COMPILE_FLAGS + "-Wno-discarded-qualifiers -Wno-implicit-int" +) \ No newline at end of file diff --git a/micropython/modules/pico_wireless/micropython.mk b/micropython/modules/pico_wireless/micropython.mk new file mode 100755 index 00000000..6d7bbb08 --- /dev/null +++ b/micropython/modules/pico_wireless/micropython.mk @@ -0,0 +1,12 @@ +WIRELESS_MOD_DIR := $(USERMOD_DIR) + +# Add our source files to the respective variables. +SRC_USERMOD += $(WIRELESS_MOD_DIR)/esp32spi.c +SRC_USERMOD_CXX += $(WIRELESS_MOD_DIR)/esp32spi.cpp + +# Add our module directory to the include path. +CFLAGS_USERMOD += -I$(WIRELESS_MOD_DIR) +CXXFLAGS_USERMOD += -I$(WIRELESS_MOD_DIR) + +# We use C++ features so have to link against the standard library. +LDFLAGS_USERMOD += -lstdc++ \ No newline at end of file diff --git a/micropython/modules/pico_wireless/pico_wireless.c b/micropython/modules/pico_wireless/pico_wireless.c new file mode 100644 index 00000000..4863580e --- /dev/null +++ b/micropython/modules/pico_wireless/pico_wireless.c @@ -0,0 +1,182 @@ +#include "pico_wireless.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// picowireless Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Module Functions *****/ +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_init_obj, picowireless_init); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_network_data_obj, picowireless_get_network_data); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_remote_data_obj, 1, picowireless_get_remote_data); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_wifi_set_network_obj, 1, picowireless_wifi_set_network); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_wifi_set_passphrase_obj, 2, picowireless_wifi_set_passphrase); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_wifi_set_key_obj, 3, picowireless_wifi_set_key); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_config_obj, 4, picowireless_config); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_set_dns_obj, 1, picowireless_set_dns); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_set_hostname_obj, 1, picowireless_set_hostname); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_disconnect_obj, picowireless_disconnect); + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_connection_status_obj, picowireless_get_connection_status); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_mac_address_obj, picowireless_get_mac_address); + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_ip_address_obj, picowireless_get_ip_address); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_subnet_mask_obj, picowireless_get_subnet_mask); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_gateway_ip_obj, picowireless_get_gateway_ip); + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_current_ssid_obj, picowireless_get_current_ssid); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_current_bssid_obj, picowireless_get_current_bssid); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_current_rssi_obj, picowireless_get_current_rssi); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_current_encryption_type_obj, picowireless_get_current_encryption_type); + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_start_scan_networks_obj, picowireless_start_scan_networks); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_scan_networks_obj, picowireless_get_scan_networks); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_ssid_networks_obj, 1, picowireless_get_ssid_networks); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_enc_type_networks_obj, 1, picowireless_get_enc_type_networks); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_bssid_networks_obj, 1, picowireless_get_bssid_networks); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_channel_networks_obj, 1, picowireless_get_channel_networks); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_rssi_networks_obj, 1, picowireless_get_rssi_networks); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_req_host_by_name_obj, 1, picowireless_req_host_by_name); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_host_by_name_obj, 0, picowireless_get_host_by_name); + +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_fw_version_obj, picowireless_get_fw_version); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_time_obj, picowireless_get_time); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_set_power_mode_obj, 1, picowireless_set_power_mode); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_wifi_set_ap_network_obj, 2, picowireless_wifi_set_ap_network); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_wifi_set_ap_passphrase_obj, 3, picowireless_wifi_set_ap_passphrase); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_ping_obj, 2, picowireless_ping); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_debug_obj, 1, picowireless_debug); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_temperature_obj, picowireless_get_temperature); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_pin_mode_obj, 2, picowireless_pin_mode); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_digital_write_obj, 2, picowireless_digital_write); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_analog_write_obj, 2, picowireless_analog_write); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_digital_read_obj, 1, picowireless_digital_read); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_analog_read_obj, 1, picowireless_analog_read); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_server_start_obj, 3, picowireless_server_start); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_client_start_obj, 4, picowireless_client_start); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_client_stop_obj, 1, picowireless_client_stop); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_server_state_obj, 1, picowireless_get_server_state); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_client_state_obj, 1, picowireless_get_client_state); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_avail_data_obj, 1, picowireless_avail_data); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_avail_server_obj, 1, picowireless_avail_server); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_data_obj, 2, picowireless_get_data); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_get_data_buf_obj, 1, picowireless_get_data_buf); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_insert_data_buf_obj, 2, picowireless_insert_data_buf); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_send_udp_data_obj, 1, picowireless_send_udp_data); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_send_data_obj, 2, picowireless_send_data); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_check_data_sent_obj, 1, picowireless_check_data_sent); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_get_socket_obj, picowireless_get_socket); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_wifi_set_ent_identity_obj, 1, picowireless_wifi_set_ent_identity); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_wifi_set_ent_username_obj, 1, picowireless_wifi_set_ent_username); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_wifi_set_ent_password_obj, 1, picowireless_wifi_set_ent_password); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_wifi_set_ent_enable_obj, picowireless_wifi_set_ent_enable); + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(picowireless_set_led_obj, 3, picowireless_set_led); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_is_pressed_obj, picowireless_is_pressed); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(picowireless_is_sdcard_detected_obj, picowireless_is_sdcard_detected); + + +/***** Globals Table *****/ +STATIC const mp_map_elem_t picowireless_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picowireless) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&picowireless_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_network_data), MP_ROM_PTR(&picowireless_get_network_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_remote_data), MP_ROM_PTR(&picowireless_get_remote_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_wifi_set_network), MP_ROM_PTR(&picowireless_wifi_set_network_obj) }, + { MP_ROM_QSTR(MP_QSTR_wifi_set_passphrase), MP_ROM_PTR(&picowireless_wifi_set_passphrase_obj) }, + { MP_ROM_QSTR(MP_QSTR_wifi_set_key), MP_ROM_PTR(&picowireless_wifi_set_key_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&picowireless_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_dns), MP_ROM_PTR(&picowireless_set_dns_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_hostname), MP_ROM_PTR(&picowireless_set_hostname_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&picowireless_disconnect_obj) } + , + { MP_ROM_QSTR(MP_QSTR_get_connection_status), MP_ROM_PTR(&picowireless_get_connection_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_mac_address), MP_ROM_PTR(&picowireless_get_mac_address_obj) }, + + { MP_ROM_QSTR(MP_QSTR_get_ip_address), MP_ROM_PTR(&picowireless_get_ip_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_subnet_mask), MP_ROM_PTR(&picowireless_get_subnet_mask_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_gateway_ip), MP_ROM_PTR(&picowireless_get_gateway_ip_obj) }, + + { MP_ROM_QSTR(MP_QSTR_get_current_ssid), MP_ROM_PTR(&picowireless_get_current_ssid_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_current_bssid), MP_ROM_PTR(&picowireless_get_current_bssid_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_current_rssi), MP_ROM_PTR(&picowireless_get_current_rssi_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_current_encryption_type), MP_ROM_PTR(&picowireless_get_current_encryption_type_obj) }, + + { MP_ROM_QSTR(MP_QSTR_start_scan_networks), MP_ROM_PTR(&picowireless_start_scan_networks_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_scan_networks), MP_ROM_PTR(&picowireless_get_scan_networks_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_ssid_networks), MP_ROM_PTR(&picowireless_get_ssid_networks_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_enc_type_networks), MP_ROM_PTR(&picowireless_get_enc_type_networks_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_bssid_networks), MP_ROM_PTR(&picowireless_get_bssid_networks_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_channel_networks), MP_ROM_PTR(&picowireless_get_channel_networks_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_rssi_networks), MP_ROM_PTR(&picowireless_get_rssi_networks_obj) }, + { MP_ROM_QSTR(MP_QSTR_req_host_by_name), MP_ROM_PTR(&picowireless_req_host_by_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_host_by_name), MP_ROM_PTR(&picowireless_get_host_by_name_obj) }, + + { MP_ROM_QSTR(MP_QSTR_get_fw_version), MP_ROM_PTR(&picowireless_get_fw_version_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_time), MP_ROM_PTR(&picowireless_get_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_power_mode), MP_ROM_PTR(&picowireless_set_power_mode_obj) }, + + { MP_ROM_QSTR(MP_QSTR_wifi_set_ap_network), MP_ROM_PTR(&picowireless_wifi_set_ap_network_obj) }, + { MP_ROM_QSTR(MP_QSTR_wifi_set_ap_passphrase), MP_ROM_PTR(&picowireless_wifi_set_ap_passphrase_obj) }, + { MP_ROM_QSTR(MP_QSTR_ping), MP_ROM_PTR(&picowireless_ping_obj) }, + + { MP_ROM_QSTR(MP_QSTR_debug), MP_ROM_PTR(&picowireless_debug_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_temperature), MP_ROM_PTR(&picowireless_get_temperature_obj) }, + { MP_ROM_QSTR(MP_QSTR_pin_mode), MP_ROM_PTR(&picowireless_pin_mode_obj) }, + + { MP_ROM_QSTR(MP_QSTR_digital_write), MP_ROM_PTR(&picowireless_digital_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_analog_write), MP_ROM_PTR(&picowireless_analog_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_digital_read), MP_ROM_PTR(&picowireless_digital_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_analog_read), MP_ROM_PTR(&picowireless_analog_read_obj) }, + + { MP_ROM_QSTR(MP_QSTR_server_start), MP_ROM_PTR(&picowireless_server_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_client_start), MP_ROM_PTR(&picowireless_client_start_obj) }, + { MP_ROM_QSTR(MP_QSTR_client_stop), MP_ROM_PTR(&picowireless_client_stop_obj) }, + + { MP_ROM_QSTR(MP_QSTR_get_server_state), MP_ROM_PTR(&picowireless_get_server_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_client_state), MP_ROM_PTR(&picowireless_get_client_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_avail_data), MP_ROM_PTR(&picowireless_avail_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_avail_server), MP_ROM_PTR(&picowireless_avail_server_obj) }, + + { MP_ROM_QSTR(MP_QSTR_get_data), MP_ROM_PTR(&picowireless_get_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_data_buf), MP_ROM_PTR(&picowireless_get_data_buf_obj) }, + { MP_ROM_QSTR(MP_QSTR_insert_data_buf), MP_ROM_PTR(&picowireless_insert_data_buf_obj) }, + { MP_ROM_QSTR(MP_QSTR_send_udp_data), MP_ROM_PTR(&picowireless_send_udp_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_send_data), MP_ROM_PTR(&picowireless_send_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_check_data_sent), MP_ROM_PTR(&picowireless_check_data_sent_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_socket), MP_ROM_PTR(&picowireless_get_socket_obj) }, + + { MP_ROM_QSTR(MP_QSTR_wifi_set_ent_identity), MP_ROM_PTR(&picowireless_wifi_set_ent_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR_wifi_set_ent_username), MP_ROM_PTR(&picowireless_wifi_set_ent_username_obj) }, + { MP_ROM_QSTR(MP_QSTR_wifi_set_ent_password), MP_ROM_PTR(&picowireless_wifi_set_ent_password_obj) }, + { MP_ROM_QSTR(MP_QSTR_wifi_set_ent_enable), MP_ROM_PTR(&picowireless_wifi_set_ent_enable_obj) }, + + { MP_ROM_QSTR(MP_QSTR_set_led), MP_ROM_PTR(&picowireless_set_led_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_pressed), MP_ROM_PTR(&picowireless_is_pressed_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_sdcard_detected), MP_ROM_PTR(&picowireless_is_sdcard_detected_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_picowireless_globals, picowireless_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t picowireless_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_picowireless_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_picowireless, picowireless_user_cmodule, MODULE_PICO_WIRELESS_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/pico_wireless/pico_wireless.cpp b/micropython/modules/pico_wireless/pico_wireless.cpp new file mode 100644 index 00000000..450b6de4 --- /dev/null +++ b/micropython/modules/pico_wireless/pico_wireless.cpp @@ -0,0 +1,1218 @@ +#include "hardware/spi.h" +#include "hardware/sync.h" +#include "pico/binary_info.h" + +#include "../../../libraries/pico_wireless/pico_wireless.hpp" + +using namespace pimoroni; + +PicoWireless *wireless = nullptr; + + +extern "C" { +#include "pico_wireless.h" + +#define NOT_INITIALISED_MSG "Cannot call this function, as picowireless is not initialised. Call picowireless.init() first." + +static void mp_obj_to_string(const mp_obj_t &obj, std::string &string_out) { + if(mp_obj_is_str_or_bytes(obj)) { + GET_STR_DATA_LEN(obj, str, str_len); + string_out = std::string((const char*)str); + } + else if(mp_obj_is_float(obj)) + mp_raise_TypeError("can't convert 'float' object to str implicitly"); + else if(mp_obj_is_int(obj)) + mp_raise_TypeError("can't convert 'int' object to str implicitly"); + else if(mp_obj_is_bool(obj)) + mp_raise_TypeError("can't convert 'bool' object to str implicitly"); + else + mp_raise_TypeError("can't convert object to str implicitly"); +} + +uint32_t mp_obj_to_ip(mp_obj_t obj) { + uint len; + mp_obj_t *items; + mp_obj_tuple_get(obj, &len, &items); + uint a = mp_obj_get_int(items[0]) & 0xff; + uint b = mp_obj_get_int(items[1]) & 0xff; + uint c = mp_obj_get_int(items[2]) & 0xff; + uint d = mp_obj_get_int(items[3]) & 0xff; + return (d << 24) | (c << 16) | (b << 8) | a; +} + +mp_obj_t mp_ip_to_obj(IPAddress ip) { + mp_obj_t tuple[4]; + tuple[0] = mp_obj_new_int(ip[0]); + tuple[1] = mp_obj_new_int(ip[1]); + tuple[2] = mp_obj_new_int(ip[2]); + tuple[3] = mp_obj_new_int(ip[3]); + return mp_obj_new_tuple(4, tuple); +} + +mp_obj_t picowireless_init() { + if(wireless == nullptr) + wireless = new PicoWireless(); + wireless->init(); + return mp_const_none; +} + +mp_obj_t picowireless_get_network_data() { + if(wireless != nullptr) { + uint8_t *ip = nullptr; + uint8_t *mask = nullptr; + uint8_t *gwip = nullptr; + wireless->get_network_data(ip, mask, gwip); + + mp_obj_t tuple[3]; + tuple[0] = mp_obj_new_bytes(ip, WL_IPV4_LENGTH); + tuple[1] = mp_obj_new_bytes(mask, WL_IPV4_LENGTH); + tuple[2] = mp_obj_new_bytes(gwip, WL_IPV4_LENGTH); + return mp_obj_new_tuple(3, tuple); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_remote_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t *ip = nullptr; + uint8_t *port = nullptr; + wireless->get_remote_data(args[ARG_sock].u_int, ip, port); + + mp_obj_t tuple[2]; + tuple[0] = mp_obj_new_bytes(ip, WL_IPV4_LENGTH); + tuple[1] = mp_obj_new_int((uint16_t)port[0] << 8 | (uint16_t)port[1]); //TODO verify size and ordering of port + return mp_obj_new_tuple(2, tuple); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_network(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_ssid, ARG_passphrase }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string ssid; + mp_obj_to_string(args[ARG_ssid].u_obj, ssid); + return mp_obj_new_int(wireless->wifi_set_network(ssid)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_passphrase(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_ssid, ARG_passphrase }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_passphrase, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string ssid, passphrase; + mp_obj_to_string(args[ARG_ssid].u_obj, ssid); + mp_obj_to_string(args[ARG_passphrase].u_obj, passphrase); + return mp_obj_new_int(wireless->wifi_set_passphrase(ssid, passphrase)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_key(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_ssid, ARG_key_idx, ARG_passphrase }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_key_idx, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_passphrase, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t key_idx = args[ARG_key_idx].u_int; + + std::string ssid, passphrase; + mp_obj_to_string(args[ARG_ssid].u_obj, ssid); + mp_obj_to_string(args[ARG_passphrase].u_obj, passphrase); + return mp_obj_new_int(wireless->wifi_set_key(ssid, key_idx, passphrase)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_valid_params, ARG_local_ip, ARG_gateway, ARG_subnet }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_valid_params, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_local_ip, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_gateway, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_subnet, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t valid_params = args[ARG_valid_params].u_int; + uint32_t local_ip = mp_obj_to_ip(args[ARG_local_ip].u_obj); + uint32_t gateway = mp_obj_to_ip(args[ARG_gateway].u_obj); + uint32_t subnet = mp_obj_to_ip(args[ARG_subnet].u_obj); + wireless->config(valid_params, local_ip, gateway, subnet); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_set_dns(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_dns_server1, ARG_dns_server2 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_dns_server1, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_dns_server2 | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t valid_params = n_args; + uint32_t dns_server1 = mp_obj_to_ip(args[ARG_dns_server1].u_obj); + uint32_t dns_server2 = n_args == 1 ? 0 : mp_obj_to_ip(args[ARG_dns_server2].u_obj); + wireless->set_dns(valid_params, dns_server1, dns_server2); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_set_hostname(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_hostname }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_hostname, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string hostname; + mp_obj_to_string(args[ARG_hostname].u_obj, hostname); + wireless->set_hostname(hostname); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_disconnect() { + if(wireless != nullptr) + return mp_obj_new_int(wireless->disconnect()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_connection_status() { + if(wireless != nullptr) + return mp_obj_new_int(wireless->get_connection_status()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_mac_address() { + if(wireless != nullptr) { + uint8_t* mac = wireless->get_mac_address(); + return mp_obj_new_bytes(mac, WL_MAC_ADDR_LENGTH); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_ip_address() { + if(wireless != nullptr) { + IPAddress ip; + wireless->get_ip_address(ip); + return mp_ip_to_obj(ip); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_subnet_mask() { + if(wireless != nullptr) { + IPAddress mask; + wireless->get_subnet_mask(mask); + return mp_ip_to_obj(mask); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_gateway_ip() { + if(wireless != nullptr) { + IPAddress mask; + wireless->get_gateway_ip(mask); + return mp_ip_to_obj(mask); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_current_ssid() { + if(wireless != nullptr) { + std::string ssid = wireless->get_current_ssid(); + return mp_obj_new_str(ssid.c_str(), ssid.length()); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_current_bssid() { + if(wireless != nullptr) { + uint8_t* bssid = wireless->get_current_bssid(); + return mp_obj_new_bytes(bssid, WL_MAC_ADDR_LENGTH); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_current_rssi() { + if(wireless != nullptr) + return mp_obj_new_int(wireless->get_current_rssi()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_current_encryption_type() { + if(wireless != nullptr) + return mp_obj_new_int(wireless->get_current_encryption_type()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_start_scan_networks() { + if(wireless != nullptr) + return mp_obj_new_int(wireless->start_scan_networks()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_scan_networks() { + if(wireless != nullptr) + return mp_obj_new_int(wireless->get_scan_networks()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_ssid_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_network_item }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_network_item, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t network_item = args[ARG_network_item].u_int; + const char* ssid = wireless->get_ssid_networks(network_item); + if(ssid != nullptr) { + std::string str_ssid(ssid, WL_SSID_MAX_LENGTH); + return mp_obj_new_str(str_ssid.c_str(), str_ssid.length()); + } + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_enc_type_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_network_item }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_network_item, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t network_item = args[ARG_network_item].u_int; + return mp_obj_new_int(wireless->get_enc_type_networks(network_item)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_bssid_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_network_item }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_network_item, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t network_item = args[ARG_network_item].u_int; + uint8_t* bssid = nullptr; + wireless->get_bssid_networks(network_item, bssid); + if(bssid != nullptr) { + return mp_obj_new_bytes(bssid, WL_MAC_ADDR_LENGTH); + } + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_channel_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_network_item }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_network_item, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t network_item = args[ARG_network_item].u_int; + return mp_obj_new_int(wireless->get_channel_networks(network_item)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_rssi_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_network_item }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_network_item, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t network_item = args[ARG_network_item].u_int; + return mp_obj_new_int(wireless->get_rssi_networks(network_item)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_req_host_by_name(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_hostname }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_hostname, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string hostname; + mp_obj_to_string(args[ARG_hostname].u_obj, hostname); + + return mp_obj_new_bool(wireless->req_host_by_name(hostname)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_false; +} + +mp_obj_t picowireless_get_host_by_name(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + if(n_args == 0) { + IPAddress ip; + if(wireless->get_host_by_name(ip)) { + return mp_ip_to_obj(ip); + } + } + else { + enum { ARG_hostname }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_hostname, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string hostname; + mp_obj_to_string(args[ARG_hostname].u_obj, hostname); + + IPAddress ip; + if(wireless->get_host_by_name(hostname, ip)) { + return mp_ip_to_obj(ip); + } + } + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_fw_version() { + if(wireless != nullptr) { + const char* fw_ver = wireless->get_fw_version(); + std::string str_fw_ver(fw_ver, WL_FW_VER_LENGTH); + return mp_obj_new_str(str_fw_ver.c_str(), str_fw_ver.length()); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_time() { + if(wireless != nullptr) + return mp_obj_new_int(wireless->get_time()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_set_power_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t mode = args[ARG_mode].u_int; + wireless->set_power_mode(mode); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_ap_network(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_ssid, ARG_channel }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_channel, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string ssid; + mp_obj_to_string(args[ARG_ssid].u_obj, ssid); + + uint8_t channel = args[ARG_channel].u_int; + return mp_obj_new_int(wireless->wifi_set_ap_network(ssid, channel)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_ap_passphrase(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_ssid, ARG_passphrase, ARG_channel }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_passphrase, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_channel, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string ssid, passphrase; + mp_obj_to_string(args[ARG_ssid].u_obj, ssid); + mp_obj_to_string(args[ARG_passphrase].u_obj, passphrase); + + uint8_t channel = args[ARG_channel].u_int; + return mp_obj_new_int(wireless->wifi_set_ap_passphrase(ssid, passphrase, channel)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_ping(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_ip_address, ARG_ttl }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ip_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_ttl, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint32_t ip_address = mp_obj_to_ip(args[ARG_ip_address].u_obj); + uint8_t ttl = args[ARG_ttl].u_int; + return mp_obj_new_int(wireless->ping(ip_address, ttl)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_debug(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_on }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_on, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t on = args[ARG_on].u_int; + wireless->debug(on); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_temperature() { + if(wireless != nullptr) + return mp_obj_new_float(wireless->get_temperature()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_pin_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_pin, ARG_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_esp_pin, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t pin = args[ARG_pin].u_int; + uint8_t mode = args[ARG_mode].u_int; + wireless->pin_mode(pin, mode); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_digital_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_pin, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_esp_pin, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t pin = args[ARG_pin].u_int; + uint8_t value = args[ARG_value].u_int; + wireless->digital_write(pin, value); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_analog_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_pin, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_esp_pin, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t pin = args[ARG_pin].u_int; + uint8_t value = args[ARG_value].u_int; + wireless->analog_write(pin, value); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_digital_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_pin, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_esp_pin, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t pin = args[ARG_pin].u_int; + return mp_obj_new_bool(wireless->digital_read(pin)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_analog_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + if(n_args == 1) { + enum { ARG_pin }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_esp_pin, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t pin = args[ARG_pin].u_int; + return mp_obj_new_int(wireless->analog_read(pin) * 16); //Returns a 16 bit-ish* number as per CircuitPython + } + else { + enum { ARG_pin, ARG_atten }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_esp_pin, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_atten, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t pin = args[ARG_pin].u_int; + uint8_t atten = args[ARG_atten].u_int; + return mp_obj_new_int(wireless->analog_read(pin, atten) * 16); //Returns a 16 bit-ish* number as per CircuitPython + } + //NOTE *better way would be to mult by 65535 then div by 4095 + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_server_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + if(n_args == 3) { + enum { ARG_port, ARG_sock, ARG_protocol_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_prt, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_protocol_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint16_t port = args[ARG_port].u_int; + uint8_t sock = args[ARG_sock].u_int; + uint8_t protocol_mode = args[ARG_protocol_mode].u_int; + wireless->start_server(port, sock, protocol_mode); + } + else { + enum { ARG_ip_address, ARG_port, ARG_sock, ARG_protocol_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ip_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_prt, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_protocol_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint32_t ip_address = mp_obj_to_ip(args[ARG_ip_address].u_obj); + uint16_t port = args[ARG_port].u_int; + uint8_t sock = args[ARG_sock].u_int; + uint8_t protocol_mode = args[ARG_protocol_mode].u_int; + wireless->start_server(ip_address, port, sock, protocol_mode); + } + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_client_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + if(n_args == 4) { + enum { ARG_ip_address, ARG_port, ARG_sock, ARG_protocol_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ip_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_prt, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_protocol_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + + uint32_t ip_address = mp_obj_to_ip(args[ARG_ip_address].u_obj); + uint16_t port = args[ARG_port].u_int; + uint8_t sock = args[ARG_sock].u_int; + uint8_t protocol_mode = args[ARG_protocol_mode].u_int; + wireless->start_client(ip_address, port, sock, protocol_mode); + } + else { + enum { ARG_hostname, ARG_ip_address, ARG_port, ARG_sock, ARG_protocol_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_hostname, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_ip_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_prt, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_protocol_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string hostname; + mp_obj_to_string(args[ARG_hostname].u_obj, hostname); + + uint32_t ip_address = mp_obj_to_ip(args[ARG_ip_address].u_obj); + uint16_t port = args[ARG_port].u_int; + uint8_t sock = args[ARG_sock].u_int; + uint8_t protocol_mode = args[ARG_protocol_mode].u_int; + wireless->start_client(hostname, ip_address, port, sock, protocol_mode); + } + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_client_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t sock = args[ARG_sock].u_int; + wireless->stop_client(sock); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_server_state(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t sock = args[ARG_sock].u_int; + return mp_obj_new_int(wireless->get_server_state(sock)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_client_state(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t sock = args[ARG_sock].u_int; + return mp_obj_new_int(wireless->get_client_state(sock)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_avail_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t sock = args[ARG_sock].u_int; + return mp_obj_new_int(wireless->avail_data(sock)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_avail_server(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t sock = args[ARG_sock].u_int; + return mp_obj_new_int(wireless->avail_server(sock)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock, ARG_peek }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_peek, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t *data = nullptr; + if(wireless->get_data(args[ARG_sock].u_int, data, args[ARG_peek].u_int)) { + return mp_obj_new_int(*data); + } + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_data_buf(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t *data = (uint8_t *)malloc(512); + uint16_t data_len = 512; + if(wireless->get_data_buf(args[ARG_sock].u_int, data, &data_len)) { + mp_obj_t response = mp_obj_new_bytes(data, data_len); + free(data); + return response; + } + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_insert_data_buf(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock, ARG_data}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); + + return mp_obj_new_bool(wireless->insert_data_buf(args[ARG_sock].u_int, (uint8_t *)bufinfo.buf, bufinfo.len)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_send_udp_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t sock = args[ARG_sock].u_int; + return mp_obj_new_bool(wireless->send_udp_data(sock)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_send_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock, ARG_data}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); + + return mp_obj_new_int(wireless->send_data(args[ARG_sock].u_int, (uint8_t *)bufinfo.buf, bufinfo.len)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_check_data_sent(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_sock }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + return mp_obj_new_int(wireless->check_data_sent(args[ARG_sock].u_int)); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_get_socket() { + if(wireless != nullptr) + return mp_obj_new_int(wireless->get_socket()); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_ent_identity(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_identity }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_identity, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string identity; + mp_obj_to_string(args[ARG_identity].u_obj, identity); + wireless->wifi_set_ent_identity(identity); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_ent_username(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_username }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_username, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string username; + mp_obj_to_string(args[ARG_username].u_obj, username); + wireless->wifi_set_ent_username(username); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_ent_password(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_password }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_password, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + std::string password; + mp_obj_to_string(args[ARG_password].u_obj, password); + wireless->wifi_set_ent_password(password); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_wifi_set_ent_enable() { + if(wireless != nullptr) + wireless->wifi_set_ent_enable(); + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(wireless != nullptr) { + enum { ARG_r, ARG_g, ARG_b }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int r = args[ARG_r].u_int; + int g = args[ARG_g].u_int; + int b = args[ARG_b].u_int; + + if(r < 0 || r > 255) + mp_raise_ValueError("r out of range. Expected 0 to 255"); + else if(g < 0 || g > 255) + mp_raise_ValueError("g out of range. Expected 0 to 255"); + else if(b < 0 || b > 255) + mp_raise_ValueError("b out of range. Expected 0 to 255"); + else + wireless->set_led(r, g, b); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return mp_const_none; +} + +mp_obj_t picowireless_is_pressed() { + bool pressed = false; + + if(wireless != nullptr) { + pressed = wireless->is_pressed(PicoWireless::A); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return pressed ? mp_const_true : mp_const_false; +} + +mp_obj_t picowireless_is_sdcard_detected() { + bool detected = false; + + if(wireless != nullptr) { + detected = wireless->is_sdcard_detected(); + } + else + mp_raise_msg(&mp_type_RuntimeError, NOT_INITIALISED_MSG); + + return detected ? mp_const_true : mp_const_false; +} +} \ No newline at end of file diff --git a/micropython/modules/pico_wireless/pico_wireless.h b/micropython/modules/pico_wireless/pico_wireless.h new file mode 100644 index 00000000..0be9a7b5 --- /dev/null +++ b/micropython/modules/pico_wireless/pico_wireless.h @@ -0,0 +1,87 @@ +// Include MicroPython API. +#include "py/runtime.h" +#include "py/objstr.h" + +// Declare the functions we'll make available in Python +extern mp_obj_t picowireless_init(); +extern mp_obj_t picowireless_get_network_data(); +extern mp_obj_t picowireless_get_remote_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_wifi_set_network(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_wifi_set_passphrase(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_wifi_set_key(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_set_dns(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_set_hostname(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_disconnect(); + +extern mp_obj_t picowireless_get_connection_status(); +extern mp_obj_t picowireless_get_mac_address(); + +extern mp_obj_t picowireless_get_ip_address(); +extern mp_obj_t picowireless_get_subnet_mask(); +extern mp_obj_t picowireless_get_gateway_ip(); + +extern mp_obj_t picowireless_get_current_ssid(); +extern mp_obj_t picowireless_get_current_bssid(); +extern mp_obj_t picowireless_get_current_rssi(); +extern mp_obj_t picowireless_get_current_encryption_type(); + +extern mp_obj_t picowireless_start_scan_networks(); +extern mp_obj_t picowireless_get_scan_networks(); +extern mp_obj_t picowireless_get_ssid_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_get_enc_type_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_get_bssid_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_get_channel_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_get_rssi_networks(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_req_host_by_name(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_get_host_by_name(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_get_fw_version(); +extern mp_obj_t picowireless_get_time(); +extern mp_obj_t picowireless_set_power_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_wifi_set_ap_network(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_wifi_set_ap_passphrase(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_ping(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_debug(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_get_temperature(); +extern mp_obj_t picowireless_pin_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_digital_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_analog_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_digital_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_analog_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_server_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_client_start(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_client_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_get_server_state(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_get_client_state(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_avail_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_avail_server(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_get_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_get_data_buf(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_insert_data_buf(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_send_udp_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t picowireless_send_data(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_check_data_sent(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_get_socket(); + +extern mp_obj_t picowireless_wifi_set_ent_identity(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_wifi_set_ent_username(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_wifi_set_ent_password(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_wifi_set_ent_enable(); + +extern mp_obj_t picowireless_set_led(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t picowireless_is_pressed(); +extern mp_obj_t picowireless_is_sdcard_detected(); \ No newline at end of file