Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: DISCO_L475VG_IOT01-Sensors-BSP
Revision 0:766454e296c3, committed 2018-08-21
- Comitter:
- group-Farnell24-IOT-Team
- Date:
- Tue Aug 21 08:34:28 2018 +0000
- Commit message:
- Initial commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ATParser/ATParser.cpp Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,427 @@
+/* Copyright (c) 2015 ARM Limited
+ *
+ * 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.
+ *
+ * @section DESCRIPTION
+ *
+ * Parser for the AT command syntax
+ *
+ */
+
+#include "ATParser.h"
+#include "mbed_debug.h"
+
+#ifdef LF
+#undef LF
+#define LF 10
+#else
+#define LF 10
+#endif
+
+#ifdef CR
+#undef CR
+#define CR 13
+#else
+#define CR 13
+#endif
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#define dbg_on 0
+//#define TRACE_AT_DATA 1
+
+// getc/putc handling with timeouts
+int ATParser::putc(char c)
+{
+ return _serial_spi->putc(c);
+}
+
+int ATParser::getc()
+{
+ return _serial_spi->getc();
+}
+
+void ATParser::flush()
+{
+ _bufferMutex.lock();
+ while (_serial_spi->readable()) {
+ _serial_spi->getc();
+ }
+ _bufferMutex.unlock();
+}
+
+// read/write handling with timeouts
+int ATParser::write(const char *data, int size_of_data, int size_in_buff)
+{
+ int i = 0;
+ _bufferMutex.lock();
+ for ( ; i < size_of_data; i++) {
+ if (putc(data[i]) < 0) {
+ _bufferMutex.unlock();
+ return -1;
+ }
+ }
+
+ _serial_spi->buffsend(size_of_data + size_in_buff);
+ _bufferMutex.unlock();
+ return (size_of_data + size_in_buff);
+}
+
+int ATParser::read(char *data)
+{
+ int readsize;
+ int i = 0;
+
+ _bufferMutex.lock();
+
+ //this->flush();
+ if(!_serial_spi->readable()) {
+ readsize = _serial_spi->read();
+ } else {
+ error("Pending data when reading from WIFI\r\n");
+ return -1;
+ }
+
+ debug_if(dbg_on, "Avail in SPI %d\r\n", readsize);
+
+ if ( readsize < 0) {
+ _bufferMutex.unlock();
+ return -1;
+ }
+
+ for (i = 0 ; i < readsize; i++) {
+ int c = getc();
+ if (c < 0) {
+ _bufferMutex.unlock();
+ return -1;
+ }
+ data[i] = c;
+ }
+
+#if TRACE_AT_DATA
+ debug_if(dbg_on, "AT<< %d BYTES\r\n", readsize);
+ for (i = 0; i < readsize; i++) {
+ debug_if(dbg_on, "%2X ", data[i]);
+ }
+ debug_if(dbg_on, "\r\n");
+#endif
+
+ _bufferMutex.unlock();
+
+ return (readsize);
+}
+
+// printf/scanf handling
+int ATParser::vprintf(const char *format, va_list args)
+{
+ _bufferMutex.lock();
+ if (vsprintf(_buffer, format, args) < 0) {
+ _bufferMutex.unlock();
+ return false;
+ }
+
+ int i = 0;
+ for ( ; _buffer[i]; i++) {
+ if (putc(_buffer[i]) < 0) {
+ _bufferMutex.unlock();
+ return -1;
+ }
+ }
+ _bufferMutex.unlock();
+
+ return i;
+}
+
+int ATParser::vscanf(const char *format, va_list args)
+{
+ // Since format is const, we need to copy it into our buffer to
+ // add the line's null terminator and clobber value-matches with asterisks.
+ //
+ // We just use the beginning of the buffer to avoid unnecessary allocations.
+ int i = 0;
+ int offset = 0;
+
+ _bufferMutex.lock();
+
+ while (format[i]) {
+ if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') {
+ _buffer[offset++] = '%';
+ _buffer[offset++] = '*';
+ i++;
+ } else {
+ _buffer[offset++] = format[i++];
+ }
+ }
+
+ // Scanf has very poor support for catching errors
+ // fortunately, we can abuse the %n specifier to determine
+ // if the entire string was matched.
+ _buffer[offset++] = '%';
+ _buffer[offset++] = 'n';
+ _buffer[offset++] = 0;
+
+ // To workaround scanf's lack of error reporting, we actually
+ // make two passes. One checks the validity with the modified
+ // format string that only stores the matched characters (%n).
+ // The other reads in the actual matched values.
+ //
+ // We keep trying the match until we succeed or some other error
+ // derails us.
+ int j = 0;
+
+ while (true) {
+ // Ran out of space
+ if (j+1 >= _buffer_size - offset) {
+ _bufferMutex.unlock();
+ return false;
+ }
+ // Recieve next character
+ int c = getc();
+ if (c < 0) {
+ _bufferMutex.unlock();
+ return -1;
+ }
+ _buffer[offset + j++] = c;
+ _buffer[offset + j] = 0;
+
+ // Check for match
+ int count = -1;
+ sscanf(_buffer+offset, _buffer, &count);
+
+ // We only succeed if all characters in the response are matched
+ if (count == j) {
+ // Store the found results
+ vsscanf(_buffer+offset, format, args);
+ _bufferMutex.unlock();
+ return j;
+ }
+ }
+}
+
+
+// Command parsing with line handling
+bool ATParser::vsend(const char *command, va_list args)
+{
+ int i=0, j=0;
+ _bufferMutex.lock();
+ // Create and send command
+ if (vsprintf(_buffer, command, args) < 0) {
+ _bufferMutex.unlock();
+ return false;
+ }
+ /* get buffer length */
+ for (i = 0; _buffer[i]; i++) {
+ }
+
+ for (j=0; _delimiter[j]; j++) {
+ _buffer[i+j] = _delimiter[j];
+ }
+ _buffer[i+j]=0; // only to get a clean debug log
+
+ bool ret = !(_serial_spi->buffwrite(_buffer, i+j) < 0);
+
+ debug_if(dbg_on, "AT> %s\n", _buffer);
+ _bufferMutex.unlock();
+ return ret;
+}
+
+bool ATParser::vrecv(const char *response, va_list args)
+{
+ _bufferMutex.lock();
+ /* Read from the wifi module, fill _rxbuffer */
+ //this->flush();
+ if(!_serial_spi->readable()) {
+ debug_if(dbg_on, "NO DATA, read again\r\n");
+ if (_serial_spi->read() < 0) {
+ return false;
+ }
+ } else {
+ debug_if(dbg_on, "Pending data\r\n");
+ }
+restart:
+ _aborted = false;
+ // Iterate through each line in the expected response
+ while (response[0]) {
+ // Since response is const, we need to copy it into our buffer to
+ // add the line's null terminator and clobber value-matches with asterisks.
+ //
+ // We just use the beginning of the buffer to avoid unnecessary allocations.
+ int i = 0;
+ int offset = 0;
+ bool whole_line_wanted = false;
+
+ while (response[i]) {
+ if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') {
+ _buffer[offset++] = '%';
+ _buffer[offset++] = '*';
+ i++;
+ } else {
+ _buffer[offset++] = response[i++];
+ // Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification
+ if (response[i - 1] == '\n' && !(i >= 3 && response[i-3] == '[' && response[i-2] == '^')) {
+ whole_line_wanted = true;
+ break;
+ }
+ }
+ }
+
+ // Scanf has very poor support for catching errors
+ // fortunately, we can abuse the %n specifier to determine
+ // if the entire string was matched.
+ _buffer[offset++] = '%';
+ _buffer[offset++] = 'n';
+ _buffer[offset++] = 0;
+
+ debug_if(dbg_on, "AT? ====%s====\n", _buffer);
+ // To workaround scanf's lack of error reporting, we actually
+ // make two passes. One checks the validity with the modified
+ // format string that only stores the matched characters (%n).
+ // The other reads in the actual matched values.
+ //
+ // We keep trying the match until we succeed or some other error
+ // derails us.
+ int j = 0;
+
+ while (true) {
+ // Recieve next character
+ int c = getc();
+ if (c < 0) {
+ debug_if(dbg_on, "AT(Timeout)\n");
+ _bufferMutex.unlock();
+ return false;
+ }
+
+#if TRACE_AT_DATA
+ debug_if(dbg_on, "%2X ", c);
+#endif
+ _buffer[offset + j++] = c;
+ _buffer[offset + j] = 0;
+
+ // Check for oob data
+ for (struct oob *oob = _oobs; oob; oob = oob->next) {
+ if ((unsigned)j == oob->len && memcmp(
+ oob->prefix, _buffer+offset, oob->len) == 0) {
+ debug_if(dbg_on, "AT! %s\n", oob->prefix);
+ oob->cb();
+
+ if (_aborted) {
+ debug_if(dbg_on, "AT(Aborted)\n");
+ _bufferMutex.unlock();
+ return false;
+ }
+ // oob may have corrupted non-reentrant buffer,
+ // so we need to set it up again
+ goto restart;
+ }
+ }
+
+ // Check for match
+ int count = -1;
+ if (whole_line_wanted && c != '\n' && c != ' ') {
+ // Don't attempt scanning until we get delimiter if they included it in format
+ // This allows recv("Foo: %s\n") to work, and not match with just the first character of a string
+ // (scanf does not itself match whitespace in its format string, so \n is not significant to it)
+ } else {
+ sscanf(_buffer+offset, _buffer, &count);
+ }
+
+ // We only succeed if all characters in the response are matched
+ if (count == j) {
+ debug_if(dbg_on, "AT= ====%s====\n", _buffer + offset);
+ // Reuse the front end of the buffer
+ memcpy(_buffer, response, i);
+ _buffer[i] = 0;
+
+ // Store the found results
+ vsscanf(_buffer+offset, _buffer, args);
+
+ // Jump to next line and continue parsing
+ response += i;
+ break;
+ }
+
+ // Clear the buffer when we hit a newline or ran out of space
+ // running out of space usually means we ran into binary data
+ if ((c == '\n') ) {
+ debug_if(dbg_on, "New line AT<<< %s", _buffer+offset);
+ j = 0;
+ }
+ if ((j + 1 >= (_buffer_size - offset))) {
+
+ debug_if(dbg_on, "Out of space AT<<< %s, j=%d", _buffer+offset, j);
+ j = 0;
+ }
+ }
+ }
+
+ _bufferMutex.unlock();
+
+ return true;
+}
+
+
+// Mapping to vararg functions
+int ATParser::printf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ int res = vprintf(format, args);
+ va_end(args);
+ return res;
+}
+
+int ATParser::scanf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ int res = vscanf(format, args);
+ va_end(args);
+ return res;
+}
+
+bool ATParser::send(const char *command, ...)
+{
+ va_list args;
+ va_start(args, command);
+ bool res = vsend(command, args);
+ va_end(args);
+ return res;
+}
+
+bool ATParser::recv(const char *response, ...)
+{
+ va_list args;
+ va_start(args, response);
+ bool res = vrecv(response, args);
+ va_end(args);
+ return res;
+}
+
+
+// oob registration
+void ATParser::oob(const char *prefix, Callback<void()> cb)
+{
+ struct oob *oob = new struct oob;
+ oob->len = strlen(prefix);
+ oob->prefix = prefix;
+ oob->cb = cb;
+ oob->next = _oobs;
+ _oobs = oob;
+}
+
+void ATParser::abort()
+{
+ _aborted = true;
+}
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ATParser/ATParser.h Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,264 @@
+/* Copyright (c) 2015 ARM Limited
+ *
+ * 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.
+ *
+ * @section DESCRIPTION
+ *
+ * Parser for the AT command syntax
+ *
+ */
+#ifndef AT_PARSER_H
+#define AT_PARSER_H
+
+#include "mbed.h"
+#include <cstdarg>
+#include <vector>
+#include "BufferedSpi.h"
+#include "Callback.h"
+
+
+/**
+* Parser class for parsing AT commands
+*
+* Here are some examples:
+* @code
+* ATParser at = ATParser(serial, "\r\n");
+* int value;
+* char buffer[100];
+*
+* at.send("AT") && at.recv("OK");
+* at.send("AT+CWMODE=%d", 3) && at.recv("OK");
+* at.send("AT+CWMODE?") && at.recv("+CWMODE:%d\r\nOK", &value);
+* at.recv("+IPD,%d:", &value);
+* at.read(buffer, value);
+* at.recv("OK");
+* @endcode
+*/
+class ATParser
+{
+private:
+ // Serial information
+ BufferedSpi *_serial_spi;
+ int _buffer_size;
+ char *_buffer;
+ Mutex _bufferMutex;
+ volatile int _timeout;
+
+ // Parsing information
+ const char *_delimiter;
+ int _delim_size;
+ char _in_prev;
+ bool dbg_on;
+ volatile bool _aborted;
+
+ struct oob {
+ unsigned len;
+ const char *prefix;
+ mbed::Callback<void()> cb;
+ oob *next;
+ };
+ oob *_oobs;
+
+public:
+ /**
+ * Constructor
+ *
+ * @param serial spi interface to use for AT commands
+ * @param buffer_size size of internal buffer for transaction
+ * @param timeout timeout of the connection
+ * @param delimiter string of characters to use as line delimiters
+ */
+ ATParser(BufferedSpi &serial_spi, const char *delimiter = "\r\n", int buffer_size = 1440, int timeout = 8000, bool debug = false) :
+ _serial_spi(&serial_spi),
+ _buffer_size(buffer_size), _in_prev(0), _oobs(NULL)
+ {
+ _buffer = new char[buffer_size];
+ setTimeout(timeout);
+ setDelimiter(delimiter);
+ debugOn(debug);
+ }
+
+ /**
+ * Destructor
+ */
+ ~ATParser()
+ {
+ while (_oobs) {
+ struct oob *oob = _oobs;
+ _oobs = oob->next;
+ delete oob;
+ }
+ delete[] _buffer;
+ }
+
+ /**
+ * Allows timeout to be changed between commands
+ *
+ * @param timeout timeout of the connection
+ */
+ void setTimeout(int timeout)
+ {
+ _timeout = timeout;
+ _serial_spi->setTimeout(timeout);
+ }
+
+ /**
+ * Sets string of characters to use as line delimiters
+ *
+ * @param delimiter string of characters to use as line delimiters
+ */
+ void setDelimiter(const char *delimiter) {
+ _delimiter = delimiter;
+ _delim_size = strlen(delimiter);
+ }
+
+ /**
+ * Allows echo to be on or off
+ *
+ * @param echo 1 for echo and 0 turns it off
+ */
+ void debugOn(uint8_t on) {
+ dbg_on = (on) ? 1 : 0;
+ }
+
+ /**
+ * Sends an AT command
+ *
+ * Sends a formatted command using printf style formatting
+ * @see printf
+ *
+ * @param command printf-like format string of command to send which
+ * is appended with a newline
+ * @param ... all printf-like arguments to insert into command
+ * @return true only if command is successfully sent
+ */
+ bool send(const char *command, ...);
+
+ bool vsend(const char *command, va_list args);
+
+ /**
+ * Receive an AT response
+ *
+ * Receives a formatted response using scanf style formatting
+ * @see scanf
+ *
+ * Responses are parsed line at a time.
+ * Any received data that does not match the response is ignored until
+ * a timeout occurs.
+ *
+ * @param response scanf-like format string of response to expect
+ * @param ... all scanf-like arguments to extract from response
+ * @return true only if response is successfully matched
+ */
+ bool recv(const char *response, ...);
+ bool vrecv(const char *response, va_list args);
+
+
+ /**
+ * Write a single byte to the underlying stream
+ *
+ * @param c The byte to write
+ * @return The byte that was written or -1 during a timeout
+ */
+ int putc(char c);
+
+ /**
+ * Get a single byte from the underlying stream
+ *
+ * @return The byte that was read or -1 during a timeout
+ */
+ int getc();
+
+ /**
+ * Write an array of bytes to the underlying stream
+ * assuming the header of the command is already in _txbuffer
+ *
+ * @param data the array of bytes to write
+ * @param size_of_data number of bytes in data array
+ * @param size_in_buff number of bytes already in the internal buff
+ * @return number of bytes written or -1 on failure
+ */
+ int write(const char *data, int size_of_data, int size_in_buff);
+
+ /**
+ * Read an array of bytes from the underlying stream
+ *
+ * @param data the destination for the read bytes
+ * @param size number of bytes to read
+ * @return number of bytes read or -1 on failure
+ */
+ int read(char *data);
+
+ /**
+ * Direct printf to underlying stream
+ * @see printf
+ *
+ * @param format format string to pass to printf
+ * @param ... arguments to printf
+ * @return number of bytes written or -1 on failure
+ */
+ int printf(const char *format, ...);
+ int vprintf(const char *format, va_list args);
+
+ /**
+ * Direct scanf on underlying stream
+ * @see ::scanf
+ *
+ * @param format format string to pass to scanf
+ * @param ... arguments to scanf
+ * @return number of bytes read or -1 on failure
+ */
+ int scanf(const char *format, ...);
+
+ int vscanf(const char *format, va_list args);
+
+ /**
+ * Attach a callback for out-of-band data
+ *
+ * @param prefix string on when to initiate callback
+ * @param func callback to call when string is read
+ * @note out-of-band data is only processed during a scanf call
+ */
+ void oob(const char *prefix, mbed::Callback<void()> func);
+
+ /**
+ * Flushes the underlying stream
+ */
+ void flush();
+
+ /**
+ * Abort current recv
+ *
+ * Can be called from oob handler to interrupt the current
+ * recv operation.
+ */
+ void abort();
+
+ /**
+ * Process out-of-band data
+ *
+ * Process out-of-band data in the receive buffer. This function
+ * returns immediately if there is no data to process.
+ *
+ * @return true if oob data processed, false otherwise
+ */
+ bool process_oob(void);
+ /**
+ * Get buffer_size
+ */
+ int get_size(void) {
+ return _buffer_size;
+ }
+
+};
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.cpp Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,83 @@
+
+/**
+ * @file Buffer.cpp
+ * @brief Software Buffer - Templated Ring Buffer for most data types
+ * @author sam grove
+ * @version 1.0
+ * @see
+ *
+ * Copyright (c) 2013
+ *
+ * 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 "MyBuffer.h"
+
+template <class T>
+MyBuffer<T>::MyBuffer(uint32_t size)
+{
+ _buf = new T [size];
+ _size = size;
+ clear();
+
+ return;
+}
+
+template <class T>
+MyBuffer<T>::~MyBuffer()
+{
+ delete [] _buf;
+
+ return;
+}
+
+template <class T>
+uint32_t MyBuffer<T>::getSize()
+{
+ return this->_size;
+}
+
+template <class T>
+ uint32_t MyBuffer<T>::getNbAvailable()
+{
+ if ( _wloc >= _rloc) return (_wloc - _rloc);
+ else return (_size - _rloc + _wloc);
+}
+
+template <class T>
+void MyBuffer<T>::clear(void)
+{
+ _wloc = 0;
+ _rloc = 0;
+ memset(_buf, 0, _size);
+
+ return;
+}
+
+template <class T>
+uint32_t MyBuffer<T>::peek(char c)
+{
+ return 1;
+}
+
+// make the linker aware of some possible types
+template class MyBuffer<uint8_t>;
+template class MyBuffer<int8_t>;
+template class MyBuffer<uint16_t>;
+template class MyBuffer<int16_t>;
+template class MyBuffer<uint32_t>;
+template class MyBuffer<int32_t>;
+template class MyBuffer<uint64_t>;
+template class MyBuffer<int64_t>;
+template class MyBuffer<char>;
+template class MyBuffer<wchar_t>;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.h Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,165 @@
+
+/**
+ * @file Buffer.h
+ * @brief Software Buffer - Templated Ring Buffer for most data types
+ * @author sam grove
+ * @version 1.0
+ * @see
+ *
+ * Copyright (c) 2013
+ *
+ * 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.
+ */
+
+#ifndef MYBUFFER_H
+#define MYBUFFER_H
+
+#include <stdint.h>
+#include <string.h>
+
+/** A templated software ring buffer
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "MyBuffer.h"
+ *
+ * MyBuffer <char> 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 <typename T>
+class MyBuffer
+{
+private:
+ T *_buf;
+ volatile uint32_t _wloc;
+ volatile uint32_t _rloc;
+ uint32_t _size;
+
+public:
+ /** Create a Buffer and allocate memory for it
+ * @param size The size of the buffer
+ */
+ MyBuffer(uint32_t size = 0x100);
+
+ /** Get the size of the ring buffer
+ * @return the size of the ring buffer
+ */
+ uint32_t getSize();
+ uint32_t getNbAvailable();
+
+ /** Destry a Buffer and release it's allocated memory
+ */
+ ~MyBuffer();
+
+ /** Add a data element into the buffer
+ * @param data Something to add to the buffer
+ */
+ void put(T data);
+
+ /** Remove a data element from the buffer
+ * @return Pull the oldest element from the buffer
+ */
+ T get(void);
+
+ /** Get the address to the head of the buffer
+ * @return The address of element 0 in the buffer
+ */
+ T *head(void);
+
+ /** Reset the buffer to 0. Useful if using head() to parse packeted data
+ */
+ void clear(void);
+
+ /** Determine if anything is readable in the buffer
+ * @return 1 if something can be read, 0 otherwise
+ */
+ uint32_t available(void);
+
+ /** Overloaded operator for writing to the buffer
+ * @param data Something to put in the buffer
+ * @return
+ */
+ MyBuffer &operator= (T data)
+ {
+ put(data);
+ return *this;
+ }
+
+ /** Overloaded operator for reading from the buffer
+ * @return Pull the oldest element from the buffer
+ */
+ operator int(void)
+ {
+ return get();
+ }
+
+ uint32_t peek(char c);
+
+};
+
+template <class T>
+inline void MyBuffer<T>::put(T data)
+{
+ _buf[_wloc++] = data;
+ _wloc %= (_size-1);
+
+ return;
+}
+
+template <class T>
+inline T MyBuffer<T>::get(void)
+{
+ T data_pos = _buf[_rloc++];
+ _rloc %= (_size-1);
+
+ return data_pos;
+}
+
+template <class T>
+inline T *MyBuffer<T>::head(void)
+{
+ T *data_pos = &_buf[0];
+
+ return data_pos;
+}
+
+template <class T>
+inline uint32_t MyBuffer<T>::available(void)
+{
+ return (_wloc == _rloc) ? 0 : 1;
+ //return 1;
+}
+
+#endif
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ATParser/BufferedSpi/BufferedPrint.c Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ * 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 <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mbed_error.h"
+
+size_t BufferedSpiThunk(void *buf_serial, const void *s, size_t length);
+
+int BufferedPrintfC(void *stream, int size, const char* format, va_list arg)
+{
+ int r;
+ char buffer[512];
+ if (size >= 512) {
+ return -1;
+ }
+ memset(buffer, 0, size);
+ r = vsprintf(buffer, format, arg);
+ // this may not hit the heap but should alert the user anyways
+ if(r > (int32_t) size) {
+ error("%s %d buffer overwrite (max_buf_size: %d exceeded: %d)!\r\n", __FILE__, __LINE__, size, r);
+ return 0;
+ }
+ if ( r > 0 ) {
+ BufferedSpiThunk(stream, buffer, r);
+ }
+ return r;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ATParser/BufferedSpi/BufferedSpi.cpp Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,326 @@
+/**
+ * @file BufferedSpi.cpp
+ * @brief Software Buffer - Extends mbed SPI functionallity
+ * @author Armelle Duboc
+ * @version 1.0
+ * @see
+ *
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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 "BufferedSpi.h"
+#include <stdarg.h>
+#include "mbed_debug.h"
+#include "mbed_error.h"
+
+// change to true to add few SPI debug lines
+#define local_debug false
+
+extern "C" int BufferedPrintfC(void *stream, int size, const char* format, va_list arg);
+
+void BufferedSpi::DatareadyRising(void)
+{
+ if (_cmddata_rdy_rising_event == 1) {
+ _cmddata_rdy_rising_event=0;
+ }
+}
+
+int BufferedSpi::wait_cmddata_rdy_high(void)
+{
+ Timer timer;
+ timer.start();
+
+ /* wait for dataready = 1 */
+ while(dataready.read() == 0) {
+ if (timer.read_ms() > _timeout) {
+ debug_if(local_debug,"ERROR: SPI write timeout\r\n");
+ return -1;
+ }
+ }
+
+ _cmddata_rdy_rising_event = 1;
+
+ return 0;
+}
+
+int BufferedSpi::wait_cmddata_rdy_rising_event(void)
+{
+ Timer timer;
+ timer.start();
+
+ while (_cmddata_rdy_rising_event == 1) {
+ if (timer.read_ms() > _timeout) {
+ _cmddata_rdy_rising_event = 0;
+ if (dataready.read() == 1) {
+ debug_if(local_debug,"ERROR: We missed rising event !! (timemout=%d)\r\n", _timeout);
+ }
+ debug_if(local_debug,"ERROR: SPI read timeout\r\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+BufferedSpi::BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName _nss, PinName _datareadypin,
+ uint32_t buf_size, uint32_t tx_multiple, const char* name)
+ : SPI(mosi, miso, sclk, NC), nss(_nss), _txbuf((uint32_t)(tx_multiple*buf_size)), _rxbuf(buf_size), dataready(_datareadypin)
+{
+ this->_buf_size = buf_size;
+ this->_tx_multiple = tx_multiple;
+ this->_sigio_event = 0;
+
+ _datareadyInt = new InterruptIn(_datareadypin);
+ _datareadyInt->rise(callback(this, &BufferedSpi::DatareadyRising));
+
+ _cmddata_rdy_rising_event = 1;
+
+ return;
+}
+
+BufferedSpi::~BufferedSpi(void)
+{
+
+ return;
+}
+
+void BufferedSpi::frequency(int hz)
+{
+ SPI::frequency(hz);
+}
+
+void BufferedSpi::format(int bits, int mode)
+{
+ SPI::format(bits, mode);
+}
+
+void BufferedSpi::disable_nss()
+{
+ nss = 1;
+ wait_us(15);
+}
+
+void BufferedSpi::enable_nss()
+{
+ nss = 0;
+ wait_us(15);
+}
+
+int BufferedSpi::readable(void)
+{
+ return _rxbuf.available(); // note: look if things are in the buffer
+}
+
+int BufferedSpi::writeable(void)
+{
+ return 1; // buffer allows overwriting by design, always true
+}
+
+int BufferedSpi::getc(void)
+{
+ if (_rxbuf.available())
+ return _rxbuf;
+ else return -1;
+}
+
+int BufferedSpi::putc(int c)
+{
+ _txbuf = (char)c;
+
+ return c;
+}
+
+void BufferedSpi::flush_txbuf(void)
+{
+ _txbuf.clear();
+}
+
+int BufferedSpi::puts(const char *s)
+{
+ if (s != NULL) {
+ const char* ptr = s;
+
+ while(*(ptr) != 0) {
+ _txbuf = *(ptr++);
+ }
+ _txbuf = '\n'; // done per puts definition
+ BufferedSpi::txIrq(); // only write to hardware in one place
+ return (ptr - s) + 1;
+ }
+ return 0;
+}
+
+extern "C" size_t BufferedSpiThunk(void *buf_spi, const void *s, size_t length)
+{
+ BufferedSpi *buffered_spi = (BufferedSpi *)buf_spi;
+ return buffered_spi->buffwrite(s, length);
+}
+
+int BufferedSpi::printf(const char* format, ...)
+{
+ va_list arg;
+ va_start(arg, format);
+ int r = BufferedPrintfC((void*)this, this->_buf_size, format, arg);
+ va_end(arg);
+ return r;
+}
+
+ssize_t BufferedSpi::buffwrite(const void *s, size_t length)
+{
+ /* flush buffer from previous message */
+ this->flush_txbuf();
+
+ if (wait_cmddata_rdy_high() < 0) {
+ debug_if(local_debug, "BufferedSpi::buffwrite timeout (%d)\r\n", _timeout);
+ return -1;
+ }
+
+ this->enable_nss();
+
+ if (s != NULL && length > 0) {
+ /* 1st fill _txbuf */
+ const char* ptr = (const char*)s;
+ const char* end = ptr + length;
+
+ while (ptr != end) {
+ _txbuf = *(ptr++);
+ }
+ if (length&1) { /* padding to send the last char */
+ _txbuf = '\n';
+ length++;
+ }
+
+ /* 2nd write in SPI */
+ BufferedSpi::txIrq(); // only write to hardware in one place
+
+ this->disable_nss();
+ return ptr - (const char*)s;
+ }
+ this->disable_nss();
+
+ return 0;
+}
+
+ssize_t BufferedSpi::buffsend(size_t length)
+{
+ /* wait for dataready = 1 */
+ if (wait_cmddata_rdy_high() < 0) {
+ debug_if(local_debug, "BufferedSpi::buffsend timeout (%d)\r\n", _timeout);
+ return -1;
+ }
+
+ this->enable_nss();
+
+ /* _txbuffer is already filled with data to send */
+ /* check if _txbuffer needs padding to send the last char */
+ if (length & 1) {
+ _txbuf = '\n';
+ length++;
+ }
+ BufferedSpi::txIrq(); // only write to hardware in one place
+
+ this->disable_nss();
+
+ return length;
+}
+
+ssize_t BufferedSpi::read()
+{
+ return this->read(0);
+}
+
+ssize_t BufferedSpi::read(uint32_t max)
+{
+ uint32_t len = 0;
+ int tmp;
+
+ disable_nss();
+
+ /* wait for data ready is up */
+ if(wait_cmddata_rdy_rising_event() != 0) {
+ debug_if(local_debug, "BufferedSpi::read timeout (%d)\r\n", _timeout);
+ return -1;
+ }
+
+ enable_nss();
+ while (dataready.read() == 1 && (len < (_buf_size - 1))) {
+ tmp = SPI::write(0xAA); // dummy write to receive 2 bytes
+
+ if (!((len == 0) && (tmp == 0x0A0D))) {
+ /* do not take into account the 2 firts \r \n char in the buffer */
+ if ((max == 0) || (len < max)) {
+ _rxbuf = (char)(tmp & 0x00FF);
+ _rxbuf = (char)((tmp >>8)& 0xFF);
+ len += 2;
+ }
+ }
+ }
+ disable_nss();
+
+ if (len >= _buf_size) {
+ debug_if(local_debug, "firmware ERROR ES_WIFI_ERROR_STUFFING_FOREVER\r\n");
+ return -1;
+ }
+
+ debug_if(local_debug, "SPI READ %d BYTES\r\n", len);
+
+ return len;
+}
+
+void BufferedSpi::txIrq(void)
+{ /* write everything available in the _txbuffer */
+ int value = 0;
+ int dbg_cnt = 0;
+ while (_txbuf.available() && (_txbuf.getNbAvailable()>0)) {
+ value = _txbuf.get();
+ if (_txbuf.available() && ((_txbuf.getNbAvailable()%2)!=0)) {
+ value |= ((_txbuf.get()<<8)&0XFF00);
+ SPI::write(value);
+ dbg_cnt++;
+ }
+ }
+ debug_if(local_debug, "SPI Sent %d BYTES\r\n", 2*dbg_cnt);
+ // disable the TX interrupt when there is nothing left to send
+ BufferedSpi::attach(NULL, BufferedSpi::TxIrq);
+ // trigger callback if necessary
+ if (_cbs[TxIrq]) {
+ _cbs[TxIrq]();
+ }
+ return;
+}
+
+void BufferedSpi::prime(void)
+{
+ BufferedSpi::txIrq(); // only write to hardware in one place
+ return;
+}
+
+void BufferedSpi::attach(Callback<void()> func, IrqType type)
+{
+ _cbs[type] = func;
+}
+
+void BufferedSpi::sigio(Callback<void()> func) {
+ core_util_critical_section_enter();
+ _sigio_cb = func;
+ if (_sigio_cb) {
+ if (_sigio_event == 1) {
+ _sigio_cb();
+ _sigio_event = 0;
+ }
+ }
+ core_util_critical_section_exit();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ATParser/BufferedSpi/BufferedSpi.h Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,235 @@
+
+/**
+ * @file BufferedSpi.h
+ * @brief Software Buffer - Extends mbed SPI functionallity
+ * @author Armelle Duboc
+ * @version 1.0
+ * @see
+ *
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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.
+ */
+
+#ifndef BUFFEREDSPI_H
+#define BUFFEREDSPI_H
+
+#include "mbed.h"
+#include "MyBuffer.h"
+
+/** A spi port (SPI) for communication with wifi device
+ *
+ * Can be used for Full Duplex communication, or Simplex by specifying
+ * one pin as NC (Not Connected)
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "BufferedSerial.h"
+ *
+ * BufferedSerial pc(USBTX, USBRX);
+ *
+ * int main()
+ * {
+ * while(1)
+ * {
+ * Timer s;
+ *
+ * s.start();
+ * pc.printf("Hello World - buffered\n");
+ * int buffered_time = s.read_us();
+ * wait(0.1f); // give time for the buffer to empty
+ *
+ * s.reset();
+ * printf("Hello World - blocking\n");
+ * int polled_time = s.read_us();
+ * s.stop();
+ * wait(0.1f); // give time for the buffer to empty
+ *
+ * pc.printf("printf buffered took %d us\n", buffered_time);
+ * pc.printf("printf blocking took %d us\n", polled_time);
+ * wait(0.5f);
+ * }
+ * }
+ * @endcode
+ */
+
+/**
+ * @class BufferedSpi
+ * @brief Software buffers and interrupt driven tx and rx for Serial
+ */
+class BufferedSpi : public SPI
+{
+private:
+ DigitalOut nss;
+ MyBuffer <char> _txbuf;
+ uint32_t _buf_size;
+ uint32_t _tx_multiple;
+ volatile int _timeout;
+ void txIrq(void);
+ void prime(void);
+
+ InterruptIn* _datareadyInt;
+ volatile int _cmddata_rdy_rising_event;
+ void DatareadyRising(void);
+ int wait_cmddata_rdy_rising_event(void);
+ int wait_cmddata_rdy_high(void);
+
+
+ Callback<void()> _cbs[2];
+
+ Callback<void()> _sigio_cb;
+ uint8_t _sigio_event;
+
+public:
+ MyBuffer <char> _rxbuf;
+ DigitalIn dataready;
+ enum IrqType {
+ RxIrq = 0,
+ TxIrq,
+
+ IrqCnt
+ };
+
+ /** Create a BufferedSpi Port, connected to the specified transmit and receive pins
+ * @param SPI mosi pin
+ * @param SPI miso pin
+ * @param SPI sclk pin
+ * @param SPI nss pin
+ * @param Dataready pin
+ * @param buf_size printf() buffer size
+ * @param tx_multiple amount of max printf() present in the internal ring buffer at one time
+ * @param name optional name
+ */
+ BufferedSpi(PinName mosi, PinName miso, PinName sclk, PinName nss, PinName datareadypin, uint32_t buf_size = 1480, uint32_t tx_multiple = 4,const char* name=NULL);
+
+ /** Destroy a BufferedSpi Port
+ */
+ virtual ~BufferedSpi(void);
+
+ /** call to SPI frequency Function
+ */
+ virtual void frequency(int hz);
+
+ /** clear the transmit buffer
+ */
+ virtual void flush_txbuf(void);
+
+ /** call to SPI format function
+ */
+ virtual void format(int bits, int mode);
+
+ virtual void enable_nss(void);
+
+ virtual void disable_nss(void);
+
+ /** Check on how many bytes are in the rx buffer
+ * @return 1 if something exists, 0 otherwise
+ */
+ virtual int readable(void);
+
+ /** Check to see if the tx buffer has room
+ * @return 1 always has room and can overwrite previous content if too small / slow
+ */
+ virtual int writeable(void);
+
+ /** Get a single byte from the BufferedSpi Port.
+ * Should check readable() before calling this.
+ * @return A byte that came in on the SPI Port
+ */
+ virtual int getc(void);
+
+ /** Write a single byte to the BufferedSpi Port.
+ * @param c The byte to write to the SPI Port
+ * @return The byte that was written to the SPI Port Buffer
+ */
+ virtual int putc(int c);
+
+ /** Write a string to the BufferedSpi Port. Must be NULL terminated
+ * @param s The string to write to the Spi Port
+ * @return The number of bytes written to the Spi Port Buffer
+ */
+ virtual int puts(const char *s);
+
+ /** Write a formatted string to the BufferedSpi Port.
+ * @param format The string + format specifiers to write to the Spi Port
+ * @return The number of bytes written to the Spi Port Buffer
+ */
+ virtual int printf(const char* format, ...);
+
+ /** Write data to the Buffered Spi Port
+ * @param s A pointer to data to send
+ * @param length The amount of data being pointed to
+ * @return The number of bytes written to the Spi Port Buffer
+ */
+ virtual ssize_t buffwrite(const void *s, std::size_t length);
+
+ /** Send datas to the Spi port that are already present
+ * in the internal _txbuffer
+ * @param length
+ * @return the number of bytes written on the SPI port
+ */
+ virtual ssize_t buffsend(size_t length);
+
+ /** Read data from the Spi Port to the _rxbuf
+ * @param max: optional. = max sieze of the input read
+ * @return The number of bytes read from the SPI port and written to the _rxbuf
+ */
+ virtual ssize_t read();
+ virtual ssize_t read(uint32_t max);
+
+ /**
+ * Allows timeout to be changed between commands
+ *
+ * @param timeout timeout of the connection
+ */
+ void setTimeout(int timeout)
+ {
+ /* this is a safe guard timeout in case module is stuck
+ * so take 5 sec margin compared to module timeout, to
+ * really only detect case where module is stuck */
+ _timeout = timeout + 5000;
+ }
+
+ /** Register a callback once any data is ready for sockets
+ * @param func Function to call on state change
+ */
+ virtual void sigio(Callback<void()> func);
+
+ /** Attach a function to call whenever a serial interrupt is generated
+ * @param func A pointer to a void function, or 0 to set as none
+ * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty)
+ */
+ virtual void attach(Callback<void()> func, IrqType type=RxIrq);
+
+ /** Attach a member function to call whenever a serial interrupt is generated
+ * @param obj pointer to the object to call the member function on
+ * @param method pointer to the member function to call
+ * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty)
+ */
+ template <typename T>
+ void attach(T *obj, void (T::*method)(), IrqType type=RxIrq) {
+ attach(Callback<void()>(obj, method), type);
+ }
+
+ /** Attach a member function to call whenever a serial interrupt is generated
+ * @param obj pointer to the object to call the member function on
+ * @param method pointer to the member function to call
+ * @param type Which serial interrupt to attach the member function to (Serial::RxIrq for receive, TxIrq for transmit buffer empty)
+ */
+ template <typename T>
+ void attach(T *obj, void (*method)(T*), IrqType type=RxIrq) {
+ attach(Callback<void()>(obj, method), type);
+ }
+};
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ISM43362.cpp Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,647 @@
+/* ISM43362 Example
+*
+* Copyright (c) STMicroelectronics 2017
+ *
+ * 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 <string.h>
+#include "ISM43362.h"
+#include "mbed_debug.h"
+
+// ao activate / de-activate debug
+#define ism_debug false
+
+ISM43362::ISM43362(PinName mosi, PinName miso, PinName sclk, PinName nss, PinName resetpin, PinName datareadypin, PinName wakeup, bool debug)
+ : _bufferspi(mosi, miso, sclk, nss, datareadypin), _parser(_bufferspi), _resetpin(resetpin),
+ _packets(0), _packets_end(&_packets)
+{
+ DigitalOut wakeup_pin(wakeup);
+ ISM43362::setTimeout((uint32_t)5000);
+ _bufferspi.format(16, 0); /* 16bits, ploarity low, phase 1Edge, master mode */
+ _bufferspi.frequency(20000000); /* up to 20 MHz */
+ _active_id = 0xFF;
+
+ reset();
+
+ _parser.debugOn(debug);
+}
+
+/**
+ * @brief Parses and returns number from string.
+ * @param ptr: pointer to string
+ * @param cnt: pointer to the number of parsed digit
+ * @retval integer value.
+ */
+#define CHARISHEXNUM(x) (((x) >= '0' && (x) <= '9') || \
+ ((x) >= 'a' && (x) <= 'f') || \
+ ((x) >= 'A' && (x) <= 'F'))
+#define CHARISNUM(x) ((x) >= '0' && (x) <= '9')
+#define CHAR2NUM(x) ((x) - '0')
+
+
+extern "C" int32_t ParseNumber(char* ptr, uint8_t* cnt)
+{
+ uint8_t minus = 0, i = 0;
+ int32_t sum = 0;
+
+ if (*ptr == '-') { /* Check for minus character */
+ minus = 1;
+ ptr++;
+ i++;
+ }
+ while (CHARISNUM(*ptr) || (*ptr=='.')) { /* Parse number */
+ if (*ptr == '.') {
+ ptr++; // next char
+ } else {
+ sum = 10 * sum + CHAR2NUM(*ptr);
+ ptr++;
+ i++;
+ }
+ }
+
+ if (cnt != NULL) { /* Save number of characters used for number */
+ *cnt = i;
+ }
+ if (minus) { /* Minus detected */
+ return 0 - sum;
+ }
+ return sum; /* Return number */
+}
+
+const char *ISM43362::get_firmware_version(void)
+{
+ char tmp_buffer[250];
+ char *ptr, *ptr2;
+
+ if(!(_parser.send("I?") && _parser.recv("%s\r\n", tmp_buffer) && check_response())) {
+ debug_if(ism_debug, "get_firmware_version is FAIL\r\n");
+ return 0;
+ }
+
+ // Get the first version in the string
+ ptr = strtok((char *)tmp_buffer, ",");
+ ptr = strtok(NULL, ",");
+ ptr2 = strtok(NULL, ",");
+ if (ptr == NULL) {
+ debug_if(ism_debug, "get_firmware_version decoding is FAIL\r\n");
+ return 0;
+ }
+ strncpy(_fw_version, ptr , ptr2-ptr);
+
+ debug_if(ism_debug, "get_firmware_version = [%s]\r\n", _fw_version);
+
+ return _fw_version;
+}
+
+bool ISM43362::reset(void)
+{
+ debug_if(ism_debug,"Reset Module\r\n");
+ _resetpin = 0;
+ wait_ms(10);
+ _resetpin = 1;
+ wait_ms(500);
+
+ /* Wait for prompt line */
+ if (!_parser.recv("> \r\n")) {
+ debug_if(ism_debug,"Reset Module failed\r\n");
+ return false;
+ }
+
+ return true;
+}
+
+void ISM43362::print_rx_buff(void) {
+ char tmp[150] = {0};
+ uint16_t i = 0;
+ while(i < 150) {
+ int c = _parser.getc();
+ if (c < 0)
+ break;
+ tmp[i] = c;
+ debug_if(ism_debug," 0x%2X",c);
+ i++;
+ }
+ debug_if(ism_debug,"Buffer content =====%s=====\r\n",tmp);
+}
+
+/* checks the standard OK response of the WIFI module, shouldbe:
+ * \r\nDATA\r\nOK\r\n>sp
+ * or
+ * \r\nERROR\r\nUSAGE\r\n>sp
+ * function returns true if OK, false otherwise. In case of error,
+ * print error content then flush buffer */
+bool ISM43362::check_response(void)
+{
+ if(!_parser.recv("OK\r\n")) {
+ print_rx_buff();
+ _parser.flush();
+ return false;
+ }
+
+ /* Then we should get "> ", but sometimes it seems it's missing,
+ * let's make it optional */
+ if(!_parser.recv("> \r\n")) {
+ debug_if(ism_debug, "Missing prompt in WIFI resp\r\n");
+ print_rx_buff();
+ _parser.flush();
+ return false;
+ }
+
+ /* Inventek module do stuffing / padding of data with 0x15,
+ * in case buffer containes such */
+ while(1) {
+ int c = _parser.getc();
+ if ( c == 0x15) {
+ continue;
+ } else {
+ /* How to put it back if needed ? */
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool ISM43362::dhcp(bool enabled)
+{
+ return (_parser.send("C4=%d", enabled ? 1:0) && check_response());
+}
+
+bool ISM43362::connect(const char *ap, const char *passPhrase)
+{
+ if (!(_parser.send("C1=%s", ap) && check_response())) {
+ return false;
+ }
+
+ if (!(_parser.send("C2=%s", passPhrase) && check_response())) {
+ return false;
+ }
+ /* TODO security level = 3 , is it hardcoded or not ???? */
+ if (!(_parser.send("C3=3") && check_response())) {
+ return false;
+ }
+ /* now connect */
+ /* connect response contains more data that we don't need now,
+ * So we only look for OK, the flush the end of it */
+ if (!(_parser.send("C0") && check_response())) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ISM43362::disconnect(void)
+{
+ return (_parser.send("CD") && check_response());
+}
+
+const char *ISM43362::getIPAddress(void)
+{
+ char tmp_ip_buffer[250];
+ char *ptr, *ptr2;
+
+ if(!(_parser.send("C?")
+ && _parser.recv("%s\r\n", tmp_ip_buffer) && check_response())) {
+ debug_if(ism_debug,"getIPAddress LINE KO: %s", tmp_ip_buffer);
+ return 0;
+ }
+
+ /* Get the IP address in the result */
+ /* TODO : check if the begining of the string is always = "eS-WiFi_AP_C47F51011231," */
+ ptr = strtok((char *)tmp_ip_buffer, ",");
+ ptr = strtok(NULL, ",");
+ ptr = strtok(NULL, ",");
+ ptr = strtok(NULL, ",");
+ ptr = strtok(NULL, ",");
+ ptr = strtok(NULL, ",");
+ ptr2 = strtok(NULL, ",");
+ if (ptr == NULL) return 0;
+ strncpy(_ip_buffer, ptr , ptr2-ptr);
+
+ tmp_ip_buffer[59] = 0;
+ debug_if(ism_debug,"receivedIPAddress: %s\n", _ip_buffer);
+
+ return _ip_buffer;
+}
+
+const char *ISM43362::getMACAddress(void)
+{
+ if(!(_parser.send("Z5") && _parser.recv("%s\r\n", _mac_buffer) && check_response())) {
+ debug_if(ism_debug,"receivedMacAddress LINE KO: %s", _mac_buffer);
+ return 0;
+ }
+
+ debug_if(ism_debug,"receivedMacAddress:%s, size=%d\r\n", _mac_buffer, sizeof(_mac_buffer));
+
+ return _mac_buffer;
+}
+
+const char *ISM43362::getGateway()
+{
+ char tmp[250];
+
+ if(!(_parser.send("C?") && _parser.recv("%s\r\n", tmp) && check_response())) {
+ debug_if(ism_debug,"getGateway LINE KO: %s\r\n", tmp);
+ return 0;
+ }
+
+ /* Extract the Gateway in the received buffer */
+ char *ptr;
+ ptr = strtok(tmp,",");
+ for (int i = 0; i< 7;i++) {
+ if (ptr == NULL) break;
+ ptr = strtok(NULL,",");
+ }
+
+ strncpy(_gateway_buffer, ptr, sizeof(_gateway_buffer));
+
+ debug_if(ism_debug,"getGateway: %s\r\n", _gateway_buffer);
+
+ return _gateway_buffer;
+}
+
+const char *ISM43362::getNetmask()
+{
+ char tmp[250];
+
+ if(!(_parser.send("C?") && _parser.recv("%s\r\n", tmp) && check_response())) {
+ debug_if(ism_debug,"getNetmask LINE KO: %s", tmp);
+ return 0;
+ }
+
+ /* Extract Netmask in the received buffer */
+ char *ptr;
+ ptr = strtok(tmp,",");
+ for (int i = 0; i< 6;i++) {
+ if (ptr == NULL) break;
+ ptr = strtok(NULL,",");
+ }
+
+ strncpy(_netmask_buffer, ptr, sizeof(_netmask_buffer));
+
+ debug_if(ism_debug,"getNetmask: %s\r\n", _netmask_buffer);
+
+ return _netmask_buffer;
+}
+
+int8_t ISM43362::getRSSI()
+{
+ int8_t rssi;
+ char tmp[25];
+
+ if(!(_parser.send("CR") && _parser.recv("%s\r\n", tmp) && check_response())) {
+ debug_if(ism_debug,"getRSSI LINE KO: %s\r\n", tmp);
+ return 0;
+ }
+
+ rssi = ParseNumber(tmp, NULL);
+
+ debug_if(ism_debug,"getRSSI: %d\r\n", rssi);
+
+ return rssi;
+}
+/**
+ * @brief Parses Security type.
+ * @param ptr: pointer to string
+ * @retval Encryption type.
+ */
+extern "C" nsapi_security_t ParseSecurity(char* ptr)
+{
+ if(strstr(ptr,"Open")) return NSAPI_SECURITY_NONE;
+ else if(strstr(ptr,"WEP")) return NSAPI_SECURITY_WEP;
+ else if(strstr(ptr,"WPA")) return NSAPI_SECURITY_WPA;
+ else if(strstr(ptr,"WPA2 AES")) return NSAPI_SECURITY_WPA2;
+ else if(strstr(ptr,"WPA WPA2")) return NSAPI_SECURITY_WPA_WPA2;
+ else if(strstr(ptr,"WPA2 TKIP")) return NSAPI_SECURITY_UNKNOWN; // ?? no match in mbed ?
+ else return NSAPI_SECURITY_UNKNOWN;
+}
+
+/**
+ * @brief Convert char in Hex format to integer.
+ * @param a: character to convert
+ * @retval integer value.
+ */
+extern "C" uint8_t Hex2Num(char a)
+{
+ if (a >= '0' && a <= '9') { /* Char is num */
+ return a - '0';
+ } else if (a >= 'a' && a <= 'f') { /* Char is lowercase character A - Z (hex) */
+ return (a - 'a') + 10;
+ } else if (a >= 'A' && a <= 'F') { /* Char is uppercase character A - Z (hex) */
+ return (a - 'A') + 10;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Extract a hex number from a string.
+ * @param ptr: pointer to string
+ * @param cnt: pointer to the number of parsed digit
+ * @retval Hex value.
+ */
+extern "C" uint32_t ParseHexNumber(char* ptr, uint8_t* cnt)
+{
+ uint32_t sum = 0;
+ uint8_t i = 0;
+
+ while (CHARISHEXNUM(*ptr)) { /* Parse number */
+ sum <<= 4;
+ sum += Hex2Num(*ptr);
+ ptr++;
+ i++;
+ }
+
+ if (cnt != NULL) { /* Save number of characters used for number */
+ *cnt = i;
+ }
+ return sum; /* Return number */
+}
+
+bool ISM43362::isConnected(void)
+{
+ return getIPAddress() != 0;
+}
+
+int ISM43362::scan(WiFiAccessPoint *res, unsigned limit)
+{
+ unsigned cnt = 0, num=0;
+ char *ptr;
+ char tmp[256];
+
+ if(!(_parser.send("F0"))) {
+ debug_if(ism_debug,"scan error\r\n");
+ return 0;
+ }
+
+ /* Parse the received buffer and fill AP buffer */
+ while (_parser.recv("#%s\n", tmp)) {
+ if (limit != 0 && cnt >= limit) {
+ /* reached end */
+ break;
+ }
+ nsapi_wifi_ap_t ap = {0};
+ debug_if(ism_debug,"received:%s", tmp);
+ ptr = strtok(tmp, ",");
+ num = 0;
+ while (ptr != NULL) {
+ switch (num++) {
+ case 0: /* Ignore index */
+ case 4: /* Ignore Max Rate */
+ case 5: /* Ignore Network Type */
+ case 7: /* Ignore Radio Band */
+ break;
+ case 1:
+ ptr[strlen(ptr) - 1] = 0;
+ strncpy((char *)ap.ssid, ptr+ 1, 32);
+ break;
+ case 2:
+ for (int i=0; i<6; i++) {
+ ap.bssid[i] = ParseHexNumber(ptr + (i*3), NULL);
+ }
+ break;
+ case 3:
+ ap.rssi = ParseNumber(ptr, NULL);
+ break;
+ case 6:
+ ap.security = ParseSecurity(ptr);
+ break;
+ case 8:
+ ap.channel = ParseNumber(ptr, NULL);
+ num = 1;
+ break;
+ default:
+ break;
+ }
+ ptr = strtok(NULL, ",");
+ }
+ res[cnt] = WiFiAccessPoint(ap);
+ cnt++;
+ }
+
+ /* We may stop before having read all the APs list, so flush the rest of
+ * it as well as OK commands */
+ _parser.flush();
+
+ debug_if(ism_debug, "End of Scan: cnt=%d\n", cnt);
+
+ return cnt;
+
+}
+
+bool ISM43362::open(const char *type, int id, const char* addr, int port)
+{ /* TODO : This is the implementation for the client socket, need to check if need to create openserver too */
+ //IDs only 0-3
+ if((id < 0) ||(id > 3)) {
+ debug_if(ism_debug, "open: wrong id\n");
+ return false;
+ }
+ /* Set communication socket */
+ debug_if(ism_debug, "OPEN socket\n");
+ _active_id = id;
+ if (!(_parser.send("P0=%d", id) && check_response())) {
+ return false;
+ }
+ /* Set protocol */
+ if (!(_parser.send("P1=%s", type) && check_response())) {
+ return false;
+ }
+ /* Set address */
+ if (!(_parser.send("P3=%s", addr) && check_response())) {
+ return false;
+ }
+ if (!(_parser.send("P4=%d", port) && check_response())) {
+ return false;
+ }
+ /* Start client */
+ if (!(_parser.send("P6=1") && check_response())) {
+ return false;
+ }
+
+ /* request as much data as possible - i.e. module max size */
+ if (!(_parser.send("R1=%d", ES_WIFI_MAX_RX_PACKET_SIZE)&& check_response())) {
+ return -1;
+ }
+
+ return true;
+}
+
+bool ISM43362::dns_lookup(const char* name, char* ip)
+{
+ char tmp[30];
+
+ if (!(_parser.send("D0=%s", name) && _parser.recv("%s\r\n", tmp)
+ && check_response())) {
+ debug_if(ism_debug,"dns_lookup LINE KO: %s", tmp);
+ return 0;
+ }
+
+ strncpy(ip, tmp, sizeof(tmp));
+
+ debug_if(ism_debug, "ip of DNSlookup: %s\n", ip);
+ return 1;
+}
+
+bool ISM43362::send(int id, const void *data, uint32_t amount)
+{
+ // The Size limit has to be checked on caller side.
+ if (amount > ES_WIFI_MAX_RX_PACKET_SIZE) {
+ return false;
+ }
+
+ /* Activate the socket id in the wifi module */
+ if ((id < 0) ||(id > 3)) {
+ return false;
+ }
+ debug_if(ism_debug, "SEND socket amount %d\n", amount);
+ if (_active_id != id) {
+ _active_id = id;
+ if (!(_parser.send("P0=%d",id) && check_response())) {
+ return false;
+ }
+ }
+
+ /* Change the write timeout */
+ if (!(_parser.send("S2=%d", _timeout) && check_response())) {
+ return false;
+ }
+ /* set Write Transport Packet Size */
+ int i = _parser.printf("S3=%d\r", (int)amount);
+ if (i < 0) {
+ return false;
+ }
+ i = _parser.write((const char *)data, amount, i);
+ if (i < 0) {
+ return false;
+ }
+
+ if (!check_response()) {
+ return false;
+ }
+
+ return true;
+}
+
+int ISM43362::check_recv_status(int id, void *data)
+{
+ int read_amount;
+ static int keep_to = 0;
+
+ debug_if(ism_debug, "ISM43362 req check_recv_status\r\n");
+ /* Activate the socket id in the wifi module */
+ if ((id < 0) ||(id > 3)) {
+ return -1;
+ }
+
+ if (_active_id != id) {
+ _active_id = id;
+ if (!(_parser.send("P0=%d",id) && check_response())) {
+ return -1;
+ }
+ }
+
+
+ /* MBED wifi driver is meant to be non-blocking, but we need anyway to
+ * wait for some data on the RECV side to avoid overflow on TX side, the
+ * tiemout is defined in higher layer */
+ if (keep_to != _timeout) {
+ if (!(_parser.send("R2=%d", _timeout) && check_response())) {
+ return -1;
+ }
+ keep_to = _timeout;
+ }
+
+ if (!_parser.send("R0")) {
+ return -1;
+ }
+ read_amount = _parser.read((char *)data);
+
+ if(read_amount < 0) {
+ debug_if(ism_debug, "ERROR in data RECV, timeout?\r\n");
+ return -1; /* nothing to read */
+ }
+
+ /* If there are spurious 0x15 at the end of the data, this is an error
+ * we hall can get rid off of them :-(
+ * This should not happen, but let's try to clean-up anyway
+ */
+ char *cleanup = (char *) data;
+ while ((read_amount > 0) && (cleanup[read_amount-1] == 0x15)) {
+ debug_if(ism_debug, "ISM4336 spurious 0X15 trashed\r\n");
+ /* Remove the trailling char then search again */
+ read_amount--;
+ }
+
+ if ((read_amount >= 6) && (strncmp("OK\r\n> ", (char *)data, 6) == 0)) {
+ debug_if(ism_debug, "ISM4336 recv 2 nothing to read=%d\r\n", read_amount);
+ return 0; /* nothing to read */
+ } else if ((read_amount >= 8) && (strncmp((char *)((uint32_t) data + read_amount - 8), "\r\nOK\r\n> ", 8)) == 0) {
+ /* bypass ""\r\nOK\r\n> " if present at the end of the chain */
+ read_amount -= 8;
+ } else {
+ debug_if(ism_debug, "ERROR in data RECV?, flushing %d bytes\r\n", read_amount);
+ int i = 0;
+ for (i = 0; i < read_amount; i++) {
+ debug_if(ism_debug, "%2X ", cleanup[i]);
+ }
+ cleanup[i] = 0;
+ debug_if(ism_debug, "\r\n%s\r\n", cleanup);
+ return -1; /* nothing to read */
+ }
+
+ debug_if(ism_debug, "ISM43362 read_amount=%d\r\n", read_amount);
+ return read_amount;
+}
+
+bool ISM43362::close(int id)
+{
+ if ((id <0) || (id > 3)) {
+ debug_if(ism_debug,"Wrong socket number\n");
+ return false;
+ }
+ /* Set connection on this socket */
+ debug_if(ism_debug,"CLOSE socket id=%d\n", id);
+ _active_id = id;
+ if (!(_parser.send("P0=%d", id) && check_response())) {
+ return false;
+ }
+ /* close this socket */
+ if (!(_parser.send("P6=0") && check_response())) {
+ return false;
+ }
+ return true;
+}
+
+void ISM43362::setTimeout(uint32_t timeout_ms)
+{
+ _timeout = timeout_ms;
+ _parser.setTimeout(timeout_ms);
+}
+
+bool ISM43362::readable()
+{
+ /* not applicable with SPI api */
+ return true;
+}
+
+bool ISM43362::writeable()
+{
+ /* not applicable with SPI api */
+ return true;
+}
+
+void ISM43362::attach(Callback<void()> func)
+{
+ /* not applicable with SPI api */
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362/ISM43362.h Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,246 @@
+/* ISM43362Interface Example
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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.
+ */
+
+#ifndef ISM43362_H
+#define ISM43362_H
+#include "ATParser.h"
+
+#define ES_WIFI_MAX_SSID_NAME_SIZE 32
+#define ES_WIFI_MAX_PSWD_NAME_SIZE 32
+#define ES_WIFI_PRODUCT_ID_SIZE 32
+#define ES_WIFI_PRODUCT_NAME_SIZE 32
+#define ES_WIFI_FW_REV_SIZE 16
+#define ES_WIFI_API_REV_SIZE 16
+#define ES_WIFI_STACK_REV_SIZE 16
+#define ES_WIFI_RTOS_REV_SIZE 16
+
+// The input range for AT Command 'R1' is 0 to 1200 bytes
+// R1 Set Read Transport Packet Size (bytes)
+#define ES_WIFI_MAX_RX_PACKET_SIZE 1200
+// Module maxume DATA payload for Tx packet is 1460
+#define ES_WIFI_MAX_TX_PACKET_SIZE 1460
+
+/** ISM43362Interface class.
+ This is an interface to a ISM43362 radio.
+ */
+class ISM43362
+{
+public:
+ ISM43362(PinName mosi, PinName miso, PinName clk, PinName nss, PinName resetpin, PinName datareadypin, PinName wakeup, bool debug=false);
+
+ /**
+ * Check firmware version of ISM43362
+ *
+ * @return null-terminated fw version or null if no version is read
+ */
+ const char *get_firmware_version(void);
+
+ /**
+ * Reset ISM43362
+ *
+ * @return true only if ISM43362 resets successfully
+ */
+ bool reset(void);
+
+ /**
+ * Enable/Disable DHCP
+ *
+ * @param enabled DHCP enabled when true
+ * @return true only if ISM43362 enables/disables DHCP successfully
+ */
+ bool dhcp(bool enabled);
+
+ /**
+ * Connect ISM43362 to AP
+ *
+ * @param ap the name of the AP
+ * @param passPhrase the password of AP
+ * @return true only if ISM43362 is connected successfully
+ */
+ bool connect(const char *ap, const char *passPhrase);
+
+ /**
+ * Disconnect ISM43362 from AP
+ *
+ * @return true only if ISM43362 is disconnected successfully
+ */
+ bool disconnect(void);
+
+ /**
+ * Get the IP address of ISM43362
+ *
+ * @return null-teriminated IP address or null if no IP address is assigned
+ */
+ const char *getIPAddress(void);
+
+ /**
+ * Get the MAC address of ISM43362
+ *
+ * @return null-terminated MAC address or null if no MAC address is assigned
+ */
+ const char *getMACAddress(void);
+
+ /** Get the local gateway
+ *
+ * @return Null-terminated representation of the local gateway
+ * or null if no network mask has been recieved
+ */
+ const char *getGateway();
+
+ /** Get the local network mask
+ *
+ * @return Null-terminated representation of the local network mask
+ * or null if no network mask has been recieved
+ */
+ const char *getNetmask();
+
+ /* Return RSSI for active connection
+ *
+ * @return Measured RSSI
+ */
+ int8_t getRSSI();
+
+ /**
+ * Check if ISM43362 is conenected
+ *
+ * @return true only if the chip has an IP address
+ */
+ bool isConnected(void);
+
+ /** Scan for available networks
+ *
+ * @param ap Pointer to allocated array to store discovered AP
+ * @param limit Size of allocated @a res array, or 0 to only count available AP
+ * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error
+ * see @a nsapi_error
+ */
+ int scan(WiFiAccessPoint *res, unsigned limit);
+
+ /**Perform a dns query
+ *
+ * @param name Hostname to resolve
+ * @param ip Buffer to store IP address
+ * @return 0 true on success, false on failure
+ */
+ bool dns_lookup(const char *name, char *ip);
+
+ /**
+ * Open a socketed connection
+ *
+ * @param type the type of socket to open "UDP" or "TCP"
+ * @param id id to give the new socket, valid 0-4
+ * @param port port to open connection with
+ * @param addr the IP address of the destination
+ * @return true only if socket opened successfully
+ */
+ bool open(const char *type, int id, const char* addr, int port);
+
+ /**
+ * Sends data to an open socket
+ *
+ * @param id id of socket to send to
+ * @param data data to be sent
+ * @param amount amount of data to be sent - max 1024
+ * @return true only if data sent successfully
+ */
+ bool send(int id, const void *data, uint32_t amount);
+
+ /**
+ * Receives data from an open socket
+ *
+ * @param id id to receive from
+ * @param data placeholder for returned information
+ * @param amount number of bytes to be received
+ * @return the number of bytes received
+ */
+ int32_t recv(int id, void *data, uint32_t amount);
+
+ /**
+ * Closes a socket
+ *
+ * @param id id of socket to close, valid only 0-4
+ * @return true only if socket is closed successfully
+ */
+ bool close(int id);
+
+ /**
+ * Allows timeout to be changed between commands
+ *
+ * @param timeout_ms timeout of the connection
+ */
+ void setTimeout(uint32_t timeout_ms);
+
+ /**
+ * Checks if data is available
+ */
+ bool readable();
+
+ /**
+ * Checks if data can be written
+ */
+ bool writeable();
+
+ /**
+ * Attach a function to call whenever network state has changed
+ *
+ * @param func A pointer to a void function, or 0 to set as none
+ */
+ void attach(Callback<void()> func);
+
+ /**
+ * Check is datas are available to read for a socket
+ * @param id socket id
+ * @param data placeholder for returned information
+ * @param amount size to read for the check
+ * @return amount of read value, or -1 for errors
+ */
+ int check_recv_status(int id, void *data);
+
+ /**
+ * Attach a function to call whenever network state has changed
+ *
+ * @param obj pointer to the object to call the member function on
+ * @param method pointer to the member function to call
+ */
+ template <typename T, typename M>
+ void attach(T *obj, M method) {
+ attach(Callback<void()>(obj, method));
+ }
+
+private:
+ BufferedSpi _bufferspi;
+ ATParser _parser;
+ DigitalOut _resetpin;
+ volatile int _timeout;
+ volatile int _active_id;
+ void print_rx_buff(void);
+ bool check_response(void);
+ struct packet {
+ struct packet *next;
+ int id;
+ uint32_t len;
+ // data follows
+ } *_packets, **_packets_end;
+ void _packet_handler();
+
+ char _ip_buffer[16];
+ char _gateway_buffer[16];
+ char _netmask_buffer[16];
+ char _mac_buffer[18];
+ char _fw_version[16];
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362Interface.cpp Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,505 @@
+/* ISM43362 implementation of NetworkInterfaceAPI
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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 <string.h>
+#include "ISM43362Interface.h"
+#include "mbed_debug.h"
+
+// ao activate / de-activate debug
+#define ism_debug false
+
+// Various timeouts for different ISM43362 operations
+#define ISM43362_CONNECT_TIMEOUT 15000 /* milliseconds */
+#define ISM43362_SEND_TIMEOUT 1000 /* milliseconds */
+#define ISM43362_RECV_TIMEOUT 100 /* milliseconds */
+#define ISM43362_MISC_TIMEOUT 100 /* milliseconds */
+
+// Tested firmware versions
+// Example of versions string returned by the module:
+// "ISM43362-M3G-L44-SPI,C3.5.2.3.BETA9,v3.5.2,v1.4.0.rc1,v8.2.1,120000000,Inventek eS-WiFi"
+// "ISM43362-M3G-L44-SPI,C3.5.2.2,v3.5.2,v1.4.0.rc1,v8.2.1,120000000,Inventek eS-WiFi"
+// Only the first version is checked !
+const char supported_fw_versions[2][15] = {"C3.5.2.3.BETA9", "C3.5.2.2"};
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+// ISM43362Interface implementation
+ISM43362Interface::ISM43362Interface(PinName mosi, PinName miso, PinName sclk, PinName nss, PinName reset, PinName datareadypin, PinName wakeup, bool debug)
+ : _ism(mosi, miso, sclk, nss, reset, datareadypin, wakeup, debug)
+{
+ memset(_ids, 0, sizeof(_ids));
+ memset(_socket_obj, 0, sizeof(_socket_obj));
+ memset(_cbs, 0, sizeof(_cbs));
+ thread_read_socket.start(callback(this, &ISM43362Interface::socket_check_read));
+}
+
+int ISM43362Interface::connect(const char *ssid, const char *pass, nsapi_security_t security,
+ uint8_t channel)
+{
+ if (channel != 0) {
+ return NSAPI_ERROR_UNSUPPORTED;
+ }
+
+ set_credentials(ssid, pass, security);
+ return connect();
+}
+
+int ISM43362Interface::connect()
+{
+ _mutex.lock();
+ const char* read_version;
+
+ _ism.setTimeout(ISM43362_MISC_TIMEOUT);
+
+ // Check all supported firmware versions
+ read_version = _ism.get_firmware_version();
+
+ if (!read_version) {
+ debug_if(ism_debug, "ISM43362: ERROR cannot read firmware version\r\n");
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+ debug_if(ism_debug, "ISM43362: read_version = [%s]\r\n", read_version);
+
+ if ((strcmp(read_version, supported_fw_versions[0]) == 0) || (strcmp(read_version, supported_fw_versions[1]) == 0)) {
+ debug_if(ism_debug, "ISM43362: firmware version is OK\r\n");
+ } else {
+ debug_if(ism_debug, "ISM43362: WARNING this firmware version has not been tested !\r\n");
+ }
+
+ if (!_ism.dhcp(true)) {
+ return NSAPI_ERROR_DHCP_FAILURE;
+ }
+
+ _ism.setTimeout(ISM43362_CONNECT_TIMEOUT);
+
+ if (!_ism.connect(ap_ssid, ap_pass)) {
+ return NSAPI_ERROR_NO_CONNECTION;
+ }
+
+ _ism.setTimeout(ISM43362_MISC_TIMEOUT);
+ if (!_ism.getIPAddress()) {
+ return NSAPI_ERROR_DHCP_FAILURE;
+ }
+
+ _ism.setTimeout(ISM43362_MISC_TIMEOUT);
+ _mutex.unlock();
+
+ return NSAPI_ERROR_OK;
+}
+
+nsapi_error_t ISM43362Interface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
+{
+ _mutex.lock();
+ if (address->set_ip_address(name)) {
+ if (version != NSAPI_UNSPEC && address->get_ip_version() != version) {
+ return NSAPI_ERROR_DNS_FAILURE;
+ }
+
+ return NSAPI_ERROR_OK;
+ }
+
+ char *ipbuff = new char[NSAPI_IP_SIZE];
+ int ret = 0;
+ _ism.setTimeout(ISM43362_CONNECT_TIMEOUT);
+ if(!_ism.dns_lookup(name, ipbuff)) {
+ ret = NSAPI_ERROR_DEVICE_ERROR;
+ } else {
+ address->set_ip_address(ipbuff);
+ }
+ _mutex.unlock();
+
+ delete[] ipbuff;
+
+ return ret;
+}
+
+int ISM43362Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security)
+{
+ _mutex.lock();
+
+ memset(ap_ssid, 0, sizeof(ap_ssid));
+ strncpy(ap_ssid, ssid, sizeof(ap_ssid));
+
+ memset(ap_pass, 0, sizeof(ap_pass));
+ strncpy(ap_pass, pass, sizeof(ap_pass));
+
+ ap_sec = security;
+ _mutex.unlock();
+
+ return 0;
+}
+
+int ISM43362Interface::set_channel(uint8_t channel)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ISM43362Interface::disconnect()
+{
+ _mutex.lock();
+
+ _ism.setTimeout(ISM43362_MISC_TIMEOUT);
+
+ if (!_ism.disconnect()) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ _mutex.unlock();
+
+ return NSAPI_ERROR_OK;
+}
+
+const char *ISM43362Interface::get_ip_address()
+{
+ _mutex.lock();
+ const char *ret = _ism.getIPAddress();
+ _mutex.unlock();
+ return ret;
+}
+
+const char *ISM43362Interface::get_mac_address()
+{
+ _mutex.lock();
+ const char *ret = _ism.getMACAddress();
+ _mutex.unlock();
+ return ret;
+}
+
+const char *ISM43362Interface::get_gateway()
+{
+ _mutex.lock();
+ const char *ret = _ism.getGateway();
+ _mutex.unlock();
+ return ret;
+}
+
+const char *ISM43362Interface::get_netmask()
+{
+ _mutex.lock();
+ const char *ret = _ism.getNetmask();
+ _mutex.unlock();
+ return ret;
+}
+
+int8_t ISM43362Interface::get_rssi()
+{
+ _mutex.lock();
+ int8_t ret = _ism.getRSSI();
+ _mutex.unlock();
+ return ret;
+}
+
+int ISM43362Interface::scan(WiFiAccessPoint *res, unsigned count)
+{
+ _mutex.lock();
+ _ism.setTimeout(ISM43362_CONNECT_TIMEOUT);
+ int ret = _ism.scan(res, count);
+ _mutex.unlock();
+ return ret;
+}
+
+struct ISM43362_socket {
+ int id;
+ nsapi_protocol_t proto;
+ volatile bool connected;
+ SocketAddress addr;
+ char read_data[1400];
+ volatile uint32_t read_data_size;
+};
+
+int ISM43362Interface::socket_open(void **handle, nsapi_protocol_t proto)
+{
+ // Look for an unused socket
+ int id = -1;
+ for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) {
+ if (!_ids[i]) {
+ id = i;
+ _ids[i] = true;
+ break;
+ }
+ }
+
+ if (id == -1) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+ _mutex.lock();
+ struct ISM43362_socket *socket = new struct ISM43362_socket;
+ if (!socket) {
+ return NSAPI_ERROR_NO_SOCKET;
+ }
+ socket->id = id;
+ debug_if(ism_debug, "socket_open, id=%d", socket->id);
+ memset(socket->read_data, 0, sizeof(socket->read_data));
+ socket->addr = 0;
+ socket->read_data_size = 0;
+ socket->proto = proto;
+ socket->connected = false;
+ *handle = socket;
+ _mutex.unlock();
+
+ return 0;
+}
+
+int ISM43362Interface::socket_close(void *handle)
+{
+ _mutex.lock();
+ struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+ debug_if(ism_debug, "socket_close, id=%d", socket->id);
+ int err = 0;
+ _ism.setTimeout(ISM43362_MISC_TIMEOUT);
+
+ if (!_ism.close(socket->id)) {
+ err = NSAPI_ERROR_DEVICE_ERROR;
+ }
+
+ socket->connected = false;
+ _ids[socket->id] = false;
+ _socket_obj[socket->id] = 0;
+ _mutex.unlock();
+ delete socket;
+ return err;
+}
+
+int ISM43362Interface::socket_bind(void *handle, const SocketAddress &address)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ISM43362Interface::socket_listen(void *handle, int backlog)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ISM43362Interface::socket_connect(void *handle, const SocketAddress &addr)
+{
+ _mutex.lock();
+ int ret = socket_connect_nolock(handle, addr);
+ _mutex.unlock();
+ return ret;
+}
+
+int ISM43362Interface::socket_connect_nolock(void *handle, const SocketAddress &addr)
+{
+ struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+ _ism.setTimeout(ISM43362_CONNECT_TIMEOUT);
+ const char *proto = (socket->proto == NSAPI_UDP) ? "1" : "0";
+ if (!_ism.open(proto, socket->id, addr.get_ip_address(), addr.get_port())) {
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+ _ids[socket->id] = true;
+ _socket_obj[socket->id] = (uint32_t)socket;
+ socket->connected = true;
+ return 0;
+
+}
+
+
+
+void ISM43362Interface::socket_check_read()
+{
+ while (1) {
+ for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) {
+ _mutex.lock();
+ if (_socket_obj[i] != 0) {
+ struct ISM43362_socket *socket = (struct ISM43362_socket *)_socket_obj[i];
+ /* Check if there is something to read for this socket. But if it */
+ /* has already been read : don't read again */
+ if ((socket->connected) && (socket->read_data_size == 0) && _cbs[socket->id].callback) {
+ _ism.setTimeout(1);
+ /* if no callback is set, no need to read ?*/
+ int read_amount = _ism.check_recv_status(socket->id, socket->read_data);
+ if (read_amount > 0) {
+ socket->read_data_size = read_amount;
+ } else if (read_amount < 0) {
+ /* Mark donw connection has been lost or closed */
+ socket->connected = false;
+ }
+ if (read_amount != 0) {
+ /* There is something to read in this socket*/
+ if (_cbs[socket->id].callback) {
+ _cbs[socket->id].callback(_cbs[socket->id].data);
+ }
+ }
+ }
+ }
+ _mutex.unlock();
+ }
+ wait_ms(50);
+ }
+}
+
+int ISM43362Interface::socket_accept(void *server, void **socket, SocketAddress *addr)
+{
+ return NSAPI_ERROR_UNSUPPORTED;
+}
+
+int ISM43362Interface::socket_send(void *handle, const void *data, unsigned size)
+{
+ _mutex.lock();
+ int ret = socket_send_nolock(handle, data, size);
+ _mutex.unlock();
+ return ret;
+}
+
+/* CAREFULL LOCK must be taken before callling this function */
+int ISM43362Interface::socket_send_nolock(void *handle, const void *data, unsigned size)
+{
+ struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+ _ism.setTimeout(ISM43362_SEND_TIMEOUT);
+
+ if (size > ES_WIFI_MAX_TX_PACKET_SIZE) {
+ size = ES_WIFI_MAX_TX_PACKET_SIZE;
+ }
+
+ if (!_ism.send(socket->id, data, size)) {
+ debug_if(ism_debug, "socket_send ERROR\r\n");
+ return NSAPI_ERROR_DEVICE_ERROR; // or WOULD_BLOCK ?
+ }
+
+ return size;
+}
+
+int ISM43362Interface::socket_recv(void *handle, void *data, unsigned size)
+{
+ _mutex.lock();
+ unsigned recv = 0;
+ struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+ char *ptr = (char *)data;
+
+ debug_if(ism_debug, "[socket_recv] req=%d\r\n", size);
+
+ if (!socket->connected) {
+ _mutex.unlock();
+ return NSAPI_ERROR_CONNECTION_LOST;
+ }
+
+ _ism.setTimeout(ISM43362_RECV_TIMEOUT);
+
+ if (socket->read_data_size == 0) {
+ /* if no callback is set, no need to read ?*/
+ int read_amount = _ism.check_recv_status(socket->id, socket->read_data);
+ if (read_amount > 0) {
+ socket->read_data_size = read_amount;
+ } else if (read_amount < 0) {
+ socket->connected = false;
+ _mutex.unlock();
+ return NSAPI_ERROR_CONNECTION_LOST;
+ }
+ }
+
+ if (socket->read_data_size != 0) {
+ debug_if(ism_debug, "read_data_size=%d\r\n", socket->read_data_size);
+ uint32_t i=0;
+ while ((i < socket->read_data_size) && (i < size)) {
+ *ptr++ = socket->read_data[i];
+ i++;
+ }
+
+ debug_if(ism_debug, "Copied i bytes=%d, vs %d requestd\r\n", i, size);
+ recv += i;
+
+ if (i >= socket->read_data_size) {
+ /* All the storeed data has been read, reset buffer */
+ memset(socket->read_data, 0, sizeof(socket->read_data));
+ socket->read_data_size = 0;
+ debug_if(ism_debug, "Socket_recv buffer reset\r\n");
+ } else {
+ /* In case there is remaining data in buffer, update socket content
+ * For now by shift copy of all data (not very efficient to be
+ * revised */
+ while (i < socket->read_data_size) {
+ socket->read_data[i - size] = socket->read_data[i];
+ i++;
+ }
+
+ socket->read_data_size -= size;
+ }
+ } else {
+ debug_if(ism_debug, "Nothing in buffer\r\n");
+ }
+
+ debug_if(ism_debug, "[socket_recv]read_datasize=%d, recv=%d\r\n", socket->read_data_size, recv);
+ _mutex.unlock();
+
+ if (recv > 0) {
+ return recv;
+ } else {
+ debug_if(ism_debug, "sock_recv returns WOULD BLOCK\r\n");
+ return NSAPI_ERROR_WOULD_BLOCK;
+ }
+}
+
+int ISM43362Interface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size)
+{
+ _mutex.lock();
+ struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+
+ if (socket->connected && socket->addr != addr) {
+ _ism.setTimeout(ISM43362_MISC_TIMEOUT);
+ if (!_ism.close(socket->id)) {
+ debug_if(ism_debug, "socket_send ERROR\r\n");
+ _mutex.unlock();
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+ socket->connected = false;
+ _ids[socket->id] = false;
+ _socket_obj[socket->id] = 0;
+ }
+
+ if (!socket->connected) {
+ int err = socket_connect_nolock(socket, addr);
+ if (err < 0) {
+ _mutex.unlock();
+ return err;
+ }
+ socket->addr = addr;
+ }
+
+ int ret = socket_send_nolock(socket, data, size);
+
+ _mutex.unlock();
+
+ return ret;
+}
+
+int ISM43362Interface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size)
+{
+ int ret = socket_recv(handle, data, size);
+ _mutex.lock();
+ if ((ret >= 0) && addr) {
+ struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+ *addr = socket->addr;
+ }
+ _mutex.unlock();
+ return ret;
+}
+
+void ISM43362Interface::socket_attach(void *handle, void (*cb)(void *), void *data)
+{
+ _mutex.lock();
+ struct ISM43362_socket *socket = (struct ISM43362_socket *)handle;
+ _cbs[socket->id].callback = cb;
+ _cbs[socket->id].data = data;
+ _mutex.unlock();
+}
+
+void ISM43362Interface::event() {
+ for (int i = 0; i < ISM43362_SOCKET_COUNT; i++) {
+ if (_cbs[i].callback) {
+ _cbs[i].callback(_cbs[i].data);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ISM43362Interface.h Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,300 @@
+/* ISM43362 implementation of NetworkInterfaceAPI
+ * Copyright (c) STMicroelectronics 2017
+ *
+ * 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.
+ */
+
+#ifndef ISM43362_INTERFACE_H
+#define ISM43362_INTERFACE_H
+
+#include "mbed.h"
+#include "ISM43362.h"
+
+
+#define ISM43362_SOCKET_COUNT 4
+
+/** ISM43362Interface class
+ * Implementation of the NetworkStack for the ISM43362
+ */
+class ISM43362Interface : public NetworkStack, public WiFiInterface
+{
+public:
+ /** ISM43362Interface lifetime
+ * @param mosi MOSI pin
+ * @param miso MISO pin
+ * @param clk CLOCK pin
+ * @param nss NSS pin
+ * @param debug Enable debugging
+ */
+ ISM43362Interface(PinName mosi, PinName miso, PinName clk, PinName nss, PinName reset, PinName dataready, PinName wakeup, bool debug = false);
+
+ /** Start the interface
+ *
+ * Attempts to connect to a WiFi network. Requires ssid and passphrase to be set.
+ * If passphrase is invalid, NSAPI_ERROR_AUTH_ERROR is returned.
+ *
+ * @return 0 on success, negative error code on failure
+ */
+ virtual int connect();
+
+ /** Start the interface
+ *
+ * Attempts to connect to a WiFi network.
+ *
+ * @param ssid Name of the network to connect to
+ * @param pass Security passphrase to connect to the network
+ * @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE)
+ * @param channel This parameter is not supported, setting it to anything else than 0 will result in NSAPI_ERROR_UNSUPPORTED
+ * @return 0 on success, or error code on failure
+ */
+ virtual int connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE,
+ uint8_t channel = 0);
+
+ /** Translates a hostname to an IP address with specific version
+ *
+ * The hostname may be either a domain name or an IP address. If the
+ * hostname is an IP address, no network transactions will be performed.
+ *
+ *
+ * @param host Hostname to resolve
+ * @param address Destination for the host SocketAddress
+ * @param version IP version of address to resolve, NSAPI_UNSPEC indicates
+ * version is chosen by the stack (defaults to NSAPI_UNSPEC)
+ * @return 0 on success, negative error code on failure
+ */
+ virtual nsapi_error_t gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
+
+ /** Set the WiFi network credentials
+ *
+ * @param ssid Name of the network to connect to
+ * @param pass Security passphrase to connect to the network
+ * @param security Type of encryption for connection
+ * (defaults to NSAPI_SECURITY_NONE)
+ * @return 0 on success, or error code on failure
+ */
+ virtual int set_credentials(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE);
+
+ /** Set the WiFi network channel - NOT SUPPORTED
+ *
+ * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED
+ *
+ * @param channel Channel on which the connection is to be made, or 0 for any (Default: 0)
+ * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED
+ */
+ virtual int set_channel(uint8_t channel);
+
+ /** Stop the interface
+ * @return 0 on success, negative on failure
+ */
+ virtual int disconnect();
+
+ /** Get the internally stored IP address
+ * @return IP address of the interface or null if not yet connected
+ */
+ virtual const char *get_ip_address();
+
+ /** Get the internally stored MAC address
+ * @return MAC address of the interface
+ */
+ virtual const char *get_mac_address();
+
+ /** Get the local gateway
+ *
+ * @return Null-terminated representation of the local gateway
+ * or null if no network mask has been recieved
+ */
+ virtual const char *get_gateway();
+
+ /** Get the local network mask
+ *
+ * @return Null-terminated representation of the local network mask
+ * or null if no network mask has been recieved
+ */
+ virtual const char *get_netmask();
+
+ /** Gets the current radio signal strength for active connection
+ *
+ * @return Connection strength in dBm (negative value)
+ */
+ virtual int8_t get_rssi();
+
+ /** Scan for available networks
+ *
+ * This function will block.
+ *
+ * @param ap Pointer to allocated array to store discovered AP
+ * @param count Size of allocated @a res array, or 0 to only count available AP
+ * @param timeout Timeout in milliseconds; 0 for no timeout (Default: 0)
+ * @return Number of entries in @a, or if @a count was 0 number of available networks, negative on error
+ * see @a nsapi_error
+ */
+ virtual int scan(WiFiAccessPoint *res, unsigned count);
+
+ /** Translates a hostname to an IP address with specific version
+ *
+ * The hostname may be either a domain name or an IP address. If the
+ * hostname is an IP address, no network transactions will be performed.
+ *
+ * If no stack-specific DNS resolution is provided, the hostname
+ * will be resolve using a UDP socket on the stack.
+ *
+ * @param address Destination for the host SocketAddress
+ * @param host Hostname to resolve
+ * @param version IP version of address to resolve, NSAPI_UNSPEC indicates
+ * version is chosen by the stack (defaults to NSAPI_UNSPEC)
+ * @return 0 on success, negative error code on failure
+ */
+ using NetworkInterface::gethostbyname;
+
+ /** Add a domain name server to list of servers to query
+ *
+ * @param addr Destination for the host address
+ * @return 0 on success, negative error code on failure
+ */
+ using NetworkInterface::add_dns_server;
+
+protected:
+ /** Open a socket
+ * @param handle Handle in which to store new socket
+ * @param proto Type of socket to open, NSAPI_TCP or NSAPI_UDP
+ * @return 0 on success, negative on failure
+ */
+ virtual int socket_open(void **handle, nsapi_protocol_t proto);
+
+ /** Close the socket
+ * @param handle Socket handle
+ * @return 0 on success, negative on failure
+ * @note On failure, any memory associated with the socket must still
+ * be cleaned up
+ */
+ virtual int socket_close(void *handle);
+
+ /** Bind a server socket to a specific port
+ * @param handle Socket handle
+ * @param address Local address to listen for incoming connections on
+ * @return 0 on success, negative on failure.
+ */
+ virtual int socket_bind(void *handle, const SocketAddress &address);
+
+ /** Start listening for incoming connections
+ * @param handle Socket handle
+ * @param backlog Number of pending connections that can be queued up at any
+ * one time [Default: 1]
+ * @return 0 on success, negative on failure
+ */
+ virtual int socket_listen(void *handle, int backlog);
+
+ /** Connects this TCP socket to the server
+ * @param handle Socket handle
+ * @param address SocketAddress to connect to
+ * @return 0 on success, negative on failure
+ */
+ virtual int socket_connect(void *handle, const SocketAddress &address);
+
+ /** Accept a new connection.
+ * @param handle Handle in which to store new socket
+ * @param server Socket handle to server to accept from
+ * @return 0 on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_accept(void *handle, void **socket, SocketAddress *address);
+
+ /** Send data to the remote host
+ * @param handle Socket handle
+ * @param data The buffer to send to the host
+ * @param size The length of the buffer to send
+ * @return Number of written bytes on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_send(void *handle, const void *data, unsigned size);
+
+ /** Receive data from the remote host
+ * @param handle Socket handle
+ * @param data The buffer in which to store the data received from the host
+ * @param size The maximum length of the buffer
+ * @return Number of received bytes on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_recv(void *handle, void *data, unsigned size);
+
+ /** Send a packet to a remote endpoint
+ * @param handle Socket handle
+ * @param address The remote SocketAddress
+ * @param data The packet to be sent
+ * @param size The length of the packet to be sent
+ * @return The number of written bytes on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_sendto(void *handle, const SocketAddress &address, const void *data, unsigned size);
+
+ /** Receive a packet from a remote endpoint
+ * @param handle Socket handle
+ * @param address Destination for the remote SocketAddress or null
+ * @param buffer The buffer for storing the incoming packet data
+ * If a packet is too long to fit in the supplied buffer,
+ * excess bytes are discarded
+ * @param size The length of the buffer
+ * @return The number of received bytes on success, negative on failure
+ * @note This call is not-blocking, if this call would block, must
+ * immediately return NSAPI_ERROR_WOULD_WAIT
+ */
+ virtual int socket_recvfrom(void *handle, SocketAddress *address, void *buffer, unsigned size);
+
+ /** Register a callback on state change of the socket
+ * @param handle Socket handle
+ * @param callback Function to call on state change
+ * @param data Argument to pass to callback
+ * @note Callback may be called in an interrupt context.
+ */
+ virtual void socket_attach(void *handle, void (*callback)(void *), void *data);
+
+ /** Provide access to the NetworkStack object
+ *
+ * @return The underlying NetworkStack object
+ */
+ virtual NetworkStack *get_stack()
+ {
+ return this;
+ }
+
+private:
+ ISM43362 _ism;
+ bool _ids[ISM43362_SOCKET_COUNT];
+ uint32_t _socket_obj[ISM43362_SOCKET_COUNT]; // store addresses of socket handles
+ Mutex _mutex;
+ Thread thread_read_socket;
+ char ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */
+ nsapi_security_t ap_sec;
+ uint8_t ap_ch;
+ char ap_pass[64]; /* The longest allowed passphrase */
+
+ void event();
+ struct {
+ void (*callback)(void *);
+ void *data;
+ } _cbs[ISM43362_SOCKET_COUNT];
+
+ /** Function called by the socket read thread to check if data is available on the wifi module
+ *
+ */
+ virtual void socket_check_read();
+ int socket_send_nolock(void *handle, const void *data, unsigned size);
+ int socket_connect_nolock(void *handle, const SocketAddress &addr);
+
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/README.md Tue Aug 21 08:34:28 2018 +0000
@@ -0,0 +1,50 @@
+# ISM43362 WiFi driver for mbed-os
+The mbed OS driver for the ISM43362 WiFi module
+
+## Currently supported platforms
+ISM43362 module is soldered on the following platforms from STMicroelectronics
+* DISCO_L475VG_IOT01A
+* DISCO_F413ZH
+
+## Configuration
+Add the following lines to the target_overrides section of mbed_app.json of your application
+```
+"DISCO_L475VG_IOT1A": {
+ "wifi-spi_miso": "PC_11",
+ "wifi-spi_mosi": "PC_12",
+ "wifi-spi_sclk": "PC_10",
+ "wifi-spi_nss": "PE_0",
+ "wifi-reset": "PE_8",
+ "wifi-dataready": "PE_1",
+ "wifi-wakeup": "PB_13"
+},
+"DISCO_F413ZH": {
+ "wifi-spi_miso": "PB_4",
+ "wifi-spi_mosi": "PB_5",
+ "wifi-spi_sclk": "PB_12",
+ "wifi-spi_nss": "PG_11",
+ "wifi-reset": "PH_1",
+ "wifi-dataready": "PG_12",
+ "wifi-wakeup": "PB_15"
+}
+```
+
+- MBED_CFG_ISM43362_SSID - SSID of the wifi access point to connect to
+- MBED_CFG_ISM43362_PASS - Passphrase of the wifi access point to connect to
+- MBED_CONF_APP_WIFI_SPI_MISO - spi-miso pin for the ism43362 connection
+- MBED_CONF_APP_WIFI_SPI_MOSI - spi-mosi pin for the ism43362 connection
+- MBED_CONF_APP_WIFI_SPI_SCLK - spi-clock pin for the ism43362 connection
+- MBED_CONF_APP_WIFI_SPI_NSS - spi-nss pin for the ism43362 connection
+- MBED_CONF_APP_WIFI_RESET - Reset pin for the ism43362 wifi module
+- MBED_CONF_APP_WIFI_DATAREADY - Data Ready pin for the ism43362 wifi module
+- MBED_CONF_APP_WIFI_WAKEUP - Wakeup pin for the ism43362 wifi module
+
+
+## Firmware version
+This driver supports ISM43362-M3G-L44-SPI,C3.5.2.3.BETA9 and C3.5.2.2 firmware version
+
+## wifi module FW update
+For more information about the wifi FW version, refer to the detailed procedure in
+http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software-expansion/x-cube-azure.html
+
+```