![](/media/cache/group/Advantech_logo.jpg.50x50_q85.jpg)
Generic Pelion Device Management example for various Advantech modules.
This example is known to work great on the following platforms:
- WISE-1530 WiFi Module using DB-1505 carrier board and external SD card reader.
Example Functionality
This example showcases the following device functionality:
- On timer button increment, simulate Pelion LWM2M button resource change
Use this example with Mbed CLI
1. Import the application into your desktop:
mbed import https://os.mbed.com/teams/Advantech/code/pelion-example-common cd pelion-example-common
2. Download your developer certificate from pelion portal
3. Compile the program
mbed compile -t <toolchain> -m <TARGET_BOARD>
(supported toolchains : GCC_ARM / ARM / IAR)
4. Copy the binary file pelion-example-common.bin to your mbed device.
Revision 0:43ff9e3bc244, committed 2019-03-12
- Comitter:
- chuanga
- Date:
- Tue Mar 12 13:48:39 2019 +0800
- Commit message:
- copying sources from github repository
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LICENSE.txt Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,165 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,162 @@ +# Pelion Device Ready example - template application + +(aka Simple Mbed Cloud Client template) + +## Overview + +This is a template application to showcase device management capabilities. It demonstrates how to create a simple application that can connect to the Pelion IoT Platform service, register resources and get ready to receive a firmware update. + +It's intended to be forked and customized to add platform-specific features (such as sensors and actuators) and configure the connectivity and storage to work **out-of-the-box**. The template application works in **developer mode** by default. + +There is a mirror version of the stable (master) template application on [this location](https://os.mbed.com/teams/mbed-os-examples/code/pelion-ready-example) to facilitate the fork and publish on https://os.mbed.com. + +## Board specific example applications + + There are a number of applications that make usage of the Simple Pelion DM Client library. + + The Pelion [Quick-Start](https://cloud.mbed.com/quick-start) is an initiative to support Mbed Partner's platforms while delivering a great User Experience to Mbed Developers. + +## Getting started with the application + +This is a summary of the process for developers to get started and get a device connected to Pelion Device Management. + +### Using Mbed Online IDE + +1. Import the application into the Online IDE. +2. Add the API key to establish connection. +3. Install the developer certificate. +4. Compile and program. + +### Using Mbed CLI + +1. Import the application into your desktop: + + ``` + mbed import https://github.com/ARMmbed/pelion-ready-example + cd pelion-ready-example + ``` + +2. Configure the API key for your Pelion Portal account. + + If you don't have an API key available, then login in [Pelion IoT Platform portal](https://portal.mbedcloud.com/), navigate to 'Access Management', 'API keys' and create a new one. Then specify the API key as global `mbed` configuration: + + ``` + mbed config -G CLOUD_SDK_API_KEY <your-api-key> + ``` + +3. Install the device management certificate: + + ``` + mbed dm init -d "company.com" --model-name "product-model" -q --force + ``` + +4. Compile and program: + + ``` + mbed compile -t <toolchain> -m <target> -f + ``` + +#### Update the application logic + +The template example uses a ticker object to periodically fire a software interrupt to simulate button presses. Let’s say you want to make an actual button press. + +By default, there is a Ticker object, which fires every five seconds and invokes a callback function: + +```cpp +Ticker timer; +timer.attach(eventQueue.event(&fake_button_press), 5.0); +``` + +This callback function changes the `button_res` resource: + +```cpp +void fake_button_press() { + int v = button_res->get_value_int() + 1; + + button_res->set_value(v); + + printf("Simulated button clicked %d times\n", v); +} +``` + +If you want to change this to an actual button, here is how to do it: + +1. Remove: + + ```cpp + Ticker timer; + timer.attach(eventQueue.event(&fake_button_press), 5.0); + ``` + +2. Declare an `InterruptIn` object on the button, and attach the callback function to the `fall` handler: + + ```cpp + InterruptIn btn(BUTTON1); + btn.fall(eventQueue.event(&fake_button_press), 5.0); + ``` + +3. Rename `fake_button_press` to `real_button_press`. + +## Enabling firmware updates + +Mbed OS 5.10 and Mbed CLI 1.8 simplifies the process to enable and perform Firmware Updates. Here is a summary on how to configure the device and verify its correct behaviour. + +For full documentation about bootloaders and firmware update, read the following documents: + +- [Introduccion to bootloaders](https://os.mbed.com/docs/latest/porting/bootloader.html) +- [Creating and using a bootloader](https://os.mbed.com/docs/latest/tutorials/bootloader.html) +- [Bootloader configuration in Mbed OS](https://os.mbed.com/docs/latest/tools/configuring-tools.html) +- [Mbed Bootloader for Pelion Device Management Client](https://github.com/ARMmbed/mbed-bootloader) +- [Updating devices with Arm Mbed CLI](https://os.mbed.com/docs/latest/tools/cli-update.html) + +This is a summary to use Arm Mbed OS managed bootloaders. + +#### Verifying that firmware update works + +Follow these steps to generate a manifest, compile and perform a firmware update of your device: + +1. Configure the API key for your Pelion account. + + If you don't have an API key available, then login in [Pelion IoT Platform portal](https://portal.mbedcloud.com/), navigate to 'Access Management', 'API keys' and create a new one. Then specify the API key as global `mbed` configuration: + + ``` + mbed config -G CLOUD_SDK_API_KEY <your-api-key> + ``` + +2. Initialize the device management feature: + + ``` + mbed dm init -d "company.com" --model-name "product-model" -q --force + ``` + +3. Compile the application, include the firware update credentials generated before, merge with the bootloader and program the device: + + ``` + mbed compile -t <toolchain> -m <target> -c -f + ``` + +4. Open a serial terminal, verify the application boots and is able to register to the Device Management service. Write down the `<endpoint ID>`, as it's required to identify the device to perform a firmware update. + +5. Update the firmware of the device through Mbed CLI: + + ``` + mbed dm update device -D <device ID> -t <toolchain> -m <target> + ``` + + Inspect the logs on the device to see the update progress. It should look similar to: + + ``` + Firmware download requested + Authorization granted + Downloading: [+++- ] 6 % + ``` + + When the download completes, the firmware is verified. If everything is OK, the firmware update is applied, the device reboots and attemps to connect to the Device Management service again. The `<endpoint ID>` should be preserved. + +## Automated testing + +The Simple Pelion Client provides Greentea tests to confirm your platform works as expected. The network and storage configuration is already defined in Mbed OS 5.10, but you may want to override the configuration in `mbed_app.json`. + +For details on Simple Pelion Client testing, refer to the documentation [here](https://github.com/ARMmbed/simple-mbed-cloud-client#testing). + +This template application contains a working application and tests passing for the `K64F` and `K66F` platforms. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bootloader/LICENSE Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,49 @@ +Permissive Binary License + +Version 1.0, September 2015 + +Redistribution. Redistribution and use in binary form, without +modification, are permitted provided that the following conditions are +met: + +1) Redistributions must reproduce the above copyright notice and the + following disclaimer in the documentation and/or other materials + provided with the distribution. + +2) Unless to the extent explicitly permitted by law, no reverse + engineering, decompilation, or disassembly of this software is + permitted. + +3) Redistribution as part of a software development kit must include the + accompanying file named "DEPENDENCIES" and any dependencies listed in + that file. + +4) Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +Limited patent license. The copyright holders (and contributors) grant a +worldwide, non-exclusive, no-charge, royalty-free patent license to +make, have made, use, offer to sell, sell, import, and otherwise +transfer this software, where such license applies only to those patent +claims licensable by the copyright holders (and contributors) that are +necessarily infringed by this software. This patent license shall not +apply to any combinations that include this software. No hardware is +licensed hereunder. + +If you institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the software +itself infringes your patent(s), then your rights granted under this +license shall terminate as of the date such litigation is filed. + +DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bootloader/bootloader_app.json Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,520 @@ +{ + "macros": [ + "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"", + "SHOW_PROGRESS_BAR=0", + "MAX_COPY_RETRIES=1", + "MAX_BOOT_RETRIES=3", + "ARM_BOOTLOADER_USE_NVSTORE_ROT=1", + "ARM_UC_USE_PAL_CRYPTO=0", + "ARM_UC_USE_PAL_BLOCKDEVICE=1", + "ARM_UC_PAAL_TRACE_ENABLE=0", + "ARM_UC_PROFILE_MBED_CLOUD_CLIENT=1", + "ARM_UC_FEATURE_CRYPTO_PAL=0", + "ARM_UC_FEATURE_CRYPTO_MBEDTLS=1", + "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE", + "DEFAULT_MAX_APPLICATION_SIZE=(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - MBED_CONF_APP_APPLICATION_START_ADDRESS - NVSTORE_AREA_1_SIZE - NVSTORE_AREA_2_SIZE)", + "DISABLE_ERROR_DESCRIPTION=1", + "Mutex=PlatformMutex" + ], + "config": { + "application-start-address": { + "help": "Address to the beginning of the active application firmware in flash", + "value": null + }, + "application-jump-address": { + "help": "Jump address for running the active application firmware", + "value": null + }, + "max-application-size": { + "help": "Maximum size of the active application", + "value": null + }, + "flash-start-address": { + "help": "Start address of internal flash. Only used in this config to help the definition of other macros.", + "value": null + }, + "flash-size": { + "help": "Total size of internal flash. Only used in this config to help the definition of other macros.", + "value": null + } + }, + "target_overrides": { + "*": { + "target.features_remove" : ["LWIP"], + "target.features_add" : ["COMMON_PAL"], + "target.extra_labels_remove" : ["PSA"], + "target.components_remove" : ["FLASHIAP"], + "platform.stdio-baud-rate" : 115200, + "platform.stdio-flush-at-exit" : false + }, + "K64F": { + "target.components_add" : ["SD"], + "flash-start-address" : "0x0", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "K66F": { + "target.components_add" : ["SD"], + "flash-start-address" : "0x0", + "flash-size" : "(2048*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUCLEO_F412ZG": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "D11", + "sd.SPI_MISO" : "D12", + "sd.SPI_CLK" : "D13", + "sd.SPI_CS" : "D10", + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUCLEO_F429ZI": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "PC_12", + "sd.SPI_MISO" : "PC_11", + "sd.SPI_CLK" : "PC_10", + "sd.SPI_CS" : "PC_9", + "flash-start-address" : "0x08000000", + "flash-size" : "(2048*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUCLEO_F767ZI": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "PC_12", + "sd.SPI_MISO" : "PC_11", + "sd.SPI_CLK" : "PC_10", + "sd.SPI_CS" : "PC_9", + "flash-start-address" : "0x08000000", + "flash-size" : "(2048*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(256*1024))", + "nvstore.area_1_size" : "(256*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(256*1024))", + "nvstore.area_2_size" : "(256*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUCLEO_F746ZG": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "PC_12", + "sd.SPI_MISO" : "PC_11", + "sd.SPI_CLK" : "PC_10", + "sd.SPI_CS" : "PC_9", + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(256*1024))", + "nvstore.area_1_size" : "(256*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(256*1024))", + "nvstore.area_2_size" : "(256*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUCLEO_F207ZG": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "PC_12", + "sd.SPI_MISO" : "PC_11", + "sd.SPI_CLK" : "PC_10", + "sd.SPI_CS" : "PC_9", + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUCLEO_L4R5ZI": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "D11", + "sd.SPI_MISO" : "D12", + "sd.SPI_CLK" : "D13", + "sd.SPI_CS" : "D10", + "flash-start-address" : "0x08000000", + "flash-size" : "(2*1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUCLEO_L476RG": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "D11", + "sd.SPI_MISO" : "D12", + "sd.SPI_CLK" : "D13", + "sd.SPI_CS" : "D10", + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "DISCO_L475VG_IOT01A": { + "target.components_add" : ["QSPIF"], + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(2*1024))", + "nvstore.area_1_size" : "(2*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(2*1024))", + "nvstore.area_2_size" : "(2*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "DISCO_F413ZH": { + "target.components_add" : ["QSPIF"], + "flash-start-address" : "0x08000000", + "flash-size" : "(1536*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "DISCO_F469NI": { + "target.components_add" : ["QSPIF"], + "target.components_remove" : ["FLASHIAP"], + "flash-start-address" : "0x08000000", + "flash-size" : "(2*1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE", + "update-client.storage-address" : "(1024*1024*2)", + "update-client.storage-size" : "(1024*1024*2)", + "update-client.storage-locations" : 1 + }, + "DISCO_F746NG": { + "target.components_add" : ["QSPIF"], + "target.components_remove" : ["FLASHIAP"], + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(256*1024))", + "nvstore.area_1_size" : "(256*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(256*1024))", + "nvstore.area_2_size" : "(256*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "DISCO_F769NI": { + "target.components_add" : ["QSPIF"], + "target.components_remove" : ["FLASHIAP"], + "flash-start-address" : "0x08000000", + "flash-size" : "(2*1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(256*1024))", + "nvstore.area_1_size" : "(256*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(256*1024))", + "nvstore.area_2_size" : "(256*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUMAKER_PFM_NUC472": { + "drivers.uart-serial-rxbuf-size" : 1024, + "drivers.uart-serial-txbuf-size" : 1024, + "flash-start-address" : "0x0", + "flash-size" : "(512*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUMAKER_PFM_M487": { + "drivers.uart-serial-rxbuf-size" : 1024, + "drivers.uart-serial-txbuf-size" : 1024, + "flash-start-address" : "0x0", + "flash-size" : "(512*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "NUMAKER_IOT_M487": { + "drivers.uart-serial-rxbuf-size" : 1024, + "drivers.uart-serial-txbuf-size" : 1024, + "flash-start-address" : "0x0", + "flash-size" : "(512*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "GR_LYCHEE": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "P5_6", + "sd.SPI_MISO" : "P5_7", + "sd.SPI_CLK" : "P5_4", + "sd.SPI_CS" : "P5_5", + "flash-start-address" : "0x18000000", + "flash-size" : "(8*1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "RZ_A1H": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "P8_5", + "sd.SPI_MISO" : "P8_6", + "sd.SPI_CLK" : "P8_3", + "sd.SPI_CS" : "P8_4", + "flash-start-address" : "0x18000000", + "flash-size" : "(8*1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "UBLOX_EVK_ODIN_W2": { + "target.components_add" : ["SD"], + "target.device_has_remove" : ["EMAC"], + "flash-start-address" : "0x08000000", + "flash-size" : "(2048*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "UBLOX_C030_U201": { + "target.components_add" : ["SD"], + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(128*1024))", + "nvstore.area_1_size" : "(128*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(128*1024))", + "nvstore.area_2_size" : "(128*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "SDT64B": { + "target.components_add" : ["SD"], + "sd.SPI_MOSI" : "PTB16", + "sd.SPI_MISO" : "PTB17", + "sd.SPI_CLK" : "PTB11", + "sd.SPI_CS" : "PTB10", + "flash-start-address" : "0x0", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(64*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + }, + "MTB_MXCHIP_EMW3166": { + "target.extra_labels_remove" : ["WICED"], + "target.components_add" : ["SPIF"], + "spif-driver.SPI_MOSI" : "PB_15", + "spif-driver.SPI_MISO" : "PB_14", + "spif-driver.SPI_CLK" : "PB_13", + "spif-driver.SPI_CS" : "PA_10", + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 48*1024)", + "nvstore.area_1_size" : "(16*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "nvstore.area_2_size" : "(16*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(1*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 128*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 129*1024)", + "max-application-size" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - MBED_CONF_APP_APPLICATION_START_ADDRESS)" + + }, + "MTB_USI_WM_BN_BM_22": { + "target.extra_labels_remove" : ["WICED"], + "target.components_add" : ["SPIF"], + "spif-driver.SPI_MOSI" : "PC_3", + "spif-driver.SPI_MISO" : "PC_2", + "spif-driver.SPI_CLK" : "PB_13", + "spif-driver.SPI_CS" : "PA_6", + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 48*1024)", + "nvstore.area_1_size" : "(16*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "nvstore.area_2_size" : "(16*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(1*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 128*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 129*1024)", + "max-application-size" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - MBED_CONF_APP_APPLICATION_START_ADDRESS)" + }, + "MTB_ADV_WISE_1570": { + "target.components_add" : ["SPIF"], + "target.OUTPUT_EXT" : "bin", + "spif-driver.SPI_FREQ" : 20000000, + "flash-start-address" : "0x08000000", + "flash-size" : "(1024*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(1*1024*1024)", + "update-client.storage-page" : 1, + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 32*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 33*1024)", + "max-application-size" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - MBED_CONF_APP_APPLICATION_START_ADDRESS)" + }, + "EFM32GG11_STK3701": { + "target.components_add" : ["QSPIF"], + "qspif.QSPI_FREQ" : 10000000, + "flash-start-address" : "0x00000000", + "flash-size" : "(2048*1024)", + "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "nvstore.area_1_size" : "(4*1024)", + "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "nvstore.area_2_size" : "(4*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(2*1024*1024)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version": "2", + "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 65*1024)", + "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + } + } +}
Binary file bootloader/mbed-bootloader-DISCO_F413ZH.bin has changed
Binary file bootloader/mbed-bootloader-DISCO_F469NI.bin has changed
Binary file bootloader/mbed-bootloader-DISCO_F746NG.bin has changed
Binary file bootloader/mbed-bootloader-DISCO_F769NI.bin has changed
Binary file bootloader/mbed-bootloader-DISCO_L475VG_IOT01A.bin has changed
Binary file bootloader/mbed-bootloader-EFM32GG11_STK3701.bin has changed
Binary file bootloader/mbed-bootloader-GR_LYCHEE.bin has changed
Binary file bootloader/mbed-bootloader-K64F.bin has changed
Binary file bootloader/mbed-bootloader-K66F.bin has changed
Binary file bootloader/mbed-bootloader-MTB_ADV_WISE_1530.bin has changed
Binary file bootloader/mbed-bootloader-MTB_ADV_WISE_1570.bin has changed
Binary file bootloader/mbed-bootloader-MTB_MXCHIP_EMW3166.bin has changed
Binary file bootloader/mbed-bootloader-MTB_USI_WM_BN_BM_22.bin has changed
Binary file bootloader/mbed-bootloader-NUCLEO_F207ZG.bin has changed
Binary file bootloader/mbed-bootloader-NUCLEO_F412ZG.bin has changed
Binary file bootloader/mbed-bootloader-NUCLEO_F429ZI.bin has changed
Binary file bootloader/mbed-bootloader-NUCLEO_F746ZG.bin has changed
Binary file bootloader/mbed-bootloader-NUCLEO_F767ZI.bin has changed
Binary file bootloader/mbed-bootloader-NUCLEO_L476RG.bin has changed
Binary file bootloader/mbed-bootloader-NUCLEO_L4R5ZI.bin has changed
Binary file bootloader/mbed-bootloader-NUMAKER_IOT_M487.bin has changed
Binary file bootloader/mbed-bootloader-NUMAKER_PFM_M487.bin has changed
Binary file bootloader/mbed-bootloader-NUMAKER_PFM_NUC472.bin has changed
Binary file bootloader/mbed-bootloader-RZ_A1H.bin has changed
Binary file bootloader/mbed-bootloader-SDT64B.bin has changed
Binary file bootloader/mbed-bootloader-UBLOX_C030_U201.bin has changed
Binary file bootloader/mbed-bootloader-UBLOX_EVK_ODIN_W2.bin has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32.lib Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,1 @@ +https://github.com/d-kato/esp32-driver/#ccbe1eda4920dd4bed7c08fe40a7fdca83e1b77e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/.mbed Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,1 @@ +ROOT=.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/ESP32/ESP32.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,973 @@ +/* ESP32 Example + * Copyright (c) 2015 ARM Limited + * Copyright (c) 2017 Renesas Electronics Corporation + * + * 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. + */ + +#if DEVICE_SERIAL && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_PRESENT) +#include "ESP32.h" + +#define ESP32_DEFAULT_BAUD_RATE 115200 +#define ESP32_ALL_SOCKET_IDS -1 + +using namespace mbed; +using namespace rtos; + +ESP32 * ESP32::instESP32 = NULL; + +ESP32 * ESP32::getESP32Inst(PinName en, PinName io0, PinName tx, PinName rx, bool debug, + PinName rts, PinName cts, int baudrate) +{ + if (instESP32 == NULL) { + instESP32 = new ESP32(en, io0, tx, rx, debug, rts, cts, baudrate); + } else { + if (debug) { + instESP32->debugOn(debug); + } + } + return instESP32; +} + +ESP32::ESP32(PinName en, PinName io0, PinName tx, PinName rx, bool debug, + PinName rts, PinName cts, int baudrate) + : _p_wifi_en(NULL), _p_wifi_io0(NULL), init_end(false) + , _serial(tx, rx, ESP32_DEFAULT_BAUD_RATE), _parser(&_serial, "\r\n") + , _packets(0), _packets_end(&_packets) + , _id_bits(0), _id_bits_close(0), _server_act(false) + , _wifi_status(STATUS_DISCONNECTED) + , _wifi_status_cb(NULL) +{ + if ((int)en != NC) { + _p_wifi_en = new DigitalOut(en); + } + if ((int)io0 != NC) { + _p_wifi_io0 = new DigitalOut(io0); + } + + _wifi_mode = WIFIMODE_STATION; + _baudrate = baudrate; + memset(_ids, 0, sizeof(_ids)); + memset(_cbs, 0, sizeof(_cbs)); + + _rts = rts; + _cts = cts; + + if ((_rts != NC) && (_cts != NC)) { + _flow_control = 3; + } else if (_rts != NC) { + _flow_control = 1; + } else if (_cts != NC) { + _flow_control = 2; + } else { + _flow_control = 0; + } + + _serial.set_baud(ESP32_DEFAULT_BAUD_RATE); + debugOn(debug); + + _parser.oob("+IPD", callback(this, &ESP32::_packet_handler)); + _parser.oob("0,CONNECT", callback(this, &ESP32::_connect_handler_0)); + _parser.oob("1,CONNECT", callback(this, &ESP32::_connect_handler_1)); + _parser.oob("2,CONNECT", callback(this, &ESP32::_connect_handler_2)); + _parser.oob("3,CONNECT", callback(this, &ESP32::_connect_handler_3)); + _parser.oob("4,CONNECT", callback(this, &ESP32::_connect_handler_4)); + _parser.oob("0,CLOSED", callback(this, &ESP32::_closed_handler_0)); + _parser.oob("1,CLOSED", callback(this, &ESP32::_closed_handler_1)); + _parser.oob("2,CLOSED", callback(this, &ESP32::_closed_handler_2)); + _parser.oob("3,CLOSED", callback(this, &ESP32::_closed_handler_3)); + _parser.oob("4,CLOSED", callback(this, &ESP32::_closed_handler_4)); + _parser.oob("WIFI ", callback(this, &ESP32::_connection_status_handler)); + + _serial.sigio(Callback<void()>(this, &ESP32::event)); + + setTimeout(); +} + +void ESP32::debugOn(bool debug) +{ + _parser.debug_on((debug) ? 1 : 0); +} + +int ESP32::get_firmware_version() +{ + int version; + + _smutex.lock(); + startup(); + bool done = _parser.send("AT+GMR") + && _parser.recv("SDK version:%d", &version) + && _parser.recv("OK"); + _smutex.unlock(); + + if(done) { + return version; + } else { + // Older firmware versions do not prefix the version with "SDK version: " + return -1; + } +} + +bool ESP32::startup() +{ + if (init_end) { + return true; + } + + if (_p_wifi_io0 != NULL) { + _p_wifi_io0->write(1); + } + if (_p_wifi_en != NULL) { + _p_wifi_en->write(0); + ThisThread::sleep_for(10); + _p_wifi_en->write(1); + _parser.recv("ready"); + } else { + setTimeout(100); + _parser.recv("ready"); + } + + reset(); + bool success = _parser.send("AT+CWMODE=%d", _wifi_mode) + && _parser.recv("OK") + && _parser.send("AT+CIPMUX=1") + && _parser.recv("OK") + && _parser.send("AT+CWAUTOCONN=0") + && _parser.recv("OK") + && _parser.send("AT+CWQAP") + && _parser.recv("OK"); + if (success) { + init_end = true; + } + + return success; +} + +bool ESP32::restart() +{ + bool success; + + _smutex.lock(); + if (!init_end) { + success = startup(); + } else { + reset(); + success = _parser.send("AT+CWMODE=%d", _wifi_mode) + && _parser.recv("OK") + && _parser.send("AT+CIPMUX=1") + && _parser.recv("OK"); + } + _smutex.unlock(); + + return success; +} + +bool ESP32::set_mode(int mode) +{ + //only 3 valid modes + if (mode < 1 || mode > 3) { + return false; + } + if (_wifi_mode != mode) { + _wifi_mode = mode; + return restart(); + } + return true; +} + +bool ESP32::cre_server(int port) +{ + if (_server_act) { + return false; + } + _smutex.lock(); + startup(); + if (!(_parser.send("AT+CIPSERVER=1,%d", port) + && _parser.recv("OK"))) { + _smutex.unlock(); + return false; + } + _server_act = true; + _smutex.unlock(); + return true; +} + +bool ESP32::del_server() +{ + _smutex.lock(); + startup(); + if (!(_parser.send("AT+CIPSERVER=0") + && _parser.recv("OK"))) { + _smutex.unlock(); + return false; + } + _server_act = false; + _smutex.unlock(); + return true; +} + +void ESP32::socket_handler(bool connect, int id) +{ + _cbs[id].Notified = 0; + if (connect) { + _id_bits |= (1 << id); + if (_server_act) { + _accept_id.push_back(id); + } + } else { + _id_bits &= ~(1 << id); + _id_bits_close |= (1 << id); + if (_server_act) { + for (size_t i = 0; i < _accept_id.size(); i++) { + if (id == _accept_id[i]) { + _accept_id.erase(_accept_id.begin() + i); + } + } + } + } +} + +bool ESP32::accept(int * p_id) +{ + bool ret = false; + + while (!ret) { + if (!_server_act) { + break; + } + + _smutex.lock(); + startup(); + if (!_accept_id.empty()) { + ret = true; + } else { + _parser.process_oob(); // Poll for inbound packets + if (!_accept_id.empty()) { + ret = true; + } + } + if (ret) { + *p_id = _accept_id[0]; + _accept_id.erase(_accept_id.begin()); + } + _smutex.unlock(); + if (!ret) { + ThisThread::sleep_for(5); + } + } + + if (ret) { + for (int i = 0; i < 50; i++) { + if ((_id_bits_close & (1 << *p_id)) == 0) { + break; + } + ThisThread::sleep_for(10); + } + } + + return ret; +} + +bool ESP32::reset(void) +{ + for (int i = 0; i < 2; i++) { + if (_parser.send("AT+RST") + && _parser.recv("OK")) { + _serial.set_baud(ESP32_DEFAULT_BAUD_RATE); +#if DEVICE_SERIAL_FC + _serial.set_flow_control(SerialBase::Disabled); +#endif + _parser.recv("ready"); + _clear_socket_packets(ESP32_ALL_SOCKET_IDS); + + if (_parser.send("AT+UART_CUR=%d,8,1,0,%d", _baudrate, _flow_control) + && _parser.recv("OK")) { + _serial.set_baud(_baudrate); +#if DEVICE_SERIAL_FC + switch (_flow_control) { + case 1: + _serial.set_flow_control(SerialBase::RTS, _rts); + break; + case 2: + _serial.set_flow_control(SerialBase::CTS, _cts); + break; + case 3: + _serial.set_flow_control(SerialBase::RTSCTS, _rts, _cts); + break; + case 0: + default: + // do nothing + break; + } +#endif + } + + return true; + } + } + + return false; +} + +bool ESP32::dhcp(bool enabled, int mode) +{ + //only 3 valid modes + if (mode < 0 || mode > 2) { + return false; + } + + _smutex.lock(); + startup(); + bool done = _parser.send("AT+CWDHCP=%d,%d", enabled?1:0, mode) + && _parser.recv("OK"); + _smutex.unlock(); + + return done; +} + +bool ESP32::connect(const char *ap, const char *passPhrase) +{ + bool ret; + + _wifi_status = STATUS_DISCONNECTED; + + _smutex.lock(); + startup(); + + setTimeout(ESP32_CONNECT_TIMEOUT); + ret = _parser.send("AT+CWJAP=\"%s\",\"%s\"", ap, passPhrase) + && _parser.recv("OK"); + setTimeout(); + _smutex.unlock(); + return ret; +} + +bool ESP32::config_soft_ap(const char *ap, const char *passPhrase, uint8_t chl, uint8_t ecn) +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CWSAP=\"%s\",\"%s\",%hhu,%hhu", ap, passPhrase, chl, ecn) + && _parser.recv("OK"); + _smutex.unlock(); + return ret; +} + +bool ESP32::get_ssid(char *ap) +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CWJAP?") + && _parser.recv("+CWJAP:\"%33[^\"]\",", ap) + && _parser.recv("OK"); + _smutex.unlock(); + return ret; +} + +bool ESP32::disconnect(void) +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CWQAP") && _parser.recv("OK"); + _smutex.unlock(); + return ret; +} + +const char *ESP32::getIPAddress(void) +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CIFSR") + && _parser.recv("+CIFSR:STAIP,\"%15[^\"]\"", _ip_buffer) + && _parser.recv("OK"); + _smutex.unlock(); + if (!ret) { + return 0; + } + return _ip_buffer; +} + +const char *ESP32::getIPAddress_ap(void) +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CIFSR") + && _parser.recv("+CIFSR:APIP,\"%15[^\"]\"", _ip_buffer_ap) + && _parser.recv("OK"); + _smutex.unlock(); + if (!ret) { + return 0; + } + return _ip_buffer_ap; +} + +const char *ESP32::getMACAddress(void) +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CIFSR") + && _parser.recv("+CIFSR:STAMAC,\"%17[^\"]\"", _mac_buffer) + && _parser.recv("OK"); + _smutex.unlock(); + + if (!ret) { + return 0; + } + return _mac_buffer; +} + +const char *ESP32::getMACAddress_ap(void) +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CIFSR") + && _parser.recv("+CIFSR:APMAC,\"%17[^\"]\"", _mac_buffer_ap) + && _parser.recv("OK"); + _smutex.unlock(); + + if (!ret) { + return 0; + } + return _mac_buffer_ap; +} + +const char *ESP32::getGateway() +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CIPSTA?") + && _parser.recv("+CIPSTA:gateway:\"%15[^\"]\"", _gateway_buffer) + && _parser.recv("OK"); + _smutex.unlock(); + + if (!ret) { + return 0; + } + return _gateway_buffer; +} + +const char *ESP32::getGateway_ap() +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CIPAP?") + && _parser.recv("+CIPAP:gateway:\"%15[^\"]\"", _gateway_buffer_ap) + && _parser.recv("OK"); + _smutex.unlock(); + + if (!ret) { + return 0; + } + return _gateway_buffer_ap; +} + +const char *ESP32::getNetmask() +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CIPSTA?") + && _parser.recv("+CIPSTA:netmask:\"%15[^\"]\"", _netmask_buffer) + && _parser.recv("OK"); + _smutex.unlock(); + + if (!ret) { + return 0; + } + return _netmask_buffer; +} + +const char *ESP32::getNetmask_ap() +{ + bool ret; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CIPAP?") + && _parser.recv("+CIPAP:netmask:\"%15[^\"]\"", _netmask_buffer_ap) + && _parser.recv("OK"); + _smutex.unlock(); + + if (!ret) { + return 0; + } + return _netmask_buffer_ap; +} + +int8_t ESP32::getRSSI() +{ + bool ret; + int8_t rssi; + char ssid[33]; + char bssid[18]; + + _smutex.lock(); + startup(); + ret = _parser.send("AT+CWJAP?") + && _parser.recv("+CWJAP:\"%32[^\"]\",\"%17[^\"]\"", ssid, bssid) + && _parser.recv("OK"); + if (!ret) { + _smutex.unlock(); + return 0; + } + + ret = _parser.send("AT+CWLAP=\"%s\",\"%s\"", ssid, bssid) + && _parser.recv("+CWLAP:(%*d,\"%*[^\"]\",%hhd,", &rssi) + && _parser.recv("OK"); + _smutex.unlock(); + + if (!ret) { + return 0; + } + + return rssi; +} + +int ESP32::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned cnt = 0; + nsapi_wifi_ap_t ap; + + if (!init_end) { + _smutex.lock(); + startup(); + _smutex.unlock(); + ThisThread::sleep_for(1500); + } + + _smutex.lock(); + setTimeout(5000); + if (!_parser.send("AT+CWLAP")) { + _smutex.unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + + while (recv_ap(&ap)) { + if (cnt < limit) { + res[cnt] = WiFiAccessPoint(ap); + } + + cnt++; + if ((limit != 0) && (cnt >= limit)) { + break; + } + setTimeout(500); + } + setTimeout(10); + _parser.recv("OK"); + setTimeout(); + _smutex.unlock(); + + return cnt; +} + +bool ESP32::isConnected(void) +{ + return getIPAddress() != 0; +} + +bool ESP32::open(const char *type, int id, const char* addr, int port, int opt) +{ + bool ret; + + if (id >= SOCKET_COUNT) { + return false; + } + _cbs[id].Notified = 0; + + _smutex.lock(); + startup(); + setTimeout(500); + if (opt != 0) { + ret = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d, %d", id, type, addr, port, opt) + && _parser.recv("OK"); + } else { + ret = _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port) + && _parser.recv("OK"); + } + setTimeout(); + _clear_socket_packets(id); + _smutex.unlock(); + + return ret; +} + +bool ESP32::send(int id, const void *data, uint32_t amount) +{ + int send_size; + bool ret; + int error_cnt = 0; + int index = 0; + + _cbs[id].Notified = 0; + if (amount == 0) { + return true; + } + + //May take a second try if device is busy + _smutex.lock(); + while (error_cnt < 2) { + if (((_id_bits & (1 << id)) == 0) + || ((_id_bits_close & (1 << id)) != 0)) { + _smutex.unlock(); + return false; + } + send_size = amount; + if (send_size > 2048) { + send_size = 2048; + } + startup(); + setTimeout(ESP32_SEND_TIMEOUT); + ret = _parser.send("AT+CIPSEND=%d,%d", id, send_size) + && _parser.recv(">") + && (_parser.write((char*)data + index, (int)send_size) >= 0) + && _parser.recv("SEND OK"); + setTimeout(); + if (ret) { + amount -= send_size; + index += send_size; + error_cnt = 0; + if (amount == 0) { + _smutex.unlock(); + return true; + } + } else { + error_cnt++; + } + } + _smutex.unlock(); + + return false; +} + +void ESP32::_packet_handler() +{ + int id; + int amount; + uint32_t tmp_timeout; + + // parse out the packet + if (!_parser.recv(",%d,%d:", &id, &amount)) { + return; + } + + struct packet *packet = (struct packet*)malloc( + sizeof(struct packet) + amount); + if (!packet) { + return; + } + + packet->id = id; + packet->len = amount; + packet->next = 0; + packet->index = 0; + + tmp_timeout = last_timeout_ms; + setTimeout(500); + if (!(_parser.read((char*)(packet + 1), amount))) { + free(packet); + setTimeout(tmp_timeout); + return; + } + + // append to packet list + *_packets_end = packet; + _packets_end = &packet->next; +} + +int32_t ESP32::recv(int id, void *data, uint32_t amount, uint32_t timeout) +{ + struct packet **p; + uint32_t idx = 0; + + _cbs[id].Notified = 0; + + _smutex.lock(); + setTimeout(timeout); + if (_rts == NC) { + while (_parser.process_oob()); // Poll for inbound packets + } else { + _parser.process_oob(); // Poll for inbound packets + } + setTimeout(); + + // check if any packets are ready for us + p = &_packets; + while (*p) { + if ((*p)->id == id) { + struct packet *q = *p; + + if (q->len <= amount) { // Return and remove full packet + memcpy(&(((uint8_t *)data)[idx]), (uint8_t*)(q+1) + q->index, q->len); + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + idx += q->len; + amount -= q->len; + free(q); + } else { // return only partial packet + memcpy(&(((uint8_t *)data)[idx]), (uint8_t*)(q+1) + q->index, amount); + q->len -= amount; + q->index += amount; + idx += amount; + break; + } + } else { + p = &(*p)->next; + } + } + _smutex.unlock(); + + if (idx > 0) { + return idx; + } else if (((_id_bits & (1 << id)) == 0) || ((_id_bits_close & (1 << id)) != 0)) { + return -2; + } else { + return -1; + } +} + +void ESP32::_clear_socket_packets(int id) +{ + struct packet **p = &_packets; + + while (*p) { + if ((*p)->id == id || id == ESP32_ALL_SOCKET_IDS) { + struct packet *q = *p; + + if (_packets_end == &(*p)->next) { + _packets_end = p; // Set last packet next field/_packets + } + *p = (*p)->next; + + free(q); + } else { + // Point to last packet next field + p = &(*p)->next; + } + } +} + +bool ESP32::close(int id, bool wait_close) +{ + if (wait_close) { + _smutex.lock(); + for (int j = 0; j < 2; j++) { + if (((_id_bits & (1 << id)) == 0) + || ((_id_bits_close & (1 << id)) != 0)) { + _id_bits_close &= ~(1 << id); + _ids[id] = false; + _clear_socket_packets(id); + _smutex.unlock(); + return true; + } + startup(); + setTimeout(500); + _parser.process_oob(); // Poll for inbound packets + setTimeout(); + } + _smutex.unlock(); + } + + //May take a second try if device is busy + for (unsigned i = 0; i < 2; i++) { + _smutex.lock(); + if ((_id_bits & (1 << id)) == 0) { + _id_bits_close &= ~(1 << id); + _ids[id] = false; + _clear_socket_packets(id); + _smutex.unlock(); + return true; + } + startup(); + setTimeout(500); + if (_parser.send("AT+CIPCLOSE=%d", id) + && _parser.recv("OK")) { + setTimeout(); + _clear_socket_packets(id); + _id_bits_close &= ~(1 << id); + _ids[id] = false; + _smutex.unlock(); + return true; + } + setTimeout(); + _smutex.unlock(); + } + + _ids[id] = false; + return false; +} + +void ESP32::setTimeout(uint32_t timeout_ms) +{ + last_timeout_ms = timeout_ms; + _parser.set_timeout(timeout_ms); +} + +bool ESP32::readable() +{ + return _serial.FileHandle::readable(); +} + +bool ESP32::writeable() +{ + return _serial.FileHandle::writable(); +} + +void ESP32::socket_attach(int id, void (*callback)(void *), void *data) +{ + _cbs[id].callback = callback; + _cbs[id].data = data; + _cbs[id].Notified = 0; +} + +bool ESP32::recv_ap(nsapi_wifi_ap_t *ap) +{ + int sec; + bool ret = _parser.recv("+CWLAP:(%d,\"%32[^\"]\",%hhd,\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",%hhu)", &sec, ap->ssid, + &ap->rssi, &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], + &ap->bssid[5], &ap->channel); + + ap->security = sec < 5 ? (nsapi_security_t)sec : NSAPI_SECURITY_UNKNOWN; + + return ret; +} + +void ESP32::_connect_handler_0() { socket_handler(true, 0); } +void ESP32::_connect_handler_1() { socket_handler(true, 1); } +void ESP32::_connect_handler_2() { socket_handler(true, 2); } +void ESP32::_connect_handler_3() { socket_handler(true, 3); } +void ESP32::_connect_handler_4() { socket_handler(true, 4); } +void ESP32::_closed_handler_0() { socket_handler(false, 0); } +void ESP32::_closed_handler_1() { socket_handler(false, 1); } +void ESP32::_closed_handler_2() { socket_handler(false, 2); } +void ESP32::_closed_handler_3() { socket_handler(false, 3); } +void ESP32::_closed_handler_4() { socket_handler(false, 4); } + +void ESP32::_connection_status_handler() +{ + char status[13]; + if (_parser.recv("%12[^\"]\n", status)) { + if (strcmp(status, "CONNECTED\n") == 0) { + _wifi_status = STATUS_CONNECTED; + } else if (strcmp(status, "GOT IP\n") == 0) { + _wifi_status = STATUS_GOT_IP; + } else if (strcmp(status, "DISCONNECT\n") == 0) { + _wifi_status = STATUS_DISCONNECTED; + } else { + return; + } + + if(_wifi_status_cb) { + _wifi_status_cb(_wifi_status); + } + } +} + +int ESP32::get_free_id() +{ + // Look for an unused socket + int id = -1; + + for (int i = 0; i < SOCKET_COUNT; i++) { + if ((!_ids[i]) && ((_id_bits & (1 << i)) == 0)) { + id = i; + _ids[i] = true; + break; + } + } + + return id; +} + +void ESP32::event() { + for (int i = 0; i < SOCKET_COUNT; i++) { + if ((_cbs[i].callback) && (_cbs[i].Notified == 0)) { + _cbs[i].callback(_cbs[i].data); + _cbs[i].Notified = 1; + } + } +} + +bool ESP32::set_network(const char *ip_address, const char *netmask, const char *gateway) +{ + bool ret; + + if (ip_address == NULL) { + return false; + } + + _smutex.lock(); + if ((netmask != NULL) && (gateway != NULL)) { + ret = _parser.send("AT+CIPSTA=\"%s\",\"%s\",\"%s\"", ip_address, gateway, netmask) + && _parser.recv("OK"); + } else { + ret = _parser.send("AT+CIPSTA=\"%s\"", ip_address) + && _parser.recv("OK"); + } + _smutex.unlock(); + + return ret; +} + +bool ESP32::set_network_ap(const char *ip_address, const char *netmask, const char *gateway) +{ + bool ret; + + if (ip_address == NULL) { + return false; + } + + _smutex.lock(); + if ((netmask != NULL) && (gateway != NULL)) { + ret = _parser.send("AT+CIPAP=\"%s\",\"%s\",\"%s\"", ip_address, gateway, netmask) + && _parser.recv("OK"); + } else { + ret = _parser.send("AT+CIPAP=\"%s\"", ip_address) + && _parser.recv("OK"); + } + _smutex.unlock(); + + return ret; +} + +void ESP32::attach_wifi_status(mbed::Callback<void(int8_t)> status_cb) +{ + _wifi_status_cb = status_cb; +} + +int8_t ESP32::get_wifi_status() const +{ + return _wifi_status; +} +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/ESP32/ESP32.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,322 @@ +/* ESP32Interface Example + * Copyright (c) 2015 ARM Limited + * Copyright (c) 2017 Renesas Electronics Corporation + * + * 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 ESP32_H +#define ESP32_H + +#if DEVICE_SERIAL && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_PRESENT) +#include <vector> +#include <stdint.h> +#include <stdlib.h> +#include "drivers/DigitalOut.h" +#include "drivers/SerialBase.h" +#include "drivers/UARTSerial.h" +#include "features/netsocket/nsapi_types.h" +#include "features/netsocket/WiFiAccessPoint.h" +#include "PinNames.h" +#include "platform/ATCmdParser.h" +#include "platform/Callback.h" +#include "platform/mbed_error.h" +#include "rtos/Mutex.h" +#include "rtos/ThisThread.h" + +#ifndef ESP32_CONNECT_TIMEOUT +#define ESP32_CONNECT_TIMEOUT 15000 +#endif +#ifndef ESP32_SEND_TIMEOUT +#define ESP32_SEND_TIMEOUT 2000 +#endif +#ifndef ESP32_RECV_TIMEOUT +#define ESP32_RECV_TIMEOUT 2000 +#endif +#ifndef ESP32_MISC_TIMEOUT +#define ESP32_MISC_TIMEOUT 2000 +#endif + +/** ESP32Interface class. + This is an interface to a ESP32 radio. + */ +class ESP32 +{ +public: + /** + * Static method to create or retrieve the single ESP32 instance + */ + static ESP32 * getESP32Inst(PinName en, PinName io0, PinName tx, PinName rx, bool debug, + PinName rts, PinName cts, int baudrate); + + ESP32(PinName en, PinName io0, PinName tx, PinName rx, bool debug, + PinName rts, PinName cts, int baudrate); + + /** + * Check firmware version of ESP8266 + * + * @return integer firmware version or -1 if firmware query command gives outdated response + */ + int get_firmware_version(void); + + /** + * Sets the Wi-Fi Mode + * + * @param mode mode of WIFI 1-client, 2-host, 3-both + * @return true only if ESP32 was setup correctly + */ + bool set_mode(int mode); + + /** + * Enable/Disable DHCP + * + * @param enabled DHCP enabled when true + * @param mode mode of DHCP 0-softAP, 1-station, 2-both + * @return true only if ESP32 enables/disables DHCP successfully + */ + bool dhcp(bool enabled, int mode); + + /** + * Connect ESP32 to AP + * + * @param ap the name of the AP + * @param passPhrase the password of AP + * @return true only if ESP32 is connected successfully + */ + bool connect(const char *ap, const char *passPhrase); + + /** + * Disconnect ESP32 from AP + * + * @return true only if ESP32 is disconnected successfully + */ + bool disconnect(void); + + /** + * Get the IP address of ESP32 + * + * @return null-teriminated IP address or null if no IP address is assigned + */ + const char *getIPAddress(void); + const char *getIPAddress_ap(void); + + /** + * Get the MAC address of ESP32 + * + * @return null-terminated MAC address or null if no MAC address is assigned + */ + const char *getMACAddress(void); + const char *getMACAddress_ap(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(); + const char *getGateway_ap(); + + /** 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(); + const char *getNetmask_ap(); + + /* Return RSSI for active connection + * + * @return Measured RSSI + */ + int8_t getRSSI(); + + /** + * Check if ESP32 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); + + /** + * 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 + * @param addr the IP address of the destination + * @param opt type=" UDP" : UDP socket's local port, zero means any + * type=" TCP" : TCP connection's keep alive time, zero means disabled + * @return true only if socket opened successfully + */ + bool open(const char *type, int id, const char* addr, int port, int opt = 0); + + /** + * 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, uint32_t timeout = ESP32_RECV_TIMEOUT); + + /** + * Closes a socket + * + * @param id id of socket to close, valid only 0-4 + * @param wait_close + * @return true only if socket is closed successfully + */ + bool close(int id, bool wait_close = false); + + /** + * Allows timeout to be changed between commands + * + * @param timeout_ms timeout of the connection + */ + void setTimeout(uint32_t timeout_ms = ESP32_MISC_TIMEOUT); + + /** + * Checks if data is available + */ + bool readable(); + + /** + * Checks if data can be written + */ + bool writeable(); + + void socket_attach(int id, void (*callback)(void *), void *data); + int get_free_id(); + + bool config_soft_ap(const char *ap, const char *passPhrase, uint8_t chl, uint8_t ecn); + + bool restart(); + bool get_ssid(char *ap); + bool cre_server(int port); + bool del_server(); + bool accept(int * p_id); + + bool set_network(const char *ip_address, const char *netmask, const char *gateway); + bool set_network_ap(const char *ip_address, const char *netmask, const char *gateway); + + /** + * 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_wifi_status(mbed::Callback<void(int8_t)> status_cb); + + /** Get the connection status + * + * @return The connection status according to ConnectionStatusType + */ + int8_t get_wifi_status() const; + + static const int8_t WIFIMODE_STATION = 1; + static const int8_t WIFIMODE_SOFTAP = 2; + static const int8_t WIFIMODE_STATION_SOFTAP = 3; + static const int8_t SOCKET_COUNT = 5; + + static const int8_t STATUS_DISCONNECTED = 0; + static const int8_t STATUS_CONNECTED = 1; + static const int8_t STATUS_GOT_IP = 2; + +private: + mbed::DigitalOut * _p_wifi_en; + mbed::DigitalOut * _p_wifi_io0; + bool init_end; + mbed::UARTSerial _serial; + mbed::ATCmdParser _parser; + struct packet { + struct packet *next; + int id; + uint32_t len; + uint32_t index; + // data follows + } *_packets, **_packets_end; + int _wifi_mode; + int _baudrate; + PinName _rts; + PinName _cts; + int _flow_control; + uint32_t last_timeout_ms; + + std::vector<int> _accept_id; + uint32_t _id_bits; + uint32_t _id_bits_close; + bool _server_act; + rtos::Mutex _smutex; // Protect serial port access + static ESP32 * instESP32; + int8_t _wifi_status; + mbed::Callback<void(int8_t)> _wifi_status_cb; + + bool _ids[SOCKET_COUNT]; + struct { + void (*callback)(void *); + void *data; + int Notified; + } _cbs[SOCKET_COUNT]; + + bool startup(); + bool reset(void); + void debugOn(bool debug); + void socket_handler(bool connect, int id); + void _connect_handler_0(); + void _connect_handler_1(); + void _connect_handler_2(); + void _connect_handler_3(); + void _connect_handler_4(); + void _closed_handler_0(); + void _closed_handler_1(); + void _closed_handler_2(); + void _closed_handler_3(); + void _closed_handler_4(); + void _connection_status_handler(); + void _packet_handler(); + void _clear_socket_packets(int id); + void event(); + bool recv_ap(nsapi_wifi_ap_t *ap); + + char _ip_buffer[16]; + char _gateway_buffer[16]; + char _netmask_buffer[16]; + char _mac_buffer[18]; + + char _ip_buffer_ap[16]; + char _gateway_buffer_ap[16]; + char _netmask_buffer_ap[16]; + char _mac_buffer_ap[18]; +}; +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/ESP32Interface.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,221 @@ +/* ESP32 implementation of NetworkInterfaceAPI + * Copyright (c) 2017 Renesas Electronics Corporation + * + * 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 "ESP32Interface.h" + +// ESP32Interface implementation +ESP32Interface::ESP32Interface() : + ESP32Stack(MBED_CONF_ESP32_WIFI_EN, MBED_CONF_ESP32_WIFI_IO0, MBED_CONF_ESP32_WIFI_TX, MBED_CONF_ESP32_WIFI_RX, MBED_CONF_ESP32_WIFI_DEBUG, MBED_CONF_ESP32_WIFI_RTS, MBED_CONF_ESP32_WIFI_CTS, MBED_CONF_ESP32_WIFI_BAUDRATE), + _dhcp(true), + _ap_ssid(), + _ap_pass(), + _ap_sec(NSAPI_SECURITY_NONE), + _ip_address(), + _netmask(), + _gateway(), + _connection_status(NSAPI_STATUS_DISCONNECTED), + _connection_status_cb(NULL) +{ + _esp->attach_wifi_status(callback(this, &ESP32Interface::wifi_status_cb)); +} + +ESP32Interface::ESP32Interface(PinName en, PinName io0, PinName tx, PinName rx, bool debug, + PinName rts, PinName cts, int baudrate) : + ESP32Stack(en, io0, tx, rx, debug, rts, cts, baudrate), + _dhcp(true), + _ap_ssid(), + _ap_pass(), + _ap_sec(NSAPI_SECURITY_NONE), + _ip_address(), + _netmask(), + _gateway(), + _connection_status(NSAPI_STATUS_DISCONNECTED), + _connection_status_cb(NULL) +{ + _esp->attach_wifi_status(callback(this, &ESP32Interface::wifi_status_cb)); +} + +ESP32Interface::ESP32Interface(PinName tx, PinName rx, bool debug) : + ESP32Stack(NC, NC, tx, rx, debug, NC, NC, 230400), + _dhcp(true), + _ap_ssid(), + _ap_pass(), + _ap_sec(NSAPI_SECURITY_NONE), + _ip_address(), + _netmask(), + _gateway(), + _connection_status(NSAPI_STATUS_DISCONNECTED), + _connection_status_cb(NULL) +{ + _esp->attach_wifi_status(callback(this, &ESP32Interface::wifi_status_cb)); +} + +nsapi_error_t ESP32Interface::set_network(const char *ip_address, const char *netmask, const char *gateway) +{ + _dhcp = false; + + strncpy(_ip_address, ip_address ? ip_address : "", sizeof(_ip_address)); + _ip_address[sizeof(_ip_address) - 1] = '\0'; + strncpy(_netmask, netmask ? netmask : "", sizeof(_netmask)); + _netmask[sizeof(_netmask) - 1] = '\0'; + strncpy(_gateway, gateway ? gateway : "", sizeof(_gateway)); + _gateway[sizeof(_gateway) - 1] = '\0'; + + return NSAPI_ERROR_OK; +} + +nsapi_error_t ESP32Interface::set_dhcp(bool dhcp) +{ + _dhcp = dhcp; + + return NSAPI_ERROR_OK; +} + +int ESP32Interface::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 ESP32Interface::connect() +{ + if (!_esp->dhcp(_dhcp, 1)) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + if (!_dhcp) { + if (!_esp->set_network(_ip_address, _netmask, _gateway)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } + + set_connection_status(NSAPI_STATUS_CONNECTING); + if (!_esp->connect(_ap_ssid, _ap_pass)) { + set_connection_status(NSAPI_STATUS_DISCONNECTED); + return NSAPI_ERROR_NO_CONNECTION; + } + + return NSAPI_ERROR_OK; +} + +int ESP32Interface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + 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; + + return 0; +} + +int ESP32Interface::set_channel(uint8_t channel) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int ESP32Interface::disconnect() +{ + if (!_esp->disconnect()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return NSAPI_ERROR_OK; +} + +const char *ESP32Interface::get_ip_address() +{ + return _esp->getIPAddress(); +} + +const char *ESP32Interface::get_mac_address() +{ + return _esp->getMACAddress(); +} + +const char *ESP32Interface::get_gateway() +{ + return _esp->getGateway(); +} + +const char *ESP32Interface::get_netmask() +{ + return _esp->getNetmask(); +} + +int8_t ESP32Interface::get_rssi() +{ + return _esp->getRSSI(); +} + +int ESP32Interface::scan(WiFiAccessPoint *res, unsigned count) +{ + return _esp->scan(res, count); +} + +void ESP32Interface::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) +{ + _connection_status_cb = status_cb; +} + +nsapi_connection_status_t ESP32Interface::get_connection_status() const +{ + return _connection_status; +} + +void ESP32Interface::set_connection_status(nsapi_connection_status_t connection_status) +{ + if (_connection_status != connection_status) { + _connection_status = connection_status; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status); + } + } +} + +void ESP32Interface::wifi_status_cb(int8_t wifi_status) +{ + switch (wifi_status) { + case ESP32::STATUS_DISCONNECTED: + set_connection_status(NSAPI_STATUS_DISCONNECTED); + break; + case ESP32::STATUS_GOT_IP: + set_connection_status(NSAPI_STATUS_GLOBAL_UP); + break; + case ESP32::STATUS_CONNECTED: + default: + // do nothing + break; + } +} + +#if MBED_CONF_ESP32_PROVIDE_DEFAULT + +WiFiInterface *WiFiInterface::get_default_instance() { + static ESP32Interface esp32; + return &esp32; +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/ESP32Interface.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,234 @@ +/* ESP32 implementation of NetworkInterfaceAPI + * Copyright (c) 2017 Renesas Electronics Corporation + * + * 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 ESP32_INTERFACE_H +#define ESP32_INTERFACE_H + +#include "mbed.h" +#include "ESP32Stack.h" + +/** ESP32Interface class + * Implementation of the NetworkStack for the ESP32 + */ +class ESP32Interface : public ESP32Stack, public WiFiInterface +{ +public: + /** ESP32Interface lifetime + * Configuration defined in mbed_lib.json + */ + ESP32Interface(); + + /** ESP32Interface lifetime + * @param en EN pin (If not used this pin, please set "NC") + * @param io0 IO0 pin (If not used this pin, please set "NC") + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging + * @param rts RTS pin + * @param cts CTS pin + * @param baudrate The baudrate of the serial port (default = 230400). + */ + ESP32Interface(PinName en, PinName io0, PinName tx, PinName rx, bool debug = false, + PinName rts = NC, PinName cts = NC, int baudrate = 230400); + + /** ESP32Interface lifetime + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging + */ + ESP32Interface(PinName tx, PinName rx, bool debug = false); + + /** Set a static IP address + * + * Configures this network interface to use a static IP address. + * Implicitly disables DHCP, which can be enabled in set_dhcp. + * Requires that the network is disconnected. + * + * @param ip_address Null-terminated representation of the local IP address + * @param netmask Null-terminated representation of the local network mask + * @param gateway Null-terminated representation of the local gateway + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_network( + const char *ip_address, const char *netmask, const char *gateway); + + /** Enable or disable DHCP on the network + * + * Enables DHCP on connecting the network. Defaults to enabled unless + * a static IP address has been assigned. Requires that the network is + * disconnected. + * + * @param dhcp True to enable DHCP + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_dhcp(bool dhcp); + + /** 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); + + /** 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; + + /** Register callback for status reporting + * + * The specified status callback function will be called on status changes + * on the network. The parameters on the callback are the event type and + * event-type dependent reason parameter. + * + * In ESP32 the callback will be called when processing OOB-messages via + * AT-parser. Do NOT call any ESP8266Interface -functions or do extensive + * processing in the callback. + * + * @param status_cb The callback for status changes + */ + virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb); + + /** Get the connection status + * + * @return The connection status according to ConnectionStatusType + */ + virtual nsapi_connection_status_t get_connection_status() const; + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack() + { + return this; + } + +private: + bool _dhcp; + char _ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + char _ap_pass[64]; /* The longest allowed passphrase */ + nsapi_security_t _ap_sec; + char _ip_address[NSAPI_IPv6_SIZE]; + char _netmask[NSAPI_IPv4_SIZE]; + char _gateway[NSAPI_IPv4_SIZE]; + nsapi_connection_status_t _connection_status; + Callback<void(nsapi_event_t, intptr_t)> _connection_status_cb; + + void set_connection_status(nsapi_connection_status_t connection_status); + void wifi_status_cb(int8_t wifi_status); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/ESP32InterfaceAP.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,205 @@ +/* ESP32 implementation of NetworkInterfaceAPI + * Copyright (c) 2017 Renesas Electronics Corporation + * + * 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 "ESP32InterfaceAP.h" + +// ESP32InterfaceAP implementation +ESP32InterfaceAP::ESP32InterfaceAP(PinName en, PinName io0, PinName tx, PinName rx, bool debug, + PinName rts, PinName cts, int baudrate) : + ESP32Stack(en, io0, tx, rx, debug, rts, cts, baudrate), + _dhcp(true), + _own_ch(1), + _own_ssid(), + _own_pass(), + _own_sec(NSAPI_SECURITY_NONE), + _ip_address(), + _netmask(), + _gateway(), + _connection_status(NSAPI_STATUS_DISCONNECTED), + _connection_status_cb(NULL) +{ +} + +ESP32InterfaceAP::ESP32InterfaceAP(PinName tx, PinName rx, bool debug) : + ESP32Stack(NC, NC, tx, rx, debug, NC, NC, 230400), + _dhcp(true), + _own_ch(1), + _own_ssid(), + _own_pass(), + _own_sec(NSAPI_SECURITY_NONE), + _ip_address(), + _netmask(), + _gateway(), + _connection_status(NSAPI_STATUS_DISCONNECTED), + _connection_status_cb(NULL) +{ +} + +nsapi_error_t ESP32InterfaceAP::set_network(const char *ip_address, const char *netmask, const char *gateway) +{ + _dhcp = false; + + strncpy(_ip_address, ip_address ? ip_address : "", sizeof(_ip_address)); + _ip_address[sizeof(_ip_address) - 1] = '\0'; + strncpy(_netmask, netmask ? netmask : "", sizeof(_netmask)); + _netmask[sizeof(_netmask) - 1] = '\0'; + strncpy(_gateway, gateway ? gateway : "", sizeof(_gateway)); + _gateway[sizeof(_gateway) - 1] = '\0'; + + return NSAPI_ERROR_OK; +} + +nsapi_error_t ESP32InterfaceAP::set_dhcp(bool dhcp) +{ + _dhcp = dhcp; + + return NSAPI_ERROR_OK; +} + +int ESP32InterfaceAP::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + int ret; + + ret = set_credentials(ssid, pass, security); + if (ret != 0) { + return ret; + } + + ret = set_channel(channel); + if (ret != 0) { + return ret; + } + + return connect(); +} + +int ESP32InterfaceAP::connect() +{ + if (!_esp->set_mode(ESP32::WIFIMODE_STATION_SOFTAP)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + if (!_esp->dhcp(_dhcp, 1)) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + if (!_dhcp) { + if (!_esp->set_network_ap(_ip_address, _netmask, _gateway)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } + + if (!_esp->config_soft_ap(_own_ssid, _own_pass, _own_ch, (uint8_t)_own_sec)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + _connection_status = NSAPI_STATUS_GLOBAL_UP; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status); + } + + return NSAPI_ERROR_OK; +} + +int ESP32InterfaceAP::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + switch (security) { + case NSAPI_SECURITY_NONE: + case NSAPI_SECURITY_WPA: + case NSAPI_SECURITY_WPA2: + case NSAPI_SECURITY_WPA_WPA2: + _own_sec = security; + break; + case NSAPI_SECURITY_UNKNOWN: + case NSAPI_SECURITY_WEP: + default: + return NSAPI_ERROR_UNSUPPORTED; + } + + memset(_own_ssid, 0, sizeof(_own_ssid)); + strncpy(_own_ssid, ssid, sizeof(_own_ssid)); + + memset(_own_pass, 0, sizeof(_own_pass)); + strncpy(_own_pass, pass, sizeof(_own_pass)); + + return 0; +} + +int ESP32InterfaceAP::set_channel(uint8_t channel) +{ + if (channel != 0) { + _own_ch = channel; + } + + return 0; +} + +int ESP32InterfaceAP::disconnect() +{ + if (!_esp->set_mode(ESP32::WIFIMODE_STATION)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + _connection_status = NSAPI_STATUS_DISCONNECTED; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connection_status); + } + + return NSAPI_ERROR_OK; +} + +const char *ESP32InterfaceAP::get_ip_address() +{ + return _esp->getIPAddress_ap(); +} + +const char *ESP32InterfaceAP::get_mac_address() +{ + return _esp->getMACAddress_ap(); +} + +const char *ESP32InterfaceAP::get_gateway() +{ + return _esp->getGateway_ap(); +} + +const char *ESP32InterfaceAP::get_netmask() +{ + return _esp->getNetmask_ap(); +} + +int8_t ESP32InterfaceAP::get_rssi() +{ + return 0; +} + +int ESP32InterfaceAP::scan(WiFiAccessPoint *res, unsigned count) +{ + return _esp->scan(res, count); +} + +void ESP32InterfaceAP::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb) +{ + _connection_status_cb = status_cb; +} + +nsapi_connection_status_t ESP32InterfaceAP::get_connection_status() const +{ + return _connection_status; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/ESP32InterfaceAP.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,229 @@ +/* ESP32 implementation of NetworkInterfaceAPI + * Copyright (c) 2017 Renesas Electronics Corporation + * + * 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 ESP32_INTERFACE_AP_H +#define ESP32_INTERFACE_AP_H + +#include "mbed.h" +#include "ESP32Stack.h" + + +/** ESP32Interface class + * Implementation of the NetworkStack for the ESP32 + */ +class ESP32InterfaceAP : public ESP32Stack, public WiFiInterface +{ +public: + /** ESP32InterfaceAP lifetime + * @param en EN pin (If not used this pin, please set "NC") + * @param io0 IO0 pin (If not used this pin, please set "NC") + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging + * @param rts RTS pin + * @param cts CTS pin + * @param baudrate The baudrate of the serial port (default = 230400). + */ + ESP32InterfaceAP(PinName en, PinName io0, PinName tx, PinName rx, bool debug = false, + PinName rts = NC, PinName cts = NC, int baudrate = 230400); + + /** ESP32InterfaceAP lifetime + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging + */ + ESP32InterfaceAP(PinName tx, PinName rx, bool debug = false); + + /** Set a static IP address + * + * Configures this network interface to use a static IP address. + * Implicitly disables DHCP, which can be enabled in set_dhcp. + * Requires that the network is disconnected. + * + * @param ip_address Null-terminated representation of the local IP address + * @param netmask Null-terminated representation of the local network mask + * @param gateway Null-terminated representation of the local gateway + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_network( + const char *ip_address, const char *netmask, const char *gateway); + + /** Enable or disable DHCP on the network + * + * Enables DHCP on connecting the network. Defaults to enabled unless + * a static IP address has been assigned. Requires that the network is + * disconnected. + * + * @param dhcp True to enable DHCP + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_dhcp(bool dhcp); + + /** 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); + + /** 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; + + /** Register callback for status reporting + * + * The specified status callback function will be called on status changes + * on the network. The parameters on the callback are the event type and + * event-type dependent reason parameter. + * + * In ESP32 the callback will be called when processing OOB-messages via + * AT-parser. Do NOT call any ESP8266Interface -functions or do extensive + * processing in the callback. + * + * @param status_cb The callback for status changes + */ + virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb); + + /** Get the connection status + * + * @return The connection status according to ConnectionStatusType + */ + virtual nsapi_connection_status_t get_connection_status() const; + + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack() + { + return this; + } + +private: + bool _dhcp; + uint8_t _own_ch; + char _own_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + char _own_pass[64]; /* The longest allowed passphrase */ + nsapi_security_t _own_sec; + char _ip_address[NSAPI_IPv6_SIZE]; + char _netmask[NSAPI_IPv4_SIZE]; + char _gateway[NSAPI_IPv4_SIZE]; + nsapi_connection_status_t _connection_status; + Callback<void(nsapi_event_t, intptr_t)> _connection_status_cb; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/ESP32Stack.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,327 @@ +/* ESP32 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * Copyright (c) 2017 Renesas Electronics Corporation + * + * 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 "ESP32Stack.h" + +// ESP32Stack implementation +ESP32Stack::ESP32Stack(PinName en, PinName io0, PinName tx, PinName rx, bool debug, + PinName rts, PinName cts, int baudrate) +{ + _esp = ESP32::getESP32Inst(en, io0, tx, rx, debug, rts, cts, baudrate); + memset(_local_ports, 0, sizeof(_local_ports)); +} + +struct esp32_socket { + int id; + nsapi_protocol_t proto; + bool connected; + SocketAddress addr; + int keepalive; // TCP + bool accept_id; + bool tcp_server; +}; + +int ESP32Stack::socket_open(void **handle, nsapi_protocol_t proto) +{ + // Look for an unused socket + int id = _esp->get_free_id(); + + if (id == -1) { + return NSAPI_ERROR_NO_SOCKET; + } + + struct esp32_socket *socket = new struct esp32_socket; + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + socket->id = id; + socket->proto = proto; + socket->connected = false; + socket->keepalive = 0; + socket->accept_id = false; + socket->tcp_server = false; + *handle = socket; + return 0; +} + +int ESP32Stack::socket_close(void *handle) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + int err = 0; + + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (!_esp->close(socket->id, socket->accept_id)) { + err = NSAPI_ERROR_DEVICE_ERROR; + } + + if (socket->tcp_server) { + _esp->del_server(); + } + _local_ports[socket->id] = 0; + + delete socket; + return err; +} + +int ESP32Stack::socket_bind(void *handle, const SocketAddress &address) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (socket->proto == NSAPI_UDP) { + if(address.get_addr().version != NSAPI_UNSPEC) { + return NSAPI_ERROR_UNSUPPORTED; + } + + for(int id = 0; id < ESP32::SOCKET_COUNT; id++) { + if(_local_ports[id] == address.get_port() && id != socket->id) { // Port already reserved by another socket + return NSAPI_ERROR_PARAMETER; + } else if (id == socket->id && socket->connected) { + return NSAPI_ERROR_PARAMETER; + } + } + _local_ports[socket->id] = address.get_port(); + return 0; + } + + socket->addr = address; + return 0; +} + +int ESP32Stack::socket_listen(void *handle, int backlog) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + (void)backlog; + + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (socket->proto != NSAPI_TCP) { + return NSAPI_ERROR_UNSUPPORTED; + } + + if (!_esp->cre_server(socket->addr.get_port())) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + socket->tcp_server = true; + return 0; +} + +int ESP32Stack::socket_connect(void *handle, const SocketAddress &addr) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (socket->proto == NSAPI_UDP) { + if (!_esp->open("UDP", socket->id, addr.get_ip_address(), addr.get_port(), _local_ports[socket->id])) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } else { + if (!_esp->open("TCP", socket->id, addr.get_ip_address(), addr.get_port(), socket->keepalive)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } + + socket->connected = true; + return 0; +} + +int ESP32Stack::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + struct esp32_socket *socket_new = new struct esp32_socket; + int id; + + if (!socket_new) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (!_esp->accept(&id)) { + delete socket_new; + return NSAPI_ERROR_NO_SOCKET; + } + + socket_new->id = id; + socket_new->proto = NSAPI_TCP; + socket_new->connected = true; + socket_new->accept_id = true; + socket_new->tcp_server = false; + *socket = socket_new; + + return 0; +} + +int ESP32Stack::socket_send(void *handle, const void *data, unsigned size) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (!_esp->send(socket->id, data, size)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return size; +} + +int ESP32Stack::socket_recv(void *handle, void *data, unsigned size) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + int32_t recv = _esp->recv(socket->id, data, size); + if (recv == -1) { + return NSAPI_ERROR_WOULD_BLOCK; + } else if (recv < 0) { + return NSAPI_ERROR_NO_SOCKET; + } else { + // do nothing + } + + return recv; +} + +int ESP32Stack::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (socket->connected && socket->addr != addr) { + if (!_esp->close(socket->id, socket->accept_id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + socket->connected = false; + } + + if (!socket->connected) { + int err = socket_connect(socket, addr); + if (err < 0) { + return err; + } + socket->addr = addr; + } + + return socket_send(socket, data, size); +} + +int ESP32Stack::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + int ret = socket_recv(socket, data, size); + if (ret >= 0 && addr) { + *addr = socket->addr; + } + + return ret; +} + +void ESP32Stack::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!socket) { + return; + } + + _esp->socket_attach(socket->id, callback, data); +} + +nsapi_error_t ESP32Stack::setsockopt(nsapi_socket_t handle, int level, + int optname, const void *optval, unsigned optlen) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!optlen) { + return NSAPI_ERROR_PARAMETER; + } else if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) { + switch (optname) { + case NSAPI_KEEPALIVE: { + if(socket->connected) {// ESP32 limitation, keepalive needs to be given before connecting + return NSAPI_ERROR_UNSUPPORTED; + } + + if (optlen == sizeof(int)) { + int secs = *(int *)optval; + if (secs >= 0 && secs <= 7200) { + socket->keepalive = secs; + return NSAPI_ERROR_OK; + } + } + return NSAPI_ERROR_PARAMETER; + } + } + } + + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t ESP32Stack::getsockopt(nsapi_socket_t handle, int level, + int optname, void *optval, unsigned *optlen) +{ + struct esp32_socket *socket = (struct esp32_socket *)handle; + + if (!optval || !optlen) { + return NSAPI_ERROR_PARAMETER; + } else if (!socket) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (level == NSAPI_SOCKET && socket->proto == NSAPI_TCP) { + switch (optname) { + case NSAPI_KEEPALIVE: { + if(*optlen > sizeof(int)) { + *optlen = sizeof(int); + } + memcpy(optval, &(socket->keepalive), *optlen); + return NSAPI_ERROR_OK; + } + } + } + + return NSAPI_ERROR_UNSUPPORTED; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/ESP32Stack.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,177 @@ +/* ESP32 implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * Copyright (c) 2017 Renesas Electronics Corporation + * + * 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 ESP32_STACK_H +#define ESP32_STACK_H + +#include "mbed.h" +#include "ESP32.h" + +/** ESP32Stack class + * Implementation of the NetworkStack for the ESP32 + */ +class ESP32Stack : public NetworkStack +{ +protected: + /** ESP32Stack lifetime + * @param en EN pin + * @param io0 IO0 pin + * @param tx TX pin + * @param rx RX pin + * @param debug Enable debugging + * @param rts RTS pin + * @param cts CTS pin + * @param baudrate The baudrate of the serial port. + */ + ESP32Stack(PinName en, PinName io0, PinName tx, PinName rx, bool debug, + PinName rts, PinName cts, int baudrate); + +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); + + /** Set stack-specific socket options + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level, + int optname, const void *optval, unsigned optlen); + + /** Get stack-specific socket options + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level, + int optname, void *optval, unsigned *optlen); + +protected: + ESP32 *_esp; + uint16_t _local_ports[ESP32::SOCKET_COUNT]; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/README.md Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,9 @@ +# The ESP32 WiFi driver for Mbed OS +The Mbed OS driver for the ESP32 WiFi module. + +## Firmware version +How to write mbed-os compatible firmware : +https://github.com/d-kato/GR-Boards_ESP32_Serial_Bridge + +## Restrictions +- Setting up an UDP server is not possible
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ESP32/mbed_lib.json Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,58 @@ +{ + "name": "esp32", + "config": { + "wifi-en": { + "help": "Enable pin", + "value": "NC" + }, + "wifi-io0": { + "help": "IO0 pin", + "value": "NC" + }, + "wifi-tx": { + "help": "Serial TX pin", + "value": "NC" + }, + "wifi-rx": { + "help": "Serial RX pin", + "value": "NC" + }, + "wifi-debug": { + "help": "Enable debugging", + "value": false + }, + "wifi-rts": { + "help": "Serial RTS pin", + "value": "NC" + }, + "wifi-cts": { + "help": "Serial CTS pin", + "value": "NC" + }, + "wifi-baudrate": { + "help": "Serial baudrate", + "value": "230400" + }, + "provide-default": { + "help": "Provide default WifiInterface. [true/false]", + "value": false + } + }, + "target_overrides": { + "GR_LYCHEE": { + "esp32.wifi-en" : "P5_3", + "esp32.wifi-io0": "P3_14", + "esp32.wifi-tx" : "P7_1", + "esp32.wifi-rx" : "P0_1", + "esp32.wifi-rts": "P7_7", + "esp32.wifi-cts": "P7_6", + "esp32.provide-default": true + }, + "RZ_A1H": { + "esp32.wifi-en" : "P3_10", + "esp32.wifi-io0": "P3_9", + "esp32.wifi-tx" : "P2_14", + "esp32.wifi-rx" : "P2_15" + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1.lib Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/#90ba1f95ce7d6f6e4e0ead265152ce0c728cbdad
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/BlockExecuter.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,22 @@ +#ifndef BLOCK_EXEC_H +#define BLOCK_EXEC_H + +#include "mbed.h" + +/* Helper class to execute something whenever entering/leaving a basic block */ +class BlockExecuter { +public: + BlockExecuter(Callback<void()> exit_cb, Callback<void()> enter_cb = Callback<void()>()) : + _exit_cb(exit_cb) { + if((bool)enter_cb) enter_cb(); + } + + ~BlockExecuter(void) { + _exit_cb(); + } + +private: + Callback<void()> _exit_cb; +}; + +#endif //BLOCK_EXEC_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/README.md Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,76 @@ +# Prototype Driver for STM Wi-Fi Expansion Boards based on the SPWFxx Module for STM32 Nucleo # + +## Currently supported expansion boards + * [X-NUCLEO-IDW01M1](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-connect-hw/x-nucleo-idw01m1.html), by setting `mbed` configuration variable `idw0xx1.expansion-board` to value `IDW01M1` + * [X-NUCLEO-IDW04A1](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-connect-hw/x-nucleo-idw04a1.html), by setting `mbed` configuration variable `idw0xx1.expansion-board` to value `IDW04A1`. You might also need to define macro `IDW04A1_WIFI_HW_BUG_WA` _(see beyond)_. + +```diff +- **The boards above are now DEPRECATED and NOT RECOMMENDED FOR NEW DESIGN.** +``` + +## Configuration examples + +### Generic concepts + +For the ones, which might be less familiar with the **"The mbed configuration system"** in general, here is a [link](https://docs.mbed.com/docs/mbed-os-handbook/en/latest/advanced/config_system/) which points to the latest version of the respective _mbed OS 5 handbook tutorial_. + +Furthermore, with respect to this driver, pls. refer to files [`mbed_app_idw01m1.json`](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/blob/master/mbed_app_idw01m1.json) and [`mbed_app_idw04a1.json`](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/blob/master/mbed_app_idw04a1.json) regarding additional reference for what is explained beyond. + +### IDW01M1 + +Add the following lines to the `target_overrides`-section of your `mbed_app.json` file. + +``` json + "idw0xx1.expansion-board": "IDW01M1", + "drivers.uart-serial-txbuf-size": 512, + "drivers.uart-serial-rxbuf-size": 512 +``` + +`IDW01M1` is the default value in the [`mbed_lib.json`](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/blob/master/mbed_lib.json) file, so setting the expansion board is not mandatory for `IDW01M1`, while setting the TX & RX buffer sizes is highly recommended. + +### IDW04A1 + +Add the following lines to the `target_overrides`-section of your `mbed_app.json` file. + +``` json + "idw0xx1.expansion-board": "IDW04A1", + "drivers.uart-serial-txbuf-size": 512, + "drivers.uart-serial-rxbuf-size": 512 +``` + +### Further configuration macros + +All configuration options mentioned in this section are optional and when required have to be added to the `macros`-section of your `mbed_app.json` file, e.g.: + +``` json + "macros": [..., "IDW04A1_WIFI_HW_BUG_WA", "SPWFSAXX_RESET_PIN=D7"] +``` + +Beyond you can find the list of available configuration macros each with a short explanation: + * `IDW04A1_WIFI_HW_BUG_WA`: activates the HW bug workaround for `IDW04A1` + * `SPWFSAXX_WAKEUP_PIN`: defines module wakeup pin _(requires value)_ + * `SPWFSAXX_RESET_PIN`: defines module reset pin _(requires value)_ + * `SPWFSAXX_RTS_PIN`: defines RTS pin of the UART device used _(requires value)_ + * `SPWFSAXX_CTS_PIN`: defines CTS pin of the UART device used _(requires value)_ + +**Note**: if the values of both `SPWFSAXX_RTS_PIN` and `SPWFSAXX_CTS_PIN` are different from `NC`, hardware flow control - if available on your development board - will be enabled on the used UART device (provided you are using `mbed-os` version greater than or equal to `v5.7.0`). + + +## Module firmware + +Please make sure that you are using the latest `major.minor` releases of the firmware available for the expansion boards as have been used for the development of this driver. The driver has been developed with the following FW versions installed: +* for [X-NUCLEO-IDW01M1](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-connect-hw/x-nucleo-idw01m1.html): Version 3.5.3 (SPWF01S-170111-665d284) + * for [X-NUCLEO-IDW04A1](http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32-nucleo-expansion-boards/stm32-ode-connect-hw/x-nucleo-idw04a1.html): Version 1.1.0 (SPWF04S-171117-0328fe3). + +Regarding information on how to perform a FW update you may refer to [X-CUBE-WIFI1](http://www.st.com/content/st_com/en/products/embedded-software/mcus-embedded-software/stm32-embedded-software/stm32cube-embedded-software-expansion/x-cube-wifi1.html), especially to document **"X-NUCLEO-IDW0xx1- FW upgrading over UART_v1.2.pdf"** which is contained within folder **"Documentation"** of the X-CUBE-WIFI1 software archive you need to download. + +The actual firmware `.bin` or `.hex` files can be found under +- [STSW-WIFI001](http://www.st.com/content/st_com/en/products/embedded-software/wireless-connectivity-software/stsw-wifi001.html) _for what concerns expansion board_ X-NUCLEO-IDW01M1 _and under_ +- [STSW-WIFI004](http://www.st.com/content/st_com/en/products/embedded-software/wireless-connectivity-software/stsw-wifi004.html) _when considering_ X-NUCLEO-IDW04A1. + + +## Known limitations + + * Like explained in issue [#11](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/issues/11), sockets might fail to close in case they are connected to a streaming server (e.g. a [RFC 864](https://tools.ietf.org/html/rfc864) test server). + * As highlighted by issue [#13](https://github.com/ARMmbed/wifi-x-nucleo-idw01m1/issues/13), the module FW limits the maximum segment size for TCP to 730 bytes, while the maximum UDP datagram length might even be further limited (but usually is also equal to 730 bytes). +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SPWFSA01/SPWFSA01.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,284 @@ +/* SPWFSA01 Device + * 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. + */ + +#include "SPWFSA01.h" +#include "SpwfSAInterface.h" +#include "mbed_debug.h" + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW01M1 + +SPWFSA01::SPWFSA01(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset) +: SPWFSAxx(tx, rx, rts, cts, ifce, debug, wakeup, reset) { +} + +bool SPWFSA01::open(const char *type, int* spwf_id, const char* addr, int port) +{ + int socket_id; + int value; + int trials; + + if(!_parser.send("AT+S.SOCKON=%s,%d,%s,ind", addr, port, type)) + { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA01::open`: error opening socket (%d)\r\n", __LINE__); + return false; + } + + /* handle both response possibilities here before returning + * otherwise module seems to remain in inconsistent state. + */ + + /* wait for first character */ + trials = 0; + while((value = _parser.getc()) < 0) { + if(trials++ > SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + } + + if(value != _cr_) { // Note: this is different to what the spec exactly says + debug_if(_dbg_on, "\r\nSPWF> error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + + if(!_recv_delim_lf()) { // Note: this is different to what the spec exactly says + debug_if(_dbg_on, "\r\nSPWF> error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + + value = _parser.getc(); + switch(value) { + case ' ': + if(_parser.recv("ID: %d\n", &socket_id) + && _recv_ok()) { + debug_if(_dbg_on, "AT^ ID: %d\r\n", socket_id); + + *spwf_id = socket_id; + return true; + } else { + empty_rx_buffer(); + } + break; + case 'E': + if(_parser.recv("RROR: %255[^\n]\n", _msg_buffer) && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ ERROR: %s (%d)\r\n", _msg_buffer, __LINE__); + } else { + debug_if(_dbg_on, "\r\nSPWF> error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + } + break; + default: + debug_if(_dbg_on, "\r\nSPWF> error opening socket (value=%d, %d)\r\n", value, __LINE__); + break; + } + + return false; +} + +int SPWFSA01::_read_in(char* buffer, int spwf_id, uint32_t amount) { + int ret = -1; + + MBED_ASSERT(buffer != NULL); + + /* block asynchronous indications */ + if(!_winds_off()) { + return -1; + } + + /* read in data */ + if(_parser.send("AT+S.SOCKR=%d,%u", spwf_id, (unsigned int)amount)) { + /* set high timeout */ + _parser.set_timeout(SPWF_READ_BIN_TIMEOUT); + /* read in binary data */ + int read = _parser.read(buffer, amount); + /* reset timeout value */ + _parser.set_timeout(_timeout); + if(read > 0) { + if(_recv_ok()) { + ret = amount; + + /* remove from pending sizes + * (MUST be done before next async indications handling (e.g. `_winds_on()`)) */ + _remove_pending_pkt_size(spwf_id, amount); + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to receive OK (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to read binary data (%u:%d), (%s, %d)\r\n", amount, read, __func__, __LINE__); + empty_rx_buffer(); + } + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to send SOCKR (%s, %d)\r\n", __func__, __LINE__); + } + + debug_if(_dbg_on, "\r\nSPWF> %s():\t%d:%d\r\n", __func__, spwf_id, amount); + + /* unblock asynchronous indications */ + _winds_on(); + + return ret; +} + +/* betzw - TODO: improve performance! */ +bool SPWFSA01::_recv_ap(nsapi_wifi_ap_t *ap) +{ + bool ret; + unsigned int channel; + int trials; + + ap->security = NSAPI_SECURITY_UNKNOWN; + + /* check for end of list */ + if(_recv_delim_cr_lf()) { + return false; + } + + /* run to 'horizontal tab' */ + trials = 0; + while(_parser.getc() != '\x09') { + if(trials++ > SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + } + + /* read in next line */ + ret = _parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf(); + + /* parse line - first phase */ + if(ret) { + int val = sscanf(_msg_buffer, + " %*s %hhx:%hhx:%hhx:%hhx:%hhx:%hhx CHAN: %u RSSI: %hhd SSID: \'%*255[^\']\'", + &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], &ap->bssid[5], + &channel, &ap->rssi); + if(val < 8) { + ret = false; + } + } + + /* parse line - second phase */ + if(ret) { // ret == true + char value; + char *rest, *first, *last; + + /* decide about position of `CAPS:` */ + first = strchr(_msg_buffer, '\''); + if(first == NULL) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + last = strrchr(_msg_buffer, '\''); + if((last == NULL) || (last < (first+1))) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + rest = strstr(last, "CAPS:"); + if(rest == NULL) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + + /* substitute '\'' with '\0' */ + *last = '\0'; + + /* copy values */ + memcpy(&ap->ssid, first+1, sizeof(ap->ssid)-1); + ap->ssid[sizeof(ap->ssid)-1] = '\0'; + ap->channel = channel; + + /* skip `CAPS: 0421 ` */ + if(strlen(rest) < 11) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + return false; + } + rest += 11; + + /* get next character */ + value = *rest++; + if(value != 'W') { // no security + ap->security = NSAPI_SECURITY_NONE; + return true; + } + + /* determine security */ + { + char buffer[10]; + + if(!(sscanf(rest, "%s%*[\x20]", (char*)&buffer) > 0)) { // '\0x20' == <space> + return true; + } else if(strncmp("EP", buffer, 10) == 0) { + ap->security = NSAPI_SECURITY_WEP; + return true; + } else if(strncmp("PA2", buffer, 10) == 0) { + ap->security = NSAPI_SECURITY_WPA2; + return true; + } else if(strncmp("PA", buffer, 10) != 0) { + return true; + } + + /* got a "WPA", check for "WPA2" */ + rest += strlen(buffer); + value = *rest++; + if(value == '\0') { // no further protocol + ap->security = NSAPI_SECURITY_WPA; + return true; + } else { // assume "WPA2" + ap->security = NSAPI_SECURITY_WPA_WPA2; + return true; + } + } + } else { // ret == false + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + } + + return ret; +} + +int SPWFSA01::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned cnt = 0; + nsapi_wifi_ap_t ap; + + if (!_parser.send("AT+S.SCAN=a,s")) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + while (_recv_ap(&ap)) { + if (cnt < limit) { + res[cnt] = WiFiAccessPoint(ap); + } + + cnt++; + if (limit != 0 && cnt >= limit) { + break; + } + } + + if(!_recv_ok()) { + empty_rx_buffer(); + } + + return cnt; +} + +#endif // MBED_CONF_IDW0XX1_EXPANSION_BOARD
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SPWFSA01/SPWFSA01.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,66 @@ +/* SPWFSA01 Device + * 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. + */ + +#ifndef SPWFSA01_H +#define SPWFSA01_H + +#include "mbed.h" +#include "ATCmdParser.h" +#include "BlockExecuter.h" + +#include "./spwfsa01_at_strings.h" +#include "../SPWFSAxx.h" + +class SpwfSAInterface; + +/** SPWFSA01 Interface class. + This is an interface to a SPWFSA01 module. + */ +class SPWFSA01 : public SPWFSAxx +{ +public: + SPWFSA01(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "u" (UDP) or "t" (TCP) + * @param id id to get the new socket number, valid 0-7 + * @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); + + /** 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 + */ + nsapi_size_or_error_t scan(WiFiAccessPoint *res, unsigned limit); + +private: + bool _recv_ap(nsapi_wifi_ap_t *ap); + + virtual int _read_in(char*, int, uint32_t); +}; + +#endif // SPWFSA01_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SPWFSA01/spwfsa01_at_strings.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,58 @@ +#ifndef SPWFSAXX_AT_STRINGS_H +#define SPWFSAXX_AT_STRINGS_H + +#if defined(TARGET_FF_MORPHO) + +#if !defined(SPWFSAXX_WAKEUP_PIN) +#define SPWFSAXX_WAKEUP_PIN PC_8 // A3 +#endif // !defined(SPWFSAXX_WAKEUP_PIN) +#if !defined(SPWFSAXX_RESET_PIN) +#define SPWFSAXX_RESET_PIN PC_12 // D7 / NC +#endif // !defined(SPWFSAXX_RESET_PIN) + +#else // !defined(TARGET_FF_MORPHO) + +#if !defined(SPWFSAXX_WAKEUP_PIN) +#define SPWFSAXX_WAKEUP_PIN NC // A3 +#endif // !defined(SPWFSAXX_WAKEUP_PIN) +#if !defined(SPWFSAXX_RESET_PIN) +#define SPWFSAXX_RESET_PIN NC // D7 / NC +#endif // !defined(SPWFSAXX_RESET_PIN) + +#endif // !defined(TARGET_FF_MORPHO) + +#define SPWFXX_SEND_RECV_PKTSIZE (730) + +#define SPWFXX_OOB_ERROR "ERROR:" // "AT-S.ERROR:" + +#define SPWFXX_RECV_OK "OK\n" // "AT-S.OK\n" +#define SPWFXX_RECV_WIFI_UP "+WIND:24:WiFi Up:%u.%u.%u.%u\n" // "+WIND:24:WiFi Up:%*u:%u.%u.%u.%u\n" +#define SPWFXX_RECV_IP_ADDR "# ip_ipaddr = %u.%u.%u.%u\n" // "AT-S.Var:ip_ipaddr=%u.%u.%u.%u\n" +#define SPWFXX_RECV_GATEWAY "# ip_gw = %u.%u.%u.%u\n" // "AT-S.Var:ip_gw=%u.%u.%u.%u\n" +#define SPWFXX_RECV_NETMASK "# ip_netmask = %u.%u.%u.%u\n" // "AT-S.Var:ip_netmask=%u.%u.%u.%u\n" +#define SPWFXX_RECV_RX_RSSI "# 0.rx_rssi = %d\n" // "AT-S.Var:0.rx_rssi=%d\n" +#define SPWFXX_RECV_MAC_ADDR "# nv_wifi_macaddr = %x:%x:%x:%x:%x:%x\n" // "AT-S.Var:nv_wifi_macaddr=%x:%x:%x:%x:%x:%x\n" +#define SPWFXX_RECV_DATALEN " DATALEN: %u\n" // "AT-S.Query:%u\n" +#define SPWFXX_RECV_PENDING_DATA ":%d:%d\n" // "::%u:%*u:%u\n" +#define SPWFXX_RECV_SOCKET_CLOSED ":%d\n" // ":%u:%*u\n" + +#define SPWFXX_SEND_FWCFG "AT&F" // "AT+S.FCFG" +#define SPWFXX_SEND_DISABLE_LE "AT+S.SCFG=localecho1,0" // "AT+S.SCFG=console_echo,0" +#define SPWFXX_SEND_DSPLY_CFGV "AT&V" // "AT+S.GCFG" +#define SPWFXX_SEND_GET_CONS_STATE "AT+S.GCFG=console1_enabled" // "AT+S.GCFG=console_enabled" +#define SPWFXX_SEND_GET_CONS_SPEED "AT+S.GCFG=console1_speed" // "AT+S.GCFG=console_speed" +#define SPWFXX_SEND_GET_HWFC_STATE "AT+S.GCFG=console1_hwfc" // "AT+S.GCFG=console_hwfc" +#define SPWFXX_SEND_GET_CONS_DELIM "AT+S.GCFG=console1_delimiter" // "AT+S.GCFG=console_delimiter" +#define SPWFXX_SEND_GET_CONS_ERRS "AT+S.GCFG=console1_errs" // "AT+S.GCFG=console_errs" +#define SPWFXX_SEND_DISABLE_FC "AT+S.SCFG=console1_hwfc,0" // "AT+S.SCFG=console_hwfc,0" +#define SPWFXX_SEND_ENABLE_FC "AT+S.SCFG=console1_hwfc,1" // "AT+S.SCFG=console_hwfc,1" +#define SPWFXX_SEND_SW_RESET "AT+CFUN=1" // "AT+S.RESET" +#define SPWFXX_SEND_SAVE_SETTINGS "AT&W" // "AT+S.WCFG" +#define SPWFXX_SEND_WIND_OFF_HIGH "AT+S.SCFG=wind_off_high," // "AT+S.SCFG=console_wind_off_high," +#define SPWFXX_SEND_WIND_OFF_MEDIUM "AT+S.SCFG=wind_off_medium," // "AT+S.SCFG=console_wind_off_medium," +#define SPWFXX_SEND_WIND_OFF_LOW "AT+S.SCFG=wind_off_low," // "AT+S.SCFG=console_wind_off_low," + +#define SPWFXX_WINDS_HIGH_ON "0x00000000" // "0x00100000" +#define SPWFXX_WINDS_MEDIUM_ON "0x00000000" // "0x80000000" + +#endif // SPWFSAXX_AT_STRINGS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SPWFSA04/SPWFSA04.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,318 @@ +/* SPWFSA04 Device + * 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. + */ + +#include "SPWFSA04.h" +#include "SpwfSAInterface.h" +#include "mbed_debug.h" + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + +SPWFSA04::SPWFSA04(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset) +: SPWFSAxx(tx, rx, rts, cts, ifce, debug, wakeup, reset) { +} + +bool SPWFSA04::open(const char *type, int* spwf_id, const char* addr, int port) +{ + int socket_id; + int value; + int trials; + + if(!_parser.send("AT+S.SOCKON=%s,%d,NULL,%s", addr, port, type)) + { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + return false; + } + + /* handle both response possibilities here before returning + * otherwise module seems to remain in inconsistent state. + */ + + if(!_parser.recv("AT-S.")) { // get prefix + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + + /* wait for next character */ + trials = 0; + while((value = _parser.getc()) < 0) { + if(++trials >= SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + } + + switch(value) { + case 'O': + /* get next character */ + value = _parser.getc(); + if(value != 'n') { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d) (%d, \'%c\')\r\n", + __LINE__, value, value); + empty_rx_buffer(); + return false; + } + + /* get socket id */ + if(!(_parser.recv(":%*u.%*u.%*u.%*u:%d\n", &socket_id) + && _recv_delim_lf() + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + return false; + } + debug_if(_dbg_on, "AT^ AT-S.On:%s:%d\r\n", addr, socket_id); + + *spwf_id = socket_id; + return true; + case 'E': + int err_nr; + if(_parser.recv("RROR:%d:%255[^\n]\n", &err_nr, _msg_buffer) && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ AT-S.ERROR:%d:%s (%d)\r\n", err_nr, _msg_buffer, __LINE__); + } else { + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d)\r\n", __LINE__); + empty_rx_buffer(); + } + break; + default: + debug_if(_dbg_on, "\r\nSPWF> `SPWFSA04::open`: error opening socket (%d) (%d, \'%c\')\r\n", + __LINE__, value, value); + empty_rx_buffer(); + break; + } + + return false; +} + +int SPWFSA04::_read_in(char* buffer, int spwf_id, uint32_t amount) { + int ret = -1; + int received, cumulative; + + MBED_ASSERT(buffer != NULL); + + /* block asynchronous indications */ + if(!_winds_off()) { + return -1; + } + + /* read in data */ + if(_parser.send("AT+S.SOCKR=%d,%d", spwf_id, (unsigned int)amount)) { + if(!(_parser.recv("AT-S.Reading:%d:%d\n", &received, &cumulative) && + _recv_delim_lf())) { + debug_if(_dbg_on, "\r\nSPWF> failed to receive AT-S.Reading (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } else { + /* set high timeout */ + _parser.set_timeout(SPWF_READ_BIN_TIMEOUT); + /* read in binary data */ + int read = _parser.read(buffer, amount); + /* reset timeout value */ + _parser.set_timeout(_timeout); + if(read > 0) { + if(_recv_ok()) { + ret = amount; + + /* remove from pending sizes + * (MUST be done before next async indications handling (e.g. `_winds_on()`)) */ + _remove_pending_pkt_size(spwf_id, amount); + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to receive OK (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } + } else { + debug_if(_dbg_on, "\r\nSPWF> failed to read binary data (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } + } + } else { + debug_if(_dbg_on, "%s(%d): failed to send SOCKR\r\n", __func__, __LINE__); + } + + debug_if(_dbg_on, "\r\nSPWF> %s():\t%d:%d\r\n", __func__, spwf_id, amount); + + /* unblock asynchronous indications */ + _winds_on(); + + return ret; +} + +/* betzw - TODO: improve performance! */ +bool SPWFSA04::_recv_ap(nsapi_wifi_ap_t *ap) +{ + bool ret; + int curr; + unsigned int channel; + int trials; + + ap->security = NSAPI_SECURITY_UNKNOWN; + + /* determine list end */ + curr = _parser.getc(); + if(curr == 'A') { // assume end of list ("AT-S.OK") + if(!(_parser.recv("T-S.OK\n") && _recv_delim_lf())) { + empty_rx_buffer(); + } + return false; + } + + /* run to 'horizontal tab' */ + trials = 0; + while(_parser.getc() != '\x09') { + if(trials++ > SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + } + + /* read in next line */ + ret = _parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf(); + + /* parse line - first phase */ + if(ret) { + int val = sscanf(_msg_buffer, + " %*s %hhx:%hhx:%hhx:%hhx:%hhx:%hhx CHAN: %u RSSI: %hhd SSID: \'%*255[^\']\'", + &ap->bssid[0], &ap->bssid[1], &ap->bssid[2], &ap->bssid[3], &ap->bssid[4], &ap->bssid[5], + &channel, &ap->rssi); + if(val < 8) { + ret = false; + } + } + + /* parse line - second phase */ + if(ret) { // ret == true + char value; + char *rest, *first, *last; + + /* decide about position of `CAPS:` */ + first = strchr(_msg_buffer, '\''); + if(first == NULL) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + last = strrchr(_msg_buffer, '\''); + if((last == NULL) || (last < (first+1))) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + rest = strstr(last, "CAPS:"); + if(rest == NULL) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + + /* substitute '\'' with '\0' */ + *last = '\0'; + + /* copy values */ + memcpy(&ap->ssid, first+1, sizeof(ap->ssid)-1); + ap->ssid[sizeof(ap->ssid)-1] = '\0'; + ap->channel = channel; + + /* skip `CAPS: 0421 ` */ + if(strlen(rest) < 11) { + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + rest += 11; + + /* get next character */ + value = *rest++; + if(value != 'W') { // no security + ap->security = NSAPI_SECURITY_NONE; + return true; + } + + /* determine security */ + { + char buffer[10]; + + if(!(sscanf(rest, "%s%*[\x20]", (char*)&buffer) > 0)) { // '\0x20' == <space> + return true; + } else if(strncmp("EP", buffer, 10) == 0) { + ap->security = NSAPI_SECURITY_WEP; + return true; + } else if(strncmp("PA2", buffer, 10) == 0) { + ap->security = NSAPI_SECURITY_WPA2; + return true; + } else if(strncmp("PA", buffer, 10) != 0) { + return true; + } + + /* got a "WPA", check for "WPA2" */ + rest += strlen(buffer); + value = *rest++; + if(value == '\0') { // no further protocol + ap->security = NSAPI_SECURITY_WPA; + return true; + } else { // assume "WPA2" + ap->security = NSAPI_SECURITY_WPA_WPA2; + return true; + } + } + } else { // ret == false + debug("\r\nSPWF> WARNING: might happen in case of RX buffer overflow! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + } + + return ret; +} + +nsapi_size_or_error_t SPWFSA04::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned int cnt = 0, found; + nsapi_wifi_ap_t ap; + + if (!_parser.send("AT+S.SCAN=s,")) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + if(!(_parser.recv("AT-S.Parsing Networks:%u\n", &found) && _recv_delim_lf())) { + debug_if(_dbg_on, "SPWF> error start network scanning\r\n"); + empty_rx_buffer(); + return NSAPI_ERROR_DEVICE_ERROR; + } + + debug_if(_dbg_on, "AT^ AT-S.Parsing Networks:%u\r\n", found); + + if(found > 0) { + while (_recv_ap(&ap)) { + if (cnt < limit) { + res[cnt] = WiFiAccessPoint(ap); + } + + if (!((limit != 0) && ((cnt + 1) > limit))) { + cnt++; + } + } + } else { + if(!_recv_ok()) { + empty_rx_buffer(); + } + } + + return cnt; +} + +#endif // MBED_CONF_IDW0XX1_EXPANSION_BOARD
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SPWFSA04/SPWFSA04.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,66 @@ +/* SPWFSA04 Device + * 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. + */ + +#ifndef SPWFSA04_H +#define SPWFSA04_H + +#include "mbed.h" +#include "ATCmdParser.h" +#include "BlockExecuter.h" + +#include "./spwfsa04_at_strings.h" +#include "../SPWFSAxx.h" + +class SpwfSAInterface; + +/** SPWFSA04 Interface class. + This is an interface to a SPWFSA04 module. + */ +class SPWFSA04 : public SPWFSAxx +{ +public: + SPWFSA04(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset); + + /** + * Open a socketed connection + * + * @param type the type of socket to open "u" (UDP) or "t" (TCP) + * @param id id to get the new socket number, valid 0-7 + * @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); + + /** 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 + */ + nsapi_size_or_error_t scan(WiFiAccessPoint *res, unsigned limit); + +private: + bool _recv_ap(nsapi_wifi_ap_t *ap); + + virtual int _read_in(char*, int, uint32_t); +}; + +#endif // SPWFSA04_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SPWFSA04/spwfsa04_at_strings.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,65 @@ +#ifndef SPWFSAXX_AT_STRINGS_H +#define SPWFSAXX_AT_STRINGS_H + +/* Define beyond macro if your X-NUCLEO-IDW04A1 expansion board has NOT the `WIFI_RST` HW patch applied on it */ +// #define IDW04A1_WIFI_HW_BUG_WA // delegated to mbed config system + +#if defined(TARGET_FF_ARDUINO) + +#if !defined(SPWFSAXX_WAKEUP_PIN) +#define SPWFSAXX_WAKEUP_PIN A3 +#endif +#if !defined(SPWFSAXX_RESET_PIN) +#ifndef IDW04A1_WIFI_HW_BUG_WA +#define SPWFSAXX_RESET_PIN D7 +#else // IDW04A1_WIFI_HW_PATCH +#define SPWFSAXX_RESET_PIN NC +#endif // !IDW04A1_WIFI_HW_PATCH +#endif + +#else // !defined(TARGET_FF_ARDUINO) + +#if !defined(SPWFSAXX_WAKEUP_PIN) +#define SPWFSAXX_WAKEUP_PIN NC +#endif +#if !defined(SPWFSAXX_RESET_PIN) +#define SPWFSAXX_RESET_PIN NC +#endif + +#endif // !defined(TARGET_FF_ARDUINO) + +#define SPWFXX_SEND_RECV_PKTSIZE (730) + +#define SPWFXX_OOB_ERROR "AT-S.ERROR:" // "ERROR:" + +#define SPWFXX_RECV_OK "AT-S.OK\n" // "OK\n" +#define SPWFXX_RECV_WIFI_UP "+WIND:24:WiFi Up:%*u:%u.%u.%u.%u\n" // "+WIND:24:WiFi Up:%u.%u.%u.%u\n" +#define SPWFXX_RECV_IP_ADDR "AT-S.Var:ip_ipaddr=%u.%u.%u.%u\n" // "# ip_ipaddr = %u.%u.%u.%u\n" +#define SPWFXX_RECV_GATEWAY "AT-S.Var:ip_gw=%u.%u.%u.%u\n" // "# ip_gw = %u.%u.%u.%u\n" +#define SPWFXX_RECV_NETMASK "AT-S.Var:ip_netmask=%u.%u.%u.%u\n" // "# ip_netmask = %u.%u.%u.%u\n" +#define SPWFXX_RECV_RX_RSSI "AT-S.Var:0.rx_rssi=%d\n" // "# 0.rx_rssi = %d\n" +#define SPWFXX_RECV_MAC_ADDR "AT-S.Var:nv_wifi_macaddr=%x:%x:%x:%x:%x:%x\n" // "# nv_wifi_macaddr = %x:%x:%x:%x:%x:%x\n" +#define SPWFXX_RECV_DATALEN "AT-S.Query:%u\n" // " DATALEN: %u\n" +#define SPWFXX_RECV_PENDING_DATA "::%u:%*u:%u\n" // ":%d:%d\n" +#define SPWFXX_RECV_SOCKET_CLOSED ":%u:%*u\n" // ":%d\n" + +#define SPWFXX_SEND_FWCFG "AT+S.FCFG" // "AT&F" +#define SPWFXX_SEND_DISABLE_LE "AT+S.SCFG=console_echo,0" // "AT+S.SCFG=localecho1,0" +#define SPWFXX_SEND_DSPLY_CFGV "AT+S.GCFG" // "AT&V" +#define SPWFXX_SEND_GET_CONS_STATE "AT+S.GCFG=console_enabled" // "AT+S.GCFG=console1_enabled" +#define SPWFXX_SEND_GET_CONS_SPEED "AT+S.GCFG=console_speed" // "AT+S.GCFG=console1_speed" +#define SPWFXX_SEND_GET_HWFC_STATE "AT+S.GCFG=console_hwfc" // "AT+S.GCFG=console1_hwfc" +#define SPWFXX_SEND_GET_CONS_DELIM "AT+S.GCFG=console_delimiter" // "AT+S.GCFG=console1_delimiter" +#define SPWFXX_SEND_GET_CONS_ERRS "AT+S.GCFG=console_errs" // "AT+S.GCFG=console1_errs" +#define SPWFXX_SEND_DISABLE_FC "AT+S.SCFG=console_hwfc,0" // "AT+S.SCFG=console1_hwfc,0" +#define SPWFXX_SEND_ENABLE_FC "AT+S.SCFG=console_hwfc,1" // "AT+S.SCFG=console1_hwfc,1" +#define SPWFXX_SEND_SW_RESET "AT+S.RESET" // "AT+CFUN=1" +#define SPWFXX_SEND_SAVE_SETTINGS "AT+S.WCFG" // "AT&W" +#define SPWFXX_SEND_WIND_OFF_HIGH "AT+S.SCFG=console_wind_off_high," // "AT+S.SCFG=wind_off_high," +#define SPWFXX_SEND_WIND_OFF_MEDIUM "AT+S.SCFG=console_wind_off_medium," // "AT+S.SCFG=wind_off_medium," +#define SPWFXX_SEND_WIND_OFF_LOW "AT+S.SCFG=console_wind_off_low," // "AT+S.SCFG=wind_off_low," + +#define SPWFXX_WINDS_HIGH_ON "0x00100000" // "0x00000000" +#define SPWFXX_WINDS_MEDIUM_ON "0x80000000" // "0x00000000" + +#endif // SPWFSAXX_AT_STRINGS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SPWFSAxx.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,1287 @@ +/* SPWFSAxx Devices + * 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. + */ + +#include "mbed_debug.h" + +#include "SpwfSAInterface.h" /* must be included first */ +#include "SPWFSAxx.h" + +static const char out_delim[] = {SPWFSAxx::_cr_, '\0'}; + +SPWFSAxx::SPWFSAxx(PinName tx, PinName rx, + PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset) +: _serial(tx, rx, SPWFXX_DEFAULT_BAUD_RATE), _parser(&_serial, out_delim), + _wakeup(wakeup, 1), _reset(reset, 1), + _rts(rts), _cts(cts), + _timeout(SPWF_INIT_TIMEOUT), _dbg_on(debug), + _pending_sockets_bitmap(0), + _network_lost_flag(false), + _associated_interface(ifce), + _call_event_callback_blocked(0), + _callback_func(), + _packets(0), _packets_end(&_packets) +{ + memset(_pending_pkt_sizes, 0, sizeof(_pending_pkt_sizes)); + + _serial.sigio(Callback<void()>(this, &SPWFSAxx::_event_handler)); + _parser.debug_on(debug); + _parser.set_timeout(_timeout); + + /* unlikely OOBs */ + _parser.oob("+WIND:5:WiFi Hardware Failure", callback(this, &SPWFSAxx::_wifi_hwfault_handler)); + _parser.oob("+WIND:33:WiFi Network Lost", callback(this, &SPWFSAxx::_network_lost_handler_th)); +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + _parser.oob("+WIND:24:WiFi Up::", callback(this, &SPWFSAxx::_skip_oob)); +#endif + _parser.oob("+WIND:8:Hard Fault", callback(this, &SPWFSAxx::_hard_fault_handler)); + + /* most likely OOBs */ + _parser.oob(SPWFXX_OOB_ERROR, callback(this, &SPWFSAxx::_error_handler)); + _parser.oob("+WIND:58:Socket Closed", callback(this, &SPWFSAxx::_server_gone_handler)); + _parser.oob("+WIND:55:Pending Data", callback(this, &SPWFSAxx::_packet_handler_th)); +} + +bool SPWFSAxx::startup(int mode) +{ + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + /*Reset module*/ + if(!hw_reset()) { + debug_if(_dbg_on, "\r\nSPWF> HW reset failed\r\n"); + return false; + } + + /* factory reset */ + if(!(_parser.send(SPWFXX_SEND_FWCFG) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error restore factory default settings\r\n"); + return false; + } + + /*switch off led*/ + if(!(_parser.send("AT+S.SCFG=blink_led,0") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error stop blinking led (%d)\r\n", __LINE__); + return false; + } + + /*set local echo to 0*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_LE) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error local echo set\r\n"); + return false; + } + + /*set the operational rates*/ + if(!(_parser.send("AT+S.SCFG=wifi_opr_rate_mask,0x003FFFCF") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error setting ht_mode\r\n"); + return false; + } + + /*enable the 802.11n mode*/ + if(!(_parser.send("AT+S.SCFG=wifi_ht_mode,1") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error setting operational rates\r\n"); + return false; + } + + /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/ + if(!(_parser.send("AT+S.SCFG=wifi_mode,%d", mode) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set idle (%d)\r\n", __LINE__); + return false; + } + +#if defined(MBED_MAJOR_VERSION) +#if !DEVICE_SERIAL_FC || (MBED_VERSION < MBED_ENCODE_VERSION(5, 7, 0)) + /*disable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n"); + return false; + } +#else // DEVICE_SERIAL_FC && (MBED_VERSION >= MBED_ENCODE_VERSION(5, 7, 0)) + if((_rts != NC) && (_cts != NC)) { + /*enable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_ENABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error enabling HW flow control\r\n"); + return false; + } + + /*configure pins for HW flow control*/ + _serial.set_flow_control(SerialBase::RTSCTS, _rts, _cts); + } else { + /*disable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n"); + return false; + } + } +#endif // DEVICE_SERIAL_FC && (MBED_VERSION >= MBED_ENCODE_VERSION(5, 7, 0)) +#else // !defined(MBED_MAJOR_VERSION) - Assuming `master` branch +#if !DEVICE_SERIAL_FC + /*disable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n"); + return false; + } +#else // DEVICE_SERIAL_FC + if((_rts != NC) && (_cts != NC)) { + /*enable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_ENABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error enabling HW flow control\r\n"); + return false; + } + + /*configure pins for HW flow control*/ + _serial.set_flow_control(SerialBase::RTSCTS, _rts, _cts); + } else { + /*disable HW flow control*/ + if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n"); + return false; + } + } +#endif // DEVICE_SERIAL_FC +#endif // !defined(MBED_MAJOR_VERSION) + + /* Disable selected WINDs */ + _winds_on(); + + /* sw reset */ + if(!reset()) { + debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__); + return false; + } + +#ifndef NDEBUG + if (!(_parser.send(SPWFXX_SEND_GET_CONS_STATE) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting console state\r\n"); + return false; + } + + if (!(_parser.send(SPWFXX_SEND_GET_CONS_SPEED) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting console speed\r\n"); + return false; + } + + if (!(_parser.send(SPWFXX_SEND_GET_HWFC_STATE) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting hwfc state\r\n"); + return false; + } + +#if (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) || defined(IDW01M1_FW_REL_35X) + /* betzw: IDW01M1 FW versions <3.5 seem to have problems with the following two commands. + * For the sake of simplicity, just excluding them for IDW01M1 in general. + */ + if (!(_parser.send(SPWFXX_SEND_GET_CONS_DELIM) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting console delimiter\r\n"); + return false; + } + + if (!(_parser.send(SPWFXX_SEND_GET_CONS_ERRS) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting console error setting\r\n"); + return false; + } +#endif // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) || defined(IDW01M1_FW_REL_35X) + + if (!(_parser.send("AT+S.GCFG=sleep_enabled") + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting sleep state enabled\r\n"); + return false; + } + + if (!(_parser.send("AT+S.GCFG=wifi_powersave") + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting powersave mode\r\n"); + return false; + } + + if (!(_parser.send("AT+S.GCFG=standby_enabled") + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> error getting standby state enabled\r\n"); + return false; + } +#endif + + return true; +} + +bool SPWFSAxx::_wait_console_active(void) { + int trials = 0; + + while(true) { + if (_parser.recv("+WIND:0:Console active\n") && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ +WIND:0:Console active\r\n"); + return true; + } + if(++trials >= SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + } +} + +bool SPWFSAxx::_wait_wifi_hw_started(void) { + int trials = 0; + + while(true) { + if (_parser.recv("+WIND:32:WiFi Hardware Started\n") && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ +WIND:32:WiFi Hardware Started\r\n"); + return true; + } + if(++trials >= SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + } +} + +bool SPWFSAxx::hw_reset(void) +{ +#if (MBED_CONF_IDW0XX1_EXPANSION_BOARD != IDW04A1) || !defined(IDW04A1_WIFI_HW_BUG_WA) // betzw: HW reset doesn't work as expected on unmodified X_NUCLEO_IDW04A1 expansion boards + _reset.write(0); + wait_ms(200); + _reset.write(1); +#else // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) && defined(IDW04A1_WIFI_HW_BUG_WA): substitute with SW reset + _parser.send(SPWFXX_SEND_SW_RESET); +#endif // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) && defined(IDW04A1_WIFI_HW_BUG_WA) + return _wait_console_active(); +} + +bool SPWFSAxx::reset(void) +{ + bool ret; + + /* save current setting in flash */ + if(!(_parser.send(SPWFXX_SEND_SAVE_SETTINGS) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error saving configuration to flash (%s, %d)\r\n", __func__, __LINE__); + return false; + } + + if(!_parser.send(SPWFXX_SEND_SW_RESET)) return false; /* betzw - NOTE: "keep the current state and reset the device". + We assume that the module informs us about the + eventual closing of sockets via "WIND" asynchronous + indications! So everything regarding the clean-up + of these situations is handled there. */ + + /* waiting for HW to start */ + ret = _wait_wifi_hw_started(); + + return ret; +} + +/* Security Mode + None = 0, + WEP = 1, + WPA_Personal = 2, + */ +bool SPWFSAxx::connect(const char *ap, const char *passPhrase, int securityMode) +{ + int trials; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + //AT+S.SCFG=wifi_wpa_psk_text,%s + if(!(_parser.send("AT+S.SCFG=wifi_wpa_psk_text,%s", passPhrase) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error pass set\r\n"); + return false; + } + + //AT+S.SSIDTXT=%s + if(!(_parser.send("AT+S.SSIDTXT=%s", ap) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error ssid set\r\n"); + return false; + } + + //AT+S.SCFG=wifi_priv_mode,%d + if(!(_parser.send("AT+S.SCFG=wifi_priv_mode,%d", securityMode) && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error security mode set\r\n"); + return false; + } + + /*set STA mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/ + if(!(_parser.send("AT+S.SCFG=wifi_mode,1") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set 1 (STA)\r\n"); + return false; + } + + /* sw reset */ + if(!reset()) { + debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__); + return false; + } + + trials = 0; + while(true) { + if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) + { + if(strstr(_msg_buffer, ":24:") != NULL) { // WiFi Up + debug_if(_dbg_on, "AT^ %s\n", _msg_buffer); + if(strchr(_msg_buffer, '.') != NULL) { // IPv4 address + break; + } else { + continue; + } + } + if(strstr(_msg_buffer, ":40:") != NULL) { // Deauthentication + debug_if(_dbg_on, "AT~ %s\n", _msg_buffer); + if(++trials < SPWFXX_MAX_TRIALS) { // give it three trials + continue; + } + disconnect(); + empty_rx_buffer(); + return false; + } else { + debug_if(_dbg_on, "AT] %s\n", _msg_buffer); + } + continue; + } + if(++trials >= SPWFXX_MAX_TRIALS) { + debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__); + empty_rx_buffer(); + return false; + } + } + + return true; +} + +bool SPWFSAxx::disconnect(void) +{ + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + /*disable Wi-Fi device*/ + if(!(_parser.send("AT+S.WIFI=0") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error disabling WiFi\r\n"); + return false; + } +#endif // IDW04A1 + + /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/ + if(!(_parser.send("AT+S.SCFG=wifi_mode,0") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set idle (%d)\r\n", __LINE__); + return false; + } + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + /*enable Wi-Fi device*/ + if(!(_parser.send("AT+S.WIFI=1") && _recv_ok())) + { + debug_if(_dbg_on, "\r\nSPWF> error enabling WiFi\r\n"); + return false; + } +#endif // IDW04A1 + + // reset module + if(!reset()) { + debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__); + return false; + } + + /* clean up state */ + _associated_interface.inner_constructor(); + _free_all_packets(); + + return true; +} + +const char *SPWFSAxx::getIPAddress(void) +{ + unsigned int n1, n2, n3, n4; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.STS=ip_ipaddr") + && _parser.recv(SPWFXX_RECV_IP_ADDR, &n1, &n2, &n3, &n4) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get IP address error\r\n"); + return NULL; + } + + debug_if(_dbg_on, "AT^ ip_ipaddr = %u.%u.%u.%u\r\n", n1, n2, n3, n4); + + sprintf((char*)_ip_buffer,"%u.%u.%u.%u", n1, n2, n3, n4); + return _ip_buffer; +} + +const char *SPWFSAxx::getGateway(void) +{ + unsigned int n1, n2, n3, n4; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.STS=ip_gw") + && _parser.recv(SPWFXX_RECV_GATEWAY, &n1, &n2, &n3, &n4) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get gateway error\r\n"); + return NULL; + } + + debug_if(_dbg_on, "AT^ ip_gw = %u.%u.%u.%u\r\n", n1, n2, n3, n4); + + sprintf((char*)_gateway_buffer,"%u.%u.%u.%u", n1, n2, n3, n4); + return _gateway_buffer; +} + +const char *SPWFSAxx::getNetmask(void) +{ + unsigned int n1, n2, n3, n4; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.STS=ip_netmask") + && _parser.recv(SPWFXX_RECV_NETMASK, &n1, &n2, &n3, &n4) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get netmask error\r\n"); + return NULL; + } + + debug_if(_dbg_on, "AT^ ip_netmask = %u.%u.%u.%u\r\n", n1, n2, n3, n4); + + sprintf((char*)_netmask_buffer,"%u.%u.%u.%u", n1, n2, n3, n4); + return _netmask_buffer; +} + +int8_t SPWFSAxx::getRssi(void) +{ + int ret; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.PEERS=0,rx_rssi") + && _parser.recv(SPWFXX_RECV_RX_RSSI, &ret) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get RX rssi error\r\n"); + return 0; + } + + return (int8_t)ret; +} + +const char *SPWFSAxx::getMACAddress(void) +{ + unsigned int n1, n2, n3, n4, n5, n6; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + if (!(_parser.send("AT+S.GCFG=nv_wifi_macaddr") + && _parser.recv(SPWFXX_RECV_MAC_ADDR, &n1, &n2, &n3, &n4, &n5, &n6) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> get MAC address error\r\n"); + return 0; + } + + debug_if(_dbg_on, "AT^ nv_wifi_macaddr = %x:%x:%x:%x:%x:%x\r\n", n1, n2, n3, n4, n5, n6); + + sprintf((char*)_mac_buffer,"%02X:%02X:%02X:%02X:%02X:%02X", n1, n2, n3, n4, n5, n6); + return _mac_buffer; +} + +bool SPWFSAxx::isConnected(void) +{ + return _associated_interface._connected_to_network; +} + +nsapi_size_or_error_t SPWFSAxx::send(int spwf_id, const void *data, uint32_t amount, int internal_id) +{ + uint32_t sent = 0U, to_send; + nsapi_size_or_error_t ret; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + _process_winds(); // perform async indication handling (to early detect eventually closed sockets) + + /* betzw - WORK AROUND module FW issues: split up big packages in smaller ones */ + for(to_send = (amount > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : amount; + sent < amount; + to_send = ((amount - sent) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (amount - sent)) { + { + BlockExecuter bh_handler(Callback<void()>(this, &SPWFSAxx::_execute_bottom_halves)); + + // betzw - TODO: handle different errors more accurately! + if (!_associated_interface._socket_is_still_connected(internal_id)) { + debug_if(_dbg_on, "\r\nSPWF> Socket not connected anymore: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__); + break; + } else if(!_parser.send("AT+S.SOCKW=%d,%d", spwf_id, (unsigned int)to_send)) { + debug_if(_dbg_on, "\r\nSPWF> Sending command failed: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__); + break; + } else if(_parser.write(((char*)data)+sent, (int)to_send) != (int)to_send) { + debug_if(_dbg_on, "\r\nSPWF> Sending data failed: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__); + break; + } else if(!_recv_ok()) { + debug_if(_dbg_on, "\r\nSPWF> Sending did not receive OK: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__); + break; + } + } + + sent += to_send; + } + + if(sent > 0) { // `sent == 0` indicates a potential error + ret = sent; + } else if(amount == 0) { + ret = NSAPI_ERROR_OK; + } else if(_associated_interface._socket_is_still_connected(internal_id)) { + ret = NSAPI_ERROR_DEVICE_ERROR; + } else { + ret = NSAPI_ERROR_CONNECTION_LOST; + } + + return ret; +} + +int SPWFSAxx::_read_len(int spwf_id) { + unsigned int amount; + + if (!(_parser.send("AT+S.SOCKQ=%d", spwf_id) + && _parser.recv(SPWFXX_RECV_DATALEN, &amount) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed\r\n", __func__); + return SPWFXX_ERR_LEN; + } + + if(amount > 0) { + debug_if(_dbg_on, "\r\nSPWF> %s():\t\t%d:%d\r\n", __func__, spwf_id, amount); + } + + MBED_ASSERT(((int)amount) >= 0); + + return (int)amount; +} + +#define SPWFXX_WINDS_OFF "0xFFFFFFFF" + +void SPWFSAxx::_winds_on(void) { + MBED_ASSERT(_is_event_callback_blocked()); + + if(!(_parser.send(SPWFXX_SEND_WIND_OFF_HIGH SPWFXX_WINDS_HIGH_ON) && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); + } + if(!(_parser.send(SPWFXX_SEND_WIND_OFF_MEDIUM SPWFXX_WINDS_MEDIUM_ON) && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); + } + if(!(_parser.send(SPWFXX_SEND_WIND_OFF_LOW SPWFXX_WINDS_LOW_ON) && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); + } +} + +/* Define beyond macro in case you want to report back failures in switching off WINDs to the caller */ +// #define SPWFXX_SOWF +/* Note: in case of error blocking has been (tried to be) lifted */ +bool SPWFSAxx::_winds_off(void) { + MBED_ASSERT(_is_event_callback_blocked()); + + if (!(_parser.send(SPWFXX_SEND_WIND_OFF_LOW SPWFXX_WINDS_OFF) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); +#ifdef SPWFXX_SOWF // betzw: try to continue + _winds_on(); + return false; +#endif + } + + if (!(_parser.send(SPWFXX_SEND_WIND_OFF_MEDIUM SPWFXX_WINDS_OFF) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); +#ifdef SPWFXX_SOWF // betzw: try to continue + _winds_on(); + return false; +#endif + } + + if (!(_parser.send(SPWFXX_SEND_WIND_OFF_HIGH SPWFXX_WINDS_OFF) + && _recv_ok())) { + debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__); +#ifdef SPWFXX_SOWF // betzw: try to continue + _winds_on(); + return false; +#endif + } + + return true; +} + +void SPWFSAxx::_execute_bottom_halves(void) { + _network_lost_handler_bh(); + _packet_handler_bh(); +} + +void SPWFSAxx::_read_in_pending(void) { + static int internal_id_cnt = 0; + + while(_is_data_pending()) { + if(_associated_interface._socket_has_connected(internal_id_cnt)) { + int spwf_id = _associated_interface._ids[internal_id_cnt].spwf_id; + + if(_is_data_pending(spwf_id)) { + int amount; + + amount = _read_in_pkt(spwf_id, false); + if(amount == SPWFXX_ERR_OOM) { /* consider only 'SPWFXX_ERR_OOM' as non recoverable */ + return; + } + } + + if(!_is_data_pending(spwf_id)) { + internal_id_cnt++; + internal_id_cnt %= SPWFSA_SOCKET_COUNT; + } + } else { + internal_id_cnt++; + internal_id_cnt %= SPWFSA_SOCKET_COUNT; + } + } +} + +/* Note: returns + * 'SPWFXX_ERR_OK' in case of success + * 'SPWFXX_ERR_OOM' in case of "out of memory" + * 'SPWFXX_ERR_READ' in case of `_read_in()` error + */ +int SPWFSAxx::_read_in_packet(int spwf_id, uint32_t amount) { + struct packet *packet = (struct packet*)malloc(sizeof(struct packet) + amount); + if (!packet) { +#ifndef NDEBUG + error("\r\nSPWF> %s(%d): Out of memory!\r\n", __func__, __LINE__); +#else // NDEBUG + debug("\r\nSPWF> %s(%d): Out of memory!\r\n", __func__, __LINE__); +#endif + debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__); + return SPWFXX_ERR_OOM; /* out of memory: give up here! */ + } + + /* init packet */ + packet->id = spwf_id; + packet->len = amount; + packet->next = 0; + + /* read data in */ + if(!(_read_in((char*)(packet + 1), spwf_id, amount) > 0)) { + free(packet); + debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__); + return SPWFXX_ERR_READ; + } else { + debug_if(_dbg_on, "\r\nSPWF> %s():\t%d:%d\r\n", __func__, spwf_id, amount); + + /* append to packet list */ + *_packets_end = packet; + _packets_end = &packet->next; + + /* force call of (external) callback */ + _call_callback(); + } + + return SPWFXX_ERR_OK; +} + +void SPWFSAxx::_free_packets(int spwf_id) { + // check if any packets are ready for `spwf_id` + for(struct packet **p = &_packets; *p;) { + if ((*p)->id == spwf_id) { + struct packet *q = *p; + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + free(q); + } else { + p = &(*p)->next; + } + } +} + +void SPWFSAxx::_free_all_packets() { + for (int spwf_id = 0; spwf_id < SPWFSA_SOCKET_COUNT; spwf_id++) { + _free_packets(spwf_id); + } +} + +bool SPWFSAxx::close(int spwf_id) +{ + bool ret = false; + + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); // `spwf_id` is valid + + for(int retry_cnt = 0; retry_cnt < SPWFXX_MAX_TRIALS; retry_cnt++) { + Timer timer; + timer.start(); + + // Flush out pending data + while(true) { + int amount = _read_in_pkt(spwf_id, true); + if(amount < 0) { // SPWFXX error + /* empty RX buffer & try to close */ + empty_rx_buffer(); + break; + } + if(amount == 0) break; // no more data to be read + + /* Try to work around module API bug: + * break out & try to close after 20 seconds + */ + if(timer.read() > 20) { + break; + } + + /* immediately free packet(s) (to avoid "out of memory") */ + _free_packets(spwf_id); + + /* interleave bottom halves */ + _execute_bottom_halves(); + } + + // Close socket + if (_parser.send("AT+S.SOCKC=%d", spwf_id) + && _recv_ok()) { + ret = true; + break; // finish closing + } else { // close failed + debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__); + /* interleave bottom halves */ + _execute_bottom_halves(); + + /* free packets */ + _free_packets(spwf_id); + } + } + + /* anticipate bottom halves */ + _execute_bottom_halves(); + + if(ret) { + /* clear pending data flag (should be redundant) */ + _clear_pending_data(spwf_id); + + /* free packets for this socket */ + _free_packets(spwf_id); + + /* reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + } else { + debug_if(_dbg_on, "\r\nSPWF> SPWFSAxx::close failed (%d)\r\n", __LINE__); + + int internal_id = _associated_interface.get_internal_id(spwf_id); + if(!_associated_interface._socket_is_still_connected(internal_id)) { + /* clear pending data flag (should be redundant) */ + _clear_pending_data(spwf_id); + + /* free packets for this socket */ + _free_packets(spwf_id); + + /* reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + + ret = true; + } + } + + return ret; +} + +/* + * Buffered serial event handler + * + * Note: executed in IRQ context! + * Note: do not call (external) callback in IRQ context while performing critical module operations + */ +void SPWFSAxx::_event_handler(void) +{ + if(!_is_event_callback_blocked()) { + _call_callback(); + } +} + +/* + * Common error handler + */ +void SPWFSAxx::_error_handler(void) +{ + if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ ERROR:%s (%d)\r\n", _msg_buffer, __LINE__); + } else { + debug_if(_dbg_on, "\r\nSPWF> Unknown ERROR string in SPWFSAxx::_error_handler (%d)\r\n", __LINE__); + } + + /* force call of (external) callback */ + _call_callback(); +} + +/* + * Handling oob ("+WIND:33:WiFi Network Lost") + */ +void SPWFSAxx::_network_lost_handler_th(void) +{ +#ifndef NDEBUG + static unsigned int net_loss_cnt = 0; + net_loss_cnt++; +#endif + + _recv_delim_cr_lf(); + + debug_if(_dbg_on, "AT^ +WIND:33:WiFi Network Lost\r\n"); + +#ifndef NDEBUG + debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_th: %d\r\n", net_loss_cnt); +#else // NDEBUG + debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_th: %d\r\n", __LINE__); +#endif // NDEBUG + + /* set flag to signal network loss */ + _network_lost_flag = true; + + /* force call of (external) callback */ + _call_callback(); + + return; +} + +/* betzw - WORK AROUND module FW issues: split up big packages in smaller ones */ +void SPWFSAxx::_add_pending_packet_sz(int spwf_id, uint32_t size) { + uint32_t to_add; + uint32_t added = _get_cumulative_size(spwf_id); + + if(size <= added) { // might happen due to delayed WIND delivery + debug_if(_dbg_on, "\r\nSPWF> WARNING: %s failed at line #%d\r\n", __func__, __LINE__); + return; + } + + for(to_add = ((size - added) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (size - added); + added < size; + to_add = ((size - added) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (size - added)) { + _add_pending_pkt_size(spwf_id, added + to_add); + added += to_add; + } + + /* force call of (external) callback */ + _call_callback(); + + /* set that data is pending */ + _set_pending_data(spwf_id); +} + +/* + * Handling oob ("+WIND:55:Pending Data") + */ +void SPWFSAxx::_packet_handler_th(void) +{ + int internal_id, spwf_id; + int amount; + + /* parse out the socket id & amount */ + if (!(_parser.recv(SPWFXX_RECV_PENDING_DATA, &spwf_id, &amount) && _recv_delim_lf())) { +#ifndef NDEBUG + error("\r\nSPWF> SPWFSAxx::%s failed!\r\n", __func__); +#endif + return; + } + + debug_if(_dbg_on, "AT^ +WIND:55:Pending Data:%d:%d\r\n", spwf_id, amount); + + /* check for the module to report a valid id */ + MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + /* set that there is pending data for socket */ + /* NOTE: it seems as if asynchronous indications might report not up-to-date data length values + * therefore we just record the socket id without considering the `amount` of data reported! + */ + internal_id = _associated_interface.get_internal_id(spwf_id); + if(internal_id != SPWFSA_SOCKET_COUNT) { + debug_if(_dbg_on, "AT^ +WIND:55:Pending Data:%d:%d - #2\r\n", spwf_id, amount); + _add_pending_packet_sz(spwf_id, amount); + + MBED_ASSERT(_get_pending_pkt_size(spwf_id) != 0); + } else { + debug_if(_dbg_on, "\r\nSPWFSAxx::%s got invalid id %d\r\n", __func__, spwf_id); + } +} + +void SPWFSAxx::_network_lost_handler_bh(void) +{ + if(!_network_lost_flag) return; + _network_lost_flag = false; + + { + bool were_connected; + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* do not call (external) callback in IRQ context as long as network is lost */ + Timer timer; + timer.start(); + + _parser.set_timeout(SPWF_NETLOST_TIMEOUT); + + were_connected = isConnected(); + _associated_interface._connected_to_network = false; + + if(were_connected) { + unsigned int n1, n2, n3, n4; + + while(true) { + if (timer.read_ms() > SPWF_CONNECT_TIMEOUT) { + debug_if(_dbg_on, "\r\nSPWF> SPWFSAxx::_network_lost_handler_bh() #%d\r\n", __LINE__); + disconnect(); + empty_rx_buffer(); + goto nlh_get_out; + } + + if((_parser.recv(SPWFXX_RECV_WIFI_UP, &n1, &n2, &n3, &n4)) && _recv_delim_lf()) { + debug_if(_dbg_on, "\r\nSPWF> Re-connected (%u.%u.%u.%u)!\r\n", n1, n2, n3, n4); + + _associated_interface._connected_to_network = true; + goto nlh_get_out; + } + } + } else { + debug_if(_dbg_on, "\r\nSPWF> Leaving SPWFSAxx::_network_lost_handler_bh\r\n"); + goto nlh_get_out; + } + + nlh_get_out: + debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_bh\r\n"); + _parser.set_timeout(_timeout); + + /* force call of (external) callback */ + _call_callback(); + + return; + } +} + +void SPWFSAxx::_recover_from_hard_faults(void) { + disconnect(); + empty_rx_buffer(); + + /* force call of (external) callback */ + _call_callback(); +} + +/* + * Handling oob ("+WIND:8:Hard Fault") + */ +void SPWFSAxx::_hard_fault_handler(void) +{ + _parser.set_timeout(SPWF_RECV_TIMEOUT); + if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) { +#ifndef NDEBUG + error("\r\nSPWF> hard fault error:\r\n%s\r\n", _msg_buffer); +#else // NDEBUG + debug("\r\nSPWF> hard fault error:\r\n%s\r\n", _msg_buffer); +#endif // NDEBUG + } else { +#ifndef NDEBUG + error("\r\nSPWF> unknown hard fault error\r\n"); +#else // NDEBUG + debug("\r\nSPWF> unknown hard fault error\r\n"); +#endif // NDEBUG + } + + // This is most likely the best we can do to recover from this module hard fault + _parser.set_timeout(SPWF_HF_TIMEOUT); + _recover_from_hard_faults(); + _parser.set_timeout(_timeout); + + /* force call of (external) callback */ + _call_callback(); +} + +/* + * Handling oob ("+WIND:5:WiFi Hardware Failure") + */ +void SPWFSAxx::_wifi_hwfault_handler(void) +{ + unsigned int failure_nr; + + /* parse out the socket id & amount */ + _parser.recv(":%u\n", &failure_nr); + _recv_delim_lf(); + +#ifndef NDEBUG + error("\r\nSPWF> WiFi HW fault error: %u\r\n", failure_nr); +#else // NDEBUG + debug("\r\nSPWF> WiFi HW fault error: %u\r\n", failure_nr); + + // This is most likely the best we can do to recover from this module hard fault + _parser.set_timeout(SPWF_HF_TIMEOUT); + _recover_from_hard_faults(); + _parser.set_timeout(_timeout); +#endif // NDEBUG + + /* force call of (external) callback */ + _call_callback(); +} + +/* + * Handling oob ("+WIND:58:Socket Closed") + * when server closes a client connection + * + * NOTE: When a socket client receives an indication about socket server gone (only for TCP sockets, WIND:58), + * the socket connection is NOT automatically closed! + */ +void SPWFSAxx::_server_gone_handler(void) +{ + int spwf_id, internal_id; + + if(!(_parser.recv(SPWFXX_RECV_SOCKET_CLOSED, &spwf_id) && _recv_delim_lf())) { +#ifndef NDEBUG + error("\r\nSPWF> SPWFSAxx::%s failed!\r\n", __func__); +#endif + goto _get_out; + } + + debug_if(_dbg_on, "AT^ +WIND:58:Socket Closed:%d\r\n", spwf_id); + + /* check for the module to report a valid id */ + MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + /* only set `server_gone` + * user still can receive data & must still explicitly close the socket + */ + internal_id = _associated_interface.get_internal_id(spwf_id); + if(internal_id != SPWFSA_SOCKET_COUNT) { + _associated_interface._ids[internal_id].server_gone = true; + } + +_get_out: + /* force call of (external) callback */ + _call_callback(); +} + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 +/* + * Handling oob (currently only for "+WIND:24:WiFi Up::") + */ +void SPWFSAxx::_skip_oob(void) +{ + if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) { + debug_if(_dbg_on, "AT^ +WIND:24:WiFi Up::%s\r\n", _msg_buffer); + } else { + debug_if(_dbg_on, "\r\nSPWF> Invalid string in SPWFSAxx::_skip_oob (%d)\r\n", __LINE__); + } +} +#endif + +void SPWFSAxx::setTimeout(uint32_t timeout_ms) +{ + _timeout = timeout_ms; + _parser.set_timeout(timeout_ms); +} + +void SPWFSAxx::attach(Callback<void()> func) +{ + _callback_func = func; /* do not call (external) callback in IRQ context during critical module operations */ +} + +/** + * Recv Function + */ +int32_t SPWFSAxx::recv(int spwf_id, void *data, uint32_t amount, bool datagram) +{ + BlockExecuter bh_handler(Callback<void()>(this, &SPWFSAxx::_execute_bottom_halves)); + + while (true) { + /* check if any packets are ready for us */ + for (struct packet **p = &_packets; *p; p = &(*p)->next) { + if ((*p)->id == spwf_id) { + debug_if(_dbg_on, "\r\nSPWF> Read done on ID %d and length of packet is %d\r\n",spwf_id,(*p)->len); + struct packet *q = *p; + + MBED_ASSERT(q->len > 0); + + if(datagram) { // UDP => always remove pkt size + // will always consume a whole pending size + uint32_t ret; + + debug_if(_dbg_on, "\r\nSPWF> %s():\t\t\t%d:%d (datagram)\r\n", __func__, spwf_id, q->len); + + ret = (amount < q->len) ? amount : q->len; + memcpy(data, q+1, ret); + + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + free(q); + + return ret; + } else { // TCP + if (q->len <= amount) { // return and remove full packet + memcpy(data, q+1, q->len); + + if (_packets_end == &(*p)->next) { + _packets_end = p; + } + *p = (*p)->next; + uint32_t len = q->len; + free(q); + + return len; + } else { // `q->len > amount`, return only partial packet + if(amount > 0) { + memcpy(data, q+1, amount); + q->len -= amount; + memmove(q+1, (uint8_t*)(q+1) + amount, q->len); + } + + return amount; + } + } + } + } + + /* check for pending data on module */ + { + int len; + + len = _read_in_pkt(spwf_id, false); + if(len <= 0) { /* SPWFXX error or no more data to be read */ + return -1; + } + } + } +} + +void SPWFSAxx::_process_winds(void) { + do { + if(_parser.process_oob()) { + /* nothing else to do! */; + } else { + debug_if(_dbg_on, "%s():\t\tNo (more) oob's found!\r\n", __func__); + return; // no (more) oob's found + } + } while(true); +} + +/* Note: returns + * '>=0' in case of success, amount of read in data (in bytes) + * 'SPWFXX_ERR_OOM' in case of "out of memory" + * 'SPWFXX_ERR_READ' in case of other `_read_in_packet()` error + * 'SPWFXX_ERR_LEN' in case of `_read_len()` error + */ +int SPWFSAxx::_read_in_pkt(int spwf_id, bool close) { + int pending; + uint32_t wind_pending; + BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* do not call (external) callback in IRQ context while receiving */ + + _process_winds(); // perform async indication handling + + if(close) { // read in all data + wind_pending = pending = _read_len(spwf_id); // triggers also async indication handling! + + if(pending > 0) { + /* reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + /* create new entry for pending size */ + _add_pending_pkt_size(spwf_id, (uint32_t)pending); +#ifndef NDEBUG + wind_pending = _get_pending_pkt_size(spwf_id); + MBED_ASSERT(pending == (int)wind_pending); +#endif + } else if(pending < 0) { + debug_if(_dbg_on, "\r\nSPWF> %s(), #%d:`_read_len()` failed (%d)!\r\n", __func__, __LINE__, pending); + } + } else { // only read in already notified data + pending = wind_pending = _get_pending_pkt_size(spwf_id); + if(pending == 0) { // special handling for no packets pending (to WORK AROUND missing WINDs)! + pending = _read_len(spwf_id); // triggers also async indication handling! + + if(pending > 0) { + _process_winds(); // perform async indication handling (again) + wind_pending = _get_pending_pkt_size(spwf_id); + + if(wind_pending == 0) { + /* betzw - WORK AROUND module FW issues: create new entry for pending size */ + debug_if(_dbg_on, "%s():\t\tAdd packet w/o WIND (%d)!\r\n", __func__, pending); + _add_pending_packet_sz(spwf_id, (uint32_t)pending); + + pending = wind_pending = _get_pending_pkt_size(spwf_id); + MBED_ASSERT(wind_pending > 0); + } + } else if(pending < 0) { + debug_if(_dbg_on, "\r\nSPWF> %s(), #%d:`_read_len()` failed (%d)!\r\n", __func__, __LINE__, pending); + } + } + } + + if((pending > 0) && (wind_pending > 0)) { + int ret = _read_in_packet(spwf_id, wind_pending); + if(ret < 0) { /* "out of memory" or `_read_in_packet()` error */ + /* we do not know if data is still pending at this point + but leaving the pending data bit set might lead to an endless loop */ + _clear_pending_data(spwf_id); + /* also reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + + return ret; + } + + if((_get_cumulative_size(spwf_id) == 0) && (pending <= (int)wind_pending)) { + _clear_pending_data(spwf_id); + } + } else if(pending < 0) { /* 'SPWFXX_ERR_LEN' error */ + MBED_ASSERT(pending == SPWFXX_ERR_LEN); + /* we do not know if data is still pending at this point + but leaving the pending data bit set might lead to an endless loop */ + _clear_pending_data(spwf_id); + /* also reset pending data sizes */ + _reset_pending_pkt_sizes(spwf_id); + + return pending; + } else if(pending == 0) { + MBED_ASSERT(wind_pending == 0); + _clear_pending_data(spwf_id); + } else if(wind_pending == 0) { // `pending > 0` + /* betzw: should never happen! */ + MBED_ASSERT(false); + } + + return (int)wind_pending; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SPWFSAxx.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,446 @@ +/* SPWFSAxx Devices + * 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. + */ + +#ifndef SPWFSAXX_H +#define SPWFSAXX_H + +#include "mbed.h" +#include "ATCmdParser.h" +#include "BlockExecuter.h" + +/* Common SPWFSAxx macros */ +#define SPWFXX_WINDS_LOW_ON "0x00000000" +#define SPWFXX_DEFAULT_BAUD_RATE 115200 +#define SPWFXX_MAX_TRIALS 3 + +#if !defined(SPWFSAXX_RTS_PIN) +#define SPWFSAXX_RTS_PIN NC +#endif // !defined(SPWFSAXX_RTS_PIN) +#if !defined(SPWFSAXX_CTS_PIN) +#define SPWFSAXX_CTS_PIN NC +#endif // !defined(SPWFSAXX_CTS_PIN) + +#define SPWFXX_ERR_OK (+1) +#define SPWFXX_ERR_OOM (-1) +#define SPWFXX_ERR_READ (-2) +#define SPWFXX_ERR_LEN (-3) + + +/* Max number of sockets & packets */ +#define SPWFSA_SOCKET_COUNT (8) +#define SPWFSA_MAX_PACKETS (4) + +#define PENDING_DATA_SLOTS (13) + +/* Pending data packets size buffer */ +class SpwfRealPendingPackets { +public: + SpwfRealPendingPackets() { + reset(); + } + + void add(uint32_t new_cum_size) { + MBED_ASSERT(new_cum_size >= cumulative_size); + + if(new_cum_size == cumulative_size) { + /* nothing to do */ + return; + } + + /* => `new_cum_size > cumulative_size` */ + real_pkt_sizes[last_pkt_ptr] = (uint16_t)(new_cum_size - cumulative_size); + cumulative_size = new_cum_size; + + last_pkt_ptr = (last_pkt_ptr + 1) % PENDING_DATA_SLOTS; + + MBED_ASSERT(first_pkt_ptr != last_pkt_ptr); + } + + uint32_t get(void) { + if(empty()) return 0; + + return real_pkt_sizes[first_pkt_ptr]; + } + + uint32_t cumulative(void) { + return cumulative_size; + } + + uint32_t remove(uint32_t size) { + MBED_ASSERT(!empty()); + + uint32_t ret = real_pkt_sizes[first_pkt_ptr]; + first_pkt_ptr = (first_pkt_ptr + 1) % PENDING_DATA_SLOTS; + + MBED_ASSERT(ret == size); + MBED_ASSERT(ret <= cumulative_size); + cumulative_size -= ret; + + return ret; + } + + void reset(void) { + memset(this, 0, sizeof(*this)); + } + +private: + bool empty(void) { + if(first_pkt_ptr == last_pkt_ptr) { + MBED_ASSERT(cumulative_size == 0); + return true; + } + return false; + } + + uint16_t real_pkt_sizes[PENDING_DATA_SLOTS]; + uint8_t first_pkt_ptr; + uint8_t last_pkt_ptr; + uint32_t cumulative_size; +}; + +class SpwfSAInterface; + +/** SPWFSAxx Interface class. + This is an interface to a SPWFSAxx module. + */ +class SPWFSAxx +{ +private: + /* abstract class*/ + SPWFSAxx(PinName tx, PinName rx, PinName rts, PinName cts, + SpwfSAInterface &ifce, bool debug, + PinName wakeup, PinName reset); + +public: + /** + * Init the SPWFSAxx + * + * @param mode mode in which to startup + * @return true only if SPWFSAxx has started up correctly + */ + bool startup(int mode); + + /** + * Connect SPWFSAxx to AP + * + * @param ap the name of the AP + * @param passPhrase the password of AP + * @param securityMode the security mode of AP (WPA/WPA2, WEP, Open) + * @return true only if SPWFSAxx is connected successfully + */ + bool connect(const char *ap, const char *passPhrase, int securityMode); + + /** + * Disconnect SPWFSAxx from AP + * + * @return true only if SPWFSAxx is disconnected successfully + */ + bool disconnect(void); + + /** + * Get the IP address of SPWFSAxx + * + * @return null-terminated IP address or null if no IP address is assigned + */ + const char *getIPAddress(void); + + /** + * Get the MAC address of SPWFSAxx + * + * @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 received + */ + const char *getGateway(void); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been received + */ + const char *getNetmask(void); + + /** Gets the current radio signal strength for active connection + * + * @return Connection strength in dBm (negative value) + */ + int8_t getRssi(); + + /** + * Sends data to an open socket + * + * @param spwf_id module id of socket to send to + * @param data data to be sent + * @param amount amount of data to be sent - max 1024 + * @param internal_id driver id of socket to send to + * @return number of written bytes on success, negative on failure + */ + nsapi_size_or_error_t send(int spwf_id, const void *data, uint32_t amount, int internal_id); + + /** + * 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 + * @param datagram receive a datagram packet + * @return the number of bytes received + */ + int32_t recv(int id, void *data, uint32_t amount, bool datagram); + + /** + * 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); + + /** + * 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); + + /** + * 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)); + } + + static const char _cr_ = '\x0d'; // '\r' carriage return + static const char _lf_ = '\x0a'; // '\n' line feed + +private: + UARTSerial _serial; + ATCmdParser _parser; + + DigitalOut _wakeup; + DigitalOut _reset; + PinName _rts; + PinName _cts; + + int _timeout; + bool _dbg_on; + + int _pending_sockets_bitmap; + SpwfRealPendingPackets _pending_pkt_sizes[SPWFSA_SOCKET_COUNT]; + + bool _network_lost_flag; + SpwfSAInterface &_associated_interface; + + /** + * Reset SPWFSAxx + * + * @return true only if SPWFSAxx resets successfully + */ + bool hw_reset(void); + bool reset(void); + + /** + * Check if SPWFSAxx is connected + * + * @return true only if the chip has an IP address + */ + bool isConnected(void); + + /** + * Checks if data is available + */ + bool readable(void) { + return _serial.FileHandle::readable(); + } + + /** + * Checks if data can be written + */ + bool writeable(void) { + return _serial.FileHandle::writable(); + } + + /** + * Try to empty RX buffer + * Can be used when commands fail receiving expected response to try to recover situation + * @note Gives no guarantee that situation improves + */ + void empty_rx_buffer(void) { + while(readable()) _parser.getc(); + } + + /* block calling (external) callback */ + volatile unsigned int _call_event_callback_blocked; + Callback<void()> _callback_func; + + struct packet { + struct packet *next; + int id; + uint32_t len; + // data follows + } *_packets, **_packets_end; + + void _packet_handler_th(void); + void _execute_bottom_halves(void); + void _network_lost_handler_th(void); + void _network_lost_handler_bh(void); + void _hard_fault_handler(void); + void _wifi_hwfault_handler(void); + void _server_gone_handler(void); +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + void _skip_oob(void); +#endif + bool _wait_wifi_hw_started(void); + bool _wait_console_active(void); + int _read_len(int); + int _flush_in(char*, int); + bool _winds_off(void); + void _winds_on(void); + void _read_in_pending(void); + int _read_in_pkt(int spwf_id, bool close); + int _read_in_packet(int spwf_id, uint32_t amount); + void _recover_from_hard_faults(void); + void _free_packets(int spwf_id); + void _free_all_packets(void); + void _process_winds(); + + virtual int _read_in(char*, int, uint32_t) = 0; + + bool _recv_delim_lf(void) { + return (_parser.getc() == _lf_); + } + + bool _recv_delim_cr(void) { + return (_parser.getc() == _cr_); + } + + bool _recv_delim_cr_lf(void) { + return _recv_delim_cr() && _recv_delim_lf(); + } + + bool _recv_ok(void) { + return _parser.recv(SPWFXX_RECV_OK) && _recv_delim_lf(); + } + + void _add_pending_packet_sz(int spwf_id, uint32_t size); + void _add_pending_pkt_size(int spwf_id, uint32_t size) { + _pending_pkt_sizes[spwf_id].add(size); + } + + uint32_t _get_cumulative_size(int spwf_id) { + return _pending_pkt_sizes[spwf_id].cumulative(); + } + + uint32_t _remove_pending_pkt_size(int spwf_id, uint32_t size) { + return _pending_pkt_sizes[spwf_id].remove(size); + } + + uint32_t _get_pending_pkt_size(int spwf_id) { + return _pending_pkt_sizes[spwf_id].get(); + } + + void _reset_pending_pkt_sizes(int spwf_id) { + _pending_pkt_sizes[spwf_id].reset(); + } + + void _set_pending_data(int spwf_id) { + _pending_sockets_bitmap |= (1 << spwf_id); + } + + void _clear_pending_data(int spwf_id) { + _pending_sockets_bitmap &= ~(1 << spwf_id); + } + + bool _is_data_pending(int spwf_id) { + return (_pending_sockets_bitmap & (1 << spwf_id)) ? true : false; + } + + bool _is_data_pending(void) { + if(_pending_sockets_bitmap != 0) return true; + else return false; + } + + void _packet_handler_bh(void) { + /* read in other eventually pending packages */ + _read_in_pending(); + } + + /* Do not call the (external) callback in IRQ context while performing critical module operations */ + void _event_handler(void); + + void _error_handler(void); + + void _call_callback(void) { + if((bool)_callback_func) { + _callback_func(); + } + } + + bool _is_event_callback_blocked(void) { + return (_call_event_callback_blocked != 0); + } + + void _block_event_callback(void) { + _call_event_callback_blocked++; + } + + void _unblock_event_callback(void) { + MBED_ASSERT(_call_event_callback_blocked > 0); + _call_event_callback_blocked--; + if(_call_event_callback_blocked == 0) { + _trigger_event_callback(); + } + } + + /* trigger call of (external) callback in case there is still data */ + void _trigger_event_callback(void) { + MBED_ASSERT(_call_event_callback_blocked == 0); + /* if still data available */ + if(readable()) { + _call_callback(); + } + } + + char _ip_buffer[16]; + char _gateway_buffer[16]; + char _netmask_buffer[16]; + char _mac_buffer[18]; + + char _msg_buffer[256]; + +private: + friend class SPWFSA01; + friend class SPWFSA04; + friend class SpwfSAInterface; +}; + +#endif // SPWFSAXX_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SpwfSAInterface.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,510 @@ +/* mbed Microcontroller Library + * Copyright (c) 20015 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. + */ + +/** + ****************************************************************************** + * @file SpwfSAInterface.cpp + * @author STMicroelectronics + * @brief Implementation of the NetworkStack for the SPWF Device + ****************************************************************************** + * @copy + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +#include "SpwfSAInterface.h" +#include "mbed_debug.h" +#include "BlockExecuter.h" + +#if MBED_CONF_RTOS_PRESENT +#define SYNC_HANDLER ScopedMutexLock sync_handler(_spwf_mutex) // assuming a recursive mutex +#else +#define SYNC_HANDLER +#endif + + +SpwfSAInterface::SpwfSAInterface(PinName tx, PinName rx, + PinName rts, PinName cts, bool debug, + PinName wakeup, PinName reset) +: _spwf(tx, rx, rts, cts, *this, debug, wakeup, reset), + _dbg_on(debug) +{ + inner_constructor(); + reset_credentials(); +} + +nsapi_error_t SpwfSAInterface::init(void) +{ + _spwf.setTimeout(SPWF_INIT_TIMEOUT); + + if(_spwf.startup(0)) { + return NSAPI_ERROR_OK; + } + else return NSAPI_ERROR_DEVICE_ERROR; +} + +nsapi_error_t SpwfSAInterface::connect(void) +{ + int mode; + char *pass_phrase = ap_pass; + SYNC_HANDLER; + + // check for valid SSID + if(ap_ssid[0] == '\0') { + return NSAPI_ERROR_PARAMETER; + } + + switch(ap_sec) + { + case NSAPI_SECURITY_NONE: + mode = 0; + pass_phrase = NULL; + break; + case NSAPI_SECURITY_WEP: + mode = 1; + break; + case NSAPI_SECURITY_WPA: + case NSAPI_SECURITY_WPA2: + mode = 2; + break; + default: + mode = 2; + break; + } + + // First: disconnect + if(_connected_to_network) { + if(!disconnect()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } + + //initialize the device before connecting + if(!_isInitialized) + { + if(init() != NSAPI_ERROR_OK) return NSAPI_ERROR_DEVICE_ERROR; + _isInitialized=true; + } + + // Then: (re-)connect + _spwf.setTimeout(SPWF_CONNECT_TIMEOUT); + + if (!_spwf.connect(ap_ssid, pass_phrase, mode)) { + return NSAPI_ERROR_AUTH_FAILURE; + } + + if (!_spwf.getIPAddress()) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + _connected_to_network = true; + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + nsapi_error_t ret; + SYNC_HANDLER; + + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + ret = set_credentials(ssid, pass, security); + if(ret != NSAPI_ERROR_OK) return ret; + + return connect(); +} + +nsapi_error_t SpwfSAInterface::disconnect(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_DISCONNECT_TIMEOUT); + CHECK_NOT_CONNECTED_ERR(); + + if (!_spwf.disconnect()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return NSAPI_ERROR_OK; +} + +const char *SpwfSAInterface::get_ip_address(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getIPAddress(); +} + +const char *SpwfSAInterface::get_mac_address(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getMACAddress(); +} + +const char *SpwfSAInterface::get_gateway(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return NULL; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getGateway(); +} + +const char *SpwfSAInterface::get_netmask(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return NULL; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getNetmask(); +} + +nsapi_error_t SpwfSAInterface::socket_open(void **handle, nsapi_protocol_t proto) +{ + int internal_id; + SYNC_HANDLER; + + for (internal_id = 0; internal_id < SPWFSA_SOCKET_COUNT; internal_id++) { + if(_ids[internal_id].internal_id == SPWFSA_SOCKET_COUNT) break; + } + + if(internal_id == SPWFSA_SOCKET_COUNT) { + debug_if(_dbg_on, "NO Socket ID Error\r\n"); + return NSAPI_ERROR_NO_SOCKET; + } + + spwf_socket_t *socket = &_ids[internal_id]; + socket->internal_id = internal_id; + socket->spwf_id = SPWFSA_SOCKET_COUNT; + socket->server_gone = false; + socket->no_more_data = false; + socket->proto = proto; + socket->addr = SocketAddress(); + + *handle = socket; + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::socket_connect(void *handle, const SocketAddress &addr) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + MBED_ASSERT(((unsigned int)socket->internal_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + if(_socket_has_connected(socket->internal_id)) { + return NSAPI_ERROR_IS_CONNECTED; + } + + _spwf.setTimeout(SPWF_OPEN_TIMEOUT); + + const char *proto = (socket->proto == NSAPI_UDP) ? "u" : "t"; //"s" for secure socket? + + if(addr.get_ip_version() != NSAPI_IPv4) { // IPv6 not supported (yet) + return NSAPI_ERROR_UNSUPPORTED; + } + + { + BlockExecuter netsock_wa_obj(Callback<void()>(&_spwf, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(&_spwf, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + /* block asynchronous indications */ + if(!_spwf._winds_off()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + { + BlockExecuter bh_handler(Callback<void()>(&_spwf, &SPWFSAxx::_execute_bottom_halves)); + { + BlockExecuter winds_enabler(Callback<void()>(&_spwf, &SPWFSAxx::_winds_on)); + + if(!_spwf.open(proto, &socket->spwf_id, addr.get_ip_address(), addr.get_port())) { + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_DEVICE_ERROR; + } + + /* check for the module to report a valid id */ + MBED_ASSERT(((unsigned int)socket->spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + _internal_ids[socket->spwf_id] = socket->internal_id; + socket->addr = addr; + + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_OK; + } + } + } +} + +nsapi_error_t SpwfSAInterface::socket_bind(void *handle, const SocketAddress &address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_close(void *handle) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + int internal_id = socket->internal_id; + SYNC_HANDLER; + + if(!_socket_is_open(internal_id)) return NSAPI_ERROR_NO_SOCKET; + + if(_socket_has_connected(socket)) { + _spwf.setTimeout(SPWF_CLOSE_TIMEOUT); + if (!_spwf.close(socket->spwf_id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + _internal_ids[socket->spwf_id] = SPWFSA_SOCKET_COUNT; + } + + _ids[internal_id].internal_id = SPWFSA_SOCKET_COUNT; + _ids[internal_id].spwf_id = SPWFSA_SOCKET_COUNT; + + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t SpwfSAInterface::socket_send(void *handle, const void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + CHECK_NOT_CONNECTED_ERR(); + + _spwf.setTimeout(SPWF_SEND_TIMEOUT); + return _spwf.send(socket->spwf_id, data, size, socket->internal_id); +} + +nsapi_size_or_error_t SpwfSAInterface::socket_recv(void *handle, void *data, unsigned size) +{ + SYNC_HANDLER; + + return _socket_recv(handle, data, size, false); +} + +nsapi_size_or_error_t SpwfSAInterface::_socket_recv(void *handle, void *data, unsigned size, bool datagram) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + + CHECK_NOT_CONNECTED_ERR(); + + if(!_socket_has_connected(socket)) { + return NSAPI_ERROR_WOULD_BLOCK; + } else if(socket->no_more_data) { + return 0; + } + + _spwf.setTimeout(SPWF_RECV_TIMEOUT); + + int32_t recv = _spwf.recv(socket->spwf_id, (char*)data, (uint32_t)size, datagram); + + MBED_ASSERT(!_spwf._is_event_callback_blocked()); + MBED_ASSERT((recv != 0) || (size == 0)); + + if (recv < 0) { + if(!_socket_is_still_connected(socket)) { + socket->no_more_data = true; + return 0; + } + + return NSAPI_ERROR_WOULD_BLOCK; + } + + return recv; +} + +nsapi_size_or_error_t SpwfSAInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + CHECK_NOT_CONNECTED_ERR(); + + if ((_socket_has_connected(socket)) && (socket->addr != addr)) { + _spwf.setTimeout(SPWF_CLOSE_TIMEOUT); + if (!_spwf.close(socket->spwf_id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + _internal_ids[socket->spwf_id] = SPWFSA_SOCKET_COUNT; + socket->spwf_id = SPWFSA_SOCKET_COUNT; + } + + _spwf.setTimeout(SPWF_CONN_SND_TIMEOUT); + if (!_socket_has_connected(socket)) { + nsapi_error_t err = socket_connect(socket, addr); + if (err < 0) { + return err; + } + } + + return socket_send(socket, data, size); +} + +nsapi_size_or_error_t SpwfSAInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + nsapi_error_t ret; + SYNC_HANDLER; + + ret = _socket_recv(socket, data, size, true); + if (ret >= 0 && addr) { + *addr = socket->addr; + } + + return ret; +} + +void SpwfSAInterface::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + if(!_socket_is_open(socket)) return; // might happen e.g. after module hard fault or voluntary disconnection + + _cbs[socket->internal_id].callback = callback; + _cbs[socket->internal_id].data = data; +} + +void SpwfSAInterface::event(void) { + for (int internal_id = 0; internal_id < SPWFSA_SOCKET_COUNT; internal_id++) { + if (_cbs[internal_id].callback && (_ids[internal_id].internal_id != SPWFSA_SOCKET_COUNT)) { + _cbs[internal_id].callback(_cbs[internal_id].data); + } + } +} + +nsapi_error_t SpwfSAInterface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + SYNC_HANDLER; + + if((ssid == NULL) || (strlen(ssid) == 0)) { + return NSAPI_ERROR_PARAMETER; + } + + if((pass != NULL) && (strlen(pass) > 0)) { + if(strlen(pass) < sizeof(ap_pass)) { + if(security == NSAPI_SECURITY_NONE) { + return NSAPI_ERROR_PARAMETER; + } + } else { + return NSAPI_ERROR_PARAMETER; + } + } else if(security != NSAPI_SECURITY_NONE) { + return NSAPI_ERROR_PARAMETER; + } + + reset_credentials(); + + ap_sec = security; + strncpy(ap_ssid, ssid, sizeof(ap_ssid) - 1); + strncpy(ap_pass, pass, sizeof(ap_pass) - 1); + + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::set_channel(uint8_t channel) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int8_t SpwfSAInterface::get_rssi(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return 0; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getRssi(); +} + +nsapi_size_or_error_t SpwfSAInterface::scan(WiFiAccessPoint *res, unsigned count) +{ + SYNC_HANDLER; + + nsapi_size_or_error_t ret; + + //initialize the device before scanning + if(!_isInitialized) + { + if(init() != NSAPI_ERROR_OK) return NSAPI_ERROR_DEVICE_ERROR; + } + + _spwf.setTimeout(SPWF_SCAN_TIMEOUT); + + { + BlockExecuter netsock_wa_obj(Callback<void()>(&_spwf, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(&_spwf, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + /* block asynchronous indications */ + if(!_spwf._winds_off()) { + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_DEVICE_ERROR; + } + + ret = _spwf.scan(res, count); + + /* unblock asynchronous indications */ + _spwf._winds_on(); + } + + MBED_ASSERT(!_spwf._is_event_callback_blocked()); + + //de-initialize the device after scanning + if(!_isInitialized) + { + nsapi_error_t err = disconnect(); + if((err != NSAPI_ERROR_OK) && (err != NSAPI_ERROR_NO_CONNECTION)) return err; + } + + return ret; +} + +#if MBED_CONF_IDW0XX1_PROVIDE_DEFAULT + +WiFiInterface *WiFiInterface::get_default_instance() { + static SpwfSAInterface spwf(MBED_CONF_IDW0XX1_TX, MBED_CONF_IDW0XX1_RX); + return &spwf; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/SpwfSAInterface.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,443 @@ +/* mbed Microcontroller Library + * 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. + */ + +/** + ****************************************************************************** + * @file SpwfSAInterface.h + * @author STMicroelectronics + * @brief Header file of the NetworkStack for the SPWF Device + ****************************************************************************** + * @copy + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> + ****************************************************************************** + */ + +#ifndef SPWFSA_INTERFACE_H +#define SPWFSA_INTERFACE_H + +#include <limits.h> + +#include "mbed.h" + +#define IDW01M1 1 +#define IDW04A1 2 + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW01M1 +#include "SPWFSA01/SPWFSA01.h" +#elif MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 +#include "SPWFSA04/SPWFSA04.h" +#else +#error No (valid) Wi-Fi exapnsion board defined (MBED_CONF_IDW0XX1_EXPANSION_BOARD: options are IDW01M1 and IDW04A1) +#endif + +// Various timeouts for different SPWF operations +#define SPWF_CONNECT_TIMEOUT 60000 +#define SPWF_DISCONNECT_TIMEOUT 30002 +#define SPWF_HF_TIMEOUT 30001 +#define SPWF_NETLOST_TIMEOUT 30000 +#define SPWF_READ_BIN_TIMEOUT 13000 +#define SPWF_CLOSE_TIMEOUT 10001 +#define SPWF_SEND_TIMEOUT 10000 +#define SPWF_INIT_TIMEOUT 8000 +#define SPWF_OPEN_TIMEOUT 5002 +#define SPWF_CONN_SND_TIMEOUT 5001 +#define SPWF_SCAN_TIMEOUT 5000 +#define SPWF_MISC_TIMEOUT 301 +#define SPWF_RECV_TIMEOUT 300 + +/** SpwfSAInterface class + * Implementation of the NetworkStack for the SPWF Device + */ +// NOTE - betzw - TODO: MUST become singleton! +class SpwfSAInterface : public NetworkStack, public WiFiInterface +{ +public: + /** SpwfSAInterface constructor + * @param tx TX pin + * @param rx RX pin + * @param rts RTS pin + * @param cts CTS pin + * @param debug Enable debugging + * @param wakeup Wakeup pin + * @param reset Reset pin + */ + SpwfSAInterface(PinName tx = MBED_CONF_IDW0XX1_TX, PinName rx = MBED_CONF_IDW0XX1_RX, + PinName rts = SPWFSAXX_RTS_PIN, PinName cts = SPWFSAXX_CTS_PIN, bool debug = false, + PinName wakeup = SPWFSAXX_WAKEUP_PIN, PinName reset = SPWFSAXX_RESET_PIN); + + /** 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 nsapi_error_t 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 nsapi_error_t connect(const char *ssid, const char *pass, nsapi_security_t security = NSAPI_SECURITY_NONE, + uint8_t channel = 0); + + /** 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 nsapi_error_t 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 nsapi_error_t set_channel(uint8_t channel); + + /** Stop the interface + * @return `NSAPI_ERROR_OK` on success, negative on failure + */ + virtual nsapi_error_t 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 received + */ + 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 received + */ + 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. If the @a count is 0, function will only return count of available networks, so that + * user can allocated necessary memory. If the @count is grater than 0 and the @a ap is not NULL it'll be populated + * with discovered networks up to value of @a count. + * + * @param res Pointer to allocated array to store discovered AP + * @param count Size of allocated @a res array, or 0 to only count available AP + * @return Number of entries in @a, or if @a count was 0 number of available networks, + * negative on error see @a nsapi_error + */ + virtual nsapi_size_or_error_t 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; + +private: + /** 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 `NSAPI_ERROR_OK` on success, negative on failure + */ + virtual nsapi_error_t socket_open(void **handle, nsapi_protocol_t proto); + + /** Close the socket + * @param handle Socket handle + * @return `NSAPI_ERROR_OK` on success, negative on failure + * @note On failure, any memory associated with the socket must still + * be cleaned up + */ + virtual nsapi_error_t socket_close(void *handle); + + /** Bind a server socket to a specific port - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param handle Socket handle + * @param address Local address to listen for incoming connections on + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_error_t socket_bind(void *handle, const SocketAddress &address); + + /** Start listening for incoming connections - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued up at any + * one time [Default: 1] + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_error_t socket_listen(void *handle, int backlog); + + /** Connects this TCP socket to the server + * @param handle Socket handle + * @param address SocketAddress to connect to + * @return `NSAPI_ERROR_OK` on success, negative on failure + */ + virtual nsapi_error_t socket_connect(void *handle, const SocketAddress &address); + + /** Accept a new connection - NOT SUPPORTED + * + * This function is not supported and will return NSAPI_ERROR_UNSUPPORTED + * + * @param handle Handle in which to store new socket + * @param server Socket handle to server to accept from + * @return Not supported, returns NSAPI_ERROR_UNSUPPORTED + */ + virtual nsapi_error_t 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_BLOCK + */ + virtual nsapi_size_or_error_t 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_BLOCK + */ + virtual nsapi_size_or_error_t 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_BLOCK + */ + virtual nsapi_size_or_error_t 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_BLOCK + */ + virtual nsapi_size_or_error_t 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: + /** spwf_socket class + * Implementation of SPWF socket structure + */ + typedef struct spwf_socket { + int8_t internal_id; + int spwf_id; + bool server_gone; + bool no_more_data; + nsapi_protocol_t proto; + SocketAddress addr; + } spwf_socket_t; + + bool _socket_is_open(spwf_socket_t *sock) { + if(((unsigned int)sock->internal_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)) { + return (_ids[sock->internal_id].internal_id == sock->internal_id); + } + return false; + } + + bool _socket_has_connected(spwf_socket_t *sock) { + return (_socket_is_open(sock) && (((unsigned int)sock->spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT))); + } + + bool _socket_is_still_connected(spwf_socket_t *sock) { + return (_socket_has_connected(sock) && !sock->server_gone); + } + + bool _socket_is_open(int internal_id) { + if(((unsigned int)internal_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)) { + return (_ids[internal_id].internal_id == internal_id); + } + return false; + } + + bool _socket_has_connected(int internal_id) { + if(!_socket_is_open(internal_id)) return false; + + spwf_socket_t &sock = _ids[internal_id]; + return (sock.spwf_id != SPWFSA_SOCKET_COUNT); + } + + bool _socket_is_still_connected(int internal_id) { + if(!_socket_has_connected(internal_id)) return false; + + spwf_socket_t &sock = _ids[internal_id]; + return (!sock.server_gone); + } + + void reset_credentials() { + memset(ap_ssid, 0, sizeof(ap_ssid)); + memset(ap_pass, 0, sizeof(ap_pass)); + ap_sec = NSAPI_SECURITY_NONE; + } + +#if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW01M1 + SPWFSA01 _spwf; +#elif MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1 + SPWFSA04 _spwf; +#endif + + bool _isInitialized; + bool _dbg_on; + bool _connected_to_network; + + spwf_socket_t _ids[SPWFSA_SOCKET_COUNT]; + struct { + void (*callback)(void *); + void *data; + } _cbs[SPWFSA_SOCKET_COUNT]; + int _internal_ids[SPWFSA_SOCKET_COUNT]; + +#if MBED_CONF_RTOS_PRESENT + Mutex _spwf_mutex; +#endif + + char ap_ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + nsapi_security_t ap_sec; + char ap_pass[64]; /* The longest allowed passphrase */ + +private: + void event(void); + nsapi_error_t init(void); + nsapi_size_or_error_t _socket_recv(void *handle, void *data, unsigned size, bool datagram); + + + int get_internal_id(int spwf_id) { // checks also if `spwf_id` is (still) "valid" + if(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)) { // valid `spwf_id` + int internal_id = _internal_ids[spwf_id]; + if((_socket_is_open(internal_id)) && (_ids[internal_id].spwf_id == spwf_id)) { + return internal_id; + } else { + return SPWFSA_SOCKET_COUNT; + } + } else { // invalid `spwf_id` + return SPWFSA_SOCKET_COUNT; + } + } + + /* Called at initialization or after module hard fault */ + void inner_constructor() { + memset(_ids, 0, sizeof(_ids)); + memset(_cbs, 0, sizeof(_cbs)); + + for (int sock_cnt = 0; sock_cnt < SPWFSA_SOCKET_COUNT; sock_cnt++) { + _ids[sock_cnt].internal_id = SPWFSA_SOCKET_COUNT; + _ids[sock_cnt].spwf_id = SPWFSA_SOCKET_COUNT; + _internal_ids[sock_cnt] = SPWFSA_SOCKET_COUNT; + } + + _spwf.attach(this, &SpwfSAInterface::event); + + _connected_to_network = false; + _isInitialized = false; + } + +private: + friend class SPWFSAxx; + friend class SPWFSA01; + friend class SPWFSA04; +}; + +#define CHECK_NOT_CONNECTED_ERR() { \ + if(!_connected_to_network) return NSAPI_ERROR_NO_CONNECTION; \ +} \ + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/mbed_app_idw01m1.json Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,11 @@ +{ + "target_overrides": { + "*": { + "idw0xx1.expansion-board": "IDW01M1", + "drivers.uart-serial-txbuf-size": 512, + "drivers.uart-serial-rxbuf-size": 512, + "idw0xx1.tx": "PA_9", + "idw0xx1.rx": "PA_10" + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/mbed_app_idw04a1.json Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,12 @@ +{ + "target_overrides": { + "*": { + "idw0xx1.expansion-board": "IDW04A1", + "drivers.uart-serial-txbuf-size": 512, + "drivers.uart-serial-rxbuf-size": 512, + "idw0xx1.tx": "D8", + "idw0xx1.rx": "D2" + } + }, + "macros": ["IDW04A1_WIFI_HW_BUG_WA"] +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_IDW04A1/mbed_lib.json Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,21 @@ +{ + "name": "idw0xx1", + "config": { + "expansion-board":{ + "help": "Options are IDW01M1 and IDW04A1", + "value": "IDW01M1" + }, + "tx":{ + "help": "TX pin for serial connection to external device", + "value": "NC" + }, + "rx":{ + "help": "RX pin for serial connection to external device", + "value": "NC" + }, + "provide-default": { + "help": "Provide default WifiInterface. [true/false]", + "value": false + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ISM43362.lib Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/wifi-ism43362/#9136e73b2a9d5fe8246f88b31277b0116322659c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ATParser/ATParser.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,454 @@ +/* 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)) + +// activate / de-activate debug +#define dbg_on 0 +#define AT_DATA_PRINT 0 +#define AT_COMMAND_PRINT 0 +#define AT_HEXA_DATA 0 + +ATParser::ATParser(BufferedSpi &serial_spi, const char *delimiter, int buffer_size, int timeout) : + _serial_spi(&serial_spi), + _buffer_size(buffer_size), _in_prev(0), _oobs(NULL) +{ + _buffer = new char[buffer_size]; + setTimeout(timeout); + setDelimiter(delimiter); +} + + +// 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(); + debug_if(dbg_on, "ATParser write: %d BYTES\r\n", size_of_data); + debug_if(AT_DATA_PRINT, "ATParser write: (ASCII) ", size_of_data); + for (; i < size_of_data; i++) { + debug_if(AT_DATA_PRINT, "%c", data[i]); + if (putc(data[i]) < 0) { + debug_if(AT_DATA_PRINT, "\r\n"); + _bufferMutex.unlock(); + return -1; + } + } + debug_if(AT_DATA_PRINT, "\r\n"); + + _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 { + debug_if(dbg_on, "Pending data when reading from WIFI\r\n"); + return -1; + } + + debug_if(dbg_on, "ATParser read: %d data avail in SPI\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 AT_HEXA_DATA + debug_if(AT_DATA_PRINT, "ATParser read: (HEXA) "); + for (i = 0; i < readsize; i++) { + debug_if(AT_DATA_PRINT, "%2X ", data[i]); + if ((i + 1) % 20 == 0) { + debug_if(AT_DATA_PRINT, "\r\n"); + } + } + debug_if(AT_DATA_PRINT, "\r\n"); +#endif + debug_if(AT_DATA_PRINT, "ATParser read: (ASCII) "); + for (i = 0; i < readsize; i++) { + debug_if(AT_DATA_PRINT, "%c", data[i]); + } + debug_if(AT_DATA_PRINT, "\r\n"); + + _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(AT_COMMAND_PRINT, "AT> %s\n", _buffer); + _bufferMutex.unlock(); + return ret; +} + +bool ATParser::vrecv(const char *response, va_list args) +{ + _bufferMutex.lock(); + + 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, "ATParser vrecv: 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; + } + + // debug_if(AT_DATA_PRINT, "%2X ", c); + + _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') { + // 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(AT_COMMAND_PRINT, "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/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ATParser/ATParser.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,246 @@ +/* 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" + +#define DEFAULT_SPI_TIMEOUT 60000 /* 1 minute */ + +/** +* 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; + + // Parsing information + const char *_delimiter; + int _delim_size; + char _in_prev; + 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 = DEFAULT_SPI_TIMEOUT); + + /** + * 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) + { + _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); + } + + /** + * 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/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,86 @@ + +/** + * @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/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/Buffer/MyBuffer.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,164 @@ + +/** + * @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/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedPrint.c Tue Mar 12 13:48:39 2019 +0800 @@ -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/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,335 @@ +/** + * @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; + nss = 1; + wait_us(15); + + 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); + unlock(); +} + +void BufferedSpi::enable_nss() +{ + lock(); + 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; + uint8_t FirstRemoved = 1; + int tmp; + + /* 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 - 2))) { + tmp = SPI::write(0xAA); // dummy write to receive 2 bytes + + if (!((len == 0) && (tmp == 0x0A0D) && (FirstRemoved))) { + /* 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; + } + } else { + FirstRemoved = 0; + } + } + 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/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ATParser/BufferedSpi/BufferedSpi.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,234 @@ + +/** + * @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 = 2500, uint32_t tx_multiple = 1, 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 in ms + */ + void setTimeout(int timeout) + { + /* this is a safe guard timeout at SPI level in case module is stuck */ + _timeout = timeout; + } + + /** 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/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ISM43362.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,710 @@ +/* ISM43362 Example +* +* Copyright (c) STMicroelectronics 2018 + * + * 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" + +// activate / de-activate debug +#define ism_debug 0 + +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); + _bufferspi.format(16, 0); /* 16bits, ploarity low, phase 1Edge, master mode */ + _bufferspi.frequency(20000000); /* up to 20 MHz */ + _active_id = 0xFF; + _FwVersionId = 0; + + _ism_debug = debug || ism_debug; + reset(); +} + +/** + * @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++; + } + if (*ptr == 'C') { /* input string from get_firmware_version is Cx.x.x.x */ + ptr++; + } + + 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 */ +} + +uint32_t ISM43362::get_firmware_version(void) +{ + char tmp_buffer[250]; + char *ptr, *ptr2; + char _fw_version[16]; + + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if (!(_parser.send("I?") && _parser.recv("%[^\n^\r]\r\n", tmp_buffer) && check_response())) { + debug_if(_ism_debug, "ISM43362: get_firmware_version is FAIL\r\n"); + return 0; + } + debug_if(_ism_debug, "ISM43362: get_firmware_version = %s\r\n", tmp_buffer); + + // 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, "ISM43362: get_firmware_version decoding is FAIL\r\n"); + return 0; + } + strncpy(_fw_version, ptr, ptr2 - ptr); + _FwVersionId = ParseNumber(_fw_version, NULL); + + return _FwVersionId; +} + +bool ISM43362::reset(void) +{ + char tmp_buffer[100]; + debug_if(_ism_debug, "ISM43362: Reset Module\r\n"); + _resetpin = 0; + wait_ms(10); + _resetpin = 1; + wait_ms(500); + + /* Wait for prompt line : the string is "> ". */ + /* As the space char is not detected by sscanf function in parser.recv, */ + /* we need to use %[\n] */ + if (!_parser.recv(">%[^\n]", tmp_buffer)) { + debug_if(_ism_debug, "ISM43362: Reset Module failed\r\n"); + return false; + } + return true; +} + +void ISM43362::print_rx_buff(void) +{ + char tmp[150] = {0}; + uint16_t i = 0; + debug_if(_ism_debug, "ISM43362: "); + 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, "\n"); + debug_if(_ism_debug, "ISM43362: 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) +{ + char tmp_buffer[100]; + if (!_parser.recv("OK\r\n")) { + print_rx_buff(); + _parser.flush(); + return false; + } + + /* Then we should get the prompt: "> " */ + /* As the space char is not detected by sscanf function in parser.recv, */ + /* we need to use %[\n] */ + if (!_parser.recv(">%[^\n]", tmp_buffer)) { + debug_if(_ism_debug, "ISM43362: 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 contains such */ + while (1) { + int c = _parser.getc(); + if (c == 0x15) { + // debug_if(_ism_debug, "ISM43362: Flush char 0x%x\n", c); + 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()); +} + +int ISM43362::connect(const char *ap, const char *passPhrase, ism_security_t ap_sec) +{ + char tmp[256]; + + if (!(_parser.send("C1=%s", ap) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + if (!(_parser.send("C2=%s", passPhrase) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + /* Check security level is acceptable */ + if (ap_sec > ISM_SECURITY_WPA_WPA2) { + debug_if(_ism_debug, "ISM43362: Unsupported security level %d\n", ap_sec); + return NSAPI_ERROR_UNSUPPORTED; + } + + if (!(_parser.send("C3=%d", ap_sec) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + if (_parser.send("C0")) { + while (_parser.recv("%[^\n]\n", tmp)) { + if (strstr(tmp, "OK")) { + _parser.flush(); + _conn_status = NSAPI_STATUS_GLOBAL_UP; + _conn_stat_cb(); + return NSAPI_ERROR_OK; + } + if (strstr(tmp, "JOIN")) { + _conn_status = NSAPI_STATUS_CONNECTING; + _conn_stat_cb(); + if (strstr(tmp, "Failed")) { + _parser.flush(); + return NSAPI_ERROR_AUTH_FAILURE; + } + } + } + } + + return NSAPI_ERROR_NO_CONNECTION; +} + +bool ISM43362::disconnect(void) +{ + _conn_status = NSAPI_STATUS_DISCONNECTED; + _conn_stat_cb(); + return (_parser.send("CD") && check_response()); +} + +const char *ISM43362::getIPAddress(void) +{ + char tmp_ip_buffer[250]; + char *ptr, *ptr2; + + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if (!(_parser.send("C?") + && _parser.recv("%[^\n^\r]\r\n", tmp_ip_buffer) + && check_response())) { + debug_if(_ism_debug, "ISM43362: getIPAddress LINE KO: %s\n", 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, "ISM43362: 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, "ISM43362: receivedMacAddress LINE KO: %s\n", _mac_buffer); + return 0; + } + + debug_if(_ism_debug, "ISM43362: receivedMacAddress:%s, size=%d\r\n", _mac_buffer, sizeof(_mac_buffer)); + + return _mac_buffer; +} + +const char *ISM43362::getGateway() +{ + char tmp[250]; + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if (!(_parser.send("C?") && _parser.recv("%[^\n^\r]\r\n", tmp) && check_response())) { + debug_if(_ism_debug, "ISM43362: 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, "ISM43362: getGateway: %s\r\n", _gateway_buffer); + + return _gateway_buffer; +} + +const char *ISM43362::getNetmask() +{ + char tmp[250]; + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if (!(_parser.send("C?") && _parser.recv("%[^\n^\r]\r\n", tmp) && check_response())) { + debug_if(_ism_debug, "ISM43362: getNetmask LINE KO: %s\n", 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, "ISM43362: 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, "ISM43362: getRSSI LINE KO: %s\r\n", tmp); + return 0; + } + + rssi = ParseNumber(tmp, NULL); + + debug_if(_ism_debug, "ISM43362: 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, "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 if (strstr(ptr, "WPA2")) { + return NSAPI_SECURITY_WPA2; // catch any other WPA2 formula + } else if (strstr(ptr, "WPA")) { + return NSAPI_SECURITY_WPA; + } 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, "ISM43362: scan error\r\n"); + return 0; + } + + /* Parse the received buffer and fill AP buffer */ + /* Use %[^\n] instead of %s to allow having spaces in the string */ + while (_parser.recv("#%[^\n]\n", tmp)) { + if (limit != 0 && cnt >= limit) { + /* reached end */ + break; + } + nsapi_wifi_ap_t ap = {0}; + debug_if(_ism_debug, "ISM43362: received:%s\n", 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, ","); + } + if (res != 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, "ISM43362: 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, "ISM43362: open: wrong id\n"); + return false; + } + /* Set communication socket */ + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P0 issue\n"); + return false; + } + /* Set protocol */ + if (!(_parser.send("P1=%s", type) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P1 issue\n"); + return false; + } + /* Set address */ + if (!(_parser.send("P3=%s", addr) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P3 issue\n"); + return false; + } + if (!(_parser.send("P4=%d", port) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P4 issue\n"); + return false; + } + /* Start client */ + if (!(_parser.send("P6=1") && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P6 issue\n"); + 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())) { + debug_if(_ism_debug, "ISM43362: open: R1 issue\n"); + return -1; + } + + /* Non blocking mode : set Read Transport Timeout to 1ms */ + if (!(_parser.send("R2=1") && check_response())) { + debug_if(_ism_debug, "ISM43362: open: R2 issue\n"); + return -1; + } + + debug_if(_ism_debug, "ISM43362: open ok with id %d type %s addr %s port %d\n", id, type, addr, port); + + 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, "ISM43362 dns_lookup: D0 issue: %s\n", tmp); + return 0; + } + + strncpy(ip, tmp, sizeof(tmp)); + + debug_if(_ism_debug, "ISM43362 dns_lookup: %s ok\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_TX_PACKET_SIZE) { + debug_if(_ism_debug, "ISM43362 send: max issue\n"); + return false; + } + + /* Activate the socket id in the wifi module */ + if ((id < 0) || (id > 3)) { + return false; + } + if (_active_id != id) { + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + debug_if(_ism_debug, "ISM43362 send: P0 issue\n"); + return false; + } + } + + /* set Write Transport Packet Size */ + int i = _parser.printf("S3=%d\r", (int)amount); + if (i < 0) { + debug_if(_ism_debug, "ISM43362 send: S3 issue\n"); + return false; + } + i = _parser.write((const char *)data, amount, i); + if (i < 0) { + return false; + } + + if (!check_response()) { + return false; + } + + debug_if(_ism_debug, "ISM43362 send: id %d amount %d\n", id, amount); + return true; +} + +int ISM43362::check_recv_status(int id, void *data) +{ + int read_amount; + + debug_if(_ism_debug, "ISM43362 check_recv_status: id %d\r\n", id); + + /* Activate the socket id in the wifi module */ + if ((id < 0) || (id > 3)) { + debug_if(_ism_debug, "ISM43362 check_recv_status: ERROR with id %d\r\n", id); + return -1; + } + + if (_active_id != id) { + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + return -1; + } + } + + + if (!_parser.send("R0")) { + return -1; + } + read_amount = _parser.read((char *)data); + + if (read_amount < 0) { + debug_if(_ism_debug, "ISM43362 check_recv_status: 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, "ISM43362 check_recv_status: 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, "ISM43362 check_recv_status: recv 2 nothing to read=%d\r\n", read_amount); + // read_amount -= 6; + 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, "ISM43362 check_recv_status: ERROR, flushing %d bytes: ", read_amount); + // for (int i = 0; i < read_amount; i++) { + // debug_if(_ism_debug, "%2X ", cleanup[i]); + // } + // debug_if(_ism_debug, "\r\n (ASCII)", cleanup); + cleanup[read_amount] = 0; + debug_if(_ism_debug, "%s\r\n", cleanup); + return -1; /* nothing to read */ + } + + debug_if(_ism_debug, "ISM43362 check_recv_status: id %d read_amount=%d\r\n", id, read_amount); + return read_amount; +} + +bool ISM43362::close(int id) +{ + if ((id < 0) || (id > 3)) { + debug_if(_ism_debug, "ISM43362: Wrong socket number\n"); + return false; + } + /* Set connection on this socket */ + debug_if(_ism_debug, "ISM43362: 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; +} + +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()> status_cb) +{ + _conn_stat_cb = status_cb; +} + +nsapi_connection_status_t ISM43362::connection_status() const +{ + debug_if(_ism_debug, "ISM43362: connection_status %d\n", _conn_status); + return _conn_status; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362/ISM43362.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,261 @@ +/* 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 +typedef enum ism_security { + ISM_SECURITY_NONE = 0x0, /*!< open access point */ + ISM_SECURITY_WEP = 0x1, /*!< phrase conforms to WEP */ + ISM_SECURITY_WPA = 0x2, /*!< phrase conforms to WPA */ + ISM_SECURITY_WPA2 = 0x3, /*!< phrase conforms to WPA2 */ + ISM_SECURITY_WPA_WPA2 = 0x4, /*!< phrase conforms to WPA/WPA2 */ + ISM_SECURITY_UNKNOWN = 0xFF, /*!< unknown/unsupported security in scan results */ +} ism_security_t; + +extern "C" int32_t ParseNumber(char *ptr, uint8_t *cnt); + +/** 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 fw version or null if no version is read + */ + uint32_t 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 + * @param ap_sec the security level of network AP + * @return nsapi_error enum + */ + int connect(const char *ap, const char *passPhrase, ism_security_t ap_sec); + + /** + * 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); + + /** + * 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)); + } + + /** Get the connection status + * + * @return The connection status according to ConnectionStatusType + */ + nsapi_connection_status_t connection_status() const; + + +private: + BufferedSpi _bufferspi; + ATParser _parser; + DigitalOut _resetpin; + 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(); + bool _ism_debug; + + char _ip_buffer[16]; + char _gateway_buffer[16]; + char _netmask_buffer[16]; + char _mac_buffer[18]; + uint32_t _FwVersionId; + + // Connection state reporting + nsapi_connection_status_t _conn_status; + mbed::Callback<void()> _conn_stat_cb; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362Interface.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,597 @@ +/* ISM43362 implementation of NetworkInterfaceAPI + * Copyright (c) STMicroelectronics 2018 + * + * 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" + + // Product ID,FW Revision,API Revision,Stack Revision,RTOS Revision,CPU Clock,Product Name +#define LATEST_FW_VERSION_NUMBER "C3.5.2.5" // ISM43362-M3G-L44-SPI,C3.5.2.5.STM,v3.5.2,v1.4.0.rc1,v8.2.1,120000000,Inventek eS-WiFi + +// activate / de-activate debug +#define ism_interface_debug 0 + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +// ISM43362Interface implementation +ISM43362Interface::ISM43362Interface(bool debug) + : _ism(MBED_CONF_ISM43362_WIFI_MOSI, MBED_CONF_ISM43362_WIFI_MISO, MBED_CONF_ISM43362_WIFI_SCLK, MBED_CONF_ISM43362_WIFI_NSS, MBED_CONF_ISM43362_WIFI_RESET, MBED_CONF_ISM43362_WIFI_DATAREADY, MBED_CONF_ISM43362_WIFI_WAKEUP, debug), + _conn_stat(NSAPI_STATUS_DISCONNECTED), + _conn_stat_cb(NULL) +{ + _ism_debug = ism_interface_debug || debug; + memset(_ids, 0, sizeof(_ids)); + memset(_socket_obj, 0, sizeof(_socket_obj)); + _ism.attach(this, &ISM43362Interface::update_conn_state_cb); + memset(_cbs, 0, sizeof(_cbs)); + memset(ap_ssid, 0, sizeof(ap_ssid)); + memset(ap_pass, 0, sizeof(ap_pass)); + ap_sec = ISM_SECURITY_UNKNOWN; + + thread_read_socket.start(callback(this, &ISM43362Interface::socket_check_read)); + + _mutex.lock(); + + // Check all supported firmware versions + _FwVersion = _ism.get_firmware_version(); + + if (!_FwVersion) { + error("ISM43362Interface: ERROR cannot read firmware version\r\n"); + } + + debug_if(_ism_debug, "ISM43362Interface: read_version = %lu\r\n", _FwVersion); + /* FW Revision should be with format "CX.X.X.X" with X as a single digit */ + if ( (_FwVersion < 1000) || (_FwVersion > 9999) ) { + debug_if(_ism_debug, "ISM43362Interface: read_version issue\r\n"); + } + +#if TARGET_DISCO_L475VG_IOT01A + if (_FwVersion < ParseNumber(LATEST_FW_VERSION_NUMBER, NULL)) { + debug_if(_ism_debug, "ISM43362Interface: please update FW\r\n"); + } +#endif + + _connect_status = NSAPI_ERROR_NO_CONNECTION; + _mutex.unlock(); +} + +nsapi_error_t ISM43362Interface::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + nsapi_error_t credentials_status = set_credentials(ssid, pass, security); + if (credentials_status) { + return credentials_status; + } + + return connect(); +} + +nsapi_error_t ISM43362Interface::connect() +{ + if (strlen(ap_ssid) == 0) { + return NSAPI_ERROR_NO_SSID; + } + + _mutex.lock(); + + if (!_ism.dhcp(true)) { + _mutex.unlock(); + return NSAPI_ERROR_DHCP_FAILURE; + } + + _connect_status = _ism.connect(ap_ssid, ap_pass, ap_sec); + debug_if(_ism_debug, "ISM43362Interface: connect_status %d\n", _connect_status); + + if (_connect_status != NSAPI_ERROR_OK) { + _mutex.unlock(); + return _connect_status; + } + + if (!_ism.getIPAddress()) { + _connect_status = NSAPI_ERROR_DHCP_FAILURE; + _mutex.unlock(); + return NSAPI_ERROR_DHCP_FAILURE; + } + + _mutex.unlock(); + + return NSAPI_ERROR_OK; +} + +nsapi_error_t ISM43362Interface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version) +{ + if (strlen(name) == 0) { + return NSAPI_ERROR_NO_SOCKET; + } + + _mutex.lock(); + if (address->set_ip_address(name)) { + if (version != NSAPI_UNSPEC && address->get_ip_version() != version) { + _mutex.unlock(); + return NSAPI_ERROR_DNS_FAILURE; + } + + _mutex.unlock(); + return NSAPI_ERROR_OK; + } + + char *ipbuff = new char[NSAPI_IP_SIZE]; + int ret = 0; + if (!_ism.dns_lookup(name, ipbuff)) { + ret = NSAPI_ERROR_DNS_FAILURE; + } 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) +{ + if ((ssid == NULL) || (strlen(ssid) == 0) || (strlen(ssid) > 32)) { + return NSAPI_ERROR_PARAMETER; + } + + if (security != NSAPI_SECURITY_NONE) { + if ((pass == NULL) || (strcmp(pass, "") == 0)) { + return NSAPI_ERROR_PARAMETER; + } + } + + if (strlen(pass) > 63) { + return NSAPI_ERROR_PARAMETER; + } + + _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)); + + switch (security) { + case NSAPI_SECURITY_NONE: + ap_sec = ISM_SECURITY_NONE; + break; + case NSAPI_SECURITY_WEP: + ap_sec = ISM_SECURITY_WEP; + break; + case NSAPI_SECURITY_WPA: + ap_sec = ISM_SECURITY_WPA; + break; + case NSAPI_SECURITY_WPA2: + ap_sec = ISM_SECURITY_WPA2; + break; + case NSAPI_SECURITY_WPA_WPA2: + ap_sec = ISM_SECURITY_WPA_WPA2; + break; + default: + ap_sec = ISM_SECURITY_UNKNOWN; + break; + } + _mutex.unlock(); + + return NSAPI_ERROR_OK; +} + +int ISM43362Interface::set_channel(uint8_t channel) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t ISM43362Interface::disconnect() +{ + _mutex.lock(); + + if (_connect_status != NSAPI_ERROR_OK) { + _mutex.unlock(); + return NSAPI_ERROR_NO_CONNECTION; + } + + if (!_ism.disconnect()) { + _mutex.unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + + _connect_status = NSAPI_ERROR_NO_CONNECTION; + _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(); + 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) { + _mutex.unlock(); + return NSAPI_ERROR_NO_SOCKET; + } + socket->id = id; + debug_if(_ism_debug, "ISM43362Interface: socket_open, id=%d\n", 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, "ISM43362Interface: socket_close, id=%d\n", socket->id); + int err = 0; + + 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; + 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) { + /* if no callback is set, no need to read ?*/ + int read_amount = _ism.check_recv_status(socket->id, socket->read_data); + // debug_if(_ism_debug, "ISM43362Interface socket_check_read: i %d read_amount %d \r\n", i, read_amount); + if (read_amount > 0) { + socket->read_data_size = read_amount; + } else if (read_amount < 0) { + /* Mark donw connection has been lost or closed */ + debug_if(_ism_debug, "ISM43362Interface socket_check_read: i %d closed\r\n", i); + 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; + + 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, "ISM43362Interface: 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, "ISM43362Interface socket_recv: req=%d read_data_size=%d connected %d\r\n", size, socket->read_data_size, socket->connected); + + if (!socket->connected) { + _mutex.unlock(); + return 0; + } + + 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; + debug_if(_ism_debug, "ISM43362Interface socket_recv: socket closed\r\n"); + _mutex.unlock(); + return 0; + } + } + + if (socket->read_data_size != 0) { + // debug_if(_ism_debug, "ISM43362Interface socket_recv: 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++; + } + + 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, "ISM43362Interface: 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, "ISM43362Interface socket_recv: Nothing in buffer\r\n"); + // } + + _mutex.unlock(); + + if (recv > 0) { + debug_if(_ism_debug, "ISM43362Interface socket_recv: recv=%d\r\n", recv); + return recv; + } else { + debug_if(_ism_debug, "ISM43362Interface socket_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) { + if (!_ism.close(socket->id)) { + debug_if(_ism_debug, "ISM43362Interface: socket_sendto 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); + } + } +} + +void ISM43362Interface::attach(Callback<void(nsapi_event_t, intptr_t)> status_cb) +{ + debug_if(_ism_debug, "ISM43362Interface: attach\n"); + _conn_stat_cb = status_cb; +} + +nsapi_connection_status_t ISM43362Interface::get_connection_status() const +{ + debug_if(_ism_debug, "ISM43362Interface: get_connection_status %d\n", _conn_stat); + return _conn_stat; +} + + +void ISM43362Interface::update_conn_state_cb() +{ + nsapi_connection_status_t prev_stat = _conn_stat; + _conn_stat = _ism.connection_status(); + debug_if(_ism_debug, "ISM43362Interface: update_conn_state_cb %d -> %d\n", prev_stat, _conn_stat); + + if (prev_stat == _conn_stat) { + return; + } + + // Inform upper layers + if (_conn_stat_cb) { + _conn_stat_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _conn_stat); + } +} + + +#if MBED_CONF_ISM43362_PROVIDE_DEFAULT + +WiFiInterface *WiFiInterface::get_default_instance() { + static ISM43362Interface ism; + return &ism; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ISM43362/ISM43362Interface.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,321 @@ +/* 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 debug Enable debugging + */ + ISM43362Interface(bool debug = MBED_CONF_ISM43362_WIFI_DEBUG); + + /** 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 nsapi_error_t 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 nsapi_error_t 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 nsapi_error_t 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 + * @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; + + /** Register callback for status reporting + * + * The specified status callback function will be called on status changes + * on the network. The parameters on the callback are the event type and + * event-type dependent reason parameter. + * + * @param status_cb The callback for status changes + */ + virtual void attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb); + + /** Get the connection status + * + * @return The connection status according to ConnectionStatusType + */ + virtual nsapi_connection_status_t get_connection_status() const; + +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 */ + ism_security_t ap_sec; + uint8_t ap_ch; + char ap_pass[64]; /* The longest allowed passphrase */ + nsapi_error_t _connect_status ; + + bool _ism_debug; + uint32_t _FwVersion; + + 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); + + // Connection state reporting to application + void update_conn_state_cb(); + nsapi_connection_status_t _conn_stat; + mbed::Callback<void(nsapi_event_t, intptr_t)> _conn_stat_cb; + + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ISM43362/README.md Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,50 @@ +# ISM43362 WiFi driver for mbed-os + +The mbed OS driver for the ISM43362 WiFi module + +https://www.inventeksys.com/products-page/wifi-modules/ism4336-m3g-l44-e-embedded-serial-to-wifi-module/ + + +## Currently supported platforms + +ISM43362 module is soldered on the following platforms from STMicroelectronics + + * [DISCO_L475VG_IOT01A](https://os.mbed.com/platforms/ST-Discovery-L475E-IOT01A/) + * [DISCO_F413ZH](https://os.mbed.com/platforms/ST-Discovery-F413H/) + +## Configuration + +Correct pins have already been configured for both supported platforms. + +Here is configured pins: + +- MBED_CONF_ISM43362_WIFI_MISO : spi-miso pin for the ism43362 connection +- MBED_CONF_ISM43362_WIFI_MOSI : spi-mosi pin for the ism43362 connection +- MBED_CONF_ISM43362_WIFI_SPI_SCLK : spi-clock pin for the ism43362 connection +- MBED_CONF_ISM43362_WIFI_SPI_NSS : spi-nss pin for the ism43362 connection +- MBED_CONF_ISM43362_WIFI_RESET : Reset pin for the ism43362 wifi module +- MBED_CONF_ISM43362_WIFI_DATAREADY : Data Ready pin for the ism43362 wifi module +- MBED_CONF_ISM43362_WIFI_WAKEUP : Wakeup pin for the ism43362 wifi module + +## Debug + +Some debug print on console can help to debug if necessary. + +- in ISM43362Interface.cpp file, set ism_interface_debug to 1 +- in ISM43362/ISM43362.cpp file, set ism_debug to 1 +- in ISM43362/ATParser/ATParser.cpp file, there are 3 different level : dbg_on / AT_DATA_PRINT / AT_COMMAND_PRINT + +Another way to enable these prints is overwrite MBED_CONF_ISM43362_WIFI_DEBUG in your json file: + "ism43362.wifi-debug": true + + +## Firmware version + +This driver has been tested with C3.5.2.2 and C3.5.2.3.BETA9 firmware version + +## wifi module FW update + +Only Wifi module from DISCO_L475VG_IOT01A can be updated (HW limitation for DISCO_F413ZH). + +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/network/COMPONENT_WIFI_ISM43362/mbed_lib.json Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,63 @@ +{ + "name": "ism43362", + "config": { + "wifi-miso": { + "help": "SPI-MISO connection to external device", + "value": "NC" + }, + "wifi-mosi": { + "help": "SPI-MOSI connection to external device", + "value": "NC" + }, + "wifi-sclk": { + "help": "SPI-CLOCK connection to external device", + "value": "NC" + }, + "wifi-nss": { + "help": "SPI chip select of external device", + "value": "NC" + }, + "wifi-reset": { + "help": "ISM43362 reset", + "value": "NC" + }, + "wifi-dataready": { + "help": "ISM43362 dataready", + "value": "NC" + }, + "wifi-wakeup": { + "help": "ISM43362 wakeup", + "value": "NC" + }, + "wifi-debug": { + "help": "Defines whether logging is on or off", + "value": false + }, + "provide-default": { + "help": "Provide default WifiInterface. [true/false]", + "value": false + } + }, + "target_overrides": { + "DISCO_F413ZH": { + "ism43362.wifi-miso": "PB_4", + "ism43362.wifi-mosi": "PB_5", + "ism43362.wifi-sclk": "PB_12", + "ism43362.wifi-nss": "PG_11", + "ism43362.wifi-reset": "PH_1", + "ism43362.wifi-dataready": "PG_12", + "ism43362.wifi-wakeup": "PB_15", + "ism43362.provide-default": true + }, + "DISCO_L475VG_IOT01A": { + "ism43362.wifi-miso": "PC_11", + "ism43362.wifi-mosi": "PC_12", + "ism43362.wifi-sclk": "PC_10", + "ism43362.wifi-nss": "PE_0", + "ism43362.wifi-reset": "PE_8", + "ism43362.wifi-dataready": "PE_1", + "ism43362.wifi-wakeup": "PB_13", + "ism43362.provide-default": true + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/storage/COMPONENT_NUSD.lib Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,1 @@ +https://github.com/OpenNuvoton/NuMaker-mbed-SD-driver/#620965ef5b323ed1c80c3ada9241daf49e487a41
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/storage/COMPONENT_NUSD/NuSDBlockDevice.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,671 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015-2016 Nuvoton + * + * 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. + */ + +/* Nuvoton mbed enabled targets which support SD card of SD bus mode */ +#if TARGET_NUVOTON + +#include "NuSDBlockDevice.h" +#include "PeripheralPins.h" +#include "mbed_debug.h" +#include "nu_modutil.h" +#include "mbed_critical.h" +#include "mbed_toolchain.h" + +/* SD DMA compatible buffer if user buffer doesn't meet requirements + * + * SD DMA buffer location requires to be: + * (1) Word-aligned + * (2) Located in 0x2xxxxxxx/0x3xxxxxxx region. Check linker files to ensure global/static + * variables are placed in this region. + * + * SD DMA buffer size DMA_BUF_SIZE must be a multiple of 512-byte block size. + * Its value is estimated to trade memory footprint off against performance. + * + */ +#define DMA_BUFF_SIZE 512 +MBED_ALIGN(4) static uint8_t dma_buff[DMA_BUFF_SIZE]; + +/* Check if specified buffer is SD DMA-compatible */ +static bool sd_dma_buff_compat(const void *buff, size_t buff_size, size_t size_aligned_to); + +#if TARGET_NUMAKER_PFM_NUC472 +#define NU_SDH_DAT0 PF_5 +#define NU_SDH_DAT1 PF_4 +#define NU_SDH_DAT2 PF_3 +#define NU_SDH_DAT3 PF_2 +#define NU_SDH_CMD PF_7 +#define NU_SDH_CLK PF_8 +#define NU_SDH_CDn PF_6 + +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 +#define NU_SDH_DAT0 PE_2 +#define NU_SDH_DAT1 PE_3 +#define NU_SDH_DAT2 PB_4 +#define NU_SDH_DAT3 PB_5 +#define NU_SDH_CMD PE_7 +#define NU_SDH_CLK PE_6 +#define NU_SDH_CDn PD_13 + +#elif TARGET_NUMAKER_PFM_M2351 +#define NU_SDH_DAT0 PE_2 +#define NU_SDH_DAT1 PE_3 +#define NU_SDH_DAT2 PE_4 +#define NU_SDH_DAT3 PE_5 +#define NU_SDH_CMD PE_7 +#define NU_SDH_CLK PE_6 +#define NU_SDH_CDn PD_13 + +#endif + +#if TARGET_NUMAKER_PFM_NUC472 +extern DISK_DATA_T SD_DiskInfo0; +extern DISK_DATA_T SD_DiskInfo1; +extern SD_INFO_T SD0,SD1; +extern int sd0_ok,sd1_ok; + +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 +extern int SDH_ok; +extern SDH_INFO_T SD0, SD1; + +#elif TARGET_NUMAKER_PFM_M2351 +extern int SDH_ok; +extern SDH_INFO_T SD0; + +#endif + + +static const struct nu_modinit_s sdh_modinit_tab[] = { +#if TARGET_NUMAKER_PFM_NUC472 + {SD_0_0, SDH_MODULE, CLK_CLKSEL0_SDHSEL_PLL, CLK_CLKDIV0_SDH(2), SDH_RST, SD_IRQn, NULL}, + {SD_0_1, SDH_MODULE, CLK_CLKSEL0_SDHSEL_PLL, CLK_CLKDIV0_SDH(2), SDH_RST, SD_IRQn, NULL}, +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 + {SD_0, SDH0_MODULE, CLK_CLKSEL0_SDH0SEL_HCLK, CLK_CLKDIV0_SDH0(2), SDH0_RST, SDH0_IRQn, NULL}, + {SD_1, SDH1_MODULE, CLK_CLKSEL0_SDH1SEL_HCLK, CLK_CLKDIV3_SDH1(2), SDH1_RST, SDH1_IRQn, NULL}, +#elif TARGET_NUMAKER_PFM_M2351 + {SD_0, SDH0_MODULE, CLK_CLKSEL0_SDH0SEL_HCLK, CLK_CLKDIV0_SDH0(2), SDH0_RST, SDH0_IRQn, NULL}, +#endif + + {NC, 0, 0, 0, 0, (IRQn_Type) 0, NULL} +}; + + + +#define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK -5001 /*!< operation would block */ +#define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED -5002 /*!< unsupported operation */ +#define SD_BLOCK_DEVICE_ERROR_PARAMETER -5003 /*!< invalid parameter */ +#define SD_BLOCK_DEVICE_ERROR_NO_INIT -5004 /*!< uninitialized */ +#define SD_BLOCK_DEVICE_ERROR_NO_DEVICE -5005 /*!< device is missing or not connected */ +#define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED -5006 /*!< write protected */ + + +NuSDBlockDevice::NuSDBlockDevice() : + _sectors(0), + _dbg(false), + _sdh_modinit(NULL), + _sdh((SDName) NC), + _sdh_base(NULL), +#if TARGET_NUMAKER_PFM_NUC472 + _sdh_port((uint32_t) -1), +#endif + _sdh_irq_thunk(this, &NuSDBlockDevice::_sdh_irq), + _sd_dat0(NU_SDH_DAT0), + _sd_dat1(NU_SDH_DAT1), + _sd_dat2(NU_SDH_DAT2), + _sd_dat3(NU_SDH_DAT3), + _sd_cmd(NU_SDH_CMD), + _sd_clk(NU_SDH_CLK), + _sd_cdn(NU_SDH_CDn), + _is_initialized(false), + _init_ref_count(0) +{ +} + +NuSDBlockDevice::NuSDBlockDevice(PinName sd_dat0, PinName sd_dat1, PinName sd_dat2, PinName sd_dat3, + PinName sd_cmd, PinName sd_clk, PinName sd_cdn) : + _sectors(0), + _dbg(false), + _sdh_modinit(NULL), + _sdh((SDName) NC), + _sdh_base(NULL), +#if TARGET_NUMAKER_PFM_NUC472 + _sdh_port((uint32_t) -1), +#endif + _sdh_irq_thunk(this, &NuSDBlockDevice::_sdh_irq), + _is_initialized(false), + _init_ref_count(0) +{ + _sd_dat0 = sd_dat0; + _sd_dat1 = sd_dat1; + _sd_dat2 = sd_dat2; + _sd_dat3 = sd_dat3; + _sd_cmd = sd_cmd; + _sd_clk = sd_clk; + _sd_cdn = sd_cdn; +} + +NuSDBlockDevice::~NuSDBlockDevice() +{ + if (_is_initialized) { + deinit(); + } +} + +int NuSDBlockDevice::init() +{ + _lock.lock(); + int err = BD_ERROR_OK; + + do { + if (_is_initialized) { + _init_ref_count ++; + break; + } else { + _init_ref_count = 0; + } + + err = _init_sdh(); + if (err != BD_ERROR_OK) { + break; + } + +#if TARGET_NUMAKER_PFM_NUC472 + SD_Open(_sdh_port | CardDetect_From_GPIO); + SD_Probe(_sdh_port); + + switch (_sdh_port) { + case SD_PORT0: + _is_initialized = sd0_ok && (SD0.CardType != SD_TYPE_UNKNOWN); + break; + + case SD_PORT1: + _is_initialized = sd1_ok && (SD1.CardType != SD_TYPE_UNKNOWN); + break; + } + +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 + MBED_ASSERT(_sdh_modinit != NULL); + + NVIC_SetVector(_sdh_modinit->irq_n, _sdh_irq_thunk.entry()); + NVIC_EnableIRQ(_sdh_modinit->irq_n); + + SDH_Open(_sdh_base, CardDetect_From_GPIO); + SDH_Probe(_sdh_base); + + switch (NU_MODINDEX(_sdh)) { + case 0: + _is_initialized = SDH_ok && (SD0.CardType != SDH_TYPE_UNKNOWN); + break; + + case 1: + _is_initialized = SDH_ok && (SD1.CardType != SDH_TYPE_UNKNOWN); + break; + } + +#elif TARGET_NUMAKER_PFM_M2351 + MBED_ASSERT(_sdh_modinit != NULL); + + NVIC_SetVector(_sdh_modinit->irq_n, _sdh_irq_thunk.entry()); + NVIC_EnableIRQ(_sdh_modinit->irq_n); + + SDH_Open(_sdh_base, CardDetect_From_GPIO); + SDH_Probe(_sdh_base); + + switch (NU_MODINDEX(_sdh)) { + case 0: + _is_initialized = SDH_ok && (SD0.CardType != SDH_TYPE_UNKNOWN); + break; + } +#endif + + if (_is_initialized) { + _init_ref_count = 1; + } else { + debug_if(_dbg, "Fail to initialize card\n"); + err = BD_ERROR_DEVICE_ERROR; + } + debug_if(_dbg, "init card = %d\n", _is_initialized); + _sectors = _sd_sectors(); + + } while (0); + + _lock.unlock(); + + return err; +} + +int NuSDBlockDevice::deinit() +{ + _lock.lock(); + int err = BD_ERROR_OK; + + do { + if (_is_initialized && _init_ref_count > 1) { + _init_ref_count --; + break; + } else if (! _is_initialized) { + _init_ref_count = 0; + break; + } + + if (_sdh_modinit) { +#if defined(DOMAIN_NS) && DOMAIN_NS + CLK_DisableModuleClock_S(_sdh_modinit->clkidx); +#else + CLK_DisableModuleClock(_sdh_modinit->clkidx); +#endif + } + +#if TARGET_NUMAKER_PFM_NUC472 + // TODO +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 + // TODO +#elif TARGET_NUMAKER_PFM_M2351 + // TODO +#endif + + _is_initialized = false; + _init_ref_count = 0; + } while (0); + + _lock.unlock(); + + return err; +} + +int NuSDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) +{ + if (! is_valid_program(addr, size)) { + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + _lock.lock(); + int err = BD_ERROR_OK; + + do { + if (! _is_initialized) { + err = SD_BLOCK_DEVICE_ERROR_NO_INIT; + break; + } + + /* Check if user buffer is SD DMA-compatible */ + if (sd_dma_buff_compat(b, static_cast<size_t>(size), 512)) { + /* User buffer is DMA-compatible. We can transfer directly. */ +#if TARGET_NUMAKER_PFM_NUC472 + if (SD_Write(_sdh_port, (uint8_t*)b, addr / 512, size / 512) != 0) { +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 || TARGET_NUMAKER_PFM_M2351 + if (SDH_Write(_sdh_base, (uint8_t*)b, addr / 512, size / 512) != 0) { +#endif + err = BD_ERROR_DEVICE_ERROR; + } + } else { + /* User buffer is not SD DMA-compatible. We must transfer via DMA intermediate buffer. */ + const uint8_t *b_pos = static_cast<const uint8_t *>(b); + bd_addr_t addr_pos = addr; + bd_size_t rmn = size; + + while (rmn) { + size_t todo_size = (rmn >= DMA_BUFF_SIZE) ? DMA_BUFF_SIZE : static_cast<size_t>(rmn); + memcpy(dma_buff, b_pos, todo_size); + +#if TARGET_NUMAKER_PFM_NUC472 + if (SD_Write(_sdh_port, const_cast<uint8_t*>(dma_buff), static_cast<uint32_t>(addr_pos / 512), static_cast<uint32_t>(todo_size / 512)) != 0) { +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 || TARGET_NUMAKER_PFM_M2351 + if (SDH_Write(_sdh_base, const_cast<uint8_t*>(dma_buff), static_cast<uint32_t>(addr_pos / 512), static_cast<uint32_t>(todo_size / 512)) != 0) { +#endif + err = BD_ERROR_DEVICE_ERROR; + break; + } + + b_pos += todo_size; + addr_pos += todo_size; + rmn -= todo_size; + } + } + } while (0); + + _lock.unlock(); + + return err; +} + +int NuSDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) +{ + if (! is_valid_read(addr, size)) { + return SD_BLOCK_DEVICE_ERROR_PARAMETER; + } + + _lock.lock(); + int err = BD_ERROR_OK; + + do { + if (! _is_initialized) { + err = SD_BLOCK_DEVICE_ERROR_NO_INIT; + break; + } + + /* Check if user buffer is SD DMA-compatible */ + if (sd_dma_buff_compat(b, static_cast<size_t>(size), 512)) { + /* User buffer is SD DMA-compatible. We can transfer directly. */ +#if TARGET_NUMAKER_PFM_NUC472 + if (SD_Read(_sdh_port, (uint8_t*)b, addr / 512, size / 512) != 0) { +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 || TARGET_NUMAKER_PFM_M2351 + if (SDH_Read(_sdh_base, (uint8_t*)b, addr / 512, size / 512) != 0) { +#endif + err = BD_ERROR_DEVICE_ERROR; + } + } else { + /* User buffer is not SD DMA-compatible. We must transfer via DMA intermediate buffer. */ + uint8_t *b_pos = static_cast<uint8_t *>(b); + bd_addr_t addr_pos = addr; + bd_size_t rmn = size; + + while (rmn) { + size_t todo_size = (rmn >= DMA_BUFF_SIZE) ? DMA_BUFF_SIZE : static_cast<size_t>(rmn); + +#if TARGET_NUMAKER_PFM_NUC472 + if (SD_Read(_sdh_port, static_cast<uint8_t*>(dma_buff), static_cast<uint32_t>(addr_pos / 512), static_cast<uint32_t>(todo_size / 512)) != 0) { +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 || TARGET_NUMAKER_PFM_M2351 + if (SDH_Read(_sdh_base, static_cast<uint8_t*>(dma_buff), static_cast<uint32_t>(addr_pos / 512), static_cast<uint32_t>(todo_size / 512)) != 0) { +#endif + err = BD_ERROR_DEVICE_ERROR; + break; + } + + memcpy(b_pos, dma_buff, todo_size); + + b_pos += todo_size; + addr_pos += todo_size; + rmn -= todo_size; + } + } + } while (0); + + _lock.unlock(); + + return err; +} + +int NuSDBlockDevice::erase(bd_addr_t addr, bd_size_t size) +{ + if (! _is_initialized) { + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + + return BD_ERROR_OK; +} + +bd_size_t NuSDBlockDevice::get_read_size() const +{ + return 512; +} + +bd_size_t NuSDBlockDevice::get_program_size() const +{ + return 512; +} + +bd_size_t NuSDBlockDevice::get_erase_size() const +{ + return 512; +} + +bd_size_t NuSDBlockDevice::get_erase_size(bd_addr_t addr) const +{ + return 512; +} + +bd_size_t NuSDBlockDevice::size() const +{ + if (! _is_initialized) { + return SD_BLOCK_DEVICE_ERROR_NO_INIT; + } + + return 512 * _sectors; +} + +void NuSDBlockDevice::debug(bool dbg) +{ + _dbg = dbg; +} + +int NuSDBlockDevice::_init_sdh() +{ + debug_if(_dbg, "SD MPF Setting & Enable SD IP Clock\n"); + + // Check if all pins belong to the same SD module + // Merge SD DAT0/1/2/3 + uint32_t sd_dat0_mod = pinmap_peripheral(_sd_dat0, PinMap_SD_DAT0); + uint32_t sd_dat1_mod = pinmap_peripheral(_sd_dat1, PinMap_SD_DAT1); + uint32_t sd_dat2_mod = pinmap_peripheral(_sd_dat2, PinMap_SD_DAT2); + uint32_t sd_dat3_mod = pinmap_peripheral(_sd_dat3, PinMap_SD_DAT3); + uint32_t sd_dat01_mod = (SDName) pinmap_merge(sd_dat0_mod, sd_dat1_mod); + uint32_t sd_dat23_mod = (SDName) pinmap_merge(sd_dat2_mod, sd_dat3_mod); + uint32_t sd_dat0123_mod = (SDName) pinmap_merge(sd_dat01_mod, sd_dat23_mod); + // Merge SD CMD/CLK/CDn + uint32_t sd_cmd_mod = pinmap_peripheral(_sd_cmd, PinMap_SD_CMD); + uint32_t sd_clk_mod = pinmap_peripheral(_sd_clk, PinMap_SD_CLK); + uint32_t sd_cdn_mod = pinmap_peripheral(_sd_cdn, PinMap_SD_CD); + uint32_t sd_cmdclk_mod = (SDName) pinmap_merge(sd_cmd_mod, sd_clk_mod); + uint32_t sd_cmdclkcdn_mod = (SDName) pinmap_merge(sd_cmdclk_mod, sd_cdn_mod); + // Merge SD DAT0/1/2/3 and SD CMD/CLK/CDn + uint32_t sd_mod = (SDName) pinmap_merge(sd_dat0123_mod, sd_cmdclkcdn_mod); + + if (sd_mod == (uint32_t) NC) { + debug("SD pinmap error\n"); + return BD_ERROR_DEVICE_ERROR; + } + + _sdh_modinit = get_modinit(sd_mod, sdh_modinit_tab); + MBED_ASSERT(_sdh_modinit != NULL); + MBED_ASSERT(_sdh_modinit->modname == sd_mod); + + + // Configure SD multi-function pins + pinmap_pinout(_sd_dat0, PinMap_SD_DAT0); + pinmap_pinout(_sd_dat1, PinMap_SD_DAT1); + pinmap_pinout(_sd_dat2, PinMap_SD_DAT2); + pinmap_pinout(_sd_dat3, PinMap_SD_DAT3); + pinmap_pinout(_sd_cmd, PinMap_SD_CMD); + pinmap_pinout(_sd_clk, PinMap_SD_CLK); + pinmap_pinout(_sd_cdn, PinMap_SD_CD); + + // Configure SD IP clock +#if defined(DOMAIN_NS) && DOMAIN_NS + SYS_UnlockReg_S(); +#else + SYS_UnlockReg(); +#endif + + // Determine SDH port dependent on passed-in pins + _sdh = (SDName) sd_mod; + _sdh_base = (SDH_T *) NU_MODBASE(_sdh); +#if TARGET_NUMAKER_PFM_NUC472 + switch (NU_MODSUBINDEX(_sdh)) { + case 0: + _sdh_port = SD_PORT0; + break; + + case 1: + _sdh_port = SD_PORT1; + break; + } +#endif + +#if defined(DOMAIN_NS) && DOMAIN_NS + SYS_ResetModule_S(_sdh_modinit->rsetidx); +#else + SYS_ResetModule(_sdh_modinit->rsetidx); +#endif + +#if defined(DOMAIN_NS) && DOMAIN_NS + CLK_SetModuleClock_S(_sdh_modinit->clkidx, _sdh_modinit->clksrc, _sdh_modinit->clkdiv); +#else + CLK_SetModuleClock(_sdh_modinit->clkidx, _sdh_modinit->clksrc, _sdh_modinit->clkdiv); +#endif + +#if defined(DOMAIN_NS) && DOMAIN_NS + CLK_EnableModuleClock_S(_sdh_modinit->clkidx); +#else + CLK_EnableModuleClock(_sdh_modinit->clkidx); +#endif + +#if defined(DOMAIN_NS) && DOMAIN_NS + SYS_LockReg_S(); +#else + SYS_LockReg(); +#endif + + return BD_ERROR_OK; +} + +uint32_t NuSDBlockDevice::_sd_sectors() +{ + _lock.lock(); + +#if TARGET_NUMAKER_PFM_NUC472 + switch (_sdh_port) { + case SD_PORT0: + _sectors = SD_DiskInfo0.totalSectorN; + break; + case SD_PORT1: + _sectors = SD_DiskInfo1.totalSectorN; + break; + } + +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 + switch (NU_MODINDEX(_sdh)) { + case 0: + _sectors = SD0.totalSectorN; + break; + case 1: + _sectors = SD1.totalSectorN; + break; + } + +#elif TARGET_NUMAKER_PFM_M2351 + switch (NU_MODINDEX(_sdh)) { + case 0: + _sectors = SD0.totalSectorN; + break; + } + +#endif + + _lock.unlock(); + + return _sectors; +} + +void NuSDBlockDevice::_sdh_irq() +{ +#if TARGET_NUMAKER_PFM_NUC472 + // TODO: Support IRQ + +#elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 + // FMI data abort interrupt + if (_sdh_base->GINTSTS & SDH_GINTSTS_DTAIF_Msk) { + _sdh_base->GINTSTS = SDH_GINTSTS_DTAIF_Msk; + /* ResetAllEngine() */ + _sdh_base->GCTL |= SDH_GCTL_GCTLRST_Msk; + } + + //----- SD interrupt status + if (_sdh_base->INTSTS & SDH_INTSTS_BLKDIF_Msk) { + // block down + extern uint8_t volatile _SDH_SDDataReady; + _SDH_SDDataReady = TRUE; + _sdh_base->INTSTS = SDH_INTSTS_BLKDIF_Msk; + } + + // NOTE: On M487, there are two SDH instances which each support port 0 and don't support port 1. + // Port 0 (support): INTEN.CDIEN0, INTEN.CDSRC0, INTSTS.CDIF0, INTSTS.CDSTS0 + // Port 1 (no support): INTEN.CDIEN1, INTEN.CDSRC1, INTSTS.CDIF1, INTSTS.CDSTS1 + if (_sdh_base->INTSTS & SDH_INTSTS_CDIF_Msk) { // port 0 card detect + _sdh_base->INTSTS = SDH_INTSTS_CDIF_Msk; + // TBD: Support PnP + } + + // CRC error interrupt + if (_sdh_base->INTSTS & SDH_INTSTS_CRCIF_Msk) { + _sdh_base->INTSTS = SDH_INTSTS_CRCIF_Msk; // clear interrupt flag + } + + if (_sdh_base->INTSTS & SDH_INTSTS_DITOIF_Msk) { + _sdh_base->INTSTS = SDH_INTSTS_DITOIF_Msk; + } + + // Response in timeout interrupt + if (_sdh_base->INTSTS & SDH_INTSTS_RTOIF_Msk) { + _sdh_base->INTSTS |= SDH_INTSTS_RTOIF_Msk; + } + +#elif TARGET_NUMAKER_PFM_M2351 + // FMI data abort interrupt + if (_sdh_base->GINTSTS & SDH_GINTSTS_DTAIF_Msk) { + _sdh_base->GINTSTS = SDH_GINTSTS_DTAIF_Msk; + /* ResetAllEngine() */ + _sdh_base->GCTL |= SDH_GCTL_GCTLRST_Msk; + } + + //----- SD interrupt status + if (_sdh_base->INTSTS & SDH_INTSTS_BLKDIF_Msk) { + // block down + extern uint8_t volatile g_u8SDDataReadyFlag; + g_u8SDDataReadyFlag = TRUE; + _sdh_base->INTSTS = SDH_INTSTS_BLKDIF_Msk; + } + + if (_sdh_base->INTSTS & SDH_INTSTS_CDIF_Msk) { // port 0 card detect + _sdh_base->INTSTS = SDH_INTSTS_CDIF_Msk; + // TBD: Support PnP + } + + // CRC error interrupt + if (_sdh_base->INTSTS & SDH_INTSTS_CRCIF_Msk) { + _sdh_base->INTSTS = SDH_INTSTS_CRCIF_Msk; // clear interrupt flag + } + + if (_sdh_base->INTSTS & SDH_INTSTS_DITOIF_Msk) { + _sdh_base->INTSTS = SDH_INTSTS_DITOIF_Msk; + } + + // Response in timeout interrupt + if (_sdh_base->INTSTS & SDH_INTSTS_RTOIF_Msk) { + _sdh_base->INTSTS |= SDH_INTSTS_RTOIF_Msk; + } + +#endif +} + +static bool sd_dma_buff_compat(const void *buff, size_t buff_size, size_t size_aligned_to) +{ + uint32_t buff_ = (uint32_t) buff; + + return (((buff_ & 0x03) == 0) && // Word-aligned buffer base address + ((buff_size & (size_aligned_to - 1)) == 0) && // 'size_aligned_to'-aligned buffer size +#if TARGET_NUMAKER_PFM_M2351 && (defined(DOMAIN_NS) && DOMAIN_NS) + (((buff_ >> 28) == 0x3) && (buff_size <= (0x40000000 - buff_)))); // 0x30000000-0x3FFFFFFF +#else + (((buff_ >> 28) == 0x2) && (buff_size <= (0x30000000 - buff_)))); // 0x20000000-0x2FFFFFFF +#endif +} + +const char *NuSDBlockDevice::get_type() const +{ + return "NUSD"; +} + +#endif /* TARGET_NUVOTON */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/storage/COMPONENT_NUSD/NuSDBlockDevice.h Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,155 @@ +/* mbed Microcontroller Library + * Copyright (c) 2015-2016 Nuvoton + * + * 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 __NU_SD_BLOCK_DEVICE_H__ +#define __NU_SD_BLOCK_DEVICE_H__ + +#if TARGET_NUVOTON + +#include "BlockDevice.h" +#include "platform/PlatformMutex.h" +#include "mbed.h" + +struct nu_modinit_s; + +class NuSDBlockDevice : public BlockDevice { +public: + /** Lifetime of an SD card + */ + NuSDBlockDevice(); + NuSDBlockDevice(PinName sd_dat0, PinName sd_dat1, PinName sd_dat2, PinName sd_dat3, + PinName sd_cmd, PinName sd_clk, PinName sd_cdn); + virtual ~NuSDBlockDevice(); + + /** Initialize a block device + * + * @return 0 on success or a negative error code on failure + */ + virtual int init(); + + /** Deinitialize a block device + * + * @return 0 on success or a negative error code on failure + */ + virtual int deinit(); + + /** Read blocks from a block device + * + * @param buffer Buffer to write blocks to + * @param addr Address of block to begin reading from + * @param size Size to read in bytes, must be a multiple of read block size + * @return 0 on success, negative error code on failure + */ + virtual int read(void *buffer, bd_addr_t addr, bd_size_t size); + + /** Program blocks to a block device + * + * The blocks must have been erased prior to being programmed + * + * @param buffer Buffer of data to write to blocks + * @param addr Address of block to begin writing to + * @param size Size to write in bytes, must be a multiple of program block size + * @return 0 on success, negative error code on failure + */ + virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size); + + /** Erase blocks on a block device + * + * The state of an erased block is undefined until it has been programmed + * + * @param addr Address of block to begin erasing + * @param size Size to erase in bytes, must be a multiple of erase block size + * @return 0 on success, negative error code on failure + */ + virtual int erase(bd_addr_t addr, bd_size_t size); + + /** Get the size of a readable block + * + * @return Size of a readable block in bytes + */ + virtual bd_size_t get_read_size() const; + + /** Get the size of a programable block + * + * @return Size of a programable block in bytes + * @note Must be a multiple of the read size + */ + virtual bd_size_t get_program_size() const; + + /** Get the size of an erasable block + * + * @return Size of an erasable block in bytes + * @note Must be a multiple of the program size + */ + virtual bd_size_t get_erase_size() const; + + /** Get the size of an erasable block given address + * + * @param addr Address within the erasable block + * @return Size of an erasable block in bytes + * @note Must be a multiple of the program size + */ + virtual bd_size_t get_erase_size(bd_addr_t addr) const; + + /** Get the total size of the underlying device + * + * @return Size of the underlying device in bytes + */ + virtual bd_size_t size() const; + + /** Enable or disable debugging + * + * @param State of debugging + */ + virtual void debug(bool dbg); + + /** Get the BlockDevice class type. + * + * @return A string representation of the BlockDevice class type. + */ + virtual const char *get_type() const; + +private: + int _init_sdh(); + uint32_t _sd_sectors(); + void _sdh_irq(); + + uint32_t _sectors; + bool _dbg; + PlatformMutex _lock; + + const struct nu_modinit_s * _sdh_modinit; + SDName _sdh; + SDH_T * _sdh_base; +#if TARGET_NUMAKER_PFM_NUC472 + uint32_t _sdh_port; +#endif + + CThunk<NuSDBlockDevice> _sdh_irq_thunk; + + PinName _sd_dat0; + PinName _sd_dat1; + PinName _sd_dat2; + PinName _sd_dat3; + PinName _sd_cmd; + PinName _sd_clk; + PinName _sd_cdn; + + bool _is_initialized; + uint32_t _init_ref_count; +}; + +#endif /* TARGET_NUVOTON */ +#endif /* __NU_SD_BLOCK_DEVICE_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/storage/COMPONENT_NUSD/README.md Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,18 @@ +# Block device driver for SD card supported by Nuvoton platforms + +This driver implements [BlockDevice class](https://github.com/ARMmbed/mbed-os/blob/master/features/filesystem/bd/BlockDevice.h) +introduced with mbed OS 5.4 for SD card running in SD bus mode on Nuvoton platforms which support it. + +ARM mbed team also releases an official [SD driver](https://github.com/armmbed/sd-driver), but it supports SPI bus mode +rather than SD bus mode. + +## Use with FAT file system +The [SD file system example](https://developer.mbed.org/teams/Nuvoton/code/NuMaker-mbed-SD-FileSystem-example/) is cloned from +the [FAT file system example](https://github.com/armmbed/mbed-os-example-fat-filesystem) released by ARM mbed team and +is modified to use this SD block device to back the FAT file system. + +## Support Nuvoton platforms +- [NuMaker-PFM-NUC472](https://developer.mbed.org/platforms/Nuvoton-NUC472/) +- NuMaker-PFM-M487 +- NuMaker-PFM-M2351 +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/storage/MySystemStorage.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2018 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 "BlockDevice.h" +#include "FileSystem.h" +#include "FATFileSystem.h" +#include "LittleFileSystem.h" + +#if COMPONENT_SPIF +#include "SPIFBlockDevice.h" +#endif + +#if COMPONENT_QSPIF +#include "QSPIFBlockDevice.h" +#endif + +#if COMPONENT_DATAFLASH +#include "DataFlashBlockDevice.h" +#endif + +#if COMPONENT_SD +#include "SDBlockDevice.h" +#endif + +#if COMPONENT_FLASHIAP +#include "FlashIAPBlockDevice.h" +#endif + +#if COMPONENT_NUSD +#include "NuSDBlockDevice.h" +#endif + +using namespace mbed; + +// Align a value to a specified size. +// Parameters : +// val - [IN] Value. +// size - [IN] Size. +// Return : Aligned value. +static inline uint32_t align_up(uint32_t val, uint32_t size) +{ + return (((val - 1) / size) + 1) * size; +} + +BlockDevice *BlockDevice::get_default_instance() +{ +#if COMPONENT_SPIF + + static SPIFBlockDevice default_bd( + MBED_CONF_SPIF_DRIVER_SPI_MOSI, + MBED_CONF_SPIF_DRIVER_SPI_MISO, + MBED_CONF_SPIF_DRIVER_SPI_CLK, + MBED_CONF_SPIF_DRIVER_SPI_CS, + MBED_CONF_SPIF_DRIVER_SPI_FREQ + ); + + return &default_bd; + +#elif COMPONENT_QSPIF + + static QSPIFBlockDevice default_bd( + MBED_CONF_QSPIF_QSPI_IO0, + MBED_CONF_QSPIF_QSPI_IO1, + MBED_CONF_QSPIF_QSPI_IO2, + MBED_CONF_QSPIF_QSPI_IO3, + MBED_CONF_QSPIF_QSPI_SCK, + MBED_CONF_QSPIF_QSPI_CSN, + MBED_CONF_QSPIF_QSPI_POLARITY_MODE, + MBED_CONF_QSPIF_QSPI_FREQ + ); + + return &default_bd; + +#elif COMPONENT_DATAFLASH + + static DataFlashBlockDevice default_bd( + MBED_CONF_DATAFLASH_SPI_MOSI, + MBED_CONF_DATAFLASH_SPI_MISO, + MBED_CONF_DATAFLASH_SPI_CLK, + MBED_CONF_DATAFLASH_SPI_CS + ); + + return &default_bd; + +#elif COMPONENT_SD + + static SDBlockDevice default_bd( + MBED_CONF_SD_SPI_MOSI, + MBED_CONF_SD_SPI_MISO, + MBED_CONF_SD_SPI_CLK, + MBED_CONF_SD_SPI_CS + ); + + return &default_bd; + +#elif COMPONENT_NUSD + + static NuSDBlockDevice default_bd; + + return &default_bd; + +#elif COMPONENT_FLASHIAP + +#if (MBED_CONF_FLASHIAP_BLOCK_DEVICE_SIZE == 0) && (MBED_CONF_FLASHIAP_BLOCK_DEVICE_BASE_ADDRESS == 0xFFFFFFFF) + + size_t flash_size; + uint32_t start_address; + uint32_t bottom_address; + FlashIAP flash; + + int ret = flash.init(); + if (ret != 0) { + return 0; + } + + //Find the start of first sector after text area + bottom_address = align_up(FLASHIAP_ROM_END, flash.get_sector_size(FLASHIAP_ROM_END)); + start_address = flash.get_flash_start(); + flash_size = flash.get_flash_size(); + + ret = flash.deinit(); + + static FlashIAPBlockDevice default_bd(bottom_address, start_address + flash_size - bottom_address); + +#else + + static FlashIAPBlockDevice default_bd; + +#endif + + return &default_bd; + +#else + + return NULL; + +#endif + +} + +FileSystem *FileSystem::get_default_instance() +{ +#if COMPONENT_SPIF || COMPONENT_QSPIF || COMPONENT_DATAFLASH || COMPONENT_NUSD + + static LittleFileSystem flash("flash", BlockDevice::get_default_instance()); + flash.set_as_default(); + + return &flash; + +#elif COMPONENT_SD + + static FATFileSystem sdcard("sd", BlockDevice::get_default_instance()); + sdcard.set_as_default(); + + return &sdcard; + +#elif COMPONENT_FLASHIAP + + static LittleFileSystem flash("flash", BlockDevice::get_default_instance()); + flash.set_as_default(); + + return &flash; + +#else + + return NULL; + +#endif + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,185 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2018 ARM Ltd. +// +// 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. +// ---------------------------------------------------------------------------- +#ifndef MBED_TEST_MODE + +#include "mbed.h" +#include "simple-mbed-cloud-client.h" +#include "FATFileSystem.h" +#include "LittleFileSystem.h" + +// Default network interface object. Don't forget to change the WiFi SSID/password in mbed_app.json if you're using WiFi. +NetworkInterface *net = NetworkInterface::get_default_instance(); + +// Default block device available on the target board +BlockDevice *bd = BlockDevice::get_default_instance(); + +#if COMPONENT_SD || COMPONENT_NUSD +// Use FATFileSystem for SD card type blockdevices +//FATFileSystem fs("fs", bd); +#else +// Use LittleFileSystem for non-SD block devices to enable wear leveling and other functions +//LittleFileSystem fs("fs", bd); +#endif + +FileSystem *fs = FileSystem::get_default_instance(); + +#if USE_BUTTON == 1 +InterruptIn button(BUTTON1); +#endif /* USE_BUTTON */ + +// Default LED to use for PUT/POST example +DigitalOut led(LED1); + +// Declaring pointers for access to Pelion Device Management Client resources outside of main() +MbedCloudClientResource *button_res; +MbedCloudClientResource *led_res; +MbedCloudClientResource *post_res; + +// An event queue is a very useful structure to debounce information between contexts (e.g. ISR and normal threads) +// This is great because things such as network operations are illegal in ISR, so updating a resource in a button's fall() function is not allowed +EventQueue eventQueue; + +/** + * PUT handler - sets the value of the built-in LED + * @param resource The resource that triggered the callback + * @param newValue Updated value for the resource + */ +void put_callback(MbedCloudClientResource *resource, m2m::String newValue) { + printf("PUT received. New value: %s\n", newValue.c_str()); + led = atoi(newValue.c_str()); +} + +/** + * POST handler - prints the content of the payload + * @param resource The resource that triggered the callback + * @param buffer If a body was passed to the POST function, this contains the data. + * Note that the buffer is deallocated after leaving this function, so copy it if you need it longer. + * @param size Size of the body + */ +void post_callback(MbedCloudClientResource *resource, const uint8_t *buffer, uint16_t size) { + printf("POST received (length %u). Payload: ", size); + for (size_t ix = 0; ix < size; ix++) { + printf("%02x ", buffer[ix]); + } + printf("\n"); +} + +/** + * Button handler + * This function will be triggered either by a physical button press or by a ticker every 5 seconds (see below) + */ +void button_press() { + int v = button_res->get_value_int() + 1; + button_res->set_value(v); + printf("Button clicked %d times\n", v); +} + +/** + * Notification callback handler + * @param resource The resource that triggered the callback + * @param status The delivery status of the notification + */ +void button_callback(MbedCloudClientResource *resource, const NoticationDeliveryStatus status) { + printf("Button notification, status %s (%d)\n", MbedCloudClientResource::delivery_status_to_string(status), status); +} + +/** + * Registration callback handler + * @param endpoint Information about the registered endpoint such as the name (so you can find it back in portal) + */ +void registered(const ConnectorClientEndpointInfo *endpoint) { + printf("Registered to Pelion Device Management. Endpoint Name: %s\n", endpoint->internal_endpoint_name.c_str()); +} + +int main(void) { + printf("\nStarting Simple Pelion Device Management Client example\n"); + +#if USE_BUTTON == 1 + // If the User button is pressed ons start, then format storage. + if (button.read() == MBED_CONF_APP_BUTTON_PRESSED_STATE) { + printf("User button is pushed on start. Formatting the storage...\n"); + int storage_status = StorageHelper::format(fs, bd); + if (storage_status != 0) { + printf("ERROR: Failed to reformat the storage (%d).\n", storage_status); + } + } else { + printf("You can hold the user button during boot to format the storage and change the device identity.\n"); + } +#endif /* USE_BUTTON */ + + // Connect to the Internet (DHCP is expected to be on) + printf("Connecting to the network using the default network interface...\n"); + net = NetworkInterface::get_default_instance(); + + nsapi_error_t net_status = NSAPI_ERROR_NO_CONNECTION; + while ((net_status = net->connect()) != NSAPI_ERROR_OK) { + printf("Unable to connect to network (%d). Retrying...\n", net_status); + } + + printf("Connected to the network successfully. IP address: %s\n", net->get_ip_address()); + + printf("Initializing Pelion Device Management Client...\n"); + + // SimpleMbedCloudClient handles registering over LwM2M to Pelion Device Management + SimpleMbedCloudClient client(net, bd, fs); + int client_status = client.init(); + if (client_status != 0) { + printf("Pelion Client initialization failed (%d)\n", client_status); + return -1; + } + + // Creating resources, which can be written or read from the cloud + button_res = client.create_resource("3200/0/5501", "button_count"); + button_res->set_value(0); + button_res->methods(M2MMethod::GET); + button_res->observable(true); + button_res->attach_notification_callback(button_callback); + + led_res = client.create_resource("3201/0/5853", "led_state"); + led_res->set_value(led.read()); + led_res->methods(M2MMethod::GET | M2MMethod::PUT); + led_res->attach_put_callback(put_callback); + + post_res = client.create_resource("3300/0/5605", "execute_function"); + post_res->methods(M2MMethod::POST); + post_res->attach_post_callback(post_callback); + + printf("Initialized Pelion Device Management Client. Registering...\n"); + + // Callback that fires when registering is complete + client.on_registered(®istered); + + // Register with Pelion DM + client.register_and_connect(); + +#if USE_BUTTON == 1 + // The button fires on an interrupt context, but debounces it to the eventqueue, so it's safe to do network operations + button.fall(eventQueue.event(&button_press)); + printf("Press the user button to increment the LwM2M resource value...\n"); +#else + // The timer fires on an interrupt context, but debounces it to the eventqueue, so it's safe to do network operations + Ticker timer; + timer.attach(eventQueue.event(&button_press), 5.0); + printf("Simulating button press every 5 seconds...\n"); +#endif /* USE_BUTTON */ + + // You can easily run the eventQueue in a separate thread if required + eventQueue.dispatch_forever(); +} + +#endif /* MBED_TEST_MODE */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#ecb3c8c837162c73537bd0f3592c6e2a42994045
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_app.json Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,133 @@ +{ + "macros": [ + "ARM_UC_USE_PAL_BLOCKDEVICE=1", + "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE", + "MCC_PLATFORM_WAIT_BEFORE_BD_INIT=3" + ], + "target_overrides": { + "*": { + "target.components_remove" : ["FLASHIAP"], + "platform.stdio-baud-rate" : 115200, + "platform.stdio-convert-newlines" : true, + "mbed-trace.enable" : false, + "nsapi.default-wifi-security" : "WPA_WPA2", + "nsapi.default-wifi-ssid" : "\"AlanAP\"", + "nsapi.default-wifi-password" : "\"Alan1234\"" + }, + "MTB_USI_WM_BN_BM_22": { + "target.components_add" : ["SPIF"], + "spif-driver.SPI_MOSI" : "PC_3", + "spif-driver.SPI_MISO" : "PC_2", + "spif-driver.SPI_CLK" : "PB_13", + "spif-driver.SPI_CS" : "PA_6", + "device-management.flash-start-address" : "0x08000000", + "device-management.flash-size" : "(1024*1024)", + "device-management.sotp-section-1-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 48*1024)", + "device-management.sotp-section-1-size" : "(16*1024)", + "device-management.sotp-section-2-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 64*1024)", + "device-management.sotp-section-2-size" : "(16*1024)", + "update-client.application-details" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 128*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(1*1024*1024)", + "update-client.storage-locations" : "1", + "target.features_add" : ["BOOTLOADER"], + "target.bootloader_img" : "bootloader/mbed-bootloader-MTB_USI_WM_BN_BM_22.bin", + "target.header_offset" : "0x20000", + "target.app_offset" : "0x20400", + "target.OUTPUT_EXT" : "hex" + }, + "MTB_ADV_WISE_1530": { + "target.features_add" : ["STORAGE", "BOOTLOADER", "LWIP"], + "target.components_remove" : ["SPIF"], + "target.components_add" : ["SD"], + "target.network-default-interface-type" : "WIFI", + "target.header_offset" : "0x00020000", + "target.app_offset" : "0x00020400", + "target.lse_available" : 0, + "target.bootloader_img" : "bootloader/mbed-bootloader-MTB_ADV_WISE_1530.bin", + "target.stdio_uart_tx" : "PA_9", + "target.stdio_uart_rx" : "PA_10", + "device-management.flash-size" : "(1024*1024*2)", + "device-management.pal_fs_mount_point_primary": "\"/sd\"", + "device-management.partition_mode" : 0, + "device-management.primary_partition_size" : "(1024*1024*2)", + "device-management.sotp-section-1-address" : "0x0800C000", + "device-management.sotp-section-1-size" : "0x4000", + "device-management.sotp-section-2-address" : "0x08010000", + "device-management.sotp-section-2-size" : "0x10000", + "update-client.application-details" : "0x08020000", + "update-client.bootloader-details" : "0x08005ce4", + "update-client.storage-address" : "(1024*1024*2)", + "update-client.storage-size" : "(1024*1024*2)", + "update-client.storage-locations" : "1", + "update-client.storage-page" : 1, + "sd.SPI_MOSI" : "PC_3", + "sd.SPI_MISO" : "PC_2", + "sd.SPI_CLK" : "PB_13", + "sd.SPI_CS" : "PB_9", + "target.led1" : "NC", + "target.led2" : "NC", + "target.OUTPUT_EXT" : "hex" + }, + "MTB_ADV_WISE_1570": { + "target.components_add" : ["SPIF"], + "spif-driver.SPI_FREQ" : 20000000, + "target.network-default-interface-type" : "CELLULAR", + "cellular.debug-at" : false, + "cellular.use-apn-lookup" : false, + "platform.stdio-baud-rate" : 115200, + "platform.default-serial-baud-rate" : 115200, + "device-management.flash-start-address" : "0x08000000", + "device-management.flash-size" : "(1024*1024)", + "device-management.sotp-section-1-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 2*(4*1024))", + "device-management.sotp-section-1-size" : "(4*1024)", + "device-management.sotp-section-2-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - 1*(4*1024))", + "device-management.sotp-section-2-size" : "(4*1024)", + "device-management.mcc_transport_mode" : 0, + "device-management.pal_dtls_peer_min_timeout" : "20000", + "device-management.pal-udp-mtu-size" : 1358, + "update-client.application-details" : "(MBED_CONF_APP_FLASH_START_ADDRESS + 32*1024)", + "update-client.storage-address" : "(2*1024*1024)", + "update-client.storage-size" : "(1*1024*1024)", + "update-client.storage-locations" : "1", + "target.features_add" : ["BOOTLOADER"], + "target.bootloader_img" : "bootloader/mbed-bootloader-MTB_ADV_WISE_1570.bin", + "target.header_offset" : "0x8000", + "target.app_offset" : "0x8400", + "target.OUTPUT_EXT" : "hex", + "mbed-client.sn-coap-duplication-max-msgs-count": 1, + "nsapi.dns-response-wait-time" : 30000 + } + }, + "config": { + "format-storage-layer-on-error": { + "help": "Whether to format the storage layer when it cannot be read - always disable for production devices!", + "value": 1 + }, + "main-stack-size": { + "value": 6000 + }, + "use-button": { + "help": "Whether the target has a button", + "macro_name": "USE_BUTTON", + "value": false + }, + "button-pressed-state": { + "help": "Value of the button when pressed", + "value": 1 + }, + "no_led": { + "help": "This flag disables the heartbeat thread in tests. This is useful for platforms that don't have an LED or the LED is used for other functionality like LED on the SPI clockline etc", + "value": null + }, + "developer-mode": { + "help": "Enable Developer mode to skip Factory enrollment", + "value": 1 + }, + "trace-level": { + "help": "Options are TRACE_LEVEL_ERROR,TRACE_LEVEL_WARN,TRACE_LEVEL_INFO,TRACE_LEVEL_DEBUG", + "macro_name": "MBED_TRACE_MAX_LEVEL", + "value": "TRACE_LEVEL_INFO" + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_cloud_dev_credentials.c Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 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. + */ +#ifndef __MBED_CLOUD_DEV_CREDENTIALS_H__ +#define __MBED_CLOUD_DEV_CREDENTIALS_H__ + +#if MBED_CONF_DEVICE_MANAGEMENT_DEVELOPER_MODE == 1 +#error "Replace mbed_cloud_dev_credentials.c with your own developer cert." +#endif + +#include <inttypes.h> + +const char MBED_CLOUD_DEV_BOOTSTRAP_ENDPOINT_NAME[] = ""; +const char MBED_CLOUD_DEV_ACCOUNT_ID[] = ""; +const char MBED_CLOUD_DEV_BOOTSTRAP_SERVER_URI[] = ""; + +const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE[] = +{ 0x0 }; + +const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE[] = +{ 0x0 }; + +const uint8_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY[] = +{ 0x0 }; + +const char MBED_CLOUD_DEV_MANUFACTURER[] = "dev_manufacturer"; + +const char MBED_CLOUD_DEV_MODEL_NUMBER[] = "dev_model_num"; + +const char MBED_CLOUD_DEV_SERIAL_NUMBER[] = "0"; + +const char MBED_CLOUD_DEV_DEVICE_TYPE[] = "dev_device_type"; + +const char MBED_CLOUD_DEV_HARDWARE_VERSION[] = "dev_hardware_version"; + +const uint32_t MBED_CLOUD_DEV_MEMORY_TOTAL_KB = 0; +const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_CERTIFICATE); +const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_SERVER_ROOT_CA_CERTIFICATE); +const uint32_t MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY_SIZE = sizeof(MBED_CLOUD_DEV_BOOTSTRAP_DEVICE_PRIVATE_KEY); + +#endif //__MBED_CLOUD_DEV_CREDENTIALS_H__ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed_settings.py Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,45 @@ +""" +mbed SDK +Copyright (c) 2016 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. +""" + +from os.path import join, abspath, dirname + +#ROOT = abspath(join(dirname(__file__), ".")) + +############################################################################## +# Build System Settings +############################################################################## +#BUILD_DIR = abspath(join(ROOT, "build")) + +# ARM +#ARM_PATH = "C:/Program Files/ARM" + +# GCC ARM +#GCC_ARM_PATH = "" + +# IAR +#IAR_PATH = "C:/Program Files (x86)/IAR Systems/Embedded Workbench 7.0/arm" + +# Goanna static analyser. Please overload it in private_settings.py +#GOANNA_PATH = "c:/Program Files (x86)/RedLizards/Goanna Central 3.2.3/bin" + +#BUILD_OPTIONS = [] + +# mbed.org username +#MBED_ORG_USER = "" + +# Print compiler warnings and errors as link format +#PRINT_COMPILER_OUTPUT_AS_LINK = False
Binary file mbed_settings.pyc has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simple-mbed-cloud-client.lib Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/simple-mbed-cloud-client/#f7e701889adb52935b77204190f347795cfd477a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/TARGET_NUVOTON/NetworkInterfaceDefaults.cpp Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,37 @@ +/* Network interface defaults + * Copyright (c) 2018-2020 Nuvoton + * + * 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 "mbed.h" + +#define ETHERNET 1 +#define WIFI 2 +#define MESH 3 +#define CELLULAR 4 + +#if MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == ETHERNET + +#include "EthInterface.h" + +EthInterface *EthInterface::get_default_instance() +{ + return get_target_default_instance(); +} + +NetworkInterface *NetworkInterface::get_default_instance() +{ + return EthInterface::get_default_instance(); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/update_default_resources.c Tue Mar 12 13:48:39 2019 +0800 @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// 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. +// ---------------------------------------------------------------------------- + +#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#endif + +#include <stdint.h> + +#ifdef MBED_CLOUD_DEV_UPDATE_ID +const uint8_t arm_uc_vendor_id[16] = { "dev_manufacturer" }; +const uint16_t arm_uc_vendor_id_size = sizeof(arm_uc_vendor_id); + +const uint8_t arm_uc_class_id[16] = { "dev_model_number" }; +const uint16_t arm_uc_class_id_size = sizeof(arm_uc_class_id); +#endif + +#ifdef MBED_CLOUD_DEV_UPDATE_CERT +const uint8_t arm_uc_default_fingerprint[32] = { 0 }; +const uint16_t arm_uc_default_fingerprint_size = + sizeof(arm_uc_default_fingerprint); + +const uint8_t arm_uc_default_certificate[1] = { 0 }; +const uint16_t arm_uc_default_certificate_size = + sizeof(arm_uc_default_certificate); +#endif \ No newline at end of file