diff --git a/inc/drivers/WIFI/Buffer.h b/inc/drivers/WIFI/Buffer.h index 1768504..dd65c24 100644 --- a/inc/drivers/WIFI/Buffer.h +++ b/inc/drivers/WIFI/Buffer.h @@ -3,39 +3,10 @@ #include #include -/** A templated software ring buffer - * - * Example: - * @code - * #include "Buffer.h" - * - * Buffer buf; - * - * int main() - * { - * buf = 'a'; - * buf.put('b'); - * char *head = buf.head(); - * puts(head); - * - * char whats_in_there[2] = {0}; - * int pos = 0; - * - * while(buf.available()) - * { - * whats_in_there[pos++] = buf; - * } - * printf("%c %c\n", whats_in_there[0], whats_in_there[1]); - * buf.clear(); - * error("done\n\n\n"); - * } - * @endcode - */ - template class Buffer { private: - T* _buffer; + T* buffer; volatile size_t writeLocation; volatile size_t readLocation; size_t size; @@ -76,9 +47,9 @@ class Buffer { void clear(void); /** Determine if anything is readable in the buffer - * @return 1 if something can be read, 0 otherwise + * @return true if something can be read, false otherwise */ - size_t available(void); + bool available(void); /** Overloaded operator for writing to the buffer * @param data Something to put in the buffer @@ -99,7 +70,8 @@ class Buffer { template void Buffer::put(T data) { - _buffer[writeLocation] = data; + buffer[writeLocation] = data; + ++writeLocation; writeLocation %= (this->size - 1); @@ -109,7 +81,8 @@ void Buffer::put(T data) template T Buffer::get(void) { - T data_pos = _buffer[readLocation]; + T data_pos = buffer[readLocation]; + ++readLocation; readLocation %= (this->size - 1); @@ -119,29 +92,29 @@ T Buffer::get(void) template T* Buffer::head(void) { - T* data_pos = &_buffer[0]; + T* data_pos = &buffer[0]; return data_pos; } template -size_t Buffer::available(void) +bool Buffer::available(void) { - return (writeLocation == readLocation) ? 0 : 1; + return (writeLocation != readLocation); } template Buffer::Buffer(size_t size) { - _buffer = new T[size]; - this->size = size; + this->buffer = new T[size]; + this->size = size; clear(); } template Buffer::~Buffer() { - delete[] _buffer; + delete[] this->buffer; } template @@ -157,7 +130,7 @@ size_t Buffer::getNbAvailable() return (writeLocation - readLocation); } else { - return (this->size - readLocation + writeLocation); + return (size - readLocation + writeLocation); } } @@ -166,7 +139,6 @@ void Buffer::clear(void) { writeLocation = 0; readLocation = 0; - memset(_buffer, 0, this->size); - return; + memset(buffer, 0, size); } \ No newline at end of file diff --git a/inc/drivers/WIFI/Wifi.h b/inc/drivers/WIFI/Wifi.h new file mode 100644 index 0000000..095bb9f --- /dev/null +++ b/inc/drivers/WIFI/Wifi.h @@ -0,0 +1,280 @@ +#include + +#include "CodalComponent.h" +#include "Ism43362Driver.h" +#include "ManagedString.h" + +#define WIFI_ISM43362_DEVICE_ID 2510 + +#define WIFI_ISM43362_DEFAULT_BUFFER_SIZE ES_WIFI_DATA_SIZE + +#define WIFI_ISM43362_EVT_DATA_RECEIVED 1 +#define WIFI_ISM43362_EVT_RX_FULL 2 + +#define WIFI_ISM43362_STATUS_RX_IN_USE 0x01 +#define WIFI_ISM43362_STATUS_TX_IN_USE 0x02 +#define WIFI_ISM43362_STATUS_RX_BUFF_INIT 0x04 +#define WIFI_ISM43362_STATUS_TX_BUFF_INIT 0x08 +#define WIFI_ISM43362_STATUS_RXD 0x10 + +namespace codal { + +class WiFiClient; + +class WiFi : public CodalComponent { + private: + Ism43362Driver ism43362; + uint8_t wifi_status; + + public: + /** + * @brief Contructor + * + */ + WiFi(codal::STM32SPI* spi, codal::STM32Pin* cs, codal::STM32Pin* commandDataReady, codal::STM32Pin* reset, + codal::STM32Pin* wakeup) + : CodalComponent(WIFI_ISM43362_DEVICE_ID, 0), + ism43362(spi, cs, commandDataReady, reset, wakeup), + wifi_status(WL_NO_SHIELD) + { + } + + /** + * @brief Contructor + * + */ + WiFi(Ism43362Driver& ism43362) + : CodalComponent(WIFI_ISM43362_DEVICE_ID, 0), ism43362(ism43362), wifi_status(WL_NO_SHIELD) + { + } + + virtual int init() override final + { + if (wifi_status == WL_NO_SHIELD) { + if (ism43362.ES_WIFI_Init() != ES_WIFI_STATUS_OK) { + wifi_status = WL_NO_SHIELD; + return DEVICE_INVALID_STATE; + } + else { + wifi_status = WL_IDLE_STATUS; + } + } + + return DEVICE_OK; + } + + /** + * @brief Destructor + * + */ + virtual ~WiFi() + { + if (isAttached()) { + detach(); + } + } + + /** + * @brief Get the number of networks visible. + * @param None + * @retval Number of discovered networks. The device can see 10 AP max. + */ + int networksVisible(); + + /** + * @brief Connect to the wifi network. + * @param ssid name of the network + * @param passphrase Passphrase. Valid characters in a passphrase + * must be between 32-126 chars. + * @retval none + */ + void attach(const ManagedString& ssid, const ManagedString& passphrase); + + /** + * @brief Check if we are connected to the wifi network. + * @param None + * @retval true if the device is connected to an AP + */ + bool isAttached(); + + /** + * @brief Disconnect from the wifi network. + * @param None + * @retval none + */ + void detach(); + + /** + * @brief Start a Client connection to a remote host + * @param hostname : name of the host to which to connect + * @param port : port to which to connect + * @retval A pointer to the client object connected to the remote host + */ + std::unique_ptr connect(const ManagedString& host, uint16_t port); + + /** + * @brief + * + */ + virtual void idleCallback() final override + { + if (this->status & WIFI_ISM43362_STATUS_RXD) { + Event(this->id, WIFI_ISM43362_EVT_DATA_RECEIVED); + this->status &= ~WIFI_ISM43362_STATUS_RXD; + } + } + + friend WiFiClient; +}; + +class WiFiClient { + private: + WiFi* wifi; + uint8_t sock; + bool connected; + uint16_t status; + + uint8_t* rxBuff; + uint8_t rxBuffSize; + volatile uint16_t rxBuffHead; + uint16_t rxBuffTail; + + public: + /** + * @brief Destroy the WiFiClient object + * + */ + ~WiFiClient() + { + if ((this->status & WIFI_ISM43362_STATUS_RX_BUFF_INIT) != 0) { + free(this->rxBuff); + } + } + + /** + * @brief Check if the connection is active with the remote host + * @param None + * @retval true if the client is connected to the remote host + */ + bool isConnected(); + + /** + * @brief Get connection state + * @param None + * @retval Socket state, FREE or BUSY + */ + uint8_t connectionState(); + + /** + * @brief Close the to the remote host connection + * @param None + * @retval None + */ + void disconnect(); + + /** + * Determines whether there is any data waiting in our reception buffer. + * + * @return 1 if we have space, 0 if we do not. + * + */ + int isReadable(); + + /** + * Determines if the socket is currently in use by another fiber for reception. + * + * @return The state of our mutex lock for reception. + * + */ + int rxInUse(); + + /** + * Locks the mutex so that others can't use this serial instance for reception + */ + void lockRx(); + + /** + * Unlocks the mutex so that others can use this serial instance for reception + */ + void unlockRx(); + + /** + * @brief Read up to size bytes from the current packet and place them into buffer + * @param buffer : Where to place read data + * @param size : length of data to read + * @retval Returns the number of bytes read, or 0 if none are available + */ + int read(char* buf, size_t size); + + /** + * @brief Read a single byte from the current packet + * @param None + * @retval the read byte + */ + char read(); + + /** + * @brief Write size bytes from buffer into the packet + * @param buf : data to write + * @param size : size of data to write + * @retval size of write data + */ + size_t write(const char* buf, size_t size); + + friend WiFi; + + private: + /** + * @brief Construct a WiFiClient object + * + */ + WiFiClient(WiFi* wifi) : wifi(wifi), sock(SOCK_NOT_AVAIL), connected(false), status(0) {} + + /** + * @brief Get the first socket number free. + * @param None + * @retval socket number or -1 if no available. + */ + uint8_t getFirstSocket(); + + /** + * @brief Start a TCP connection to the remote host + * @param ip : IP to which to send packets + * @param port : port to which to send packets + * @retval true if successful, false if there was a problem with the supplied IP address or port + */ + bool connect(IPAddress ip, uint16_t port); + + /** + * @brief Start a TCP connection to the remote host + * @param host : host to which to send the packet + * @param port : port to which to send the packet + * @retval true if successful, false if there was a problem with the supplied IP address or port + */ + bool connect(const ManagedString& host, uint16_t port); + + /** + * We do not want to always have our buffers initialised, especially if users to not + * use them. We only bring them up on demand. + */ + int initialiseReceptionBuffer() + { + if ((this->status & WIFI_ISM43362_STATUS_RX_BUFF_INIT) != 0) { + free(this->rxBuff); + } + + this->status &= ~WIFI_ISM43362_STATUS_RX_BUFF_INIT; + + if ((this->rxBuff = (uint8_t*)malloc(rxBuffSize)) == NULL) { + return DEVICE_NO_RESOURCES; + } + + this->rxBuffHead = 0; + this->rxBuffTail = 0; + + this->status |= WIFI_ISM43362_STATUS_RX_BUFF_INIT; + + return DEVICE_OK; + } +}; +} // namespace codal \ No newline at end of file diff --git a/samples/WIFI/HttpClient/WIFI_Http_Client_Sample.cpp b/samples/WIFI/HttpClient/WIFI_Http_Client_Sample.cpp index 4fbe6a2..88b8a43 100644 --- a/samples/WIFI/HttpClient/WIFI_Http_Client_Sample.cpp +++ b/samples/WIFI/HttpClient/WIFI_Http_Client_Sample.cpp @@ -1,6 +1,8 @@ -#include "WIFI_Http_Client_Sample.h" +#include #include "Ism43362Driver.h" +#include "WIFI_Buffer_Sample.h" +#include "Wifi.h" #include "ssd1306.h" codal::STM32Pin miso3(ID_PIN_WIFI_ISM43362_MISO, PinNumber::PC_11, codal::PIN_CAPABILITY_DIGITAL); @@ -16,11 +18,14 @@ codal::STM32Pin commandDataReadyPin(ID_PIN_WIFI_ISM43362_COMMAND_DATA_READY, Pin codal::PIN_CAPABILITY_DIGITAL); Ism43362Driver DrvWiFi(&spi3, &csPin, &commandDataReadyPin, &resetPin, &wakeUpPin); +codal::WiFi wifi(DrvWiFi); -const char* ssid = "SSID"; -const char* passphrase = "PASSWORD"; +const char* ssid = "NEDJAR"; +const char* passphrase = "Camevenere1!"; +const char* host = "google.com"; +const char* methodName = "GET"; -void Wifi_Http_Client_Sample_main(codal::STM32DISCO_L475VG_IOT& discoL475VgIot) +void Wifi_Buffer_Sample_main(codal::STM32DISCO_L475VG_IOT& discoL475VgIot) { discoL475VgIot.serial.init(115200); @@ -29,23 +34,35 @@ void Wifi_Http_Client_Sample_main(codal::STM32DISCO_L475VG_IOT& discoL475VgIot) printf("* Demonstration du wifi *\r\n"); printf("*******************************************\r\n"); - if (DrvWiFi.ES_WIFI_Init() != ES_WIFI_STATUS_OK) { + if (wifi.init() != DEVICE_OK) { printf("Init not Ok\r\n"); return; } + else + printf("Init Ok\r\n"); - printf("Init Ok\r\n"); + printf("Number of network : %d \r\n", wifi.networksVisible()); - printf("Begin scan network\r\n"); - DrvWiFi.ES_WIFI_ListAccessPoints(); - printf("End scan network\r\n"); + printf("Connection to %s \r\n", ssid); - printf("Number of network : %d\r\n", DrvWiFi.ES_WIFI_GetApNbr()); + wifi.attach(ssid, passphrase); - if (DrvWiFi.ES_WIFI_Connect(ssid, passphrase, ES_WIFI_SEC_WPA2) != ES_WIFI_STATUS_OK) { - printf("Connection to %s not Ok\r\n", ssid); - DrvWiFi.ES_WIFI_Disconnect(); + if (!wifi.isAttached()) { + printf("Not connected to %s \r\n", ssid); + wifi.detach(); return; } - printf("Connected to %s\r\n", ssid); + + printf("Connected to %s \r\n", ssid); + + auto client = wifi.connect(host, 80); + + if (client->isConnected()) { + auto req = "GET / HTTP/1.1\r\nHost: google.com\r\nConnection: Close\r\n\r\n"; + client->write(req, strlen(req)); + char buffer[2000]; + memset(buffer, 0, 2000); + client->read(buffer, 2000); + printf("Received : %s\r\n", buffer); + } } \ No newline at end of file diff --git a/source/drivers/WIFI/Buffer.cpp b/source/drivers/WIFI/Buffer.cpp index 3638a79..8760141 100644 --- a/source/drivers/WIFI/Buffer.cpp +++ b/source/drivers/WIFI/Buffer.cpp @@ -1,19 +1,3 @@ - -/** - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - #include "Buffer.h" // make the linker aware of some possible specialisation diff --git a/source/drivers/WIFI/Wifi.cpp b/source/drivers/WIFI/Wifi.cpp new file mode 100644 index 0000000..d16d5a2 --- /dev/null +++ b/source/drivers/WIFI/Wifi.cpp @@ -0,0 +1,183 @@ +#include "Wifi.h" + +#include + +int codal::WiFi::networksVisible() +{ + ism43362.ES_WIFI_ListAccessPoints(); + return ism43362.ES_WIFI_GetApNbr(); +} + +void codal::WiFi::attach(const ManagedString& ssid, const ManagedString& passphrase) +{ + ES_WIFI_Status_t attachStatus = + ism43362.ES_WIFI_Connect(ssid.toCharArray(), passphrase.toCharArray(), ES_WIFI_SEC_WPA_WPA2); + + if (attachStatus == ES_WIFI_STATUS_OK) { + wifi_status = WL_CONNECTED; + } + else { + ism43362.ES_WIFI_Disconnect(); + wifi_status = WL_CONNECT_FAILED; + } +} + +bool codal::WiFi::isAttached() +{ + return wifi_status == WL_CONNECTED; +} + +void codal::WiFi::detach() +{ + if (wifi_status != WL_NO_SHIELD) { + ism43362.ES_WIFI_Disconnect(); + wifi_status = WL_DISCONNECTED; + } +} + +std::unique_ptr codal::WiFi::connect(const ManagedString& host, uint16_t port) +{ + std::unique_ptr client(new WiFiClient(this)); + client->connect(host, port); + return client; +} + +uint8_t codal::WiFiClient::getFirstSocket() +{ + return wifi->ism43362.getFreeSocket(); +} + +uint8_t codal::WiFiClient::connectionState() +{ + if (sock == SOCK_NOT_AVAIL) { + return SOCKET_FREE; + } + else { + return wifi->ism43362.getSocketState(sock); + } +} + +bool codal::WiFiClient::isConnected() +{ + return connected; +} + +bool codal::WiFiClient::connect(IPAddress ip, uint16_t port) +{ + int8_t sock; + + if (this->sock == NO_SOCKET_AVAIL) { + sock = getFirstSocket(); // get next free socket + if (sock != -1) { + this->sock = sock; + } + } + + if (this->sock != NO_SOCKET_AVAIL) { + // set connection parameter and start client + wifi->ism43362.ES_WIFI_SetConnectionParam(this->sock, ES_WIFI_TCP_CONNECTION, port, ip); + wifi->ism43362.ES_WIFI_StartClientConnection(this->sock); + this->connected = true; + return true; + } + + return false; +} + +bool codal::WiFiClient::connect(const ManagedString& host, uint16_t port) +{ + IPAddress remoteHostAddress; + + wifi->ism43362.ES_WIFI_DNS_LookUp(host.toCharArray(), &remoteHostAddress); + + return connect(remoteHostAddress, port); +} + +void codal::WiFiClient::disconnect() +{ + if (this->sock == NO_SOCKET_AVAIL) { + return; + } + + wifi->ism43362.ES_WIFI_StopServerSingleConn(this->sock); + + this->sock = NO_SOCKET_AVAIL; + this->connected = false; +} + +/** + * @brief Read a single byte from the current packet + * @param None + * @retval the read byte + */ +char codal::WiFiClient::read() +{ + uint8_t receivedByte = '\0'; // data received + uint16_t receivedLength = 0; // number of data received + + wifi->ism43362.ES_WIFI_ReceiveData(this->sock, &receivedByte, 1, &receivedLength, WIFI_TIMEOUT); + + return receivedByte; +} + +int codal::WiFiClient::read(char* buf, size_t size) +{ + if (rxInUse()) return DEVICE_SERIAL_IN_USE; + + lockRx(); + + // lazy initialisation of our buffers + if (!(status & WIFI_ISM43362_STATUS_RX_BUFF_INIT)) { + int result = initialiseReceptionBuffer(); + + if (result != DEVICE_OK) return result; + } + + uint16_t receivedLength = 0; + + wifi->ism43362.ES_WIFI_ReceiveData(this->sock, (uint8_t*)buf, size, &receivedLength, WIFI_TIMEOUT); + + if (receivedLength < size) { + buf[receivedLength] = '\0'; + } + + unlockRx(); + + return receivedLength; +} + +size_t codal::WiFiClient::write(const char* buf, size_t size) +{ + uint16_t sentLength = 0; // number of data really send + uint8_t* temp = (uint8_t*)buf; + + wifi->ism43362.ES_WIFI_SendResp(this->sock, temp, size, &sentLength, WIFI_TIMEOUT); + + return sentLength; +} + +int codal::WiFiClient::isReadable() +{ + if (!(status & WIFI_ISM43362_STATUS_RX_BUFF_INIT)) { + int result = initialiseReceptionBuffer(); + + if (result != DEVICE_OK) return result; + } + + return (rxBuffTail != rxBuffHead) ? 1 : 0; +} + +int codal::WiFiClient::rxInUse() +{ + return (status & WIFI_ISM43362_STATUS_RX_IN_USE); +} + +void codal::WiFiClient::lockRx() +{ + status |= WIFI_ISM43362_STATUS_RX_IN_USE; +} + +void codal::WiFiClient::unlockRx() +{ + status &= ~WIFI_ISM43362_STATUS_RX_IN_USE; +} \ No newline at end of file