From 8c8ba5719139861109f16b4d7b5d7df52c82d377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 25 Apr 2022 21:53:33 +0200 Subject: [PATCH] [realtek-ambz] Add new WiFi library The Realtek one sucked --- arduino/libretuya/IPv6Address.cpp | 8 +- arduino/libretuya/IPv6Address.h | 13 +- arduino/libretuya/api/WiFi.h | 202 ++++++++-------- arduino/libretuya/api/WiFiClient.h | 9 +- arduino/libretuya/api/WiFiServer.h | 4 +- arduino/libretuya/api/WiFiType.h | 14 +- arduino/realtek-ambz/libraries/WiFi/WiFi.cpp | 94 ++++++++ arduino/realtek-ambz/libraries/WiFi/WiFi.h | 177 ++++++++++++++ .../realtek-ambz/libraries/WiFi/WiFiAP.cpp | 151 ++++++++++++ .../libraries/WiFi/WiFiGeneric.cpp | 150 ++++++++++++ .../realtek-ambz/libraries/WiFi/WiFiPriv.h | 41 ++++ .../realtek-ambz/libraries/WiFi/WiFiSTA.cpp | 227 ++++++++++++++++++ .../realtek-ambz/libraries/WiFi/WiFiScan.cpp | 117 +++++++++ builder/frameworks/realtek-ambz-arduino.py | 13 +- builder/frameworks/realtek-ambz-sdk.py | 1 + 15 files changed, 1092 insertions(+), 129 deletions(-) create mode 100644 arduino/realtek-ambz/libraries/WiFi/WiFi.cpp create mode 100644 arduino/realtek-ambz/libraries/WiFi/WiFi.h create mode 100644 arduino/realtek-ambz/libraries/WiFi/WiFiAP.cpp create mode 100644 arduino/realtek-ambz/libraries/WiFi/WiFiGeneric.cpp create mode 100644 arduino/realtek-ambz/libraries/WiFi/WiFiPriv.h create mode 100644 arduino/realtek-ambz/libraries/WiFi/WiFiSTA.cpp create mode 100644 arduino/realtek-ambz/libraries/WiFi/WiFiScan.cpp diff --git a/arduino/libretuya/IPv6Address.cpp b/arduino/libretuya/IPv6Address.cpp index 2f39b37..e062f2e 100644 --- a/arduino/libretuya/IPv6Address.cpp +++ b/arduino/libretuya/IPv6Address.cpp @@ -47,9 +47,9 @@ bool IPv6Address::operator==(const uint8_t* addr) const return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; } -/* size_t IPv6Address::printTo(Print& p) const +size_t IPv6Address::printTo(Print& p) const { - size_t n = 0; + /* size_t n = 0; for(int i = 0; i < 16; i+=2) { if(i){ n += p.print(':'); @@ -58,8 +58,8 @@ bool IPv6Address::operator==(const uint8_t* addr) const n += p.printf("%02x", _address.bytes[i+1]); } - return n; -} */ + return n; */ +} String IPv6Address::toString() const { diff --git a/arduino/libretuya/IPv6Address.h b/arduino/libretuya/IPv6Address.h index fff5df0..a26df79 100644 --- a/arduino/libretuya/IPv6Address.h +++ b/arduino/libretuya/IPv6Address.h @@ -17,15 +17,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef IPv6Address_h -#define IPv6Address_h +#pragma once #include #include -#include +#include // A class to make it easier to handle and pass around IP addresses +namespace arduino { + class IPv6Address: public Printable { private: @@ -84,7 +85,7 @@ public: IPv6Address& operator=(const uint8_t *address); // TODO implement printTo() - // virtual size_t printTo(Print& p) const; + virtual size_t printTo(Print& p) const; String toString() const; friend class UDP; @@ -92,4 +93,6 @@ public: friend class Server; }; -#endif +} + +using arduino::IPv6Address; diff --git a/arduino/libretuya/api/WiFi.h b/arduino/libretuya/api/WiFi.h index e1cf6c1..21e0f1f 100644 --- a/arduino/libretuya/api/WiFi.h +++ b/arduino/libretuya/api/WiFi.h @@ -27,147 +27,151 @@ #include #include -#include "WiFiClient.h" -#include "WiFiServer.h" #include "WiFiType.h" -#include "WiFiUdp.h" // TODO wifi events // TODO WiFiMulti library -class IWiFi { +class IWiFiClass { public: - void printDiag(Print &dest); + virtual void printDiag(Print &dest) = 0; +}; - // WiFiGenericClass - int32_t channel(void); - static bool mode(WiFiMode mode); - static WiFiMode getMode(); +class IWiFiGenericClass { + public: + virtual int32_t channel(void) = 0; + virtual bool mode(WiFiMode mode) = 0; + virtual WiFiMode getMode() = 0; + virtual WiFiStatus status() = 0; - bool enableSTA(bool enable); - bool enableAP(bool enable); + virtual bool enableSTA(bool enable) = 0; + virtual bool enableAP(bool enable) = 0; - bool setSleep(bool enable); - bool getSleep(); + virtual bool setSleep(bool enable) = 0; + virtual bool getSleep() = 0; - bool setTxPower(int power); - int getTxPower(); + virtual bool setTxPower(int power) = 0; + virtual int getTxPower() = 0; - static int hostByName(const char *aHostname, IPAddress &aResult); + virtual int hostByName(const char *hostname, IPAddress &aResult) { + aResult = hostByName(hostname); + return true; + } + + virtual IPAddress hostByName(const char *hostname) = 0; static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet); static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet); static uint8_t calculateSubnetCIDR(IPAddress subnetMask); + static String macToString(uint8_t *mac); +}; - // WiFiSTAClass - WiFiStatus begin( +class IWiFiSTAClass { + public: + virtual WiFiStatus begin( const char *ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, - bool connect = true, - ); - WiFiStatus - begin(char *ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true, ); - WiFiStatus begin(); + bool connect = true + ) = 0; + virtual WiFiStatus begin( + char *ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true + ) = 0; - bool config( - IPAddress local_ip, + virtual bool config( + IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, - IPAddress dns2 = (uint32_t)0x00000000, - ); + IPAddress dns2 = (uint32_t)0x00000000 + ) = 0; - bool reconnect(); - bool disconnect(bool wifioff = false, bool eraseap = false); + virtual bool reconnect() = 0; + virtual bool disconnect(bool wifiOff = false) = 0; - bool isConnected(); + virtual bool isConnected(); - bool setAutoConnect(bool autoConnect); - bool getAutoConnect(); + virtual bool setAutoReconnect(bool autoReconnect) = 0; + virtual bool getAutoReconnect() = 0; - bool setAutoReconnect(bool autoReconnect); - bool getAutoReconnect(); + virtual WiFiStatus waitForConnectResult(unsigned long timeout) = 0; - uint8_t waitForConnectResult(); + virtual IPAddress localIP() = 0; + virtual uint8_t *macAddress(uint8_t *mac) = 0; + virtual String macAddress() = 0; + virtual IPAddress subnetMask() = 0; + virtual IPAddress gatewayIP() = 0; + virtual IPAddress dnsIP(uint8_t dns_no = 0) = 0; + virtual IPAddress broadcastIP() = 0; + virtual IPAddress networkID() = 0; + virtual uint8_t subnetCIDR() = 0; + virtual bool enableIpV6() = 0; + virtual IPv6Address localIPv6() = 0; + virtual const char *getHostname() = 0; + virtual bool setHostname(const char *hostname) = 0; + virtual bool setMacAddress(const uint8_t *mac) = 0; - IPAddress localIP(); - uint8_t *macAddress(uint8_t *mac); - String macAddress(); - IPAddress subnetMask(); - IPAddress gatewayIP(); - IPAddress dnsIP(uint8_t dns_no = 0); - IPAddress broadcastIP(); - IPAddress networkID(); - uint8_t subnetCIDR(); - bool enableIpV6(); - IPv6Address localIPv6(); - const char *getHostname(); - bool setHostname(const char *hostname); - - bool hostname(const String &aHostname) { + inline bool hostname(const String &aHostname) { return setHostname(aHostname.c_str()); } - static WiFiStatus status(); - String SSID() const; - String psk() const; - uint8_t *BSSID(); - String BSSIDstr(); - int8_t RSSI(); + virtual const String SSID() = 0; + virtual const String psk() = 0; + virtual uint8_t *BSSID() = 0; + virtual String BSSIDstr() = 0; + virtual int8_t RSSI() = 0; + virtual WiFiAuthMode getEncryption() = 0; +}; - // WiFiScanClass - int16_t scanNetworks( +class IWiFiScanClass { + public: + virtual int16_t scanNetworks( bool async = false, - bool show_hidden = false, + bool showHidden = false, bool passive = false, - uint32_t max_ms_per_chan = 300, - uint8_t channel = 0, - ); - bool getNetworkInfo( + uint32_t maxMsPerChannel = 300, + uint8_t channel = 0 + ) = 0; + virtual bool getNetworkInfo( uint8_t networkItem, String &ssid, WiFiAuthMode &encryptionType, int32_t &RSSI, uint8_t *&BSSID, - int32_t &channel, - ); + int32_t &channel + ) = 0; - int16_t scanComplete(); - void scanDelete(); + virtual int16_t scanComplete() = 0; + virtual void scanDelete() = 0; - String SSID(uint8_t networkItem); - WiFiAuthMode encryptionType(uint8_t networkItem); - int32_t RSSI(uint8_t networkItem); - uint8_t *BSSID(uint8_t networkItem); - String BSSIDstr(uint8_t networkItem); - int32_t channel(uint8_t networkItem); - - static void *getScanInfoByIndex(int i) { - return _getScanInfoByIndex(i); - }; - - // WiFiAPClass - bool softAP( - const char *ssid, const char *passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4 - ); - bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet); - bool softAPdisconnect(bool wifioff = false); - - uint8_t softAPgetStationNum(); - - IPAddress softAPIP(); - IPAddress softAPBroadcastIP(); - IPAddress softAPNetworkID(); - uint8_t softAPSubnetCIDR(); - bool softAPenableIpV6(); - IPv6Address softAPIPv6(); - const char *softAPgetHostname(); - bool softAPsetHostname(const char *hostname); - uint8_t *softAPmacAddress(uint8_t *mac); - String softAPmacAddress(void); - String softAPSSID(void) const; + virtual String SSID(uint8_t networkItem) = 0; + virtual WiFiAuthMode encryptionType(uint8_t networkItem) = 0; + virtual int32_t RSSI(uint8_t networkItem) = 0; + virtual uint8_t *BSSID(uint8_t networkItem) = 0; + virtual String BSSIDstr(uint8_t networkItem) = 0; + virtual int32_t channel(uint8_t networkItem) = 0; }; -extern WiFiClass WiFi; +class IWiFiAPClass { + public: + virtual bool softAP( + const char *ssid, const char *passphrase = NULL, int channel = 1, bool ssidHidden = false, int maxClients = 4 + ) = 0; + virtual bool softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet) = 0; + virtual bool softAPdisconnect(bool wifiOff = false) = 0; + + virtual uint8_t softAPgetStationNum() = 0; + + virtual IPAddress softAPIP() = 0; + virtual IPAddress softAPBroadcastIP() = 0; + virtual IPAddress softAPNetworkID() = 0; + virtual uint8_t softAPSubnetCIDR() = 0; + virtual bool softAPenableIpV6() = 0; + virtual IPv6Address softAPIPv6() = 0; + virtual const char *softAPgetHostname() = 0; + virtual bool softAPsetHostname(const char *hostname) = 0; + virtual uint8_t *softAPmacAddress(uint8_t *mac) = 0; + virtual String softAPmacAddress(void) = 0; + virtual const String softAPSSID(void) = 0; +}; diff --git a/arduino/libretuya/api/WiFiClient.h b/arduino/libretuya/api/WiFiClient.h index 0691b43..5a0c22a 100644 --- a/arduino/libretuya/api/WiFiClient.h +++ b/arduino/libretuya/api/WiFiClient.h @@ -21,11 +21,10 @@ #include #include -#include class IWiFiClient : public Client { public: - WiFiClient(int fd); + IWiFiClient(int fd) {} int connect(IPAddress ip, uint16_t port, int32_t timeout); int connect(const char *host, uint16_t port, int32_t timeout); @@ -36,7 +35,7 @@ class IWiFiClient : public Client { int socket(); int setTimeout(uint32_t seconds); - WiFiClient &operator=(const WiFiClient &other); + IWiFiClient &operator=(const WiFiClient &other); bool operator==(const bool value) { return bool() == value; @@ -46,9 +45,9 @@ class IWiFiClient : public Client { return bool() != value; } - bool operator==(const WiFiClient &); + bool operator==(const IWiFiClient &); - bool operator!=(const WiFiClient &rhs) { + bool operator!=(const IWiFiClient &rhs) { return !this->operator==(rhs); }; diff --git a/arduino/libretuya/api/WiFiServer.h b/arduino/libretuya/api/WiFiServer.h index 66ac3a7..d18ff46 100644 --- a/arduino/libretuya/api/WiFiServer.h +++ b/arduino/libretuya/api/WiFiServer.h @@ -28,9 +28,9 @@ class IWiFiServer : public Server { public: void listenOnLocalhost() {} - WiFiServer(uint16_t port = 80, uint8_t max_clients = 4) {} + IWiFiServer(uint16_t port = 80, uint8_t max_clients = 4) {} - ~WiFiServer() { + ~IWiFiServer() { end(); } diff --git a/arduino/libretuya/api/WiFiType.h b/arduino/libretuya/api/WiFiType.h index c85c076..490e237 100644 --- a/arduino/libretuya/api/WiFiType.h +++ b/arduino/libretuya/api/WiFiType.h @@ -24,10 +24,10 @@ #define WIFI_SCAN_RUNNING (-1) #define WIFI_SCAN_FAILED (-2) -#define WiFiMode_t wl_mode_t -#define WiFiMode wl_mode_t +#define WiFiMode_t wifi_mode_t +#define WiFiMode wifi_mode_t #define WiFiStatus wl_status_t -#define WiFiAuthMode wl_auth_mode_t +#define WiFiAuthMode wifi_auth_mode_t #define WIFI_OFF WIFI_MODE_NULL #define WIFI_STA WIFI_MODE_STA @@ -40,7 +40,7 @@ typedef enum { WIFI_MODE_AP, WIFI_MODE_APSTA, WIFI_MODE_MAX, -} wl_mode_t; +} wifi_mode_t; typedef enum { WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library @@ -56,11 +56,11 @@ typedef enum { typedef enum { WIFI_AUTH_INVALID = 255, WIFI_AUTH_AUTO = 200, - WIFI_AUTH_OPEN_SYSTEM = 0, - WIFI_AUTH_SHARED_KEY = 1, + WIFI_AUTH_OPEN = 0, + WIFI_AUTH_WEP = 1, WIFI_AUTH_WPA = 10, WIFI_AUTH_WPA2 = 11, WIFI_AUTH_WPA_PSK = 2, WIFI_AUTH_WPA2_PSK = 3, WIFI_AUTH_WPA_WPA2_PSK = 4, -} wl_auth_mode_t; +} wifi_auth_mode_t; diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFi.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFi.cpp new file mode 100644 index 0000000..d00e23e --- /dev/null +++ b/arduino/realtek-ambz/libraries/WiFi/WiFi.cpp @@ -0,0 +1,94 @@ +#include "WiFi.h" +#include "WiFiPriv.h" + +rtw_network_info_t wifi = {0}; +rtw_ap_info_t ap = {0}; +rtw_wifi_setting_t wifi_setting; +unsigned char sta_password[65] = {0}; +unsigned char ap_password[65] = {0}; + +void reset_wifi_struct(void) { + memset(wifi.ssid.val, 0, sizeof(wifi.ssid.val)); + memset(wifi.bssid.octet, 0, ETH_ALEN); + memset(sta_password, 0, sizeof(sta_password)); + memset(ap_password, 0, sizeof(ap_password)); + wifi.ssid.len = 0; + wifi.password = NULL; + wifi.password_len = 0; + wifi.key_id = -1; + memset(ap.ssid.val, 0, sizeof(ap.ssid.val)); + ap.ssid.len = 0; + ap.password = NULL; + ap.password_len = 0; + ap.channel = 1; +} + +WiFiClass::WiFiClass() { + _scanSem = xSemaphoreCreateBinary(); +} + +WiFiClass::~WiFiClass() { + vSemaphoreDelete(_scanSem); +} + +void WiFiClass::printDiag(Print &dest) { + const char *modes[] = {"NULL", "STA", "AP", "STA+AP"}; + const char *enc[] = {"Open", "WEP", "WPA PSK", "WPA2 PSK", "WPA/WPA2", "WPA", "WPA2"}; + + dest.print("Mode: "); + dest.println(modes[getMode()]); + + if (wifi_mode & WIFI_MODE_STA) { + dest.println("-- Station --"); + dest.print("SSID: "); + dest.println(SSID()); + if (isConnected()) { + dest.print("BSSID: "); + dest.println(BSSIDstr()); + dest.print("RSSI: "); + dest.println(RSSI()); + dest.print("Encryption: "); + dest.println(enc[getEncryption()]); + dest.print("IP: "); + dest.println(localIP()); + dest.print("MAC: "); + dest.println(macAddress()); + dest.print("Hostname: "); + dest.println(getHostname()); + } + } + + if (wifi_mode & WIFI_MODE_AP) { + dest.println("-- Access Point --"); + dest.print("SSID: "); + dest.println(softAPSSID()); + dest.print("IP: "); + dest.println(softAPIP()); + dest.print("MAC: "); + dest.println(softAPmacAddress()); + dest.print("Hostname: "); + dest.println(softAPgetHostname()); + } +} + +WiFiAuthMode WiFiClass::securityTypeToAuthMode(uint8_t type) { + switch (wifi_setting.security_type) { + case RTW_SECURITY_OPEN: + return WIFI_AUTH_OPEN; + case RTW_SECURITY_WEP_SHARED: + return WIFI_AUTH_WEP; + case RTW_SECURITY_WPA_TKIP_PSK: + return WIFI_AUTH_WPA_PSK; + case RTW_SECURITY_WPA_AES_PSK: + return WIFI_AUTH_WPA; + case RTW_SECURITY_WPA2_TKIP_PSK: + return WIFI_AUTH_WPA2_PSK; + case RTW_SECURITY_WPA2_AES_PSK: + return WIFI_AUTH_WPA2; + case RTW_SECURITY_WPA_WPA2_MIXED: + return WIFI_AUTH_WPA_WPA2_PSK; + } + return WIFI_AUTH_INVALID; +} + +WiFiClass WiFi; diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFi.h b/arduino/realtek-ambz/libraries/WiFi/WiFi.h new file mode 100644 index 0000000..80f32f5 --- /dev/null +++ b/arduino/realtek-ambz/libraries/WiFi/WiFi.h @@ -0,0 +1,177 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include +#include +#include + +#ifdef __cplusplus +} // extern "C" +#endif + +class WiFiClass : public IWiFiClass, + public IWiFiGenericClass, + public IWiFiSTAClass, + public IWiFiScanClass, + public IWiFiAPClass { + private: + static WiFiAuthMode securityTypeToAuthMode(uint8_t type); + + bool _initialized; + bool _sleep; + + bool _scanning = false; + SemaphoreHandle_t _scanSem; + uint8_t _netCount = 0; + char **_netSsid = NULL; + WiFiAuthMode *_netEncr = NULL; + int32_t *_netRssi = NULL; + rtw_mac_t *_netBssid = NULL; + int32_t *_netChannel = NULL; + + static rtw_result_t scanHandler(rtw_scan_handler_result_t *result); + + public: + // IWiFiClass + WiFiClass(); + ~WiFiClass(); + void printDiag(Print &dest); + + public: + // IWiFiGenericClass + int32_t channel(void); + + bool mode(WiFiMode mode) override; + WiFiMode getMode(); + WiFiStatus status(); + + bool enableSTA(bool enable); + bool enableAP(bool enable); + + bool setSleep(bool enable); + bool getSleep(); + + bool setTxPower(int power); + int getTxPower(); + + IPAddress hostByName(const char *hostname); + + static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet); + static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet); + static uint8_t calculateSubnetCIDR(IPAddress subnetMask); + static String macToString(uint8_t *mac); + + public: + // IWiFiSTAClass + WiFiStatus begin( + const char *ssid, + const char *passphrase = NULL, + int32_t channel = 0, + const uint8_t *bssid = NULL, + bool connect = true + ) override; + WiFiStatus + begin(char *ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true); + + bool config( + IPAddress localIP, + IPAddress gateway, + IPAddress subnet, + IPAddress dns1 = (uint32_t)0x00000000, + IPAddress dns2 = (uint32_t)0x00000000 + ); + + inline bool reconnect() { + return reconnect(NULL); + } + + bool reconnect(const uint8_t *bssid = NULL); + bool disconnect(bool wifiOff = false); + + bool isConnected() override; + + bool setAutoReconnect(bool autoReconnect); + bool getAutoReconnect(); + + WiFiStatus waitForConnectResult(unsigned long timeout); + + IPAddress localIP(); + uint8_t *macAddress(uint8_t *mac); + String macAddress(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsIP(uint8_t dns_no); + IPAddress broadcastIP(); + IPAddress networkID(); + uint8_t subnetCIDR(); + bool enableIpV6(); + IPv6Address localIPv6(); + const char *getHostname(); + bool setHostname(const char *hostname); + bool setMacAddress(const uint8_t *mac); + + const String SSID(); + const String psk(); + uint8_t *BSSID(); + String BSSIDstr(); + int8_t RSSI(); + WiFiAuthMode getEncryption(); + + public: + // IWiFiScanClass + int16_t scanNetworks( + bool async = false, + bool showHidden = false, + bool passive = false, + uint32_t maxMsPerChannel = 300, + uint8_t channel = 0 + ); + bool getNetworkInfo( + uint8_t networkItem, + String &ssid, + WiFiAuthMode &encryptionType, + int32_t &RSSI, + uint8_t *&BSSID, + int32_t &channel + ); + + int16_t scanComplete(); + void scanDelete(); + + String SSID(uint8_t networkItem); + WiFiAuthMode encryptionType(uint8_t networkItem); + int32_t RSSI(uint8_t networkItem); + uint8_t *BSSID(uint8_t networkItem); + String BSSIDstr(uint8_t networkItem); + int32_t channel(uint8_t networkItem); + + public: + // IWiFiAPClass + bool softAP( + const char *ssid, const char *passphrase = NULL, int channel = 1, bool ssidHidden = false, int maxClients = 4 + ); + bool softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet); + bool softAPdisconnect(bool wifiOff = false); + + uint8_t softAPgetStationNum(); + + IPAddress softAPIP(); + IPAddress softAPBroadcastIP(); + IPAddress softAPNetworkID(); + uint8_t softAPSubnetCIDR(); + bool softAPenableIpV6(); + IPv6Address softAPIPv6(); + const char *softAPgetHostname(); + bool softAPsetHostname(const char *hostname); + uint8_t *softAPmacAddress(uint8_t *mac); + String softAPmacAddress(void); + const String softAPSSID(void); +}; + +extern WiFiClass WiFi; diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiAP.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFiAP.cpp new file mode 100644 index 0000000..2a34824 --- /dev/null +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiAP.cpp @@ -0,0 +1,151 @@ +#include "WiFi.h" +#include "WiFiPriv.h" + +bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bool ssidHidden, int maxClients) { + if (!enableAP(true)) + return false; + + if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) + return false; + + if (passphrase && strlen(passphrase) < 8) + return false; + + strcpy((char *)ap.ssid.val, ssid); + ap.ssid.len = strlen(ssid); + ap.channel = channel; + + ap.security_type = RTW_SECURITY_OPEN; + ap.password = NULL; + ap.password_len = 0; + + if (passphrase) { + strcpy((char *)ap_password, passphrase); + wifi.security_type = RTW_SECURITY_WPA2_AES_PSK; + wifi.password = ap_password; + wifi.password_len = strlen(passphrase); + } + + dhcps_deinit(); + + int ret; + if (!ssidHidden) { + ret = wifi_start_ap( + (char *)ap.ssid.val, + ap.security_type, + (char *)ap.password, + ap.ssid.len, + ap.password_len, + ap.channel + ); + } else { + ret = wifi_start_ap_with_hidden_ssid( + (char *)ap.ssid.val, + ap.security_type, + (char *)ap.password, + ap.ssid.len, + ap.password_len, + ap.channel + ); + } + + if (ret < 0) + return false; + + uint8_t timeout = 20; + unsigned char essid[33]; + + const char *ifname = NETNAME_AP; + struct netif *ifs = NETIF_RTW_AP; + + while (1) { + if (wext_get_ssid(ifname, essid) > 0) { + if (strcmp((const char *)essid, (const char *)ap.ssid.val) == 0) + break; + } + + if (!timeout) + return false; + + vTaskDelay(1 * configTICK_RATE_HZ); + timeout--; + } + + dhcps_init(ifs); + return true; +} + +bool WiFiClass::softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet) { + if (!enableAP(true)) + return false; + struct netif *ifs = NETIF_RTW_AP; + struct ip_addr ipaddr, netmask, gw; + ipaddr.addr = localIP; + netmask.addr = subnet; + gw.addr = gateway; + netif_set_addr(ifs, &ipaddr, &netmask, &gw); + return true; +} + +bool WiFiClass::softAPdisconnect(bool wifiOff) { + // TODO implement wifi_restart_ap + if (wifiOff) + return enableAP(false); + return true; +} + +uint8_t WiFiClass::softAPgetStationNum() { + // TODO + return 0; +} + +IPAddress WiFiClass::softAPIP() { + return LwIP_GetIP(NETIF_RTW_AP); +} + +IPAddress WiFiClass::softAPBroadcastIP() { + return calculateBroadcast(softAPIP(), LwIP_GetMASK(NETIF_RTW_AP)); +} + +IPAddress WiFiClass::softAPNetworkID() { + return calculateNetworkID(softAPIP(), LwIP_GetMASK(NETIF_RTW_AP)); +} + +uint8_t WiFiClass::softAPSubnetCIDR() { + return calculateSubnetCIDR(LwIP_GetMASK(NETIF_RTW_AP)); +} + +bool WiFiClass::softAPenableIpV6() { + return false; +} + +IPv6Address WiFiClass::softAPIPv6() { + return IPv6Address(); +} + +const char *WiFiClass::softAPgetHostname() { + return netif_get_hostname(NETIF_RTW_AP); +} + +bool WiFiClass::softAPsetHostname(const char *hostname) { + netif_set_hostname(NETIF_RTW_AP, (char *)hostname); + return true; +} + +uint8_t *WiFiClass::softAPmacAddress(uint8_t *mac) { + uint8_t *macLocal = LwIP_GetMAC(NETIF_RTW_AP); + memcpy(mac, macLocal, ETH_ALEN); + free(macLocal); + return mac; +} + +String WiFiClass::softAPmacAddress(void) { + uint8_t mac[ETH_ALEN]; + macAddress(mac); + return macToString(mac); +} + +const String WiFiClass::softAPSSID(void) { + wifi_get_setting(NETNAME_AP, &wifi_setting); + return (char *)wifi_setting.ssid; +} diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiGeneric.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFiGeneric.cpp new file mode 100644 index 0000000..f6baad5 --- /dev/null +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiGeneric.cpp @@ -0,0 +1,150 @@ +#include "WiFi.h" +#include "WiFiPriv.h" + +int32_t WiFiClass::channel() { + int channel; + wifi_get_channel(&channel); + return channel; +} + +bool WiFiClass::mode(WiFiMode mode) { + WiFiMode currentMode = getMode(); + if (mode == currentMode) + return true; + + if (!currentMode && mode && !_initialized) { + // initialize wifi first + LwIP_Init(); + reset_wifi_struct(); + wifi_manager_init(); + _initialized = true; + } + if (currentMode) { + // stop wifi to change mode + dhcps_deinit(); + if (wifi_off() != RTW_SUCCESS) + return false; + vTaskDelay(20); + } + + if (wifi_on((rtw_mode_t)mode) != RTW_SUCCESS) + return false; + + if (mode & WIFI_MODE_AP) { + dhcps_init(NETIF_RTW_STA); + } + return true; +} + +WiFiMode WiFiClass::getMode() { + if (!_initialized) + return WIFI_MODE_NULL; + return (WiFiMode)wifi_mode; +} + +WiFiStatus WiFiClass::status() { + if (wifi_is_connected_to_ap() == 0) { + return WL_CONNECTED; + } else { + return WL_DISCONNECTED; + } +} + +bool WiFiClass::enableSTA(bool enable) { + WiFiMode currentMode = getMode(); + if ((currentMode & WIFI_MODE_STA != 0) != enable) { + return mode((WiFiMode)(currentMode ^ WIFI_MODE_STA)); + } + return true; +} + +bool WiFiClass::enableAP(bool enable) { + WiFiMode currentMode = getMode(); + if ((currentMode & WIFI_MODE_AP != 0) != enable) { + return mode((WiFiMode)(currentMode ^ WIFI_MODE_AP)); + } + return true; +} + +bool WiFiClass::setSleep(bool enable) { + if (enable) + if (wifi_enable_powersave() != RTW_SUCCESS) + return false; + else if (wifi_disable_powersave() != RTW_SUCCESS) + return false; + _sleep = enable; + return true; +} + +bool WiFiClass::getSleep() { + return _sleep; +} + +bool WiFiClass::setTxPower(int power) { + return false; // wifi_set_txpower(power) == RTW_SUCCESS; +} + +int WiFiClass::getTxPower() { + return 0; + int power = 0; + wifi_get_txpower(&power); + return power; +} + +IPAddress WiFiClass::hostByName(const char *hostname) { + ip_addr_t ip; + int ret = netconn_gethostbyname(hostname, &ip); + if (ret == ERR_OK) { + return ip.addr; + } + return IPAddress(); +} + +IPAddress WiFiClass::calculateNetworkID(IPAddress ip, IPAddress subnet) { + IPAddress networkID; + + for (size_t i = 0; i < 4; i++) + networkID[i] = subnet[i] & ip[i]; + + return networkID; +} + +IPAddress WiFiClass::calculateBroadcast(IPAddress ip, IPAddress subnet) { + IPAddress broadcastIp; + + for (int i = 0; i < 4; i++) + broadcastIp[i] = ~subnet[i] | ip[i]; + + return broadcastIp; +} + +uint8_t WiFiClass::calculateSubnetCIDR(IPAddress subnetMask) { + uint8_t CIDR = 0; + + for (uint8_t i = 0; i < 4; i++) { + if (subnetMask[i] == 0x80) // 128 + CIDR += 1; + else if (subnetMask[i] == 0xC0) // 192 + CIDR += 2; + else if (subnetMask[i] == 0xE0) // 224 + CIDR += 3; + else if (subnetMask[i] == 0xF0) // 242 + CIDR += 4; + else if (subnetMask[i] == 0xF8) // 248 + CIDR += 5; + else if (subnetMask[i] == 0xFC) // 252 + CIDR += 6; + else if (subnetMask[i] == 0xFE) // 254 + CIDR += 7; + else if (subnetMask[i] == 0xFF) // 255 + CIDR += 8; + } + + return CIDR; +} + +String WiFiClass::macToString(uint8_t *mac) { + char macStr[ETH_ALEN * 3]; + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return macStr; +} diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiPriv.h b/arduino/realtek-ambz/libraries/WiFi/WiFiPriv.h new file mode 100644 index 0000000..09b512c --- /dev/null +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiPriv.h @@ -0,0 +1,41 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define LWIP_NETIF_HOSTNAME 1 // this is defined in PIO builder + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern struct netif xnetif[NET_IF_NUM]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#include + +#include "WiFi.h" + +extern rtw_network_info_t wifi; +extern rtw_ap_info_t ap; +extern rtw_wifi_setting_t wifi_setting; +extern unsigned char sta_password[65]; +extern unsigned char ap_password[65]; +extern void reset_wifi_struct(void); +extern rtw_mode_t wifi_mode; + +#define NETIF_RTW_STA &xnetif[RTW_STA_INTERFACE] +#define NETIF_RTW_AP (wifi_mode == WIFI_MODE_APSTA ? &xnetif[RTW_AP_INTERFACE] : NETIF_RTW_STA) + +#define NETNAME_STA WLAN0_NAME +#define NETNAME_AP (wifi_mode == WIFI_MODE_APSTA ? WLAN1_NAME : WLAN0_NAME) diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiSTA.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFiSTA.cpp new file mode 100644 index 0000000..84047ec --- /dev/null +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiSTA.cpp @@ -0,0 +1,227 @@ +#include "WiFi.h" +#include "WiFiPriv.h" + +WiFiStatus WiFiClass::begin(char *ssid, char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) { + return begin((const char *)ssid, (const char *)passphrase, channel, bssid, connect); +} + +WiFiStatus +WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) { + if (!enableSTA(true)) + return WL_CONNECT_FAILED; + + if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) + return WL_CONNECT_FAILED; + + if (passphrase && strlen(passphrase) > 64) + return WL_CONNECT_FAILED; + + memset(wifi.bssid.octet, 0, ETH_ALEN); + strcpy((char *)wifi.ssid.val, ssid); + wifi.ssid.len = strlen(ssid); + + wifi.security_type = RTW_SECURITY_OPEN; + wifi.password = NULL; + wifi.password_len = 0; + wifi.key_id = 0; + + if (passphrase) { + strcpy((char *)sta_password, passphrase); + wifi.security_type = RTW_SECURITY_WPA2_AES_PSK; + wifi.password = sta_password; + wifi.password_len = strlen(passphrase); + } + + if (reconnect(bssid)) + return WL_CONNECTED; + else + return WL_CONNECT_FAILED; +} + +bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) { + if (!enableSTA(true)) + return false; + struct netif *ifs = NETIF_RTW_STA; + struct ip_addr ipaddr, netmask, gw, d1, d2; + ipaddr.addr = localIP; + netmask.addr = subnet; + gw.addr = gateway; + d1.addr = dns1; + d2.addr = dns2; + netif_set_addr(ifs, &ipaddr, &netmask, &gw); + if (dns1[0]) + dns_setserver(0, &d1); + if (dns2[0]) + dns_setserver(0, &d2); + return true; +} + +bool WiFiClass::reconnect(const uint8_t *bssid) { + int ret; + uint8_t dhcpRet; + + if (!bssid) { + ret = wifi_connect( + (char *)wifi.ssid.val, + wifi.security_type, + (char *)wifi.password, + wifi.ssid.len, + wifi.password_len, + wifi.key_id, + NULL + ); + } else { + ret = wifi_connect_bssid( + (unsigned char *)bssid, + (char *)wifi.ssid.val, + wifi.security_type, + (char *)wifi.password, + ETH_ALEN, + wifi.ssid.len, + wifi.password_len, + wifi.key_id, + NULL + ); + } + + if (ret == RTW_SUCCESS) { + dhcpRet = LwIP_DHCP(0, DHCP_START); + if (dhcpRet == DHCP_ADDRESS_ASSIGNED) + return true; + wifi_disconnect(); + return false; + } + return false; +} + +bool WiFiClass::disconnect(bool wifiOff) { + int ret = wifi_disconnect(); + if (wifiOff) + enableSTA(false); + return ret == RTW_SUCCESS; +} + +bool WiFiClass::isConnected() { + return status() == WL_CONNECTED; +} + +bool WiFiClass::setAutoReconnect(bool autoReconnect) { + return wifi_set_autoreconnect(autoReconnect) == RTW_SUCCESS; +} + +bool WiFiClass::getAutoReconnect() { + bool autoReconnect; + wifi_get_autoreconnect((uint8_t *)&autoReconnect); + return autoReconnect; +} + +WiFiStatus WiFiClass::waitForConnectResult(unsigned long timeout) { + if ((wifi_mode & WIFI_MODE_STA) == 0) { + return WL_DISCONNECTED; + } + unsigned long start = millis(); + while ((!status() || status() >= WL_DISCONNECTED) && (millis() - start) < timeout) { + delay(100); + } + return status(); +} + +IPAddress WiFiClass::localIP() { + if (!wifi_mode) + return IPAddress(); + return LwIP_GetIP(NETIF_RTW_STA); +} + +uint8_t *WiFiClass::macAddress(uint8_t *mac) { + uint8_t *macLocal = LwIP_GetMAC(NETIF_RTW_STA); + memcpy(mac, macLocal, ETH_ALEN); + free(macLocal); + return mac; +} + +String WiFiClass::macAddress(void) { + uint8_t mac[ETH_ALEN]; + macAddress(mac); + return macToString(mac); +} + +IPAddress WiFiClass::subnetMask() { + return LwIP_GetMASK(NETIF_RTW_STA); +} + +IPAddress WiFiClass::gatewayIP() { + return LwIP_GetGW(NETIF_RTW_STA); +} + +IPAddress WiFiClass::dnsIP(uint8_t dns_no) { + struct ip_addr dns; + LwIP_GetDNS(&dns); + return dns.addr; +} + +IPAddress WiFiClass::broadcastIP() { + return LwIP_GetBC(NETIF_RTW_STA); +} + +IPAddress WiFiClass::networkID() { + return calculateNetworkID(gatewayIP(), subnetMask()); +} + +uint8_t WiFiClass::subnetCIDR() { + return calculateSubnetCIDR(subnetMask()); +} + +bool WiFiClass::enableIpV6() { + return false; +} + +IPv6Address WiFiClass::localIPv6() { + return IPv6Address(); +} + +const char *WiFiClass::getHostname() { + return netif_get_hostname(NETIF_RTW_STA); +} + +bool WiFiClass::setHostname(const char *hostname) { + netif_set_hostname(NETIF_RTW_STA, (char *)hostname); + return true; +} + +bool WiFiClass::setMacAddress(const uint8_t *mac) { + return wifi_set_mac_address((char *)mac) == RTW_SUCCESS; +} + +const String WiFiClass::SSID() { + if (!isConnected()) + return ""; + wifi_get_setting(NETNAME_STA, &wifi_setting); + return (char *)wifi_setting.ssid; +} + +const String WiFiClass::psk() { + if (!isConnected() || !wifi.password) + return ""; + return (char *)wifi.password; +} + +uint8_t *WiFiClass::BSSID() { + uint8_t bssid[ETH_ALEN]; + wext_get_bssid(NETNAME_STA, bssid); + return bssid; +} + +String WiFiClass::BSSIDstr() { + return macToString(BSSID()); +} + +int8_t WiFiClass::RSSI() { + int rssi = 0; + wifi_get_rssi(&rssi); + return rssi; +} + +WiFiAuthMode WiFiClass::getEncryption() { + wifi_get_setting(NETNAME_STA, &wifi_setting); + return WiFiClass::securityTypeToAuthMode(wifi_setting.security_type); +} diff --git a/arduino/realtek-ambz/libraries/WiFi/WiFiScan.cpp b/arduino/realtek-ambz/libraries/WiFi/WiFiScan.cpp new file mode 100644 index 0000000..092826d --- /dev/null +++ b/arduino/realtek-ambz/libraries/WiFi/WiFiScan.cpp @@ -0,0 +1,117 @@ +#include "WiFi.h" +#include "WiFiPriv.h" + +rtw_result_t WiFiClass::scanHandler(rtw_scan_handler_result_t *result) { + WiFiClass *cls = (WiFiClass *)result->user_data; + + if (result->scan_complete == RTW_TRUE) { + cls->_scanning = false; + xSemaphoreGive(cls->_scanSem); + return RTW_SUCCESS; + } + + rtw_scan_result_t *net = &result->ap_details; + net->SSID.val[net->SSID.len] = '\0'; + + uint8_t newSize = cls->_netCount + 1; + cls->_netSsid = (char **)realloc(cls->_netSsid, newSize * sizeof(char *)); + cls->_netEncr = (WiFiAuthMode *)realloc(cls->_netEncr, newSize * sizeof(WiFiAuthMode)); + cls->_netRssi = (int32_t *)realloc(cls->_netRssi, newSize * sizeof(int32_t)); + cls->_netBssid = (rtw_mac_t *)realloc(cls->_netBssid, newSize * sizeof(rtw_mac_t)); + cls->_netChannel = (int32_t *)realloc(cls->_netChannel, newSize * sizeof(int32_t)); + + cls->_netSsid[cls->_netCount] = (char *)malloc((net->SSID.len + 1) * sizeof(char)); + strcpy(cls->_netSsid[cls->_netCount], (char *)net->SSID.val); + cls->_netEncr[cls->_netCount] = WiFiClass::securityTypeToAuthMode(net->security); + cls->_netRssi[cls->_netCount] = net->signal_strength; + memcpy(cls->_netBssid[cls->_netCount].octet, net->BSSID.octet, ETH_ALEN); + cls->_netChannel[cls->_netCount] = net->channel; + cls->_netCount++; + + return RTW_SUCCESS; +} + +int16_t WiFiClass::scanNetworks(bool async, bool showHidden, bool passive, uint32_t maxMsPerChannel, uint8_t channel) { + if (_scanning) + return WIFI_SCAN_RUNNING; + scanDelete(); + + if (wifi_scan_networks(scanHandler, this) != RTW_SUCCESS) + return WIFI_SCAN_FAILED; + + _scanning = true; + + if (!async) { + xSemaphoreTake(_scanSem, 1); // reset the semaphore quickly + xSemaphoreTake(_scanSem, pdMS_TO_TICKS(maxMsPerChannel * 20)); + return _netCount; + } + return WIFI_SCAN_RUNNING; +} + +bool WiFiClass::getNetworkInfo( + uint8_t networkItem, String &ssid, WiFiAuthMode &encType, int32_t &rssi, uint8_t *&bssid, int32_t &channel +) { + ssid = SSID(networkItem); + encType = encryptionType(networkItem); + rssi = RSSI(networkItem); + bssid = BSSID(networkItem); + channel = this->channel(networkItem); +} + +int16_t WiFiClass::scanComplete() { + if (_scanning) + return WIFI_SCAN_RUNNING; + return _netCount; +} + +void WiFiClass::scanDelete() { + for (uint8_t i = 0; i < _netCount; i++) { + free(_netSsid[i]); + } + free(_netSsid); + free(_netEncr); + free(_netRssi); + free(_netBssid); + free(_netChannel); + _netCount = 0; + _netSsid = NULL; + _netEncr = NULL; + _netRssi = NULL; + _netBssid = NULL; + _netChannel = NULL; +} + +String WiFiClass::SSID(uint8_t networkItem) { + if (networkItem >= _netCount) + return ""; + return _netSsid[networkItem]; +} + +WiFiAuthMode WiFiClass::encryptionType(uint8_t networkItem) { + if (networkItem >= _netCount) + return WIFI_AUTH_INVALID; + return _netEncr[networkItem]; +} + +int32_t WiFiClass::RSSI(uint8_t networkItem) { + if (networkItem >= _netCount) + return 0; + return _netRssi[networkItem]; +} + +uint8_t *WiFiClass::BSSID(uint8_t networkItem) { + if (networkItem >= _netCount) + return NULL; + return _netBssid[networkItem].octet; +} + +String WiFiClass::BSSIDstr(uint8_t networkItem) { + return macToString(BSSID(networkItem)); +} + +int32_t WiFiClass::channel(uint8_t networkItem) { + if (networkItem >= _netCount) + return 0; + return _netChannel[networkItem]; +} diff --git a/builder/frameworks/realtek-ambz-arduino.py b/builder/frameworks/realtek-ambz-arduino.py index e31babb..5fb0f4c 100644 --- a/builder/frameworks/realtek-ambz-arduino.py +++ b/builder/frameworks/realtek-ambz-arduino.py @@ -130,7 +130,6 @@ sources_core = [ "+<" + CORE_DIR + "/cores/arduino/ssl_drv.cpp>", "+<" + CORE_DIR + "/cores/arduino/Tone.cpp>", "+<" + CORE_DIR + "/cores/arduino/WebSocketClient.cpp>", - "+<" + CORE_DIR + "/cores/arduino/wifi_drv.cpp>", "+<" + CORE_DIR + "/cores/arduino/WInterrupts.c>", "+<" + CORE_DIR + "/cores/arduino/wiring.c>", "+<" + CORE_DIR + "/cores/arduino/wiring_analog.c>", @@ -167,18 +166,18 @@ sources_core += [ sources_libs = [ # fmt: off "+<" + CORE_DIR +"/libraries/Flash/Flash.cpp>", - "+<" + CORE_DIR +"/libraries/WiFi/src/WiFi.cpp>", - "+<" + CORE_DIR +"/libraries/WiFi/src/WiFiClient.cpp>", - "+<" + CORE_DIR +"/libraries/WiFi/src/WiFiServer.cpp>", - "+<" + CORE_DIR +"/libraries/WiFi/src/WiFiSSLClient.cpp>", - "+<" + CORE_DIR +"/libraries/WiFi/src/WiFiUdp.cpp>", + "+<" + CORE_DIR +"/libraries/WiFi/WiFi.cpp>", + "+<" + CORE_DIR +"/libraries/WiFi/WiFiAP.cpp>", + "+<" + CORE_DIR +"/libraries/WiFi/WiFiGeneric.cpp>", + "+<" + CORE_DIR +"/libraries/WiFi/WiFiScan.cpp>", + "+<" + CORE_DIR +"/libraries/WiFi/WiFiSTA.cpp>", # fmt: on ] env.Append( CPPPATH=[ # fmt: off join(CORE_DIR, "libraries", "Flash"), - join(CORE_DIR, "libraries", "WiFi", "src"), + join(CORE_DIR, "libraries", "WiFi"), # fmt: on ], ) diff --git a/builder/frameworks/realtek-ambz-sdk.py b/builder/frameworks/realtek-ambz-sdk.py index 5965189..1646e23 100644 --- a/builder/frameworks/realtek-ambz-sdk.py +++ b/builder/frameworks/realtek-ambz-sdk.py @@ -70,6 +70,7 @@ env.Replace( "CONFIG_PLATFORM_8711B", ("F_CPU", "166000000L"), ("LWIP_TIMEVAL_PRIVATE", "0"), + ("LWIP_NETIF_HOSTNAME", "1"), ], LINKFLAGS=[ "-mcpu=cortex-m4",