diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4c01c7d --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +PROJECT_NAME := mkrwifi1010-fw + +EXTRA_COMPONENT_DIRS := $(PWD)/arduino + +include $(IDF_PATH)/make/project.mk diff --git a/README.md b/README.md new file mode 100644 index 0000000..0a477ae --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# MKR WiFi 1010: NINA-W102 firmware + +This firmware uses [Espressif's IDF](https://github.com/espressif/esp-idf) + +## Building + +1. [Download the ESP32 toolchain](http://esp-idf.readthedocs.io/en/v3.0/get-started/index.html#setup-toolchain) +1. Extract it and add it to your `PATH`: `export PATH=$PATH:/bin` +1. Clone **v3.0** of the IDF: `git clone --branch v3.0 --recursive https://github.com/espressif/esp-idf.git` +1. Set the `IDF_PATH` environment variable: `export IDF_PATH=` +1. Run `make` to build the firmware (in the directory of this read me) +1. Load the `WiFi1010FirmwareUpdater` example sketch on to the board +1. Use `esptool` to flash the compiled firmware + +## License + +Copyright (c) 2018 Arduino AG. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/arduino/component.mk b/arduino/component.mk new file mode 100644 index 0000000..e2da802 --- /dev/null +++ b/arduino/component.mk @@ -0,0 +1,3 @@ +COMPONENT_ADD_INCLUDEDIRS := cores/esp32 libraries/SPIS/src libraries/WiFi/src + +COMPONENT_SRCDIRS := cores/esp32 libraries/SPIS/src libraries/WiFi/src diff --git a/arduino/cores/esp32/Arduino.h b/arduino/cores/esp32/Arduino.h new file mode 100644 index 0000000..0ad6923 --- /dev/null +++ b/arduino/cores/esp32/Arduino.h @@ -0,0 +1,52 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARDUINO_H +#define ARDUINO_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif // __cplusplus + +// system functions +void init(void); + +// sketch +void setup(void); +void loop(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus + #include "WMath.h" +#endif +#include "delay.h" + +#include "wiring_digital.h" +#include "wiring_analog.h" + +#endif // ARDUINO_H diff --git a/arduino/cores/esp32/WInterrupts.c b/arduino/cores/esp32/WInterrupts.c new file mode 100644 index 0000000..2a9f560 --- /dev/null +++ b/arduino/cores/esp32/WInterrupts.c @@ -0,0 +1,74 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "wiring_digital.h" + +#include "WInterrupts.h" + +static voidFuncPtr callbacksInt[GPIO_NUM_MAX] = { NULL }; + +void IRAM_ATTR gpioInterruptHandler(void* arg) +{ + uint32_t pin = (uint32_t)arg; + + if (callbacksInt[pin]) { + callbacksInt[pin](); + } +} + +void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) +{ + callbacksInt[pin] = callback; + + switch (mode) { + case LOW: + gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_LOW_LEVEL); + gpio_wakeup_enable((gpio_num_t)pin, GPIO_INTR_LOW_LEVEL); + break; + + case HIGH: + gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_HIGH_LEVEL); + gpio_wakeup_enable((gpio_num_t)pin, GPIO_INTR_HIGH_LEVEL); + break; + + case CHANGE: + gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_ANYEDGE); + break; + + case FALLING: + gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_NEGEDGE); + break; + + case RISING: + gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_POSEDGE); + break; + + default: + gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE); + break; + } + + gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); + + gpio_isr_handler_add((gpio_num_t)pin, gpioInterruptHandler, (void*)pin); + + gpio_intr_enable((gpio_num_t)pin); +} diff --git a/arduino/cores/esp32/WInterrupts.h b/arduino/cores/esp32/WInterrupts.h new file mode 100644 index 0000000..24fe376 --- /dev/null +++ b/arduino/cores/esp32/WInterrupts.h @@ -0,0 +1,43 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _WIRING_INTERRUPTS_ +#define _WIRING_INTERRUPTS_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// #define LOW 0 +// #define HIGH 1 +#define CHANGE 2 +#define FALLING 3 +#define RISING 4 + +typedef void (*voidFuncPtr)(void); + +void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/arduino/cores/esp32/WMath.cpp b/arduino/cores/esp32/WMath.cpp new file mode 100644 index 0000000..f754453 --- /dev/null +++ b/arduino/cores/esp32/WMath.cpp @@ -0,0 +1,33 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +extern "C" { + #include +} + +#include "WMath.h" + +extern long random(long howbig) +{ + if(howbig == 0) { + return 0; + } + + return esp_random() % howbig; +} diff --git a/arduino/cores/esp32/WMath.h b/arduino/cores/esp32/WMath.h new file mode 100644 index 0000000..454fbac --- /dev/null +++ b/arduino/cores/esp32/WMath.h @@ -0,0 +1,33 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _WIRING_MATH_ +#define _WIRING_MATH_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern long random(long); + +#ifdef __cplusplus +} +#endif + +#endif /* _WIRING_MATH_ */ diff --git a/arduino/cores/esp32/delay.c b/arduino/cores/esp32/delay.c new file mode 100644 index 0000000..2377884 --- /dev/null +++ b/arduino/cores/esp32/delay.c @@ -0,0 +1,33 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include "delay.h" + +unsigned long millis() +{ + return xTaskGetTickCount() * portTICK_PERIOD_MS; +} + +void delay(uint32_t ms) +{ + vTaskDelay(ms / portTICK_PERIOD_MS); +} diff --git a/arduino/cores/esp32/delay.h b/arduino/cores/esp32/delay.h new file mode 100644 index 0000000..cf877c9 --- /dev/null +++ b/arduino/cores/esp32/delay.h @@ -0,0 +1,37 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef DELAY_H +#define DELAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern unsigned long millis(); + +extern void delay(uint32_t ms); + +#ifdef __cplusplus +} +#endif + +#endif // DELAY_H diff --git a/arduino/cores/esp32/main.cpp b/arduino/cores/esp32/main.cpp new file mode 100644 index 0000000..420a6ef --- /dev/null +++ b/arduino/cores/esp32/main.cpp @@ -0,0 +1,40 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#define ARDUINO_MAIN +#include "Arduino.h" + +void arduino_main(void*) { + init(); + + setup(); + + while (1) { + loop(); + } +} + +extern "C" { + void app_main() { + xTaskCreatePinnedToCore(arduino_main, "arduino", 8192, NULL, 1, NULL, 1); + } +} diff --git a/arduino/cores/esp32/wiring.c b/arduino/cores/esp32/wiring.c new file mode 100644 index 0000000..d0cdeee --- /dev/null +++ b/arduino/cores/esp32/wiring.c @@ -0,0 +1,26 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "Arduino.h" + +void init() { + nvs_flash_init(); +} diff --git a/arduino/cores/esp32/wiring_analog.c b/arduino/cores/esp32/wiring_analog.c new file mode 100644 index 0000000..cc5b363 --- /dev/null +++ b/arduino/cores/esp32/wiring_analog.c @@ -0,0 +1,45 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "wiring_analog.h" + +void analogWrite(uint32_t pin, uint32_t value) +{ + periph_module_enable(PERIPH_LEDC_MODULE); + + ledc_timer_config_t timerConf = { + .bit_num = LEDC_TIMER_10_BIT, + .freq_hz = 1000, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .timer_num = (pin / 7), + }; + ledc_timer_config(&timerConf); + + ledc_channel_config_t ledc_conf = { + .channel = (pin % 7), + .duty = (value << 2), + .gpio_num = pin, + .intr_type = LEDC_INTR_DISABLE, + .speed_mode = LEDC_HIGH_SPEED_MODE, + .timer_sel = (pin / 7) + }; + ledc_channel_config(&ledc_conf); +} diff --git a/arduino/cores/esp32/wiring_analog.h b/arduino/cores/esp32/wiring_analog.h new file mode 100644 index 0000000..a04b58b --- /dev/null +++ b/arduino/cores/esp32/wiring_analog.h @@ -0,0 +1,35 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIRING_ANALOG_H +#define WIRING_ANALOG_H + +#include "Arduino.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void analogWrite(uint32_t pin, uint32_t value); + +#ifdef __cplusplus +} +#endif + +#endif // WIRING_ANALOG_H diff --git a/arduino/cores/esp32/wiring_digital.c b/arduino/cores/esp32/wiring_digital.c new file mode 100644 index 0000000..a38cfe0 --- /dev/null +++ b/arduino/cores/esp32/wiring_digital.c @@ -0,0 +1,44 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "wiring_digital.h" + +void pinMode(uint32_t pin, uint32_t mode) +{ + switch (mode) { + case INPUT: + gpio_set_direction((gpio_num_t)pin, GPIO_MODE_INPUT); + gpio_set_pull_mode((gpio_num_t)pin, GPIO_FLOATING); + break; + + case OUTPUT: + gpio_set_direction((gpio_num_t)pin, GPIO_MODE_OUTPUT); + gpio_set_pull_mode((gpio_num_t)pin, GPIO_FLOATING); + break; + } + + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pin], PIN_FUNC_GPIO); +} + +void digitalWrite(uint32_t pin, uint32_t val) +{ + gpio_set_level((gpio_num_t)pin, val); +} diff --git a/arduino/cores/esp32/wiring_digital.h b/arduino/cores/esp32/wiring_digital.h new file mode 100644 index 0000000..0aabef4 --- /dev/null +++ b/arduino/cores/esp32/wiring_digital.h @@ -0,0 +1,43 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIRING_DIGITAL_H +#define WIRING_DIGITAL_H + +#include "Arduino.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOW 0x00 +#define HIGH 0x01 + +#define INPUT 0x00 +#define OUTPUT 0x01 + +extern void pinMode(uint32_t pin, uint32_t mode); + +extern void digitalWrite(uint32_t pin, uint32_t val); + +#ifdef __cplusplus +} +#endif + +#endif // WIRING_DIGITAL_H diff --git a/arduino/libraries/SPIS/src/SPIS.cpp b/arduino/libraries/SPIS/src/SPIS.cpp new file mode 100644 index 0000000..341b18d --- /dev/null +++ b/arduino/libraries/SPIS/src/SPIS.cpp @@ -0,0 +1,116 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include +#include + +#include "wiring_digital.h" +#include "WInterrupts.h" + +#include "SPIS.h" + +SPISClass::SPISClass(spi_host_device_t hostDevice, int dmaChannel, int mosiPin, int misoPin, int sclkPin, int csPin, int readyPin) : + _hostDevice(hostDevice), + _dmaChannel(dmaChannel), + _mosiPin(mosiPin), + _misoPin(misoPin), + _sclkPin(sclkPin), + _csPin(csPin), + _readyPin(readyPin) +{ +} + +int SPISClass::begin() +{ + spi_bus_config_t busCfg; + spi_slave_interface_config_t slvCfg; + + pinMode(_readyPin, OUTPUT); + digitalWrite(_readyPin, HIGH); + + _readySemaphore = xSemaphoreCreateCounting(1, 0); + + attachInterrupt(_csPin, onChipSelect, FALLING); + + memset(&busCfg, 0x00, sizeof(busCfg)); + busCfg.mosi_io_num = _mosiPin; + busCfg.miso_io_num = _misoPin; + busCfg.sclk_io_num = _sclkPin; + + memset(&slvCfg, 0x00, sizeof(slvCfg)); + slvCfg.mode = 0; + slvCfg.spics_io_num = _csPin; + slvCfg.queue_size = 1; + slvCfg.flags = 0; + slvCfg.post_setup_cb = SPISClass::onSetupComplete; + slvCfg.post_trans_cb = NULL; + + gpio_set_pull_mode((gpio_num_t)_mosiPin, GPIO_FLOATING); + gpio_set_pull_mode((gpio_num_t)_sclkPin, GPIO_PULLDOWN_ONLY); + gpio_set_pull_mode((gpio_num_t)_csPin, GPIO_PULLUP_ONLY); + + spi_slave_initialize(_hostDevice, &busCfg, &slvCfg, _dmaChannel); + + return 1; +} + +int SPISClass::transfer(uint8_t out[], uint8_t in[], size_t len) +{ + spi_slave_transaction_t slvTrans; + spi_slave_transaction_t* slvRetTrans; + + memset(&slvTrans, 0x00, sizeof(slvTrans)); + + slvTrans.length = len * 8; + slvTrans.trans_len = 0; + slvTrans.tx_buffer = out; + slvTrans.rx_buffer = in; + + spi_slave_queue_trans(_hostDevice, &slvTrans, portMAX_DELAY); + xSemaphoreTake(_readySemaphore, portMAX_DELAY); + digitalWrite(_readyPin, LOW); + spi_slave_get_trans_result(_hostDevice, &slvRetTrans, portMAX_DELAY); + digitalWrite(_readyPin, HIGH); + + return (slvTrans.trans_len / 8); +} + +void SPISClass::onChipSelect() +{ + SPIS.handleOnChipSelect(); +} + +void SPISClass::handleOnChipSelect() +{ + digitalWrite(_readyPin, HIGH); +} + +void SPISClass::onSetupComplete(spi_slave_transaction_t*) +{ + SPIS.handleSetupComplete(); +} + +void SPISClass::handleSetupComplete() +{ + xSemaphoreGiveFromISR(_readySemaphore, NULL); +} + +SPISClass SPIS(VSPI_HOST, 1, 12, 23, 18, 5, 33); diff --git a/arduino/libraries/SPIS/src/SPIS.h b/arduino/libraries/SPIS/src/SPIS.h new file mode 100644 index 0000000..9065351 --- /dev/null +++ b/arduino/libraries/SPIS/src/SPIS.h @@ -0,0 +1,58 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef SPIS_H +#define SPIS_H + +#include +#include + +class SPISClass { + + public: + SPISClass(spi_host_device_t hostDevice, int dmaChannel, int mosiPin, int misoPin, int sclkPin, int csPin, int readyPin); + + int begin(); + int transfer(uint8_t out[], uint8_t in[], size_t len); + + private: + static void onChipSelect(); + void handleOnChipSelect(); + + static void onSetupComplete(spi_slave_transaction_t*); + void handleSetupComplete(); + + private: + spi_host_device_t _hostDevice; + int _dmaChannel; + int _mosiPin; + int _misoPin; + int _sclkPin; + int _csPin; + int _readyPin; + + intr_handle_t _csIntrHandle; + + SemaphoreHandle_t _readySemaphore; +}; + +extern SPISClass SPIS; + +#endif + diff --git a/arduino/libraries/WiFi/src/WiFi.cpp b/arduino/libraries/WiFi/src/WiFi.cpp new file mode 100644 index 0000000..924f9bb --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFi.cpp @@ -0,0 +1,674 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "WiFi.h" + +WiFiClass::WiFiClass() : + _initialized(false), + _status(WL_NO_SHIELD), + _interface(ESP_IF_WIFI_STA), + _onReceiveCallback(NULL) +{ + _eventGroup = xEventGroupCreate(); + memset(&_apRecord, 0x00, sizeof(_apRecord)); + memset(&_ipInfo, 0x00, sizeof(_ipInfo)); +} + +uint8_t WiFiClass::status() +{ + if (!_initialized) { + _initialized = true; + init(); + } + + return _status; +} + +int WiFiClass::hostByName(const char* hostname, /*IPAddress*/uint32_t& result) +{ + result = 0xffffffff; + + struct hostent* hostEntry = lwip_gethostbyname(hostname); + + if (hostEntry == NULL) { + return 0; + } + + memcpy(&result, hostEntry->h_addr_list[0], sizeof(result)); + + return 1; +} + +int WiFiClass::ping(/*IPAddress*/uint32_t host, uint8_t ttl) +{ + uint32_t timeout = 5000; + + int s = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP); + + struct timeval timeoutVal; + timeoutVal.tv_sec = (timeout / 1000); + timeoutVal.tv_usec = (timeout % 1000) * 1000; + + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeoutVal, sizeof(timeoutVal)); + setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + + struct __attribute__((__packed__)) { + struct icmp_echo_hdr header; + uint8_t data[32]; + } request; + + ICMPH_TYPE_SET(&request.header, ICMP_ECHO); + ICMPH_CODE_SET(&request.header, 0); + request.header.chksum = 0; + request.header.id = 0xAFAF; + request.header.seqno = random(0xffff); + + for (size_t i = 0; i < sizeof(request.data); i++) { + request.data[i] = i; + } + + request.header.chksum = inet_chksum(&request, sizeof(request)); + + ip_addr_t addr; + addr.type = IPADDR_TYPE_V4; + addr.u_addr.ip4.addr = host; + // IP_ADDR4(&addr, ip[0], ip[1], ip[2], ip[3]); + + struct sockaddr_in to; + struct sockaddr_in from; + + to.sin_len = sizeof(to); + to.sin_family = AF_INET; + inet_addr_from_ipaddr(&to.sin_addr, ip_2_ip4(&addr)); + + sendto(s, &request, sizeof(request), 0, (struct sockaddr*)&to, sizeof(to)); + unsigned long sendTime = millis(); + unsigned long recvTime = 0; + + do { + socklen_t fromlen = sizeof(from); + + struct __attribute__((__packed__)) { + struct ip_hdr ipHeader; + struct icmp_echo_hdr header; + } response; + + int rxSize = recvfrom(s, &response, sizeof(response), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen); + if (rxSize == -1) { + // time out + break; + } + + if (rxSize < sizeof(response)) { + // too short + continue; + } + + if (from.sin_family != AF_INET) { + // not IPv4 + continue; + } + + if ((response.header.id == request.header.id) && (response.header.seqno == request.header.seqno)) { + recvTime = millis(); + } + } while (recvTime == 0); + + close(s); + + if (recvTime == 0) { + return -1; + } else { + return (recvTime - sendTime); + } +} + +uint8_t WiFiClass::begin(const char* ssid) +{ + return begin(ssid, ""); +} + +uint8_t WiFiClass::begin(const char* ssid, uint8_t key_idx, const char* key) +{ + return begin(ssid, key); +} + +uint8_t WiFiClass::begin(const char* ssid, const char* key) +{ + wifi_config_t wifiConfig; + + memset(&wifiConfig, 0x00, sizeof(wifiConfig)); + strncpy((char*)wifiConfig.sta.ssid, ssid, sizeof(wifiConfig.sta.ssid)); + strncpy((char*)wifiConfig.sta.password, key, sizeof(wifiConfig.sta.password)); + _status = WL_NO_SSID_AVAIL; + + _interface = ESP_IF_WIFI_STA; + + esp_wifi_set_mode(WIFI_MODE_STA); + esp_wifi_start(); + xEventGroupWaitBits(_eventGroup, BIT0, false, true, portMAX_DELAY); + + if (esp_wifi_set_config(ESP_IF_WIFI_STA, &wifiConfig) != ESP_OK) { + _status = WL_CONNECT_FAILED; + } + + esp_wifi_connect(); + + return _status; +} + +uint8_t WiFiClass::beginAP(const char *ssid, uint8_t channel) +{ + wifi_config_t wifiConfig; + + memset(&wifiConfig, 0x00, sizeof(wifiConfig)); + strncpy((char*)wifiConfig.ap.ssid, ssid, sizeof(wifiConfig.sta.ssid)); + wifiConfig.ap.channel = 0; + wifiConfig.ap.authmode = WIFI_AUTH_OPEN; + wifiConfig.ap.max_connection = 4; + + _status = WL_NO_SSID_AVAIL; + + _interface = ESP_IF_WIFI_AP; + + esp_wifi_stop(); + esp_wifi_set_mode(WIFI_MODE_AP); + + if (esp_wifi_set_config(ESP_IF_WIFI_AP, &wifiConfig) != ESP_OK) { + _status = WL_AP_FAILED; + } + + esp_wifi_start(); + xEventGroupWaitBits(_eventGroup, BIT1, false, true, portMAX_DELAY); + + return _status; +} + +uint8_t WiFiClass::beginAP(const char *ssid, uint8_t key_idx, const char* key, uint8_t channel) +{ + wifi_config_t wifiConfig; + + memset(&wifiConfig, 0x00, sizeof(wifiConfig)); + strncpy((char*)wifiConfig.ap.ssid, ssid, sizeof(wifiConfig.sta.ssid)); + strncpy((char*)wifiConfig.ap.password, key, sizeof(wifiConfig.sta.password)); + wifiConfig.ap.channel = 0; + wifiConfig.ap.authmode = WIFI_AUTH_WEP; + wifiConfig.ap.max_connection = 4; + + _status = WL_NO_SSID_AVAIL; + + _interface = ESP_IF_WIFI_AP; + + esp_wifi_stop(); + esp_wifi_set_mode(WIFI_MODE_AP); + + if (esp_wifi_set_config(ESP_IF_WIFI_AP, &wifiConfig) != ESP_OK) { + _status = WL_AP_FAILED; + } + + esp_wifi_start(); + xEventGroupWaitBits(_eventGroup, BIT1, false, true, portMAX_DELAY); + + return _status; +} + +uint8_t WiFiClass::beginAP(const char *ssid, const char* key, uint8_t channel) +{ + wifi_config_t wifiConfig; + + memset(&wifiConfig, 0x00, sizeof(wifiConfig)); + strncpy((char*)wifiConfig.ap.ssid, ssid, sizeof(wifiConfig.sta.ssid)); + strncpy((char*)wifiConfig.ap.password, key, sizeof(wifiConfig.sta.password)); + wifiConfig.ap.channel = 0; + wifiConfig.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK; + wifiConfig.ap.max_connection = 4; + + _status = WL_NO_SSID_AVAIL; + + _interface = ESP_IF_WIFI_AP; + + esp_wifi_stop(); + esp_wifi_set_mode(WIFI_MODE_AP); + + if (esp_wifi_set_config(ESP_IF_WIFI_AP, &wifiConfig) != ESP_OK) { + _status = WL_AP_FAILED; + } + + esp_wifi_start(); + xEventGroupWaitBits(_eventGroup, BIT1, false, true, portMAX_DELAY); + + return _status; +} + +void WiFiClass::config(/*IPAddress*/uint32_t local_ip, /*IPAddress*/uint32_t gateway, /*IPAddress*/uint32_t subnet) +{ + dns_clear_servers(true); + + _ipInfo.ip.addr = local_ip; + _ipInfo.gw.addr = gateway; + _ipInfo.netmask.addr = subnet; + tcpip_adapter_set_ip_info(_interface == ESP_IF_WIFI_AP ? TCPIP_ADAPTER_IF_AP : TCPIP_ADAPTER_IF_STA, &_ipInfo); +} + +void WiFiClass::setDNS(/*IPAddress*/uint32_t dns_server1, /*IPAddress*/uint32_t dns_server2) +{ + ip_addr_t d; + d.type = IPADDR_TYPE_V4; + + if (dns_server1) { + d.u_addr.ip4.addr = static_cast(dns_server1); + dns_setserver(0, &d); + } + + if (dns_server2) { + d.u_addr.ip4.addr = static_cast(dns_server2); + dns_setserver(1, &d); + } +} + +void WiFiClass::hostname(const char* name) +{ + tcpip_adapter_set_hostname(_interface == ESP_IF_WIFI_AP ? TCPIP_ADAPTER_IF_AP : TCPIP_ADAPTER_IF_STA, name); +} + +void WiFiClass::disconnect() +{ + esp_wifi_disconnect(); + esp_wifi_stop(); +} + +void WiFiClass::end() +{ + esp_wifi_stop(); +} + +uint8_t* WiFiClass::macAddress(uint8_t* mac) +{ + uint8_t macTemp[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + esp_wifi_get_mac(_interface, macTemp); + + mac[0] = macTemp[5]; + mac[1] = macTemp[4]; + mac[2] = macTemp[3]; + mac[3] = macTemp[2]; + mac[4] = macTemp[1]; + mac[5] = macTemp[0]; + + return mac; +} + +uint32_t WiFiClass::localIP() +{ + return _ipInfo.ip.addr; +} + +uint32_t WiFiClass::subnetMask() +{ + return _ipInfo.netmask.addr; +} + +uint32_t WiFiClass::gatewayIP() +{ + return _ipInfo.gw.addr; +} + +char* WiFiClass::SSID() +{ + return (char*)_apRecord.ssid; +} + +int32_t WiFiClass::RSSI() +{ + if (_interface == ESP_IF_WIFI_AP) { + return 0; + } else { + esp_wifi_sta_get_ap_info(&_apRecord); + + return _apRecord.rssi; + } +} + +uint8_t WiFiClass::encryptionType() +{ + uint8_t encryptionType = _apRecord.authmode; + + if (encryptionType == WIFI_AUTH_OPEN) { + encryptionType = 7; + } else if (encryptionType == WIFI_AUTH_WEP) { + encryptionType = 5; + } else if (encryptionType == WIFI_AUTH_WPA_PSK) { + encryptionType = 2; + } else if (encryptionType == WIFI_AUTH_WPA2_PSK || encryptionType == WIFI_AUTH_WPA_WPA2_PSK) { + encryptionType = 4; + } else { + // unknown? + encryptionType = 255; + } + + return encryptionType; +} + +uint8_t* WiFiClass::BSSID(uint8_t* bssid) +{ + if (_interface == ESP_IF_WIFI_AP) { + return macAddress(bssid); + } else { + bssid[0] = _apRecord.bssid[5]; + bssid[1] = _apRecord.bssid[4]; + bssid[2] = _apRecord.bssid[3]; + bssid[3] = _apRecord.bssid[2]; + bssid[4] = _apRecord.bssid[1]; + bssid[5] = _apRecord.bssid[0]; + + return bssid; + } +} + +int8_t WiFiClass::scanNetworks() +{ + esp_wifi_set_mode(WIFI_MODE_STA); + esp_wifi_start(); + xEventGroupWaitBits(_eventGroup, BIT0, false, true, portMAX_DELAY); + + wifi_scan_config_t config; + + config.ssid = 0; + config.bssid = 0; + config.channel = 0; + config.show_hidden = false; + config.scan_type = WIFI_SCAN_TYPE_ACTIVE; + config.scan_time.active.min = 100; + config.scan_time.active.max = 300; + + xEventGroupClearBits(_eventGroup, BIT2); + + if (esp_wifi_scan_start(&config, false) != ESP_OK) { + _status = WL_NO_SSID_AVAIL; + return 0; + } + + xEventGroupWaitBits(_eventGroup, BIT2, false, true, portMAX_DELAY); + + uint16_t numNetworks; + esp_wifi_scan_get_ap_num(&numNetworks); + + if (numNetworks > MAX_SCAN_RESULTS) { + numNetworks = MAX_SCAN_RESULTS; + } + + esp_wifi_scan_get_ap_records(&numNetworks, _scanResults); + + _status = WL_SCAN_COMPLETED; + + return numNetworks; +} + +char* WiFiClass::SSID(uint8_t pos) +{ + return (char*)_scanResults[pos].ssid; +} + +int32_t WiFiClass::RSSI(uint8_t pos) +{ + return _scanResults[pos].rssi; +} + +uint8_t WiFiClass::encryptionType(uint8_t pos) +{ + uint8_t encryptionType = _scanResults[pos].authmode; + + if (encryptionType == WIFI_AUTH_OPEN) { + encryptionType = 7; + } else if (encryptionType == WIFI_AUTH_WEP) { + encryptionType = 5; + } else if (encryptionType == WIFI_AUTH_WPA_PSK) { + encryptionType = 2; + } else if (encryptionType == WIFI_AUTH_WPA2_PSK || encryptionType == WIFI_AUTH_WPA_WPA2_PSK) { + encryptionType = 4; + } else { + // unknown? + encryptionType = 255; + } + + return encryptionType; +} + +uint8_t* WiFiClass::BSSID(uint8_t pos, uint8_t* bssid) +{ + const uint8_t* tempBssid = _scanResults[pos].bssid; + + bssid[0] = tempBssid[5]; + bssid[1] = tempBssid[4]; + bssid[2] = tempBssid[3]; + bssid[3] = tempBssid[2]; + bssid[4] = tempBssid[1]; + bssid[5] = tempBssid[0]; + + return bssid; +} + +uint8_t WiFiClass::channel(uint8_t pos) +{ + return _scanResults[pos].primary; +} + +unsigned long WiFiClass::getTime() +{ + time_t now; + + time(&now); + + if (now < 946684800) { + return 0; + } + + return now; +} + +void WiFiClass::lowPowerMode() +{ + esp_wifi_set_ps(WIFI_PS_MODEM); +} + +void WiFiClass::noLowPowerMode() +{ + esp_wifi_set_ps(WIFI_PS_NONE); +} + +void WiFiClass::onReceive(void(*callback)(void)) +{ + _onReceiveCallback = callback; +} + +err_t WiFiClass::staNetifInputHandler(struct pbuf* p, struct netif* inp) +{ + return WiFi.handleStaNetifInput(p, inp); +} + +err_t WiFiClass::apNetifInputHandler(struct pbuf* p, struct netif* inp) +{ + return WiFi.handleApNetifInput(p, inp); +} + +err_t WiFiClass::handleStaNetifInput(struct pbuf* p, struct netif* inp) +{ + err_t result = _staNetifInput(p, inp); + + if (_onReceiveCallback) { + _onReceiveCallback(); + } + + return result; +} + +err_t WiFiClass::handleApNetifInput(struct pbuf* p, struct netif* inp) +{ + err_t result = _apNetifInput(p, inp); + + if (_onReceiveCallback) { + _onReceiveCallback(); + } + + return result; +} + +void WiFiClass::init() +{ + tcpip_adapter_init(); + esp_event_loop_init(WiFiClass::systemEventHandler, this); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + esp_wifi_init(&cfg); + esp_wifi_set_storage(WIFI_STORAGE_RAM); + + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, (char*)"0.pool.ntp.org"); + sntp_setservername(1, (char*)"1.pool.ntp.org"); + sntp_setservername(2, (char*)"2.pool.ntp.org"); + sntp_init(); + + _status = WL_IDLE_STATUS; +} + +esp_err_t WiFiClass::systemEventHandler(void* ctx, system_event_t* event) +{ + ((WiFiClass*)ctx)->handleSystemEvent(event); + + return ESP_OK; +} + +void WiFiClass::handleSystemEvent(system_event_t* event) +{ + switch (event->event_id) { + case SYSTEM_EVENT_SCAN_DONE: + xEventGroupSetBits(_eventGroup, BIT2); + break; + + case SYSTEM_EVENT_STA_START: { + struct netif* staNetif; + + if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, (void**)&staNetif) == ESP_OK) { + if (staNetif->input != WiFiClass::staNetifInputHandler) { + _staNetifInput = staNetif->input; + + staNetif->input = WiFiClass::staNetifInputHandler; + } + } + + xEventGroupSetBits(_eventGroup, BIT0); + break; + } + + case SYSTEM_EVENT_STA_STOP: + xEventGroupClearBits(_eventGroup, BIT0); + break; + + case SYSTEM_EVENT_STA_CONNECTED: + esp_wifi_sta_get_ap_info(&_apRecord); + break; + + case SYSTEM_EVENT_STA_GOT_IP: + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &_ipInfo); + _status = WL_CONNECTED; + break; + + case SYSTEM_EVENT_STA_DISCONNECTED: { + uint8_t reason = event->event_info.disconnected.reason; + + memset(&_apRecord, 0x00, sizeof(_apRecord)); + + if (reason == 201/*NO_AP_FOUND*/ || reason == 202/*AUTH_FAIL*/ || reason == 203/*ASSOC_FAIL*/) { + _status = WL_CONNECT_FAILED; + } else { + _status = WL_DISCONNECTED; + } + break; + } + + case SYSTEM_EVENT_STA_LOST_IP: + memset(&_ipInfo, 0x00, sizeof(_ipInfo)); + _status = WL_CONNECTION_LOST; + break; + + case SYSTEM_EVENT_AP_START: { + struct netif* apNetif; + + if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_AP, (void**)&apNetif) == ESP_OK) { + if (apNetif->input != WiFiClass::apNetifInputHandler) { + _apNetifInput = apNetif->input; + + apNetif->input = WiFiClass::apNetifInputHandler; + } + } + + wifi_config_t config; + + esp_wifi_get_config(ESP_IF_WIFI_AP, &config); + memcpy(_apRecord.ssid, config.ap.ssid, sizeof(config.ap.ssid)); + _apRecord.authmode = config.ap.authmode; + + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &_ipInfo); + _status = WL_AP_LISTENING; + xEventGroupSetBits(_eventGroup, BIT1); + break; + } + + case SYSTEM_EVENT_AP_STOP: + _status = WL_IDLE_STATUS; + memset(&_apRecord, 0x00, sizeof(_apRecord)); + memset(&_ipInfo, 0x00, sizeof(_ipInfo)); + xEventGroupClearBits(_eventGroup, BIT1); + break; + + case SYSTEM_EVENT_AP_STACONNECTED: + _status = WL_AP_CONNECTED; + break; + + case SYSTEM_EVENT_AP_STADISCONNECTED: + wifi_sta_list_t staList; + + esp_wifi_ap_get_sta_list(&staList); + + if (staList.num == 0) { + _status = WL_AP_LISTENING; + } + break; + + default: + break; + } +} + +WiFiClass WiFi; diff --git a/arduino/libraries/WiFi/src/WiFi.h b/arduino/libraries/WiFi/src/WiFi.h new file mode 100644 index 0000000..092ffd0 --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFi.h @@ -0,0 +1,129 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFI_H +#define WIFI_H + +#include + +#include +#include + +#include + +#include + +typedef enum { + WL_NO_SHIELD = 255, + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL, + WL_SCAN_COMPLETED, + WL_CONNECTED, + WL_CONNECT_FAILED, + WL_CONNECTION_LOST, + WL_DISCONNECTED, + WL_AP_LISTENING, + WL_AP_CONNECTED, + WL_AP_FAILED, +} wl_status_t; + +#define MAX_SCAN_RESULTS 10 + +class WiFiClass +{ +public: + WiFiClass(); + + uint8_t begin(const char* ssid); + uint8_t begin(const char* ssid, uint8_t key_idx, const char* key); + uint8_t begin(const char* ssid, const char* key); + + uint8_t beginAP(const char *ssid, uint8_t channel); + uint8_t beginAP(const char *ssid, uint8_t key_idx, const char* key, uint8_t channel); + uint8_t beginAP(const char *ssid, const char* key, uint8_t channel); + + + void config(/*IPAddress*/uint32_t local_ip, /*IPAddress*/uint32_t gateway, /*IPAddress*/uint32_t subnet); + + void setDNS(/*IPAddress*/uint32_t dns_server1, /*IPAddress*/uint32_t dns_server2); + + void hostname(const char* name); + + void disconnect(); + void end(); + + uint8_t* macAddress(uint8_t* mac); + + uint32_t localIP(); + uint32_t subnetMask(); + uint32_t gatewayIP(); + char* SSID(); + int32_t RSSI(); + uint8_t encryptionType(); + uint8_t* BSSID(uint8_t* bssid); + int8_t scanNetworks(); + char* SSID(uint8_t pos); + int32_t RSSI(uint8_t pos); + uint8_t encryptionType(uint8_t pos); + uint8_t* BSSID(uint8_t pos, uint8_t* bssid); + uint8_t channel(uint8_t pos); + + uint8_t status(); + + int hostByName(const char* hostname, /*IPAddress*/uint32_t& result); + + int ping(/*IPAddress*/uint32_t host, uint8_t ttl); + + unsigned long getTime(); + + void lowPowerMode(); + void noLowPowerMode(); + + void onReceive(void(*)(void)); + +private: + void init(); + + static esp_err_t systemEventHandler(void* ctx, system_event_t* event); + void handleSystemEvent(system_event_t* event); + + static err_t staNetifInputHandler(struct pbuf* p, struct netif* inp); + static err_t apNetifInputHandler(struct pbuf* p, struct netif* inp); + err_t handleStaNetifInput(struct pbuf* p, struct netif* inp); + err_t handleApNetifInput(struct pbuf* p, struct netif* inp); + +private: + bool _initialized; + volatile uint8_t _status; + EventGroupHandle_t _eventGroup; + esp_interface_t _interface; + + wifi_ap_record_t _scanResults[MAX_SCAN_RESULTS]; + wifi_ap_record_t _apRecord; + tcpip_adapter_ip_info_t _ipInfo; + + netif_input_fn _staNetifInput; + netif_input_fn _apNetifInput; + + void (*_onReceiveCallback)(void); +}; + +extern WiFiClass WiFi; + +#endif // WIFI_H diff --git a/arduino/libraries/WiFi/src/WiFiClient.cpp b/arduino/libraries/WiFi/src/WiFiClient.cpp new file mode 100644 index 0000000..9c96f02 --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFiClient.cpp @@ -0,0 +1,215 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include +#include + +#include "WiFiClient.h" + + +WiFiClient::WiFiClient() : + WiFiClient(-1) +{ +} + +WiFiClient::WiFiClient(int socket) : + _socket(socket) +{ +} + +int WiFiClient::connect(const char* host, uint16_t port) +{ + struct hostent* server = gethostbyname(host); + + if (server == NULL) { + return 0; + } + + return connect(server->h_addr, port); +} + +int WiFiClient::connect(/*IPAddress*/uint32_t ip, uint16_t port) +{ + _socket = lwip_socket(AF_INET, SOCK_STREAM, 0); + + if (_socket < 0) { + _socket = -1; + return 0; + } + + struct sockaddr_in addr; + memset(&addr, 0x00, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = (uint32_t)ip; + addr.sin_port = htons(port); + + if (lwip_connect_r(_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + lwip_close_r(_socket); + _socket = -1; + return 0; + } + + int nonBlocking = 1; + lwip_ioctl_r(_socket, FIONBIO, &nonBlocking); + + return 1; +} + +size_t WiFiClient::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiClient::write(const uint8_t *buf, size_t size) +{ + if (_socket == -1) { + return 0; + } + + int result = lwip_send_r(_socket, (void*)buf, size, MSG_DONTWAIT); + + if (result < 0) { + lwip_close_r(_socket); + _socket = -1; + return 0; + } + + return result; +} + +int WiFiClient::available() +{ + if (_socket == -1) { + return 0; + } + + int result = 0; + + if (lwip_ioctl_r(_socket, FIONREAD, &result) < 0) { + lwip_close_r(_socket); + _socket = -1; + return 0; + } + + return result; +} + +int WiFiClient::read() +{ + uint8_t b; + + if (read(&b, sizeof(b)) == -1) { + return -1; + } + + return b; +} + +int WiFiClient::read(uint8_t* buf, size_t size) +{ + if (!available()) { + return -1; + } + + int result = lwip_recv_r(_socket, buf, size, MSG_DONTWAIT); + + if (result <= 0 && errno != EWOULDBLOCK) { + lwip_close_r(_socket); + _socket = -1; + return 0; + } + + if (result == 0) { + result = -1; + } + + return result; +} + +int WiFiClient::peek() +{ + uint8_t b; + + if (recv(_socket, &b, sizeof(b), MSG_PEEK | MSG_DONTWAIT) <= 0) { + if (errno != EWOULDBLOCK) { + lwip_close_r(_socket); + _socket = -1; + } + + return -1; + } + + return b; +} + +void WiFiClient::flush() +{ +} + +void WiFiClient::stop() +{ + if (_socket != -1) { + lwip_close_r(_socket); + _socket = -1; + } +} + +uint8_t WiFiClient::connected() +{ + if (_socket != -1) { + // use peek to update socket state + peek(); + } + + return (_socket != -1); +} + +WiFiClient::operator bool() +{ + return (_socket != -1); +} + +bool WiFiClient::operator==(const WiFiClient &other) const +{ + return (_socket == other._socket); +} + +/*IPAddress*/uint32_t WiFiClient::remoteIP() +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + + getpeername(_socket, (struct sockaddr*)&addr, &len); + + return ((struct sockaddr_in *)&addr)->sin_addr.s_addr; +} + +uint16_t WiFiClient::remotePort() +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + + getpeername(_socket, (struct sockaddr*)&addr, &len); + + return ntohs(((struct sockaddr_in *)&addr)->sin_port); +} diff --git a/arduino/libraries/WiFi/src/WiFiClient.h b/arduino/libraries/WiFi/src/WiFiClient.h new file mode 100644 index 0000000..2c54e9a --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFiClient.h @@ -0,0 +1,64 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFICLIENT_H +#define WIFICLIENT_H + +#include +// #include +// #include + +class WiFiServer; + +class WiFiClient /*: public Client*/ { + +public: + WiFiClient(); + + uint8_t status(); + + virtual int connect(/*IPAddress*/uint32_t ip, uint16_t port); + virtual int connect(const char* host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + bool operator==(const WiFiClient &other) const; + + virtual /*IPAddress*/uint32_t remoteIP(); + virtual uint16_t remotePort(); + + // using Print::write; + +protected: + friend class WiFiServer; + + WiFiClient(int socket); + +private: + int _socket; +}; + +#endif // WIFICLIENT_H diff --git a/arduino/libraries/WiFi/src/WiFiSSLClient.cpp b/arduino/libraries/WiFi/src/WiFiSSLClient.cpp new file mode 100644 index 0000000..316cbf6 --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFiSSLClient.cpp @@ -0,0 +1,554 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include "WiFiSSLClient.h" + +class __Guard { +public: + __Guard(SemaphoreHandle_t handle) { + _handle = handle; + + xSemaphoreTakeRecursive(_handle, portMAX_DELAY); + } + + ~__Guard() { + xSemaphoreGiveRecursive(_handle); + } + +private: + SemaphoreHandle_t _handle; +}; + +#define synchronized __Guard __guard(_mbedMutex); + +WiFiSSLClient::WiFiSSLClient() : + _connected(false), + _peek(-1) +{ + _netContext.fd = -1; + + _mbedMutex = xSemaphoreCreateRecursiveMutex(); +} + +int WiFiSSLClient::connect(const char* host, uint16_t port) +{ + synchronized { + _netContext.fd = -1; + _connected = false; + + mbedtls_ssl_init(&_sslContext); + mbedtls_ctr_drbg_init(&_ctrDrbgContext); + mbedtls_ssl_config_init(&_sslConfig); + mbedtls_entropy_init(&_entropyContext); + mbedtls_x509_crt_init(&_caCrt); + mbedtls_net_init(&_netContext); + + if (mbedtls_ctr_drbg_seed(&_ctrDrbgContext, mbedtls_entropy_func, &_entropyContext, NULL, 0) != 0) { + stop(); + return 0; + } + + if (mbedtls_ssl_config_defaults(&_sslConfig, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) { + stop(); + return 0; + } + + mbedtls_ssl_conf_authmode(&_sslConfig, MBEDTLS_SSL_VERIFY_REQUIRED); + + if (mbedtls_x509_crt_parse(&_caCrt, (const unsigned char *)ROOT_CAs, strlen(ROOT_CAs) + 1) != 0) { + stop(); + return 0; + } + + mbedtls_ssl_conf_ca_chain(&_sslConfig, &_caCrt, NULL); + + mbedtls_ssl_conf_rng(&_sslConfig, mbedtls_ctr_drbg_random, &_ctrDrbgContext); + + if (mbedtls_ssl_setup(&_sslContext, &_sslConfig) != 0) { + stop(); + return 0; + } + + char portStr[6]; + itoa(port, portStr, 10); + + if (mbedtls_net_connect(&_netContext, host, portStr, MBEDTLS_NET_PROTO_TCP) != 0) { + stop(); + return 0; + } + + mbedtls_ssl_set_bio(&_sslContext, &_netContext, mbedtls_net_send, mbedtls_net_recv, NULL); + + int result; + + do { + result = mbedtls_ssl_handshake(&_sslContext); + } while (result == MBEDTLS_ERR_SSL_WANT_READ || result == MBEDTLS_ERR_SSL_WANT_WRITE); + + if (result != 0) { + stop(); + return 0; + } + + mbedtls_net_set_nonblock(&_netContext); + _connected = true; + + return 1; + } +} + +int WiFiSSLClient::connect(/*IPAddress*/uint32_t ip, uint16_t port) +{ + char ipStr[16]; + + sprintf(ipStr, "%d.%d.%d.%d", ((ip & 0xff000000) >> 24), ((ip & 0x00ff0000) >> 16), ((ip & 0x0000ff00) >> 8), ((ip & 0x000000ff) >> 0)/*ip[0], ip[1], ip[2], ip[3]*/); + + return connect(ipStr, port); +} + +size_t WiFiSSLClient::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiSSLClient::write(const uint8_t *buf, size_t size) +{ + synchronized { + int written = mbedtls_ssl_write(&_sslContext, buf, size); + + if (written < 0) { + written = 0; + } + + return written; + } +} + +int WiFiSSLClient::available() +{ + synchronized { + int result = mbedtls_ssl_read(&_sslContext, NULL, 0); + + int n = mbedtls_ssl_get_bytes_avail(&_sslContext); + + if (n == 0 && result != 0 && result != MBEDTLS_ERR_SSL_WANT_READ) { + stop(); + } + + return n; + } +} + +int WiFiSSLClient::read() +{ + uint8_t b; + + if (_peek != -1) { + b = _peek; + _peek = -1; + } else if (read(&b, sizeof(b)) == -1) { + return -1; + } + + return b; +} + +int WiFiSSLClient::read(uint8_t* buf, size_t size) +{ + synchronized { + if (!available()) { + return -1; + } + + int result = mbedtls_ssl_read(&_sslContext, buf, size); + + if (result < 0) { + if (result != MBEDTLS_ERR_SSL_WANT_READ && result != MBEDTLS_ERR_SSL_WANT_WRITE) { + stop(); + } + + return -1; + } + + return result; + } +} + +int WiFiSSLClient::peek() +{ + if (_peek == -1) { + _peek = read(); + } + + return _peek; +} + +void WiFiSSLClient::flush() +{ +} + +void WiFiSSLClient::stop() +{ + synchronized { + if (_netContext.fd > 0) { + mbedtls_ssl_session_reset(&_sslContext); + + mbedtls_net_free(&_netContext); + mbedtls_x509_crt_free(&_caCrt); + mbedtls_entropy_free(&_entropyContext); + mbedtls_ssl_config_free(&_sslConfig); + mbedtls_ctr_drbg_free(&_ctrDrbgContext); + mbedtls_ssl_free(&_sslContext); + } + + _connected = false; + _netContext.fd = -1; + } +} + +uint8_t WiFiSSLClient::connected() +{ + synchronized { + if (!_connected) { + return 0; + } + + if (available()) { + return 1; + } + + return 1; + } +} + +WiFiSSLClient::operator bool() +{ + return ((_netContext.fd != -1) && _connected); +} + +/*IPAddress*/uint32_t WiFiSSLClient::remoteIP() +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + + getpeername(_netContext.fd, (struct sockaddr*)&addr, &len); + + return ((struct sockaddr_in *)&addr)->sin_addr.s_addr; +} + +uint16_t WiFiSSLClient::remotePort() +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + + getpeername(_netContext.fd, (struct sockaddr*)&addr, &len); + + return ntohs(((struct sockaddr_in *)&addr)->sin_port); +} + +const char* WiFiSSLClient::ROOT_CAs = +"-----BEGIN CERTIFICATE-----\n" +"MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU\n" +"MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs\n" +"IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290\n" +"MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux\n" +"FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h\n" +"bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v\n" +"dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt\n" +"H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9\n" +"uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX\n" +"mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX\n" +"a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN\n" +"E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0\n" +"WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD\n" +"VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0\n" +"Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU\n" +"cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx\n" +"IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN\n" +"AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH\n" +"YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5\n" +"6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC\n" +"Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX\n" +"c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a\n" +"mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n" +"RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\n" +"VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\n" +"DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\n" +"ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\n" +"VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\n" +"mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\n" +"IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\n" +"mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\n" +"XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\n" +"dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\n" +"jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\n" +"BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\n" +"DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n" +"9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" +"jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\n" +"Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n" +"ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n" +"R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB\n" +"hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n" +"A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV\n" +"BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5\n" +"MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT\n" +"EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\n" +"Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh\n" +"dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR\n" +"6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X\n" +"pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC\n" +"9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV\n" +"/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf\n" +"Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z\n" +"+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w\n" +"qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah\n" +"SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC\n" +"u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf\n" +"Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq\n" +"crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\n" +"FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB\n" +"/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl\n" +"wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM\n" +"4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV\n" +"2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna\n" +"FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ\n" +"CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK\n" +"boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke\n" +"jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL\n" +"S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb\n" +"QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl\n" +"0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB\n" +"NVOFBkpdn627G190\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n" +"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" +"DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n" +"PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n" +"Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" +"AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n" +"rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n" +"OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n" +"xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n" +"7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n" +"aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" +"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n" +"SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n" +"ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n" +"AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n" +"R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n" +"JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n" +"Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n" +"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" +"d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" +"ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n" +"MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" +"LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n" +"RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n" +"+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n" +"PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n" +"xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n" +"Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n" +"hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n" +"EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n" +"MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n" +"FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n" +"nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n" +"eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n" +"hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n" +"Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" +"vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n" +"+OkuE6N36B9K\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC\n" +"VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0\n" +"Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW\n" +"KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl\n" +"cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw\n" +"NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw\n" +"NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy\n" +"ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV\n" +"BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ\n" +"KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo\n" +"Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4\n" +"4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9\n" +"KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI\n" +"rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi\n" +"94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB\n" +"sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi\n" +"gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo\n" +"kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE\n" +"vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\n" +"A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t\n" +"O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua\n" +"AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP\n" +"9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/\n" +"eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m\n" +"0vdXcDazv/wor3ElhVsT/h5/WrQ8\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV\n" +"UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy\n" +"dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1\n" +"MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx\n" +"dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B\n" +"AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f\n" +"BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A\n" +"cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC\n" +"AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ\n" +"MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm\n" +"aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw\n" +"ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj\n" +"IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF\n" +"MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA\n" +"A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n" +"7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh\n" +"1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n" +"MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\n" +"YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG\n" +"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg\n" +"R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9\n" +"9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq\n" +"fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv\n" +"iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU\n" +"1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\n" +"bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW\n" +"MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA\n" +"ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l\n" +"uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn\n" +"Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS\n" +"tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" +"PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un\n" +"hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV\n" +"5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB\n" +"mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT\n" +"MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s\n" +"eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" +"cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ\n" +"BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg\n" +"MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0\n" +"BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg\n" +"LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz\n" +"+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm\n" +"hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn\n" +"5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W\n" +"JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL\n" +"DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC\n" +"huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\n" +"HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB\n" +"AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB\n" +"zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN\n" +"kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD\n" +"AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH\n" +"SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G\n" +"spki4cErx5z481+oghLrGREt\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G\n" +"A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp\n" +"Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1\n" +"MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG\n" +"A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n" +"hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL\n" +"v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8\n" +"eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq\n" +"tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n" +"C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa\n" +"zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB\n" +"mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH\n" +"V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n\n" +"bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG\n" +"3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs\n" +"J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO\n" +"291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS\n" +"ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n" +"AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\n" +"TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx\n" +"EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT\n" +"EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp\n" +"ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz\n" +"NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH\n" +"EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE\n" +"AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw\n" +"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD\n" +"E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH\n" +"/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy\n" +"DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh\n" +"GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR\n" +"tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA\n" +"AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\n" +"FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX\n" +"WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu\n" +"9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr\n" +"gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo\n" +"2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\n" +"LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI\n" +"4uJEvlz36hz1\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\n" +"yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n" +"ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\n" +"U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\n" +"ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\n" +"aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\n" +"MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\n" +"ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\n" +"biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\n" +"U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" +"aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\n" +"nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\n" +"t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\n" +"SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\n" +"BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\n" +"rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\n" +"NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\n" +"BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\n" +"BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\n" +"aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\n" +"MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\n" +"p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\n" +"5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\n" +"WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\n" +"4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\n" +"hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n" +"-----END CERTIFICATE-----\n"; diff --git a/arduino/libraries/WiFi/src/WiFiSSLClient.h b/arduino/libraries/WiFi/src/WiFiSSLClient.h new file mode 100644 index 0000000..eb21263 --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFiSSLClient.h @@ -0,0 +1,73 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFISSLCLIENT_H +#define WIFISSLCLIENT_H + +#include +#include +#include +#include +#include + +#include +// #include +// #include + +class WiFiSSLClient /*: public Client*/ { + +public: + WiFiSSLClient(); + + uint8_t status(); + + virtual int connect(/*IPAddress*/uint32_t ip, uint16_t port); + virtual int connect(const char* host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + + // using Print::write; + + virtual /*IPAddress*/uint32_t remoteIP(); + virtual uint16_t remotePort(); + +private: + static const char* ROOT_CAs; + + mbedtls_entropy_context _entropyContext; + mbedtls_ctr_drbg_context _ctrDrbgContext; + mbedtls_ssl_context _sslContext; + mbedtls_ssl_config _sslConfig; + mbedtls_net_context _netContext; + mbedtls_x509_crt _caCrt; + bool _connected; + int _peek; + + SemaphoreHandle_t _mbedMutex; +}; + +#endif /* WIFISSLCLIENT_H */ diff --git a/arduino/libraries/WiFi/src/WiFiServer.cpp b/arduino/libraries/WiFi/src/WiFiServer.cpp new file mode 100644 index 0000000..687174e --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFiServer.cpp @@ -0,0 +1,142 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include + +#include "WiFiClient.h" +#include "WiFiServer.h" + +WiFiServer::WiFiServer() : + WiFiServer(0) +{ +} + +WiFiServer::WiFiServer(uint16_t port) : + _port(port), + _socket(-1) +{ + for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { + _spawnedSockets[i] = -1; + } +} + +void WiFiServer::begin() +{ + _socket = lwip_socket(AF_INET, SOCK_STREAM, 0); + + if (_socket < 0) { + return; + } + + struct sockaddr_in addr; + memset(&addr, 0x00, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = (uint32_t)0; + addr.sin_port = htons(_port); + + if (lwip_bind(_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + lwip_close_r(_socket); + _socket = -1; + return; + } + + if (lwip_listen(_socket, 1) < 0) { + lwip_close_r(_socket); + _socket = -1; + return; + } + + int nonBlocking = 1; + lwip_ioctl_r(_socket, FIONBIO, &nonBlocking); + + return; +} + +WiFiClient WiFiServer::available(uint8_t* status) +{ + int result = lwip_accept(_socket, NULL, 0); + + if (status) { + *status = (result != -1); + } + + if (result != -1) { + // store the connected socket + for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { + if (_spawnedSockets[i] == -1) { + _spawnedSockets[i] = result; + break; + } + } + } + + result = -1; + + // find an existing socket with data + for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { + if (_spawnedSockets[i] != -1) { + WiFiClient c(_spawnedSockets[i]); + + if (!c.connected()) { + // socket not connected, clear from book keeping + _spawnedSockets[i] = -1; + } else if (c.available()) { + result = _spawnedSockets[i]; + + break; + } + } + } + + return WiFiClient(result); +} + +uint8_t WiFiServer::status() { + // Deprecated. + return 0; +} + +size_t WiFiServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiServer::write(const uint8_t *buffer, size_t size) +{ + size_t written = 0; + + for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { + if (_spawnedSockets[i] != -1) { + WiFiClient c(_spawnedSockets[i]); + + written += c.write(buffer, size); + } + } + + return written; +} + +WiFiServer::operator bool() +{ + return (_port != 0 && _socket != -1); +} diff --git a/arduino/libraries/WiFi/src/WiFiServer.h b/arduino/libraries/WiFi/src/WiFiServer.h new file mode 100644 index 0000000..3bd759e --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFiServer.h @@ -0,0 +1,50 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFISERVER_H +#define WIFISERVER_H + +#include + +#include +// #include + +class WiFiClient; + +class WiFiServer /*: public Server*/ { +public: + WiFiServer(); + WiFiServer(uint16_t); + WiFiClient available(uint8_t* status = NULL); + void begin(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + uint8_t status(); + + // using Print::write; + + virtual operator bool(); + +private: + uint16_t _port; + int _socket; + int _spawnedSockets[CONFIG_LWIP_MAX_SOCKETS]; +}; + +#endif // WIFISERVER_H diff --git a/arduino/libraries/WiFi/src/WiFiUdp.cpp b/arduino/libraries/WiFi/src/WiFiUdp.cpp new file mode 100644 index 0000000..641c0bb --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFiUdp.cpp @@ -0,0 +1,218 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include +#include + +#include "WiFiUdp.h" + +WiFiUDP::WiFiUDP() : + _socket(-1), + _remoteIp(0), + _remotePort(0), + _rcvIndex(0), + _rcvSize(0), + _sndSize(0) +{ +} + +uint8_t WiFiUDP::begin(uint16_t port) +{ + _socket = lwip_socket(AF_INET, SOCK_DGRAM, 0); + + if (_socket < 0) { + return 0; + } + + struct sockaddr_in addr; + memset(&addr, 0x00, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = (uint32_t)0; + addr.sin_port = htons(port); + + if (lwip_bind(_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + lwip_close_r(_socket); + _socket = -1; + return 0; + } + + int nonBlocking = 1; + lwip_ioctl_r(_socket, FIONBIO, &nonBlocking); + + return 1; +} + +uint8_t WiFiUDP::beginMulticast(/*IPAddress*/uint32_t ip, uint16_t port) +{ + if (!begin(port)) { + return 0; + } + + struct ip_mreq multi; + + multi.imr_multiaddr.s_addr = (uint32_t)ip; + multi.imr_interface.s_addr = (uint32_t)0; + + lwip_setsockopt_r(_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multi, sizeof(multi)); + + return 1; +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int WiFiUDP::available() +{ + return (_rcvSize - _rcvIndex); +} + +/* Release any resources being used by this WiFiUDP instance */ +void WiFiUDP::stop() +{ + lwip_close_r(_socket); + _socket = -1; +} + +int WiFiUDP::beginPacket(const char *host, uint16_t port) +{ + struct hostent* server = gethostbyname(host); + + if (server == NULL) { + return 0; + } + + return beginPacket(server->h_addr, port); +} + +int WiFiUDP::beginPacket(/*IPAddress*/uint32_t ip, uint16_t port) +{ + _remoteIp = ip; + _remotePort = port; + + _sndSize = 0; + + return 1; +} + +int WiFiUDP::endPacket() +{ + struct sockaddr_in addr; + memset(&addr, 0x00, sizeof(addr)); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = _remoteIp; + addr.sin_port = htons(_remotePort); + + if (lwip_sendto(_socket, _sndBuffer, _sndSize, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + return 0; + } + + return 1; +} + +size_t WiFiUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t WiFiUDP::write(const uint8_t *buffer, size_t size) +{ + size_t written = size; + + if ((_sndSize + size) > sizeof(_sndBuffer)) { + written = sizeof(_sndBuffer) - _sndSize; + } + + memcpy(&_sndBuffer[_sndSize], buffer, size); + + _sndSize += written; + + return written; +} + +int WiFiUDP::parsePacket() +{ + struct sockaddr_in addr; + socklen_t addrLen = sizeof(addr); + + _rcvIndex = 0; + _rcvSize = 0; + + int result = lwip_recvfrom_r(_socket, _rcvBuffer, sizeof(_rcvBuffer), MSG_DONTWAIT, (struct sockaddr*)&addr, &addrLen); + + if (result <= 0) { + return 0; + } + + _rcvSize = result; + _remoteIp = addr.sin_addr.s_addr; + _remotePort = ntohs(addr.sin_port); + + return result; +} + +int WiFiUDP::read() +{ + uint8_t b; + + if (read(&b, sizeof(b)) < 1) { + return -1; + } + + return b; +} + +int WiFiUDP::read(unsigned char* buf, size_t size) +{ + if (available() < (int)size) { + size = available(); + } + + memcpy(buf, &_rcvBuffer[_rcvIndex], size); + + _rcvIndex += size; + + return size; +} + +int WiFiUDP::peek() +{ + if (!available()) { + return -1; + } + + return _rcvBuffer[_rcvIndex]; +} + +void WiFiUDP::flush() +{ +} + +/*IPAddress*/uint32_t WiFiUDP::remoteIP() +{ + return _remoteIp; +} + +uint16_t WiFiUDP::remotePort() +{ + return _remotePort; +} diff --git a/arduino/libraries/WiFi/src/WiFiUdp.h b/arduino/libraries/WiFi/src/WiFiUdp.h new file mode 100644 index 0000000..e61864b --- /dev/null +++ b/arduino/libraries/WiFi/src/WiFiUdp.h @@ -0,0 +1,66 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFIUDP_H +#define WIFIUDP_H + +// #include + +class WiFiUDP /*: public UDP*/ { + +public: + WiFiUDP(); + virtual uint8_t begin(uint16_t); + virtual uint8_t beginMulticast(/*IPAddress*/uint32_t, uint16_t); + virtual void stop(); + + virtual int beginPacket(/*IPAddress*/uint32_t ip, uint16_t port); + virtual int beginPacket(const char *host, uint16_t port); + virtual int endPacket(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buffer, size_t size); + + // using Print::write; + + virtual int parsePacket(); + virtual int available(); + virtual int read(); + virtual int read(unsigned char* buffer, size_t len); + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + virtual int peek(); + virtual void flush(); + + virtual /*IPAddress*/ uint32_t remoteIP(); + virtual uint16_t remotePort(); + + virtual operator bool() { return _socket != -1; } + +private: + int _socket; + uint32_t _remoteIp; + uint16_t _remotePort; + + uint8_t _rcvBuffer[1500]; + uint16_t _rcvIndex; + uint16_t _rcvSize; + uint8_t _sndBuffer[1500]; + uint16_t _sndSize; +}; + +#endif // WIFIUDP_H diff --git a/main/CommandHandler.cpp b/main/CommandHandler.cpp new file mode 100644 index 0000000..1ddc47a --- /dev/null +++ b/main/CommandHandler.cpp @@ -0,0 +1,1104 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include + +#include "CommandHandler.h" + +const char FIRMWARE_VERSION[6] = "1.0.0"; + +/*IPAddress*/uint32_t resolvedHostname; + +#define MAX_SOCKETS CONFIG_LWIP_MAX_SOCKETS +uint8_t socketTypes[MAX_SOCKETS]; +WiFiClient tcpClients[MAX_SOCKETS]; +WiFiUDP udps[MAX_SOCKETS]; +WiFiSSLClient tlsClients[MAX_SOCKETS]; +WiFiServer tcpServers[MAX_SOCKETS]; + + +int setNet(const uint8_t command[], uint8_t response[]) +{ + char ssid[32 + 1]; + + memset(ssid, 0x00, sizeof(ssid)); + memcpy(ssid, &command[4], command[3]); + + WiFi.begin(ssid); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int setPassPhrase(const uint8_t command[], uint8_t response[]) +{ + char ssid[32 + 1]; + char pass[64 + 1]; + + memset(ssid, 0x00, sizeof(ssid)); + memset(pass, 0x00, sizeof(pass)); + + memcpy(ssid, &command[4], command[3]); + memcpy(pass, &command[5 + command[3]], command[4 + command[3]]); + + WiFi.begin(ssid, pass); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int setKey(const uint8_t command[], uint8_t response[]) +{ + char ssid[32 + 1]; + char key[26 + 1]; + + memset(ssid, 0x00, sizeof(ssid)); + memset(key, 0x00, sizeof(key)); + + memcpy(ssid, &command[4], command[3]); + memcpy(key, &command[7 + command[3]], command[6 + command[3]]); + + WiFi.begin(ssid, key); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int setIPconfig(const uint8_t command[], uint8_t response[]) +{ + uint32_t ip; + uint32_t gwip; + uint32_t mask; + + memcpy(&ip, &command[6], sizeof(ip)); + memcpy(&gwip, &command[11], sizeof(gwip)); + memcpy(&mask, &command[16], sizeof(mask)); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + WiFi.config(ip, gwip, mask); + + return 6; +} + +int setDNSconfig(const uint8_t command[], uint8_t response[]) +{ + uint32_t dns1; + uint32_t dns2; + + memcpy(&dns1, &command[6], sizeof(dns1)); + memcpy(&dns2, &command[11], sizeof(dns2)); + + WiFi.setDNS(dns1, dns2); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int setHostname(const uint8_t command[], uint8_t response[]) +{ + char hostname[255 + 1]; + + memset(hostname, 0x00, sizeof(hostname)); + memcpy(hostname, &command[4], command[3]); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + WiFi.hostname(hostname); + + return 6; +} + +int setPowerMode(const uint8_t command[], uint8_t response[]) +{ + if (command[4]) { + // low power + WiFi.lowPowerMode(); + } else { + // no low power + WiFi.noLowPowerMode(); + } + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int setApNet(const uint8_t command[], uint8_t response[]) +{ + char ssid[32 + 1]; + uint8_t channel; + + memset(ssid, 0x00, sizeof(ssid)); + memcpy(ssid, &command[4], command[3]); + + channel = command[5 + command[3]]; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + if (WiFi.beginAP(ssid, channel) != WL_AP_FAILED) { + response[4] = 1; + } else { + response[4] = 0; + } + + return 6; +} + +int setApPassPhrase(const uint8_t command[], uint8_t response[]) +{ + char ssid[32 + 1]; + char pass[64 + 1]; + uint8_t channel; + + memset(ssid, 0x00, sizeof(ssid)); + memset(pass, 0x00, sizeof(pass)); + + memcpy(ssid, &command[4], command[3]); + memcpy(pass, &command[5 + command[3]], command[4 + command[3]]); + channel = command[6 + command[3] + command[4 + command[3]]]; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + if (WiFi.beginAP(ssid, pass, channel) != WL_AP_FAILED) { + response[4] = 1; + } else { + response[4] = 0; + } + + return 6; +} + +extern void setDebug(int debug); + +int setDebug(const uint8_t command[], uint8_t response[]) +{ + setDebug(command[4]); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +extern "C" { + uint8_t temprature_sens_read(); +} + +int getTemperature(const uint8_t command[], uint8_t response[]) +{ + float temperature = (temprature_sens_read() - 32) / 1.8; + + response[2] = 1; // number of parameters + response[3] = sizeof(temperature); // parameter 1 length + + memcpy(&response[4], &temperature, sizeof(temperature)); + + return 9; +} + +int getConnStatus(const uint8_t command[], uint8_t response[]) +{ + uint8_t status = WiFi.status(); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = status; + + return 6; +} + +int getIPaddr(const uint8_t command[], uint8_t response[]) +{ + /*IPAddress*/uint32_t ip = WiFi.localIP(); + /*IPAddress*/uint32_t mask = WiFi.subnetMask(); + /*IPAddress*/uint32_t gwip = WiFi.gatewayIP(); + + response[2] = 3; // number of parameters + + response[3] = 4; // parameter 1 length + memcpy(&response[4], &ip, sizeof(ip)); + + response[8] = 4; // parameter 2 length + memcpy(&response[9], &mask, sizeof(mask)); + + response[13] = 4; // parameter 3 length + memcpy(&response[14], &gwip, sizeof(gwip)); + + return 19; +} + +int getMACaddr(const uint8_t command[], uint8_t response[]) +{ + uint8_t mac[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + WiFi.macAddress(mac); + + response[2] = 1; // number of parameters + response[3] = sizeof(mac); // parameter 1 length + + memcpy(&response[4], mac, sizeof(mac)); + + return 11; +} + +int getCurrSSID(const uint8_t command[], uint8_t response[]) +{ + // ssid + const char* ssid = WiFi.SSID(); + uint8_t ssidLen = strlen(ssid); + + response[2] = 1; // number of parameters + response[3] = ssidLen; // parameter 1 length + + memcpy(&response[4], ssid, ssidLen); + + return (5 + ssidLen); +} + +int getCurrBSSID(const uint8_t command[], uint8_t response[]) +{ + uint8_t bssid[6]; + + WiFi.BSSID(bssid); + + response[2] = 1; // number of parameters + response[3] = 6; // parameter 1 length + + memcpy(&response[4], bssid, sizeof(bssid)); + + return 11; +} + +int getCurrRSSI(const uint8_t command[], uint8_t response[]) +{ + int32_t rssi = WiFi.RSSI(); + + response[2] = 1; // number of parameters + response[3] = sizeof(rssi); // parameter 1 length + + memcpy(&response[4], &rssi, sizeof(rssi)); + + return 9; +} + +int getCurrEnct(const uint8_t command[], uint8_t response[]) +{ + uint8_t encryptionType = WiFi.encryptionType(); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = encryptionType; + + return 6; +} + +int scanNetworks(const uint8_t command[], uint8_t response[]) +{ + int num = WiFi.scanNetworks(); + int responseLength = 3; + + response[2] = num; + + for (int i = 0; i < num; i++) { + const char* ssid = WiFi.SSID(i); + int ssidLen = strlen(ssid); + + response[responseLength++] = ssidLen; + + memcpy(&response[responseLength], ssid, ssidLen); + responseLength += ssidLen; + } + + return (responseLength + 1); +} + +int startServerTcp(const uint8_t command[], uint8_t response[]) +{ + uint32_t ip = 0; + uint16_t port; + uint8_t socket; + uint8_t type; + + if (command[2] == 3) { + memcpy(&port, &command[4], sizeof(port)); + port = ntohs(port); + socket = command[7]; + type = command[9]; + } else { + memcpy(&ip, &command[4], sizeof(ip)); + memcpy(&port, &command[9], sizeof(port)); + port = ntohs(port); + socket = command[12]; + type = command[14]; + } + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + if (type == 0x00) { + tcpServers[socket] = WiFiServer(port); + + tcpServers[socket].begin(); + + socketTypes[socket] = 0x00; + response[4] = 1; + } else if (type == 0x01 && udps[socket].begin(port)) { + socketTypes[socket] = 0x01; + response[4] = 1; + } else if (type == 0x03 && udps[socket].beginMulticast(ip, port)) { + socketTypes[socket] = 0x01; + response[4] = 1; + } else { + response[4] = 0; + } + + return 6; +} + +int getStateTcp(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket = command[4]; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + if (tcpServers[socket]) { + response[4] = 1; + } else { + response[4] = 0; + } + + return 6; +} + +int dataSentTcp(const uint8_t command[], uint8_t response[]) +{ + // -> no op as write does the work + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int availDataTcp(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket = command[4]; + uint16_t available = 0; + + if (socketTypes[socket] == 0x00) { + if (tcpServers[socket]) { + WiFiClient client = tcpServers[socket].available(); + + available = 255; + + if (client) { + // try to find existing socket slot + for (int i = 0; i < MAX_SOCKETS; i++) { + if (i == socket) { + continue; // skip this slot + } + + if (socketTypes[i] == 0x00 && tcpClients[i] == client) { + available = i; + break; + } + } + + if (available == 255) { + // book keep new slot + + for (int i = 0; i < MAX_SOCKETS; i++) { + if (i == socket) { + continue; // skip this slot + } + + if (socketTypes[i] == 255) { + socketTypes[i] = 0x00; + tcpClients[i] = client; + + available = i; + break; + } + } + } + } + } else { + available = tcpClients[socket].available(); + } + } else if (socketTypes[socket] == 0x01) { + available = udps[socket].available(); + + if (available <= 0) { + available = udps[socket].parsePacket(); + } + } else if (socketTypes[socket] == 0x02) { + available = tlsClients[socket].available(); + } + + response[2] = 1; // number of parameters + response[3] = sizeof(available); // parameter 1 length + + memcpy(&response[4], &available, sizeof(available)); + + return 7; +} + +int getDataTcp(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket = command[4]; + uint8_t peek = command[6]; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + if (socketTypes[socket] == 0x00) { + if (peek) { + response[4] = tcpClients[socket].peek(); + } else { + response[4] = tcpClients[socket].read(); + } + } else if (socketTypes[socket] == 0x01) { + if (peek) { + response[4] = udps[socket].peek(); + } else { + response[4] = udps[socket].read(); + } + } else if (socketTypes[socket] == 0x02) { + if (peek) { + response[4] = tlsClients[socket].peek(); + } else { + response[4] = tlsClients[socket].read(); + } + } + + return 6; +} + +int startClientTcp(const uint8_t command[], uint8_t response[]) +{ + char host[255 + 1]; + uint32_t ip; + uint16_t port; + uint8_t socket; + uint8_t type; + + memset(host, 0x00, sizeof(host)); + + if (command[2] == 4) { + memcpy(&ip, &command[4], sizeof(ip)); + memcpy(&port, &command[9], sizeof(port)); + port = ntohs(port); + socket = command[12]; + type = command[14]; + } else { + memcpy(host, &command[4], command[3]); + memcpy(&ip, &command[5 + command[3]], sizeof(ip)); + memcpy(&port, &command[10 + command[3]], sizeof(port)); + port = ntohs(port); + socket = command[13 + command[3]]; + type = command[15 + command[3]]; + } + + if (type == 0x00) { + int result; + + if (host[0] != '\0') { + result = tcpClients[socket].connect(host, port); + } else { + result = tcpClients[socket].connect(ip, port); + } + + if (result) { + socketTypes[socket] = 0x00; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; + } else { + response[2] = 0; // number of parameters + + return 4; + } + } else if (type == 0x01) { + int result; + + if (host[0] != '\0') { + result = udps[socket].beginPacket(host, port); + } else { + result = udps[socket].beginPacket(ip, port); + } + + if (result) { + socketTypes[socket] = 0x01; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; + } else { + response[2] = 0; // number of parameters + + return 4; + } + } else if (type == 0x02) { + int result; + + if (host[0] != '\0') { + result = tlsClients[socket].connect(host, port); + } else { + result = tlsClients[socket].connect(ip, port); + } + + if (result) { + socketTypes[socket] = 0x02; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; + } else { + response[2] = 0; // number of parameters + + return 4; + } + } else { + response[2] = 0; // number of parameters + + return 4; + } +} + +int stopClientTcp(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket = command[4]; + + if (socketTypes[socket] == 0x00) { + tcpClients[socket].stop(); + + socketTypes[socket] = 255; + } else if (socketTypes[socket] == 0x01) { + udps[socket].stop(); + + socketTypes[socket] = 255; + } else if (socketTypes[socket] == 0x02) { + tlsClients[socket].stop(); + + socketTypes[socket] = 255; + } + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int getClientStateTcp(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket = command[4]; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + if ((socketTypes[socket] == 0x00) && tcpClients[socket].connected()) { + response[4] = 4; + } else if ((socketTypes[socket] == 0x02) && tlsClients[socket].connected()) { + response[4] = 4; + } else { + socketTypes[socket] = 255; + response[4] = 0; + } + + return 6; +} + +int disconnect(const uint8_t command[], uint8_t response[]) +{ + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + WiFi.disconnect(); + + return 6; +} + +int getIdxRSSI(const uint8_t command[], uint8_t response[]) +{ + // RSSI + int32_t rssi = WiFi.RSSI(command[4]); + + response[2] = 1; // number of parameters + response[3] = sizeof(rssi); // parameter 1 length + + memcpy(&response[4], &rssi, sizeof(rssi)); + + return 9; +} + +int getIdxEnct(const uint8_t command[], uint8_t response[]) +{ + uint8_t encryptionType = WiFi.encryptionType(command[4]); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = encryptionType; + + return 6; +} + +int reqHostByName(const uint8_t command[], uint8_t response[]) +{ + char host[255 + 1]; + + memset(host, 0x00, sizeof(host)); + memcpy(host, &command[4], command[3]); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + resolvedHostname = /*IPAddress(255, 255, 255, 255)*/0xffffffff; + if (WiFi.hostByName(host, resolvedHostname)) { + response[4] = 1; + } else { + response[4] = 0; + } + + return 6; +} + +int getHostByName(const uint8_t command[], uint8_t response[]) +{ + response[2] = 1; // number of parameters + response[3] = 4; // parameter 1 length + memcpy(&response[4], &resolvedHostname, sizeof(resolvedHostname)); + + return 9; +} + +int startScanNetworks(const uint8_t command[], uint8_t response[]) +{ + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int getFwVersion(const uint8_t command[], uint8_t response[]) +{ + response[2] = 1; // number of parameters + response[3] = sizeof(FIRMWARE_VERSION); // parameter 1 length + + memcpy(&response[4], FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION)); + + return 11; +} + +int sendUDPdata(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket = command[4]; + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + if (udps[socket].endPacket()) { + response[4] = 1; + } else { + response[4] = 0; + } + + return 6; +} + +int getRemoteData(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket = command[4]; + + /*IPAddress*/uint32_t ip = /*IPAddress(0, 0, 0, 0)*/0; + uint16_t port = 0; + + if (socketTypes[socket] == 0x00) { + ip = tcpClients[socket].remoteIP(); + port = tcpClients[socket].remotePort(); + } else if (socketTypes[socket] == 0x01) { + ip = udps[socket].remoteIP(); + port = udps[socket].remotePort(); + } else if (socketTypes[socket] == 0x02) { + ip = tlsClients[socket].remoteIP(); + port = tlsClients[socket].remotePort(); + } + + response[2] = 2; // number of parameters + + response[3] = 4; // parameter 1 length + memcpy(&response[4], &ip, sizeof(ip)); + + response[8] = 2; // parameter 2 length + response[9] = (port >> 8) & 0xff; + response[10] = (port >> 0) & 0xff; + + return 12; +} + +int getTime(const uint8_t command[], uint8_t response[]) +{ + unsigned long now = WiFi.getTime(); + + response[2] = 1; // number of parameters + response[3] = sizeof(now); // parameter 1 length + + memcpy(&response[4], &now, sizeof(now)); + + return 5 + sizeof(now); +} + +int getIdxBSSID(const uint8_t command[], uint8_t response[]) +{ + uint8_t bssid[6]; + + WiFi.BSSID(command[4], bssid); + + response[2] = 1; // number of parameters + response[3] = 6; // parameter 1 length + memcpy(&response[4], bssid, sizeof(bssid)); + + return 11; +} + +int getIdxChannel(const uint8_t command[], uint8_t response[]) +{ + uint8_t channel = WiFi.channel(command[4]); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = channel; + + return 6; +} + +int sendDataTcp(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket; + uint16_t length; + uint16_t written = 0; + + socket = command[5]; + memcpy(&length, &command[6], sizeof(length)); + length = ntohs(length); + + if ((socketTypes[socket] == 0x00) && tcpServers[socket]) { + written = tcpServers[socket].write(&command[8], length); + } else if (socketTypes[socket] == 0x00) { + written = tcpClients[socket].write(&command[8], length); + } else if (socketTypes[socket] == 0x02) { + written = tlsClients[socket].write(&command[8], length); + } + + response[2] = 1; // number of parameters + response[3] = sizeof(written); // parameter 1 length + memcpy(&response[4], &written, sizeof(written)); + + return 7; +} + +int getDataBufTcp(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket; + uint16_t length; + int read = 0; + + socket = command[5]; + memcpy(&length, &command[8], sizeof(length)); + + if (socketTypes[socket] == 0x00) { + read = tcpClients[socket].read(&response[5], length); + } else if (socketTypes[socket] == 0x01) { + read = udps[socket].read(&response[5], length); + } else if (socketTypes[socket] == 0x02) { + read = tlsClients[socket].read(&response[5], length); + } + + if (read < 0) { + read = 0; + } + + response[2] = 1; // number of parameters + response[3] = (read >> 8) & 0xff; // parameter 1 length + response[4] = (read >> 0) & 0xff; + + return (6 + read); +} + +int insertDataBuf(const uint8_t command[], uint8_t response[]) +{ + uint8_t socket; + uint16_t length; + + socket = command[5]; + memcpy(&length, &command[6], sizeof(length)); + length = ntohs(length); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + + if (udps[socket].write(&command[8], length) != 0) { + response[4] = 1; + } else { + response[4] = 0; + } + + return 6; +} + +int ping(const uint8_t command[], uint8_t response[]) +{ + uint32_t ip; + uint8_t ttl; + int16_t result; + + memcpy(&ip, &command[4], sizeof(ip)); + ttl = command[9]; + + result = WiFi.ping(ip, ttl); + + response[2] = 1; // number of parameters + response[3] = sizeof(result); // parameter 1 length + memcpy(&response[4], &result, sizeof(result)); + + return 7; +} + +int getSocket(const uint8_t command[], uint8_t response[]) +{ + uint8_t result = 255; + + for (int i = 0; i < MAX_SOCKETS; i++) { + if (socketTypes[i] == 255) { + result = i; + break; + } + } + + response[2] = 1; // number of parameters + response[3] = sizeof(result); // parameter 1 length + response[4] = result; + + return 6; +} + +int setPinMode(const uint8_t command[], uint8_t response[]) +{ + uint8_t pin = command[4]; + uint8_t mode = command[6]; + + pinMode(pin, mode); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int setDigitalWrite(const uint8_t command[], uint8_t response[]) +{ + uint8_t pin = command[4]; + uint8_t value = command[6]; + + digitalWrite(pin, value); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + +int setAnalogWrite(const uint8_t command[], uint8_t response[]) +{ + uint8_t pin = command[4]; + uint8_t value = command[6]; + + analogWrite(pin, value); + + response[2] = 1; // number of parameters + response[3] = 1; // parameter 1 length + response[4] = 1; + + return 6; +} + + +typedef int (*CommandHandlerType)(const uint8_t command[], uint8_t response[]); + +const CommandHandlerType commandHandlers[] = { + // 0x00 -> 0x0f + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + // 0x10 -> 0x1f + setNet, setPassPhrase, setKey, NULL, setIPconfig, setDNSconfig, setHostname, setPowerMode, setApNet, setApPassPhrase, setDebug, getTemperature, NULL, NULL, NULL, NULL, + + // 0x20 -> 0x2f + getConnStatus, getIPaddr, getMACaddr, getCurrSSID, getCurrBSSID, getCurrRSSI, getCurrEnct, scanNetworks, startServerTcp, getStateTcp, dataSentTcp, availDataTcp, getDataTcp, startClientTcp, stopClientTcp, getClientStateTcp, + + // 0x30 -> 0x3f + disconnect, NULL, getIdxRSSI, getIdxEnct, reqHostByName, getHostByName, startScanNetworks, getFwVersion, NULL, sendUDPdata, getRemoteData, getTime, getIdxBSSID, getIdxChannel, ping, getSocket, + + // 0x40 -> 0x4f + NULL, NULL, NULL, NULL, sendDataTcp, getDataBufTcp, insertDataBuf, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + // 0x50 -> 0x5f + setPinMode, setDigitalWrite, setAnalogWrite, +}; + +#define NUM_COMMAND_HANDLERS (sizeof(commandHandlers) / sizeof(commandHandlers[0])) + +CommandHandlerClass::CommandHandlerClass() +{ +} + +void CommandHandlerClass::begin() +{ + pinMode(0, OUTPUT); + + for (int i = 0; i < MAX_SOCKETS; i++) { + socketTypes[i] = 255; + } + + _updateGpio0PinSemaphore = xSemaphoreCreateCounting(2, 0); + + WiFi.onReceive(CommandHandlerClass::onWiFiReceive); + + xTaskCreatePinnedToCore(CommandHandlerClass::gpio0Updater, "gpio0Updater", 8192, NULL, 1, NULL, 1); +} + +int CommandHandlerClass::handle(const uint8_t command[], uint8_t response[]) +{ + int responseLength = 0; + + if (command[0] == 0xe0 && command[1] < NUM_COMMAND_HANDLERS) { + CommandHandlerType commandHandlerType = commandHandlers[command[1]]; + + if (commandHandlerType) { + responseLength = commandHandlerType(command, response); + } + } + + if (responseLength == 0) { + response[0] = 0xef; + response[1] = 0x00; + response[2] = 0xee; + + responseLength = 3; + } else { + response[0] = 0xe0; + response[1] = (0x80 | command[1]); + response[responseLength - 1] = 0xee; + } + + xSemaphoreGive(_updateGpio0PinSemaphore); + + return responseLength; +} + +void CommandHandlerClass::gpio0Updater(void*) +{ + while (1) { + CommandHandler.updateGpio0Pin(); + } +} + +void CommandHandlerClass::updateGpio0Pin() +{ + xSemaphoreTake(_updateGpio0PinSemaphore, portMAX_DELAY); + + int available = 0; + + for (int i = 0; i < MAX_SOCKETS; i++) { + if (socketTypes[i] == 0x00) { + if (tcpServers[i] && tcpServers[i].available()) { + available = 1; + break; + } else if (tcpClients[i] && tcpClients[i].connected() && tcpClients[i].available()) { + available = 1; + break; + } + } + + if (socketTypes[i] == 0x01 && udps[i] && (udps[i].available() || udps[i].parsePacket())) { + available = 1; + break; + } + + if (socketTypes[i] == 0x02 && tlsClients[i] && tlsClients[i].connected() && tlsClients[i].available()) { + available = 1; + break; + } + } + + if (available) { + digitalWrite(0, HIGH); + } else { + digitalWrite(0, LOW); + } +} + +void CommandHandlerClass::onWiFiReceive() +{ + CommandHandler.handleWiFiReceive(); +} + +void CommandHandlerClass::handleWiFiReceive() +{ + xSemaphoreGiveFromISR(_updateGpio0PinSemaphore, NULL); +} + +CommandHandlerClass CommandHandler; diff --git a/main/CommandHandler.h b/main/CommandHandler.h new file mode 100644 index 0000000..e58f4a4 --- /dev/null +++ b/main/CommandHandler.h @@ -0,0 +1,45 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef COMMAND_HANDLER_H +#define COMMAND_HANDLER_H + +#include + +class CommandHandlerClass { +public: + CommandHandlerClass(); + + void begin(); + int handle(const uint8_t command[], uint8_t response[]); + +private: + static void gpio0Updater(void*); + void updateGpio0Pin(); + + static void onWiFiReceive(); + void handleWiFiReceive(); + +private: + SemaphoreHandle_t _updateGpio0PinSemaphore; +}; + +extern CommandHandlerClass CommandHandler; + +#endif diff --git a/main/component.mk b/main/component.mk new file mode 100644 index 0000000..e69de29 diff --git a/main/sketch.ino.cpp b/main/sketch.ino.cpp new file mode 100644 index 0000000..a14b57a --- /dev/null +++ b/main/sketch.ino.cpp @@ -0,0 +1,121 @@ +/* + This file is part of the MKR WiFi 1010 firmware. + Copyright (C) 2018 Arduino AG (http://www.arduino.cc/) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +extern "C" { + #include +} + +#include + +#include +#include + +#include "CommandHandler.h" + +#define SPI_BUFFER_LEN SPI_MAX_DMA_LEN + +int debug = 0; + +uint8_t* commandBuffer; +uint8_t* responseBuffer; + +void dumpBuffer(const char* label, uint8_t data[], int length) { + ets_printf("%s: ", label); + + for (int i = 0; i < length; i++) { + ets_printf("%02x", data[i]); + } + + ets_printf("\r\n"); +} + +void setDebug(int d) { + debug = d; + + if (debug) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[1], 0); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[3], 0); + + const char* default_uart_dev = "/dev/uart/0"; + _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r"); + _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w"); + _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w"); + + uart_div_modify(CONFIG_CONSOLE_UART_NUM, (APB_CLK_FREQ << 4) / 115200); + + // uartAttach(); + ets_install_uart_printf(); + uart_tx_switch(CONFIG_CONSOLE_UART_NUM); + } else { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[1], PIN_FUNC_GPIO); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[3], PIN_FUNC_GPIO); + + _GLOBAL_REENT->_stdin = (FILE*) &__sf_fake_stdin; + _GLOBAL_REENT->_stdout = (FILE*) &__sf_fake_stdout; + _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr; + + ets_install_putc1(NULL); + ets_install_putc2(NULL); + } +} + +void setup() { + setDebug(debug); + + // put SWD and SWCLK pins connected to SAMD as inputs + pinMode(15, INPUT); + pinMode(21, INPUT); + + SPIS.begin(); + + if (WiFi.status() == WL_NO_SHIELD) { + while (1); // no shield + } + + commandBuffer = (uint8_t*)heap_caps_malloc(SPI_BUFFER_LEN, MALLOC_CAP_DMA); + responseBuffer = (uint8_t*)heap_caps_malloc(SPI_BUFFER_LEN, MALLOC_CAP_DMA); + + CommandHandler.begin(); +} + +void loop() { + // wait for a command + memset(commandBuffer, 0x00, SPI_BUFFER_LEN); + int commandLength = SPIS.transfer(NULL, commandBuffer, SPI_BUFFER_LEN); + + if (commandLength == 0) { + return; + } + + if (debug) { + dumpBuffer("COMMAND", commandBuffer, commandLength); + } + + // process + memset(responseBuffer, 0x00, SPI_BUFFER_LEN); + int responseLength = CommandHandler.handle(commandBuffer, responseBuffer); + + SPIS.transfer(responseBuffer, NULL, responseLength); + + if (debug) { + dumpBuffer("RESPONSE", responseBuffer, responseLength); + } +} diff --git a/sdkconfig b/sdkconfig index 15d19ce..1644b49 100644 --- a/sdkconfig +++ b/sdkconfig @@ -13,13 +13,13 @@ CONFIG_MAKE_WARN_UNDEFINED_VARIABLES=y # # Bootloader config # -CONFIG_LOG_BOOTLOADER_LEVEL_NONE= +CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y CONFIG_LOG_BOOTLOADER_LEVEL_ERROR= CONFIG_LOG_BOOTLOADER_LEVEL_WARN= -CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y +CONFIG_LOG_BOOTLOADER_LEVEL_INFO= CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG= CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE= -CONFIG_LOG_BOOTLOADER_LEVEL=3 +CONFIG_LOG_BOOTLOADER_LEVEL=0 CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V= CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y @@ -127,10 +127,10 @@ CONFIG_BT_RESERVE_DRAM=0 # # ESP32-specific # -CONFIG_ESP32_DEFAULT_CPU_FREQ_80= -CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_80=y +CONFIG_ESP32_DEFAULT_CPU_FREQ_160= CONFIG_ESP32_DEFAULT_CPU_FREQ_240= -CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160 +CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=80 CONFIG_MEMMAP_SMP=y CONFIG_SPIRAM_SUPPORT= CONFIG_MEMMAP_TRACEMEM= @@ -156,11 +156,10 @@ CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF= CONFIG_NEWLIB_STDIN_LINE_ENDING_LF= CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y CONFIG_NEWLIB_NANO_FORMAT= -CONFIG_CONSOLE_UART_DEFAULT=y +CONFIG_CONSOLE_UART_DEFAULT= CONFIG_CONSOLE_UART_CUSTOM= -CONFIG_CONSOLE_UART_NONE= +CONFIG_CONSOLE_UART_NONE=y CONFIG_CONSOLE_UART_NUM=0 -CONFIG_CONSOLE_UART_BAUDRATE=115200 CONFIG_ULP_COPROC_ENABLED= CONFIG_ULP_COPROC_RESERVE_MEM=0 CONFIG_ESP32_PANIC_PRINT_HALT= @@ -341,7 +340,7 @@ CONFIG_L2_TO_L3_COPY= CONFIG_LWIP_MAX_SOCKETS=10 CONFIG_LWIP_SO_REUSE=y CONFIG_LWIP_SO_REUSE_RXTOALL=y -CONFIG_LWIP_SO_RCVBUF= +CONFIG_LWIP_SO_RCVBUF=y CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 CONFIG_LWIP_IP_FRAG= CONFIG_LWIP_IP_REASSEMBLY=