├── .gitignore ├── CHANGELOG ├── Makefile ├── README.md ├── arduino ├── component.mk ├── cores │ └── esp32 │ │ ├── Arduino.h │ │ ├── WInterrupts.c │ │ ├── WInterrupts.h │ │ ├── WMath.cpp │ │ ├── WMath.h │ │ ├── delay.c │ │ ├── delay.h │ │ ├── main.cpp │ │ ├── wiring.c │ │ ├── wiring_analog.c │ │ ├── wiring_analog.h │ │ ├── wiring_digital.c │ │ └── wiring_digital.h └── libraries │ ├── SPIS │ └── src │ │ ├── SPIS.cpp │ │ └── SPIS.h │ └── WiFi │ └── src │ ├── WiFi.cpp │ ├── WiFi.h │ ├── WiFiClient.cpp │ ├── WiFiClient.h │ ├── WiFiSSLClient.cpp │ ├── WiFiSSLClient.h │ ├── WiFiServer.cpp │ ├── WiFiServer.h │ ├── WiFiUdp.cpp │ └── WiFiUdp.h ├── combine.py ├── data └── roots.pem ├── main ├── CommandHandler.cpp ├── CommandHandler.h ├── component.mk └── sketch.ino.cpp ├── partitions.csv └── sdkconfig /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | *.bin 3 | sdkconfig.old 4 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Adafruit's Arduino NINA-W102 firmware 1.3.1 - 2019.04.24 2 | 3 | * Updated README.md to indicate this is Adafruit's fork 4 | * Updated README.md with current, reproducible build instructions 5 | * Updated CHANGELOG with various Adafruit changes 6 | 7 | Adafruit's Arduino NINA-W102 firmware 1.3.0 - 2019.04.04 8 | 9 | * Rev'd version in CommandHandler.cpp 10 | * Added version number to combine.py script 11 | 12 | Adafruit's Arduino NINA-W102 firmware 1.2.2 - 2019.04.04 13 | 14 | * Added support for WPA2 Enterprise 15 | 16 | Adafruit's Arduino NINA-W102 firmware 1.2.2 - 2019.02.28 17 | 18 | * First official Adafruit release 19 | 20 | Arduino NINA-W102 firmware 1.2.1 - 2018.11.16 21 | 22 | * Fixed factory SSL certificates being incorrectly parsed due to OOM caused by Bluetooth inclusion 23 | 24 | Arduino NINA-W102 firmware 1.2.0 - 2018.11.13 25 | 26 | * Fixed DNS servers not sticking when static IP address is used 27 | * Added HCI UART mode on boot, enabled if SS is LOW 28 | * Erase NVS flash on init failure 29 | 30 | Arduino NINA-W102 firmware 1.1.0 - 2018.10.4 31 | 32 | * WiFi is now stopped before connecting to AP 33 | * Changed default STA hostname to "arduino-XXYY" 34 | * Switched to all channel scan when connecting to AP in STA mode 35 | * Fixed static IP's support in STA + AP modes 36 | * Return failure on bad AP params 37 | * Moved certificates to separate mmapped partition, added a larger set of built-in root CA's 38 | * Updated to use esp-idf v3.1 39 | 40 | Arduino NINA-W102 firmware 1.0.0 - 2018.06.28 41 | 42 | * Initial release 43 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := nina-fw 2 | 3 | # Passthrough Board Port 4 | M4_PORT := /dev/cu.usbmodem14121301 5 | UPLOAD_BAUD = 115200 6 | # ESP32 USB Serial Port 7 | ESP_PORT := /dev/cu.usbserial-AH03B302 8 | 9 | # Directories and Files 10 | BOOT_VOLUME := /Volumes/FEATHERBOOT/. 11 | CIRCUITPYTHON_UF2 := circuitpython.uf2 12 | 13 | EXTRA_COMPONENT_DIRS := $(PWD)/arduino 14 | 15 | ifeq ($(RELEASE),1) 16 | CFLAGS += -DNDEBUG -DCONFIG_FREERTOS_ASSERT_DISABLE -Os -DLOG_LOCAL_LEVEL=0 17 | CPPFLAGS += -DNDEBUG -Os 18 | endif 19 | 20 | ifeq ($(UNO_WIFI_REV2),1) 21 | CFLAGS += -DUNO_WIFI_REV2 22 | CPPFLAGS += -DUNO_WIFI_REV2 23 | endif 24 | 25 | include $(IDF_PATH)/make/project.mk 26 | 27 | load-passthrough: 28 | cp passthrough.UF2 $(BOOT_VOLUME) 29 | 30 | load-nina: 31 | esptool.py --port $(M4_PORT) --before no_reset --baud $(UPLOAD_BAUD) write_flash 0 NINA_W102-1.4.0.bin 32 | 33 | load-circuitpython: 34 | cp $(CIRCUITPYTHON_UF2) $(BOOT_VOLUME) 35 | 36 | serial: 37 | miniterm.py $(ESP_PORT) $(UPLOAD_BAUD) 38 | 39 | firmware: all 40 | python combine.py 41 | 42 | .PHONY: firmware 43 | 44 | .PHONY: load-passthrough 45 | 46 | .PHONY: load-nina 47 | 48 | .PHONY: load-circuitpython 49 | 50 | .PHONY: serial -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adafruit fork of the Arduino NINA-W102 firmware 2 | 3 | This is the Adafruit fork of the Arduino NINA-W102 firmware. The original 4 | repository is located at https://github.com/arduino/nina-fw 5 | 6 | This firmware uses [Espressif's IDF](https://github.com/espressif/esp-idf) 7 | 8 | ## Building 9 | 10 | The firmware shipped in Adafruit's products is compiled following these 11 | instructions. These may differ from the instructions included in the 12 | original Arduino firmware repository. 13 | 14 | 1. [Download the ESP32 toolchain](https://docs.espressif.com/projects/esp-idf/en/v3.3/get-started/index.html#setup-toolchain) 15 | 1. Extract it and add it to your `PATH`: `export PATH=$PATH:/bin` 16 | 1. Clone **v3.3** of the IDF: `git clone --branch v3.3 --recursive https://github.com/espressif/esp-idf.git` 17 | 1. Set the `IDF_PATH` environment variable: `export IDF_PATH=` 18 | 1. Run `make firmware` to build the firmware (in the directory of this read me) 19 | 1. You should have a file named `NINA_W102-x.x.x.bin` in the top directory 20 | 1. Use appropriate tools (esptool.py, appropriate pass-through firmware etc) 21 | to load this binary file onto your board. 22 | a. If you do not know how to do this, [we have an excellent guide on the Adafruit Learning System for upgrading your ESP32's firmware](https://learn.adafruit.com/upgrading-esp32-firmware) 23 | 24 | 25 | ## License 26 | 27 | Copyright (c) 2018 Arduino SA. All rights reserved. 28 | 29 | This library is free software; you can redistribute it and/or 30 | modify it under the terms of the GNU Lesser General Public 31 | License as published by the Free Software Foundation; either 32 | version 2.1 of the License, or (at your option) any later version. 33 | 34 | This library is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 37 | Lesser General Public License for more details. 38 | 39 | You should have received a copy of the GNU Lesser General Public 40 | License along with this library; if not, write to the Free Software 41 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 42 | -------------------------------------------------------------------------------- /arduino/component.mk: -------------------------------------------------------------------------------- 1 | COMPONENT_ADD_INCLUDEDIRS := cores/esp32 libraries/SPIS/src libraries/WiFi/src 2 | 3 | COMPONENT_SRCDIRS := cores/esp32 libraries/SPIS/src libraries/WiFi/src 4 | -------------------------------------------------------------------------------- /arduino/cores/esp32/Arduino.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef ARDUINO_H 21 | #define ARDUINO_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C"{ 31 | #endif // __cplusplus 32 | 33 | // system functions 34 | void init(void); 35 | 36 | // sketch 37 | void setup(void); 38 | void loop(void); 39 | 40 | #ifdef __cplusplus 41 | } // extern "C" 42 | #endif 43 | 44 | #ifdef __cplusplus 45 | #include "WMath.h" 46 | #endif 47 | #include "delay.h" 48 | 49 | #include "wiring_digital.h" 50 | #include "wiring_analog.h" 51 | 52 | #endif // ARDUINO_H 53 | -------------------------------------------------------------------------------- /arduino/cores/esp32/WInterrupts.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | #include "wiring_digital.h" 23 | 24 | #include "WInterrupts.h" 25 | 26 | static voidFuncPtr callbacksInt[GPIO_NUM_MAX] = { NULL }; 27 | 28 | void IRAM_ATTR gpioInterruptHandler(void* arg) 29 | { 30 | uint32_t pin = (uint32_t)arg; 31 | 32 | if (callbacksInt[pin]) { 33 | callbacksInt[pin](); 34 | } 35 | } 36 | 37 | void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) 38 | { 39 | callbacksInt[pin] = callback; 40 | 41 | switch (mode) { 42 | case LOW: 43 | gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_LOW_LEVEL); 44 | gpio_wakeup_enable((gpio_num_t)pin, GPIO_INTR_LOW_LEVEL); 45 | break; 46 | 47 | case HIGH: 48 | gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_HIGH_LEVEL); 49 | gpio_wakeup_enable((gpio_num_t)pin, GPIO_INTR_HIGH_LEVEL); 50 | break; 51 | 52 | case CHANGE: 53 | gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_ANYEDGE); 54 | break; 55 | 56 | case FALLING: 57 | gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_NEGEDGE); 58 | break; 59 | 60 | case RISING: 61 | gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_POSEDGE); 62 | break; 63 | 64 | default: 65 | gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE); 66 | break; 67 | } 68 | 69 | gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3); 70 | 71 | gpio_isr_handler_add((gpio_num_t)pin, gpioInterruptHandler, (void*)pin); 72 | 73 | gpio_intr_enable((gpio_num_t)pin); 74 | } 75 | -------------------------------------------------------------------------------- /arduino/cores/esp32/WInterrupts.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef _WIRING_INTERRUPTS_ 21 | #define _WIRING_INTERRUPTS_ 22 | 23 | #include 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | // #define LOW 0 30 | // #define HIGH 1 31 | #define CHANGE 2 32 | #define FALLING 3 33 | #define RISING 4 34 | 35 | typedef void (*voidFuncPtr)(void); 36 | 37 | void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /arduino/cores/esp32/WMath.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | extern "C" { 21 | #include 22 | } 23 | 24 | #include "WMath.h" 25 | 26 | extern long random(long howbig) 27 | { 28 | if(howbig == 0) { 29 | return 0; 30 | } 31 | 32 | return esp_random() % howbig; 33 | } 34 | -------------------------------------------------------------------------------- /arduino/cores/esp32/WMath.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef _WIRING_MATH_ 21 | #define _WIRING_MATH_ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | extern long random(long); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif /* _WIRING_MATH_ */ 34 | -------------------------------------------------------------------------------- /arduino/cores/esp32/delay.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "delay.h" 24 | 25 | unsigned long millis() 26 | { 27 | return xTaskGetTickCount() * portTICK_PERIOD_MS; 28 | } 29 | 30 | void delay(uint32_t ms) 31 | { 32 | vTaskDelay(ms / portTICK_PERIOD_MS); 33 | } 34 | -------------------------------------------------------------------------------- /arduino/cores/esp32/delay.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef DELAY_H 21 | #define DELAY_H 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | #include 28 | 29 | extern unsigned long millis(); 30 | 31 | extern void delay(uint32_t ms); 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | 37 | #endif // DELAY_H 38 | -------------------------------------------------------------------------------- /arduino/cores/esp32/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #define ARDUINO_MAIN 24 | #include "Arduino.h" 25 | 26 | void arduino_main(void*) { 27 | init(); 28 | 29 | setup(); 30 | 31 | while (1) { 32 | loop(); 33 | } 34 | } 35 | 36 | extern "C" { 37 | void app_main() { 38 | xTaskCreatePinnedToCore(arduino_main, "arduino", 8192, NULL, 1, NULL, 1); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /arduino/cores/esp32/wiring.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | #include "Arduino.h" 23 | 24 | void init() { 25 | if (nvs_flash_init() != ESP_OK) { 26 | nvs_flash_erase(); 27 | 28 | nvs_flash_init(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /arduino/cores/esp32/wiring_analog.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | #include "wiring_analog.h" 23 | 24 | void analogWrite(uint32_t pin, uint32_t value) 25 | { 26 | periph_module_enable(PERIPH_LEDC_MODULE); 27 | 28 | ledc_timer_config_t timerConf = { 29 | .bit_num = LEDC_TIMER_10_BIT, 30 | .freq_hz = 1000, 31 | .speed_mode = LEDC_HIGH_SPEED_MODE, 32 | .timer_num = (pin / 7), 33 | }; 34 | ledc_timer_config(&timerConf); 35 | 36 | ledc_channel_config_t ledc_conf = { 37 | .channel = (pin % 7), 38 | .duty = (value << 2), 39 | .gpio_num = pin, 40 | .intr_type = LEDC_INTR_DISABLE, 41 | .speed_mode = LEDC_HIGH_SPEED_MODE, 42 | .timer_sel = (pin / 7) 43 | }; 44 | ledc_channel_config(&ledc_conf); 45 | } 46 | -------------------------------------------------------------------------------- /arduino/cores/esp32/wiring_analog.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef WIRING_ANALOG_H 21 | #define WIRING_ANALOG_H 22 | 23 | #include "Arduino.h" 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | extern void analogWrite(uint32_t pin, uint32_t value); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif // WIRING_ANALOG_H 36 | -------------------------------------------------------------------------------- /arduino/cores/esp32/wiring_digital.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | #include "wiring_digital.h" 23 | 24 | void pinMode(uint32_t pin, uint32_t mode) 25 | { 26 | switch (mode) { 27 | case INPUT: 28 | gpio_set_direction((gpio_num_t)pin, GPIO_MODE_INPUT); 29 | gpio_set_pull_mode((gpio_num_t)pin, GPIO_FLOATING); 30 | break; 31 | 32 | case OUTPUT: 33 | gpio_set_direction((gpio_num_t)pin, GPIO_MODE_OUTPUT); 34 | gpio_set_pull_mode((gpio_num_t)pin, GPIO_FLOATING); 35 | break; 36 | } 37 | 38 | PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pin], PIN_FUNC_GPIO); 39 | } 40 | 41 | void digitalWrite(uint32_t pin, uint32_t val) 42 | { 43 | gpio_set_level((gpio_num_t)pin, val); 44 | } 45 | 46 | int digitalRead(uint32_t pin) 47 | { 48 | return gpio_get_level(pin); 49 | } 50 | -------------------------------------------------------------------------------- /arduino/cores/esp32/wiring_digital.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef WIRING_DIGITAL_H 21 | #define WIRING_DIGITAL_H 22 | 23 | #include "Arduino.h" 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #define LOW 0x00 30 | #define HIGH 0x01 31 | 32 | #define INPUT 0x00 33 | #define OUTPUT 0x01 34 | 35 | extern void pinMode(uint32_t pin, uint32_t mode); 36 | 37 | extern void digitalWrite(uint32_t pin, uint32_t val); 38 | 39 | extern int digitalRead(uint32_t pin); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif // WIRING_DIGITAL_H 46 | -------------------------------------------------------------------------------- /arduino/libraries/SPIS/src/SPIS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include "wiring_digital.h" 26 | #include "WInterrupts.h" 27 | 28 | #include "SPIS.h" 29 | 30 | SPISClass::SPISClass(spi_host_device_t hostDevice, int dmaChannel, int mosiPin, int misoPin, int sclkPin, int csPin, int readyPin) : 31 | _hostDevice(hostDevice), 32 | _dmaChannel(dmaChannel), 33 | _mosiPin(mosiPin), 34 | _misoPin(misoPin), 35 | _sclkPin(sclkPin), 36 | _csPin(csPin), 37 | _readyPin(readyPin) 38 | { 39 | } 40 | 41 | int SPISClass::begin() 42 | { 43 | spi_bus_config_t busCfg; 44 | spi_slave_interface_config_t slvCfg; 45 | 46 | pinMode(_readyPin, OUTPUT); 47 | digitalWrite(_readyPin, HIGH); 48 | 49 | _readySemaphore = xSemaphoreCreateCounting(1, 0); 50 | 51 | attachInterrupt(_csPin, onChipSelect, FALLING); 52 | 53 | memset(&busCfg, 0x00, sizeof(busCfg)); 54 | busCfg.mosi_io_num = _mosiPin; 55 | busCfg.miso_io_num = _misoPin; 56 | busCfg.sclk_io_num = _sclkPin; 57 | 58 | memset(&slvCfg, 0x00, sizeof(slvCfg)); 59 | slvCfg.mode = 0; 60 | slvCfg.spics_io_num = _csPin; 61 | slvCfg.queue_size = 1; 62 | slvCfg.flags = 0; 63 | slvCfg.post_setup_cb = SPISClass::onSetupComplete; 64 | slvCfg.post_trans_cb = NULL; 65 | 66 | gpio_set_pull_mode((gpio_num_t)_mosiPin, GPIO_FLOATING); 67 | gpio_set_pull_mode((gpio_num_t)_sclkPin, GPIO_PULLDOWN_ONLY); 68 | gpio_set_pull_mode((gpio_num_t)_csPin, GPIO_PULLUP_ONLY); 69 | 70 | spi_slave_initialize(_hostDevice, &busCfg, &slvCfg, _dmaChannel); 71 | 72 | return 1; 73 | } 74 | 75 | int SPISClass::transfer(uint8_t out[], uint8_t in[], size_t len) 76 | { 77 | spi_slave_transaction_t slvTrans; 78 | spi_slave_transaction_t* slvRetTrans; 79 | 80 | memset(&slvTrans, 0x00, sizeof(slvTrans)); 81 | 82 | slvTrans.length = len * 8; 83 | slvTrans.trans_len = 0; 84 | slvTrans.tx_buffer = out; 85 | slvTrans.rx_buffer = in; 86 | 87 | spi_slave_queue_trans(_hostDevice, &slvTrans, portMAX_DELAY); 88 | xSemaphoreTake(_readySemaphore, portMAX_DELAY); 89 | digitalWrite(_readyPin, LOW); 90 | spi_slave_get_trans_result(_hostDevice, &slvRetTrans, portMAX_DELAY); 91 | digitalWrite(_readyPin, HIGH); 92 | 93 | return (slvTrans.trans_len / 8); 94 | } 95 | 96 | void SPISClass::onChipSelect() 97 | { 98 | SPIS.handleOnChipSelect(); 99 | } 100 | 101 | void SPISClass::handleOnChipSelect() 102 | { 103 | digitalWrite(_readyPin, HIGH); 104 | } 105 | 106 | void SPISClass::onSetupComplete(spi_slave_transaction_t*) 107 | { 108 | SPIS.handleSetupComplete(); 109 | } 110 | 111 | void SPISClass::handleSetupComplete() 112 | { 113 | xSemaphoreGiveFromISR(_readySemaphore, NULL); 114 | } 115 | 116 | SPISClass SPIS(VSPI_HOST, 1, 14, 23, 18, 5, 25); 117 | -------------------------------------------------------------------------------- /arduino/libraries/SPIS/src/SPIS.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef SPIS_H 21 | #define SPIS_H 22 | 23 | #include 24 | #include 25 | 26 | class SPISClass { 27 | 28 | public: 29 | SPISClass(spi_host_device_t hostDevice, int dmaChannel, int mosiPin, int misoPin, int sclkPin, int csPin, int readyPin); 30 | 31 | int begin(); 32 | int transfer(uint8_t out[], uint8_t in[], size_t len); 33 | 34 | private: 35 | static void onChipSelect(); 36 | void handleOnChipSelect(); 37 | 38 | static void onSetupComplete(spi_slave_transaction_t*); 39 | void handleSetupComplete(); 40 | 41 | private: 42 | spi_host_device_t _hostDevice; 43 | int _dmaChannel; 44 | int _mosiPin; 45 | int _misoPin; 46 | int _sclkPin; 47 | int _csPin; 48 | int _readyPin; 49 | 50 | intr_handle_t _csIntrHandle; 51 | 52 | SemaphoreHandle_t _readySemaphore; 53 | }; 54 | 55 | extern SPISClass SPIS; 56 | 57 | #endif 58 | 59 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "WiFi.h" 36 | 37 | WiFiClass::WiFiClass() : 38 | _initialized(false), 39 | _status(WL_NO_SHIELD), 40 | _interface(ESP_IF_WIFI_STA), 41 | _onReceiveCallback(NULL) 42 | { 43 | _eventGroup = xEventGroupCreate(); 44 | memset(&_apRecord, 0x00, sizeof(_apRecord)); 45 | memset(&_ipInfo, 0x00, sizeof(_ipInfo)); 46 | memset(&_dnsServers, 0x00, sizeof(_dnsServers)); 47 | } 48 | 49 | uint8_t WiFiClass::status() 50 | { 51 | if (!_initialized) { 52 | _initialized = true; 53 | init(); 54 | } 55 | 56 | return _status; 57 | } 58 | 59 | int WiFiClass::hostByName(const char* hostname, /*IPAddress*/uint32_t& result) 60 | { 61 | result = 0xffffffff; 62 | 63 | struct hostent* hostEntry = lwip_gethostbyname(hostname); 64 | 65 | if (hostEntry == NULL) { 66 | return 0; 67 | } 68 | 69 | memcpy(&result, hostEntry->h_addr_list[0], sizeof(result)); 70 | 71 | return 1; 72 | } 73 | 74 | int WiFiClass::ping(/*IPAddress*/uint32_t host, uint8_t ttl) 75 | { 76 | uint32_t timeout = 5000; 77 | 78 | int s = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP); 79 | 80 | struct timeval timeoutVal; 81 | timeoutVal.tv_sec = (timeout / 1000); 82 | timeoutVal.tv_usec = (timeout % 1000) * 1000; 83 | 84 | setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeoutVal, sizeof(timeoutVal)); 85 | setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 86 | 87 | struct __attribute__((__packed__)) { 88 | struct icmp_echo_hdr header; 89 | uint8_t data[32]; 90 | } request; 91 | 92 | ICMPH_TYPE_SET(&request.header, ICMP_ECHO); 93 | ICMPH_CODE_SET(&request.header, 0); 94 | request.header.chksum = 0; 95 | request.header.id = 0xAFAF; 96 | request.header.seqno = random(0xffff); 97 | 98 | for (size_t i = 0; i < sizeof(request.data); i++) { 99 | request.data[i] = i; 100 | } 101 | 102 | request.header.chksum = inet_chksum(&request, sizeof(request)); 103 | 104 | ip_addr_t addr; 105 | addr.type = IPADDR_TYPE_V4; 106 | addr.u_addr.ip4.addr = host; 107 | // IP_ADDR4(&addr, ip[0], ip[1], ip[2], ip[3]); 108 | 109 | struct sockaddr_in to; 110 | struct sockaddr_in from; 111 | 112 | to.sin_len = sizeof(to); 113 | to.sin_family = AF_INET; 114 | inet_addr_from_ip4addr(&to.sin_addr, ip_2_ip4(&addr)); 115 | 116 | sendto(s, &request, sizeof(request), 0, (struct sockaddr*)&to, sizeof(to)); 117 | unsigned long sendTime = millis(); 118 | unsigned long recvTime = 0; 119 | 120 | do { 121 | socklen_t fromlen = sizeof(from); 122 | 123 | struct __attribute__((__packed__)) { 124 | struct ip_hdr ipHeader; 125 | struct icmp_echo_hdr header; 126 | } response; 127 | 128 | int rxSize = recvfrom(s, &response, sizeof(response), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen); 129 | if (rxSize == -1) { 130 | // time out 131 | break; 132 | } 133 | 134 | if (rxSize < sizeof(response)) { 135 | // too short 136 | continue; 137 | } 138 | 139 | if (from.sin_family != AF_INET) { 140 | // not IPv4 141 | continue; 142 | } 143 | 144 | if ((response.header.id == request.header.id) && (response.header.seqno == request.header.seqno)) { 145 | recvTime = millis(); 146 | } 147 | } while (recvTime == 0); 148 | 149 | close(s); 150 | 151 | if (recvTime == 0) { 152 | return -1; 153 | } else { 154 | return (recvTime - sendTime); 155 | } 156 | } 157 | 158 | uint8_t WiFiClass::begin(const char* ssid) 159 | { 160 | return begin(ssid, ""); 161 | } 162 | 163 | uint8_t WiFiClass::begin(const char* ssid, uint8_t key_idx, const char* key) 164 | { 165 | return begin(ssid, key); 166 | } 167 | 168 | uint8_t WiFiClass::begin(const char* ssid, const char* key) 169 | { 170 | wifi_config_t wifiConfig; 171 | 172 | memset(&wifiConfig, 0x00, sizeof(wifiConfig)); 173 | strncpy((char*)wifiConfig.sta.ssid, ssid, sizeof(wifiConfig.sta.ssid)); 174 | strncpy((char*)wifiConfig.sta.password, key, sizeof(wifiConfig.sta.password)); 175 | wifiConfig.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; 176 | _status = WL_NO_SSID_AVAIL; 177 | 178 | _interface = ESP_IF_WIFI_STA; 179 | 180 | esp_wifi_stop(); 181 | esp_wifi_set_mode(WIFI_MODE_STA); 182 | esp_wifi_start(); 183 | xEventGroupWaitBits(_eventGroup, BIT0, false, true, portMAX_DELAY); 184 | 185 | if (esp_wifi_set_config(ESP_IF_WIFI_STA, &wifiConfig) != ESP_OK) { 186 | _status = WL_CONNECT_FAILED; 187 | } 188 | 189 | if (_ipInfo.ip.addr) { 190 | tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); 191 | tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &_ipInfo); 192 | } else { 193 | tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA); 194 | } 195 | 196 | esp_wifi_connect(); 197 | 198 | return _status; 199 | } 200 | 201 | uint8_t WiFiClass::beginAP(const char *ssid, uint8_t channel) 202 | { 203 | wifi_config_t wifiConfig; 204 | 205 | memset(&wifiConfig, 0x00, sizeof(wifiConfig)); 206 | strncpy((char*)wifiConfig.ap.ssid, ssid, sizeof(wifiConfig.sta.ssid)); 207 | wifiConfig.ap.channel = 0; 208 | wifiConfig.ap.authmode = WIFI_AUTH_OPEN; 209 | wifiConfig.ap.max_connection = 4; 210 | 211 | _status = WL_NO_SSID_AVAIL; 212 | 213 | _interface = ESP_IF_WIFI_AP; 214 | 215 | esp_wifi_stop(); 216 | esp_wifi_set_mode(WIFI_MODE_AP); 217 | 218 | if (esp_wifi_set_config(ESP_IF_WIFI_AP, &wifiConfig) != ESP_OK) { 219 | _status = WL_AP_FAILED; 220 | } else { 221 | esp_wifi_start(); 222 | xEventGroupWaitBits(_eventGroup, BIT1, false, true, portMAX_DELAY); 223 | } 224 | 225 | return _status; 226 | } 227 | 228 | uint8_t WiFiClass::beginAP(const char *ssid, uint8_t key_idx, const char* key, uint8_t channel) 229 | { 230 | wifi_config_t wifiConfig; 231 | 232 | memset(&wifiConfig, 0x00, sizeof(wifiConfig)); 233 | strncpy((char*)wifiConfig.ap.ssid, ssid, sizeof(wifiConfig.sta.ssid)); 234 | strncpy((char*)wifiConfig.ap.password, key, sizeof(wifiConfig.sta.password)); 235 | wifiConfig.ap.channel = 0; 236 | wifiConfig.ap.authmode = WIFI_AUTH_WEP; 237 | wifiConfig.ap.max_connection = 4; 238 | 239 | _status = WL_NO_SSID_AVAIL; 240 | 241 | _interface = ESP_IF_WIFI_AP; 242 | 243 | esp_wifi_stop(); 244 | esp_wifi_set_mode(WIFI_MODE_AP); 245 | 246 | if (esp_wifi_set_config(ESP_IF_WIFI_AP, &wifiConfig) != ESP_OK) { 247 | _status = WL_AP_FAILED; 248 | } else { 249 | esp_wifi_start(); 250 | xEventGroupWaitBits(_eventGroup, BIT1, false, true, portMAX_DELAY); 251 | } 252 | 253 | return _status; 254 | } 255 | 256 | uint8_t WiFiClass::beginAP(const char *ssid, const char* key, uint8_t channel) 257 | { 258 | wifi_config_t wifiConfig; 259 | 260 | memset(&wifiConfig, 0x00, sizeof(wifiConfig)); 261 | strncpy((char*)wifiConfig.ap.ssid, ssid, sizeof(wifiConfig.sta.ssid)); 262 | strncpy((char*)wifiConfig.ap.password, key, sizeof(wifiConfig.sta.password)); 263 | wifiConfig.ap.channel = 0; 264 | wifiConfig.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK; 265 | wifiConfig.ap.max_connection = 4; 266 | 267 | _status = WL_NO_SSID_AVAIL; 268 | 269 | _interface = ESP_IF_WIFI_AP; 270 | 271 | esp_wifi_stop(); 272 | esp_wifi_set_mode(WIFI_MODE_AP); 273 | 274 | if (esp_wifi_set_config(ESP_IF_WIFI_AP, &wifiConfig) != ESP_OK) { 275 | _status = WL_AP_FAILED; 276 | } else { 277 | esp_wifi_start(); 278 | xEventGroupWaitBits(_eventGroup, BIT1, false, true, portMAX_DELAY); 279 | } 280 | 281 | return _status; 282 | } 283 | 284 | void WiFiClass::config(/*IPAddress*/uint32_t local_ip, /*IPAddress*/uint32_t gateway, /*IPAddress*/uint32_t subnet) 285 | { 286 | dns_clear_servers(true); 287 | 288 | _ipInfo.ip.addr = local_ip; 289 | _ipInfo.gw.addr = gateway; 290 | _ipInfo.netmask.addr = subnet; 291 | 292 | if (_interface == ESP_IF_WIFI_AP) { 293 | tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP); 294 | tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &_ipInfo); 295 | tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP); 296 | } else { 297 | tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); 298 | tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &_ipInfo); 299 | } 300 | } 301 | 302 | void WiFiClass::setDNS(/*IPAddress*/uint32_t dns_server1, /*IPAddress*/uint32_t dns_server2) 303 | { 304 | ip_addr_t d; 305 | d.type = IPADDR_TYPE_V4; 306 | 307 | _dnsServers[0] = dns_server1; 308 | _dnsServers[1] = dns_server2; 309 | 310 | if (dns_server1) { 311 | d.u_addr.ip4.addr = static_cast(dns_server1); 312 | dns_setserver(0, &d); 313 | } 314 | 315 | if (dns_server2) { 316 | d.u_addr.ip4.addr = static_cast(dns_server2); 317 | dns_setserver(1, &d); 318 | } 319 | } 320 | 321 | void WiFiClass::hostname(const char* name) 322 | { 323 | tcpip_adapter_set_hostname(_interface == ESP_IF_WIFI_AP ? TCPIP_ADAPTER_IF_AP : TCPIP_ADAPTER_IF_STA, name); 324 | } 325 | 326 | void WiFiClass::disconnect() 327 | { 328 | esp_wifi_disconnect(); 329 | esp_wifi_stop(); 330 | } 331 | 332 | void WiFiClass::end() 333 | { 334 | esp_wifi_stop(); 335 | } 336 | 337 | uint8_t* WiFiClass::macAddress(uint8_t* mac) 338 | { 339 | uint8_t macTemp[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 340 | 341 | esp_wifi_get_mac(_interface, macTemp); 342 | 343 | mac[0] = macTemp[5]; 344 | mac[1] = macTemp[4]; 345 | mac[2] = macTemp[3]; 346 | mac[3] = macTemp[2]; 347 | mac[4] = macTemp[1]; 348 | mac[5] = macTemp[0]; 349 | 350 | return mac; 351 | } 352 | 353 | uint32_t WiFiClass::localIP() 354 | { 355 | return _ipInfo.ip.addr; 356 | } 357 | 358 | uint32_t WiFiClass::subnetMask() 359 | { 360 | return _ipInfo.netmask.addr; 361 | } 362 | 363 | uint32_t WiFiClass::gatewayIP() 364 | { 365 | return _ipInfo.gw.addr; 366 | } 367 | 368 | char* WiFiClass::SSID() 369 | { 370 | return (char*)_apRecord.ssid; 371 | } 372 | 373 | int32_t WiFiClass::RSSI() 374 | { 375 | if (_interface == ESP_IF_WIFI_AP) { 376 | return 0; 377 | } else { 378 | esp_wifi_sta_get_ap_info(&_apRecord); 379 | 380 | return _apRecord.rssi; 381 | } 382 | } 383 | 384 | uint8_t WiFiClass::encryptionType() 385 | { 386 | uint8_t encryptionType = _apRecord.authmode; 387 | 388 | if (encryptionType == WIFI_AUTH_OPEN) { 389 | encryptionType = 7; 390 | } else if (encryptionType == WIFI_AUTH_WEP) { 391 | encryptionType = 5; 392 | } else if (encryptionType == WIFI_AUTH_WPA_PSK) { 393 | encryptionType = 2; 394 | } else if (encryptionType == WIFI_AUTH_WPA2_PSK || encryptionType == WIFI_AUTH_WPA_WPA2_PSK) { 395 | encryptionType = 4; 396 | } else { 397 | // unknown? 398 | encryptionType = 255; 399 | } 400 | 401 | return encryptionType; 402 | } 403 | 404 | uint8_t* WiFiClass::BSSID(uint8_t* bssid) 405 | { 406 | if (_interface == ESP_IF_WIFI_AP) { 407 | return macAddress(bssid); 408 | } else { 409 | bssid[0] = _apRecord.bssid[5]; 410 | bssid[1] = _apRecord.bssid[4]; 411 | bssid[2] = _apRecord.bssid[3]; 412 | bssid[3] = _apRecord.bssid[2]; 413 | bssid[4] = _apRecord.bssid[1]; 414 | bssid[5] = _apRecord.bssid[0]; 415 | 416 | return bssid; 417 | } 418 | } 419 | 420 | int8_t WiFiClass::scanNetworks() 421 | { 422 | esp_wifi_set_mode(WIFI_MODE_STA); 423 | esp_wifi_start(); 424 | xEventGroupWaitBits(_eventGroup, BIT0, false, true, portMAX_DELAY); 425 | 426 | wifi_scan_config_t config; 427 | 428 | config.ssid = 0; 429 | config.bssid = 0; 430 | config.channel = 0; 431 | config.show_hidden = false; 432 | config.scan_type = WIFI_SCAN_TYPE_ACTIVE; 433 | config.scan_time.active.min = 100; 434 | config.scan_time.active.max = 300; 435 | 436 | xEventGroupClearBits(_eventGroup, BIT2); 437 | 438 | if (esp_wifi_scan_start(&config, false) != ESP_OK) { 439 | _status = WL_NO_SSID_AVAIL; 440 | return 0; 441 | } 442 | 443 | xEventGroupWaitBits(_eventGroup, BIT2, false, true, portMAX_DELAY); 444 | 445 | uint16_t numNetworks; 446 | esp_wifi_scan_get_ap_num(&numNetworks); 447 | 448 | if (numNetworks > MAX_SCAN_RESULTS) { 449 | numNetworks = MAX_SCAN_RESULTS; 450 | } 451 | 452 | esp_wifi_scan_get_ap_records(&numNetworks, _scanResults); 453 | 454 | _status = WL_SCAN_COMPLETED; 455 | 456 | return numNetworks; 457 | } 458 | 459 | char* WiFiClass::SSID(uint8_t pos) 460 | { 461 | return (char*)_scanResults[pos].ssid; 462 | } 463 | 464 | int32_t WiFiClass::RSSI(uint8_t pos) 465 | { 466 | return _scanResults[pos].rssi; 467 | } 468 | 469 | uint8_t WiFiClass::encryptionType(uint8_t pos) 470 | { 471 | uint8_t encryptionType = _scanResults[pos].authmode; 472 | 473 | if (encryptionType == WIFI_AUTH_OPEN) { 474 | encryptionType = 7; 475 | } else if (encryptionType == WIFI_AUTH_WEP) { 476 | encryptionType = 5; 477 | } else if (encryptionType == WIFI_AUTH_WPA_PSK) { 478 | encryptionType = 2; 479 | } else if (encryptionType == WIFI_AUTH_WPA2_PSK || encryptionType == WIFI_AUTH_WPA_WPA2_PSK) { 480 | encryptionType = 4; 481 | } else { 482 | // unknown? 483 | encryptionType = 255; 484 | } 485 | 486 | return encryptionType; 487 | } 488 | 489 | uint8_t* WiFiClass::BSSID(uint8_t pos, uint8_t* bssid) 490 | { 491 | const uint8_t* tempBssid = _scanResults[pos].bssid; 492 | 493 | bssid[0] = tempBssid[5]; 494 | bssid[1] = tempBssid[4]; 495 | bssid[2] = tempBssid[3]; 496 | bssid[3] = tempBssid[2]; 497 | bssid[4] = tempBssid[1]; 498 | bssid[5] = tempBssid[0]; 499 | 500 | return bssid; 501 | } 502 | 503 | uint8_t WiFiClass::channel(uint8_t pos) 504 | { 505 | return _scanResults[pos].primary; 506 | } 507 | 508 | unsigned long WiFiClass::getTime() 509 | { 510 | time_t now; 511 | 512 | time(&now); 513 | 514 | if (now < 946684800) { 515 | return 0; 516 | } 517 | 518 | return now; 519 | } 520 | 521 | void WiFiClass::lowPowerMode() 522 | { 523 | esp_wifi_set_ps(WIFI_PS_MODEM); 524 | } 525 | 526 | void WiFiClass::noLowPowerMode() 527 | { 528 | esp_wifi_set_ps(WIFI_PS_NONE); 529 | } 530 | 531 | void WiFiClass::onReceive(void(*callback)(void)) 532 | { 533 | _onReceiveCallback = callback; 534 | } 535 | 536 | err_t WiFiClass::staNetifInputHandler(struct pbuf* p, struct netif* inp) 537 | { 538 | return WiFi.handleStaNetifInput(p, inp); 539 | } 540 | 541 | err_t WiFiClass::apNetifInputHandler(struct pbuf* p, struct netif* inp) 542 | { 543 | return WiFi.handleApNetifInput(p, inp); 544 | } 545 | 546 | err_t WiFiClass::handleStaNetifInput(struct pbuf* p, struct netif* inp) 547 | { 548 | err_t result = _staNetifInput(p, inp); 549 | 550 | if (_onReceiveCallback) { 551 | _onReceiveCallback(); 552 | } 553 | 554 | return result; 555 | } 556 | 557 | err_t WiFiClass::handleApNetifInput(struct pbuf* p, struct netif* inp) 558 | { 559 | err_t result = _apNetifInput(p, inp); 560 | 561 | if (_onReceiveCallback) { 562 | _onReceiveCallback(); 563 | } 564 | 565 | return result; 566 | } 567 | 568 | void WiFiClass::init() 569 | { 570 | tcpip_adapter_init(); 571 | esp_event_loop_init(WiFiClass::systemEventHandler, this); 572 | 573 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 574 | esp_wifi_init(&cfg); 575 | esp_wifi_set_storage(WIFI_STORAGE_RAM); 576 | 577 | sntp_setoperatingmode(SNTP_OPMODE_POLL); 578 | sntp_setservername(0, (char*)"0.pool.ntp.org"); 579 | sntp_setservername(1, (char*)"1.pool.ntp.org"); 580 | sntp_setservername(2, (char*)"2.pool.ntp.org"); 581 | sntp_init(); 582 | 583 | _status = WL_IDLE_STATUS; 584 | } 585 | 586 | esp_err_t WiFiClass::systemEventHandler(void* ctx, system_event_t* event) 587 | { 588 | ((WiFiClass*)ctx)->handleSystemEvent(event); 589 | 590 | return ESP_OK; 591 | } 592 | 593 | void WiFiClass::handleSystemEvent(system_event_t* event) 594 | { 595 | switch (event->event_id) { 596 | case SYSTEM_EVENT_SCAN_DONE: 597 | xEventGroupSetBits(_eventGroup, BIT2); 598 | break; 599 | 600 | case SYSTEM_EVENT_STA_START: { 601 | struct netif* staNetif; 602 | uint8_t mac[6]; 603 | char defaultHostname[13]; 604 | 605 | esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); 606 | sprintf(defaultHostname, "arduino-%.2x%.2x", mac[4], mac[5]); 607 | tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, defaultHostname); 608 | 609 | if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, (void**)&staNetif) == ESP_OK) { 610 | if (staNetif->input != WiFiClass::staNetifInputHandler) { 611 | _staNetifInput = staNetif->input; 612 | 613 | staNetif->input = WiFiClass::staNetifInputHandler; 614 | } 615 | } 616 | 617 | xEventGroupSetBits(_eventGroup, BIT0); 618 | break; 619 | } 620 | 621 | case SYSTEM_EVENT_STA_STOP: 622 | xEventGroupClearBits(_eventGroup, BIT0); 623 | break; 624 | 625 | case SYSTEM_EVENT_STA_CONNECTED: 626 | esp_wifi_sta_get_ap_info(&_apRecord); 627 | 628 | if (_ipInfo.ip.addr) { 629 | // re-apply the custom DNS settings 630 | setDNS(_dnsServers[0], _dnsServers[1]); 631 | 632 | // static IP 633 | _status = WL_CONNECTED; 634 | } 635 | break; 636 | 637 | case SYSTEM_EVENT_STA_GOT_IP: 638 | memcpy(&_ipInfo, &event->event_info.got_ip.ip_info, sizeof(_ipInfo)); 639 | _status = WL_CONNECTED; 640 | break; 641 | 642 | case SYSTEM_EVENT_STA_DISCONNECTED: { 643 | uint8_t reason = event->event_info.disconnected.reason; 644 | 645 | memset(&_apRecord, 0x00, sizeof(_apRecord)); 646 | 647 | if (reason == 201/*NO_AP_FOUND*/ || reason == 202/*AUTH_FAIL*/ || reason == 203/*ASSOC_FAIL*/) { 648 | _status = WL_CONNECT_FAILED; 649 | } else { 650 | _status = WL_DISCONNECTED; 651 | } 652 | break; 653 | } 654 | 655 | case SYSTEM_EVENT_STA_LOST_IP: 656 | memset(&_ipInfo, 0x00, sizeof(_ipInfo)); 657 | memset(&_dnsServers, 0x00, sizeof(_dnsServers)); 658 | _status = WL_CONNECTION_LOST; 659 | break; 660 | 661 | case SYSTEM_EVENT_AP_START: { 662 | struct netif* apNetif; 663 | 664 | if (tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_AP, (void**)&apNetif) == ESP_OK) { 665 | if (apNetif->input != WiFiClass::apNetifInputHandler) { 666 | _apNetifInput = apNetif->input; 667 | 668 | apNetif->input = WiFiClass::apNetifInputHandler; 669 | } 670 | } 671 | 672 | wifi_config_t config; 673 | 674 | esp_wifi_get_config(ESP_IF_WIFI_AP, &config); 675 | memcpy(_apRecord.ssid, config.ap.ssid, sizeof(config.ap.ssid)); 676 | _apRecord.authmode = config.ap.authmode; 677 | 678 | if (_ipInfo.ip.addr) { 679 | // custom static IP 680 | tcpip_adapter_dhcps_stop(TCPIP_ADAPTER_IF_AP); 681 | tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_AP, &_ipInfo); 682 | tcpip_adapter_dhcps_start(TCPIP_ADAPTER_IF_AP); 683 | 684 | // re-apply the custom DNS settings 685 | setDNS(_dnsServers[0], _dnsServers[1]); 686 | } else { 687 | tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &_ipInfo); 688 | } 689 | 690 | _status = WL_AP_LISTENING; 691 | xEventGroupSetBits(_eventGroup, BIT1); 692 | break; 693 | } 694 | 695 | case SYSTEM_EVENT_AP_STOP: 696 | _status = WL_IDLE_STATUS; 697 | memset(&_apRecord, 0x00, sizeof(_apRecord)); 698 | memset(&_ipInfo, 0x00, sizeof(_ipInfo)); 699 | xEventGroupClearBits(_eventGroup, BIT1); 700 | break; 701 | 702 | case SYSTEM_EVENT_AP_STACONNECTED: 703 | _status = WL_AP_CONNECTED; 704 | break; 705 | 706 | case SYSTEM_EVENT_AP_STADISCONNECTED: 707 | wifi_sta_list_t staList; 708 | 709 | esp_wifi_ap_get_sta_list(&staList); 710 | 711 | if (staList.num == 0) { 712 | _status = WL_AP_LISTENING; 713 | } 714 | break; 715 | 716 | default: 717 | break; 718 | } 719 | } 720 | 721 | WiFiClass WiFi; 722 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFi.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef WIFI_H 21 | #define WIFI_H 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | #include 31 | 32 | typedef enum { 33 | WL_NO_SHIELD = 255, 34 | WL_IDLE_STATUS = 0, 35 | WL_NO_SSID_AVAIL, 36 | WL_SCAN_COMPLETED, 37 | WL_CONNECTED, 38 | WL_CONNECT_FAILED, 39 | WL_CONNECTION_LOST, 40 | WL_DISCONNECTED, 41 | WL_AP_LISTENING, 42 | WL_AP_CONNECTED, 43 | WL_AP_FAILED, 44 | } wl_status_t; 45 | 46 | #define MAX_SCAN_RESULTS 10 47 | 48 | class WiFiClass 49 | { 50 | public: 51 | WiFiClass(); 52 | 53 | uint8_t begin(const char* ssid); 54 | uint8_t begin(const char* ssid, uint8_t key_idx, const char* key); 55 | uint8_t begin(const char* ssid, const char* key); 56 | 57 | uint8_t beginAP(const char *ssid, uint8_t channel); 58 | uint8_t beginAP(const char *ssid, uint8_t key_idx, const char* key, uint8_t channel); 59 | uint8_t beginAP(const char *ssid, const char* key, uint8_t channel); 60 | 61 | 62 | void config(/*IPAddress*/uint32_t local_ip, /*IPAddress*/uint32_t gateway, /*IPAddress*/uint32_t subnet); 63 | 64 | void setDNS(/*IPAddress*/uint32_t dns_server1, /*IPAddress*/uint32_t dns_server2); 65 | 66 | void hostname(const char* name); 67 | 68 | void disconnect(); 69 | void end(); 70 | 71 | uint8_t* macAddress(uint8_t* mac); 72 | 73 | uint32_t localIP(); 74 | uint32_t subnetMask(); 75 | uint32_t gatewayIP(); 76 | char* SSID(); 77 | int32_t RSSI(); 78 | uint8_t encryptionType(); 79 | uint8_t* BSSID(uint8_t* bssid); 80 | int8_t scanNetworks(); 81 | char* SSID(uint8_t pos); 82 | int32_t RSSI(uint8_t pos); 83 | uint8_t encryptionType(uint8_t pos); 84 | uint8_t* BSSID(uint8_t pos, uint8_t* bssid); 85 | uint8_t channel(uint8_t pos); 86 | 87 | uint8_t status(); 88 | 89 | int hostByName(const char* hostname, /*IPAddress*/uint32_t& result); 90 | 91 | int ping(/*IPAddress*/uint32_t host, uint8_t ttl); 92 | 93 | unsigned long getTime(); 94 | 95 | void lowPowerMode(); 96 | void noLowPowerMode(); 97 | 98 | void onReceive(void(*)(void)); 99 | 100 | private: 101 | void init(); 102 | 103 | static esp_err_t systemEventHandler(void* ctx, system_event_t* event); 104 | void handleSystemEvent(system_event_t* event); 105 | 106 | static err_t staNetifInputHandler(struct pbuf* p, struct netif* inp); 107 | static err_t apNetifInputHandler(struct pbuf* p, struct netif* inp); 108 | err_t handleStaNetifInput(struct pbuf* p, struct netif* inp); 109 | err_t handleApNetifInput(struct pbuf* p, struct netif* inp); 110 | 111 | private: 112 | bool _initialized; 113 | volatile uint8_t _status; 114 | EventGroupHandle_t _eventGroup; 115 | esp_interface_t _interface; 116 | 117 | wifi_ap_record_t _scanResults[MAX_SCAN_RESULTS]; 118 | wifi_ap_record_t _apRecord; 119 | tcpip_adapter_ip_info_t _ipInfo; 120 | uint32_t _dnsServers[2]; 121 | 122 | netif_input_fn _staNetifInput; 123 | netif_input_fn _apNetifInput; 124 | 125 | void (*_onReceiveCallback)(void); 126 | }; 127 | 128 | extern WiFiClass WiFi; 129 | 130 | #endif // WIFI_H 131 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFiClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include "WiFiClient.h" 27 | 28 | 29 | WiFiClient::WiFiClient() : 30 | WiFiClient(-1) 31 | { 32 | } 33 | 34 | WiFiClient::WiFiClient(int socket) : 35 | _socket(socket) 36 | { 37 | } 38 | 39 | int WiFiClient::connect(const char* host, uint16_t port) 40 | { 41 | struct hostent* server = gethostbyname(host); 42 | 43 | if (server == NULL) { 44 | return 0; 45 | } 46 | 47 | return connect(server->h_addr, port); 48 | } 49 | 50 | int WiFiClient::connect(/*IPAddress*/uint32_t ip, uint16_t port) 51 | { 52 | _socket = lwip_socket(AF_INET, SOCK_STREAM, 0); 53 | 54 | if (_socket < 0) { 55 | _socket = -1; 56 | return 0; 57 | } 58 | 59 | struct sockaddr_in addr; 60 | memset(&addr, 0x00, sizeof(addr)); 61 | 62 | addr.sin_family = AF_INET; 63 | addr.sin_addr.s_addr = (uint32_t)ip; 64 | addr.sin_port = htons(port); 65 | 66 | if (lwip_connect_r(_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 67 | lwip_close_r(_socket); 68 | _socket = -1; 69 | return 0; 70 | } 71 | 72 | int nonBlocking = 1; 73 | lwip_ioctl_r(_socket, FIONBIO, &nonBlocking); 74 | 75 | return 1; 76 | } 77 | 78 | size_t WiFiClient::write(uint8_t b) 79 | { 80 | return write(&b, 1); 81 | } 82 | 83 | size_t WiFiClient::write(const uint8_t *buf, size_t size) 84 | { 85 | if (_socket == -1) { 86 | return 0; 87 | } 88 | 89 | int result = lwip_send_r(_socket, (void*)buf, size, MSG_DONTWAIT); 90 | 91 | if (result < 0) { 92 | lwip_close_r(_socket); 93 | _socket = -1; 94 | return 0; 95 | } 96 | 97 | return result; 98 | } 99 | 100 | int WiFiClient::available() 101 | { 102 | if (_socket == -1) { 103 | return 0; 104 | } 105 | 106 | int result = 0; 107 | 108 | if (lwip_ioctl_r(_socket, FIONREAD, &result) < 0) { 109 | lwip_close_r(_socket); 110 | _socket = -1; 111 | return 0; 112 | } 113 | 114 | return result; 115 | } 116 | 117 | int WiFiClient::read() 118 | { 119 | uint8_t b; 120 | 121 | if (read(&b, sizeof(b)) == -1) { 122 | return -1; 123 | } 124 | 125 | return b; 126 | } 127 | 128 | int WiFiClient::read(uint8_t* buf, size_t size) 129 | { 130 | if (!available()) { 131 | return -1; 132 | } 133 | 134 | int result = lwip_recv_r(_socket, buf, size, MSG_DONTWAIT); 135 | 136 | if (result <= 0 && errno != EWOULDBLOCK) { 137 | lwip_close_r(_socket); 138 | _socket = -1; 139 | return 0; 140 | } 141 | 142 | if (result == 0) { 143 | result = -1; 144 | } 145 | 146 | return result; 147 | } 148 | 149 | int WiFiClient::peek() 150 | { 151 | uint8_t b; 152 | 153 | if (recv(_socket, &b, sizeof(b), MSG_PEEK | MSG_DONTWAIT) <= 0) { 154 | if (errno != EWOULDBLOCK) { 155 | lwip_close_r(_socket); 156 | _socket = -1; 157 | } 158 | 159 | return -1; 160 | } 161 | 162 | return b; 163 | } 164 | 165 | void WiFiClient::flush() 166 | { 167 | } 168 | 169 | void WiFiClient::stop() 170 | { 171 | if (_socket != -1) { 172 | lwip_close_r(_socket); 173 | _socket = -1; 174 | } 175 | } 176 | 177 | uint8_t WiFiClient::connected() 178 | { 179 | if (_socket != -1) { 180 | // use peek to update socket state 181 | peek(); 182 | } 183 | 184 | return (_socket != -1); 185 | } 186 | 187 | WiFiClient::operator bool() 188 | { 189 | return (_socket != -1); 190 | } 191 | 192 | bool WiFiClient::operator==(const WiFiClient &other) const 193 | { 194 | return (_socket == other._socket); 195 | } 196 | 197 | /*IPAddress*/uint32_t WiFiClient::remoteIP() 198 | { 199 | struct sockaddr_storage addr; 200 | socklen_t len = sizeof(addr); 201 | 202 | getpeername(_socket, (struct sockaddr*)&addr, &len); 203 | 204 | return ((struct sockaddr_in *)&addr)->sin_addr.s_addr; 205 | } 206 | 207 | uint16_t WiFiClient::remotePort() 208 | { 209 | struct sockaddr_storage addr; 210 | socklen_t len = sizeof(addr); 211 | 212 | getpeername(_socket, (struct sockaddr*)&addr, &len); 213 | 214 | return ntohs(((struct sockaddr_in *)&addr)->sin_port); 215 | } 216 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFiClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef WIFICLIENT_H 21 | #define WIFICLIENT_H 22 | 23 | #include 24 | // #include 25 | // #include 26 | 27 | class WiFiServer; 28 | 29 | class WiFiClient /*: public Client*/ { 30 | 31 | public: 32 | WiFiClient(); 33 | 34 | uint8_t status(); 35 | 36 | virtual int connect(/*IPAddress*/uint32_t ip, uint16_t port); 37 | virtual int connect(const char* host, uint16_t port); 38 | virtual size_t write(uint8_t); 39 | virtual size_t write(const uint8_t *buf, size_t size); 40 | virtual int available(); 41 | virtual int read(); 42 | virtual int read(uint8_t *buf, size_t size); 43 | virtual int peek(); 44 | virtual void flush(); 45 | virtual void stop(); 46 | virtual uint8_t connected(); 47 | virtual operator bool(); 48 | bool operator==(const WiFiClient &other) const; 49 | 50 | virtual /*IPAddress*/uint32_t remoteIP(); 51 | virtual uint16_t remotePort(); 52 | 53 | // using Print::write; 54 | 55 | protected: 56 | friend class WiFiServer; 57 | 58 | WiFiClient(int socket); 59 | 60 | private: 61 | int _socket; 62 | }; 63 | 64 | #endif // WIFICLIENT_H 65 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFiSSLClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include "Arduino.h" 21 | #include 22 | #include 23 | #include 24 | #include "esp_partition.h" 25 | 26 | #include "WiFiSSLClient.h" 27 | 28 | class __Guard { 29 | public: 30 | __Guard(SemaphoreHandle_t handle) { 31 | _handle = handle; 32 | 33 | xSemaphoreTakeRecursive(_handle, portMAX_DELAY); 34 | } 35 | 36 | ~__Guard() { 37 | xSemaphoreGiveRecursive(_handle); 38 | } 39 | 40 | private: 41 | SemaphoreHandle_t _handle; 42 | }; 43 | 44 | #define synchronized __Guard __guard(_mbedMutex); 45 | 46 | WiFiSSLClient::WiFiSSLClient() : 47 | _connected(false), 48 | _peek(-1) 49 | { 50 | _netContext.fd = -1; 51 | 52 | _mbedMutex = xSemaphoreCreateRecursiveMutex(); 53 | } 54 | 55 | int WiFiSSLClient::connect(const char* host, uint16_t port) 56 | { 57 | ets_printf("** Connect(host/port) Called\n"); 58 | return connect(host, port, _cert, _private_key); 59 | } 60 | 61 | int WiFiSSLClient::connect(const char* host, uint16_t port, const char* client_cert, const char* client_key) 62 | { 63 | ets_printf("** Connect(host/port/cert/key) called\n"); 64 | int ret, flags; 65 | synchronized { 66 | _netContext.fd = -1; 67 | _connected = false; 68 | 69 | ets_printf("Free internal heap before TLS %u", heap_caps_get_free_size(MALLOC_CAP_8BIT)); 70 | 71 | ets_printf("*** connect init\n"); 72 | // SSL Client Initialization 73 | mbedtls_ssl_init(&_sslContext); 74 | mbedtls_ctr_drbg_init(&_ctrDrbgContext); 75 | mbedtls_ssl_config_init(&_sslConfig); 76 | 77 | mbedtls_net_init(&_netContext); 78 | 79 | ets_printf("*** connect inited\n"); 80 | 81 | ets_printf("*** connect drbgseed\n"); 82 | mbedtls_entropy_init(&_entropyContext); 83 | // Seeds and sets up CTR_DRBG for future reseeds, pers is device personalization (esp) 84 | ret = mbedtls_ctr_drbg_seed(&_ctrDrbgContext, mbedtls_entropy_func, 85 | &_entropyContext, (const unsigned char *) pers, strlen(pers)); 86 | if (ret < 0) { 87 | ets_printf("Unable to set up mbedtls_entropy.\n"); 88 | stop(); 89 | return 0; 90 | } 91 | 92 | ets_printf("*** connect ssl hostname\n"); 93 | /* Hostname set here should match CN in server certificate */ 94 | if(mbedtls_ssl_set_hostname(&_sslContext, host) != 0) { 95 | stop(); 96 | return 0; 97 | } 98 | 99 | ets_printf("*** connect ssl config\n"); 100 | ret= mbedtls_ssl_config_defaults(&_sslConfig, MBEDTLS_SSL_IS_CLIENT, 101 | MBEDTLS_SSL_TRANSPORT_STREAM, 102 | MBEDTLS_SSL_PRESET_DEFAULT); 103 | if (ret != 0) { 104 | stop(); 105 | ets_printf("Error Setting up SSL Config: %d\n", ret); 106 | return 0; 107 | } 108 | 109 | ets_printf("*** connect authmode\n"); 110 | // we're always using the root CA cert from partition, so MBEDTLS_SSL_VERIFY_REQUIRED 111 | ets_printf("*** Loading CA Cert...\n"); 112 | mbedtls_x509_crt_init(&_caCrt); 113 | mbedtls_ssl_conf_authmode(&_sslConfig, MBEDTLS_SSL_VERIFY_REQUIRED); 114 | 115 | // setting up CA certificates from partition 116 | spi_flash_mmap_handle_t handle; 117 | const unsigned char* certs_data = {}; 118 | ets_printf("*** connect part findfirst\n"); 119 | const esp_partition_t* part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "certs"); 120 | if (part == NULL) { 121 | stop(); 122 | return 0; 123 | } 124 | 125 | ets_printf("*** connect part mmap\n"); 126 | int ret = esp_partition_mmap(part, 0, part->size, SPI_FLASH_MMAP_DATA, (const void**)&certs_data, &handle); 127 | if (ret != ESP_OK) { 128 | ets_printf("*** Error partition mmap %d\n", ret); 129 | stop(); 130 | return 0; 131 | } 132 | 133 | ets_printf("Length of certs_data: %d", strlen((char*)certs_data)+1); 134 | ets_printf("*** connect crt parse\n"); 135 | ret = mbedtls_x509_crt_parse(&_caCrt, certs_data, strlen((char*)certs_data) + 1); 136 | ets_printf("*** connect conf ca chain\n"); 137 | mbedtls_ssl_conf_ca_chain(&_sslConfig, &_caCrt, NULL); 138 | if (ret < 0) { 139 | ets_printf("*** Error parsing CA chain.\n"); 140 | stop(); 141 | return 0; 142 | } 143 | 144 | ets_printf("*** check for client_cert and client_key\n"); 145 | if (client_cert != NULL && client_key != NULL) { 146 | mbedtls_x509_crt_init(&_clientCrt); 147 | mbedtls_pk_init(&_clientKey); 148 | 149 | ets_printf("*** Loading client certificate.\n"); 150 | // note: +1 added for line ending 151 | ret = mbedtls_x509_crt_parse(&_clientCrt, (const unsigned char *)client_cert, strlen(client_cert) + 1); 152 | if (ret != 0) { 153 | ets_printf("ERROR: Client cert not parsed properly(%d)\n", ret); 154 | stop(); 155 | return 0; 156 | } 157 | 158 | ets_printf("*** Loading private key.\n"); 159 | ret = mbedtls_pk_parse_key(&_clientKey, (const unsigned char *)client_key, strlen(client_key)+1, 160 | NULL, 0); 161 | if (ret != 0) { 162 | ets_printf("ERROR: Private key not parsed properly:(%d)\n", ret); 163 | stop(); 164 | return 0; 165 | } 166 | // set own certificate chain and key 167 | ret = mbedtls_ssl_conf_own_cert(&_sslConfig, &_clientCrt, &_clientKey); 168 | if (ret != 0) { 169 | if (ret == -0x7f00) { 170 | ets_printf("ERROR: Memory allocation failed, MBEDTLS_ERR_SSL_ALLOC_FAILED"); 171 | } 172 | ets_printf("Private key not parsed properly(%d)\n", ret); 173 | stop(); 174 | return 0; 175 | } 176 | } 177 | else { 178 | ets_printf("Client certificate and key not provided.\n"); 179 | } 180 | 181 | ets_printf("*** connect conf RNG\n"); 182 | mbedtls_ssl_conf_rng(&_sslConfig, mbedtls_ctr_drbg_random, &_ctrDrbgContext); 183 | 184 | ets_printf("*** connect ssl setup\n"); 185 | if ((ret = mbedtls_ssl_setup(&_sslContext, &_sslConfig)) != 0) { 186 | if (ret == -0x7f00){ 187 | ets_printf("%s", &_clientCrt); 188 | ets_printf("Memory allocation failed (MBEDTLS_ERR_SSL_ALLOC_FAILED)\n"); 189 | ets_printf("Free internal heap: %u\n", heap_caps_get_free_size(MALLOC_CAP_8BIT)); 190 | } 191 | ets_printf("Unable to connect ssl setup %d\n", ret); 192 | stop(); 193 | return 0; 194 | } 195 | 196 | char portStr[6]; 197 | itoa(port, portStr, 10); 198 | ets_printf("*** connect netconnect\n"); 199 | if (mbedtls_net_connect(&_netContext, host, portStr, MBEDTLS_NET_PROTO_TCP) != 0) { 200 | stop(); 201 | return 0; 202 | } 203 | 204 | ets_printf("*** connect set bio\n"); 205 | mbedtls_ssl_set_bio(&_sslContext, &_netContext, mbedtls_net_send, mbedtls_net_recv, NULL); 206 | 207 | ets_printf("*** start SSL/TLS handshake...\n"); 208 | unsigned long start_handshake = millis(); 209 | // ref: https://tls.mbed.org/api/ssl_8h.html#a4a37e497cd08c896870a42b1b618186e 210 | while ((ret = mbedtls_ssl_handshake(&_sslContext)) !=0) { 211 | if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 212 | ets_printf("Error performing SSL handshake"); 213 | } 214 | if((millis() - start_handshake) > _handshake_timeout){ 215 | ets_printf("SSL Handshake Timeout\n"); 216 | stop(); 217 | return -1; 218 | } 219 | vTaskDelay(10 / portTICK_PERIOD_MS); 220 | } 221 | 222 | if (client_cert != NULL && client_key != NULL) 223 | { 224 | ets_printf("Protocol is %s Ciphersuite is %s", mbedtls_ssl_get_version(&_sslContext), mbedtls_ssl_get_ciphersuite(&_sslContext)); 225 | } 226 | ets_printf("Verifying peer X.509 certificate\n"); 227 | char buf[512]; 228 | if ((flags = mbedtls_ssl_get_verify_result(&_sslContext)) != 0) { 229 | bzero(buf, sizeof(buf)); 230 | mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); 231 | ets_printf("Failed to verify peer certificate! verification info: %s\n", buf); 232 | stop(); // invalid certificate, stop 233 | return -1; 234 | } else { 235 | ets_printf("Certificate chain verified.\n"); 236 | } 237 | 238 | ets_printf("*** ssl set nonblock\n"); 239 | mbedtls_net_set_nonblock(&_netContext); 240 | 241 | ets_printf("Free internal heap before cleanup: %u\n", heap_caps_get_free_size(MALLOC_CAP_8BIT)); 242 | // free the heap 243 | if (certs_data != NULL) { 244 | mbedtls_x509_crt_free(&_caCrt); 245 | } 246 | if (client_cert != NULL) { 247 | mbedtls_x509_crt_free(&_clientCrt); 248 | } 249 | if (client_key !=NULL) { 250 | mbedtls_pk_free(&_clientKey); 251 | } 252 | ets_printf("Free internal heap after cleanup: %u\n", heap_caps_get_free_size(MALLOC_CAP_8BIT)); 253 | _connected = true; 254 | return 1; 255 | } 256 | } 257 | 258 | int WiFiSSLClient::connect(/*IPAddress*/uint32_t ip, uint16_t port) 259 | { 260 | char ipStr[16]; 261 | 262 | 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]*/); 263 | 264 | return connect(ipStr, port); 265 | } 266 | 267 | size_t WiFiSSLClient::write(uint8_t b) 268 | { 269 | return write(&b, 1); 270 | } 271 | 272 | size_t WiFiSSLClient::write(const uint8_t *buf, size_t size) 273 | { 274 | synchronized { 275 | int written = mbedtls_ssl_write(&_sslContext, buf, size); 276 | 277 | if (written < 0) { 278 | written = 0; 279 | } 280 | 281 | return written; 282 | } 283 | } 284 | 285 | int WiFiSSLClient::available() 286 | { 287 | synchronized { 288 | int result = mbedtls_ssl_read(&_sslContext, NULL, 0); 289 | 290 | int n = mbedtls_ssl_get_bytes_avail(&_sslContext); 291 | 292 | if (n == 0 && result != 0 && result != MBEDTLS_ERR_SSL_WANT_READ) { 293 | stop(); 294 | } 295 | 296 | return n; 297 | } 298 | } 299 | 300 | int WiFiSSLClient::read() 301 | { 302 | uint8_t b; 303 | 304 | if (_peek != -1) { 305 | b = _peek; 306 | _peek = -1; 307 | } else if (read(&b, sizeof(b)) == -1) { 308 | return -1; 309 | } 310 | 311 | return b; 312 | } 313 | 314 | int WiFiSSLClient::read(uint8_t* buf, size_t size) 315 | { 316 | synchronized { 317 | if (!available()) { 318 | return -1; 319 | } 320 | 321 | int result = mbedtls_ssl_read(&_sslContext, buf, size); 322 | 323 | if (result < 0) { 324 | if (result != MBEDTLS_ERR_SSL_WANT_READ && result != MBEDTLS_ERR_SSL_WANT_WRITE) { 325 | stop(); 326 | } 327 | 328 | return -1; 329 | } 330 | 331 | return result; 332 | } 333 | } 334 | 335 | int WiFiSSLClient::peek() 336 | { 337 | if (_peek == -1) { 338 | _peek = read(); 339 | } 340 | 341 | return _peek; 342 | } 343 | 344 | void WiFiSSLClient::setCertificate(const char *client_ca) 345 | { 346 | ets_printf("\n*** Setting client certificate...\n"); 347 | _cert = client_ca; 348 | ets_printf("%s", _cert); 349 | ets_printf("\n*** Set client certificate\n"); 350 | } 351 | 352 | void WiFiSSLClient::setPrivateKey(const char *private_key) 353 | { 354 | ets_printf("Setting client private key...\n"); 355 | _private_key = private_key; 356 | ets_printf("Set client private key\n"); 357 | } 358 | 359 | void WiFiSSLClient::setHandshakeTimeout(unsigned long timeout) 360 | { 361 | _handshake_timeout = timeout * 1000; 362 | } 363 | 364 | void WiFiSSLClient::flush() 365 | { 366 | } 367 | 368 | void WiFiSSLClient::stop() 369 | { 370 | synchronized { 371 | if (_netContext.fd > 0) { 372 | mbedtls_ssl_session_reset(&_sslContext); 373 | 374 | mbedtls_net_free(&_netContext); 375 | mbedtls_x509_crt_free(&_caCrt); 376 | mbedtls_x509_crt_free(&_clientCrt); 377 | mbedtls_pk_free(&_clientKey); 378 | mbedtls_entropy_free(&_entropyContext); 379 | mbedtls_ssl_config_free(&_sslConfig); 380 | mbedtls_ctr_drbg_free(&_ctrDrbgContext); 381 | mbedtls_ssl_free(&_sslContext); 382 | } 383 | 384 | _connected = false; 385 | _netContext.fd = -1; 386 | } 387 | 388 | vTaskDelay(1); 389 | } 390 | 391 | uint8_t WiFiSSLClient::connected() 392 | { 393 | synchronized { 394 | if (!_connected) { 395 | return 0; 396 | } 397 | 398 | if (available()) { 399 | return 1; 400 | } 401 | 402 | return 1; 403 | } 404 | } 405 | 406 | WiFiSSLClient::operator bool() 407 | { 408 | return ((_netContext.fd != -1) && _connected); 409 | } 410 | 411 | /*IPAddress*/uint32_t WiFiSSLClient::remoteIP() 412 | { 413 | struct sockaddr_storage addr; 414 | socklen_t len = sizeof(addr); 415 | 416 | getpeername(_netContext.fd, (struct sockaddr*)&addr, &len); 417 | 418 | return ((struct sockaddr_in *)&addr)->sin_addr.s_addr; 419 | } 420 | 421 | uint16_t WiFiSSLClient::remotePort() 422 | { 423 | struct sockaddr_storage addr; 424 | socklen_t len = sizeof(addr); 425 | 426 | getpeername(_netContext.fd, (struct sockaddr*)&addr, &len); 427 | 428 | return ntohs(((struct sockaddr_in *)&addr)->sin_port); 429 | } 430 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFiSSLClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef WIFISSLCLIENT_H 21 | #define WIFISSLCLIENT_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | 34 | class WiFiSSLClient /*: public Client*/ { 35 | 36 | public: 37 | WiFiSSLClient(); 38 | 39 | uint8_t status(); 40 | 41 | virtual int connect(/*IPAddress*/uint32_t ip, uint16_t port); 42 | virtual int connect(const char* host, uint16_t port); 43 | virtual int connect(const char* host, uint16_t port, const char* client_cert, const char* client_key); 44 | virtual size_t write(uint8_t); 45 | virtual size_t write(const uint8_t *buf, size_t size); 46 | virtual int available(); 47 | virtual int read(); 48 | virtual int read(uint8_t *buf, size_t size); 49 | virtual int peek(); 50 | virtual void flush(); 51 | virtual void stop(); 52 | virtual uint8_t connected(); 53 | virtual operator bool(); 54 | virtual void setCertificate(const char *client_ca); 55 | virtual void setPrivateKey (const char *private_key); 56 | virtual void setHandshakeTimeout(unsigned long timeout); 57 | 58 | // using Print::write; 59 | 60 | virtual /*IPAddress*/uint32_t remoteIP(); 61 | virtual uint16_t remotePort(); 62 | const char *pers = "esp32-tls"; 63 | 64 | private: 65 | static const char* ROOT_CAs; 66 | const char *_cert; // user-provided certificate 67 | const char *_private_key; // user-provided private 68 | 69 | mbedtls_entropy_context _entropyContext; 70 | mbedtls_ctr_drbg_context _ctrDrbgContext; 71 | mbedtls_ssl_context _sslContext; 72 | mbedtls_ssl_config _sslConfig; 73 | mbedtls_net_context _netContext; 74 | mbedtls_x509_crt _caCrt; 75 | mbedtls_x509_crt _clientCrt; 76 | mbedtls_pk_context _clientKey; 77 | bool _connected; 78 | int _peek; 79 | unsigned long _handshake_timeout = 120000; 80 | 81 | SemaphoreHandle_t _mbedMutex; 82 | }; 83 | 84 | #endif /* WIFISSLCLIENT_H */ 85 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFiServer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "WiFiClient.h" 26 | #include "WiFiServer.h" 27 | 28 | WiFiServer::WiFiServer() : 29 | WiFiServer(0) 30 | { 31 | } 32 | 33 | WiFiServer::WiFiServer(uint16_t port) : 34 | _port(port), 35 | _socket(-1) 36 | { 37 | for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { 38 | _spawnedSockets[i] = -1; 39 | } 40 | } 41 | 42 | void WiFiServer::begin() 43 | { 44 | _socket = lwip_socket(AF_INET, SOCK_STREAM, 0); 45 | 46 | if (_socket < 0) { 47 | return; 48 | } 49 | 50 | struct sockaddr_in addr; 51 | memset(&addr, 0x00, sizeof(addr)); 52 | 53 | addr.sin_family = AF_INET; 54 | addr.sin_addr.s_addr = (uint32_t)0; 55 | addr.sin_port = htons(_port); 56 | 57 | if (lwip_bind(_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 58 | lwip_close_r(_socket); 59 | _socket = -1; 60 | return; 61 | } 62 | 63 | if (lwip_listen(_socket, 1) < 0) { 64 | lwip_close_r(_socket); 65 | _socket = -1; 66 | return; 67 | } 68 | 69 | int nonBlocking = 1; 70 | lwip_ioctl_r(_socket, FIONBIO, &nonBlocking); 71 | 72 | return; 73 | } 74 | 75 | WiFiClient WiFiServer::available(uint8_t* status) 76 | { 77 | int result = lwip_accept(_socket, NULL, 0); 78 | 79 | if (status) { 80 | *status = (result != -1); 81 | } 82 | 83 | if (result != -1) { 84 | // store the connected socket 85 | for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { 86 | if (_spawnedSockets[i] == -1) { 87 | _spawnedSockets[i] = result; 88 | break; 89 | } 90 | } 91 | } 92 | 93 | result = -1; 94 | 95 | // find an existing socket with data 96 | for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { 97 | if (_spawnedSockets[i] != -1) { 98 | WiFiClient c(_spawnedSockets[i]); 99 | 100 | if (!c.connected()) { 101 | // socket not connected, clear from book keeping 102 | _spawnedSockets[i] = -1; 103 | } else if (c.available()) { 104 | result = _spawnedSockets[i]; 105 | 106 | break; 107 | } 108 | } 109 | } 110 | 111 | return WiFiClient(result); 112 | } 113 | 114 | uint8_t WiFiServer::status() { 115 | // Deprecated. 116 | return 0; 117 | } 118 | 119 | size_t WiFiServer::write(uint8_t b) 120 | { 121 | return write(&b, 1); 122 | } 123 | 124 | size_t WiFiServer::write(const uint8_t *buffer, size_t size) 125 | { 126 | size_t written = 0; 127 | 128 | for (int i = 0; i < CONFIG_LWIP_MAX_SOCKETS; i++) { 129 | if (_spawnedSockets[i] != -1) { 130 | WiFiClient c(_spawnedSockets[i]); 131 | 132 | written += c.write(buffer, size); 133 | } 134 | } 135 | 136 | return written; 137 | } 138 | 139 | WiFiServer::operator bool() 140 | { 141 | return (_port != 0 && _socket != -1); 142 | } 143 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFiServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef WIFISERVER_H 21 | #define WIFISERVER_H 22 | 23 | #include 24 | 25 | #include 26 | // #include 27 | 28 | class WiFiClient; 29 | 30 | class WiFiServer /*: public Server*/ { 31 | public: 32 | WiFiServer(); 33 | WiFiServer(uint16_t); 34 | WiFiClient available(uint8_t* status = NULL); 35 | void begin(); 36 | virtual size_t write(uint8_t); 37 | virtual size_t write(const uint8_t *buf, size_t size); 38 | uint8_t status(); 39 | 40 | // using Print::write; 41 | 42 | virtual operator bool(); 43 | 44 | private: 45 | uint16_t _port; 46 | int _socket; 47 | int _spawnedSockets[CONFIG_LWIP_MAX_SOCKETS]; 48 | }; 49 | 50 | #endif // WIFISERVER_H 51 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFiUdp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include "WiFiUdp.h" 27 | 28 | WiFiUDP::WiFiUDP() : 29 | _socket(-1), 30 | _remoteIp(0), 31 | _remotePort(0), 32 | _rcvIndex(0), 33 | _rcvSize(0), 34 | _sndSize(0) 35 | { 36 | } 37 | 38 | uint8_t WiFiUDP::begin() 39 | { 40 | if(_socket <0) 41 | _socket = lwip_socket(AF_INET, SOCK_DGRAM, 0); 42 | 43 | if (_socket < 0) { 44 | return 0; 45 | } 46 | return 1; 47 | } 48 | 49 | uint8_t WiFiUDP::begin(uint16_t port) 50 | { 51 | if(_socket <0) 52 | _socket = lwip_socket(AF_INET, SOCK_DGRAM, 0); 53 | 54 | if (_socket < 0) { 55 | return 0; 56 | } 57 | 58 | struct sockaddr_in addr; 59 | memset(&addr, 0x00, sizeof(addr)); 60 | 61 | addr.sin_family = AF_INET; 62 | addr.sin_addr.s_addr = (uint32_t)0; 63 | addr.sin_port = htons(port); 64 | 65 | if (lwip_bind(_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 66 | lwip_close_r(_socket); 67 | _socket = -1; 68 | return 0; 69 | } 70 | 71 | int nonBlocking = 1; 72 | lwip_ioctl_r(_socket, FIONBIO, &nonBlocking); 73 | 74 | return 1; 75 | } 76 | 77 | uint8_t WiFiUDP::beginMulticast(/*IPAddress*/uint32_t ip, uint16_t port) 78 | { 79 | if (!begin(port)) { 80 | return 0; 81 | } 82 | 83 | struct ip_mreq multi; 84 | 85 | multi.imr_multiaddr.s_addr = (uint32_t)ip; 86 | multi.imr_interface.s_addr = (uint32_t)0; 87 | 88 | lwip_setsockopt_r(_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multi, sizeof(multi)); 89 | 90 | return 1; 91 | } 92 | 93 | /* return number of bytes available in the current packet, 94 | will return zero if parsePacket hasn't been called yet */ 95 | int WiFiUDP::available() 96 | { 97 | return (_rcvSize - _rcvIndex); 98 | } 99 | 100 | /* Release any resources being used by this WiFiUDP instance */ 101 | void WiFiUDP::stop() 102 | { 103 | lwip_close_r(_socket); 104 | _socket = -1; 105 | } 106 | 107 | int WiFiUDP::beginPacket(const char *host, uint16_t port) 108 | { 109 | struct hostent* server = gethostbyname(host); 110 | 111 | if (server == NULL) { 112 | return 0; 113 | } 114 | 115 | return beginPacket(server->h_addr, port); 116 | } 117 | 118 | int WiFiUDP::beginPacket(/*IPAddress*/uint32_t ip, uint16_t port) 119 | { 120 | _remoteIp = ip; 121 | _remotePort = port; 122 | 123 | _sndSize = 0; 124 | 125 | return 1; 126 | } 127 | 128 | int WiFiUDP::endPacket() 129 | { 130 | struct sockaddr_in addr; 131 | memset(&addr, 0x00, sizeof(addr)); 132 | 133 | addr.sin_family = AF_INET; 134 | addr.sin_addr.s_addr = _remoteIp; 135 | addr.sin_port = htons(_remotePort); 136 | 137 | if (lwip_sendto(_socket, _sndBuffer, _sndSize, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 138 | return 0; 139 | } 140 | 141 | return 1; 142 | } 143 | 144 | size_t WiFiUDP::write(uint8_t byte) 145 | { 146 | return write(&byte, 1); 147 | } 148 | 149 | size_t WiFiUDP::write(const uint8_t *buffer, size_t size) 150 | { 151 | size_t written = size; 152 | 153 | if ((_sndSize + size) > sizeof(_sndBuffer)) { 154 | written = sizeof(_sndBuffer) - _sndSize; 155 | } 156 | 157 | memcpy(&_sndBuffer[_sndSize], buffer, size); 158 | 159 | _sndSize += written; 160 | 161 | return written; 162 | } 163 | 164 | int WiFiUDP::parsePacket() 165 | { 166 | struct sockaddr_in addr; 167 | socklen_t addrLen = sizeof(addr); 168 | 169 | _rcvIndex = 0; 170 | _rcvSize = 0; 171 | 172 | int result = lwip_recvfrom_r(_socket, _rcvBuffer, sizeof(_rcvBuffer), MSG_DONTWAIT, (struct sockaddr*)&addr, &addrLen); 173 | 174 | if (result <= 0) { 175 | return 0; 176 | } 177 | 178 | _rcvSize = result; 179 | _remoteIp = addr.sin_addr.s_addr; 180 | _remotePort = ntohs(addr.sin_port); 181 | 182 | return result; 183 | } 184 | 185 | int WiFiUDP::read() 186 | { 187 | uint8_t b; 188 | 189 | if (read(&b, sizeof(b)) < 1) { 190 | return -1; 191 | } 192 | 193 | return b; 194 | } 195 | 196 | int WiFiUDP::read(unsigned char* buf, size_t size) 197 | { 198 | if (available() < (int)size) { 199 | size = available(); 200 | } 201 | 202 | memcpy(buf, &_rcvBuffer[_rcvIndex], size); 203 | 204 | _rcvIndex += size; 205 | 206 | return size; 207 | } 208 | 209 | int WiFiUDP::peek() 210 | { 211 | if (!available()) { 212 | return -1; 213 | } 214 | 215 | return _rcvBuffer[_rcvIndex]; 216 | } 217 | 218 | void WiFiUDP::flush() 219 | { 220 | } 221 | 222 | /*IPAddress*/uint32_t WiFiUDP::remoteIP() 223 | { 224 | return _remoteIp; 225 | } 226 | 227 | uint16_t WiFiUDP::remotePort() 228 | { 229 | return _remotePort; 230 | } 231 | -------------------------------------------------------------------------------- /arduino/libraries/WiFi/src/WiFiUdp.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef WIFIUDP_H 21 | #define WIFIUDP_H 22 | 23 | // #include 24 | 25 | class WiFiUDP /*: public UDP*/ { 26 | 27 | public: 28 | WiFiUDP(); 29 | virtual uint8_t begin(); 30 | virtual uint8_t begin(uint16_t); 31 | virtual uint8_t beginMulticast(/*IPAddress*/uint32_t, uint16_t); 32 | virtual void stop(); 33 | 34 | virtual int beginPacket(/*IPAddress*/uint32_t ip, uint16_t port); 35 | virtual int beginPacket(const char *host, uint16_t port); 36 | virtual int endPacket(); 37 | virtual size_t write(uint8_t); 38 | virtual size_t write(const uint8_t *buffer, size_t size); 39 | 40 | // using Print::write; 41 | 42 | virtual int parsePacket(); 43 | virtual int available(); 44 | virtual int read(); 45 | virtual int read(unsigned char* buffer, size_t len); 46 | virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; 47 | virtual int peek(); 48 | virtual void flush(); 49 | 50 | virtual /*IPAddress*/ uint32_t remoteIP(); 51 | virtual uint16_t remotePort(); 52 | 53 | virtual operator bool() { return _socket != -1; } 54 | 55 | private: 56 | int _socket; 57 | uint32_t _remoteIp; 58 | uint16_t _remotePort; 59 | 60 | uint8_t _rcvBuffer[1500]; 61 | uint16_t _rcvIndex; 62 | uint16_t _rcvSize; 63 | uint8_t _sndBuffer[1500]; 64 | uint16_t _sndSize; 65 | }; 66 | 67 | #endif // WIFIUDP_H 68 | -------------------------------------------------------------------------------- /combine.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys; 4 | 5 | booloaderData = open("build/bootloader/bootloader.bin", "rb").read() 6 | partitionData = open("build/partitions.bin", "rb").read() 7 | appData = open("build/nina-fw.bin", "rb").read() 8 | certsData = open("data/roots.pem", "rb").read() 9 | 10 | # calculate the output binary size, app offset 11 | outputSize = 0x30000 + len(appData) 12 | if (outputSize % 1024): 13 | outputSize += 1024 - (outputSize % 1024) 14 | 15 | # allocate and init to 0xff 16 | outputData = bytearray(b'\xff') * outputSize 17 | 18 | # copy data: bootloader, partitions, app 19 | for i in range(0, len(booloaderData)): 20 | outputData[0x1000 + i] = booloaderData[i] 21 | 22 | for i in range(0, len(partitionData)): 23 | outputData[0x8000 + i] = partitionData[i] 24 | 25 | for i in range(0, len(appData)): 26 | outputData[0x30000 + i] = appData[i] 27 | 28 | for i in range(0, len(certsData)): 29 | outputData[0x10000 + i] = certsData[i] 30 | 31 | # zero terminate the pem file 32 | outputData[0x10000 + len(certsData)] = 0 33 | 34 | outputFilename = "NINA_W102-1.4.0.bin" 35 | if (len(sys.argv) > 1): 36 | outputFilename = sys.argv[1] 37 | 38 | # write out 39 | with open(outputFilename,"w+b") as f: 40 | f.seek(0) 41 | f.write(outputData) 42 | -------------------------------------------------------------------------------- /data/roots.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU 3 | MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs 4 | IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 5 | MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux 6 | FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h 7 | bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v 8 | dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt 9 | H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 10 | uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX 11 | mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX 12 | a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN 13 | E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 14 | WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD 15 | VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 16 | Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU 17 | cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx 18 | IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN 19 | AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH 20 | YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 21 | 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC 22 | Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX 23 | c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a 24 | mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= 25 | -----END CERTIFICATE----- 26 | -----BEGIN CERTIFICATE----- 27 | MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ 28 | RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD 29 | VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX 30 | DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y 31 | ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy 32 | VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr 33 | mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr 34 | IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK 35 | mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu 36 | XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy 37 | dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye 38 | jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 39 | BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 40 | DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 41 | 9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx 42 | jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 43 | Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz 44 | ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS 45 | R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp 46 | -----END CERTIFICATE----- 47 | -----BEGIN CERTIFICATE----- 48 | MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB 49 | hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G 50 | A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV 51 | BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 52 | MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT 53 | EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR 54 | Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh 55 | dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR 56 | 6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X 57 | pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC 58 | 9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV 59 | /erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf 60 | Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z 61 | +pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w 62 | qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah 63 | SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC 64 | u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf 65 | Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq 66 | crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E 67 | FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB 68 | /wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl 69 | wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM 70 | 4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV 71 | 2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna 72 | FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ 73 | CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK 74 | boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke 75 | jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL 76 | S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb 77 | QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl 78 | 0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB 79 | NVOFBkpdn627G190 80 | -----END CERTIFICATE----- 81 | -----BEGIN CERTIFICATE----- 82 | MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ 83 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT 84 | DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow 85 | PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD 86 | Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 87 | AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O 88 | rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq 89 | OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b 90 | xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 91 | 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD 92 | aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV 93 | HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG 94 | SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 95 | ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr 96 | AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz 97 | R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 98 | JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo 99 | Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ 100 | -----END CERTIFICATE----- 101 | -----BEGIN CERTIFICATE----- 102 | MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs 103 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 104 | d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j 105 | ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL 106 | MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 107 | LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug 108 | RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm 109 | +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW 110 | PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM 111 | xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB 112 | Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 113 | hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg 114 | EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF 115 | MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA 116 | FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec 117 | nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z 118 | eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF 119 | hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 120 | Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe 121 | vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep 122 | +OkuE6N36B9K 123 | -----END CERTIFICATE----- 124 | -----BEGIN CERTIFICATE----- 125 | MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC 126 | VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 127 | Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW 128 | KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl 129 | cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw 130 | NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw 131 | NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy 132 | ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV 133 | BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ 134 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo 135 | Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 136 | 4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 137 | KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI 138 | rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi 139 | 94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB 140 | sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi 141 | gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo 142 | kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE 143 | vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA 144 | A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t 145 | O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua 146 | AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP 147 | 9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ 148 | eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m 149 | 0vdXcDazv/wor3ElhVsT/h5/WrQ8 150 | -----END CERTIFICATE----- 151 | -----BEGIN CERTIFICATE----- 152 | MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV 153 | UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy 154 | dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 155 | MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx 156 | dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B 157 | AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f 158 | BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A 159 | cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC 160 | AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ 161 | MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm 162 | aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw 163 | ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj 164 | IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF 165 | MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA 166 | A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 167 | 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 168 | 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 169 | -----END CERTIFICATE----- 170 | -----BEGIN CERTIFICATE----- 171 | MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT 172 | MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i 173 | YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG 174 | EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg 175 | R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 176 | 9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq 177 | fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv 178 | iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU 179 | 1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ 180 | bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW 181 | MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA 182 | ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l 183 | uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn 184 | Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS 185 | tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF 186 | PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un 187 | hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV 188 | 5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== 189 | -----END CERTIFICATE----- 190 | -----BEGIN CERTIFICATE----- 191 | MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB 192 | mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT 193 | MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s 194 | eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv 195 | cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ 196 | BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg 197 | MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 198 | BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg 199 | LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz 200 | +uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm 201 | hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn 202 | 5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W 203 | JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL 204 | DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC 205 | huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw 206 | HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB 207 | AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB 208 | zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN 209 | kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD 210 | AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH 211 | SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G 212 | spki4cErx5z481+oghLrGREt 213 | -----END CERTIFICATE----- 214 | -----BEGIN CERTIFICATE----- 215 | MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G 216 | A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp 217 | Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 218 | MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG 219 | A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI 220 | hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL 221 | v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 222 | eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq 223 | tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd 224 | C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa 225 | zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB 226 | mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH 227 | V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n 228 | bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG 229 | 3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs 230 | J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO 231 | 291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS 232 | ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd 233 | AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 234 | TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== 235 | -----END CERTIFICATE----- 236 | -----BEGIN CERTIFICATE----- 237 | MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx 238 | EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT 239 | EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp 240 | ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz 241 | NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH 242 | EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE 243 | AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw 244 | DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD 245 | E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH 246 | /PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy 247 | DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh 248 | GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR 249 | tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA 250 | AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE 251 | FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX 252 | WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu 253 | 9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr 254 | gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo 255 | 2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO 256 | LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI 257 | 4uJEvlz36hz1 258 | -----END CERTIFICATE----- 259 | -----BEGIN CERTIFICATE----- 260 | MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB 261 | yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL 262 | ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp 263 | U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW 264 | ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 265 | aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL 266 | MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW 267 | ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln 268 | biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp 269 | U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y 270 | aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 271 | nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex 272 | t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz 273 | SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG 274 | BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ 275 | rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ 276 | NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E 277 | BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH 278 | BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy 279 | aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv 280 | MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE 281 | p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 282 | 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK 283 | WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 284 | 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N 285 | hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq 286 | -----END CERTIFICATE----- 287 | -----BEGIN CERTIFICATE----- 288 | MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb 289 | MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow 290 | GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj 291 | YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL 292 | MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE 293 | BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM 294 | GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP 295 | ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua 296 | BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe 297 | 3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 298 | YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR 299 | rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm 300 | ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU 301 | oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF 302 | MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v 303 | QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t 304 | b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF 305 | AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q 306 | GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz 307 | Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 308 | G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi 309 | l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 310 | smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== 311 | -----END CERTIFICATE----- 312 | -----BEGIN CERTIFICATE----- 313 | MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB 314 | gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G 315 | A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV 316 | BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw 317 | MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl 318 | YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P 319 | RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 320 | aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 321 | UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI 322 | 2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 323 | Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp 324 | +2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ 325 | DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O 326 | nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW 327 | /zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g 328 | PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u 329 | QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY 330 | SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv 331 | IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ 332 | RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 333 | zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd 334 | BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB 335 | ZQ== 336 | -----END CERTIFICATE----- 337 | -----BEGIN CERTIFICATE----- 338 | MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL 339 | MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE 340 | BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT 341 | IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw 342 | MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy 343 | ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N 344 | T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv 345 | biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR 346 | FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J 347 | cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW 348 | BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ 349 | BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm 350 | fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv 351 | GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= 352 | -----END CERTIFICATE----- 353 | -----BEGIN CERTIFICATE----- 354 | MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL 355 | MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl 356 | eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT 357 | JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx 358 | MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT 359 | Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg 360 | VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm 361 | aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo 362 | I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng 363 | o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G 364 | A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD 365 | VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB 366 | zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW 367 | RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= 368 | -----END CERTIFICATE----- 369 | -----BEGIN CERTIFICATE----- 370 | MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB 371 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 372 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 373 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw 374 | MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV 375 | BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU 376 | aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy 377 | dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK 378 | AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B 379 | 3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY 380 | tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ 381 | Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 382 | VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT 383 | 79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 384 | c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT 385 | Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l 386 | c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee 387 | UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE 388 | Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd 389 | BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G 390 | A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF 391 | Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO 392 | VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 393 | ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs 394 | 8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR 395 | iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze 396 | Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ 397 | XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ 398 | qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB 399 | VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB 400 | L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG 401 | jjxDah2nGN59PRbxYvnKkKj9 402 | -----END CERTIFICATE----- 403 | -----BEGIN CERTIFICATE----- 404 | MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG 405 | A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh 406 | bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE 407 | ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS 408 | b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 409 | 7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS 410 | J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y 411 | HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP 412 | t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz 413 | FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY 414 | XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ 415 | MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw 416 | hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js 417 | MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA 418 | A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj 419 | Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx 420 | XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o 421 | omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc 422 | A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW 423 | WL1WMRJOEcgh4LMRkWXbtKaIOM5V 424 | -----END CERTIFICATE----- 425 | -----BEGIN CERTIFICATE----- 426 | MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl 427 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 428 | d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv 429 | b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG 430 | EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl 431 | cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi 432 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c 433 | JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP 434 | mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ 435 | wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 436 | VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ 437 | AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB 438 | AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW 439 | BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun 440 | pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC 441 | dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf 442 | fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm 443 | NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx 444 | H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe 445 | +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== 446 | -----END CERTIFICATE----- 447 | -----BEGIN CERTIFICATE----- 448 | MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl 449 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 450 | d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv 451 | b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG 452 | EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl 453 | cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi 454 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA 455 | n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc 456 | biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp 457 | EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA 458 | bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu 459 | YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB 460 | AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW 461 | BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI 462 | QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I 463 | 0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni 464 | lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 465 | B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv 466 | ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo 467 | IhNzbM8m9Yop5w== 468 | -----END CERTIFICATE----- 469 | -----BEGIN CERTIFICATE----- 470 | MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw 471 | CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu 472 | ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg 473 | RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV 474 | UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu 475 | Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq 476 | hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf 477 | Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q 478 | RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ 479 | BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD 480 | AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY 481 | JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv 482 | 6pZjamVFkpUBtA== 483 | -----END CERTIFICATE----- 484 | -----BEGIN CERTIFICATE----- 485 | MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh 486 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 487 | d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD 488 | QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT 489 | MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j 490 | b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG 491 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB 492 | CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 493 | nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt 494 | 43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P 495 | T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 496 | gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO 497 | BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR 498 | TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw 499 | DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr 500 | hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg 501 | 06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF 502 | PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls 503 | YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk 504 | CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= 505 | -----END CERTIFICATE----- 506 | -----BEGIN CERTIFICATE----- 507 | MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh 508 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 509 | d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH 510 | MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT 511 | MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j 512 | b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG 513 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI 514 | 2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx 515 | 1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ 516 | q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz 517 | tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ 518 | vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP 519 | BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV 520 | 5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY 521 | 1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 522 | NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG 523 | Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 524 | 8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe 525 | pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl 526 | MrY= 527 | -----END CERTIFICATE----- 528 | -----BEGIN CERTIFICATE----- 529 | MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw 530 | CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu 531 | ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe 532 | Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw 533 | EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x 534 | IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF 535 | K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG 536 | fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO 537 | Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd 538 | BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx 539 | AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ 540 | oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 541 | sycX 542 | -----END CERTIFICATE----- 543 | -----BEGIN CERTIFICATE----- 544 | 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 574 | -----END CERTIFICATE----- 575 | -----BEGIN CERTIFICATE----- 576 | MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG 577 | A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 578 | d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu 579 | dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq 580 | RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy 581 | MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD 582 | VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 583 | L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g 584 | Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD 585 | ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi 586 | A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt 587 | ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH 588 | Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O 589 | BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC 590 | R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX 591 | hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G 592 | -----END CERTIFICATE----- 593 | -----BEGIN CERTIFICATE----- 594 | MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC 595 | VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 596 | cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs 597 | IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz 598 | dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy 599 | NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu 600 | dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt 601 | dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 602 | aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj 603 | YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 604 | AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T 605 | RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN 606 | cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW 607 | wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 608 | U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 609 | jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP 610 | BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN 611 | BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ 612 | jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ 613 | Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v 614 | 1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R 615 | nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH 616 | VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== 617 | -----END CERTIFICATE----- 618 | -----BEGIN CERTIFICATE----- 619 | MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML 620 | RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp 621 | bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 622 | IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp 623 | ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 624 | MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 625 | LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp 626 | YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG 627 | A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp 628 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq 629 | K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe 630 | sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX 631 | MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT 632 | XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ 633 | HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH 634 | 4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV 635 | HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub 636 | j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo 637 | U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf 638 | zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b 639 | u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ 640 | bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er 641 | fF6adulZkMV8gzURZVE= 642 | -----END CERTIFICATE----- 643 | -----BEGIN CERTIFICATE----- 644 | MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE 645 | BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz 646 | dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL 647 | MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp 648 | cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC 649 | AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP 650 | Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr 651 | ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL 652 | MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 653 | yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr 654 | VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ 655 | nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ 656 | KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG 657 | XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj 658 | vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt 659 | Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g 660 | N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC 661 | nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= 662 | -----END CERTIFICATE----- 663 | -----BEGIN CERTIFICATE----- 664 | MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE 665 | BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz 666 | dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL 667 | MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp 668 | cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC 669 | AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y 670 | YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua 671 | kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL 672 | QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp 673 | 6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG 674 | yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i 675 | QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ 676 | KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO 677 | tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu 678 | QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ 679 | Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u 680 | olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 681 | x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= 682 | -----END CERTIFICATE----- 683 | -----BEGIN CERTIFICATE----- 684 | MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE 685 | BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz 686 | dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG 687 | A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U 688 | cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf 689 | qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ 690 | JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ 691 | +jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS 692 | s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 693 | HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 694 | 70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG 695 | V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S 696 | qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S 697 | 5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia 698 | C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX 699 | OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE 700 | FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ 701 | BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 702 | KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg 703 | Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B 704 | 8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ 705 | MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc 706 | 0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ 707 | u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF 708 | u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH 709 | YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 710 | GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO 711 | RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e 712 | KeC2uAloGRwYQw== 713 | -----END CERTIFICATE----- 714 | -----BEGIN CERTIFICATE----- 715 | MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC 716 | VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ 717 | cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ 718 | BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt 719 | VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D 720 | 0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 721 | ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G 722 | A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G 723 | A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs 724 | aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I 725 | flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== 726 | -----END CERTIFICATE----- 727 | -----BEGIN CERTIFICATE----- 728 | MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG 729 | A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv 730 | b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw 731 | MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i 732 | YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT 733 | aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ 734 | jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp 735 | xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 736 | 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG 737 | snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ 738 | U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 739 | 9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E 740 | BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B 741 | AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz 742 | yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE 743 | 38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP 744 | AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad 745 | DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME 746 | HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== 747 | -----END CERTIFICATE----- 748 | -----BEGIN CERTIFICATE----- 749 | MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G 750 | A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp 751 | Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 752 | MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG 753 | A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI 754 | hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 755 | RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT 756 | gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm 757 | KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd 758 | QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ 759 | XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw 760 | DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o 761 | LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU 762 | RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp 763 | jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK 764 | 6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX 765 | mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs 766 | Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH 767 | WD9f 768 | -----END CERTIFICATE----- 769 | -----BEGIN CERTIFICATE----- 770 | MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk 771 | MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH 772 | bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX 773 | DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD 774 | QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu 775 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc 776 | 8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke 777 | hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD 778 | VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI 779 | KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg 780 | 515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO 781 | xwy8p2Fp8fc74SrL+SvzZpA3 782 | -----END CERTIFICATE----- 783 | -----BEGIN CERTIFICATE----- 784 | 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 813 | 5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= 814 | -----END CERTIFICATE----- 815 | -----BEGIN CERTIFICATE----- 816 | MIICMzCCAbmgAwIBAgIOSBtqCfT5YHE6/oHMht0wCgYIKoZIzj0EAwMwXDELMAkG 817 | A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv 818 | b3QgQ0ExIDAeBgNVBAMTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFI4MB4XDTE2MDYx 819 | NTAwMDAwMFoXDTM2MDYxNTAwMDAwMFowXDELMAkGA1UEBhMCQkUxGTAXBgNVBAoT 820 | EEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExIDAeBgNVBAMTF0ds 821 | b2JhbFNpZ24gUm9vdCBDQSAtIFI4MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEuO58 822 | MIfYlB9Ua22Ynfx1+1uIq0K6jX05ft1EPTk84QWhSmRgrDemc7D5yUVLCwbQOuDx 823 | bV/6XltaUrV240bb1R6MdHpCyUE1T8bU4ihgqzSKzrFAI0alrhkkUnyQVUTOo0Iw 824 | QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULzoS 825 | JoDoisJQeG0GxDR+4kk5V3YwCgYIKoZIzj0EAwMDaAAwZQIxAMehPbKSkPrKXeAn 826 | hII7Icz0jfiUVvIgXxHArLxfFaULyBZDp/jFf40goH9e/BYcJwIwHoz1Vr8425zm 827 | pteEKebfDVMu6CsBt30JPLEyahqauArq6K0I8nQ51SsiNtzvRmbY 828 | -----END CERTIFICATE----- 829 | -----BEGIN CERTIFICATE----- 830 | MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx 831 | EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT 832 | HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs 833 | ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw 834 | MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 835 | b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj 836 | aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp 837 | Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 838 | ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg 839 | nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 840 | HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N 841 | Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN 842 | dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 843 | HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO 844 | BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G 845 | CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU 846 | sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 847 | 4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg 848 | 8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K 849 | pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 850 | mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 851 | -----END CERTIFICATE----- 852 | -----BEGIN CERTIFICATE----- 853 | MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl 854 | MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp 855 | U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw 856 | NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE 857 | ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp 858 | ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 859 | DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf 860 | 8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN 861 | +lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 862 | X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa 863 | K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA 864 | 1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G 865 | A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR 866 | zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 867 | YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD 868 | bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w 869 | DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 870 | L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D 871 | eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl 872 | xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp 873 | VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY 874 | WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= 875 | -----END CERTIFICATE----- 876 | -----BEGIN CERTIFICATE----- 877 | MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh 878 | MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE 879 | YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 880 | MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo 881 | ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg 882 | MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN 883 | ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA 884 | PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w 885 | wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi 886 | EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY 887 | avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ 888 | YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE 889 | sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h 890 | /t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 891 | IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj 892 | YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD 893 | ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy 894 | OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P 895 | TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ 896 | HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER 897 | dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf 898 | ReYNnyicsbkqWletNw+vHX/bvZ8= 899 | -----END CERTIFICATE----- 900 | -----BEGIN CERTIFICATE----- 901 | MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk 902 | MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH 903 | bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX 904 | DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD 905 | QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu 906 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ 907 | FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw 908 | DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F 909 | uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX 910 | kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs 911 | ewv4n4Q= 912 | -----END CERTIFICATE----- 913 | -----BEGIN CERTIFICATE----- 914 | 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 943 | -----END CERTIFICATE----- 944 | -----BEGIN CERTIFICATE----- 945 | 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 974 | -----END CERTIFICATE----- 975 | -----BEGIN CERTIFICATE----- 976 | MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw 977 | CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU 978 | MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw 979 | MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp 980 | Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA 981 | IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout 982 | 736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A 983 | DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud 984 | DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk 985 | fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA 986 | njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd 987 | -----END CERTIFICATE----- 988 | -----BEGIN CERTIFICATE----- 989 | MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw 990 | CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU 991 | MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw 992 | MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp 993 | Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA 994 | IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu 995 | hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l 996 | xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud 997 | DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 998 | CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx 999 | sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== 1000 | -----END CERTIFICATE----- 1001 | -------------------------------------------------------------------------------- /main/CommandHandler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "esp_wpa2.h" 26 | extern "C" { 27 | #include 28 | } 29 | 30 | #include "CommandHandler.h" 31 | 32 | #include "Arduino.h" 33 | 34 | const char FIRMWARE_VERSION[6] = "1.4.0"; 35 | 36 | // Optional, user-defined X.509 certificate 37 | char CERT_BUF[1300]; 38 | bool setCert = 0; 39 | 40 | // Optional, user-defined RSA private key 41 | char PK_BUFF[1700]; 42 | bool setPSK = 0; 43 | 44 | /*IPAddress*/uint32_t resolvedHostname; 45 | 46 | #define MAX_SOCKETS CONFIG_LWIP_MAX_SOCKETS 47 | uint8_t socketTypes[MAX_SOCKETS]; 48 | WiFiClient tcpClients[MAX_SOCKETS]; 49 | WiFiUDP udps[MAX_SOCKETS]; 50 | WiFiSSLClient tlsClients[MAX_SOCKETS]; 51 | WiFiServer tcpServers[MAX_SOCKETS]; 52 | 53 | 54 | int setNet(const uint8_t command[], uint8_t response[]) 55 | { 56 | char ssid[32 + 1]; 57 | 58 | memset(ssid, 0x00, sizeof(ssid)); 59 | memcpy(ssid, &command[4], command[3]); 60 | 61 | WiFi.begin(ssid); 62 | 63 | response[2] = 1; // number of parameters 64 | response[3] = 1; // parameter 1 length 65 | response[4] = 1; 66 | 67 | return 6; 68 | } 69 | 70 | int setPassPhrase(const uint8_t command[], uint8_t response[]) 71 | { 72 | char ssid[32 + 1]; 73 | char pass[64 + 1]; 74 | 75 | memset(ssid, 0x00, sizeof(ssid)); 76 | memset(pass, 0x00, sizeof(pass)); 77 | 78 | memcpy(ssid, &command[4], command[3]); 79 | memcpy(pass, &command[5 + command[3]], command[4 + command[3]]); 80 | 81 | WiFi.begin(ssid, pass); 82 | 83 | response[2] = 1; // number of parameters 84 | response[3] = 1; // parameter 1 length 85 | response[4] = 1; 86 | 87 | return 6; 88 | } 89 | 90 | int setKey(const uint8_t command[], uint8_t response[]) 91 | { 92 | char ssid[32 + 1]; 93 | char key[26 + 1]; 94 | 95 | memset(ssid, 0x00, sizeof(ssid)); 96 | memset(key, 0x00, sizeof(key)); 97 | 98 | memcpy(ssid, &command[4], command[3]); 99 | memcpy(key, &command[7 + command[3]], command[6 + command[3]]); 100 | 101 | WiFi.begin(ssid, key); 102 | 103 | response[2] = 1; // number of parameters 104 | response[3] = 1; // parameter 1 length 105 | response[4] = 1; 106 | 107 | return 6; 108 | } 109 | 110 | int setIPconfig(const uint8_t command[], uint8_t response[]) 111 | { 112 | uint32_t ip; 113 | uint32_t gwip; 114 | uint32_t mask; 115 | 116 | memcpy(&ip, &command[6], sizeof(ip)); 117 | memcpy(&gwip, &command[11], sizeof(gwip)); 118 | memcpy(&mask, &command[16], sizeof(mask)); 119 | 120 | response[2] = 1; // number of parameters 121 | response[3] = 1; // parameter 1 length 122 | 123 | WiFi.config(ip, gwip, mask); 124 | 125 | return 6; 126 | } 127 | 128 | int setDNSconfig(const uint8_t command[], uint8_t response[]) 129 | { 130 | uint32_t dns1; 131 | uint32_t dns2; 132 | 133 | memcpy(&dns1, &command[6], sizeof(dns1)); 134 | memcpy(&dns2, &command[11], sizeof(dns2)); 135 | 136 | WiFi.setDNS(dns1, dns2); 137 | 138 | response[2] = 1; // number of parameters 139 | response[3] = 1; // parameter 1 length 140 | response[4] = 1; 141 | 142 | return 6; 143 | } 144 | 145 | int setHostname(const uint8_t command[], uint8_t response[]) 146 | { 147 | char hostname[255 + 1]; 148 | 149 | memset(hostname, 0x00, sizeof(hostname)); 150 | memcpy(hostname, &command[4], command[3]); 151 | 152 | response[2] = 1; // number of parameters 153 | response[3] = 1; // parameter 1 length 154 | response[4] = 1; 155 | 156 | WiFi.hostname(hostname); 157 | 158 | return 6; 159 | } 160 | 161 | int setPowerMode(const uint8_t command[], uint8_t response[]) 162 | { 163 | if (command[4]) { 164 | // low power 165 | WiFi.lowPowerMode(); 166 | } else { 167 | // no low power 168 | WiFi.noLowPowerMode(); 169 | } 170 | 171 | response[2] = 1; // number of parameters 172 | response[3] = 1; // parameter 1 length 173 | response[4] = 1; 174 | 175 | return 6; 176 | } 177 | 178 | int setApNet(const uint8_t command[], uint8_t response[]) 179 | { 180 | char ssid[32 + 1]; 181 | uint8_t channel; 182 | 183 | memset(ssid, 0x00, sizeof(ssid)); 184 | memcpy(ssid, &command[4], command[3]); 185 | 186 | channel = command[5 + command[3]]; 187 | 188 | response[2] = 1; // number of parameters 189 | response[3] = 1; // parameter 1 length 190 | 191 | if (WiFi.beginAP(ssid, channel) != WL_AP_FAILED) { 192 | response[4] = 1; 193 | } else { 194 | response[4] = 0; 195 | } 196 | 197 | return 6; 198 | } 199 | 200 | int setApPassPhrase(const uint8_t command[], uint8_t response[]) 201 | { 202 | char ssid[32 + 1]; 203 | char pass[64 + 1]; 204 | uint8_t channel; 205 | 206 | memset(ssid, 0x00, sizeof(ssid)); 207 | memset(pass, 0x00, sizeof(pass)); 208 | 209 | memcpy(ssid, &command[4], command[3]); 210 | memcpy(pass, &command[5 + command[3]], command[4 + command[3]]); 211 | channel = command[6 + command[3] + command[4 + command[3]]]; 212 | 213 | response[2] = 1; // number of parameters 214 | response[3] = 1; // parameter 1 length 215 | 216 | if (WiFi.beginAP(ssid, pass, channel) != WL_AP_FAILED) { 217 | response[4] = 1; 218 | } else { 219 | response[4] = 0; 220 | } 221 | 222 | return 6; 223 | } 224 | 225 | extern void setDebug(int debug); 226 | 227 | int setDebug(const uint8_t command[], uint8_t response[]) 228 | { 229 | setDebug(command[4]); 230 | 231 | response[2] = 1; // number of parameters 232 | response[3] = 1; // parameter 1 length 233 | response[4] = 1; 234 | 235 | return 6; 236 | } 237 | 238 | extern "C" { 239 | uint8_t temprature_sens_read(); 240 | } 241 | 242 | int getTemperature(const uint8_t command[], uint8_t response[]) 243 | { 244 | float temperature = (temprature_sens_read() - 32) / 1.8; 245 | 246 | response[2] = 1; // number of parameters 247 | response[3] = sizeof(temperature); // parameter 1 length 248 | 249 | memcpy(&response[4], &temperature, sizeof(temperature)); 250 | 251 | return 9; 252 | } 253 | 254 | int getConnStatus(const uint8_t command[], uint8_t response[]) 255 | { 256 | uint8_t status = WiFi.status(); 257 | 258 | response[2] = 1; // number of parameters 259 | response[3] = 1; // parameter 1 length 260 | response[4] = status; 261 | 262 | return 6; 263 | } 264 | 265 | int getIPaddr(const uint8_t command[], uint8_t response[]) 266 | { 267 | /*IPAddress*/uint32_t ip = WiFi.localIP(); 268 | /*IPAddress*/uint32_t mask = WiFi.subnetMask(); 269 | /*IPAddress*/uint32_t gwip = WiFi.gatewayIP(); 270 | 271 | response[2] = 3; // number of parameters 272 | 273 | response[3] = 4; // parameter 1 length 274 | memcpy(&response[4], &ip, sizeof(ip)); 275 | 276 | response[8] = 4; // parameter 2 length 277 | memcpy(&response[9], &mask, sizeof(mask)); 278 | 279 | response[13] = 4; // parameter 3 length 280 | memcpy(&response[14], &gwip, sizeof(gwip)); 281 | 282 | return 19; 283 | } 284 | 285 | int getMACaddr(const uint8_t command[], uint8_t response[]) 286 | { 287 | uint8_t mac[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 288 | 289 | WiFi.macAddress(mac); 290 | 291 | response[2] = 1; // number of parameters 292 | response[3] = sizeof(mac); // parameter 1 length 293 | 294 | memcpy(&response[4], mac, sizeof(mac)); 295 | 296 | return 11; 297 | } 298 | 299 | int getCurrSSID(const uint8_t command[], uint8_t response[]) 300 | { 301 | // ssid 302 | const char* ssid = WiFi.SSID(); 303 | uint8_t ssidLen = strlen(ssid); 304 | 305 | response[2] = 1; // number of parameters 306 | response[3] = ssidLen; // parameter 1 length 307 | 308 | memcpy(&response[4], ssid, ssidLen); 309 | 310 | return (5 + ssidLen); 311 | } 312 | 313 | int getCurrBSSID(const uint8_t command[], uint8_t response[]) 314 | { 315 | uint8_t bssid[6]; 316 | 317 | WiFi.BSSID(bssid); 318 | 319 | response[2] = 1; // number of parameters 320 | response[3] = 6; // parameter 1 length 321 | 322 | memcpy(&response[4], bssid, sizeof(bssid)); 323 | 324 | return 11; 325 | } 326 | 327 | int getCurrRSSI(const uint8_t command[], uint8_t response[]) 328 | { 329 | int32_t rssi = WiFi.RSSI(); 330 | 331 | response[2] = 1; // number of parameters 332 | response[3] = sizeof(rssi); // parameter 1 length 333 | 334 | memcpy(&response[4], &rssi, sizeof(rssi)); 335 | 336 | return 9; 337 | } 338 | 339 | int getCurrEnct(const uint8_t command[], uint8_t response[]) 340 | { 341 | uint8_t encryptionType = WiFi.encryptionType(); 342 | 343 | response[2] = 1; // number of parameters 344 | response[3] = 1; // parameter 1 length 345 | response[4] = encryptionType; 346 | 347 | return 6; 348 | } 349 | 350 | int scanNetworks(const uint8_t command[], uint8_t response[]) 351 | { 352 | int num = WiFi.scanNetworks(); 353 | int responseLength = 3; 354 | 355 | response[2] = num; 356 | 357 | for (int i = 0; i < num; i++) { 358 | const char* ssid = WiFi.SSID(i); 359 | int ssidLen = strlen(ssid); 360 | 361 | response[responseLength++] = ssidLen; 362 | 363 | memcpy(&response[responseLength], ssid, ssidLen); 364 | responseLength += ssidLen; 365 | } 366 | 367 | return (responseLength + 1); 368 | } 369 | 370 | int startServerTcp(const uint8_t command[], uint8_t response[]) 371 | { 372 | uint32_t ip = 0; 373 | uint16_t port; 374 | uint8_t socket; 375 | uint8_t type; 376 | 377 | if (command[2] == 3) { 378 | memcpy(&port, &command[4], sizeof(port)); 379 | port = ntohs(port); 380 | socket = command[7]; 381 | type = command[9]; 382 | } else { 383 | memcpy(&ip, &command[4], sizeof(ip)); 384 | memcpy(&port, &command[9], sizeof(port)); 385 | port = ntohs(port); 386 | socket = command[12]; 387 | type = command[14]; 388 | } 389 | 390 | response[2] = 1; // number of parameters 391 | response[3] = 1; // parameter 1 length 392 | 393 | if (type == 0x00) { 394 | tcpServers[socket] = WiFiServer(port); 395 | 396 | tcpServers[socket].begin(); 397 | 398 | socketTypes[socket] = 0x00; 399 | response[4] = 1; 400 | } else if (type == 0x01 && udps[socket].begin(port)) { 401 | socketTypes[socket] = 0x01; 402 | response[4] = 1; 403 | } else if (type == 0x03 && udps[socket].beginMulticast(ip, port)) { 404 | socketTypes[socket] = 0x01; 405 | response[4] = 1; 406 | } else { 407 | response[4] = 0; 408 | } 409 | 410 | return 6; 411 | } 412 | 413 | int getStateTcp(const uint8_t command[], uint8_t response[]) 414 | { 415 | uint8_t socket = command[4]; 416 | 417 | response[2] = 1; // number of parameters 418 | response[3] = 1; // parameter 1 length 419 | 420 | if (tcpServers[socket]) { 421 | response[4] = 1; 422 | } else { 423 | response[4] = 0; 424 | } 425 | 426 | return 6; 427 | } 428 | 429 | int dataSentTcp(const uint8_t command[], uint8_t response[]) 430 | { 431 | // -> no op as write does the work 432 | 433 | response[2] = 1; // number of parameters 434 | response[3] = 1; // parameter 1 length 435 | response[4] = 1; 436 | 437 | return 6; 438 | } 439 | 440 | int availDataTcp(const uint8_t command[], uint8_t response[]) 441 | { 442 | uint8_t socket = command[4]; 443 | uint16_t available = 0; 444 | 445 | if (socketTypes[socket] == 0x00) { 446 | if (tcpServers[socket]) { 447 | WiFiClient client = tcpServers[socket].available(); 448 | 449 | available = 255; 450 | 451 | if (client) { 452 | // try to find existing socket slot 453 | for (int i = 0; i < MAX_SOCKETS; i++) { 454 | if (i == socket) { 455 | continue; // skip this slot 456 | } 457 | 458 | if (socketTypes[i] == 0x00 && tcpClients[i] == client) { 459 | available = i; 460 | break; 461 | } 462 | } 463 | 464 | if (available == 255) { 465 | // book keep new slot 466 | 467 | for (int i = 0; i < MAX_SOCKETS; i++) { 468 | if (i == socket) { 469 | continue; // skip this slot 470 | } 471 | 472 | if (socketTypes[i] == 255) { 473 | socketTypes[i] = 0x00; 474 | tcpClients[i] = client; 475 | 476 | available = i; 477 | break; 478 | } 479 | } 480 | } 481 | } 482 | } else { 483 | available = tcpClients[socket].available(); 484 | } 485 | } else if (socketTypes[socket] == 0x01) { 486 | available = udps[socket].available(); 487 | 488 | if (available <= 0) { 489 | available = udps[socket].parsePacket(); 490 | } 491 | } else if (socketTypes[socket] == 0x02) { 492 | available = tlsClients[socket].available(); 493 | } 494 | 495 | response[2] = 1; // number of parameters 496 | response[3] = sizeof(available); // parameter 1 length 497 | 498 | memcpy(&response[4], &available, sizeof(available)); 499 | 500 | return 7; 501 | } 502 | 503 | int getDataTcp(const uint8_t command[], uint8_t response[]) 504 | { 505 | uint8_t socket = command[4]; 506 | uint8_t peek = command[6]; 507 | 508 | response[2] = 1; // number of parameters 509 | response[3] = 1; // parameter 1 length 510 | 511 | if (socketTypes[socket] == 0x00) { 512 | if (peek) { 513 | response[4] = tcpClients[socket].peek(); 514 | } else { 515 | response[4] = tcpClients[socket].read(); 516 | } 517 | } else if (socketTypes[socket] == 0x01) { 518 | if (peek) { 519 | response[4] = udps[socket].peek(); 520 | } else { 521 | response[4] = udps[socket].read(); 522 | } 523 | } else if (socketTypes[socket] == 0x02) { 524 | if (peek) { 525 | response[4] = tlsClients[socket].peek(); 526 | } else { 527 | response[4] = tlsClients[socket].read(); 528 | } 529 | } 530 | 531 | return 6; 532 | } 533 | 534 | int startClientTcp(const uint8_t command[], uint8_t response[]) 535 | { 536 | char host[255 + 1]; 537 | uint32_t ip; 538 | uint16_t port; 539 | uint8_t socket; 540 | uint8_t type; 541 | 542 | memset(host, 0x00, sizeof(host)); 543 | 544 | if (command[2] == 4) { 545 | memcpy(&ip, &command[4], sizeof(ip)); 546 | memcpy(&port, &command[9], sizeof(port)); 547 | port = ntohs(port); 548 | socket = command[12]; 549 | type = command[14]; 550 | } else { 551 | memcpy(host, &command[4], command[3]); 552 | memcpy(&ip, &command[5 + command[3]], sizeof(ip)); 553 | memcpy(&port, &command[10 + command[3]], sizeof(port)); 554 | port = ntohs(port); 555 | socket = command[13 + command[3]]; 556 | type = command[15 + command[3]]; 557 | } 558 | 559 | if (type == 0x00) { 560 | int result; 561 | 562 | if (host[0] != '\0') { 563 | result = tcpClients[socket].connect(host, port); 564 | } else { 565 | result = tcpClients[socket].connect(ip, port); 566 | } 567 | 568 | if (result) { 569 | socketTypes[socket] = 0x00; 570 | 571 | response[2] = 1; // number of parameters 572 | response[3] = 1; // parameter 1 length 573 | response[4] = 1; 574 | 575 | return 6; 576 | } else { 577 | response[2] = 0; // number of parameters 578 | 579 | return 4; 580 | } 581 | } else if (type == 0x01) { 582 | int result; 583 | 584 | result = udps[socket].begin(); 585 | if(result){ 586 | if (host[0] != '\0') { 587 | result = udps[socket].beginPacket(host, port); 588 | } else { 589 | result = udps[socket].beginPacket(ip, port); 590 | } 591 | } 592 | 593 | if (result) { 594 | socketTypes[socket] = 0x01; 595 | 596 | response[2] = 1; // number of parameters 597 | response[3] = 1; // parameter 1 length 598 | response[4] = 1; 599 | 600 | return 6; 601 | } else { 602 | response[2] = 0; // number of parameters 603 | 604 | return 4; 605 | } 606 | } else if (type == 0x02) { 607 | int result; 608 | if (host[0] != '\0') { 609 | if (setCert && setPSK) { 610 | tlsClients[socket].setCertificate(CERT_BUF); 611 | tlsClients[socket].setPrivateKey(PK_BUFF); 612 | } 613 | result = tlsClients[socket].connect(host, port); 614 | } else { 615 | if (setCert && setPSK) { 616 | tlsClients[socket].setCertificate(CERT_BUF); 617 | tlsClients[socket].setPrivateKey(PK_BUFF); 618 | } 619 | result = tlsClients[socket].connect(ip, port); 620 | } 621 | 622 | if (result) { 623 | socketTypes[socket] = 0x02; 624 | 625 | response[2] = 1; // number of parameters 626 | response[3] = 1; // parameter 1 length 627 | response[4] = 1; 628 | 629 | return 6; 630 | } else { 631 | response[2] = 0; // number of parameters 632 | 633 | return 4; 634 | } 635 | } else { 636 | response[2] = 0; // number of parameters 637 | 638 | return 4; 639 | } 640 | } 641 | 642 | int stopClientTcp(const uint8_t command[], uint8_t response[]) 643 | { 644 | uint8_t socket = command[4]; 645 | 646 | if (socketTypes[socket] == 0x00) { 647 | tcpClients[socket].stop(); 648 | 649 | socketTypes[socket] = 255; 650 | } else if (socketTypes[socket] == 0x01) { 651 | udps[socket].stop(); 652 | 653 | socketTypes[socket] = 255; 654 | } else if (socketTypes[socket] == 0x02) { 655 | tlsClients[socket].stop(); 656 | 657 | socketTypes[socket] = 255; 658 | } 659 | 660 | response[2] = 1; // number of parameters 661 | response[3] = 1; // parameter 1 length 662 | response[4] = 1; 663 | 664 | return 6; 665 | } 666 | 667 | int getClientStateTcp(const uint8_t command[], uint8_t response[]) 668 | { 669 | uint8_t socket = command[4]; 670 | 671 | response[2] = 1; // number of parameters 672 | response[3] = 1; // parameter 1 length 673 | 674 | if ((socketTypes[socket] == 0x00) && tcpClients[socket].connected()) { 675 | response[4] = 4; 676 | } else if ((socketTypes[socket] == 0x02) && tlsClients[socket].connected()) { 677 | response[4] = 4; 678 | } else { 679 | socketTypes[socket] = 255; 680 | response[4] = 0; 681 | } 682 | 683 | return 6; 684 | } 685 | 686 | int disconnect(const uint8_t command[], uint8_t response[]) 687 | { 688 | response[2] = 1; // number of parameters 689 | response[3] = 1; // parameter 1 length 690 | response[4] = 1; 691 | 692 | WiFi.disconnect(); 693 | 694 | return 6; 695 | } 696 | 697 | int getIdxRSSI(const uint8_t command[], uint8_t response[]) 698 | { 699 | // RSSI 700 | int32_t rssi = WiFi.RSSI(command[4]); 701 | 702 | response[2] = 1; // number of parameters 703 | response[3] = sizeof(rssi); // parameter 1 length 704 | 705 | memcpy(&response[4], &rssi, sizeof(rssi)); 706 | 707 | return 9; 708 | } 709 | 710 | int getIdxEnct(const uint8_t command[], uint8_t response[]) 711 | { 712 | uint8_t encryptionType = WiFi.encryptionType(command[4]); 713 | 714 | response[2] = 1; // number of parameters 715 | response[3] = 1; // parameter 1 length 716 | response[4] = encryptionType; 717 | 718 | return 6; 719 | } 720 | 721 | int reqHostByName(const uint8_t command[], uint8_t response[]) 722 | { 723 | char host[255 + 1]; 724 | 725 | memset(host, 0x00, sizeof(host)); 726 | memcpy(host, &command[4], command[3]); 727 | 728 | response[2] = 1; // number of parameters 729 | response[3] = 1; // parameter 1 length 730 | 731 | resolvedHostname = /*IPAddress(255, 255, 255, 255)*/0xffffffff; 732 | if (WiFi.hostByName(host, resolvedHostname)) { 733 | response[4] = 1; 734 | } else { 735 | response[4] = 0; 736 | } 737 | 738 | return 6; 739 | } 740 | 741 | int getHostByName(const uint8_t command[], uint8_t response[]) 742 | { 743 | response[2] = 1; // number of parameters 744 | response[3] = 4; // parameter 1 length 745 | memcpy(&response[4], &resolvedHostname, sizeof(resolvedHostname)); 746 | 747 | return 9; 748 | } 749 | 750 | int startScanNetworks(const uint8_t command[], uint8_t response[]) 751 | { 752 | response[2] = 1; // number of parameters 753 | response[3] = 1; // parameter 1 length 754 | response[4] = 1; 755 | 756 | return 6; 757 | } 758 | 759 | int getFwVersion(const uint8_t command[], uint8_t response[]) 760 | { 761 | response[2] = 1; // number of parameters 762 | response[3] = sizeof(FIRMWARE_VERSION); // parameter 1 length 763 | 764 | memcpy(&response[4], FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION)); 765 | 766 | return 11; 767 | } 768 | 769 | int sendUDPdata(const uint8_t command[], uint8_t response[]) 770 | { 771 | uint8_t socket = command[4]; 772 | 773 | response[2] = 1; // number of parameters 774 | response[3] = 1; // parameter 1 length 775 | 776 | if (udps[socket].endPacket()) { 777 | response[4] = 1; 778 | } else { 779 | response[4] = 0; 780 | } 781 | 782 | return 6; 783 | } 784 | 785 | int getRemoteData(const uint8_t command[], uint8_t response[]) 786 | { 787 | uint8_t socket = command[4]; 788 | 789 | /*IPAddress*/uint32_t ip = /*IPAddress(0, 0, 0, 0)*/0; 790 | uint16_t port = 0; 791 | 792 | if (socketTypes[socket] == 0x00) { 793 | ip = tcpClients[socket].remoteIP(); 794 | port = tcpClients[socket].remotePort(); 795 | } else if (socketTypes[socket] == 0x01) { 796 | ip = udps[socket].remoteIP(); 797 | port = udps[socket].remotePort(); 798 | } else if (socketTypes[socket] == 0x02) { 799 | ip = tlsClients[socket].remoteIP(); 800 | port = tlsClients[socket].remotePort(); 801 | } 802 | 803 | response[2] = 2; // number of parameters 804 | 805 | response[3] = 4; // parameter 1 length 806 | memcpy(&response[4], &ip, sizeof(ip)); 807 | 808 | response[8] = 2; // parameter 2 length 809 | response[9] = (port >> 8) & 0xff; 810 | response[10] = (port >> 0) & 0xff; 811 | 812 | return 12; 813 | } 814 | 815 | int getTime(const uint8_t command[], uint8_t response[]) 816 | { 817 | unsigned long now = WiFi.getTime(); 818 | 819 | response[2] = 1; // number of parameters 820 | response[3] = sizeof(now); // parameter 1 length 821 | 822 | memcpy(&response[4], &now, sizeof(now)); 823 | 824 | return 5 + sizeof(now); 825 | } 826 | 827 | int getIdxBSSID(const uint8_t command[], uint8_t response[]) 828 | { 829 | uint8_t bssid[6]; 830 | 831 | WiFi.BSSID(command[4], bssid); 832 | 833 | response[2] = 1; // number of parameters 834 | response[3] = 6; // parameter 1 length 835 | memcpy(&response[4], bssid, sizeof(bssid)); 836 | 837 | return 11; 838 | } 839 | 840 | int getIdxChannel(const uint8_t command[], uint8_t response[]) 841 | { 842 | uint8_t channel = WiFi.channel(command[4]); 843 | 844 | response[2] = 1; // number of parameters 845 | response[3] = 1; // parameter 1 length 846 | response[4] = channel; 847 | 848 | return 6; 849 | } 850 | 851 | int sendDataTcp(const uint8_t command[], uint8_t response[]) 852 | { 853 | uint8_t socket; 854 | uint16_t length; 855 | uint16_t written = 0; 856 | 857 | socket = command[5]; 858 | memcpy(&length, &command[6], sizeof(length)); 859 | length = ntohs(length); 860 | 861 | if ((socketTypes[socket] == 0x00) && tcpServers[socket]) { 862 | written = tcpServers[socket].write(&command[8], length); 863 | } else if (socketTypes[socket] == 0x00) { 864 | written = tcpClients[socket].write(&command[8], length); 865 | } else if (socketTypes[socket] == 0x02) { 866 | written = tlsClients[socket].write(&command[8], length); 867 | } 868 | 869 | response[2] = 1; // number of parameters 870 | response[3] = sizeof(written); // parameter 1 length 871 | memcpy(&response[4], &written, sizeof(written)); 872 | 873 | return 7; 874 | } 875 | 876 | int getDataBufTcp(const uint8_t command[], uint8_t response[]) 877 | { 878 | uint8_t socket; 879 | uint16_t length; 880 | int read = 0; 881 | 882 | socket = command[5]; 883 | memcpy(&length, &command[8], sizeof(length)); 884 | 885 | if (socketTypes[socket] == 0x00) { 886 | read = tcpClients[socket].read(&response[5], length); 887 | } else if (socketTypes[socket] == 0x01) { 888 | read = udps[socket].read(&response[5], length); 889 | } else if (socketTypes[socket] == 0x02) { 890 | read = tlsClients[socket].read(&response[5], length); 891 | } 892 | 893 | if (read < 0) { 894 | read = 0; 895 | } 896 | 897 | response[2] = 1; // number of parameters 898 | response[3] = (read >> 8) & 0xff; // parameter 1 length 899 | response[4] = (read >> 0) & 0xff; 900 | 901 | return (6 + read); 902 | } 903 | 904 | int insertDataBuf(const uint8_t command[], uint8_t response[]) 905 | { 906 | uint8_t socket; 907 | uint16_t length; 908 | 909 | socket = command[5]; 910 | memcpy(&length, &command[6], sizeof(length)); 911 | length = ntohs(length); 912 | 913 | response[2] = 1; // number of parameters 914 | response[3] = 1; // parameter 1 length 915 | 916 | if (udps[socket].write(&command[8], length) != 0) { 917 | response[4] = 1; 918 | } else { 919 | response[4] = 0; 920 | } 921 | 922 | return 6; 923 | } 924 | 925 | int ping(const uint8_t command[], uint8_t response[]) 926 | { 927 | uint32_t ip; 928 | uint8_t ttl; 929 | int16_t result; 930 | 931 | memcpy(&ip, &command[4], sizeof(ip)); 932 | ttl = command[9]; 933 | 934 | result = WiFi.ping(ip, ttl); 935 | 936 | response[2] = 1; // number of parameters 937 | response[3] = sizeof(result); // parameter 1 length 938 | memcpy(&response[4], &result, sizeof(result)); 939 | 940 | return 7; 941 | } 942 | 943 | int getSocket(const uint8_t command[], uint8_t response[]) 944 | { 945 | uint8_t result = 255; 946 | 947 | for (int i = 0; i < MAX_SOCKETS; i++) { 948 | if (socketTypes[i] == 255) { 949 | result = i; 950 | break; 951 | } 952 | } 953 | 954 | response[2] = 1; // number of parameters 955 | response[3] = sizeof(result); // parameter 1 length 956 | response[4] = result; 957 | 958 | return 6; 959 | } 960 | 961 | int setPinMode(const uint8_t command[], uint8_t response[]) 962 | { 963 | uint8_t pin = command[4]; 964 | uint8_t mode = command[6]; 965 | 966 | pinMode(pin, mode); 967 | 968 | response[2] = 1; // number of parameters 969 | response[3] = 1; // parameter 1 length 970 | response[4] = 1; 971 | 972 | return 6; 973 | } 974 | 975 | int setDigitalWrite(const uint8_t command[], uint8_t response[]) 976 | { 977 | uint8_t pin = command[4]; 978 | uint8_t value = command[6]; 979 | 980 | digitalWrite(pin, value); 981 | 982 | response[2] = 1; // number of parameters 983 | response[3] = 1; // parameter 1 length 984 | response[4] = 1; 985 | 986 | return 6; 987 | } 988 | 989 | int setAnalogWrite(const uint8_t command[], uint8_t response[]) 990 | { 991 | uint8_t pin = command[4]; 992 | uint8_t value = command[6]; 993 | 994 | analogWrite(pin, value); 995 | 996 | response[2] = 1; // number of parameters 997 | response[3] = 1; // parameter 1 length 998 | response[4] = 1; 999 | 1000 | return 6; 1001 | } 1002 | 1003 | int wpa2EntSetIdentity(const uint8_t command[], uint8_t response[]) { 1004 | char identity[32 + 1]; 1005 | 1006 | memset(identity, 0x00, sizeof(identity)); 1007 | memcpy(identity, &command[4], command[3]); 1008 | 1009 | esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)identity, strlen(identity)); 1010 | 1011 | response[2] = 1; // number of parameters 1012 | response[3] = 1; // parameter 1 length 1013 | response[4] = 1; 1014 | 1015 | return 6; 1016 | } 1017 | 1018 | int wpa2EntSetUsername(const uint8_t command[], uint8_t response[]) { 1019 | char username[32 + 1]; 1020 | 1021 | memset(username, 0x00, sizeof(username)); 1022 | memcpy(username, &command[4], command[3]); 1023 | 1024 | esp_wifi_sta_wpa2_ent_set_username((uint8_t *)username, strlen(username)); 1025 | 1026 | response[2] = 1; // number of parameters 1027 | response[3] = 1; // parameter 1 length 1028 | response[4] = 1; 1029 | 1030 | return 6; 1031 | } 1032 | 1033 | int wpa2EntSetPassword(const uint8_t command[], uint8_t response[]) { 1034 | char password[32 + 1]; 1035 | 1036 | memset(password, 0x00, sizeof(password)); 1037 | memcpy(password, &command[4], command[3]); 1038 | 1039 | esp_wifi_sta_wpa2_ent_set_password((uint8_t *)password, strlen(password)); 1040 | 1041 | response[2] = 1; // number of parameters 1042 | response[3] = 1; // parameter 1 length 1043 | response[4] = 1; 1044 | 1045 | return 6; 1046 | } 1047 | 1048 | int wpa2EntSetCACert(const uint8_t command[], uint8_t response[]) { 1049 | // not yet implemented (need to decide if writing in the filesystem is better than loading every time) 1050 | // keep in mind size limit for messages 1051 | return 0; 1052 | } 1053 | 1054 | int wpa2EntSetCertKey(const uint8_t command[], uint8_t response[]) { 1055 | // not yet implemented (need to decide if writing in the filesystem is better than loading every time) 1056 | // keep in mind size limit for messages 1057 | return 0; 1058 | } 1059 | 1060 | int wpa2EntEnable(const uint8_t command[], uint8_t response[]) { 1061 | 1062 | esp_wpa2_config_t config = WPA2_CONFIG_INIT_DEFAULT(); 1063 | esp_wifi_sta_wpa2_ent_enable(&config); 1064 | 1065 | response[2] = 1; // number of parameters 1066 | response[3] = 1; // parameter 1 length 1067 | response[4] = 1; 1068 | 1069 | return 6; 1070 | } 1071 | 1072 | int setClientCert(const uint8_t command[], uint8_t response[]){ 1073 | ets_printf("*** Called setClientCert\n"); 1074 | 1075 | memset(CERT_BUF, 0x00, sizeof(CERT_BUF)); 1076 | memcpy(CERT_BUF, &command[4], sizeof(CERT_BUF)); 1077 | 1078 | response[2] = 1; // number of parameters 1079 | response[3] = 1; // parameter 1 length 1080 | response[4] = 1; 1081 | 1082 | setCert = 1; 1083 | 1084 | return 6; 1085 | } 1086 | 1087 | int setCertKey(const uint8_t command[], uint8_t response[]){ 1088 | ets_printf("*** Called setCertKey\n"); 1089 | 1090 | memset(PK_BUFF, 0x00, sizeof(PK_BUFF)); 1091 | memcpy(PK_BUFF, &command[4], sizeof(PK_BUFF)); 1092 | 1093 | response[2] = 1; // number of parameters 1094 | response[3] = 1; // parameter 1 length 1095 | response[4] = 1; 1096 | 1097 | setPSK = 1; 1098 | 1099 | return 6; 1100 | } 1101 | 1102 | 1103 | int getAdcValue(const uint8_t command[], uint8_t response[]){ 1104 | uint8_t len = command[3]; 1105 | uint8_t j = 0; 1106 | int v; 1107 | 1108 | response[2] = len; 1109 | for(int i=0; i> 8 & 0xff); 1114 | response[6+j] = (uint8_t)(v & 0xff); 1115 | j += 4; 1116 | } 1117 | return len*4+4; 1118 | } 1119 | 1120 | int softReset(const uint8_t command[], uint8_t response[]){ 1121 | esp_restart(); 1122 | response[2] = 0; 1123 | return 4; 1124 | } 1125 | 1126 | typedef int (*CommandHandlerType)(const uint8_t command[], uint8_t response[]); 1127 | 1128 | const CommandHandlerType commandHandlers[] = { 1129 | // 0x00 -> 0x0f 1130 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1131 | 1132 | // 0x10 -> 0x1f 1133 | setNet, setPassPhrase, setKey, NULL, setIPconfig, setDNSconfig, setHostname, setPowerMode, setApNet, setApPassPhrase, setDebug, getTemperature, NULL, NULL, NULL, NULL, 1134 | 1135 | // 0x20 -> 0x2f 1136 | getConnStatus, getIPaddr, getMACaddr, getCurrSSID, getCurrBSSID, getCurrRSSI, getCurrEnct, scanNetworks, startServerTcp, getStateTcp, dataSentTcp, availDataTcp, getDataTcp, startClientTcp, stopClientTcp, getClientStateTcp, 1137 | 1138 | // 0x30 -> 0x3f 1139 | disconnect, NULL, getIdxRSSI, getIdxEnct, reqHostByName, getHostByName, startScanNetworks, getFwVersion, NULL, sendUDPdata, getRemoteData, getTime, getIdxBSSID, getIdxChannel, ping, getSocket, 1140 | 1141 | // 0x40 -> 0x4f 1142 | setClientCert, setCertKey, NULL, NULL, sendDataTcp, getDataBufTcp, insertDataBuf, NULL, NULL, NULL, wpa2EntSetIdentity, wpa2EntSetUsername, wpa2EntSetPassword, wpa2EntSetCACert, wpa2EntSetCertKey, wpa2EntEnable, 1143 | 1144 | // 0x50 -> 0x5f 1145 | setPinMode, setDigitalWrite, setAnalogWrite, getAdcValue, softReset, 1146 | }; 1147 | 1148 | #define NUM_COMMAND_HANDLERS (sizeof(commandHandlers) / sizeof(commandHandlers[0])) 1149 | 1150 | CommandHandlerClass::CommandHandlerClass() 1151 | { 1152 | } 1153 | 1154 | void CommandHandlerClass::begin() 1155 | { 1156 | pinMode(0, OUTPUT); 1157 | 1158 | for (int i = 0; i < MAX_SOCKETS; i++) { 1159 | socketTypes[i] = 255; 1160 | } 1161 | 1162 | _updateGpio0PinSemaphore = xSemaphoreCreateCounting(2, 0); 1163 | 1164 | WiFi.onReceive(CommandHandlerClass::onWiFiReceive); 1165 | 1166 | xTaskCreatePinnedToCore(CommandHandlerClass::gpio0Updater, "gpio0Updater", 8192, NULL, 1, NULL, 1); 1167 | } 1168 | 1169 | int CommandHandlerClass::handle(const uint8_t command[], uint8_t response[]) 1170 | { 1171 | int responseLength = 0; 1172 | 1173 | if (command[0] == 0xe0 && command[1] < NUM_COMMAND_HANDLERS) { 1174 | CommandHandlerType commandHandlerType = commandHandlers[command[1]]; 1175 | 1176 | if (commandHandlerType) { 1177 | responseLength = commandHandlerType(command, response); 1178 | } 1179 | } 1180 | 1181 | if (responseLength == 0) { 1182 | response[0] = 0xef; 1183 | response[1] = 0x00; 1184 | response[2] = 0xee; 1185 | 1186 | responseLength = 3; 1187 | } else { 1188 | response[0] = 0xe0; 1189 | response[1] = (0x80 | command[1]); 1190 | response[responseLength - 1] = 0xee; 1191 | } 1192 | 1193 | xSemaphoreGive(_updateGpio0PinSemaphore); 1194 | 1195 | return responseLength; 1196 | } 1197 | 1198 | void CommandHandlerClass::gpio0Updater(void*) 1199 | { 1200 | while (1) { 1201 | CommandHandler.updateGpio0Pin(); 1202 | } 1203 | } 1204 | 1205 | void CommandHandlerClass::updateGpio0Pin() 1206 | { 1207 | xSemaphoreTake(_updateGpio0PinSemaphore, portMAX_DELAY); 1208 | 1209 | int available = 0; 1210 | 1211 | for (int i = 0; i < MAX_SOCKETS; i++) { 1212 | if (socketTypes[i] == 0x00) { 1213 | if (tcpServers[i] && tcpServers[i].available()) { 1214 | available = 1; 1215 | break; 1216 | } else if (tcpClients[i] && tcpClients[i].connected() && tcpClients[i].available()) { 1217 | available = 1; 1218 | break; 1219 | } 1220 | } 1221 | 1222 | if (socketTypes[i] == 0x01 && udps[i] && (udps[i].available() || udps[i].parsePacket())) { 1223 | available = 1; 1224 | break; 1225 | } 1226 | 1227 | if (socketTypes[i] == 0x02 && tlsClients[i] && tlsClients[i].connected() && tlsClients[i].available()) { 1228 | available = 1; 1229 | break; 1230 | } 1231 | } 1232 | 1233 | if (available) { 1234 | digitalWrite(0, HIGH); 1235 | } else { 1236 | digitalWrite(0, LOW); 1237 | } 1238 | 1239 | vTaskDelay(1); 1240 | } 1241 | 1242 | void CommandHandlerClass::onWiFiReceive() 1243 | { 1244 | CommandHandler.handleWiFiReceive(); 1245 | } 1246 | 1247 | void CommandHandlerClass::handleWiFiReceive() 1248 | { 1249 | xSemaphoreGiveFromISR(_updateGpio0PinSemaphore, NULL); 1250 | } 1251 | 1252 | CommandHandlerClass CommandHandler; 1253 | -------------------------------------------------------------------------------- /main/CommandHandler.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef COMMAND_HANDLER_H 21 | #define COMMAND_HANDLER_H 22 | 23 | #include 24 | 25 | class CommandHandlerClass { 26 | public: 27 | CommandHandlerClass(); 28 | 29 | void begin(); 30 | int handle(const uint8_t command[], uint8_t response[]); 31 | 32 | private: 33 | static void gpio0Updater(void*); 34 | void updateGpio0Pin(); 35 | 36 | static void onWiFiReceive(); 37 | void handleWiFiReceive(); 38 | 39 | private: 40 | SemaphoreHandle_t _updateGpio0PinSemaphore; 41 | }; 42 | 43 | extern CommandHandlerClass CommandHandler; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sipeed/Maixduino_esp32_fimware/90fd6f16f6004539894a39e69686f2d2af8d97ee/main/component.mk -------------------------------------------------------------------------------- /main/sketch.ino.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino NINA firmware. 3 | Copyright (c) 2018 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include 21 | 22 | extern "C" { 23 | #include 24 | #include 25 | #include 26 | #include 27 | } 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #include "CommandHandler.h" 35 | 36 | #define SPI_BUFFER_LEN SPI_MAX_DMA_LEN 37 | 38 | int debug = 0; 39 | 40 | uint8_t* commandBuffer; 41 | uint8_t* responseBuffer; 42 | 43 | void dumpBuffer(const char* label, uint8_t data[], int length) { 44 | ets_printf("%s: ", label); 45 | 46 | for (int i = 0; i < length; i++) { 47 | ets_printf("%02x", data[i]); 48 | } 49 | 50 | ets_printf("\r\n"); 51 | } 52 | 53 | void setDebug(int d) { 54 | debug = d; 55 | 56 | if (debug) { 57 | PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[1], 0); 58 | PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[3], 0); 59 | 60 | const char* default_uart_dev = "/dev/uart/0"; 61 | _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r"); 62 | _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w"); 63 | _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w"); 64 | 65 | uart_div_modify(CONFIG_CONSOLE_UART_NUM, (APB_CLK_FREQ << 4) / 115200); 66 | 67 | // uartAttach(); 68 | ets_install_uart_printf(); 69 | uart_tx_switch(CONFIG_CONSOLE_UART_NUM); 70 | 71 | ets_printf("*** DEBUG ON\n"); 72 | } else { 73 | PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[1], PIN_FUNC_GPIO); 74 | PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[3], PIN_FUNC_GPIO); 75 | 76 | _GLOBAL_REENT->_stdin = (FILE*) &__sf_fake_stdin; 77 | _GLOBAL_REENT->_stdout = (FILE*) &__sf_fake_stdout; 78 | _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr; 79 | 80 | ets_install_putc1(NULL); 81 | ets_install_putc2(NULL); 82 | } 83 | } 84 | 85 | void setupWiFi(); 86 | void setupBluetooth(); 87 | 88 | void setupADC(); 89 | void setup() { 90 | setDebug(debug); 91 | 92 | // put SWD and SWCLK pins connected to SAMD as inputs 93 | pinMode(15, INPUT); 94 | pinMode(21, INPUT); 95 | 96 | pinMode(5, INPUT); 97 | if (digitalRead(5) == LOW) { 98 | if (debug) ets_printf("*** BLUETOOTH ON\n"); 99 | 100 | setupBluetooth(); 101 | } else { 102 | if (debug) ets_printf("*** WIFI ON\n"); 103 | 104 | setupWiFi(); 105 | } 106 | setupADC(); 107 | } 108 | 109 | #define UNO_WIFI_REV2 110 | 111 | void setupBluetooth() { 112 | periph_module_enable(PERIPH_UART1_MODULE); 113 | periph_module_enable(PERIPH_UHCI0_MODULE); 114 | 115 | #ifdef UNO_WIFI_REV2 116 | uart_set_pin(UART_NUM_1, 1, 3, 33, 0); // TX, RX, RTS, CTS 117 | #else 118 | uart_set_pin(UART_NUM_1, 23, 12, 18, 5); 119 | #endif 120 | uart_set_hw_flow_ctrl(UART_NUM_1, UART_HW_FLOWCTRL_CTS_RTS, 5); 121 | 122 | esp_bt_controller_config_t btControllerConfig = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); 123 | 124 | btControllerConfig.hci_uart_no = UART_NUM_1; 125 | #ifdef UNO_WIFI_REV2 126 | btControllerConfig.hci_uart_baudrate = 115200; 127 | #else 128 | btControllerConfig.hci_uart_baudrate = 912600; 129 | #endif 130 | 131 | esp_bt_controller_init(&btControllerConfig); 132 | while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE); 133 | esp_bt_controller_enable(ESP_BT_MODE_BLE); 134 | esp_bt_sleep_enable(); 135 | 136 | vTaskSuspend(NULL); 137 | 138 | while (1) { 139 | vTaskDelay(portMAX_DELAY); 140 | } 141 | } 142 | 143 | void setupWiFi() { 144 | esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); 145 | if (debug) ets_printf("*** SPIS\n"); 146 | SPIS.begin(); 147 | 148 | if (WiFi.status() == WL_NO_SHIELD) { 149 | if (debug) ets_printf("*** NOSHIELD\n"); 150 | while (1); // no shield 151 | } 152 | 153 | commandBuffer = (uint8_t*)heap_caps_malloc(SPI_BUFFER_LEN, MALLOC_CAP_DMA); 154 | responseBuffer = (uint8_t*)heap_caps_malloc(SPI_BUFFER_LEN, MALLOC_CAP_DMA); 155 | 156 | if (debug) ets_printf("*** BEGIN\n"); 157 | CommandHandler.begin(); 158 | } 159 | 160 | void loop() { 161 | if (debug) ets_printf("."); 162 | // wait for a command 163 | memset(commandBuffer, 0x00, SPI_BUFFER_LEN); 164 | int commandLength = SPIS.transfer(NULL, commandBuffer, SPI_BUFFER_LEN); 165 | if (debug) ets_printf("%d", commandLength); 166 | if (commandLength == 0) { 167 | return; 168 | } 169 | 170 | if (debug) { 171 | dumpBuffer("COMMAND", commandBuffer, commandLength); 172 | } 173 | 174 | // process 175 | memset(responseBuffer, 0x00, SPI_BUFFER_LEN); 176 | int responseLength = CommandHandler.handle(commandBuffer, responseBuffer); 177 | 178 | SPIS.transfer(responseBuffer, NULL, responseLength); 179 | 180 | if (debug) { 181 | dumpBuffer("RESPONSE", responseBuffer, responseLength); 182 | } 183 | } 184 | 185 | void setupADC(){ 186 | uint8_t channels[] = {ADC_CHANNEL_0, ADC_CHANNEL_3, ADC_CHANNEL_4, ADC_CHANNEL_5, ADC_CHANNEL_6, ADC_CHANNEL_7}; 187 | adc1_config_width(ADC_WIDTH_BIT_12); 188 | for(uint8_t i=0; i