diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 5a3c59e0..00000000 --- a/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.pio -.vscode -lib -build.log -build_output -.cache diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index e80666bf..00000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b1ad7d05..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "files.associations": { - "*.tcc": "cpp", - "string": "cpp", - "functional": "cpp", - "array": "cpp", - "atomic": "cpp", - "bitset": "cpp", - "cctype": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "cstdarg": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "list": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "fstream": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "new": "cpp", - "ostream": "cpp", - "numeric": "cpp", - "ratio": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "system_error": "cpp", - "cinttypes": "cpp", - "regex": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "typeinfo": "cpp" - }, - "cmake.configureOnOpen": true -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 99208207..00000000 --- a/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# IoTManager -Это модульная система беспроводной автоматизации на базе ESP32/ESP8266 микроконтроллеров и приложения IoT Manager. -Телеграм канал обсуждения приложения и системы автоматизации https://t.me/IoTmanager -# [Инструкция](https://github.com/IoTManagerProject/IoTManager/wiki) - -![](https://github.com/IoTManagerProject/IoTManager/blob/beta/doc/pictures/007%20iot%20manager.jpg) diff --git a/data/.exclude.files b/data/.exclude.files deleted file mode 100644 index 955397fa..00000000 --- a/data/.exclude.files +++ /dev/null @@ -1,2 +0,0 @@ -/*.js.gz -/.exclude.files diff --git a/data/config.json b/data/config.json deleted file mode 100644 index 88fa28c5..00000000 --- a/data/config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "IoTmanager", - "chipID": "", - "apssid": "IoTmanager", - "appass": "", - "routerssid": "VOLODYA", - "routerpass": "BELCHENKO", - "timezone": 1, - "ntp": "pool.ntp.org", - "mqttServer": "m12.cloudmqtt.com", - "mqttPort": 14053, - "mqttPrefix": "/iotTest", - "mqttUser": "lbscvzuj", - "mqttPass": "bLxlveOgaF8F", - "scen": "1", - "telegramApi": "1416711569:AAEI0j83GmXqwzb_gnK1B0Am0gDwZoJt5xo", - "telegonof": "0", - "weblogin": "admin", - "webpass": "admin", - "udponoff": "1", - "blink": "1", - "oneWirePin": "2", - "serverip": "http://206.189.49.244" -} \ No newline at end of file diff --git a/data/css/build.css.gz b/data/css/build.css.gz deleted file mode 100644 index b62ceaf0..00000000 Binary files a/data/css/build.css.gz and /dev/null differ diff --git a/data/edit.htm b/data/edit.htm deleted file mode 100644 index 1ebb989d..00000000 --- a/data/edit.htm +++ /dev/null @@ -1,658 +0,0 @@ - - - - - - FS Editor - - - - - - - -
-
-
-
- - - - - \ No newline at end of file diff --git a/data/favicon.ico b/data/favicon.ico deleted file mode 100644 index 50d908fa..00000000 Binary files a/data/favicon.ico and /dev/null differ diff --git a/data/icon.jpeg b/data/icon.jpeg deleted file mode 100644 index abdd18c0..00000000 Binary files a/data/icon.jpeg and /dev/null differ diff --git a/data/index.htm.gz b/data/index.htm.gz deleted file mode 100644 index 073ff4ab..00000000 Binary files a/data/index.htm.gz and /dev/null differ diff --git a/data/index.json b/data/index.json deleted file mode 100644 index c0f41268..00000000 --- a/data/index.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "configs": [ - "/config.live.json", - "/config.setup.json", - "/lang/lang.ru.json" - ], - "title": "Главная", - "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - }, - { - "type": "text", - "class": "alert alert-light", - "title": "
IoT Manager
" - }, - { - "type": "link", - "title": "Конфигурация устройства", - "action": "/?set.device", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Конфигурация WIFI", - "action": "/?set.wifi", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Конфигурация MQTT", - "action": "/?set.mqtt", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Конфигурация telegram", - "action": "/?set.telegram", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Утилиты", - "action": "/?set.utilities", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Скачать приложение IoT Manager для android", - "action": "https://play.google.com/store/apps/details?id=ru.esp8266.iotmanager", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Скачать приложение IoT Manager для iphone", - "action": "https://apps.apple.com/ru/app/iot-manager/id1155934877", - "class": "btn btn-block btn-default" - } - ] -} diff --git a/data/items/analog-adc.txt b/data/items/analog-adc.txt deleted file mode 100644 index 8bc0e914..00000000 --- a/data/items/analog-adc.txt +++ /dev/null @@ -1 +0,0 @@ -0;analog-adc;id;fillgauge;Сенсоры;Аналоговый;order;gol;map[0,1024,0,100];c[1] \ No newline at end of file diff --git a/data/items/bme280-hum.txt b/data/items/bme280-hum.txt deleted file mode 100644 index c8afd255..00000000 --- a/data/items/bme280-hum.txt +++ /dev/null @@ -1 +0,0 @@ -0;bme280-hum;id;anydataHum;Сенсоры;Влажность;order;addr[0x76];c[1] \ No newline at end of file diff --git a/data/items/bme280-press.txt b/data/items/bme280-press.txt deleted file mode 100644 index f79973e2..00000000 --- a/data/items/bme280-press.txt +++ /dev/null @@ -1 +0,0 @@ -0;bme280-press;id;anydataPress;Сенсоры;Давление;order;addr[0x76];c[1] \ No newline at end of file diff --git a/data/items/bme280-temp.txt b/data/items/bme280-temp.txt deleted file mode 100644 index 6e5e9003..00000000 --- a/data/items/bme280-temp.txt +++ /dev/null @@ -1 +0,0 @@ -0;bme280-temp;id;anydataTemp;Сенсоры;Температура;order;addr[0x76];c[1] \ No newline at end of file diff --git a/data/items/bmp280-press.txt b/data/items/bmp280-press.txt deleted file mode 100644 index 44b9e8c9..00000000 --- a/data/items/bmp280-press.txt +++ /dev/null @@ -1 +0,0 @@ -0;bmp280-press;id;anydataPress;Сенсоры;Давление;order;addr[0x76];c[1] \ No newline at end of file diff --git a/data/items/bmp280-temp.txt b/data/items/bmp280-temp.txt deleted file mode 100644 index c3cb42eb..00000000 --- a/data/items/bmp280-temp.txt +++ /dev/null @@ -1 +0,0 @@ -0;bmp280-temp;id;anydataTemp;Сенсоры;Температура;order;addr[0x76];c[1] \ No newline at end of file diff --git a/data/items/button-in.txt b/data/items/button-in.txt deleted file mode 100644 index 79d79ec9..00000000 --- a/data/items/button-in.txt +++ /dev/null @@ -1 +0,0 @@ -0;button-in;id;toggle;Кнопки;Освещение;order;pin;db[20] \ No newline at end of file diff --git a/data/items/button-out.inv.txt b/data/items/button-out.inv.txt deleted file mode 100644 index fd3bdead..00000000 --- a/data/items/button-out.inv.txt +++ /dev/null @@ -1 +0,0 @@ -0;button-out;id;toggle;Кнопки;Освещение;order;pin;inv[1];st[1] \ No newline at end of file diff --git a/data/items/button-out.npin.txt b/data/items/button-out.npin.txt deleted file mode 100644 index 33bb17da..00000000 --- a/data/items/button-out.npin.txt +++ /dev/null @@ -1 +0,0 @@ -0;button-out;id;toggle;Кнопки;Освещение;order;st[0] \ No newline at end of file diff --git a/data/items/button-out.pin.txt b/data/items/button-out.pin.txt deleted file mode 100644 index 81310f4e..00000000 --- a/data/items/button-out.pin.txt +++ /dev/null @@ -1 +0,0 @@ -0;button-out;id;toggle;Кнопки;Освещение;order;pin;st[0] \ No newline at end of file diff --git a/data/items/dallas-temp.txt b/data/items/dallas-temp.txt deleted file mode 100644 index 0da8bdca..00000000 --- a/data/items/dallas-temp.txt +++ /dev/null @@ -1 +0,0 @@ -0;dallas-temp;id;anydataTemp;Сенсоры;Температура;order;sal;index[0];int[10] \ No newline at end of file diff --git a/data/items/dht11-hum.txt b/data/items/dht11-hum.txt deleted file mode 100644 index b7d9a820..00000000 --- a/data/items/dht11-hum.txt +++ /dev/null @@ -1 +0,0 @@ -0;dht-hum;id;anydataHum;Сенсоры;Влажность;order;thd;type[dht11];c[1] \ No newline at end of file diff --git a/data/items/dht11-temp.txt b/data/items/dht11-temp.txt deleted file mode 100644 index 39c5e949..00000000 --- a/data/items/dht11-temp.txt +++ /dev/null @@ -1 +0,0 @@ -0;dht-temp;id;anydataTemp;Сенсоры;Температура;order;thd;type[dht11];c[1] \ No newline at end of file diff --git a/data/items/dht22-hum.txt b/data/items/dht22-hum.txt deleted file mode 100644 index ab69cf97..00000000 --- a/data/items/dht22-hum.txt +++ /dev/null @@ -1 +0,0 @@ -0;dht-hum;id;anydataHum;Сенсоры;Влажность;order;thd;type[dht22];c[1] \ No newline at end of file diff --git a/data/items/dht22-temp.txt b/data/items/dht22-temp.txt deleted file mode 100644 index d14a434d..00000000 --- a/data/items/dht22-temp.txt +++ /dev/null @@ -1 +0,0 @@ -0;dht-temp;id;anydataTemp;Сенсоры;Температура;order;thd;type[dht22];c[1] \ No newline at end of file diff --git a/data/items/impuls-out.txt b/data/items/impuls-out.txt deleted file mode 100644 index 99994ae5..00000000 --- a/data/items/impuls-out.txt +++ /dev/null @@ -1 +0,0 @@ -0;impuls-out;id;na;na;na;order;pin \ No newline at end of file diff --git a/data/items/input-digit.txt b/data/items/input-digit.txt deleted file mode 100644 index bfb99882..00000000 --- a/data/items/input-digit.txt +++ /dev/null @@ -1 +0,0 @@ -0;input-digit;id;inputDigit;Ввод;Введите#цифру;order;st[60] \ No newline at end of file diff --git a/data/items/input-time.txt b/data/items/input-time.txt deleted file mode 100644 index 14c29d89..00000000 --- a/data/items/input-time.txt +++ /dev/null @@ -1 +0,0 @@ -0;input-time;id;inputTime;Ввод;Введите#время;order;st[10:00] \ No newline at end of file diff --git a/data/items/logging.txt b/data/items/logging.txt deleted file mode 100644 index 8253774f..00000000 --- a/data/items/logging.txt +++ /dev/null @@ -1 +0,0 @@ -0;logging;id;chart;Графики;История;order;val[any];int[60];cnt[100] \ No newline at end of file diff --git a/data/items/modbus.txt b/data/items/modbus.txt deleted file mode 100644 index a782395a..00000000 --- a/data/items/modbus.txt +++ /dev/null @@ -1 +0,0 @@ -0;modbus;id;anydata;Modbus;Регистр;order;addr[1];reg[0];c[1] \ No newline at end of file diff --git a/data/items/output-text.txt b/data/items/output-text.txt deleted file mode 100644 index f96c2e26..00000000 --- a/data/items/output-text.txt +++ /dev/null @@ -1 +0,0 @@ -0;output-text;id;anydata;Вывод;Сигнализация;order;st[Обнаружено#движение] \ No newline at end of file diff --git a/data/items/pwm-out.txt b/data/items/pwm-out.txt deleted file mode 100644 index 39a42037..00000000 --- a/data/items/pwm-out.txt +++ /dev/null @@ -1 +0,0 @@ -0;pwm-out;id;range;Ползунки;Яркость;order;pin;st[500] \ No newline at end of file diff --git a/data/items/ultrasonic-cm.txt b/data/items/ultrasonic-cm.txt deleted file mode 100644 index cca50890..00000000 --- a/data/items/ultrasonic-cm.txt +++ /dev/null @@ -1 +0,0 @@ -0;ultrasonic-cm;id;anydata;Сенсоры;Расстояние;order;cin;map[0,500,0,100];c[1] \ No newline at end of file diff --git a/data/items/uptime.txt b/data/items/uptime.txt deleted file mode 100644 index 972241b4..00000000 --- a/data/items/uptime.txt +++ /dev/null @@ -1 +0,0 @@ -0;uptime;id;anydataTime;Системные;%name%#uptime;order \ No newline at end of file diff --git a/data/js/build.chart.js.gz b/data/js/build.chart.js.gz deleted file mode 100644 index 654707fd..00000000 Binary files a/data/js/build.chart.js.gz and /dev/null differ diff --git a/data/js/function.js.gz b/data/js/function.js.gz deleted file mode 100644 index b3e5ea56..00000000 Binary files a/data/js/function.js.gz and /dev/null differ diff --git a/data/lang/lang.ru.json b/data/lang/lang.ru.json deleted file mode 100644 index 2c089bcb..00000000 --- a/data/lang/lang.ru.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "SetDevConf": "Конфигурация устройства", - "SetDevPreset": "Выберите из списка подходящий пресет кофигурации", - - "ButSave":"Сохранить", - "ButMainPage":"Главная", - - - "SetUDPList": "Список других устройств в сети:", - "SetUDPWarn1": "После нажатия на кнопку переформировать список устройств ждите примерно минуту, а затем обновите страницу и список появится вновь", - - "SetUDPUpdateList":"Переформировать список устройств", - "SetUDPUpdatePage":"Обновить страницу", - "SetUDPNameOfDev":"Имя этого устройства:", - "SetUDPDateExchange":"Включить обмен данными между устройствами", - "SetUDPWarn2":"Если обмен данными включен, то устройства будут обмениваться широковещательными пакетами udp для формирования списка устройств и для осуществления посылки настроек mqtt. Данный обмен создает дополнительную нагрузку на wifi сеть.", - - "SetWiFiNameOfDev":"Имя устройства:", - "SetWiFiRouterConnect":"Подключение к WiFi роутеру:", - "SetWiFiAccessPoint":"Точка доступа:", - "SetWiFiWeb":"Логин и пароль web interface:", - "SetWiFiTimeZone":"Временная зона:", - "SetWiFiNTP":"Сервер NTP:", - "SetWiFiWarn1":"Имя устройства должно состоять из английских букв и иметь длинну от 6 до 12 символов", - "SetWiFiWarn2":"После того как вы введете логин пароль от вашего wifi роутера необходимо нажать кнопку сохранить, а затем обязательно нажать кнопку перезагрузить устройство внизу этой страницы", - "SetWiFiWarn3":"Устройство постоянно сканирует сеть на наличие wifi. Если роутер отключен, то устройство автоматически перейдет в режим точки доступа. Когда wifi появится устройство автоматически подключится к роутеру снова, и выключит точку доступа", - "SetWiFiWarn4":"После изменения поля NTP сервер необходимо перезагрузить устройство", - "SetWiFiWarn5":"Светодиод статуса подключения показывает четыре состояния подключения:
1. мигает редко - идет подключение к wifi
2. мигает часто - идет подключение к серверу mqtt
3. горит постоянно - модуль в режиме точки доступа,
4. не горит - модуль подключен к wifi и к mqtt.
Светодиод подключен к gpio2. Если галочка стоит - то использовать этот пин нельзя", - - "SetMQTTServerName":"Имя сервера:", - "SetMQTTPort":"Номер порта:", - "SetMQTTPrefix":"Префикс:", - "SetMQTTUserName":"Имя пользователя:", - "SetMQTTPassword":"Пароль:", - - "SetMQTTSendSettings":"Отправить настройки MQTT с этого устройства на все остальные", - "SetMQTTWarn1":"Обратите внимание что поле префикс может состоять только из одного слова и одного разделителя: /prefix, вариант вида: /prefix1/prefix2 работать не будет. После изменения поля prefix необходимо перезагрузить устройство", - "SetMQTTWarn2":"Прежде чем нажимать на кнопку Отправить настройки MQTT сохрание их, если Вы их меняли. Настройки получат и перезапишут все устройства в локальной сети" -} \ No newline at end of file diff --git a/data/presets/dal.c.txt b/data/presets/dal.c.txt deleted file mode 100644 index 7cd73ce5..00000000 --- a/data/presets/dal.c.txt +++ /dev/null @@ -1,5 +0,0 @@ -0;dallas-temp;temp;anydataTemp;Термостат;Температура;1;pin[2];index[0];int[10] -0;logging;log;chart;Термостат;История;2;val[temp];int[60];cnt[100] -0;input-digit;inputU;inputDigit;Термостат;Верхний#порог;3;st[30] -0;input-digit;inputL;inputDigit;Термостат;Нижний#порог;4;st[20] -0;button-out;button;toggle;Термостат;Нагрев;5;pin[12];st[0] \ No newline at end of file diff --git a/data/presets/dal.s.txt b/data/presets/dal.s.txt deleted file mode 100644 index dc4c8c07..00000000 --- a/data/presets/dal.s.txt +++ /dev/null @@ -1,8 +0,0 @@ -temp > inputU -button 0 -telegram нагрев#выключен 1 -end -temp < inputL -button 1 -telegram нагрев#включен 1 -end \ No newline at end of file diff --git a/data/presets/dht.c.txt b/data/presets/dht.c.txt deleted file mode 100644 index 35f8dd19..00000000 --- a/data/presets/dht.c.txt +++ /dev/null @@ -1,5 +0,0 @@ -0;dht-hum;hum;anydataHum;Теплица;Влажность;1;pin[2];type[dht11];c[1] -0;logging;log;chart;Теплица;История;2;val[hum];int[60];cnt[100] -0;input-digit;inputU;inputDigit;Теплица;Верхний#порог;3;st[45] -0;input-digit;inputL;inputDigit;Теплица;Нижний#порог;4;st[35] -0;button-out;button;toggle;Теплица;Полив;5;pin[12];st[0] \ No newline at end of file diff --git a/data/presets/dht.s.txt b/data/presets/dht.s.txt deleted file mode 100644 index f69cdc54..00000000 --- a/data/presets/dht.s.txt +++ /dev/null @@ -1,8 +0,0 @@ -hum > inputU -button 0 -telegram полив#выключен 1 -end -hum < inputL -button 1 -telegram полив#включен 1 -end \ No newline at end of file diff --git a/data/presets/rel.c.txt b/data/presets/rel.c.txt deleted file mode 100644 index af8550f0..00000000 --- a/data/presets/rel.c.txt +++ /dev/null @@ -1,4 +0,0 @@ -0;button-out;button1;toggle;Реле;Освещение;1;pin[12];st[0] -0;button-out;button2;toggle;Реле;Освещение;2;pin[13];st[0] -0;input-time;T1;inputTime;Реле;Введите#время#включения;3;st[10:00] -0;input-time;T2;inputTime;Реле;Введите#время#выключения;4;st[11:00] \ No newline at end of file diff --git a/data/presets/rel.s.txt b/data/presets/rel.s.txt deleted file mode 100644 index 844d1c5b..00000000 --- a/data/presets/rel.s.txt +++ /dev/null @@ -1,8 +0,0 @@ -timenow = T1 -button1 1 -button2 0 -end -timenow = T2 -button1 0 -button2 1 -end \ No newline at end of file diff --git a/data/s.conf.csv b/data/s.conf.csv deleted file mode 100644 index 40b35ae1..00000000 --- a/data/s.conf.csv +++ /dev/null @@ -1 +0,0 @@ -Удалить;Тип элемента;Id;Виджет;Имя вкладки;Имя виджета;Позиция виджета \ No newline at end of file diff --git a/data/s.scen.txt b/data/s.scen.txt deleted file mode 100644 index ab0c0141..00000000 --- a/data/s.scen.txt +++ /dev/null @@ -1 +0,0 @@ -// \ No newline at end of file diff --git a/data/set.dev.json b/data/set.dev.json deleted file mode 100644 index fb697b50..00000000 --- a/data/set.dev.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "configs": [ - "/config.setup.json", - "/lang/lang.ru.json" - ], - "title": "Конфигурация", - "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - }, - { - "type": "link", - "title": "{{ButMainPage}}", - "action": "/", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "h3", - "title": "Адрес сервера обновлений" - }, - { - "type": "input", - "title": "ip address", - "name": "serverip-arg", - "state": "{{serverip}}" - }, - { - "type": "button", - "title": "{{ButSave}}", - "action": "set?serverip=[[serverip-arg]]", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Перезагрузить устройство", - "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/set?device=ok');}", - "class": "btn btn-block btn-danger" - } - ] - } \ No newline at end of file diff --git a/data/set.device.json b/data/set.device.json deleted file mode 100644 index 55a874a1..00000000 --- a/data/set.device.json +++ /dev/null @@ -1,199 +0,0 @@ -{ - "configs": [ - "/config.setup.json", - "/config.option.json", - "/config.live.json", - "/lang/lang.ru.json" - ], - "class": "col-sm-offset-1 col-sm-10", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - }, - { - "type": "link", - "title": "{{ButMainPage}}", - "action": "/", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "h4", - "title": "Device ID: {{chipID}}" - }, - { - "type": "h4", - "title": "IP address: {{ip}}" - }, - { - "type": "h4", - "title": "Time: {{timenow}}" - }, - { - "type": "h4", - "title": "Uptime: {{uptime}}" - }, - { - "type": "h4", - "title": "Build version: {{firmware_version}}" - }, - { - "type": "h4", - "title": "LittleFS version: 267" - }, - { - "type": "hr" - }, - { - "type": "dropdown", - "name": "help-url1", - "class": "btn btn-default", - "style": "display:inline", - "title": { - "#": "Выберите элемент из списка", - "/set?addItem=button-out.pin": "1.Кнопка управляющая пином", - "/set?addItem=button-out.npin": "2.Кнопка виртуальная", - "/set?addItem=button-in": "4.Кнопка физическая", - "/set?addItem=pwm-out": "3.Широтно импульсная модуляция pwm", - "/set?addItem=input-digit": "5.Окно ввода цифровых значений", - "/set?addItem=input-time": "6.Окно ввода времени", - "/set?addItem=output-text": "7.Окно вывода любого текста, предупреждения, цифры", - "/set?addItem=analog-adc": "8.Датчик аналоговый, чтение аналогового входа", - "/set?addItem=dallas-temp": "9.Датчик температуры ds18b20", - "/set?addItem=ultrasonic-cm": "10.Датчик расстояния ультрозвуковой JSN-SR04T, HC-SR04, HY-SRF05", - "/set?addItem=dht11-temp": "11.Датчик температуры DHT11", - "/set?addItem=dht11-hum": "12.Датчик влажности DHT11", - "/set?addItem=dht22-temp": "13.Датчик температуры DHT22, DHT33, DHT44, AM2302, RHT03", - "/set?addItem=dht22-hum": "14.Датчик влажности DHT22, DHT33, DHT44, AM2302, RHT03", - "/set?addItem=bme280-temp": "15.Датчик температуры bme280", - "/set?addItem=bme280-hum": "16.Датчик влажности bme280", - "/set?addItem=bme280-press": "17.Датчик давления bme280", - "/set?addItem=bmp280-temp": "18.Датчик температуры bmp280", - "/set?addItem=bmp280-press": "19.Датчик давления bmp280", - "/set?addItem=impuls-out": "20.Создать импульсы через заданный промежуток времени (управление шд)", - "/set?addItem=modbus": "21.Прочитать регистр modbus устройства", - "/set?addItem=logging": "a.Логгирование и вывод в график любой величины", - "/set?addItem=uptime": "b.Отобразить время работы устройства" - } - }, - { - "type": "dropdown", - "name": "help-url2", - "class": "btn btn-default", - "style": "display:inline", - "title": { - "#": "Выберите пресет из списка", - "/set?addPreset=dal.c": "1.Термостат на основе ds18b20 с оповещением в телеграм", - "/set?addPreset=dht.c": "2.Контроль влажности на основе DHT с оповещением в телеграм", - "/set?addPreset=rel.c": "3.Включение выключение реле в заданное время" - } - }, - { - "type": "hr" - }, - { - "type": "csv", - "title": [ - "checkbox", - "html", - "text", - "text", - "text", - "text", - "text" - ], - "state": "s.conf.csv", - "style": "width:100%;", - "action": "/set?saveItems", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "link", - "title": "Удалить выбранные элементы", - "action": "javascript:{send_request(this,'/set?delChoosingItems');setTimeout(function(){location.href='/?set.device' ; }, 1000);}", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Удалить все", - "action": "/set?delAllItems", - "class": "btn btn-block btn-default" - }, - { - "type": "text", - "title": "

После любого изменения таблицы элементов, включая удаление/добавление строк, необходимо нажать кнопку СОХРАНИТЬ ТАБЛИЦУ. Иногда, для корректной работы необходимо перезагрузить устройство после финального завершения его настройки

" - }, - { - "type": "h2", - "title": "Сценарии" - }, - { - "type": "checkbox", - "name": "scen", - "title": "Включить сценарии", - "action": "/set?scen=[[scen]]", - "state": "{{scen}}" - }, - { - "type": "file", - "state": "s.scen.txt", - "style": "width:100%;height:350px", - "title": "Сохранить", - "action": "/set?sceninit", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "link", - "title": "Ручная настройка", - "action": "/?set.manual", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "Инструкция к системе автоматизации", - "action": "https://github.com/IoTManagerProject/IoTManager/wiki", - "class": "btn btn-block btn-default" - }, - { - "type": "button", - "title": "Очистить логи сенсоров", - "action": "/set?cleanlog", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "h3", - "name": "my-block", - "style": "position:fixed;top:50%;left:50%;width:400px;margin-left:-200px;text-align:center;", - "class": "hidden" - }, - { - "type": "button", - "title": "Обновить прошивку устройства", - "action": "/check", - "response": "[[my-block]]", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "link", - "title": "Перезагрузить устройство", - "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/set?device=ok');}", - "class": "btn btn-block btn-danger" - } - ] -} \ No newline at end of file diff --git a/data/set.manual.json b/data/set.manual.json deleted file mode 100644 index bd3b7ba0..00000000 --- a/data/set.manual.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "configs": [ - "/config.setup.json", - "/config.option.json", - "/config.live.json", - "/lang/lang.ru.json" - ], - "class": "col-sm-offset-1 col-sm-10", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - }, - { - "type": "link", - "title": "{{ButMainPage}}", - "action": "/", - "class": "btn btn-block btn-default" - }, - { - "type": "file", - "state": "s.conf.csv", - "style": "width:100%;height:350px", - "title": "Сохранить", - "action": "/set?saveItems", - "class": "btn btn-block btn-default" - }, - { - "type": "file", - "state": "s.scen.txt", - "style": "width:100%;height:350px", - "title": "Сохранить", - "action": "/set?sceninit", - "class": "btn btn-block btn-default" - } - ] -} \ No newline at end of file diff --git a/data/set.mqtt.json b/data/set.mqtt.json deleted file mode 100644 index a088c2dc..00000000 --- a/data/set.mqtt.json +++ /dev/null @@ -1,133 +0,0 @@ -{ - "configs": [ - "/config.setup.json", - "/lang/lang.ru.json" - ], - "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - - }, - { - "type": "link", - "title": "{{ButMainPage}}", - "action": "/", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - - { - "type": "h4", - "title": "{{SetMQTTServerName}}", - "style": "width:60%;float:left;" - }, - { - "type": "input", - "title": "", - "name": "mqttServer-arg", - "state": "{{mqttServer}}", - "style": "width:40%;float:right" - }, - { - "type": "h4", - "title": "{{SetMQTTPort}}", - "style": "width:60%;float:left;" - }, - { - "type": "input", - "title": "", - "name": "mqttPort-arg", - "state": "{{mqttPort}}", - "style": "width:40%;float:right" - }, - { - "type": "h4", - "title": "{{SetMQTTPrefix}}", - "style": "width:60%;float:left;" - }, - { - "type": "input", - "title": "", - "name": "mqttPrefix-arg", - "state": "{{mqttPrefix}}", - "style": "width:40%;float:right" - }, - { - "type": "h4", - "title": "{{SetMQTTUserName}}", - "style": "width:60%;float:left;" - }, - { - "type": "input", - "title": "", - "name": "mqttUser-arg", - "state": "{{mqttUser}}", - "style": "width:40%;float:right" - }, - { - "type": "h4", - "title": "{{SetMQTTPassword}}", - "style": "width:60%;float:left;" - }, - { - "type": "input", - "title": "", - "name": "mqttPass-arg", - "state": "{{mqttPass}}", - "style": "width:40%;float:right" - }, - { - "type": "h3", - "name": "my-block", - "style": "position:fixed;top:30%;left:50%;width:400px;margin-left:-200px;text-align:center;", - "class": "hidden" - }, - - { - "type": "button", - "title": "{{ButSave}}", - "style": "width:100%;float:left;", - "action": "set?mqttServer=[[mqttServer-arg]]&mqttPort=[[mqttPort-arg]]&mqttPrefix=[[mqttPrefix-arg]]&mqttUser=[[mqttUser-arg]]&mqttPass=[[mqttPass-arg]]", - "class": "btn btn-block btn-default" - }, - { - "type": "button", - "style": "width:100%;float:left;", - "title": "{{SetMQTTSendSettings}}", - "action": "set?mqttsend", - "class": "btn btn-block btn-default" - }, - - { - "type": "button", - "style": "width:100%;float:left;", - "title": "Проверить соединение с MQTT", - "action": "set?mqttcheck", - "response": "[[my-block]]", - "class": "btn btn-block btn-default" - }, - { - "type": "text", - "style": "width:100%;float:left;", - "title": "

{{SetMQTTWarn1}}

" - - }, - { - "type": "text", - "style": "width:100%;float:left;", - "title": "

{{SetMQTTWarn2}}

" - }, - { - "type": "link", - "style": "width:100%;float:left;", - "title": "Перезагрузить устройство", - "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/restart?device=ok');}", - "class": "btn btn-block btn-danger" - } - ] -} \ No newline at end of file diff --git a/data/set.telegram.json b/data/set.telegram.json deleted file mode 100644 index 76560093..00000000 --- a/data/set.telegram.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "configs": [ - "/config.setup.json", - "/lang/lang.ru.json" - ], - "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - }, - { - "type": "link", - "title": "{{ButMainPage}}", - "action": "/", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "checkbox", - "name": "tel", - "title": "Включить телеграм", - "action": "/set?telegonof=[[tel]]", - "state": "{{telegonof}}" - }, - { - "type": "hr" - }, - { - "type": "h4", - "style": "width:40%;float:left;", - "title": "Telegram API token:" - }, - { - "type": "input", - "title": "", - "name": "telegramApi-arg", - "style": "width:60%;float:right", - "state": "{{telegramApi}}" - }, - { - "type": "button", - "title": "{{ButSave}}", - "action": "set?telegramApi=[[telegramApi-arg]]", - "class": "btn btn-block btn-default", - "style": "width:100%;display:inline" - }, - { - "type": "hr" - }, - { - "type": "text", - "title": "

После настройки telegram перезагрузите устройство что бы изменения вступили в силу

" - }, - { - "type": "hr" - }, - { - "type": "link", - "title": "Перезагрузить устройство", - "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/set?device=ok');}", - "class": "btn btn-block btn-danger" - } - ] -} \ No newline at end of file diff --git a/data/set.udp.json b/data/set.udp.json deleted file mode 100644 index 6bea3042..00000000 --- a/data/set.udp.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "configs": [ - "/config.setup.json", - "/lang/lang.ru.json" - ], - "title": "Главная", - "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - }, - { - "type": "link", - "title": "{{ButMainPage}}", - "action": "/", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "h3", - "title": "{{SetUDPList}}" - }, - { - "type": "hr" - }, - { - "type": "csv", - "title": [ - "html", - "html", - "html" - ], - "state": "dev.csv", - "style": "width:100%;", - "class": "nan" - }, - { - "type": "hr" - }, - { - "type": "link", - "title": "{{SetUDPUpdateList}}", - "action": "/set?updatelist", - "class": "btn btn-block btn-default" - }, - { - "type": "link", - "title": "{{SetUDPUpdatePage}}", - "action": "/set?updatepage", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "text", - "title": "

{{SetUDPWarn1}}

", - "style": "width:100%;float:left;" - }, - { - "type": "h3", - "title": "{{SetUDPNameOfDev}}" - }, - { - "type": "input", - "title": "{{SetUDPNameOfDev}}", - "name": "devname-arg", - "state": "{{name}}", - "pattern": "[A-Za-z0-9]{6,12}" - }, - { - "type": "button", - "title": "{{ButSave}}", - "action": "/set?devname=[[devname-arg]]", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "checkbox", - "name": "udponoff", - "title": "{{SetUDPDateExchange}}", - "action": "/set?udponoff=[[udponoff]]", - "state": "{{udponoff}}" - }, - { - "type": "text", - "title": "

{{SetUDPWarn2}}

" - } - ] -} \ No newline at end of file diff --git a/data/set.utilities.json b/data/set.utilities.json deleted file mode 100644 index 9314cd8b..00000000 --- a/data/set.utilities.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "configs": [ - "/config.live.json", - "/config.setup.json", - "/lang/lang.ru.json" - ], - "title": "Главная", - "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - }, - { - "type": "link", - "title": "{{ButMainPage}}", - "action": "/", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "h3", - "title": "Сканирование шины i2c" - }, - { - "type": "h4", - "title": "{{i2c}}" - }, - { - "type": "link", - "title": "Сканировать", - "action": "/set?i2c", - "class": "btn btn-block btn-default" - } - ] -} \ No newline at end of file diff --git a/data/set.wifi.json b/data/set.wifi.json deleted file mode 100644 index 936d1cc2..00000000 --- a/data/set.wifi.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "configs": [ - "/config.setup.json", - "/lang/lang.ru.json" - ], - "title": "Конфигурация", - "class": "col-sm-offset-1 col-sm-10 col-md-offset-2 col-md-8 col-lg-offset-3 col-lg-6", - "content": [ - { - "type": "h5", - "title": "{{name}}", - "class": "alert-default" - }, - { - "type": "link", - "title": "{{ButMainPage}}", - "action": "/", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "h3", - "title": "{{SetWiFiNameOfDev}}" - }, - { - "type": "input", - "title": "{{SetWiFiNameOfDev}}", - "name": "devname-arg", - "state": "{{name}}" - }, - { - "type": "button", - "title": "{{ButSave}}", - "action": "set?devname=[[devname-arg]]", - "class": "btn btn-block btn-default" - }, - { - "type": "text", - "title": "

{{SetWiFiWarn1}}

" - }, - { - "type": "hr" - }, - { - "type": "h3", - "title": "{{SetWiFiRouterConnect}}" - }, - { - "type": "input", - "title": "", - "name": "routerssid-arg", - "state": "{{routerssid}}" - }, - { - "type": "password", - "title": "", - "name": "routerpass-arg", - "state": "{{routerpass}}" - }, - { - "type": "button", - "title": "{{ButSave}}", - "class": "btn btn-block btn-default", - "action": "set?routerssid=[[routerssid-arg]]&routerpass=[[routerpass-arg]]" - }, - { - "type": "text", - "title": "

{{SetWiFiWarn2}}

" - }, - { - "type": "hr" - }, - { - "type": "checkbox", - "name": "blink", - "title": "Включить светодиод статуса подключения", - "action": "/set?blink=[[blink]]", - "state": "{{blink}}" - }, - { - "type": "text", - "title": "

{{SetWiFiWarn5}}

" - }, - { - "type": "hr" - }, - { - "type": "h3", - "title": "{{SetWiFiAccessPoint}}" - }, - { - "type": "input", - "title": "", - "name": "apssid-arg", - "state": "{{apssid}}", - "pattern": ".{1,20}" - }, - { - "type": "password", - "title": "", - "name": "appass-arg", - "state": "{{appass}}", - "pattern": ".{8,20}" - }, - { - "type": "button", - "title": "{{ButSave}}", - "action": "set?apssid=[[apssid-arg]]&appass=[[appass-arg]]", - "class": "btn btn-block btn-default" - }, - { - "type": "text", - "title": "

{{SetWiFiWarn3}}

" - }, - { - "type": "hr" - }, - { - "type": "h3", - "title": "{{SetWiFiWeb}}" - }, - { - "type": "input", - "title": "Логин", - "name": "weblogin-arg", - "state": "{{weblogin}}", - "pattern": ".{1,20}" - }, - { - "type": "password", - "title": "Пароль", - "name": "webpass-arg", - "state": "{{webpass}}", - "pattern": ".{1,20}" - }, - { - "type": "button", - "title": "{{ButSave}}", - "action": "set?weblogin=[[weblogin-arg]]&webpass=[[webpass-arg]]", - "class": "btn btn-block btn-default" - }, - { - "type": "hr" - }, - { - "type": "h3", - "title": "{{SetWiFiTimeZone}}" - }, - { - "type": "input", - "title": "", - "name": "timezone-arg", - "state": "{{timezone}}", - "pattern": ".{1,20}" - }, - { - "type": "input", - "title": "", - "name": "ntp-arg", - "state": "{{ntp}}" - }, - { - "type": "button", - "title": "{{ButSave}}", - "action": "set?timezone=[[timezone-arg]]&ntp=[[ntp-arg]]", - "class": "btn btn-block btn-default" - }, - { - "type": "text", - "title": "

{{SetWiFiWarn4}}

" - }, - { - "type": "hr" - }, - { - "type": "link", - "title": "Перезагрузить устройство", - "action": "javascript:if(confirm(renameBlock(jsonResponse,'Перезагрузить?'))){send_request(this,'/set?device=ok');}", - "class": "btn btn-block btn-danger" - } - ] -} \ No newline at end of file diff --git a/data/widgets/alarm.json b/data/widgets/alarm.json deleted file mode 100644 index e0e636c3..00000000 --- a/data/widgets/alarm.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "widget": "anydata", - "icon": "body", - "color": "red", - "descrColor": "red" -} \ No newline at end of file diff --git a/data/widgets/anydata.json b/data/widgets/anydata.json deleted file mode 100644 index 4157b9c9..00000000 --- a/data/widgets/anydata.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget": "anydata", - "after": "", - "icon": "" -} \ No newline at end of file diff --git a/data/widgets/anydataHum.json b/data/widgets/anydataHum.json deleted file mode 100644 index ebc5b5af..00000000 --- a/data/widgets/anydataHum.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget": "anydata", - "after": "%", - "icon": "water" -} \ No newline at end of file diff --git a/data/widgets/anydataPress.json b/data/widgets/anydataPress.json deleted file mode 100644 index e67af2c8..00000000 --- a/data/widgets/anydataPress.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget": "anydata", - "after": "mm", - "icon": "speedometer" -} \ No newline at end of file diff --git a/data/widgets/anydataTemp.json b/data/widgets/anydataTemp.json deleted file mode 100644 index 112da222..00000000 --- a/data/widgets/anydataTemp.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget": "anydata", - "after": "°С", - "icon": "thermometer" -} \ No newline at end of file diff --git a/data/widgets/anydataTime.json b/data/widgets/anydataTime.json deleted file mode 100644 index 888a40f6..00000000 --- a/data/widgets/anydataTime.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget": "anydata", - "after": "", - "icon": "speedometer" - } \ No newline at end of file diff --git a/data/widgets/btn.json b/data/widgets/btn.json deleted file mode 100644 index 67dcc0d3..00000000 --- a/data/widgets/btn.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "widget": "btn", - "size": "large", - "color": "green", - "send": "test" -} \ No newline at end of file diff --git a/data/widgets/chart.json b/data/widgets/chart.json deleted file mode 100644 index 9ecc61e3..00000000 --- a/data/widgets/chart.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "widget": "chart", - "dateFormat": "HH:mm" -} \ No newline at end of file diff --git a/data/widgets/fillgauge.json b/data/widgets/fillgauge.json deleted file mode 100644 index 34315ea8..00000000 --- a/data/widgets/fillgauge.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "widget": "fillgauge", - "circleColor": "#00FFFF", - "textColor": "#FFFFFF", - "waveTextColor": "#000000", - "waveColor": "#00FFFF" -} \ No newline at end of file diff --git a/data/widgets/inputDate.json b/data/widgets/inputDate.json deleted file mode 100644 index ecc3113d..00000000 --- a/data/widgets/inputDate.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "widget" : "input", - "size" : "small", - "color" : "orange", - "type" : "date" -} \ No newline at end of file diff --git a/data/widgets/inputDigit.json b/data/widgets/inputDigit.json deleted file mode 100644 index 20196c6a..00000000 --- a/data/widgets/inputDigit.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget" : "input", - "color" : "blue", - "type" : "number" -} \ No newline at end of file diff --git a/data/widgets/inputText.json b/data/widgets/inputText.json deleted file mode 100644 index 3484d53b..00000000 --- a/data/widgets/inputText.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "widget" : "input", - "size" : "small", - "color" : "orange", - "type" : "text" -} \ No newline at end of file diff --git a/data/widgets/inputTime.json b/data/widgets/inputTime.json deleted file mode 100644 index e39942a4..00000000 --- a/data/widgets/inputTime.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget" : "input", - "color" : "blue", - "type" : "time" -} \ No newline at end of file diff --git a/data/widgets/progress-line.json b/data/widgets/progress-line.json deleted file mode 100644 index b2a95529..00000000 --- a/data/widgets/progress-line.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "widget": "progress-line", - "icon": "sunny", - "descrColor": "", - "color": "", - "max": "100", - "background": "", - "stroke": "10", - "disabled": "", - "before": "", - "after": "" -} \ No newline at end of file diff --git a/data/widgets/progress-round.json b/data/widgets/progress-round.json deleted file mode 100644 index bf3ddae5..00000000 --- a/data/widgets/progress-round.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "widget": "progress-round", - "descrColor": "", - "max": "100", - "stroke": "20", - "color": "#45ccce", - "background": "#777", - "before": "", - "semicircle": "1", - "after": "" -} \ No newline at end of file diff --git a/data/widgets/range.json b/data/widgets/range.json deleted file mode 100644 index 4d1e0ff3..00000000 --- a/data/widgets/range.json +++ /dev/null @@ -1,9 +0,0 @@ - { - "widget" : "range", - "descrColor": "red", - "after" : "%", - "k" : 0.0977, - "min" : 0, - "max" : 100, - "debounce": 500 -} \ No newline at end of file diff --git a/data/widgets/select.json b/data/widgets/select.json deleted file mode 100644 index bad018fd..00000000 --- a/data/widgets/select.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "widget": "select", - "options": [ - "Выключен", - "Включен" - ], - "status": 0 -} \ No newline at end of file diff --git a/data/widgets/toggle.json b/data/widgets/toggle.json deleted file mode 100644 index 4e9eed5e..00000000 --- a/data/widgets/toggle.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget": "toggle", - "icon": "", - "iconOff": "" -} \ No newline at end of file diff --git a/data/widgets/toggleSunMoon.json b/data/widgets/toggleSunMoon.json deleted file mode 100644 index 5501aa75..00000000 --- a/data/widgets/toggleSunMoon.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "widget": "toggle", - "icon": "sunny", - "iconOff": "moon" -} \ No newline at end of file diff --git a/doc/1.txt b/doc/1.txt deleted file mode 100644 index d08be432..00000000 --- a/doc/1.txt +++ /dev/null @@ -1,566 +0,0 @@ -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) - -## Возможности - - - Объединение различных по типу и назначению устройств: управление, получение данных, и настройка параметров - всё в одном приложении - - - Взаимодействие с устройствами осуществляется через "облачный" сервис с использованием протокола mqtt, позволит контролировать их из любой точки Мира (при наличии доступа в Интернет) - - - Поддержка нескольких профилей и их переключение "на лету", дает возможность объединить устройства в группы - - -Настройка (после "прошивки") производится через веб-интерфейс, чтобы получить к нему доступ необходимо соединиться с WiFi AP устройства и набрать в адресной строке браузера http://192.168.4.1. -Далее выбрать типовой шаблон автоматизации, произвести настройку под свои требования и задачи. -Основные разделы интерфейса: конфигурация и сценарии. -В окне конфигурации задаются "объекты", "элементы управления" устройства (dashboard) - им устройство будет представлено в приложении компаньоне проекта. В окне сценариев задаются реакции на события и изменения в параметрах работы системы. - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) - -## Команды, назначение и применение - -Команды служат для настройки и управления устройством и его взаимодействия - -**`buttonSet 1 1`** Изменит состояние "кнопки" №1, установит его в значение 1 - -**`pinSet 13 0`** Установит GPIO 13 состояние 0 - -**`pinChange 13`** Состояние GPIO 13 будет изменено на противоположное - -**`pwmSet 1 500`** Настройка pwm №1 будет использовано значение 500 - -**`timeSet 1 08-00-00`** Установит для элемента ввода времени - inputTime значение 08:00:00 - -**`digitSet 1 56`** Элемент №1 (для цифровых параметров) отобразит число 56 - -**`stepperSet 1 100 1`** Шаговый двигатель №1 - вращение 100 "шагов" по часовой стрелке (для движения в обратную сторону используются отрицательные значения параметра) - -**`servoSet 1 180`** Сервопривод №1 принять положение 180° - -**`timerStart 1 60 sec`** Установить для таймера №1 обратный отсчёт в 60 секунд - -**`timerStop 1`** Остановить таймер №1 - -**`textSet 1 Привет`** Установить для элемента текстовое поле №1 - "привет" - -**`push Внимание Протечка`** Отправить push-уведомление с темой "внимание" и содержанием "протечка" - -**`firmwareUpdate`** Обновить прошивку устройства "по воздуху" - -**`firmwareVersion Версия прошивки Системные 1`** Узнать версию прошивки устройстве - -## Сценарии - -Элементарный блок в сценарии состоит из набора команд и триггера - условия для их выполнения - -**temp > 60** -digitSet 1 60 -stepperSet 1 100 1 -textSet 1 Перегрев -**end** - -Условие: когда температура превысит 60° -Запустит: команда шаговому двигателю, в приложение отправить сообщение и цифровое значение температуры. - -В сценарии может быть несколько блоков, при необходимости из приложения есть возможность "выключать" часть из них. -Неактивные блоки сценария будут проигнорированы. - -Для взаимодействия устройств между собой предусмотрены команды mqtt и http - -**temp > 60** -mqtt 154348-134 digitSet_1_56 -mqtt 154348-136 stepperSet _1_100_1 -http 192.168.1.10 textSet_1_Перегрев -**end** - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 1.1 Объект "кнопка" - -(эти строки мы пишем в "конфигурации устройства") - -### a) кнопка управляющая выходом (пином). Пины нумеруются по системе нумирации gpio для esp контроллеров. - -`button 1 13 кухня освещение 0 1` - -**"button"** это объект создающий кнопку в приложении -**"1"** это номер этой кнопки (необходимый для ее аутентификации) -**"13"** это номер пина которым будет управлять данная кнопка -**"кухня"** это название кнопки в приложении -**"освещение"** это название вкладки в приложении на которой появится данная кнопка -**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1) -**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта - - -### б) виртуальная кнопка - кнопка реакцию на которую можно задать в сценариях: - -`button 1 na запустить таймеры 0 1` - -**"button"** это объект создающий кнопку в приложении -**"1"** это номер этой кнопки (необходимый для ее аутентификации) -**"na"** абривиатура not available означающая что эта кнопка виртуальная и что пин не установлен -**"запустить"** это название кнопки в приложении -**"таймеры"** это название вкладки в приложении на которой появится данная кнопка -**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1) -**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта - -### в) кнопка включающая и выключающая все сценарии: - -`button 1 scenario запустить таймеры 0 1` - -**"button"** это объект создающий кнопку в приложении -**"1"** это номер этой кнопки (необходимый для ее аутентификации) -**"scenario"** слово означающее что эта кнопка для управления сценариями -**"запустить"** это название кнопки в приложении -**"таймеры"** это название вкладки в приложении на которой появится данная кнопка -**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1) -**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта - - -### г) кнопка включающая выключающая определенные блоки сценариев: - -`button 1 line1,line3, Включить#отправку#push Оповещение 0 1` - -**"button"** это объект создающий кнопку в приложении -**"1"** это номер этой кнопки (необходимый для ее аутентификации) -**"line1,line3,"** это блоки сценариев нумирация сверху вниз. Блоком считается выражение от начала до слова end -**"Включить#отправку#push"** это название кнопки в приложении -**"Оповещение"** это название вкладки в приложении на которой появится данная кнопка -**"0"** это начальное состояние кнопки при старте модуля (выкд 0, вкл 1) -**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта - -## 1.2 Команды управления объектом "кнопка" - -(эти строки мы пишем в "сценариях") - - ### а) Команда включения выключения кнопки по ее номеру - -`buttonSet 1 1` - -**"buttonSet"** команда управления объектом button -**"1"** номер кнопки которой будем управлять -**"1"** состояние включено, 0 - выключено - -### б) Команда изменения состояния кнопки на противоположное - -`buttonChange 1` - -**"buttonChange"** команда управления объектом button -**"1"** номер кнопки которой будем управлять - -## 1.3 Вызов событий объектом "кнопока" - -(эти строки мы пишем в "сценариях") - -объект button может быть равен либо 0 либо 1 - -`button1 = 1` -`button2 = 0` - -Пример использования: - -`button1 = 1` -`buttonSet 2 1` -`buttonSet 3 0` -`end` - - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 2.1 Объект "физическая кнопка" - -`switch 1 0 10` - -**switch** это объект создающий физическую кнопку -**1** номер кнопки -**0** пин кнопки (при подключении необходим подтягивающий резистор) -**10** задержка для избавления от дребезга с мили секундах - -## 2.2 Вызов событий объектом "физическая кнопка" - -`switch1` может быть равна нулю или единицы, ноль - событие отбрасывания кнопки, единица - событие нажатия - -`switch1 = 1` -`buttonChange 1` -`end` - - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 3.1 Объект "широтноимпульсная модуляция" - -`pwm 1 12 яркость освещение 1023 1` - -**"pwm"** это объект создающий управление шим в приложении в виде ползунка -**"1"** это номер этого объекта -**"12"** это номер пина на котором будет генерироваться шим заданной в приложении величены -**"Яркость"** это название кнопки в приложении -**"Оповещение"** это название вкладки в приложении на которой появится данная кнопка -**"1023"** это начальное значение шим сигнала и ползунка (изменяется от 0 до 1023) -**"1"** это уникальный номер и номер сортировки данной кнопки. Этот номер должен быть уникален для каждого объекта - -## 3.2 Команда управления объектом "широтноимпульсная модуляция" - -`pwmSet 1 500` - -**"pwmSet"** команда управления объектом -**"1"** номер объекта, которым будем управлять -**"500"** значение которое установится после выполнения команды (от 0 до 1023) - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 4.1 Объект "окно ввода времени" - -`inputTime time1 Во#сколько#включить? Таймеры 20-30-00 1` - -**inputTime** это объект создающий окно ввода в приложении -**time1** переменная в которую будет записано время введенное в окно -**Во#сколько#включить?** это название окна в приложении -**Таймеры** это название вкладки в приложении -**20-30-00** начальное значение времени после загрузки устройства -**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта - -## 4.2 Управление объектом "окно ввода времени" - -`timeSet 1 08-00-00` - -**"timeSet"** команда управления объектом -**"1"** номер объекта, которым будем управлять в данном случае окном ввода с `time1` -**"08-00-00"** время которое хотим установить - -В окно ввода можно вводить время в приложении но если необходимо изменить время автоматически -по какому нибудь событию то можно использовать команду выше - **timeSet**. - -## 4.3 Вызов событий объектом "окно ввода времени" - -`timenow = time1` -`buttonSet 1 1` -`end` - -`timenow` всегда хранит в себе текущее время, и поэтому исходя из данного сценария кнопка номер 1 включится в то время которое будет введено в окно ввода `time1` - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 5.1 Объект "окно ввода цифры" - -`inputDigit digit1 Через#сколько#секунд#выключить? Таймеры 5 2` - -**inputDigit** это объект создающий окно ввода в приложении -**digit1** переменная в которую будет записана цифра, введенная в окно -**Через#сколько#секунд#выключить?** это название окна в приложении -**Таймеры** это название вкладки в приложении -**5** цифра по умолчанию, после загрузки модуля -**2** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта - -## 5.2 Управление объектом "окно ввода цифры": - -`digitSet 1 56` - -**"digitSet"** команда управления объектом -**"1"** номер объекта, которым будем управлять в данном случае окном ввода с `digit1` -**"56"** цифра которую хотим установить - -В окно ввода можно вводить цифры в приложении, но если необходимо изменить цифру автоматически -по какому нибудь событию, то можно использовать команду выше - **digitSet**. - -## 5.3 Вызов событий объектом "окно ввода цифры" - -`dallas > digit1` -`buttonSet 1 0` -`end` - -`button1 = 1` -`timerStart 1 digit1 sec` -`end` - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 6.1 Объект "dallas" (сенсор температуры ds18b20) - -`dallas temp1 2 123456 Водонагреватель,#t°C Термостат any-data 1` - -**dallas** это объект чтения датчика температуры -**2** пин датчика температуры -**Водонагреватель,#t°C** это название виджета в приложении -**Датчики** название вкладки в приложении -**any-data** или **progress-round** или **progress-line** три разных варианта виджета отображения -**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта - -## 6.2 Вызов событий объектом "dallas" - -В сценариях dallas можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=): - -`dallas > digit1` -`buttonSet 1 0` -`end` - -Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=): - -`dallas > 60` -`buttonSet 1 0` -`end` - - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 7.1 Объект "analog" (аналоговый вход контроллера) - -`analog adc 0 Аналоговый#вход,#% Датчики progress-round 310 620 1 100 1` - -**analog** это объект чтения аналогового входа -**adc** это переменная -**0** пин аналогового входа (для esp8266 всегда 0, для esp32 пока что не доделал читаться будет всегда пин 34) -**Аналоговый#вход,#%** это название виджета в приложении -**Датчики** название вкладки в приложении -**any-data** или **progress-round** или **progress-line** три разных варианта виджета отображения -**310** начальная величина читаемого диапазона -**620** конечная величина читаемого диапазона -**1** начальная величина выводимого диапазона -**100** конечная величина выводимого диапазона -**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта - -## 7.2 Вызов событий объектом "analog" - -В сценариях analog можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=): - -`analog > digit1` -`buttonSet 1 0` -`end` - -Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=): - -`analog > 50` -`buttonSet 1 0` -`end` - - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 8.1 Объект "level" (ультразвуковой дальномер JSN-SR04T, HC-SR04, HY-SRF05) - -`level Вода#в#баке,#% Датчики any-data 125 20 1` - -**level** это объект чтения датчика расстояния -**Вода#в#баке** это название виджета в приложении -**Датчики** название вкладки в приложении -**any-data** или **progress-round** или **progress-line** три разных варианта отображения виджета -**125** расстояние от датчика до дна бака в сантиметрах -**20** расстояние от датчика до поверхности воды, когда бак полный, в сантиметрах -**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта - -Подключать дальномер нужно: - -| | trig | echo | -| :-: | :-: | :-: | -| wemos | D5 | D6 | -| esp | 14 | 12 | - -## 8.2 Вызов событий объектом "level" - -В сценариях level можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=): - -`level > digit1` -`buttonSet 1 0` -`end` - -Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=): - -`level > 95` -`buttonSet 1 0` -`end` - - - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 9.1 Объект "dht" (Сенсоры DHT11, DHT22, DHT33, DHT44, AM2302, RHT03) - -dhtT DHT11 2 Температура#DHT,#t°C Датчики any-data 1 -dhtH DHT11 2 Влажность#DHT,#% Датчики any-data 2 -dhtComfort Степень#комфорта: Датчики 3 -dhtPerception Восприятие: Датчики 4 -dhtDewpoint Точка#росы: Датчики 5 - -**dhtT** или **dhtH** температура или влажность -**DHT11** или **DHT22** чтение DHT11 или DHT22, DHT33, DHT44, AM2302, RHT03 соответственно -**2** пин датчика -**Температура#DHT,#t°C** это название виджета в приложении -**Датчики** название вкладки в приложении -**any-data** или **progress-round** или **progress-line** три разных варианта отображения виджета -**1** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта - -## 9.2 Вызов событий объектом "dhtT" или "dhtH" - -В сценариях "dhtT" или "dhtH" можно сравнивать с переменной окна ввода `digit1` (>,<,>=,<=,=): - -`dhtT > digit1` -`buttonSet 1 0` -`end` - -`dhtH > digit1` -`buttonSet 1 0` -`end` - -Или можно сравнивать с постоянной цифрой (>,<,>=,<=,=): - -`dhtT > 50` -`buttonSet 1 0` -`end` - -`dhtH < 40` -`buttonSet 1 0` -`end` - - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 10.1 Объект "stepper" (Драйвер шагового двигателя A4988) - -stepper 1 12 4 -stepper 2 13 5 - -**stepper** объект создающий шаговый двигатель -**1** номер шаговика -**12** номер пина количества шагов -**4** номер пина направления - -## 10.2 управление объектом "stepper" - -`stepperSet 1 200 1` - -**stepperSet** команда управления шаговым двигателем -**1** номер шагового двигателя (их может быть не более двух) -**200** количество шагов (обратное направление отрицательное значение параметра) -**1** интервал между шагами (мс) - -`button1 = 1` -`stepperSet 1 200 1` -`end` -`button1 = 0` -`stepperSet 1 -200 1` -`end` - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 11.1 Объект "обратный таймер" - -Прежде чем читать этот раздел запустите пресет №3 на устройстве. -Нажав на кнопку "Выберите во что вы хотите превратить esp" - -Можно использовать цифры из окон ввода: - -`timerStart 1 digit1 sec` - -Можно писать цифры прям в объект: - -`timerStart 1 10 sec` - -Можно установить часы минуты или секунды: - -`timerStart 1 10 sec` -`timerStart 1 10 min` -`timerStart 1 10 hours` - -Используем это объект в сценариях вот так: - -`button1 = 1` -`timerStart 1 digit1 sec` -`end` - -Смысл в том что при нажатии на кнопку один запуститься обратный отчет, на величину digit1 секунд. Если напишем например: - -`dallas < 60` -`timerStart 1 digit1 sec` -`end` - -то такой же отчет запустится когда значение температуры вырастит больше 60 градусов. Таким образом обратный отчет можно запустить реакцией на любое событие. Итак теперь обратный отчет запущен, обратный таймер уменьшается, и нам надо назначить действие на тот момент когда он обнулится. Для этого я придумал выражение: `timer1 = 0` - -Используем его и в общем получаем вот такой сценарий: - -`button1 = 1` -`timerStart 1 digit1 sec` -`end` -`timer1 = 0` -`buttonSet 1 0` -`end` - -Когда таймер закончит отсчёт, кнопка станет "неактивной". Используйте преет №3, как пример подобного сценария -Например: - -`dallas < 60` -`buttonSet 1 0` -`buttonSet 2 0` -`pwmSet 1 1023` -`mqtt 2653450020 buttonChange_1` -`mqtt 2653450020 pinSet_13_1` -`http 192.168.1.32 pinSet_14_1` -`end` - -Вот что может произойти на разных устройствах по одному событию повышения температуры... - - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 12 Журнал (лог) данных - - -`logging analog 1 100 slow Аналоговый#вход Датчики 7` - -**logging** объект для логирования -**analog** или **dhtT** или **dhtH** какой сенсор будем логировать, можно указать любой -**1** период между точками в минутах -**100** количество точек (старые точки будут удаляться по мере добавления новых) -**slow** или **fast** метод выгрузки графика в приложение, slow - выгружает график по одной точке (меньше расходуется оперативка, лучше использовать для esp8266), fast - выгрузка графика сразу (больше расход оперативки, подходит для esp32) -**Аналоговый#вход** название графика в приложении -**Датчики** название вкладки в приложении -**7** это уникальный номер и номер сортировки. Этот номер должен быть уникален для каждого объекта - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) -## 13 Взаимодействие устройств между собой - -Устройства могут между собой обмениваться командами. Команды можно отправлять по http или по mqtt. -По событию на одном устройстве можно вызвать действие на другом. Например на esp01 стоит датчик температуры, реле стоит на esp02. - -Настройки esp01: - -`dhtT temp 2 dht11 Температура#DHT,#t°C Датчики any-data 1` - -`temp < 40` -`http 192.168.10.25 buttonSet_1_1` -`end` - -Настройки esp02: - -`button 1 13 Включить#реле Реле 0 1` - -И теперь когда температура датчика на esp01 станет меньше 40 градусов то на esp02 будет отправлена команда на включение кнопки: buttonSet_1_1 - -Если вы хотите отправить команду через mqtt то сценарий будет выглядеть следующим образом: - -`temp < 40` -`mqtt 12343442-12413131 buttonSet_1_1` -`end` - -где `12343442-12413131` id esp02 той на которую отправляем команду. Id можно взять в веб интерфейсе на странице конфигурация устройства. Или в списке устройств в сети. - -Теперь рассмотрим вариант внешнего управления esp с помощью get запросов. - -`http://192.168.88.239/cmd?command=buttonSet%201%201` - -Разберем эту строку. Сама команда в ней выглядит вот так: buttonSet%201%201. `%20` заменяют пробел. - -То есть что бы составить get запрос на изменение например pwm нужно: - -Взять команду `pwmSet 1 500` -Заменить в ней пробелы на `%20` получится так: `pwmSet%201%20500` -И добавить ее в конец строки `http://192.168.88.239/cmd?command=` где указывается ip адрес устройства - -В итоге получится http://192.168.88.239/cmd?command=pwmSet%201%20500 - - - - - - \ No newline at end of file diff --git a/doc/2.txt b/doc/2.txt deleted file mode 100644 index 529f22bb..00000000 --- a/doc/2.txt +++ /dev/null @@ -1,85 +0,0 @@ -# В этой инструкции будет описано как с esp отправлять email и push - -# Часть 1. Привязать email и pushbullet к сайту pushingbox - -### 1. Необходимо перейти на сайт: [pushingbox](https://www.pushingbox.com/) -### 2. Войти с помощью google -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_1.png) -### 3. Перейти в мои сервисы и добавить новый сервис -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_2.png) -### 4. Нас интересуют два сервиса email и pushbullet -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_4%2B.png) -### 5. Выбираем сначало сервис для отправки email. В окно `Name of your email configuration` - вводим слово "email". В окно `Email address` - вводим ваш email адрес. жмем submit -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_5.png) -manager_modules_firmware/blob/master/push_instruction/Screenshot_6.png) -### 6.1 Привязываем pushbullet. Переходим на сайт [pushbullet.com](https://www.pushbullet.com/) -### 6.2 Входим с гуглом или фейсбуком -### 6.3 Идем в настройки -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_7.png) -### 6.4 Создаем токен -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_8.png) -### 6.5 Идем опять в сервисы и теперь выбираем сервис pushbullet [pushingbox.com/services](https://www.pushingbox.com/services.php) нажимаем add service -### Берем токен, и вставляем его в окно Access token. -### Окно Device token (optional) оставляем пустым. -### В окно Name of your Pushbullet configuration пишем слово "push". -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_6.png) - -### 7. Теперь наш email и pushbullet привязаны к pushingbox. Далее можно скачать приложение pushbullet на телефон и войти с гуглом или фейсбуком сответственно с пунктом 6.3 этой инструкции -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_9.png) - -# Часть 2. Создание сценариев отправки email - -### 8.1. Сценарий для отправки email. Заходим в My Scenarios: -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_10.png) - -### 8.2 Пишем слово email (это имя сценария отправки email) жмем add: -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_12.png) -### 8.3 Нажимаем add an action -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_14.png) -### 8.4 Выбираем наш email который мы зарегестрировали ранее и нажимаем Add an action with this service -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_11.png) -### 8.5 Делаем все как на скриншоте и жмем submit -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_15.png) -### 8.6 Возвращаемся на мои сценарии -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_17.png) -### 8.7 Вставляем токен в веб интерфейс esp -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_18.png) - -# Часть 3. Создание сценариев отправки push - -### 9.1. Сценарий для отправки push. Заходим в My Scenarios: -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_10.png) - -### 9.2 Пишем слово push (это имя сценария отправки email) жмем add: -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_19.png) -### 9.3 Нажимаем add an action -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_20.png) -### 9.4 Выбираем наш pushbullet который мы зарегестрировали ранее и нажимаем Add an action with this service -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_11.png) -### 9.5 Делаем все как на скриншоте и жмем submit -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_15.png) -### 9.6 Возвращаемся на мои сценарии -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_21.png) -### 9.7 Вставляем токен в веб интерфейс esp -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_18.png) - -# Часть 4. Итог - -При создании такой конфигурации как на картинке: - -`button 1 na Отправить#push Push 0 1` - - -`button1 = 1` -`push внимание кнопка#нажата` -`end` - -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_22.png) - -Если мы введем токен для email то будут приходить email -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_17.png) - -Если для push то будут приходить push в pushbullet -![](https://github.com/IoTManagerProject/Wiki/tree/master/pictures/push_instruction/Screenshot_21.png) - -Способ описанный в данной инструкции более сложный в настройке но зато очень надежный. \ No newline at end of file diff --git a/doc/3.txt b/doc/3.txt deleted file mode 100644 index 31226847..00000000 --- a/doc/3.txt +++ /dev/null @@ -1,32 +0,0 @@ -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) - -### 1. Скачать архив из [релизов](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/releases) или из закрепленного сообщения группы телеграм с последней версией прошивки - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) - - -### 2. Для ESP8266 c 4 и больше мб памяти (все сделать как на скриншотах) - -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp8266_1.png) - -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp8266_2.png) - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) - -### 2. Для ESP8266 c 1 мб памяти (все сделать как на скриншотах) - -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp8266_1mb_1.png) - -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp8266_1mb_2.png) - -*** -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/1.png?raw=true) - -### 2. Для ESP32 (все сделать как на скриншотах) - -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp32_1.png) - -![](https://github.com/DmitryBorisenko33/esp32-esp8266_iot-manager_modules_firmware/blob/master/pictures/esp32_2.png) \ No newline at end of file diff --git a/doc/conf/c001.txt b/doc/conf/c001.txt deleted file mode 100644 index 733f4c95..00000000 --- a/doc/conf/c001.txt +++ /dev/null @@ -1,3 +0,0 @@ -button 1 5 Включить#реле Реле 0 1 - -//это простая кнопка номер 1 управляющая пином 5 имеющая начальное состояние 0 \ No newline at end of file diff --git a/doc/conf/c002.txt b/doc/conf/c002.txt deleted file mode 100644 index 1e54f5dd..00000000 --- a/doc/conf/c002.txt +++ /dev/null @@ -1,6 +0,0 @@ -inputTime time1 Во#сколько#включить? Таймеры 20-30-00 1 -inputTime time2 Во#сколько#выключить? Таймеры 20-35-00 2 -button 1 5 Кнопка#(по#таймеру) Таймеры 0 3 - -//время в приложение необходимо вводить в строгом формате: ЧЧ-ММ-СС -//можно создавать любое количество таймеров, копируя строку inputTime... \ No newline at end of file diff --git a/doc/conf/c003.txt b/doc/conf/c003.txt deleted file mode 100644 index 9f0c5c45..00000000 --- a/doc/conf/c003.txt +++ /dev/null @@ -1,4 +0,0 @@ -button 1 5 Вкл#на#время Таймеры 0 1 -inputDigit digit1 Через#сколько#секунд#выключить? Таймеры 5 2 - -//в сценариях можно поменять на sec, min или hours если нужны другие размерности времени \ No newline at end of file diff --git a/doc/conf/c004.txt b/doc/conf/c004.txt deleted file mode 100644 index b0978b0d..00000000 --- a/doc/conf/c004.txt +++ /dev/null @@ -1,3 +0,0 @@ -button 1 na Включить#все Освещение 0 1 - -//при нажатии на эту кнопку пины номер 5 и 13 поведут себя как установленно в сценариях \ No newline at end of file diff --git a/doc/conf/c005.txt b/doc/conf/c005.txt deleted file mode 100644 index 5ef7e5f5..00000000 --- a/doc/conf/c005.txt +++ /dev/null @@ -1,4 +0,0 @@ -button 1 13 Включить#реле Реле 0 1 -switch 1 0 10 - -//можно управлять реле на пине 13 кнопкой на пине 0 или кнопкой в приложении \ No newline at end of file diff --git a/doc/conf/c006.txt b/doc/conf/c006.txt deleted file mode 100644 index db812455..00000000 --- a/doc/conf/c006.txt +++ /dev/null @@ -1,6 +0,0 @@ -button 1 5 Включить#все Реле 0 1 - - -//что бы использовать эту конфигурацию на другой esp необходимо активировать пресет -//"Вкл. выкл. локального реле", затем в сценарии данного модуля подставить Device ID -//того esp, кнопка на этом девайсе будет выключать другие устройства по воздуху \ No newline at end of file diff --git a/doc/conf/c007.txt b/doc/conf/c007.txt deleted file mode 100644 index 739a1424..00000000 --- a/doc/conf/c007.txt +++ /dev/null @@ -1,6 +0,0 @@ -switch 1 0 10 - -//что бы использовать эту конфигурацию на другой esp необходимо активировать пресет -//"Вкл. выкл. локального реле", затем в сценарии данного модуля подставить Device ID -//того esp, к данному модулю нужно подключить кнопку к пину 0 и тогда -//один девайс будет управлять другим по воздуху \ No newline at end of file diff --git a/doc/conf/c008.txt b/doc/conf/c008.txt deleted file mode 100644 index 09eef72c..00000000 --- a/doc/conf/c008.txt +++ /dev/null @@ -1,6 +0,0 @@ -pwm 1 3 Яркость#коредор: Реле 1023 1 -pwm 2 4 Яркость#ванная: Реле 510 2 - -//в приложении появятся ползунки, соответствующее значение pwm -//будет установленно на пинах 3 и 4 -//1023 и 510 это начальные значения после загрузки модуля \ No newline at end of file diff --git a/doc/conf/c009.txt b/doc/conf/c009.txt deleted file mode 100644 index 496b4761..00000000 --- a/doc/conf/c009.txt +++ /dev/null @@ -1,7 +0,0 @@ -dhtT t 2 dht11 Температура#DHT,#t°C Датчики anydata 1 -dhtH h 2 dht11 Влажность#DHT,#t°C Датчики anydata 2 -dhtComfort Степень#комфорта: Датчики 3 -dhtPerception Восприятие: Датчики 4 -dhtDewpoint Точка#росы: Датчики 5 -logging t 1 50 Температура Датчики 6 -logging h 1 50 Влажность Датчики 7 \ No newline at end of file diff --git a/doc/conf/c010.txt b/doc/conf/c010.txt deleted file mode 100644 index 0972be00..00000000 --- a/doc/conf/c010.txt +++ /dev/null @@ -1,7 +0,0 @@ -dhtT t 2 dht22 Температура#DHT,#t°C Датчики anydata 1 -dhtH h 2 dht22 Влажность#DHT,#t°C Датчики anydata 2 -dhtComfort Степень#комфорта: Датчики 3 -dhtPerception Восприятие: Датчики 4 -dhtDewpoint Точка#росы: Датчики 5 -logging t 1 50 Температура Датчики 6 -logging h 1 50 Влажность Датчики 7 \ No newline at end of file diff --git a/doc/conf/c011.txt b/doc/conf/c011.txt deleted file mode 100644 index acf8f5e3..00000000 --- a/doc/conf/c011.txt +++ /dev/null @@ -1,8 +0,0 @@ -analog adc 0 Аналоговый#вход,#% Датчики progress-round 310 620 1 100 1 -logging adc 5 100 Аналоговый#вход Датчики 2 - -//если датчик углекислого газа выдает напряжение от 1 вольта до 2 вольт, то значит -//значение чтения аналогового входа будут примерно равным -//при 1 вольте - 310, а при 2 вольтах - 620 (считаем по пропорции) -//данная строка переведет диапазон 310-620 в диапазон 1-100 и отобразит в приложении -//варианты отображения: anydata, progress-round, progress-line, fillgauge diff --git a/doc/conf/c012.txt b/doc/conf/c012.txt deleted file mode 100644 index 3793a877..00000000 --- a/doc/conf/c012.txt +++ /dev/null @@ -1,6 +0,0 @@ -bmp280T temp1 0x76 Температура#bmp280 Датчики anydata 1 -bmp280P press1 0x76 Давление#bmp280 Датчики anydata 2 -logging temp1 1 100 Температура Датчики 3 -logging press1 1 100 Давление Датчики 4 - -//Чтение и логгирование датчика bmp280. Датчик подключается к шине i2c (esp8266 - gpio 5, 4) \ No newline at end of file diff --git a/doc/conf/c013.txt b/doc/conf/c013.txt deleted file mode 100644 index 78630cfe..00000000 --- a/doc/conf/c013.txt +++ /dev/null @@ -1,9 +0,0 @@ -bme280T temp1 0x76 Температура#bmp280 Датчики anydata 1 -bme280P pres1 0x76 Давление#bmp280 Датчики anydata 2 -bme280H hum1 0x76 Влажность#bmp280 Датчики anydata 3 -bme280A altit1 0x76 Высота#bmp280 Датчики anydata 4 -logging temp1 1 100 Температура Датчики 5 -logging press1 1 100 Давление Датчики 6 -logging hum1 1 100 Влажность Датчики 7 - -//Чтение и логгирование датчика bme280. Датчик подключается к шине i2c (esp8266 - gpio 5, 4) \ No newline at end of file diff --git a/doc/conf/c014.txt b/doc/conf/c014.txt deleted file mode 100644 index c850b3e2..00000000 --- a/doc/conf/c014.txt +++ /dev/null @@ -1,7 +0,0 @@ -dallas temp1 2 1 Температура Датчики anydata 1 -dallas temp2 2 2 Температура Датчики anydata 2 -logging temp1 1 100 Температура Датчики 3 -logging temp2 1 100 Температура Датчики 4 - -//2 - номер пина датчика -//варианты отображения: anydata, progress-round, progress-line, fillgauge \ No newline at end of file diff --git a/doc/conf/c015.txt b/doc/conf/c015.txt deleted file mode 100644 index 6567cf6d..00000000 --- a/doc/conf/c015.txt +++ /dev/null @@ -1,12 +0,0 @@ -dallas 2 Водонагреватель,#t°C Термостат anydata 1 -logging dallas 5 100 Температура Термостат 2 -inputDigit digit1 При#скольки#выключить? Термостат 40 3 -inputDigit digit2 При#скольки#включить? Термостат 20 4 -button 1 5 Нагреватель Термостат 0 5 -button 2 line1,line2, Автоматический#режим Термостат 1 6 - -//2 - номер пина датчика -//5 - номер пина реле -//это термостат который будет держать температуру между двумя -//установленными в приложении значениями, так же можно выключить -//автоматический режим, и тогда нагреватель будет управляться в ручную \ No newline at end of file diff --git a/doc/conf/c016.txt b/doc/conf/c016.txt deleted file mode 100644 index 0b82f2b9..00000000 --- a/doc/conf/c016.txt +++ /dev/null @@ -1,12 +0,0 @@ -levelPr p 14 12 Уровень#в#баке,#% Датчики fillgauge 125 25 1 -ultrasonicCm cm 14 12 Дистанция,#см Датчики anydata 2 -inputDigit digit1 При#скольки#выключить? Датчики 95 3 -inputDigit digit2 При#скольки#включить? Датчики 10 4 -button 1 5 Насос Датчики 0 5 -logging p 1 100 Вода#в#баке Датчики 6 - -//125 - это расстояние от датчика до дна бака в сантиметрах -//25 - это расстояние от датчика до поверхности воды когда бак полный в сантиметрах -//distancePr - эта строка выводит процент заполнения бака -//distanceCm - эта строка выводит расстояние в сантиметрах -//варианты отображения: anydata, progress-round, progress-line, fillgauge \ No newline at end of file diff --git a/doc/conf/c017.txt b/doc/conf/c017.txt deleted file mode 100644 index fa0b78ac..00000000 --- a/doc/conf/c017.txt +++ /dev/null @@ -1,11 +0,0 @@ -button 1 5 Прихожая Освещение 0 1 -inputDigit digit1 Задержка#выключения Освещение 30 2 -switch 1 0 10 - -//0 - номер пина датчика движения -//5 - номер пина реле -//при срабатывании датчика движения включится реле и обратный таймер на 30 сек -//если движение не будет обнаружено повтороно в течении 30 секунд - свет выключится -//если движение повторится в течении 30 секунд то таймер продлится опять на 30 сек -//свет выключится только в том случае если в комнате все замрет на 30 сек -//задержку выключения можно будет настраивать в приложении \ No newline at end of file diff --git a/doc/conf/c018.txt b/doc/conf/c018.txt deleted file mode 100644 index bc7d8192..00000000 --- a/doc/conf/c018.txt +++ /dev/null @@ -1,12 +0,0 @@ -switch 1 0 20 -text 1 Вход: Охрана 1 -textSet 1 не#обнаружено-time -button 1 na Сбросить Охрана 0 2 -button 2 line3, Включить#push Охрана 1 3 - -//0 - номер пина датчика -//при срабатывании датчика движения устройство пошлет пуш и в приложении будет -//написано в текстовом поле, что движение было обнаружено -//так же будет зафиксирован момент времени срабатывания датчика -//в приложении можно отключать отправку пуш сообщений на тот случай если дома хозяин -//перевести датчик снова в режим ожидания движения можно нажав кнопку сброса в приложении \ No newline at end of file diff --git a/doc/conf/c019.txt b/doc/conf/c019.txt deleted file mode 100644 index 82b41ae2..00000000 --- a/doc/conf/c019.txt +++ /dev/null @@ -1,17 +0,0 @@ -stepper 1 12 4 -stepper 2 13 5 -button 1 na Открыть#штору#1 Шторы 0 1 -button 2 na Открыть#штору#2 Шторы 0 2 - -//для подключения необходим драйвер шагового двигателя A4988 - -//stepper 1 12 4 шаговый двигатель с параметрами: 1 - номер шагового двигателя, -//12 - номер пина количества шагов, 4 - номер пина направления - -//stepper 2 13 5 шаговый двигатель с параметрами: 2 - номер шагового двигателя, -//13 - номер пина количества шагов, 5 - номер пина направления - -//stepperSet 1 200 5 - прокрутить шаговик номер 1 на 200 шагов по часовой стрелке -//с задержкой между шагами 5 милисекунд (чем меньше задержка тем больше скорость) -//если поставить -200 то будет вращаться против часовой стрелки -//можно подключить не более двух шаговиков \ No newline at end of file diff --git a/doc/conf/c020.txt b/doc/conf/c020.txt deleted file mode 100644 index 5d45aea0..00000000 --- a/doc/conf/c020.txt +++ /dev/null @@ -1,17 +0,0 @@ -servo 1 12 50 Мой#сервопривод Сервоприводы 0 100 0 180 1 -servo 2 13 50 Мой#сервопривод Сервоприводы 0 100 0 180 2 -button 1 na Открыть1 Сервоприводы 0 3 -button 2 na Открыть2 Сервоприводы 0 4 - -//Можно создавать не более двух сервоприводов на одном устройстве. -//1 - номер привода -//12 - номер пина -//50 - начальное значение в процентах - -//0 - 100 диапазон ползунка -//0 - 180 диапазон угла - -//Представим ситуацию когда есть некая заслонка и при угле в 30 градусов она закрыта, -//а при угле в 90 градусов открыта. В этом случае необходимо написать -//0 100 30 90 и тогда поставив ползунок в 0 % серва встанет в положение 30 градусов, -//а если поставить ползунок в 100 % серва встанет в положение 90 градусов. \ No newline at end of file diff --git a/doc/conf/c021.txt b/doc/conf/c021.txt deleted file mode 100644 index 615742f3..00000000 --- a/doc/conf/c021.txt +++ /dev/null @@ -1,7 +0,0 @@ -serialBegin 9600 12 13 -button 1 na Управляется#из#arduino Serial 0 1 -button 2 na Отправить#в#arduino Serial 0 2 -text 1 Текст#из#arduino Serial 3 - -//12 13 это пины uart к которым вы можете подключить arduino. Скетч для arduino выложен в группу. -//команда serialWrite ard-on отправит в arduino текст ard-on \ No newline at end of file diff --git a/doc/conf/c100.txt b/doc/conf/c100.txt deleted file mode 100644 index c943b43b..00000000 --- a/doc/conf/c100.txt +++ /dev/null @@ -1,12 +0,0 @@ -button 1 na Включить#все Реле 0 1 -button 2 13 Прихожая Реле 0 2 -button 3 14 Кухня Реле 0 3 -pwm 1 3 Яркость#коредор: Реле 1023 4 -pwm 2 4 Яркость#ванная: Реле 510 5 -analog adc 0 Аналоговый#вход Датчики fillgauge 1 1023 1 1023 6 -logging adc 1 100 Аналоговый#вход Датчики 7 - -//Это демо конфигурация. В ней показано как связать кнопки c помощью сценариев -//Кнопка номер 1 связана с кнопкой 2, 3 и с pwm 2 -//Так же продемонстрированна система логгирования данных строкой logging -//1 - это интервал между точками в минутах, 100 это количество точек \ No newline at end of file diff --git a/doc/conf/s001.txt b/doc/conf/s001.txt deleted file mode 100644 index 8b137891..00000000 --- a/doc/conf/s001.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/conf/s002.txt b/doc/conf/s002.txt deleted file mode 100644 index 5deba589..00000000 --- a/doc/conf/s002.txt +++ /dev/null @@ -1,6 +0,0 @@ -timenow = time1 -buttonSet 1 1 -end -timenow = time2 -buttonSet 1 0 -end diff --git a/doc/conf/s003.txt b/doc/conf/s003.txt deleted file mode 100644 index f8ced990..00000000 --- a/doc/conf/s003.txt +++ /dev/null @@ -1,6 +0,0 @@ -button1 = 1 -timerStart 1 digit1 sec -end -timer1 = 0 -buttonSet 1 0 -end \ No newline at end of file diff --git a/doc/conf/s004.txt b/doc/conf/s004.txt deleted file mode 100644 index 276282c3..00000000 --- a/doc/conf/s004.txt +++ /dev/null @@ -1,8 +0,0 @@ -button1 = 1 -pinSet 5 1 -pinSet 13 0 -end -button1 = 0 -pinSet 5 0 -pinSet 13 1 -end \ No newline at end of file diff --git a/doc/conf/s005.txt b/doc/conf/s005.txt deleted file mode 100644 index 093de1fe..00000000 --- a/doc/conf/s005.txt +++ /dev/null @@ -1,3 +0,0 @@ -switch1 = 1 -buttonChange 1 -end \ No newline at end of file diff --git a/doc/conf/s006.txt b/doc/conf/s006.txt deleted file mode 100644 index 9eb30933..00000000 --- a/doc/conf/s006.txt +++ /dev/null @@ -1,8 +0,0 @@ -button1 = 1 -mqtt 3233662-1589485 buttonSet_1_1 -mqtt 2233662-1589486 buttonSet_1_1 -end -button1 = 0 -mqtt 3233662-1589485 buttonSet_1_0 -mqtt 2233662-1589486 buttonSet_1_0 -end \ No newline at end of file diff --git a/doc/conf/s007.txt b/doc/conf/s007.txt deleted file mode 100644 index 0c48cbdf..00000000 --- a/doc/conf/s007.txt +++ /dev/null @@ -1,4 +0,0 @@ -switch1 = 1 -mqtt 3233662-1589485 buttonChange_1 -mqtt 2233662-1589486 buttonChange_1 -end \ No newline at end of file diff --git a/doc/conf/s008.txt b/doc/conf/s008.txt deleted file mode 100644 index 8b137891..00000000 --- a/doc/conf/s008.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/conf/s009.txt b/doc/conf/s009.txt deleted file mode 100644 index 8b137891..00000000 --- a/doc/conf/s009.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/conf/s010.txt b/doc/conf/s010.txt deleted file mode 100644 index 8b137891..00000000 --- a/doc/conf/s010.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/conf/s011.txt b/doc/conf/s011.txt deleted file mode 100644 index 8b137891..00000000 --- a/doc/conf/s011.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/conf/s012.txt b/doc/conf/s012.txt deleted file mode 100644 index 8b137891..00000000 --- a/doc/conf/s012.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/conf/s013.txt b/doc/conf/s013.txt deleted file mode 100644 index 8b137891..00000000 --- a/doc/conf/s013.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/conf/s014.txt b/doc/conf/s014.txt deleted file mode 100644 index 8b137891..00000000 --- a/doc/conf/s014.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/doc/conf/s015.txt b/doc/conf/s015.txt deleted file mode 100644 index 60782623..00000000 --- a/doc/conf/s015.txt +++ /dev/null @@ -1,6 +0,0 @@ -dallas > digit1 -buttonSet 1 0 -end -dallas < digit2 -buttonSet 1 1 -end \ No newline at end of file diff --git a/doc/conf/s016.txt b/doc/conf/s016.txt deleted file mode 100644 index babd78ab..00000000 --- a/doc/conf/s016.txt +++ /dev/null @@ -1,6 +0,0 @@ -p > digit1 -buttonSet 1 0 -end -p < digit2 -buttonSet 1 1 -end \ No newline at end of file diff --git a/doc/conf/s017.txt b/doc/conf/s017.txt deleted file mode 100644 index 899b7035..00000000 --- a/doc/conf/s017.txt +++ /dev/null @@ -1,7 +0,0 @@ -switch1 = 1 -timerStart 1 digit1 sec -buttonSet 1 1 -end -timer1 = 0 -buttonSet 1 0 -end \ No newline at end of file diff --git a/doc/conf/s018.txt b/doc/conf/s018.txt deleted file mode 100644 index f764dc9d..00000000 --- a/doc/conf/s018.txt +++ /dev/null @@ -1,10 +0,0 @@ -switch1 = 1 -textSet 1 обнаружено#движение-time -end -button1 = 1 -textSet 1 не#обнаружено-time -buttonSet 1 0 -end -switch1 = 1 -push Внимание обнаружено#движение! -end \ No newline at end of file diff --git a/doc/conf/s019.txt b/doc/conf/s019.txt deleted file mode 100644 index 16e7cfa6..00000000 --- a/doc/conf/s019.txt +++ /dev/null @@ -1,12 +0,0 @@ -button1 = 1 -stepperSet 1 200 1 -end -button1 = 0 -stepperSet 1 -200 1 -end -button2 = 1 -stepperSet 2 200 1 -end -button2 = 0 -stepperSet 2 -200 1 -end \ No newline at end of file diff --git a/doc/conf/s020.txt b/doc/conf/s020.txt deleted file mode 100644 index b4340463..00000000 --- a/doc/conf/s020.txt +++ /dev/null @@ -1,12 +0,0 @@ -button1 = 1 -servoSet 1 100 -end -button1 = 0 -servoSet 1 0 -end -button2 = 1 -servoSet 2 100 -end -button2 = 0 -servoSet 2 0 -end \ No newline at end of file diff --git a/doc/conf/s021.txt b/doc/conf/s021.txt deleted file mode 100644 index 9ae72453..00000000 --- a/doc/conf/s021.txt +++ /dev/null @@ -1,6 +0,0 @@ -button2 = 1 -serialWrite ard-11-1 -end -button2 = 0 -serialWrite ard-11-0 -end \ No newline at end of file diff --git a/doc/conf/s100.txt b/doc/conf/s100.txt deleted file mode 100644 index 4927ac1e..00000000 --- a/doc/conf/s100.txt +++ /dev/null @@ -1,13 +0,0 @@ -button1 = 1 -buttonSet 2 1 -buttonSet 3 1 -pwmSet 2 1024 -end -button1 = 0 -buttonSet 2 0 -buttonSet 3 0 -pwmSet 2 0 -end -adc > 50 -buttonSet 2 1 -end \ No newline at end of file diff --git a/doc/orders.xlsm b/doc/orders.xlsm deleted file mode 100644 index d86f040e..00000000 Binary files a/doc/orders.xlsm and /dev/null differ diff --git a/doc/pictures/001 iot manager.jpeg b/doc/pictures/001 iot manager.jpeg deleted file mode 100644 index 39914774..00000000 Binary files a/doc/pictures/001 iot manager.jpeg and /dev/null differ diff --git a/doc/pictures/002 iot manager.jpeg b/doc/pictures/002 iot manager.jpeg deleted file mode 100644 index 80b9d67c..00000000 Binary files a/doc/pictures/002 iot manager.jpeg and /dev/null differ diff --git a/doc/pictures/003 iot manager.jpeg b/doc/pictures/003 iot manager.jpeg deleted file mode 100644 index 3f23d111..00000000 Binary files a/doc/pictures/003 iot manager.jpeg and /dev/null differ diff --git a/doc/pictures/007 iot manager.jpg b/doc/pictures/007 iot manager.jpg deleted file mode 100644 index 2178d634..00000000 Binary files a/doc/pictures/007 iot manager.jpg and /dev/null differ diff --git a/doc/pictures/008 flash.jpg b/doc/pictures/008 flash.jpg deleted file mode 100644 index 65be639f..00000000 Binary files a/doc/pictures/008 flash.jpg and /dev/null differ diff --git a/doc/pictures/009 flash.jpg b/doc/pictures/009 flash.jpg deleted file mode 100644 index 14341646..00000000 Binary files a/doc/pictures/009 flash.jpg and /dev/null differ diff --git a/doc/pictures/010 flash.jpg b/doc/pictures/010 flash.jpg deleted file mode 100644 index c26de4bc..00000000 Binary files a/doc/pictures/010 flash.jpg and /dev/null differ diff --git a/doc/pictures/011 flash.jpg b/doc/pictures/011 flash.jpg deleted file mode 100644 index 7329b0c0..00000000 Binary files a/doc/pictures/011 flash.jpg and /dev/null differ diff --git a/doc/pictures/012 wifi.jpg b/doc/pictures/012 wifi.jpg deleted file mode 100644 index 13c4c9d3..00000000 Binary files a/doc/pictures/012 wifi.jpg and /dev/null differ diff --git a/doc/pictures/013 wifi.jpg b/doc/pictures/013 wifi.jpg deleted file mode 100644 index c2938a8a..00000000 Binary files a/doc/pictures/013 wifi.jpg and /dev/null differ diff --git a/doc/pictures/014 wifi.jpg b/doc/pictures/014 wifi.jpg deleted file mode 100644 index 411b7a4d..00000000 Binary files a/doc/pictures/014 wifi.jpg and /dev/null differ diff --git a/doc/pictures/015 wifi.jpg b/doc/pictures/015 wifi.jpg deleted file mode 100644 index 394d00d7..00000000 Binary files a/doc/pictures/015 wifi.jpg and /dev/null differ diff --git a/doc/pictures/016 wifi.jpg b/doc/pictures/016 wifi.jpg deleted file mode 100644 index 4369c37f..00000000 Binary files a/doc/pictures/016 wifi.jpg and /dev/null differ diff --git a/doc/pictures/017.jpg b/doc/pictures/017.jpg deleted file mode 100644 index 68b210e2..00000000 Binary files a/doc/pictures/017.jpg and /dev/null differ diff --git a/doc/pictures/018.jpg b/doc/pictures/018.jpg deleted file mode 100644 index e8c0cc93..00000000 Binary files a/doc/pictures/018.jpg and /dev/null differ diff --git a/doc/pictures/019.jpg b/doc/pictures/019.jpg deleted file mode 100644 index 5667ee58..00000000 Binary files a/doc/pictures/019.jpg and /dev/null differ diff --git a/doc/pictures/020.jpg b/doc/pictures/020.jpg deleted file mode 100644 index 13fc001e..00000000 Binary files a/doc/pictures/020.jpg and /dev/null differ diff --git a/include/BufferExecute.h b/include/BufferExecute.h deleted file mode 100644 index 238844f5..00000000 --- a/include/BufferExecute.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include - -extern void loopCmdAdd(const String& cmdStr); -extern void fileCmdExecute(const String& filename); -extern void csvCmdExecute(String& cmdStr); -extern void spaceCmdExecute(String& cmdStr); -extern void loopCmdExecute(); -extern void addKey(String& key, String& keyNumberTable, int number); -extern int getKeyNum(String& key, String& keyNumberTable); - -extern void buttonOut(); -extern void buttonOutSet(); - -extern void pwmOut(); -extern void pwmOutSet(); - -extern void buttonIn(); -extern void buttonInSet(); - -extern void inputDigit(); -extern void inputDigitSet(); - -extern void inputTime(); -extern void inputTimeSet(); - -extern void textOut(); -extern void textOutSet(); - -extern void analogAdc(); -extern void analogReading(); - -extern void ultrasonicCm(); -extern void ultrasonicReading(); - -extern void dallasTemp(); -extern void dallasReading(); - -extern void dhtTemp(); -extern void dhtReadingTemp(); -extern void dhtHum(); -extern void dhtReadingHum(); - -extern void bme280Temp(); -extern void bme280ReadingTemp(); -extern void bme280Hum(); -extern void bme280ReadingHum(); -extern void bme280Press(); -extern void bme280ReadingPress(); - -extern void bmp280Temp(); -extern void bmp280ReadingTemp(); -extern void bmp280Press(); -extern void bmp280ReadingPress(); - -//extern void modbus(); -//extern void modbusReading(); - -extern void sysUptime(); -extern void uptimeReading(); - -extern void logging(); - -extern void impuls(); diff --git a/include/Bus.h b/include/Bus.h deleted file mode 100644 index 11edd50b..00000000 --- a/include/Bus.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include -void busInit(); -String i2c_scan(); \ No newline at end of file diff --git a/include/Class/CallBackTest.h b/include/Class/CallBackTest.h deleted file mode 100644 index 6632bfe0..00000000 --- a/include/Class/CallBackTest.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include -#include -#include - -// Декларируем тип - сигнатуру метода , который мы готовы принять в данном случае это -// должен быть метод без результата и без параметров. -// Новый тип мы называем AsynсActionCb - хотя можешь назвать вообще как нравиться а что значит callBack - -typedef std::function AsyncActionCb; //метод без результата и параметров -typedef std::function AsyncParamActionCb; //метод без результата и параметров - -class CallBackTest { - private: - long count; - AsyncActionCb _cb; - AsyncParamActionCb _pcb; - - - public: - CallBackTest(); - void loop(); - void setCallback(AsyncActionCb cb); - void setCallback(AsyncParamActionCb pcb); -}; -//extern CallBackTest* CB; \ No newline at end of file diff --git a/include/Class/LineParsing.h b/include/Class/LineParsing.h deleted file mode 100644 index 99a807f1..00000000 --- a/include/Class/LineParsing.h +++ /dev/null @@ -1,237 +0,0 @@ -#pragma once - -#include - -#include "Global.h" -#include "Utils/JsonUtils.h" - -class LineParsing { - protected: - String _key; - String _file; - String _page; - String _descr; - String _order; - String _addr; - String _reg; - String _pin; - String _map; - String _c; - String _inv; - String _state; - String _db; - String _type; - String _int; - String _cnt; - String _val; - String _index; - - public: - LineParsing() : - - _key{""}, - _file{""}, - _page{""}, - _descr{""}, - _order{""}, - _addr{""}, - _reg{""}, - _pin{""}, - _map{""}, - _c{""}, - _inv{""}, - _state{""}, - _db{""}, - _type{""}, - _int{""}, - _cnt{""}, - _val{""}, - _index{""} - - {}; - - void update() { - //String order = sCmd.order(); - //SerialPrint("I","module","create '" + order + "'"); - for (int i = 1; i < 12; i++) { - if (i == 1) _key = sCmd.next(); - if (i == 2) _file = sCmd.next(); - if (i == 3) _page = sCmd.next(); - if (i == 4) _descr = sCmd.next(); - if (i == 5) _order = sCmd.next(); - } - - for (int i = 1; i < 10; i++) { - String arg = sCmd.next(); - if (arg != "") { - if (arg.indexOf("pin[") != -1) { - _pin = extractInner(arg); - } - if (arg.indexOf("inv[") != -1) { - _inv = extractInner(arg); - } - if (arg.indexOf("st[") != -1) { - _state = extractInner(arg); - } - if (arg.indexOf("db[") != -1) { - _db = extractInner(arg); - } - if (arg.indexOf("map[") != -1) { - _map = extractInner(arg); - } - if (arg.indexOf("c[") != -1) { - _c = extractInner(arg); - } - if (arg.indexOf("type[") != -1) { - _type = extractInner(arg); - } - if (arg.indexOf("addr[") != -1) { - _addr = extractInner(arg); - } - if (arg.indexOf("reg[") != -1) { - _reg = extractInner(arg); - } - if (arg.indexOf("int[") != -1) { - _int = extractInner(arg); - } - if (arg.indexOf("cnt[") != -1) { - _cnt = extractInner(arg); - } - if (arg.indexOf("val[") != -1) { - _val = extractInner(arg); - } - if (arg.indexOf("index[") != -1) { - _index = extractInner(arg); - } - } - } - - _page.replace("#", " "); - - _descr.replace("#", " "); - - _descr.replace("%ver%", String(FIRMWARE_VERSION)); - _descr.replace("%name%", jsonReadStr(configSetupJson, F("name"))); - - createWidget(_descr, _page, _order, _file, _key); - } - - //jsonWriteStr(configOptionJson, _key + "_pin", _pin); - - String gkey() { - return _key; - } - String gfile() { - return _file; - } - String gpage() { - return _page; - } - String gdescr() { - return _descr; - } - String gorder() { - return _order; - } - String gpin() { - return _pin; - } - String ginv() { - return _inv; - } - String gstate() { - return _state; - } - String gmap() { - return _map; - } - String gc() { - return _c; - } - String gtype() { - return _type; - } - String gaddr() { - return _addr; - } - String gregaddr() { - return _reg; - } - String gint() { - return _int; - } - String gcnt() { - return _cnt; - } - String gval() { - return _val; - } - String gindex() { - return _index; - } - - - void clear() { - _key = ""; - _file = ""; - _page = ""; - _descr = ""; - _order = ""; - _addr = ""; - _reg = ""; - _pin = ""; - _map = ""; - _c = ""; - _inv = ""; - _state = ""; - _db = ""; - _type = ""; - _int = ""; - _cnt = ""; - _val = ""; - _index = ""; - } - - String extractInnerDigit(String str) { - int p1 = str.indexOf("["); - int p2 = str.indexOf("]"); - return str.substring(p1 + 1, p2); - } - - void createWidget(String descr, String page, String order, String filename, String topic) { - if (filename != "na") { - String buf = "{}"; - if (!loadWidget(filename, buf)) { - return; - } - - if(filename.indexOf("chart") != -1) jsonWriteStr(buf, "maxCount", _cnt); - - jsonWriteStr(buf, "page", page); - jsonWriteStr(buf, "order", order); - jsonWriteStr(buf, "descr", descr); - jsonWriteStr(buf, "topic", prex + "/" + topic); - -#ifdef LAYOUT_IN_RAM - all_widgets += widget + "\r\n"; -#else - addFileLn("layout.txt", buf); -#endif - } - } - - bool loadWidget(const String& filename, String& buf) { - buf = readFile(getWidgetFile(filename), 2048); - bool res = !(buf == "Failed" || buf == "Large"); - if (!res) { - //SerialPrint("[E]","module","on load" + filename); - } - return res; - } - - const String getWidgetFile(const String& name) { - return "/widgets/" + name + ".json"; - } -}; - -extern LineParsing myLineParsing; diff --git a/include/Class/NotAsync.h b/include/Class/NotAsync.h deleted file mode 100644 index 1d5278cc..00000000 --- a/include/Class/NotAsync.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include -#include - -#include - -typedef std::function NotAsyncCb; - -struct NotAsyncItem { - bool test; - NotAsyncCb cb; - void* cb_arg; - volatile bool is_used = false; -}; - -class NotAsync { - private: - uint8_t size; - uint8_t task = 0; - NotAsyncItem* items = NULL; - void handle(NotAsyncCb f, void* arg); - - public: - NotAsync(uint8_t size); - ~NotAsync(); - - void add(uint8_t i, NotAsyncCb, void* arg); - void make(uint8_t task); - void loop(); -}; - -extern NotAsync* myNotAsyncActions; \ No newline at end of file diff --git a/include/Class/ScenarioClass2.h b/include/Class/ScenarioClass2.h deleted file mode 100644 index 6dc84eb6..00000000 --- a/include/Class/ScenarioClass2.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include -#include "Cmd.h" -#include "Global.h" - -class Scenario { - -public: - - void loop() { - - String allBlocks = scenario; - allBlocks.replace("\r\n", "\n"); - allBlocks.replace("\r", "\n"); - allBlocks += "\n"; - - String incommingEvent = selectToMarker(eventBuf, ","); - - while (allBlocks.length() > 1) { - String oneBlock = selectToMarker(allBlocks, "end\n"); - String condition = selectToMarker(oneBlock, "\n"); - - String setEvent = selectFromMarkerToMarker(condition, " ", 0); - String setEventSign = selectFromMarkerToMarker(condition, " ", 1); - String setEventValue = selectFromMarkerToMarker(condition, " ", 2); - if (!isDigitStr(setEventValue)) setEventValue = jsonReadStr(configLiveJson, setEventValue); - - String incommingEventValue = jsonReadStr(configLiveJson, incommingEvent); - - if (incommingEvent == setEvent) { - - boolean flag = false; - - if (setEventSign == "=") { - flag = incommingEventValue == setEventValue; - } - else if (setEventSign == "!=") { - flag = incommingEventValue != setEventValue; - } - else if (setEventSign == "<") { - flag = incommingEventValue.toFloat() < setEventValue.toFloat(); - } - else if (setEventSign == ">") { - flag = incommingEventValue.toFloat() > setEventValue.toFloat(); - } - else if (setEventSign == ">=") { - flag = incommingEventValue.toFloat() >= setEventValue.toFloat(); - } - else if (setEventSign == "<=") { - flag = incommingEventValue.toFloat() <= setEventValue.toFloat(); - } - - if (flag) { - //SerialPrint("I", "Scenario", "incomming Event Value: " + incommingEventValue); - //SerialPrint("I", "Scenario", "set Event Value: " + setEventValue); - - oneBlock = deleteBeforeDelimiter(oneBlock, "\n"); - oneBlock.replace("end", ""); - SerialPrint("I", "Scenario", condition + " set:\n" + oneBlock); - spaceCmdExecute(oneBlock); - } - } - allBlocks = deleteBeforeDelimiter(allBlocks, "end\n"); - } - eventBuf = deleteBeforeDelimiter(eventBuf, ","); - } -}; - -extern Scenario* myScenario; \ No newline at end of file diff --git a/include/Class/ScenarioClass3.h b/include/Class/ScenarioClass3.h deleted file mode 100644 index 3bedf2bc..00000000 --- a/include/Class/ScenarioClass3.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once -#include -#include "Cmd.h" -#include "Global.h" - -class Scenario { - -public: - - void loop() { - - String allBlocks = scenario; - allBlocks.replace("\r\n", "\n"); - allBlocks.replace("\r", "\n"); - allBlocks += "\n"; - - String incommingEvent = selectToMarker(eventBuf, ","); - String incommingEventKey = selectToMarker(incommingEvent, " "); - String incommingEventValue = selectToMarkerLast(incommingEvent, " "); - - while (allBlocks.length() > 1) { - String oneBlock = selectToMarker(allBlocks, "end\n"); - String condition = selectToMarker(oneBlock, "\n"); - - String setEventKey = selectFromMarkerToMarker(condition, " ", 0); - - if (incommingEventKey == setEventKey) { - - String setEventSign = selectFromMarkerToMarker(condition, " ", 1); - String setEventValue = selectFromMarkerToMarker(condition, " ", 2); - if (!isDigitStr(setEventValue)) setEventValue = jsonReadStr(configLiveJson, setEventValue); - - boolean flag = false; - - if (setEventSign == "=") { - flag = incommingEventValue == setEventValue; - } - else if (setEventSign == "!=") { - flag = incommingEventValue != setEventValue; - } - else if (setEventSign == "<") { - flag = incommingEventValue.toFloat() < setEventValue.toFloat(); - } - else if (setEventSign == ">") { - flag = incommingEventValue.toFloat() > setEventValue.toFloat(); - } - else if (setEventSign == ">=") { - flag = incommingEventValue.toFloat() >= setEventValue.toFloat(); - } - else if (setEventSign == "<=") { - flag = incommingEventValue.toFloat() <= setEventValue.toFloat(); - } - - if (flag) { - //SerialPrint("I", "Scenario", "incomming Event Value: " + incommingEventValue); - //SerialPrint("I", "Scenario", "set Event Value: " + setEventValue); - - oneBlock = deleteBeforeDelimiter(oneBlock, "\n"); - oneBlock.replace("end", ""); - SerialPrint("I", "Scenario", condition + " \n" + oneBlock); - spaceCmdExecute(oneBlock); - } - } - allBlocks = deleteBeforeDelimiter(allBlocks, "end\n"); - } - eventBuf = deleteBeforeDelimiter(eventBuf, ","); - } -}; - -extern Scenario* myScenario; \ No newline at end of file diff --git a/include/Clock.h b/include/Clock.h deleted file mode 100644 index c083e627..00000000 --- a/include/Clock.h +++ /dev/null @@ -1,166 +0,0 @@ -#pragma once - -#include "Clock.h" -#include "Global.h" -#include "Utils/TimeUtils.h" -#include "Utils/SerialPrint.h" - -extern void clock_init(); - -#ifdef ESP8266 -#include "sntp.h" -#endif - -class Clock { - private: - Time_t _time_local; - Time_t _time_utc; - unsigned long _uptime; - unsigned long _unixtime; - int _timezone; - String _ntp; - bool _hasSynced; - bool _configured; - - public: - Clock() : _uptime{0}, _timezone{0}, _ntp{""}, _hasSynced{false}, _configured{false} {}; - - void loop() { - unsigned long passed = millis_since(_uptime); - if (passed < ONE_SECOND_ms) { - return; - } - _uptime += passed; - - // world time - time_t now = getSystemTime(); - time_t estimated = _unixtime + (passed / ONE_SECOND_ms); - double drift = difftime(now, estimated); - if (drift > 1) { - // Обработать ситуации c дрифтом времени на значительные величины - } - - _unixtime = now; - - breakEpochToTime(_unixtime, _time_utc); - - breakEpochToTime(_unixtime + getOffsetInSeconds(_timezone), _time_local); - } - - bool hasSync() { - if (!_hasSynced) { - startSync(); - } - return _hasSynced; - } - - void setNtpPool(String ntp) { - if (!_ntp.equals(ntp)) { - _ntp = ntp; - _configured = false; - } - } - - void setTimezone(int timezone) { - if (_timezone != timezone) { - _timezone = timezone; - _configured = false; - } - } - - void startSync() { - if (!_configured) { - SerialPrint("I", "NTP", "sync to: " + _ntp + " timezone: " + String(_timezone)); - setupSntp(); - _configured = true; - return; - } - _hasSynced = hasTimeSynced(); - if (_hasSynced) { - SerialPrint("I", "NTP", "synced " + getDateDotFormated() + " " + getTime()); - } else { - SerialPrint("E", "NTP", "failed to obtain time"); - } - } - - void setupSntp() { -#ifdef ESP8266 - sntp_setservername(0, _ntp.c_str()); - sntp_setservername(1, "ru.pool.ntp.org"); - sntp_setservername(2, "pool.ntp.org"); - sntp_stop(); - sntp_set_timezone(0); - sntp_init(); -#else - configTime(0, 0, _ntp.c_str(), "ru.pool.ntp.org", "pool.ntp.org"); -#endif - } - - bool hasTimeSynced() const { - return _unixtime > MIN_DATETIME; - } - - time_t getSystemTime() const { - timeval tv{0, 0}; - timezone tz = timezone{0, 0}; - time_t epoch = 0; - if (gettimeofday(&tv, &tz) != -1) { - epoch = tv.tv_sec; - } - return epoch; - } - - const String getTimeUnix() { - return String(_unixtime); - } - - /* - * Локальное время "дд.ММ.гг" - */ - const String getDateDotFormated() { - char buf[32]; - sprintf(buf, "%02d.%02d.%02d", _time_local.day_of_month, _time_local.month, _time_local.year); - return String(buf); - } - - /* - * Локальное дата время "дд.ММ.гг чч.мм.cc" - */ - const String getDateTimeDotFormated() { - char buf[32]; - sprintf(buf, "%02d.%02d.%02d %02d:%02d:%02d", _time_local.day_of_month, _time_local.month, _time_local.year, _time_local.hour, _time_local.minute, _time_local.second); - return String(buf); - } - - /* - * Локальное время "чч:мм:cc" - */ - const String getTime() { - char buf[32]; - sprintf(buf, "%02d:%02d:%02d", _time_local.hour, _time_local.minute, _time_local.second); - return String(buf); - } - - const String getTimeJson() { - char buf[32]; - sprintf(buf, "%02d-%02d-%02d", _time_local.hour, _time_local.minute, _time_local.second); - return String(buf); - } - - /* - * Локальное время "чч:мм" - */ - const String getTimeWOsec() { - char buf[32]; - sprintf(buf, "%02d:%02d", _time_local.hour, _time_local.minute); - return String(buf); - } - - /* - * Время с момента запуска "чч:мм:cc" далее "дд чч:мм" - */ - const String getUptime() { - return prettyMillis(_uptime); - } -}; -extern Clock* timeNow; \ No newline at end of file diff --git a/include/Cmd.h b/include/Cmd.h deleted file mode 100644 index eb27380d..00000000 --- a/include/Cmd.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -extern void cmd_init(); - -extern void sensorsInit(); - -//extern void levelPr(); -//extern void ultrasonicCm(); -//extern void ultrasonic_reading(); - -extern void analog_reading1(); -extern void analog_reading2(); -extern void dallas_reading(); -extern void dhtT_reading(); - -//extern void dallas(); - -extern void bmp280T(); -extern void bmp280P(); -extern void bmp280T_reading(); -extern void bmp280P_reading(); - -extern void bme280T(); -extern void bme280P(); -extern void bme280H(); -extern void bme280A(); - -extern void bme280T_reading(); -extern void bme280P_reading(); -extern void bme280H_reading(); -extern void bme280A_reading(); - -//extern void dhtT(); -//extern void dhtH(); -//extern void dhtP(); -//extern void dhtC(); -//extern void dhtD(); -//extern void dhtH_reading(); -//extern void dhtP_reading(); -//extern void dhtC_reading(); -//extern void dhtD_reading(); - -extern void handle_time_init(); -extern void stepper(); -extern void stepperSet(); -extern void servo_(); -extern void servoSet(); -extern void serialBegin(); -extern void serialWrite(); -extern void logging(); - -extern void button(); -extern void timeSet(); - -extern void mqttOrderSend(); -extern void httpOrderSend(); -extern void firmwareVersion(); -extern void firmwareUpdate(); -extern void loadScenario(); - -extern void fileCmdExecute(const String& filename); -extern void csvCmdExecute(String& cmdStr); -extern void spaceCmdExecute(String& cmdStr); \ No newline at end of file diff --git a/include/Consts.h b/include/Consts.h deleted file mode 100644 index e0679110..00000000 --- a/include/Consts.h +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once - -//===========Firmware============================================================================================================================================= -#ifdef ESP8266 -#define FIRMWARE_NAME "esp8266-iotm" -#define FIRMWARE_VERSION 267 -#endif -#ifdef ESP32 -#define FIRMWARE_NAME "esp32-iotm" -#define FIRMWARE_VERSION 267 -#endif -#define FLASH_4MB true - -//===========FSystem============================================================================================================================================== -#define NUM_BUTTONS 6 -#define LED_PIN 2 - -//===========MQTT================================================================================================================================================= -#define MQTT_RECONNECT_INTERVAL 20000 - -//==========Telemetry============================================================================================================================================= -#define TELEMETRY_UPDATE_INTERVAL_MIN 60 - -//=========Configuration========================================================================================================================================== -#define DEVICE_CONFIG_FILE "s.conf.csv" -#define DEVICE_SCENARIO_FILE "s.scen.txt" - - -//=========System parts=========================================================================================================================================== -//#define OTA_UPDATES_ENABLED -//#define MDNS_ENABLED -//#define WEBSOCKET_ENABLED -//#define LAYOUT_IN_RAM -//#define UDP_ENABLED -//#define SSDP_ENABLED - -//=========Sensors enable/disable================================================================================================================================= -#define TANK_LEVEL_SAMPLES 10 -#define LEVEL_ENABLED -#define ANALOG_ENABLED -#define DALLAS_ENABLED -#define DHT_ENABLED -#define BMP_ENABLED -#define BME_ENABLED - - -//=========Gears enable/disable=================================================================================================================================== -#define STEPPER_ENABLED -#define SERVO_ENABLED - - -//========Other enable/disable==================================================================================================================================== -#define LOGGING_ENABLED -#define SERIAL_ENABLED -#define PUSH_ENABLED - -struct Time_t { - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t day_of_week; - uint8_t day_of_month; - uint8_t month; - uint16_t day_of_year; - uint16_t year; - unsigned long days; - unsigned long valid; -}; - -//================================================================================================================================================================ -enum TimerTask_t { WIFI_SCAN, - WIFI_MQTT_CONNECTION_CHECK, - SENSORS10SEC, - SENSORS30SEC, - TIMER_COUNTDOWN, - TIME, - TIME_SYNC, - STATISTICS, - STATISTICS_WORK, - UPTIME, - UDP, - UDP_DB, - TEST }; - -enum NotAsyncActions { - do_ZERO, - do_UPGRADE, - do_GETLASTVERSION, - do_UDPDATAPARSE, - do_MQTTUDP, - do_BUSSCAN, - do_MQTTPARAMSCHANGED, - do_deviceInit, - do_delChoosingItems, - do_LAST, -}; - -enum LedStatus_t { - LED_OFF, - LED_ON, - LED_SLOW, - LED_FAST -}; - -enum ConfigType_t { - CT_CONFIG, - CT_SCENARIO -}; - -//07.11.2020 -//RAM: [===== ] 46.8% (used 38376 bytes from 81920 bytes) -//Flash: [===== ] 54.2% (used 566004 bytes from 1044464 bytes) \ No newline at end of file diff --git a/include/ESP32.h b/include/ESP32.h deleted file mode 100644 index 1662e906..00000000 --- a/include/ESP32.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#ifdef ESP32 -// don't change order -#include "WiFi.h" -// - -#include "ESPAsyncWebServer.h" -#include "SPIFFSEditor.h" -// don't change order -#include -#include -#include -#include - -// -#include -#include - -#ifdef MDNS_ENABLED -#include -#endif - -extern AsyncUDP udp; - -#endif \ No newline at end of file diff --git a/include/ESP8266.h b/include/ESP8266.h deleted file mode 100644 index 6296fc81..00000000 --- a/include/ESP8266.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#ifdef ESP8266 -#include -#include -#include "ESPAsyncTCP.h" -#include "ESPAsyncWebServer.h" -#include -#include -#include -#include -#include -#ifdef MDNS_ENABLED -#include -#endif - -extern WiFiUDP udp; - -#endif \ No newline at end of file diff --git a/include/FSEditor.h b/include/FSEditor.h deleted file mode 100644 index 69282648..00000000 --- a/include/FSEditor.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include - -#ifdef ESP8266 -#include -#endif - -class FSEditor : public AsyncWebHandler { - private: - fs::FS _fs; - String _username; - String _password; - bool _authenticated; - uint32_t _startTime; - - private: - void getDirList(const String& path, String& output); - - public: -#ifdef ESP32 - FSEditor(const fs::FS& fs, const String& username = String(), const String& password = String()); -#else - FSEditor(const String& username = String(), const String& password = String(), const fs::FS& fs = LittleFS); -#endif - virtual bool canHandle(AsyncWebServerRequest* request) override final; - virtual void handleRequest(AsyncWebServerRequest* request) override final; - virtual void handleUpload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) override final; - virtual bool isRequestHandlerTrivial() override final { - return false; - } -}; \ No newline at end of file diff --git a/include/Global.h b/include/Global.h deleted file mode 100644 index 59226d64..00000000 --- a/include/Global.h +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once -//===================Libraries=================================================================================================================================================== -#include -#include -#include -#include "CTBot.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Clock.h" -#include "Consts.h" -#include "ESP32.h" -#include "ESP8266.h" -#include "GyverFilters.h" -#include "MqttClient.h" -#include "Upgrade.h" -#include "Utils/FileUtils.h" -#include "Utils/JsonUtils.h" -#include "Utils/SerialPrint.h" -#include "Utils/StringUtils.h" -#include "Utils/SysUtils.h" -#include "Utils/WiFiUtils.h" - -#ifdef WEBSOCKET_ENABLED -extern AsyncWebSocket ws; -//extern AsyncEventSource events; -#endif - - -extern TickerScheduler ts; -extern WiFiClient espClient; -extern PubSubClient mqtt; -extern StringCommand sCmd; -extern AsyncWebServer server; - -extern boolean but[NUM_BUTTONS]; -extern Bounce* buttons; - -//Global vars -extern boolean just_load; -extern boolean telegramInitBeen; - -// Json -extern String configSetupJson; //все настройки -extern String configLiveJson; //все данные с датчиков (связан с mqtt) -extern String configOptionJson; //для трансфера - -// Mqtt -extern String chipId; -extern String prex; -extern String all_widgets; -extern String scenario; - -//orders and events -extern String orderBuf; -extern String eventBuf; -extern String itemsFile; -extern String itemsLine; - -//key lists and numbers -extern String impulsKeyList; -extern int impulsEnterCounter; - -// Sensors -extern String sensorReadingMap10sec; -extern String sensorReadingMap30sec; - - -extern String loggingKeyList; -extern int enter_to_logging_counter; -extern int scenario_line_status[40]; -extern int lastVersion; - -// Main -extern void setChipId(); -extern void saveConfig(); -extern void setConfigParam(const char* param, const String& value); - -extern String getURL(const String& urls); -extern void do_fscheck(); -extern void doBusScan(); -extern void servo_(); - -extern void setLedStatus(LedStatus_t); - -//Scenario -extern void eventGen2(String eventName, String eventValue); -extern String add_set(String param_name); - -//Timers -extern void Timer_countdown_init(); -extern void timerStart_(); -extern void addTimer(String number, String time); -extern void timerStop_(); -extern void delTimer(String number); -extern int readTimer(int number); - -extern void upgradeInit(); - -// widget -extern void createWidgetByType(String widget_name, String page_name, String page_number, String file, String topic); -extern void createWidgetParam(String widget_name, String page_name, String page_number, String file, String topic, String name1, String param1, String name2, String param2, String name3, String param3); -extern void createWidget(String widget_name, String page_name, String page_number, String type, String topik); -extern void createChart(String widget_name, String page_name, String page_number, String file, String topic, String maxCount); - -// PushingBox -extern void pushControl(); - -// UDP -//extern void udpInit(); -//extern void do_udp_data_parse(); -//extern void do_mqtt_send_settings_to_udp(); - -extern void do_update(); - -// Init -extern void uptime_init(); - -// Web -extern void web_init(); - -// Upgrade -extern String serverIP; diff --git a/include/HttpServer.h b/include/HttpServer.h deleted file mode 100644 index fa7a5187..00000000 --- a/include/HttpServer.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "Global.h" - -namespace HttpServer { - -void init(); - -} // namespace HttpServer diff --git a/include/Init.h b/include/Init.h deleted file mode 100644 index bb2b2ca7..00000000 --- a/include/Init.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -extern void loadConfig(); -extern void all_init(); -extern void statistics_init(); -extern void loadScenario(); -extern void Device_init(); -extern void prsets_init(); -extern void handle_uptime(); -extern void handle_statistics(); diff --git a/include/ItemsList.h b/include/ItemsList.h deleted file mode 100644 index c0b716ec..00000000 --- a/include/ItemsList.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include "Global.h" - -extern void itemsListInit(); -extern void addItem(String name); -extern void addPreset(String name); -extern void delChoosingItems(); -extern void delAllItems(); -extern uint8_t getNewElementNumber(String file); -extern uint8_t getFreePinAll(); -extern uint8_t getFreePinAnalog(); diff --git a/include/Module/CharBuffer.h b/include/Module/CharBuffer.h deleted file mode 100644 index 74fd922d..00000000 --- a/include/Module/CharBuffer.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include - -class CharBuffer : Print { - public: - CharBuffer(size_t size) : _capacity(size < 2 ? 2 : size), _write(0), _read(0) { - _pool = new char[_capacity + 1]; - memset(_pool, 0, _capacity + 1); - } - - CharBuffer(const CharBuffer &src) { - _capacity = src._capacity; - _write = src._write; - memcpy(_pool, src._pool, src._write); - } - - CharBuffer(const char *str) : CharBuffer(strlen(str) + 1) { - write((const uint8_t *)str, strlen(str)); - } - - ~CharBuffer() { - delete _pool; - } - - void clear() { - memset(_pool, 0, _capacity); - _write = 0; - _read = 0; - } - - size_t size() const { return _capacity; } - - size_t free() const { return _capacity - _write - 2; } - - size_t available() const { return _write; } - - const char *c_str() { - if (_pool[_write] != '\x00') - _pool[_write] = '\x00'; - return _pool; - } - - size_t write(char ch) { - return write((uint8_t)ch); - }; - - size_t write(const uint8_t ch) { - size_t n = 0; - if (_write < (_capacity - 2)) { - _pool[_write++] = ch; - n = 1; - } - return n; - } - - size_t write(const uint8_t *ptr, const size_t size) { - size_t n = 0; - while (n < size) { - uint8_t ch = ptr[n++]; - if (!write(ch)) - break; - } - return n; - } - - protected: - char *_pool; - size_t _capacity; - size_t _write; - size_t _read; -}; diff --git a/include/Module/CircularBuffer.h b/include/Module/CircularBuffer.h deleted file mode 100644 index 5c197652..00000000 --- a/include/Module/CircularBuffer.h +++ /dev/null @@ -1,86 +0,0 @@ -#pragma once - -#include - -template -class CircularBuffer { - public: - CircularBuffer() : _head{0}, _tail{0}, _full{false} {} - - ~CircularBuffer() {} - - void reset() { - _head = _tail = _full = 0; - } - - bool empty() const { - return _head == _tail && !_full; - } - - bool full() const { - return _full; - } - - size_t size() const { - size_t res = 0; - if (!_full) { - if (_head < _tail) - res = BUFFER_SIZE + _head - _tail; - else - res = _head - _tail; - } else { - res = BUFFER_SIZE; - } - return res; - } - - void push(const T &item) { - if (_full) { - _tail++; - if (_tail == BUFFER_SIZE) - _tail = 0; - } - _pool[_head++] = item; - if (_head == BUFFER_SIZE) - _head = 0; - if (_head == _tail) - _full = true; - } - - bool pop(T &item) { - bool res = false; - if (!empty()) { - item = _pool[_tail++]; - if (_tail == BUFFER_SIZE) _tail = 0; - _full = false; - res = true; - } - return res; - } - - bool pop_back(T &item) { - bool res = false; - if (!empty()) { - item = _pool[--_head]; - _full = false; - res = true; - } - return res; - } - - bool peek(T &item) const { - bool res = false; - if (!empty()) { - item = _pool[_tail]; - - res = true; - } - return res; - } - - private: - T _pool[BUFFER_SIZE]; - size_t _head; - size_t _tail; - bool _full; -}; \ No newline at end of file diff --git a/include/Module/CommandShell.h b/include/Module/CommandShell.h deleted file mode 100644 index 6a986639..00000000 --- a/include/Module/CommandShell.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -#include "Module/Terminal.h" -#include "Module/CircularBuffer.h" -#include "Module/Runner.h" - -class CommandShell { - public: - CommandShell(Runner *runner); - - void setTerm(Terminal *term); - Terminal *term(); - - void showGreetings(bool = true); - void showFarewell(bool = true); - - void clearHistory(); - void addHistory(const char *); - bool getHistoryInput(String &); - void setEditLine(const String &); - bool active(); - void loop(); - - private: - size_t printGreetings(Print *); - size_t printFarewell(Print *); - size_t printPrompt(Print *); - - void onOpen(Print *out); - void onClose(Print *out); - void onData(const char *); - void onHistory(Print *out); - bool getLastInput(String &); - - private: - CircularBuffer _history; - Terminal *_term; - Runner *_runner; - String _path; - bool _active; - bool _greetings; - bool _farewell; -}; diff --git a/include/Module/EditLine.h b/include/Module/EditLine.h deleted file mode 100644 index 4368fb7f..00000000 --- a/include/Module/EditLine.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include "Module/CharBuffer.h" - -class EditLine : public CharBuffer { - public: - EditLine(size_t size) : CharBuffer(size){}; - - char &operator[](size_t i) { return _pool[i]; } - - char operator[](size_t i) const { return _pool[i]; } - - EditLine &operator=(const EditLine &src) { - delete[] _pool; - _pool = new char[src._capacity]; - memcpy(_pool, src._pool, src._capacity); - _read = src._read; - _write = src._write; - return *this; - } - - void del() { - size_t i; - for (i = _write; i < _capacity; ++i) - _pool[i] = _pool[i + 1]; - _pool[i] = '\x00'; - } - - bool backspace() { - bool res = false; - if (prev()) { - del(); - res = true; - } - return res; - } - - bool next() { - bool res = false; - if (_write < _capacity - 1) { - _write++; - res = true; - } - return res; - } - - bool prev() { - bool res = false; - if (_write > 0) { - _write--; - res = true; - } - return res; - } - - size_t home() { - size_t res = _write; - _write = 0; - return res; - } - - size_t end() { - size_t n; - for (n = 0; n < _capacity - 1; ++n) - if (_pool[n] == '\x00') break; - return n; - } -}; diff --git a/include/Module/Module.h b/include/Module/Module.h deleted file mode 100644 index 800d5919..00000000 --- a/include/Module/Module.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include - -enum ModuleState_t { - MOD_INIT, - MOD_INIT_FAILED, - MOD_INIT_COMPLETE, - MOD_START_FAILED, - MOD_ACTIVE -}; - -class Module { - protected: - virtual bool onInit() { return true; }; - virtual void onEnd(){}; - virtual bool onStart() { return true; } - virtual void onStop(){}; - virtual void onLoop() = 0; - - protected: - Print *_out; - - public: - Module() : _state{MOD_INIT} {} - - bool init(bool force = false) { - if (_state > MOD_INIT_COMPLETE) { - return true; - } - if (_state == MOD_INIT_FAILED && !force) { - return false; - } - - _state = onInit() ? MOD_INIT_COMPLETE : MOD_INIT_FAILED; - - return _state == MOD_INIT_COMPLETE; - } - - bool start(bool force = false) { - if (_state == MOD_ACTIVE) { - return true; - } - if (_state == MOD_START_FAILED && !force) { - return false; - } - if (_state < MOD_INIT_COMPLETE) { - if (!init(force)) { - return false; - } - } - _state = onStart() ? MOD_ACTIVE : MOD_START_FAILED; - return _state == MOD_ACTIVE; - } - - void stop() { - if (_state < MOD_ACTIVE) { - return; - } - onStop(); - _state = MOD_INIT_COMPLETE; - }; - - void end() { - if (_state < MOD_INIT_FAILED) { - return; - } - onEnd(); - _state = MOD_INIT; - }; - - void loop() { - if (_state == MOD_ACTIVE || start()) onLoop(); - }; - - void setOutput(Print *p) { _out = p; } - - ModuleState_t getState() { - return _state; - } - - private: - ModuleState_t _state; -}; diff --git a/include/Module/Runner.h b/include/Module/Runner.h deleted file mode 100644 index 45ca7403..00000000 --- a/include/Module/Runner.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include "Cmd.h" - -class Runner { - public: - virtual void run(const char*, Print*); -}; - -class CmdRunner : public Runner { - public: - void run(const char* cmd, Print* out) override { - String cmdStr{cmd}; - csvCmdExecute(cmdStr); - } -}; \ No newline at end of file diff --git a/include/Module/Telnet.h b/include/Module/Telnet.h deleted file mode 100644 index ade6e4f2..00000000 --- a/include/Module/Telnet.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include "Global.h" - -#include "Module/Module.h" -#include "Module/Terminal.h" -#include "Module/CommandShell.h" - -#include - -enum TelnetEvent_t { - TE_CONNECTED, - TE_DISCONNECTED -}; - -typedef std::function TelnetEventHandler; - -class Telnet : public Module { - public: - Telnet(uint16_t port) : _port{port}, _lastConnected{false} {}; - - public: - void setEventHandler(TelnetEventHandler); - void sendData(const String&); - bool hasClient(); - bool isShellActive(); - void setCommandShell(CommandShell*); - - protected: - bool onInit() override; - void onEnd() override; - bool onStart() override; - void onStop() override; - void onLoop() override; - - private: - void onConnect(); - void onDisconnect(); - void onData(); - void onOpen(); - void onClose(); - - private: - TelnetEventHandler _eventHandler; - uint16_t _port; - bool _lastConnected; - WiFiClient _client; - WiFiServer* _server; - Terminal* _term; - CommandShell* _shell; -}; diff --git a/include/Module/Terminal.h b/include/Module/Terminal.h deleted file mode 100644 index cbb8a6f8..00000000 --- a/include/Module/Terminal.h +++ /dev/null @@ -1,186 +0,0 @@ -#pragma once - -#include - -#include "Module/EditLine.h" -#include - -#define A_NORMAL 0x0000 // normal -#define A_UNDERLINE 0x0001 // underline -#define A_REVERSE 0x0002 // reverse -#define A_BLINK 0x0004 // blink -#define A_BOLD 0x0008 // bold -#define A_DIM 0x0010 // dim -#define A_STANDOUT A_BOLD // standout (same as bold) - -#define F_BLACK 0x0100 // foreground black -#define F_RED 0x0200 // foreground red -#define F_GREEN 0x0300 // foreground green -#define F_BROWN 0x0400 // foreground brown -#define F_BLUE 0x0500 // foreground blue -#define F_MAGENTA 0x0600 // foreground magenta -#define F_CYAN 0x0700 // foreground cyan -#define F_WHITE 0x0800 // foreground white -#define F_YELLOW F_BROWN // some terminals show brown as yellow (with A_BOLD) -#define F_COLOR 0x0F00 // foreground mask - -#define B_BLACK 0x1000 // background black -#define B_RED 0x2000 // background red -#define B_GREEN 0x3000 // background green -#define B_BROWN 0x4000 // background brown -#define B_BLUE 0x5000 // background blue -#define B_MAGENTA 0x6000 // background magenta -#define B_CYAN 0x7000 // background cyan -#define B_WHITE 0x8000 // background white -#define B_YELLOW B_BROWN // some terminals show brown as yellow (with A_BOLD) -#define B_COLOR 0xF000 // background mask - -#define CHAR_NULL 0x00 -#define CHAR_BEL 0x07 -#define CHAR_BS 0x08 -#define CHAR_SPACE 0x20 -#define CHAR_TAB 0x09 -#define CHAR_LF 0x0a -#define CHAR_CR 0x0d -#define CHR_ZERO 0x30 - -#define KEY_DEL 0x7f -#define KEY_DOWN 0x80 -#define KEY_UP 0x81 -#define KEY_LEFT 0x82 -#define KEY_RIGHT 0x83 -#define KEY_HOME 0x84 -#define KEY_INS 0x86 -#define KEY_PAGE_DOWN 0x87 -#define KEY_PAGE_UP 0x88 -#define KEY_END 0x89 -#define CHAR_LT 0x8b -#define CHAR_CSI 0x9b -#define CHAR_ESC 0x1b -#define CHAR_BIN 0xFF - -#define ESC_CURSOR_HOME "\x1b[H" -#define ESC_SAVE_CURSOR "\x1b[s" -#define ESC_UNSAVE_CURSOR "\x1b[u" -#define ESC_SAVE_CURSOR_AND_ATTRS "\x1b[7" -#define ESC_RESTORE_CURSOR_AND_ATTRS "\x1b[8" - -#define ESC_CLEAR "\x1b[2J" -#define ESC_CLEAR_BOTTOM "\x1b[J" -#define ESC_CLEAR_EOL "\x1b[0K" - -#define ESC_CURSOR_UP "\x1b[1A" -#define ESC_CURSOR_DOWN "\x1b[1B" -#define ESC_CURSOR_FORWARD "\x1b[1C" -#define ESC_CURSOR_BACKWARD "\x1b[1D" - -#define SEQ_CSI PSTR("\033[") // code introducer -#define SEQ_LOAD_G1 PSTR("\033)0") // load G1 character set -#define SEQ_CLEAR PSTR("\033[2J") // clear screen -#define SEQ_ATTRSET PSTR("\033[0") // set attributes, e.g. "\033[0;7;1m" - -#define SEQ_ATTRSET_BOLD PSTR(";1") // bold -#define SEQ_ATTRSET_DIM PSTR(";2") // dim -#define SEQ_ATTRSET_FCOLOR PSTR(";3") // forground color -#define SEQ_ATTRSET_UNDERLINE PSTR(";4") // underline -#define SEQ_ATTRSET_BCOLOR PSTR(";4") // background color -#define SEQ_ATTRSET_BLINK PSTR(";5") // blink -#define SEQ_ATTRSET_REVERSE PSTR(";7") // reverse - -enum TerminalEventEnum { - EVENT_OPEN, - EVENT_CLOSE, - EVENT_TAB -}; - -enum SpecialKeyEnum { SPEC_KEY_UP, - SPEC_KEY_TAB, - SPEC_KEY_ENTER, - SPEC_KEY_ESC }; - -typedef std::function SpecialKeyPressedEvent; - -typedef std::function TerminalEventHandler; - -typedef std::function TerminalInputEventHandler; - -enum EOLType_t { CRLF, - LFCR, - LF, - CR }; - -enum State { ST_INACTIVE, - ST_NORMAL, - ST_ESC_SEQ, - ST_CTRL_SEQ }; - -class Terminal : public Print { - public: - Terminal(Stream *stream = nullptr); - - void setStream(Stream *stream); - void setEOL(EOLType_t code); - void enableControlCodes(bool enabled = true); - void enableEcho(bool enabled = true); - void enableColors(bool enabled = true); - void setOnEvent(TerminalEventHandler); - void setOnSpecKeyPress(SpecialKeyPressedEvent); - void setOnReadLine(TerminalInputEventHandler); - - bool setLine(const uint8_t *bytes, size_t size); - CharBuffer &getLine(); - - void backsp(); - void clear(); - void clear_line(); - size_t println(const char *str); - size_t println(void); - size_t write_P(PGM_P str); - size_t write(uint8_t c); - size_t write(const uint8_t *buf, size_t size); - void writeByDigit(uint8_t i); - bool available(); - void loop(); - void start(); - void quit(); - void initscr(); - void attrset(uint16_t attr); - - private: - void move(uint8_t y, uint8_t x); - TerminalEventHandler eventHandler_; - TerminalInputEventHandler inputHandler_; - - uint8_t attr = 0xff; - uint8_t curY = 0xff; - uint8_t curX = 0xff; - - unsigned long _lastReceived = 0; - State state; - Stream *_stream; - EditLine _line; - char _cc_buf[32] = {0}; - size_t _cc_pos = 0; - bool _color = false; - bool _controlCodes = false; - bool _echo = false; - EOLType_t _eol = CRLF; - - struct ControlCode { - const char *cc; - const char ch; - }; - - ControlCode keyMap[10] = { - {"G", KEY_HOME}, // 71 Home key - {"H", KEY_UP}, // 72 Up arrow - {"I", KEY_PAGE_UP}, // 73 PageUp - {"K", KEY_LEFT}, // 75 Left arrow - {"M", KEY_RIGHT}, // 77 Right arrow - {"O", KEY_END}, // 79 End key - {"P", KEY_DOWN}, // 80 Down arrow - {"Q", KEY_PAGE_DOWN}, // 81 PageDown - {"R", KEY_INS}, // 82 Insert - {"S", KEY_DEL}, // 83 Delete - }; -}; diff --git a/include/MqttClient.h b/include/MqttClient.h deleted file mode 100644 index 7656ced5..00000000 --- a/include/MqttClient.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - - -void mqttInit(); -boolean mqttConnect(); -void mqttReconnect(); -void mqttLoop(); -void mqttSubscribe(); - -boolean publish(const String& topic, const String& data); -boolean publishData(const String& topic, const String& data); -boolean publishChart(const String& topic, const String& data); -boolean publishControl(String id, String topic, String state); -boolean publishChart_test(const String& topic, const String& data); -boolean publishStatus(const String& topic, const String& data); - -void publishWidgets(); -void publishState(); - -void mqttCallback(char* topic, uint8_t* payload, size_t length); -const String getStateStr(); diff --git a/include/MqttDiscovery.h b/include/MqttDiscovery.h deleted file mode 100644 index 282b26fc..00000000 --- a/include/MqttDiscovery.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "Utils/SysUtils.h" - -namespace Discovery { - - -} \ No newline at end of file diff --git a/include/RemoteOrdersUdp.h b/include/RemoteOrdersUdp.h deleted file mode 100644 index 1500c55e..00000000 --- a/include/RemoteOrdersUdp.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#ifdef ESP8266 -#include "ESPAsyncUDP.h" -extern AsyncUDP asyncUdp; -extern void asyncUdpInit(); -extern String uint8tToString(uint8_t* data, size_t len); -extern bool udpPacketValidation(String& data); -extern void udpPacketParse(String& data); -#endif \ No newline at end of file diff --git a/include/SSDP.h b/include/SSDP.h deleted file mode 100644 index 353b193c..00000000 --- a/include/SSDP.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -#include "Consts.h" - -#ifdef SSDP_ENABLED -void SsdpInit(); -#endif \ No newline at end of file diff --git a/include/Sensors.h b/include/Sensors.h deleted file mode 100644 index 45dcbb04..00000000 --- a/include/Sensors.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - - diff --git a/include/Servo/Servos.h b/include/Servo/Servos.h deleted file mode 100644 index db53c01e..00000000 --- a/include/Servo/Servos.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#ifdef ESP8266 -#include -#else -#include -#endif - -struct Servo_t { - uint8_t num; - uint8_t pin; - Servo* obj; - Servo_t(uint8_t num, uint8_t pin) : num{num}, pin{pin}, obj{nullptr} {}; -}; - -class Servos { - public: - Servos(); - Servo* get(uint8_t num); - Servo* create(uint8_t num, uint8_t pin); - - size_t count(); - - private: - std::vector _items; -}; - -extern Servos myServo; \ No newline at end of file diff --git a/include/Strings_.h b/include/Strings_.h deleted file mode 100644 index 21865168..00000000 --- a/include/Strings_.h +++ /dev/null @@ -1,139 +0,0 @@ -#pragma once - -//Strings -// #include -#include - -#include -#include - -class char_array { - private: - char *p_stringarray; //initial input array - char *p_inputstring; //holds actual length data - //char **pp_database_string; //allocate data database.cpp - int stringsize; //holds array size to allocate memory - int charinput; //holds array input size - - public: - inline char_array(); //inline so other functions can call on it - inline ~char_array(); - inline void getinput(char *&); //retrieves user input - inline void grabline(char *&); //retrieve line with whitespace included NOT COMPLETE, may not need - inline int sortline(char **&, char *&); //sorts line into an array of strings and returns number of separate strings - inline int arraysize(); //returns size of string array - inline void printinput(); //print input string - inline void changedefaultsize(); //change default input size NOT COMPLETE -}; - -inline char_array::char_array() //constructor -{ - stringsize = 0; - charinput = 64; - p_stringarray = new char[charinput]; -} - -inline char_array::~char_array() //destructor -{ - delete[] p_inputstring; - delete[] p_stringarray; -} - -inline void char_array::getinput(char *&p_stringin) { - stringsize = 0; - - scanf("%63s", p_stringarray); //get input string - - while (p_stringarray[stringsize] != 0) //finding out the size of string array - { - stringsize++; - } - stringsize++; - - p_inputstring = new char[stringsize]; //reallocate memory block and set array inside - for (int i = 0; i < stringsize; i++) { - p_inputstring[i] = p_stringarray[i]; - } - - p_inputstring[stringsize - 1] = '\x00'; - - p_stringin = new char[stringsize]; //set pp_stringin - - p_stringin = p_inputstring; -} - -inline void char_array::grabline(char *&p_stringin) { - stringsize = 0; - std::cin.getline(p_stringarray, charinput); - while (p_stringarray[stringsize] != 0) { - stringsize++; - } - stringsize++; - p_inputstring = new char[stringsize]; - - for (int i = 0; i < stringsize; i++) { - p_inputstring[i] = p_stringarray[i]; - } - - p_stringin = new char[stringsize]; - p_stringin = p_inputstring; -} - -inline int char_array::sortline(char **&pp_stringin, char *&p_string) { - int position = 0; //position in string - int charcount = 1; //how many characters there are - int wordnum; //which word is being processed - int wordcount = 1; //number of words in string - int bookmark = 0; //holds last known position - - while (p_string[position] == ' ') { - position++; - } - - wordnum = position; //borrow wordnum to hold position value - while (p_string[position] != '\x00') //find total inputted string word length - { - if ((p_string[position] == ' ') && ((p_string[position + 1] != ' ') || (p_string[position + 1] != '\x00'))) { - wordcount++; - } - position++; - } - position = wordnum; //set position to original value - for (wordnum = 0; wordnum < wordcount; wordnum++) { - charcount = 1; - while (p_string[position] == ' ') { - position++; - } - while ((p_string[position] != ' ') && (p_string[position] != '\x00')) { - position++; - charcount++; - } - pp_stringin[wordnum] = new char[charcount]; - - for (int i = 0; i < charcount; i++) { - pp_stringin[wordnum][i] = p_string[i + bookmark]; - } - pp_stringin[wordnum][charcount - 1] = '\x00'; - bookmark = position + 1; - } - - return wordcount; -} - -inline int char_array::arraysize() { - if (stringsize != 0) { - return stringsize; - } else { - printf("Array size is set at 0\n"); - return 0; - } -} - -inline void char_array::printinput() { - printf("%s", p_inputstring); -} - -inline void char_array::changedefaultsize() { - printf("Input new default input string size: "); - scanf("%i", charinput); -} diff --git a/include/Telegram.h b/include/Telegram.h deleted file mode 100644 index 9fd18857..00000000 --- a/include/Telegram.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "Global.h" - -extern void sendTelegramMsg(); -extern void telegramInit(); -extern void handleTelegram(); -extern bool isTelegramEnabled(); -extern void telegramMsgParse(String msg); -extern String returnListOfParams(); \ No newline at end of file diff --git a/include/Upgrade.h b/include/Upgrade.h deleted file mode 100644 index b02adb12..00000000 --- a/include/Upgrade.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -extern void upgradeInit(); -extern void getLastVersion(); -extern void upgrade_firmware(int type); -extern bool upgradeFS(); -extern bool upgradeBuild(); -extern void restartEsp(); \ No newline at end of file diff --git a/include/Utils/FileHelper.h b/include/Utils/FileHelper.h deleted file mode 100644 index daa9186c..00000000 --- a/include/Utils/FileHelper.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include - -#include "FS.h" - -#ifdef ESP32 -#include "LITTLEFS.h" -#define LittleFS LITTLEFS -#endif -#ifdef ESP8266 -#include -#endif - -class FileHelper { - public: - FileHelper(const String filename); - /* - * Проверить существование - */ - void exists(); - /* - * Удалить файл - */ - void remove(); - /* - * Открыть файл установить позицию @position - */ - File seek(size_t position = 0); - - /* - * Чтение строки с содержащей @substr - */ - String readFileString(const String substr); - - /* - * Добовление строки @str в файл - */ - String appendStr(const String str); - - /* - * Запись строки - */ - String writeStr(const String); - - /* - * Чтение в строку - */ - String readStr(size_t); - - /* - * Размер в байтах - */ - size_t getSize(); -}; \ No newline at end of file diff --git a/include/Utils/FileUtils.h b/include/Utils/FileUtils.h deleted file mode 100644 index da2688ac..00000000 --- a/include/Utils/FileUtils.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include - -#include "Consts.h" - -#include "FS.h" - -#ifdef ESP32 -#include "LITTLEFS.h" -#define LittleFS LITTLEFS -#endif -#ifdef ESP8266 -#include -#endif - -/* -* Инициализация ФС -*/ -bool fileSystemInit(); - -/* -* Удалить файл -*/ -void removeFile(const String& filename); - -/* -* Открыть файл на позиции -*/ -File seekFile(const String& filename, size_t position = 0); - -/* -* Чтение строки из файла -* возвращает стоку из файла в которой есть искомое слово found -*/ -const String readFileString(const String& filename, const String& to_find); - -/* -* Добовление строки в файл -*/ -const String addFileLn(const String& filename, const String& str); - -/* -* Добовление строки в файл -*/ -const String addFile(const String& filename, const String& str); - -/* -* Запись строки в файл -*/ -const String writeFile(const String& filename, const String& str); - -/* -* Чтение файла в строку -*/ -const String readFile(const String& filename, size_t max_size); - -/* -* Размер файла -*/ -const String getFileSize(const String& filename); - -bool copyFile(const String& src, const String& dst, bool overwrite = true); - -const String getFSSizeInfo(); - -const String getConfigFile(uint8_t preset, ConfigType_t type); diff --git a/include/Utils/JsonUtils.h b/include/Utils/JsonUtils.h deleted file mode 100644 index c244a14e..00000000 --- a/include/Utils/JsonUtils.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -String jsonReadStr(String& json, String name); - -int jsonReadInt(String& json, String name); - -boolean jsonReadBool(String& json, String name); - -String jsonWriteStr(String& json, String name, String value); - -String jsonWriteInt(String& json, String name, int value); - -String jsonWriteFloat(String& json, String name, float value); - -String jsonWriteBool(String& json, String name, boolean value); - -void saveConfig(); \ No newline at end of file diff --git a/include/Utils/SerialPrint.h b/include/Utils/SerialPrint.h deleted file mode 100644 index f0d2d79c..00000000 --- a/include/Utils/SerialPrint.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -#include -void SerialPrint(String errorLevel, String module, String msg); \ No newline at end of file diff --git a/include/Utils/StatUtils.h b/include/Utils/StatUtils.h deleted file mode 100644 index c97abf8e..00000000 --- a/include/Utils/StatUtils.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include -#include "Global.h" - -extern void initSt(); -extern String updateDevicePsn(String lat, String lon, String accur); -extern String updateDeviceStatus(); -extern String addNewDevice(); - -extern void decide(); -extern void getPsn(); - -extern String getUptimeTotal(); -extern uint8_t getNextNumber(String file); -extern uint8_t getCurrentNumber(String file); - -//extern int plusOneHour(); -//extern void eeWriteInt(int pos, int val); -//extern int eeGetInt(int pos); -//extern void updateDeviceList(); -//extern void saveId(String file, int id); -//extern int getId(String file); \ No newline at end of file diff --git a/include/Utils/StringUtils.h b/include/Utils/StringUtils.h deleted file mode 100644 index 6ba28348..00000000 --- a/include/Utils/StringUtils.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -uint8_t hexStringToUint8(String hex); - -uint16_t hexStringToUint16(String hex); - -String selectToMarkerLast(String str, String found); - -String selectToMarker(String str, String found); - -String extractInner(String str); - -String deleteAfterDelimiter(String str, String found); - -String deleteBeforeDelimiter(String str, String found); - -String deleteBeforeDelimiterTo(String str, String found); - -String deleteToMarkerLast(String str, String found); - -String selectFromMarkerToMarker(String str, String found, int number); - -size_t itemsCount(String str, const String& separator); - -boolean isDigitStr(const String&); - -String prettyBytes(size_t size); - diff --git a/include/Utils/SysUtils.h b/include/Utils/SysUtils.h deleted file mode 100644 index de03e287..00000000 --- a/include/Utils/SysUtils.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include -#include "Global.h" - -uint32_t ESP_getChipId(); - -const String getChipId(); - -void setLedStatus(LedStatus_t status); - -const String getUniqueId(const String& name); - -const String printMemoryStatus(); - -const String getHeapStats(); - -const String getMacAddress(); - -void setChipId(); diff --git a/include/Utils/TimeUtils.h b/include/Utils/TimeUtils.h deleted file mode 100644 index d20286cf..00000000 --- a/include/Utils/TimeUtils.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include "Consts.h" - -#define ONE_MINUTE_s 60 -#define ONE_HOUR_m 60 -#define ONE_HOUR_s 60 * ONE_MINUTE_s -#define LEAP_YEAR(Y) (((1970 + Y) > 0) && !((1970 + Y) % 4) && (((1970 + Y) % 100) || !((1970 + Y) % 400))) -#define MIN_DATETIME 1575158400 -#define ONE_SECOND_ms 1000 - -/* -* Время (мс) прошедщее с @since -*/ -unsigned long millis_since(unsigned long sinse); - -/* -* Интерввал времени (мс) между @start и @finish -*/ -unsigned long millis_passed(unsigned long start, unsigned long finish); - -/* -* Форматиронное время интервала (мс) -* "чч:мм:cc", -* "дд чч:мм", если > 24 часов -*/ -const String prettyMillis(unsigned long time_ms = millis()); - -/* -* Форматиронное время интервала (c) -* "чч:мм:cc", -* "дд чч:мм", если > 24 часов -*/ -const String prettySeconds(unsigned long time_s); - -/* -* Тайм зона в секундах -*/ -int getOffsetInSeconds(int timezone); - -/* -* Тайм зона в минутах -*/ -int getOffsetInMinutes(int timezone); - -/* -* Разбивает время на составляющие -*/ -void breakEpochToTime(unsigned long epoch, Time_t& tm); \ No newline at end of file diff --git a/include/Utils/Timings.h b/include/Utils/Timings.h deleted file mode 100644 index c992eeee..00000000 --- a/include/Utils/Timings.h +++ /dev/null @@ -1,71 +0,0 @@ -#include - -enum Timings_t { MT_ONE, - MT_TWO, - NUM_TIMINGS }; - -struct Timing { - unsigned long _total_mu; - unsigned long _min_mu; - unsigned long _max_mu; - - Timing() : _total_mu{0}, _min_mu{999999}, _max_mu{0} {}; - - void reset() { - _total_mu = 0; - _min_mu = 999999; - _max_mu = 0; - } - - void add(unsigned long time_mu) { - if (time_mu == 0) return; - - _total_mu += time_mu; - - if (_min_mu > time_mu) { - _min_mu = time_mu; - } - - if (_max_mu < time_mu) { - _max_mu = time_mu; - } - } -}; - -static const char* module_name[NUM_TIMINGS] = {"strings", "boolean"}; - -struct Timings { - Timing mu[NUM_TIMINGS]; - - unsigned long _counter; - unsigned long _start; - unsigned long long _total; - - Timings() : _counter{0}, _start{0} {}; - - void add(size_t module, unsigned long now = micros()) { - unsigned long time = now - _start; - _total += time; - mu[module].add(time); - _start = now; - } - - void count() { - _counter++; - _start = micros(); - } - - void print() { - if (!_counter) { - return; - }; - Serial.printf("lp/ms: %llu ", _counter / _total); - for (size_t i = 0; i < NUM_TIMINGS; i++) { - Serial.printf("%s: %.2f%% ", module_name[i], ((float)mu[i]._total_mu / _total) * 100); - mu[i].reset(); - } - Serial.println(); - _counter = 0; - _total = 0; - }; -}; \ No newline at end of file diff --git a/include/Utils/WebUtils.h b/include/Utils/WebUtils.h deleted file mode 100644 index 5479314c..00000000 --- a/include/Utils/WebUtils.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "HttpServer.h" -#include - -extern String getURL(const String& urls); -extern const String getMethodName(AsyncWebServerRequest* request); -extern const String getRequestInfo(AsyncWebServerRequest* request); \ No newline at end of file diff --git a/include/Utils/WiFiUtils.h b/include/Utils/WiFiUtils.h deleted file mode 100644 index ef2c9379..00000000 --- a/include/Utils/WiFiUtils.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "Global.h" - -boolean isNetworkActive(); - -void routerConnect(); - -bool startAPMode(); - -boolean RouterFind(String ssid); - diff --git a/include/Web.h b/include/Web.h deleted file mode 100644 index a80a08d2..00000000 --- a/include/Web.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "Arduino.h" - - -void web_init(); -void setConfigParam(const char* param, const String& value); diff --git a/include/items/ButtonInClass.h b/include/items/ButtonInClass.h deleted file mode 100644 index 1c66b945..00000000 --- a/include/items/ButtonInClass.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once -#include - -#include "Class/LineParsing.h" -#include "Global.h" - - - -class ButtonInClass : public LineParsing { - protected: - int numberEntering = 0; - int state = _state.toInt(); - - public: - ButtonInClass() : LineParsing(){}; - - void init() { - if (_pin != "") { - int number = numberEntering++; - buttons[number].attach(_pin.toInt()); - buttons[number].interval(_db.toInt()); - but[number] = true; - jsonWriteStr(configOptionJson, "switch_num_" + String(number), _key); - } - } - - void loop() { - static uint8_t switch_number = 1; - if (but[switch_number]) { - buttons[switch_number].update(); - if (buttons[switch_number].fell()) { - String key = jsonReadStr(configOptionJson, "switch_num_" + String(switch_number)); - state = 1; - switchChangeVirtual(key, String(state)); - } - if (buttons[switch_number].rose()) { - String key = jsonReadStr(configOptionJson, "switch_num_" + String(switch_number)); - state = 0; - switchChangeVirtual(key, String(state)); - } - } - switch_number++; - if (switch_number == NUM_BUTTONS) { - switch_number = 0; - } - } - - void switchStateSetDefault() { - if (_state != "") { - switchChangeVirtual(_key, _state); - } - } - - void switchChangeVirtual(String key, String state) { - eventGen2(key, state); - jsonWriteInt(configLiveJson, key, state.toInt()); - publishStatus(key, state); - } -}; - -extern ButtonInClass myButtonIn; \ No newline at end of file diff --git a/include/items/ButtonOutClass.h b/include/items/ButtonOutClass.h deleted file mode 100644 index 1afebc63..00000000 --- a/include/items/ButtonOutClass.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include - -#include "Class/LineParsing.h" -#include "Global.h" - -class ButtonOutClass : public LineParsing { -public: - ButtonOutClass() : LineParsing() {}; - - void init() { - if (_pin != "") { - pinMode(_pin.toInt(), OUTPUT); - } - jsonWriteStr(configOptionJson, _key + "_pin", _pin); - jsonWriteStr(configOptionJson, _key + "_inv", _inv); - } - - void pinStateSetDefault() { - pinChange(_key, _state); - } - - - void pinChange(String key, String state) { - String pin = jsonReadStr(configOptionJson, key + "_pin"); - String inv = jsonReadStr(configOptionJson, key + "_inv"); - int pinInt = pin.toInt(); - - if (inv == "") { - digitalWrite(pinInt, state.toInt()); - } - else { - digitalWrite(pinInt, !state.toInt()); - } - eventGen2(key, state); - jsonWriteInt(configLiveJson, key, state.toInt()); - publishStatus(key, state); - } -}; - -extern ButtonOutClass myButtonOut; \ No newline at end of file diff --git a/include/items/ImpulsOutClass.h b/include/items/ImpulsOutClass.h deleted file mode 100644 index 1d9f9fa6..00000000 --- a/include/items/ImpulsOutClass.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include - -#include "Global.h" - -class ImpulsOutClass; - -typedef std::vector MyImpulsOutVector; - -class ImpulsOutClass { - public: - ImpulsOutClass(unsigned int impulsPin); - ~ImpulsOutClass(); - - void loop(); - void execute(unsigned long impulsPeriod, unsigned int impulsCount); - - private: - unsigned long currentMillis; - unsigned long prevMillis; - - unsigned long _impulsPeriod = 0; - unsigned int _impulsCount = 0; - unsigned int _impulsCountBuf = 0; - unsigned int _impulsPin = 0; - -}; - -extern MyImpulsOutVector* myImpulsOut; - -extern void impulsExecute(); diff --git a/include/items/InputClass.h b/include/items/InputClass.h deleted file mode 100644 index 447fccfe..00000000 --- a/include/items/InputClass.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include -#include "Class/LineParsing.h" -#include "Global.h" - -class InputClass : public LineParsing { - public: - InputClass() : LineParsing(){}; - - void inputSetDefaultFloat() { - inputSetFloat(_key, _state); - } - - void inputSetDefaultStr() { - inputSetStr(_key, _state); - } - - void inputSetFloat(String key, String state) { - eventGen2(key, state); - jsonWriteFloat(configLiveJson, key, state.toFloat()); - publishStatus(key, state); - } - - void inputSetStr(String key, String state) { - eventGen2(key, state); - jsonWriteStr(configLiveJson, key, state); - publishStatus(key, state); - } -}; - -extern InputClass myInput; \ No newline at end of file diff --git a/include/items/LoggingClass.h b/include/items/LoggingClass.h deleted file mode 100644 index 9f8094c7..00000000 --- a/include/items/LoggingClass.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include - -#include "Global.h" - -class LoggingClass; - -typedef std::vector MyLoggingVector; - -class LoggingClass { - public: - - LoggingClass(unsigned long period, unsigned int maxPoints, String loggingValueKey, String key); - ~LoggingClass(); - - void loop(); - - private: - - unsigned long currentMillis; - unsigned long prevMillis; - unsigned long _period; - unsigned int _maxPoints; - String _loggingValueKey; - String _key; - - void addNewDelOldData(const String filename, size_t maxPoints, String payload); -}; - -extern MyLoggingVector* myLogging; - -extern void choose_log_date_and_send(); -extern void sendLogData(String file, String topic); -extern void clean_log_date(); diff --git a/include/items/OutputTextClass.h b/include/items/OutputTextClass.h deleted file mode 100644 index 8e3867ba..00000000 --- a/include/items/OutputTextClass.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include -#include "Class/LineParsing.h" -#include "Global.h" - -class OutputTextClass : public LineParsing { - public: - OutputTextClass() : LineParsing(){}; - - void OutputModuleStateSetDefault() { - if (_state != "") { - OutputModuleChange(_key, _state); - } - } - - void OutputModuleChange(String key, String state) { - state.replace("#", " "); - eventGen2(key, state); - jsonWriteStr(configLiveJson, key, state); - publishStatus(key, state); - } -}; -extern OutputTextClass myOutputText; \ No newline at end of file diff --git a/include/items/PwmOutClass.h b/include/items/PwmOutClass.h deleted file mode 100644 index bd6570ba..00000000 --- a/include/items/PwmOutClass.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include -#include "Class/LineParsing.h" -#include "Global.h" - -class PwmOutClass : public LineParsing { - public: - PwmOutClass() : LineParsing(){}; - - void pwmModeSet() { - if (_pin != "") { - pinMode(_pin.toInt(), INPUT); - } - } - - void pwmStateSetDefault() { - if (_state != "") { - pwmChange(_key, _pin, _state); - } - } - - void pwmChange(String key, String pin, String state) { - int pinInt = pin.toInt(); - analogWrite(pinInt, state.toInt()); - eventGen2(key, state); - jsonWriteInt(configLiveJson, key, state.toInt()); - publishStatus(key, state); - } -}; - -extern PwmOutClass myPwmOut; \ No newline at end of file diff --git a/include/items/SensorAnalogClass.h b/include/items/SensorAnalogClass.h deleted file mode 100644 index ccaba263..00000000 --- a/include/items/SensorAnalogClass.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include - -#include "Class/LineParsing.h" -#include "Global.h" -#include "items/SensorConvertingClass.h" - -class SensorAnalogClass : public SensorConvertingClass { - public: - SensorAnalogClass() : SensorConvertingClass(){}; - - void SensorAnalogInit() { - jsonWriteStr(configOptionJson, _key + "_pin", _pin); - jsonWriteStr(configOptionJson, _key + "_map", _map); - jsonWriteStr(configOptionJson, _key + "_с", _c); - } - - int SensorAnalogRead(String key, String pin) { - int value; -#ifdef ESP32 - int pinInt = pin.toInt(); - value = analogRead(pinInt); -#endif -#ifdef ESP8266 - value = analogRead(A0); -#endif - value = this->mapping(key, value); - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - return value; - } -}; -extern SensorAnalogClass mySensorAnalog; \ No newline at end of file diff --git a/include/items/SensorBme280Class.h b/include/items/SensorBme280Class.h deleted file mode 100644 index 42b7d532..00000000 --- a/include/items/SensorBme280Class.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include - -#include "Class/LineParsing.h" -#include "Global.h" -#include "items/SensorConvertingClass.h" - -Adafruit_BME280 bme; -Adafruit_Sensor *bme_temp = bme.getTemperatureSensor(); -Adafruit_Sensor *bme_pressure = bme.getPressureSensor(); -Adafruit_Sensor *bme_humidity = bme.getHumiditySensor(); - -class SensorBme280Class : public SensorConvertingClass { - public: - SensorBme280Class() : SensorConvertingClass(){}; - - void SensorBme280Init() { - bme.begin(hexStringToUint8(_addr)); - jsonWriteStr(configOptionJson, _key + "_map", _map); - jsonWriteStr(configOptionJson, _key + "_с", _c); - sensorReadingMap10sec += _key + ","; - } - - void SensorBme280ReadTmp(String key) { - float value; - value = bme.readTemperature(); - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - } - - void SensorBme280ReadHum(String key) { - float value; - value = bme.readHumidity(); - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - } - - void SensorBme280ReadPress(String key) { - float value; - value = bme.readPressure(); - value = value / 1.333224 / 100; - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - } -}; -extern SensorBme280Class mySensorBme280; \ No newline at end of file diff --git a/include/items/SensorBmp280Class.h b/include/items/SensorBmp280Class.h deleted file mode 100644 index 934245a1..00000000 --- a/include/items/SensorBmp280Class.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include - -#include "Class/LineParsing.h" -#include "Global.h" -#include "items/SensorConvertingClass.h" - -Adafruit_BMP280 bmp; -Adafruit_Sensor *bmp_temp = bmp.getTemperatureSensor(); -Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor(); - -class SensorBmp280Class : public SensorConvertingClass { - public: - SensorBmp280Class() : SensorConvertingClass(){}; - - void SensorBmp280Init() { - bmp.begin(hexStringToUint8(_addr)); - jsonWriteStr(configOptionJson, _key + "_map", _map); - jsonWriteStr(configOptionJson, _key + "_с", _c); - sensorReadingMap10sec += _key + ","; - } - - void SensorBmp280ReadTmp(String key) { - float value; - sensors_event_t temp_event; - bmp_temp->getEvent(&temp_event); - value = temp_event.temperature; - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - } - - void SensorBmp280ReadPress(String key) { - float value; - sensors_event_t pressure_event; - bmp_pressure->getEvent(&pressure_event); - value = pressure_event.pressure; - value = value / 1.333224; - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - } -}; -extern SensorBmp280Class mySensorBmp280; \ No newline at end of file diff --git a/include/items/SensorConvertingClass.h b/include/items/SensorConvertingClass.h deleted file mode 100644 index 5ddf59c8..00000000 --- a/include/items/SensorConvertingClass.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include "Class/LineParsing.h" -#include "Global.h" - -class SensorConvertingClass : public LineParsing { - public: - SensorConvertingClass() : LineParsing(){}; - - int mapping(String key, int input) { - String map_ = jsonReadStr(configOptionJson, key + "_map"); - if (map_ != "") { - input = map(input, - selectFromMarkerToMarker(map_, ",", 0).toInt(), - selectFromMarkerToMarker(map_, ",", 1).toInt(), - selectFromMarkerToMarker(map_, ",", 2).toInt(), - selectFromMarkerToMarker(map_, ",", 3).toInt()); - } - return input; - } - - float correction(String key, float input) { - String corr = jsonReadStr(configOptionJson, key + "_с"); - if (corr != "") { - float coef = corr.toFloat(); - input = input * coef; - } - return input; - } -}; \ No newline at end of file diff --git a/include/items/SensorDallas.h b/include/items/SensorDallas.h deleted file mode 100644 index 3feeb572..00000000 --- a/include/items/SensorDallas.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "Global.h" -#include - -extern DallasTemperature sensors; -extern OneWire* oneWire; - -class SensorDallas; - -typedef std::vector MySensorDallasVector; - -class SensorDallas { -public: - - SensorDallas(unsigned long interval, unsigned int pin, unsigned int index, String key); - ~SensorDallas(); - - void loop(); - void readDallas(); - -private: - - unsigned long currentMillis; - unsigned long prevMillis; - unsigned long _interval; - String _key; - unsigned int _pin; - unsigned int _index; - -}; - -extern MySensorDallasVector* mySensorDallas2; - -extern void dallas(); - - diff --git a/include/items/SensorDhtClass.h b/include/items/SensorDhtClass.h deleted file mode 100644 index 6eb4433b..00000000 --- a/include/items/SensorDhtClass.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once -#include - -#include "Class/LineParsing.h" -#include "Global.h" -#include "items/SensorConvertingClass.h" - -DHTesp dht; -class SensorDhtClass : public SensorConvertingClass { - public: - SensorDhtClass() : SensorConvertingClass(){}; - - void SensorDhtInit() { - if (_type == "dht11") { - dht.setup(_pin.toInt(), DHTesp::DHT11); - } - if (_type == "dht22") { - dht.setup(_pin.toInt(), DHTesp::DHT22); - } - sensorReadingMap10sec += _key + ","; - - //to do если надо будет читать несколько dht - //dhtEnterCounter++; - //jsonWriteInt(configOptionJson, _key + "_num", dhtEnterCounter); - - jsonWriteStr(configOptionJson, _key + "_map", _map); - jsonWriteStr(configOptionJson, _key + "_с", _c); - } - - void SensorDhtReadTemp(String key) { - //to do если надо будет читать несколько dht - //int cnt = jsonReadInt(configOptionJson, key + "_num"); - float value; - static int counter; - if (dht.getStatus() != 0 && counter < 5) { - counter++; - //return; - } else { - counter = 0; - value = dht.getTemperature(); - if (String(value) != "nan") { - //value = this->mapping(key, value); - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - } else { - Serial.println("[E] sensor '" + key); - } - } - } - - void SensorDhtReadHum(String key) { - //to do если надо будет читать несколько dht - //int cnt = jsonReadInt(configOptionJson, key + "_num"); - float value; - static int counter; - if (dht.getStatus() != 0 && counter < 5) { - counter++; - //return; - } else { - counter = 0; - value = dht.getHumidity(); - if (String(value) != "nan") { - //value = this->mapping(key, value); - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - } else { - Serial.println("[E] sensor '" + key); - } - } - } -}; -extern SensorDhtClass mySensorDht; \ No newline at end of file diff --git a/include/items/SensorModbusClass.h b/include/items/SensorModbusClass.h deleted file mode 100644 index a93063c8..00000000 --- a/include/items/SensorModbusClass.h +++ /dev/null @@ -1,83 +0,0 @@ -//#pragma once -//#include -//#include -//#include -// -//#include "Class/LineParsing.h" -//#include "Global.h" -//#include "items/SensorConvertingClass.h" -// -//ModbusMaster modbus1; -//SoftwareSerial uart(13, 12); // RX, TX -// -//class SensorModbusClass : public SensorConvertingClass { -// public: -// SensorModbusClass() : SensorConvertingClass(){}; -// -// void SensorModbusInit() { -// uart.begin(9600); -// jsonWriteStr(configOptionJson, _key + "_map", _map); -// jsonWriteStr(configOptionJson, _key + "_с", _c); -// sensorReadingMap10sec += _key + " " + _addr + " " + _reg + ","; -// Serial.println(sensorReadingMap10sec); -// } -// -// void SensorModbusRead(String key, uint8_t slaveAddress, uint16_t regAddress) { -// int value; -// -// modbus1.begin(slaveAddress, uart); -// uint16_t reqisterValue = modbus1.readHoldingRegisters(regAddress, 1); -// if (getResultMsg(&modbus1, reqisterValue)) { -// reqisterValue = modbus1.getResponseBuffer(0); -// value = reqisterValue; -// } else { -// value = NULL; -// } -// -// int valueFl = this->correction(key, value); -// eventGen2(key, String(valueFl)); -// jsonWriteStr(configLiveJson, key, String(valueFl)); -// publishStatus(key, String(valueFl)); -// SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl) + ", Slave dev addr: " + String(slaveAddress) + ", Register: " + String(regAddress)); -// } -// -// bool getResultMsg(ModbusMaster* modbus1, uint16_t result) { -// String tmpstr; -// switch (result) { -// case modbus1->ku8MBSuccess: -// return true; -// tmpstr += "Ok"; -// break; -// case modbus1->ku8MBIllegalFunction: -// tmpstr += "Illegal Function"; -// break; -// case modbus1->ku8MBIllegalDataAddress: -// tmpstr += "Illegal Data Address"; -// break; -// case modbus1->ku8MBIllegalDataValue: -// tmpstr += "Illegal Data Value"; -// break; -// case modbus1->ku8MBSlaveDeviceFailure: -// tmpstr += "Slave Device Failure"; -// break; -// case modbus1->ku8MBInvalidSlaveID: -// tmpstr += "Invalid Slave ID"; -// break; -// case modbus1->ku8MBInvalidFunction: -// tmpstr += "Invalid Function"; -// break; -// case modbus1->ku8MBResponseTimedOut: -// tmpstr += "Response Timed Out"; -// break; -// case modbus1->ku8MBInvalidCRC: -// tmpstr += "Invalid CRC"; -// break; -// default: -// tmpstr += "Unknown error: " + String(result); -// break; -// } -// SerialPrint("I", "Modbus", tmpstr); -// return false; -// } -//}; -//extern SensorModbusClass mySensorModbus; \ No newline at end of file diff --git a/include/items/SensorUltrasonicClass.h b/include/items/SensorUltrasonicClass.h deleted file mode 100644 index 6adce30d..00000000 --- a/include/items/SensorUltrasonicClass.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include - -#include "Class/LineParsing.h" -#include "Global.h" -#include "items/SensorConvertingClass.h" -#include "GyverFilters.h" - -GMedian<6, int> testFilter; - -class SensorUltrasonic : public SensorConvertingClass { - public: - SensorUltrasonic() : SensorConvertingClass(){}; - void init() { - sensorReadingMap10sec += _key + ","; - String trig = selectFromMarkerToMarker(_pin, ",", 0); - String echo = selectFromMarkerToMarker(_pin, ",", 1); - pinMode(trig.toInt(), OUTPUT); - pinMode(echo.toInt(), INPUT); - jsonWriteStr(configOptionJson, _key + "_trig", trig); - jsonWriteStr(configOptionJson, _key + "_echo", echo); - jsonWriteStr(configOptionJson, _key + "_map", _map); - jsonWriteStr(configOptionJson, _key + "_с", _c); - } - - void SensorUltrasonicRead(String key) { - int trig = jsonReadStr(configOptionJson, key + "_trig").toInt(); - int echo = jsonReadStr(configOptionJson, key + "_echo").toInt(); - int value; - - digitalWrite(trig, LOW); - delayMicroseconds(2); - digitalWrite(trig, HIGH); - delayMicroseconds(10); - digitalWrite(trig, LOW); - long duration_ = pulseIn(echo, HIGH, 30000); // 3000 µs = 50cm // 30000 µs = 5 m - value = duration_ / 29 / 2; - - value = testFilter.filtered(value); - - value = this->mapping(key, value); - float valueFl = this->correction(key, value); - eventGen2(key, String(valueFl)); - jsonWriteStr(configLiveJson, key, String(valueFl)); - publishStatus(key, String(valueFl)); - SerialPrint("I", "Sensor", "'" + key + "' data: " + String(valueFl)); - } -}; -extern SensorUltrasonic mySensorUltrasonic; \ No newline at end of file diff --git a/include/main.h b/include/main.h deleted file mode 100644 index 0d48dfc5..00000000 --- a/include/main.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -//void myCallback; \ No newline at end of file diff --git a/lib/ESP8266-StringCommand/StringCommand.cpp b/lib/ESP8266-StringCommand/StringCommand.cpp deleted file mode 100644 index 3d53dcd7..00000000 --- a/lib/ESP8266-StringCommand/StringCommand.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/** - * SerialCommand - A Wiring/Arduino library to tokenize and parse commands - * received over a serial port. - * - * Copyright (C) 2012 Stefan Rado - * Copyright (C) 2011 Steven Cogswell - * http://husks.wordpress.com - * - * Version 20120522 - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this library. If not, see . - */ -#include "StringCommand.h" - -/** - * Constructor makes sure some things are set. - */ -StringCommand::StringCommand() - : commandList(NULL), - commandCount(0), - defaultHandler(NULL), - term('\n'), // default terminator for commands, newline character - last(NULL), - main(NULL) -{ - strcpy(delim, " "); // strtok_r needs a null-terminated string - clearBuffer(); -} - -/** - * Adds a "command" and a handler function to the list of available commands. - * This is used for matching a found token in the buffer, and gives the pointer - * to the handler function to deal with it. - */ -void StringCommand::addCommand(const char *command, void (*function)()) { - #ifdef SERIALCOMMAND_DEBUG - Serial.print("Adding command ("); - Serial.print(commandCount); - Serial.print("): "); - Serial.println(command); - #endif - - commandList = (StringCommandCallback *) realloc(commandList, (commandCount + 1) * sizeof(StringCommandCallback)); - strncpy(commandList[commandCount].command, command, SERIALCOMMAND_MAXCOMMANDLENGTH); - commandList[commandCount].function = function; - commandCount++; -} - -/** - * This sets up a handler to be called in the event that the receveived command string - * isn't in the list of commands. - */ -void StringCommand::setDefaultHandler(void (*function)(const char *)) { - defaultHandler = function; -} - - -/** - * This checks the Serial stream for characters, and assembles them into a buffer. - * When the terminator character (default '\n') is seen, it starts parsing the - * buffer for a prefix command, and calls handlers setup by addCommand() member - */ -void StringCommand::readStr(String sBuffer ) { - sBuffer.toCharArray(buffer, SERIALCOMMAND_BUFFER); - #ifdef SERIALCOMMAND_DEBUG - Serial.print("Received: "); - Serial.println(buffer); - #endif - - char *command = strtok_r(buffer, delim, &last); // Search for command at start of buffer - if (command != NULL) { - boolean matched = false; - for (int i = 0; i < commandCount; i++) { - #ifdef SERIALCOMMAND_DEBUG - Serial.print("Comparing ["); - Serial.print(command); - Serial.print("] to ["); - Serial.print(commandList[i].command); - Serial.println("]"); - #endif - - - - // Compare the found command against the list of known commands for a match - if (strncmp(command, commandList[i].command, SERIALCOMMAND_MAXCOMMANDLENGTH) == 0) { - #ifdef SERIALCOMMAND_DEBUG - Serial.print("Matched Command: "); - Serial.println(command); - #endif - - // Execute the stored handler function for the command - (*commandList[i].function)(); - matched = true; - break; - } - } - - - if (!matched && (defaultHandler != NULL)) { - (*defaultHandler)(command); - } - - - clearBuffer(); - } -} - -/* - * Clear the input buffer. - */ -void StringCommand::clearBuffer() { - buffer[0] = '\0'; - bufPos = 0; -} - -/** - * Retrieve the next token ("word" or "argument") from the command buffer. - * Returns NULL if no more tokens exist. - */ -char *StringCommand::next() { - return strtok_r(NULL, delim, &last); -} - -char *StringCommand::order() { - return strtok_r(buffer, delim, &main); -} diff --git a/lib/ESP8266-StringCommand/StringCommand.h b/lib/ESP8266-StringCommand/StringCommand.h deleted file mode 100644 index b37d5a1a..00000000 --- a/lib/ESP8266-StringCommand/StringCommand.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * SerialCommand - A Wiring/Arduino library to tokenize and parse commands - * received over a serial port. - * - * Copyright (C) 2012 Stefan Rado - * Copyright (C) 2011 Steven Cogswell - * http://husks.wordpress.com - * - * Version 20120522 - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this library. If not, see . - */ -#ifndef StringCommand_h -#define StringCommand_h - -#if defined(WIRING) && WIRING >= 100 - #include -#elif defined(ARDUINO) && ARDUINO >= 100 - #include -#else - #include -#endif -#include - -// Size of the input buffer in bytes (maximum length of one command plus arguments) -#define SERIALCOMMAND_BUFFER 128 //256 -// Maximum length of a command excluding the terminating null -#define SERIALCOMMAND_MAXCOMMANDLENGTH 16 - -// Uncomment the next line to run the library in debug mode (verbose messages) -//#define SERIALCOMMAND_DEBUG - - -class StringCommand { - public: - StringCommand(); // Constructor - void addCommand(const char *command, void(*function)()); // Add a command to the processing dictionary. - void setDefaultHandler(void (*function)(const char *)); // A handler to call when no valid command received. - - void readStr(String sBuffer ); // Main entry point. - void clearBuffer(); // Clears the input buffer. - char *next(); // Returns pointer to next token found in command buffer (for getting arguments to commands). - char *order(); - - private: - // Command/handler dictionary - struct StringCommandCallback { - char command[SERIALCOMMAND_MAXCOMMANDLENGTH + 1]; - void (*function)(); - }; // Data structure to hold Command/Handler function key-value pairs - StringCommandCallback *commandList; // Actual definition for command/handler array - byte commandCount; - - // Pointer to the default handler function - void (*defaultHandler)(const char *); - - char delim[2]; // null-terminated list of character to be used as delimeters for tokenizing (default " ") - char term; // Character that signals end of command (default '\n') - - char buffer[SERIALCOMMAND_BUFFER + 1]; // Buffer of stored characters while waiting for terminator character - byte bufPos; // Current position in the buffer - char *last; // State variable used by strtok_r during processing - char *main; -}; - -#endif //StringCommand_h diff --git a/lib/ESP8266-StringCommand/keywords.txt b/lib/ESP8266-StringCommand/keywords.txt deleted file mode 100644 index c9799b2c..00000000 --- a/lib/ESP8266-StringCommand/keywords.txt +++ /dev/null @@ -1,23 +0,0 @@ -####################################### -# Datatypes (KEYWORD1) -####################################### - -StringCommand KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -addCommand KEYWORD2 -setDefaultHandler KEYWORD2 -readString KEYWORD2 -clearBuffer KEYWORD2 -next KEYWORD2 - -####################################### -# Instances (KEYWORD2) -####################################### - -####################################### -# Constants (LITERAL1) -####################################### diff --git a/lib/ESP8266-StringCommand/readme.md b/lib/ESP8266-StringCommand/readme.md deleted file mode 100644 index 731ee5e2..00000000 --- a/lib/ESP8266-StringCommand/readme.md +++ /dev/null @@ -1,5 +0,0 @@ -StringCommand -============= -Библиотека для ESP8266 позволяющая связать запуск пользовательских функций с строковой переменной. - - diff --git a/lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp32.sh b/lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp32.sh deleted file mode 100644 index cf1026d6..00000000 --- a/lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp32.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -export ARDUINO_ESP32_PATH="$ARDUINO_USR_PATH/hardware/espressif/esp32" -if [ ! -d "$ARDUINO_ESP32_PATH" ]; then - echo "Installing ESP32 Arduino Core ..." - script_init_path="$PWD" - mkdir -p "$ARDUINO_USR_PATH/hardware/espressif" - cd "$ARDUINO_USR_PATH/hardware/espressif" - - echo "Installing Python Serial ..." - pip install pyserial > /dev/null - - if [ "$OS_IS_WINDOWS" == "1" ]; then - echo "Installing Python Requests ..." - pip install requests > /dev/null - fi - - if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then - echo "Linking Core..." - ln -s $GITHUB_WORKSPACE esp32 - else - echo "Cloning Core Repository..." - git clone https://github.com/espressif/arduino-esp32.git esp32 > /dev/null 2>&1 - fi - - echo "Updating Submodules ..." - cd esp32 - git submodule update --init --recursive > /dev/null 2>&1 - - echo "Installing Platform Tools ..." - cd tools && python get.py - cd $script_init_path - - echo "ESP32 Arduino has been installed in '$ARDUINO_ESP32_PATH'" - echo "" -fi diff --git a/lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp8266.sh b/lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp8266.sh deleted file mode 100644 index 048cd024..00000000 --- a/lib/ESPAsyncWebServer/.github/scripts/install-arduino-core-esp8266.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -echo "Installing ESP8266 Arduino Core ..." -script_init_path="$PWD" -mkdir -p "$ARDUINO_USR_PATH/hardware/esp8266com" -cd "$ARDUINO_USR_PATH/hardware/esp8266com" - -echo "Installing Python Serial ..." -pip install pyserial > /dev/null - -if [ "$OS_IS_WINDOWS" == "1" ]; then - echo "Installing Python Requests ..." - pip install requests > /dev/null -fi - -echo "Cloning Core Repository ..." -git clone https://github.com/esp8266/Arduino.git esp8266 > /dev/null 2>&1 - -echo "Updating submodules ..." -cd esp8266 -git submodule update --init --recursive > /dev/null 2>&1 - -echo "Installing Platform Tools ..." -cd tools -python get.py > /dev/null -cd $script_init_path - -echo "ESP8266 Arduino has been installed in '$ARDUINO_USR_PATH/hardware/esp8266com'" -echo "" diff --git a/lib/ESPAsyncWebServer/.github/scripts/install-arduino-ide.sh b/lib/ESPAsyncWebServer/.github/scripts/install-arduino-ide.sh deleted file mode 100644 index ce60cb82..00000000 --- a/lib/ESPAsyncWebServer/.github/scripts/install-arduino-ide.sh +++ /dev/null @@ -1,228 +0,0 @@ -#!/bin/bash - -#OSTYPE: 'linux-gnu', ARCH: 'x86_64' => linux64 -#OSTYPE: 'msys', ARCH: 'x86_64' => win32 -#OSTYPE: 'darwin18', ARCH: 'i386' => macos - -OSBITS=`arch` -if [[ "$OSTYPE" == "linux"* ]]; then - export OS_IS_LINUX="1" - ARCHIVE_FORMAT="tar.xz" - if [[ "$OSBITS" == "i686" ]]; then - OS_NAME="linux32" - elif [[ "$OSBITS" == "x86_64" ]]; then - OS_NAME="linux64" - elif [[ "$OSBITS" == "armv7l" || "$OSBITS" == "aarch64" ]]; then - OS_NAME="linuxarm" - else - OS_NAME="$OSTYPE-$OSBITS" - echo "Unknown OS '$OS_NAME'" - exit 1 - fi -elif [[ "$OSTYPE" == "darwin"* ]]; then - export OS_IS_MACOS="1" - ARCHIVE_FORMAT="zip" - OS_NAME="macosx" -elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then - export OS_IS_WINDOWS="1" - ARCHIVE_FORMAT="zip" - OS_NAME="windows" -else - OS_NAME="$OSTYPE-$OSBITS" - echo "Unknown OS '$OS_NAME'" - exit 1 -fi -export OS_NAME - -ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp" -ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp" - -if [ "$OS_IS_MACOS" == "1" ]; then - export ARDUINO_IDE_PATH="/Applications/Arduino.app/Contents/Java" - export ARDUINO_USR_PATH="$HOME/Documents/Arduino" -elif [ "$OS_IS_WINDOWS" == "1" ]; then - export ARDUINO_IDE_PATH="$HOME/arduino_ide" - export ARDUINO_USR_PATH="$HOME/Documents/Arduino" -else - export ARDUINO_IDE_PATH="$HOME/arduino_ide" - export ARDUINO_USR_PATH="$HOME/Arduino" -fi - -if [ ! -d "$ARDUINO_IDE_PATH" ]; then - echo "Installing Arduino IDE on $OS_NAME ..." - echo "Downloading 'arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT' to 'arduino.$ARCHIVE_FORMAT' ..." - if [ "$OS_IS_LINUX" == "1" ]; then - wget -O "arduino.$ARCHIVE_FORMAT" "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1 - echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..." - tar xf "arduino.$ARCHIVE_FORMAT" > /dev/null - mv arduino-nightly "$ARDUINO_IDE_PATH" - else - curl -o "arduino.$ARCHIVE_FORMAT" -L "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1 - echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..." - unzip "arduino.$ARCHIVE_FORMAT" > /dev/null - if [ "$OS_IS_MACOS" == "1" ]; then - mv "Arduino.app" "/Applications/Arduino.app" - else - mv arduino-nightly "$ARDUINO_IDE_PATH" - fi - fi - rm -rf "arduino.$ARCHIVE_FORMAT" - - mkdir -p "$ARDUINO_USR_PATH/libraries" - mkdir -p "$ARDUINO_USR_PATH/hardware" - - echo "Arduino IDE Installed in '$ARDUINO_IDE_PATH'" - echo "" -fi - -function build_sketch(){ # build_sketch [extra-options] - if [ "$#" -lt 2 ]; then - echo "ERROR: Illegal number of parameters" - echo "USAGE: build_sketch [extra-options]" - return 1 - fi - - local fqbn="$1" - local sketch="$2" - local build_flags="$3" - local xtra_opts="$4" - local win_opts="" - if [ "$OS_IS_WINDOWS" == "1" ]; then - local ctags_version=`ls "$ARDUINO_IDE_PATH/tools-builder/ctags/"` - local preprocessor_version=`ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/"` - win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version -prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version" - fi - - echo "" - echo "Compiling '"$(basename "$sketch")"' ..." - mkdir -p "$ARDUINO_BUILD_DIR" - mkdir -p "$ARDUINO_CACHE_DIR" - $ARDUINO_IDE_PATH/arduino-builder -compile -logger=human -core-api-version=10810 \ - -fqbn=$fqbn \ - -warnings="all" \ - -tools "$ARDUINO_IDE_PATH/tools-builder" \ - -tools "$ARDUINO_IDE_PATH/tools" \ - -built-in-libraries "$ARDUINO_IDE_PATH/libraries" \ - -hardware "$ARDUINO_IDE_PATH/hardware" \ - -hardware "$ARDUINO_USR_PATH/hardware" \ - -libraries "$ARDUINO_USR_PATH/libraries" \ - -build-cache "$ARDUINO_CACHE_DIR" \ - -build-path "$ARDUINO_BUILD_DIR" \ - -prefs=compiler.cpp.extra_flags="$build_flags" \ - $win_opts $xtra_opts "$sketch" -} - -function count_sketches() # count_sketches -{ - local examples="$1" - rm -rf sketches.txt - if [ ! -d "$examples" ]; then - touch sketches.txt - return 0 - fi - local sketches=$(find $examples -name *.ino) - local sketchnum=0 - for sketch in $sketches; do - local sketchdir=$(dirname $sketch) - local sketchdirname=$(basename $sketchdir) - local sketchname=$(basename $sketch) - if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then - continue - fi; - if [[ -f "$sketchdir/.test.skip" ]]; then - continue - fi - echo $sketch >> sketches.txt - sketchnum=$(($sketchnum + 1)) - done - return $sketchnum -} - -function build_sketches() # build_sketches [extra-options] -{ - local fqbn=$1 - local examples=$2 - local chunk_idex=$3 - local chunks_num=$4 - local xtra_opts=$5 - - if [ "$#" -lt 2 ]; then - echo "ERROR: Illegal number of parameters" - echo "USAGE: build_sketches [ ] [extra-options]" - return 1 - fi - - if [ "$#" -lt 4 ]; then - chunk_idex="0" - chunks_num="1" - xtra_opts=$3 - fi - - if [ "$chunks_num" -le 0 ]; then - echo "ERROR: Chunks count must be positive number" - return 1 - fi - if [ "$chunk_idex" -ge "$chunks_num" ]; then - echo "ERROR: Chunk index must be less than chunks count" - return 1 - fi - - set +e - count_sketches "$examples" - local sketchcount=$? - set -e - local sketches=$(cat sketches.txt) - rm -rf sketches.txt - - local chunk_size=$(( $sketchcount / $chunks_num )) - local all_chunks=$(( $chunks_num * $chunk_size )) - if [ "$all_chunks" -lt "$sketchcount" ]; then - chunk_size=$(( $chunk_size + 1 )) - fi - - local start_index=$(( $chunk_idex * $chunk_size )) - if [ "$sketchcount" -le "$start_index" ]; then - echo "Skipping job" - return 0 - fi - - local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size )) - if [ "$end_index" -gt "$sketchcount" ]; then - end_index=$sketchcount - fi - - local start_num=$(( $start_index + 1 )) - echo "Found $sketchcount Sketches"; - echo "Chunk Count : $chunks_num" - echo "Chunk Size : $chunk_size" - echo "Start Sketch: $start_num" - echo "End Sketch : $end_index" - - local sketchnum=0 - for sketch in $sketches; do - local sketchdir=$(dirname $sketch) - local sketchdirname=$(basename $sketchdir) - local sketchname=$(basename $sketch) - if [ "${sketchdirname}.ino" != "$sketchname" ] \ - || [ -f "$sketchdir/.test.skip" ]; then - continue - fi - sketchnum=$(($sketchnum + 1)) - if [ "$sketchnum" -le "$start_index" ] \ - || [ "$sketchnum" -gt "$end_index" ]; then - continue - fi - local sketchBuildFlags="" - if [ -f "$sketchdir/.test.build_flags" ]; then - while read line; do - sketchBuildFlags="$sketchBuildFlags $line" - done < "$sketchdir/.test.build_flags" - fi - build_sketch "$fqbn" "$sketch" "$sketchBuildFlags" "$xtra_opts" - local result=$? - if [ $result -ne 0 ]; then - return $result - fi - done - return 0 -} diff --git a/lib/ESPAsyncWebServer/.github/scripts/install-platformio.sh b/lib/ESPAsyncWebServer/.github/scripts/install-platformio.sh deleted file mode 100644 index 594948ea..00000000 --- a/lib/ESPAsyncWebServer/.github/scripts/install-platformio.sh +++ /dev/null @@ -1,140 +0,0 @@ -#!/bin/bash - -echo "Installing Python Wheel ..." -pip install wheel > /dev/null 2>&1 - -echo "Installing PlatformIO ..." -pip install -U platformio > /dev/null 2>&1 - -echo "PlatformIO has been installed" -echo "" - - -function build_pio_sketch(){ # build_pio_sketch - if [ "$#" -lt 3 ]; then - echo "ERROR: Illegal number of parameters" - echo "USAGE: build_pio_sketch " - return 1 - fi - - local board="$1" - local sketch="$2" - local buildFlags="$3" - local sketch_dir=$(dirname "$sketch") - echo "" - echo "Compiling '"$(basename "$sketch")"' ..." - python -m platformio ci -l '.' --board "$board" "$sketch_dir" --project-option="board_build.partitions = huge_app.csv" --project-option="build_flags=$buildFlags" -} - -function count_sketches() # count_sketches -{ - local examples="$1" - rm -rf sketches.txt - if [ ! -d "$examples" ]; then - touch sketches.txt - return 0 - fi - local sketches=$(find $examples -name *.ino) - local sketchnum=0 - for sketch in $sketches; do - local sketchdir=$(dirname $sketch) - local sketchdirname=$(basename $sketchdir) - local sketchname=$(basename $sketch) - if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then - continue - fi; - if [[ -f "$sketchdir/.test.skip" ]]; then - continue - fi - echo $sketch >> sketches.txt - sketchnum=$(($sketchnum + 1)) - done - return $sketchnum -} - -function build_pio_sketches() # build_pio_sketches -{ - if [ "$#" -lt 2 ]; then - echo "ERROR: Illegal number of parameters" - echo "USAGE: build_pio_sketches [ ]" - return 1 - fi - - local board=$1 - local examples=$2 - local chunk_idex=$3 - local chunks_num=$4 - - if [ "$#" -lt 4 ]; then - chunk_idex="0" - chunks_num="1" - fi - - if [ "$chunks_num" -le 0 ]; then - echo "ERROR: Chunks count must be positive number" - return 1 - fi - if [ "$chunk_idex" -ge "$chunks_num" ]; then - echo "ERROR: Chunk index must be less than chunks count" - return 1 - fi - - set +e - count_sketches "$examples" - local sketchcount=$? - set -e - local sketches=$(cat sketches.txt) - rm -rf sketches.txt - - local chunk_size=$(( $sketchcount / $chunks_num )) - local all_chunks=$(( $chunks_num * $chunk_size )) - if [ "$all_chunks" -lt "$sketchcount" ]; then - chunk_size=$(( $chunk_size + 1 )) - fi - - local start_index=$(( $chunk_idex * $chunk_size )) - if [ "$sketchcount" -le "$start_index" ]; then - echo "Skipping job" - return 0 - fi - - local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size )) - if [ "$end_index" -gt "$sketchcount" ]; then - end_index=$sketchcount - fi - - local start_num=$(( $start_index + 1 )) - echo "Found $sketchcount Sketches"; - echo "Chunk Count : $chunks_num" - echo "Chunk Size : $chunk_size" - echo "Start Sketch: $start_num" - echo "End Sketch : $end_index" - - local sketchnum=0 - for sketch in $sketches; do - local sketchdir=$(dirname $sketch) - local sketchdirname=$(basename $sketchdir) - local sketchname=$(basename $sketch) - if [ "${sketchdirname}.ino" != "$sketchname" ] \ - || [ -f "$sketchdir/.test.skip" ]; then - continue - fi - local sketchBuildFlags="" - if [ -f "$sketchdir/.test.build_flags" ]; then - while read line; do - sketchBuildFlags="$sketchBuildFlags $line" - done < "$sketchdir/.test.build_flags" - fi - sketchnum=$(($sketchnum + 1)) - if [ "$sketchnum" -le "$start_index" ] \ - || [ "$sketchnum" -gt "$end_index" ]; then - continue - fi - build_pio_sketch "$board" "$sketch" "$sketchBuildFlags" - local result=$? - if [ $result -ne 0 ]; then - return $result - fi - done - return 0 -} diff --git a/lib/ESPAsyncWebServer/.github/scripts/on-push.sh b/lib/ESPAsyncWebServer/.github/scripts/on-push.sh deleted file mode 100644 index 96fff573..00000000 --- a/lib/ESPAsyncWebServer/.github/scripts/on-push.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -set -e - -if [ ! -z "$TRAVIS_BUILD_DIR" ]; then - export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR" - export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG" -elif [ -z "$GITHUB_WORKSPACE" ]; then - export GITHUB_WORKSPACE="$PWD" - export GITHUB_REPOSITORY="me-no-dev/ESPAsyncWebServer" -fi - -TARGET_PLATFORM="$1" -CHUNK_INDEX=$2 -CHUNKS_CNT=$3 -BUILD_PIO=0 -if [ "$#" -lt 1 ]; then - TARGET_PLATFORM="esp32" -fi -if [ "$#" -lt 3 ] || [ "$CHUNKS_CNT" -le 0 ]; then - CHUNK_INDEX=0 - CHUNKS_CNT=1 -elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ]; then - CHUNK_INDEX=$CHUNKS_CNT -elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then - BUILD_PIO=1 -fi - -if [ "$BUILD_PIO" -eq 0 ]; then - # ArduinoIDE Test - source ./.github/scripts/install-arduino-ide.sh - - echo "Installing ESPAsyncWebServer ..." - cp -rf "$GITHUB_WORKSPACE" "$ARDUINO_USR_PATH/libraries/ESPAsyncWebServer" - echo "Installing ArduinoJson ..." - git clone https://github.com/bblanchon/ArduinoJson "$ARDUINO_USR_PATH/libraries/ArduinoJson" > /dev/null 2>&1 - - if [[ "$TARGET_PLATFORM" == "esp32" ]]; then - echo "Installing AsyncTCP ..." - git clone https://github.com/me-no-dev/AsyncTCP "$ARDUINO_USR_PATH/libraries/AsyncTCP" > /dev/null 2>&1 - FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app" - source ./.github/scripts/install-arduino-core-esp32.sh - echo "BUILDING ESP32 EXAMPLES" - else - echo "Installing ESPAsyncTCP ..." - git clone https://github.com/me-no-dev/ESPAsyncTCP "$ARDUINO_USR_PATH/libraries/ESPAsyncTCP" > /dev/null 2>&1 - FQBN="esp8266com:esp8266:generic:eesz=4M1M,ip=lm2f" - source ./.github/scripts/install-arduino-core-esp8266.sh - echo "BUILDING ESP8266 EXAMPLES" - fi - build_sketches "$FQBN" "$GITHUB_WORKSPACE/examples" "$CHUNK_INDEX" "$CHUNKS_CNT" -else - # PlatformIO Test - source ./.github/scripts/install-platformio.sh - - python -m platformio lib --storage-dir "$GITHUB_WORKSPACE" install - echo "Installing ArduinoJson ..." - python -m platformio lib -g install https://github.com/bblanchon/ArduinoJson.git > /dev/null 2>&1 - if [[ "$TARGET_PLATFORM" == "esp32" ]]; then - BOARD="esp32dev" - echo "Installing AsyncTCP ..." - python -m platformio lib -g install https://github.com/me-no-dev/AsyncTCP.git > /dev/null 2>&1 - echo "BUILDING ESP32 EXAMPLES" - else - BOARD="esp12e" - echo "Installing ESPAsyncTCP ..." - python -m platformio lib -g install https://github.com/me-no-dev/ESPAsyncTCP.git > /dev/null 2>&1 - echo "BUILDING ESP8266 EXAMPLES" - fi - build_pio_sketches "$BOARD" "$GITHUB_WORKSPACE/examples" -fi diff --git a/lib/ESPAsyncWebServer/.github/stale.yml b/lib/ESPAsyncWebServer/.github/stale.yml deleted file mode 100644 index ce7a8e3f..00000000 --- a/lib/ESPAsyncWebServer/.github/stale.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Configuration for probot-stale - https://github.com/probot/stale - -daysUntilStale: 60 -daysUntilClose: 14 -limitPerRun: 30 -staleLabel: stale -exemptLabels: - - pinned - - security - - "to be implemented" - - "for reference" - - "move to PR" - - "enhancement" - -only: issues -onlyLabels: [] -exemptProjects: false -exemptMilestones: false -exemptAssignees: false - -markComment: > - [STALE_SET] This issue has been automatically marked as stale because it has not had - recent activity. It will be closed in 14 days if no further activity occurs. Thank you - for your contributions. - -unmarkComment: > - [STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future. - -closeComment: > - [STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions. - diff --git a/lib/ESPAsyncWebServer/.github/workflows/push.yml b/lib/ESPAsyncWebServer/.github/workflows/push.yml deleted file mode 100644 index abdea462..00000000 --- a/lib/ESPAsyncWebServer/.github/workflows/push.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: ESP Async Web Server CI - -on: - push: - branches: - - master - - release/* - pull_request: - -jobs: - - build-arduino: - name: Arduino for ${{ matrix.board }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - board: [esp32, esp8266] - steps: - - uses: actions/checkout@v1 - - name: Build Tests - run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 0 1 - - build-pio: - name: PlatformIO for ${{ matrix.board }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - board: [esp32, esp8266] - steps: - - uses: actions/checkout@v1 - - name: Build Tests - run: bash ./.github/scripts/on-push.sh ${{ matrix.board }} 1 1 diff --git a/lib/ESPAsyncWebServer/.gitignore b/lib/ESPAsyncWebServer/.gitignore deleted file mode 100644 index a0f0e538..00000000 --- a/lib/ESPAsyncWebServer/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.vscode -.DS_Store diff --git a/lib/ESPAsyncWebServer/.travis.yml b/lib/ESPAsyncWebServer/.travis.yml deleted file mode 100644 index e1b70352..00000000 --- a/lib/ESPAsyncWebServer/.travis.yml +++ /dev/null @@ -1,46 +0,0 @@ -sudo: false - -language: python - -os: - - linux - -git: - depth: false - -stages: - - build - -jobs: - include: - - - name: "Build Arduino ESP32" - if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) - stage: build - script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp32 - - - name: "Build Arduino ESP8266" - if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) - stage: build - script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp8266 - - - name: "Build Platformio ESP32" - if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) - stage: build - script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp32 1 1 - - - name: "Build Platformio ESP8266" - if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) - stage: build - script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh esp8266 1 1 - -notifications: - email: - on_success: change - on_failure: change - webhooks: - urls: - - https://webhooks.gitter.im/e/60e65d0c78ea0a920347 - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: never # options: [always|never|change] default: always diff --git a/lib/ESPAsyncWebServer/CMakeLists.txt b/lib/ESPAsyncWebServer/CMakeLists.txt deleted file mode 100644 index 64292eca..00000000 --- a/lib/ESPAsyncWebServer/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(COMPONENT_SRCDIRS - "src" -) - -set(COMPONENT_ADD_INCLUDEDIRS - "src" -) - -set(COMPONENT_REQUIRES - "arduino-esp32" - "AsyncTCP" -) - -register_component() - -target_compile_definitions(${COMPONENT_TARGET} PUBLIC -DESP32) -target_compile_options(${COMPONENT_TARGET} PRIVATE -fno-rtti) diff --git a/lib/ESPAsyncWebServer/README.md b/lib/ESPAsyncWebServer/README.md deleted file mode 100644 index d6dd3206..00000000 --- a/lib/ESPAsyncWebServer/README.md +++ /dev/null @@ -1,1521 +0,0 @@ -# ESPAsyncWebServer -[![Build Status](https://travis-ci.org/me-no-dev/ESPAsyncWebServer.svg?branch=master)](https://travis-ci.org/me-no-dev/ESPAsyncWebServer) ![](https://github.com/me-no-dev/ESPAsyncWebServer/workflows/ESP%20Async%20Web%20Server%20CI/badge.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/395dd42cfc674e6ca2e326af3af80ffc)](https://www.codacy.com/manual/me-no-dev/ESPAsyncWebServer?utm_source=github.com&utm_medium=referral&utm_content=me-no-dev/ESPAsyncWebServer&utm_campaign=Badge_Grade) - -For help and support [![Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer](https://badges.gitter.im/me-no-dev/ESPAsyncWebServer.svg)](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -Async HTTP and WebSocket Server for ESP8266 Arduino - -For ESP8266 it requires [ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) -To use this library you might need to have the latest git versions of [ESP8266](https://github.com/esp8266/Arduino) Arduino Core - -For ESP32 it requires [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) to work -To use this library you might need to have the latest git versions of [ESP32](https://github.com/espressif/arduino-esp32) Arduino Core - -## Table of contents -- [ESPAsyncWebServer](#espasyncwebserver) - - [Table of contents](#table-of-contents) - - [Installation](#installation) - - [Using PlatformIO](#using-platformio) - - [Why should you care](#why-should-you-care) - - [Important things to remember](#important-things-to-remember) - - [Principles of operation](#principles-of-operation) - - [The Async Web server](#the-async-web-server) - - [Request Life Cycle](#request-life-cycle) - - [Rewrites and how do they work](#rewrites-and-how-do-they-work) - - [Handlers and how do they work](#handlers-and-how-do-they-work) - - [Responses and how do they work](#responses-and-how-do-they-work) - - [Template processing](#template-processing) - - [Libraries and projects that use AsyncWebServer](#libraries-and-projects-that-use-asyncwebserver) - - [Request Variables](#request-variables) - - [Common Variables](#common-variables) - - [Headers](#headers) - - [GET, POST and FILE parameters](#get-post-and-file-parameters) - - [FILE Upload handling](#file-upload-handling) - - [Body data handling](#body-data-handling) - - [JSON body handling with ArduinoJson](#json-body-handling-with-arduinojson) - - [Responses](#responses) - - [Redirect to another URL](#redirect-to-another-url) - - [Basic response with HTTP Code](#basic-response-with-http-code) - - [Basic response with HTTP Code and extra headers](#basic-response-with-http-code-and-extra-headers) - - [Basic response with string content](#basic-response-with-string-content) - - [Basic response with string content and extra headers](#basic-response-with-string-content-and-extra-headers) - - [Send large webpage from PROGMEM](#send-large-webpage-from-progmem) - - [Send large webpage from PROGMEM and extra headers](#send-large-webpage-from-progmem-and-extra-headers) - - [Send large webpage from PROGMEM containing templates](#send-large-webpage-from-progmem-containing-templates) - - [Send large webpage from PROGMEM containing templates and extra headers](#send-large-webpage-from-progmem-containing-templates-and-extra-headers) - - [Send binary content from PROGMEM](#send-binary-content-from-progmem) - - [Respond with content coming from a Stream](#respond-with-content-coming-from-a-stream) - - [Respond with content coming from a Stream and extra headers](#respond-with-content-coming-from-a-stream-and-extra-headers) - - [Respond with content coming from a Stream containing templates](#respond-with-content-coming-from-a-stream-containing-templates) - - [Respond with content coming from a Stream containing templates and extra headers](#respond-with-content-coming-from-a-stream-containing-templates-and-extra-headers) - - [Respond with content coming from a File](#respond-with-content-coming-from-a-file) - - [Respond with content coming from a File and extra headers](#respond-with-content-coming-from-a-file-and-extra-headers) - - [Respond with content coming from a File containing templates](#respond-with-content-coming-from-a-file-containing-templates) - - [Respond with content using a callback](#respond-with-content-using-a-callback) - - [Respond with content using a callback and extra headers](#respond-with-content-using-a-callback-and-extra-headers) - - [Respond with content using a callback containing templates](#respond-with-content-using-a-callback-containing-templates) - - [Respond with content using a callback containing templates and extra headers](#respond-with-content-using-a-callback-containing-templates-and-extra-headers) - - [Chunked Response](#chunked-response) - - [Chunked Response containing templates](#chunked-response-containing-templates) - - [Print to response](#print-to-response) - - [ArduinoJson Basic Response](#arduinojson-basic-response) - - [ArduinoJson Advanced Response](#arduinojson-advanced-response) - - [Serving static files](#serving-static-files) - - [Serving specific file by name](#serving-specific-file-by-name) - - [Serving files in directory](#serving-files-in-directory) - - [Serving static files with authentication](#serving-static-files-with-authentication) - - [Specifying Cache-Control header](#specifying-cache-control-header) - - [Specifying Date-Modified header](#specifying-date-modified-header) - - [Specifying Template Processor callback](#specifying-template-processor-callback) - - [Param Rewrite With Matching](#param-rewrite-with-matching) - - [Using filters](#using-filters) - - [Serve different site files in AP mode](#serve-different-site-files-in-ap-mode) - - [Rewrite to different index on AP](#rewrite-to-different-index-on-ap) - - [Serving different hosts](#serving-different-hosts) - - [Determine interface inside callbacks](#determine-interface-inside-callbacks) - - [Bad Responses](#bad-responses) - - [Respond with content using a callback without content length to HTTP/1.0 clients](#respond-with-content-using-a-callback-without-content-length-to-http10-clients) - - [Async WebSocket Plugin](#async-websocket-plugin) - - [Async WebSocket Event](#async-websocket-event) - - [Methods for sending data to a socket client](#methods-for-sending-data-to-a-socket-client) - - [Direct access to web socket message buffer](#direct-access-to-web-socket-message-buffer) - - [Limiting the number of web socket clients](#limiting-the-number-of-web-socket-clients) - - [Async Event Source Plugin](#async-event-source-plugin) - - [Setup Event Source on the server](#setup-event-source-on-the-server) - - [Setup Event Source in the browser](#setup-event-source-in-the-browser) - - [Scanning for available WiFi Networks](#scanning-for-available-wifi-networks) - - [Remove handlers and rewrites](#remove-handlers-and-rewrites) - - [Setting up the server](#setting-up-the-server) - - [Setup global and class functions as request handlers](#setup-global-and-class-functions-as-request-handlers) - - [Methods for controlling websocket connections](#methods-for-controlling-websocket-connections) - - [Adding Default Headers](#adding-default-headers) - - [Path variable](#path-variable) - -## Installation - -### Using PlatformIO - -[PlatformIO](http://platformio.org) is an open source ecosystem for IoT development with cross platform build system, library manager and full support for Espressif ESP8266/ESP32 development. It works on the popular host OS: Mac OS X, Windows, Linux 32/64, Linux ARM (like Raspberry Pi, BeagleBone, CubieBoard). - -1. Install [PlatformIO IDE](http://platformio.org/platformio-ide) -2. Create new project using "PlatformIO Home > New Project" -3. Update dev/platform to staging version: - - [Instruction for Espressif 8266](http://docs.platformio.org/en/latest/platforms/espressif8266.html#using-arduino-framework-with-staging-version) - - [Instruction for Espressif 32](http://docs.platformio.org/en/latest/platforms/espressif32.html#using-arduino-framework-with-staging-version) - 4. Add "ESP Async WebServer" to project using [Project Configuration File `platformio.ini`](http://docs.platformio.org/page/projectconf.html) and [lib_deps](http://docs.platformio.org/page/projectconf/section_env_library.html#lib-deps) option: - -```ini -[env:myboard] -platform = espressif... -board = ... -framework = arduino - -# using the latest stable version -lib_deps = ESP Async WebServer - -# or using GIT Url (the latest development version) -lib_deps = https://github.com/me-no-dev/ESPAsyncWebServer.git -``` - 5. Happy coding with PlatformIO! - -## Why should you care -- Using asynchronous network means that you can handle more than one connection at the same time -- You are called once the request is ready and parsed -- When you send the response, you are immediately ready to handle other connections - while the server is taking care of sending the response in the background -- Speed is OMG -- Easy to use API, HTTP Basic and Digest MD5 Authentication (default), ChunkedResponse -- Easily extendible to handle any type of content -- Supports Continue 100 -- Async WebSocket plugin offering different locations without extra servers or ports -- Async EventSource (Server-Sent Events) plugin to send events to the browser -- URL Rewrite plugin for conditional and permanent url rewrites -- ServeStatic plugin that supports cache, Last-Modified, default index and more -- Simple template processing engine to handle templates - -## Important things to remember -- This is fully asynchronous server and as such does not run on the loop thread. -- You can not use yield or delay or any function that uses them inside the callbacks -- The server is smart enough to know when to close the connection and free resources -- You can not send more than one response to a single request - -## Principles of operation - -### The Async Web server -- Listens for connections -- Wraps the new clients into ```Request``` -- Keeps track of clients and cleans memory -- Manages ```Rewrites``` and apply them on the request url -- Manages ```Handlers``` and attaches them to Requests - -### Request Life Cycle -- TCP connection is received by the server -- The connection is wrapped inside ```Request``` object -- When the request head is received (type, url, get params, http version and host), - the server goes through all ```Rewrites``` (in the order they were added) to rewrite the url and inject query parameters, - next, it goes through all attached ```Handlers```(in the order they were added) trying to find one - that ```canHandle``` the given request. If none are found, the default(catch-all) handler is attached. -- The rest of the request is received, calling the ```handleUpload``` or ```handleBody``` methods of the ```Handler``` if they are needed (POST+File/Body) -- When the whole request is parsed, the result is given to the ```handleRequest``` method of the ```Handler``` and is ready to be responded to -- In the ```handleRequest``` method, to the ```Request``` is attached a ```Response``` object (see below) that will serve the response data back to the client -- When the ```Response``` is sent, the client is closed and freed from the memory - -### Rewrites and how do they work -- The ```Rewrites``` are used to rewrite the request url and/or inject get parameters for a specific request url path. -- All ```Rewrites``` are evaluated on the request in the order they have been added to the server. -- The ```Rewrite``` will change the request url only if the request url (excluding get parameters) is fully match - the rewrite url, and when the optional ```Filter``` callback return true. -- Setting a ```Filter``` to the ```Rewrite``` enables to control when to apply the rewrite, decision can be based on - request url, http version, request host/port/target host, get parameters or the request client's localIP or remoteIP. -- Two filter callbacks are provided: ```ON_AP_FILTER``` to execute the rewrite when request is made to the AP interface, - ```ON_STA_FILTER``` to execute the rewrite when request is made to the STA interface. -- The ```Rewrite``` can specify a target url with optional get parameters, e.g. ```/to-url?with=params``` - -### Handlers and how do they work -- The ```Handlers``` are used for executing specific actions to particular requests -- One ```Handler``` instance can be attached to any request and lives together with the server -- Setting a ```Filter``` to the ```Handler``` enables to control when to apply the handler, decision can be based on - request url, http version, request host/port/target host, get parameters or the request client's localIP or remoteIP. -- Two filter callbacks are provided: ```ON_AP_FILTER``` to execute the rewrite when request is made to the AP interface, - ```ON_STA_FILTER``` to execute the rewrite when request is made to the STA interface. -- The ```canHandle``` method is used for handler specific control on whether the requests can be handled - and for declaring any interesting headers that the ```Request``` should parse. Decision can be based on request - method, request url, http version, request host/port/target host and get parameters -- Once a ```Handler``` is attached to given ```Request``` (```canHandle``` returned true) - that ```Handler``` takes care to receive any file/data upload and attach a ```Response``` - once the ```Request``` has been fully parsed -- ```Handlers``` are evaluated in the order they are attached to the server. The ```canHandle``` is called only - if the ```Filter``` that was set to the ```Handler``` return true. -- The first ```Handler``` that can handle the request is selected, not further ```Filter``` and ```canHandle``` are called. - -### Responses and how do they work -- The ```Response``` objects are used to send the response data back to the client -- The ```Response``` object lives with the ```Request``` and is freed on end or disconnect -- Different techniques are used depending on the response type to send the data in packets - returning back almost immediately and sending the next packet when this one is received. - Any time in between is spent to run the user loop and handle other network packets -- Responding asynchronously is probably the most difficult thing for most to understand -- Many different options exist for the user to make responding a background task - -### Template processing -- ESPAsyncWebserver contains simple template processing engine. -- Template processing can be added to most response types. -- Currently it supports only replacing template placeholders with actual values. No conditional processing, cycles, etc. -- Placeholders are delimited with ```%``` symbols. Like this: ```%TEMPLATE_PLACEHOLDER%```. -- It works by extracting placeholder name from response text and passing it to user provided function which should return actual value to be used instead of placeholder. -- Since it's user provided function, it is possible for library users to implement conditional processing and cycles themselves. -- Since it's impossible to know the actual response size after template processing step in advance (and, therefore, to include it in response headers), the response becomes [chunked](#chunked-response). - -## Libraries and projects that use AsyncWebServer -- [WebSocketToSerial](https://github.com/hallard/WebSocketToSerial) - Debug serial devices through the web browser -- [Sattrack](https://github.com/Hopperpop/Sattrack) - Track the ISS with ESP8266 -- [ESP Radio](https://github.com/Edzelf/Esp-radio) - Icecast radio based on ESP8266 and VS1053 -- [VZero](https://github.com/andig/vzero) - the Wireless zero-config controller for volkszaehler.org -- [ESPurna](https://bitbucket.org/xoseperez/espurna) - ESPurna ("spark" in Catalan) is a custom C firmware for ESP8266 based smart switches. It was originally developed with the ITead Sonoff in mind. -- [fauxmoESP](https://bitbucket.org/xoseperez/fauxmoesp) - Belkin WeMo emulator library for ESP8266. -- [ESP-RFID](https://github.com/omersiar/esp-rfid) - MFRC522 RFID Access Control Management project for ESP8266. - -## Request Variables - -### Common Variables -```cpp -request->version(); // uint8_t: 0 = HTTP/1.0, 1 = HTTP/1.1 -request->method(); // enum: HTTP_GET, HTTP_POST, HTTP_DELETE, HTTP_PUT, HTTP_PATCH, HTTP_HEAD, HTTP_OPTIONS -request->url(); // String: URL of the request (not including host, port or GET parameters) -request->host(); // String: The requested host (can be used for virtual hosting) -request->contentType(); // String: ContentType of the request (not avaiable in Handler::canHandle) -request->contentLength(); // size_t: ContentLength of the request (not avaiable in Handler::canHandle) -request->multipart(); // bool: True if the request has content type "multipart" -``` - -### Headers -```cpp -//List all collected headers -int headers = request->headers(); -int i; -for(i=0;igetHeader(i); - Serial.printf("HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); -} - -//get specific header by name -if(request->hasHeader("MyHeader")){ - AsyncWebHeader* h = request->getHeader("MyHeader"); - Serial.printf("MyHeader: %s\n", h->value().c_str()); -} - -//List all collected headers (Compatibility) -int headers = request->headers(); -int i; -for(i=0;iheaderName(i).c_str(), request->header(i).c_str()); -} - -//get specific header by name (Compatibility) -if(request->hasHeader("MyHeader")){ - Serial.printf("MyHeader: %s\n", request->header("MyHeader").c_str()); -} -``` - -### GET, POST and FILE parameters -```cpp -//List all parameters -int params = request->params(); -for(int i=0;igetParam(i); - if(p->isFile()){ //p->isPost() is also true - Serial.printf("FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); - } else if(p->isPost()){ - Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); - } else { - Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); - } -} - -//Check if GET parameter exists -if(request->hasParam("download")) - AsyncWebParameter* p = request->getParam("download"); - -//Check if POST (but not File) parameter exists -if(request->hasParam("download", true)) - AsyncWebParameter* p = request->getParam("download", true); - -//Check if FILE was uploaded -if(request->hasParam("download", true, true)) - AsyncWebParameter* p = request->getParam("download", true, true); - -//List all parameters (Compatibility) -int args = request->args(); -for(int i=0;iargName(i).c_str(), request->arg(i).c_str()); -} - -//Check if parameter exists (Compatibility) -if(request->hasArg("download")) - String arg = request->arg("download"); -``` - -### FILE Upload handling -```cpp -void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ - if(!index){ - Serial.printf("UploadStart: %s\n", filename.c_str()); - } - for(size_t i=0; i(); - // ... -}); -server.addHandler(handler); -``` - -## Responses -### Redirect to another URL -```cpp -//to local url -request->redirect("/login"); - -//to external url -request->redirect("http://esp8266.com"); -``` - -### Basic response with HTTP Code -```cpp -request->send(404); //Sends 404 File Not Found -``` - -### Basic response with HTTP Code and extra headers -```cpp -AsyncWebServerResponse *response = request->beginResponse(404); //Sends 404 File Not Found -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Basic response with string content -```cpp -request->send(200, "text/plain", "Hello World!"); -``` - -### Basic response with string content and extra headers -```cpp -AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", "Hello World!"); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Send large webpage from PROGMEM -```cpp -const char index_html[] PROGMEM = "..."; // large char array, tested with 14k -request->send_P(200, "text/html", index_html); -``` - -### Send large webpage from PROGMEM and extra headers -```cpp -const char index_html[] PROGMEM = "..."; // large char array, tested with 14k -AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Send large webpage from PROGMEM containing templates -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -const char index_html[] PROGMEM = "..."; // large char array, tested with 14k -request->send_P(200, "text/html", index_html, processor); -``` - -### Send large webpage from PROGMEM containing templates and extra headers -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -const char index_html[] PROGMEM = "..."; // large char array, tested with 14k -AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html, processor); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Send binary content from PROGMEM -```cpp - -//File: favicon.ico.gz, Size: 726 -#define favicon_ico_gz_len 726 -const uint8_t favicon_ico_gz[] PROGMEM = { - 0x1F, 0x8B, 0x08, 0x08, 0x0B, 0x87, 0x90, 0x57, 0x00, 0x03, 0x66, 0x61, 0x76, 0x69, 0x63, 0x6F, - 0x6E, 0x2E, 0x69, 0x63, 0x6F, 0x00, 0xCD, 0x53, 0x5F, 0x48, 0x9A, 0x51, 0x14, 0xBF, 0x62, 0x6D, - 0x86, 0x96, 0xA9, 0x64, 0xD3, 0xFE, 0xA8, 0x99, 0x65, 0x1A, 0xB4, 0x8A, 0xA8, 0x51, 0x54, 0x23, - 0xA8, 0x11, 0x49, 0x51, 0x8A, 0x34, 0x62, 0x93, 0x85, 0x31, 0x58, 0x44, 0x12, 0x45, 0x2D, 0x58, - 0xF5, 0x52, 0x41, 0x10, 0x23, 0x82, 0xA0, 0x20, 0x98, 0x2F, 0xC1, 0x26, 0xED, 0xA1, 0x20, 0x89, - 0x04, 0xD7, 0x83, 0x58, 0x20, 0x28, 0x04, 0xAB, 0xD1, 0x9B, 0x8C, 0xE5, 0xC3, 0x60, 0x32, 0x64, - 0x0E, 0x56, 0xBF, 0x9D, 0xEF, 0xF6, 0x30, 0x82, 0xED, 0xAD, 0x87, 0xDD, 0x8F, 0xF3, 0xDD, 0x8F, - 0x73, 0xCF, 0xEF, 0x9C, 0xDF, 0x39, 0xBF, 0xFB, 0x31, 0x26, 0xA2, 0x27, 0x37, 0x97, 0xD1, 0x5B, - 0xCF, 0x9E, 0x67, 0x30, 0xA6, 0x66, 0x8C, 0x99, 0xC9, 0xC8, 0x45, 0x9E, 0x6B, 0x3F, 0x5F, 0x74, - 0xA6, 0x94, 0x5E, 0xDB, 0xFF, 0xB2, 0xE6, 0xE7, 0xE7, 0xF9, 0xDE, 0xD6, 0xD6, 0x96, 0xDB, 0xD8, - 0xD8, 0x78, 0xBF, 0xA1, 0xA1, 0xC1, 0xDA, 0xDC, 0xDC, 0x2C, 0xEB, 0xED, 0xED, 0x15, 0x9B, 0xCD, - 0xE6, 0x4A, 0x83, 0xC1, 0xE0, 0x2E, 0x29, 0x29, 0x99, 0xD6, 0x6A, 0xB5, 0x4F, 0x75, 0x3A, 0x9D, - 0x61, 0x75, 0x75, 0x95, 0xB5, 0xB7, 0xB7, 0xDF, 0xC8, 0xD1, 0xD4, 0xD4, 0xF4, 0xB0, 0xBA, 0xBA, - 0xFA, 0x83, 0xD5, 0x6A, 0xFD, 0x5A, 0x5E, 0x5E, 0x9E, 0x28, 0x2D, 0x2D, 0x0D, 0x10, 0xC6, 0x4B, - 0x98, 0x78, 0x5E, 0x5E, 0xDE, 0x95, 0x42, 0xA1, 0x40, 0x4E, 0x4E, 0xCE, 0x65, 0x76, 0x76, 0xF6, - 0x47, 0xB5, 0x5A, 0x6D, 0x4F, 0x26, 0x93, 0xA2, 0xD6, 0xD6, 0x56, 0x8E, 0x6D, 0x69, 0x69, 0xD1, - 0x11, 0x36, 0x62, 0xB1, 0x58, 0x60, 0x32, 0x99, 0xA0, 0xD7, 0xEB, 0x51, 0x58, 0x58, 0x88, 0xFC, - 0xFC, 0x7C, 0x10, 0x16, 0x02, 0x56, 0x2E, 0x97, 0x43, 0x2A, 0x95, 0x42, 0x2C, 0x16, 0x23, 0x33, - 0x33, 0x33, 0xAE, 0x52, 0xA9, 0x1E, 0x64, 0x65, 0x65, 0x71, 0x7C, 0x7D, 0x7D, 0xBD, 0x93, 0xEA, - 0xFE, 0x30, 0x1A, 0x8D, 0xE8, 0xEC, 0xEC, 0xC4, 0xE2, 0xE2, 0x22, 0x6A, 0x6A, 0x6A, 0x40, 0x39, - 0x41, 0xB5, 0x38, 0x4E, 0xC8, 0x33, 0x3C, 0x3C, 0x0C, 0x87, 0xC3, 0xC1, 0x6B, 0x54, 0x54, 0x54, - 0xBC, 0xE9, 0xEB, 0xEB, 0x93, 0x5F, 0x5C, 0x5C, 0x30, 0x8A, 0x9D, 0x2E, 0x2B, 0x2B, 0xBB, 0xA2, - 0x3E, 0x41, 0xBD, 0x21, 0x1E, 0x8F, 0x63, 0x6A, 0x6A, 0x0A, 0x81, 0x40, 0x00, 0x94, 0x1B, 0x3D, - 0x3D, 0x3D, 0x42, 0x3C, 0x96, 0x96, 0x96, 0x70, 0x7E, 0x7E, 0x8E, 0xE3, 0xE3, 0x63, 0xF8, 0xFD, - 0xFE, 0xB4, 0xD7, 0xEB, 0xF5, 0x8F, 0x8F, 0x8F, 0x5B, 0x68, 0x5E, 0x6F, 0x05, 0xCE, 0xB4, 0xE3, - 0xE8, 0xE8, 0x08, 0x27, 0x27, 0x27, 0xD8, 0xDF, 0xDF, 0xC7, 0xD9, 0xD9, 0x19, 0x6C, 0x36, 0x1B, - 0x36, 0x36, 0x36, 0x38, 0x9F, 0x85, 0x85, 0x05, 0xAC, 0xAF, 0xAF, 0x23, 0x1A, 0x8D, 0x22, 0x91, - 0x48, 0x20, 0x16, 0x8B, 0xFD, 0xDA, 0xDA, 0xDA, 0x7A, 0x41, 0x33, 0x7E, 0x57, 0x50, 0x50, 0x80, - 0x89, 0x89, 0x09, 0x84, 0xC3, 0x61, 0x6C, 0x6F, 0x6F, 0x23, 0x12, 0x89, 0xE0, 0xE0, 0xE0, 0x00, - 0x43, 0x43, 0x43, 0x58, 0x5E, 0x5E, 0xE6, 0x9C, 0x7D, 0x3E, 0x1F, 0x46, 0x47, 0x47, 0x79, 0xBE, - 0xBD, 0xBD, 0x3D, 0xE1, 0x3C, 0x1D, 0x0C, 0x06, 0x9F, 0x10, 0xB7, 0xC7, 0x84, 0x4F, 0xF6, 0xF7, - 0xF7, 0x63, 0x60, 0x60, 0x00, 0x83, 0x83, 0x83, 0x18, 0x19, 0x19, 0xC1, 0xDC, 0xDC, 0x1C, 0x8F, - 0x17, 0x7C, 0xA4, 0x27, 0xE7, 0x34, 0x39, 0x39, 0x89, 0x9D, 0x9D, 0x1D, 0x6E, 0x54, 0xE3, 0x13, - 0xE5, 0x34, 0x11, 0x37, 0x49, 0x51, 0x51, 0xD1, 0x4B, 0xA5, 0x52, 0xF9, 0x45, 0x26, 0x93, 0x5D, - 0x0A, 0xF3, 0x92, 0x48, 0x24, 0xA0, 0x6F, 0x14, 0x17, 0x17, 0xA3, 0xB6, 0xB6, 0x16, 0x5D, 0x5D, - 0x5D, 0x7C, 0x1E, 0xBB, 0xBB, 0xBB, 0x9C, 0xD7, 0xE1, 0xE1, 0x21, 0x42, 0xA1, 0xD0, 0x6B, 0xD2, - 0x45, 0x4C, 0x33, 0x12, 0x34, 0xCC, 0xA0, 0x19, 0x54, 0x92, 0x56, 0x0E, 0xD2, 0xD9, 0x43, 0xF8, - 0xCF, 0x82, 0x56, 0xC2, 0xDC, 0xEB, 0xEA, 0xEA, 0x38, 0x7E, 0x6C, 0x6C, 0x4C, 0xE0, 0xFE, 0x9D, - 0xB8, 0xBF, 0xA7, 0xFA, 0xAF, 0x56, 0x56, 0x56, 0xEE, 0x6D, 0x6E, 0x6E, 0xDE, 0xB8, 0x47, 0x55, - 0x55, 0x55, 0x6C, 0x66, 0x66, 0x46, 0x44, 0xDA, 0x3B, 0x34, 0x1A, 0x4D, 0x94, 0xB0, 0x3F, 0x09, - 0x7B, 0x45, 0xBD, 0xA5, 0x5D, 0x2E, 0x57, 0x8C, 0x7A, 0x73, 0xD9, 0xED, 0xF6, 0x3B, 0x84, 0xFF, - 0xE7, 0x7D, 0xA6, 0x3A, 0x2C, 0x95, 0x4A, 0xB1, 0x8E, 0x8E, 0x0E, 0x6D, 0x77, 0x77, 0xB7, 0xCD, - 0xE9, 0x74, 0x3E, 0x73, 0xBB, 0xDD, 0x8F, 0x3C, 0x1E, 0x8F, 0xE6, 0xF4, 0xF4, 0x94, 0xAD, 0xAD, - 0xAD, 0xDD, 0xDE, 0xCF, 0x73, 0x0B, 0x0B, 0xB8, 0xB6, 0xE0, 0x5D, 0xC6, 0x66, 0xC5, 0xE4, 0x10, - 0x4C, 0xF4, 0xF7, 0xD8, 0x59, 0xF2, 0x7F, 0xA3, 0xB8, 0xB4, 0xFC, 0x0F, 0xEE, 0x37, 0x70, 0xEC, - 0x16, 0x4A, 0x7E, 0x04, 0x00, 0x00 -}; - -AsyncWebServerResponse *response = request->beginResponse_P(200, "image/x-icon", favicon_ico_gz, favicon_ico_gz_len); -response->addHeader("Content-Encoding", "gzip"); -request->send(response); -``` - -### Respond with content coming from a Stream -```cpp -//read 12 bytes from Serial and send them as Content Type text/plain -request->send(Serial, "text/plain", 12); -``` - -### Respond with content coming from a Stream and extra headers -```cpp -//read 12 bytes from Serial and send them as Content Type text/plain -AsyncWebServerResponse *response = request->beginResponse(Serial, "text/plain", 12); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Respond with content coming from a Stream containing templates -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -//read 12 bytes from Serial and send them as Content Type text/plain -request->send(Serial, "text/plain", 12, processor); -``` - -### Respond with content coming from a Stream containing templates and extra headers -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -//read 12 bytes from Serial and send them as Content Type text/plain -AsyncWebServerResponse *response = request->beginResponse(Serial, "text/plain", 12, processor); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Respond with content coming from a File -```cpp -//Send index.htm with default content type -request->send(SPIFFS, "/index.htm"); - -//Send index.htm as text -request->send(SPIFFS, "/index.htm", "text/plain"); - -//Download index.htm -request->send(SPIFFS, "/index.htm", String(), true); -``` - -### Respond with content coming from a File and extra headers -```cpp -//Send index.htm with default content type -AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm"); - -//Send index.htm as text -AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", "text/plain"); - -//Download index.htm -AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.htm", String(), true); - -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Respond with content coming from a File containing templates -Internally uses [Chunked Response](#chunked-response). - -Index.htm contents: -``` -%HELLO_FROM_TEMPLATE% -``` - -Somewhere in source files: -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -//Send index.htm with template processor function -request->send(SPIFFS, "/index.htm", String(), false, processor); -``` - -### Respond with content using a callback -```cpp -//send 128 bytes as plain text -request->send("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - //Write up to "maxLen" bytes into "buffer" and return the amount written. - //index equals the amount of bytes that have been already sent - //You will not be asked for more bytes once the content length has been reached. - //Keep in mind that you can not delay or yield waiting for more data! - //Send what you currently have and you will be asked for more again - return mySource.read(buffer, maxLen); -}); -``` - -### Respond with content using a callback and extra headers -```cpp -//send 128 bytes as plain text -AsyncWebServerResponse *response = request->beginResponse("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - //Write up to "maxLen" bytes into "buffer" and return the amount written. - //index equals the amount of bytes that have been already sent - //You will not be asked for more bytes once the content length has been reached. - //Keep in mind that you can not delay or yield waiting for more data! - //Send what you currently have and you will be asked for more again - return mySource.read(buffer, maxLen); -}); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Respond with content using a callback containing templates -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -//send 128 bytes as plain text -request->send("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - //Write up to "maxLen" bytes into "buffer" and return the amount written. - //index equals the amount of bytes that have been already sent - //You will not be asked for more bytes once the content length has been reached. - //Keep in mind that you can not delay or yield waiting for more data! - //Send what you currently have and you will be asked for more again - return mySource.read(buffer, maxLen); -}, processor); -``` - -### Respond with content using a callback containing templates and extra headers -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -//send 128 bytes as plain text -AsyncWebServerResponse *response = request->beginResponse("text/plain", 128, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - //Write up to "maxLen" bytes into "buffer" and return the amount written. - //index equals the amount of bytes that have been already sent - //You will not be asked for more bytes once the content length has been reached. - //Keep in mind that you can not delay or yield waiting for more data! - //Send what you currently have and you will be asked for more again - return mySource.read(buffer, maxLen); -}, processor); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Chunked Response -Used when content length is unknown. Works best if the client supports HTTP/1.1 -```cpp -AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - //Write up to "maxLen" bytes into "buffer" and return the amount written. - //index equals the amount of bytes that have been already sent - //You will be asked for more data until 0 is returned - //Keep in mind that you can not delay or yield waiting for more data! - return mySource.read(buffer, maxLen); -}); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Chunked Response containing templates -Used when content length is unknown. Works best if the client supports HTTP/1.1 -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -AsyncWebServerResponse *response = request->beginChunkedResponse("text/plain", [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - //Write up to "maxLen" bytes into "buffer" and return the amount written. - //index equals the amount of bytes that have been already sent - //You will be asked for more data until 0 is returned - //Keep in mind that you can not delay or yield waiting for more data! - return mySource.read(buffer, maxLen); -}, processor); -response->addHeader("Server","ESP Async Web Server"); -request->send(response); -``` - -### Print to response -```cpp -AsyncResponseStream *response = request->beginResponseStream("text/html"); -response->addHeader("Server","ESP Async Web Server"); -response->printf("Webpage at %s", request->url().c_str()); - -response->print("

Hello "); -response->print(request->client()->remoteIP()); -response->print("

"); - -response->print("

General

"); -response->print("
    "); -response->printf("
  • Version: HTTP/1.%u
  • ", request->version()); -response->printf("
  • Method: %s
  • ", request->methodToString()); -response->printf("
  • URL: %s
  • ", request->url().c_str()); -response->printf("
  • Host: %s
  • ", request->host().c_str()); -response->printf("
  • ContentType: %s
  • ", request->contentType().c_str()); -response->printf("
  • ContentLength: %u
  • ", request->contentLength()); -response->printf("
  • Multipart: %s
  • ", request->multipart()?"true":"false"); -response->print("
"); - -response->print("

Headers

"); -response->print("
    "); -int headers = request->headers(); -for(int i=0;igetHeader(i); - response->printf("
  • %s: %s
  • ", h->name().c_str(), h->value().c_str()); -} -response->print("
"); - -response->print("

Parameters

"); -response->print("
    "); -int params = request->params(); -for(int i=0;igetParam(i); - if(p->isFile()){ - response->printf("
  • FILE[%s]: %s, size: %u
  • ", p->name().c_str(), p->value().c_str(), p->size()); - } else if(p->isPost()){ - response->printf("
  • POST[%s]: %s
  • ", p->name().c_str(), p->value().c_str()); - } else { - response->printf("
  • GET[%s]: %s
  • ", p->name().c_str(), p->value().c_str()); - } -} -response->print("
"); - -response->print(""); -//send the response last -request->send(response); -``` - -### ArduinoJson Basic Response -This way of sending Json is great for when the result is below 4KB -```cpp -#include "AsyncJson.h" -#include "ArduinoJson.h" - - -AsyncResponseStream *response = request->beginResponseStream("application/json"); -DynamicJsonBuffer jsonBuffer; -JsonObject &root = jsonBuffer.createObject(); -root["heap"] = ESP.getFreeHeap(); -root["ssid"] = WiFi.SSID(); -root.printTo(*response); -request->send(response); -``` - -### ArduinoJson Advanced Response -This response can handle really large Json objects (tested to 40KB) -There isn't any noticeable speed decrease for small results with the method above -Since ArduinoJson does not allow reading parts of the string, the whole Json has to -be passed every time a chunks needs to be sent, which shows speed decrease proportional -to the resulting json packets -```cpp -#include "AsyncJson.h" -#include "ArduinoJson.h" - - -AsyncJsonResponse * response = new AsyncJsonResponse(); -response->addHeader("Server","ESP Async Web Server"); -JsonObject& root = response->getRoot(); -root["heap"] = ESP.getFreeHeap(); -root["ssid"] = WiFi.SSID(); -response->setLength(); -request->send(response); -``` - -## Serving static files -In addition to serving files from SPIFFS as described above, the server provide a dedicated handler that optimize the -performance of serving files from SPIFFS - ```AsyncStaticWebHandler```. Use ```server.serveStatic()``` function to -initialize and add a new instance of ```AsyncStaticWebHandler``` to the server. -The Handler will not handle the request if the file does not exists, e.g. the server will continue to look for another -handler that can handle the request. -Notice that you can chain setter functions to setup the handler, or keep a pointer to change it at a later time. - -### Serving specific file by name -```cpp -// Serve the file "/www/page.htm" when request url is "/page.htm" -server.serveStatic("/page.htm", SPIFFS, "/www/page.htm"); -``` - -### Serving files in directory -To serve files in a directory, the path to the files should specify a directory in SPIFFS and ends with "/". -```cpp -// Serve files in directory "/www/" when request url starts with "/" -// Request to the root or none existing files will try to server the defualt -// file name "index.htm" if exists -server.serveStatic("/", SPIFFS, "/www/"); - -// Server with different default file -server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("default.html"); -``` - -### Serving static files with authentication - -```cpp -server - .serveStatic("/", SPIFFS, "/www/") - .setDefaultFile("default.html") - .setAuthentication("user", "pass"); -``` - -### Specifying Cache-Control header -It is possible to specify Cache-Control header value to reduce the number of calls to the server once the client loaded -the files. For more information on Cache-Control values see [Cache-Control](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) -```cpp -// Cache responses for 10 minutes (600 seconds) -server.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=600"); - -//*** Change Cache-Control after server setup *** - -// During setup - keep a pointer to the handler -AsyncStaticWebHandler* handler = &server.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=600"); - -// At a later event - change Cache-Control -handler->setCacheControl("max-age=30"); -``` - -### Specifying Date-Modified header -It is possible to specify Date-Modified header to enable the server to return Not-Modified (304) response for requests -with "If-Modified-Since" header with the same value, instead of responding with the actual file content. -```cpp -// Update the date modified string every time files are updated -server.serveStatic("/", SPIFFS, "/www/").setLastModified("Mon, 20 Jun 2016 14:00:00 GMT"); - -//*** Chage last modified value at a later stage *** - -// During setup - read last modified value from config or EEPROM -String date_modified = loadDateModified(); -AsyncStaticWebHandler* handler = &server.serveStatic("/", SPIFFS, "/www/"); -handler->setLastModified(date_modified); - -// At a later event when files are updated -String date_modified = getNewDateModfied(); -saveDateModified(date_modified); // Save for next reset -handler->setLastModified(date_modified); -``` - -### Specifying Template Processor callback -It is possible to specify template processor for static files. For information on template processor see -[Respond with content coming from a File containing templates](#respond-with-content-coming-from-a-file-containing-templates). -```cpp -String processor(const String& var) -{ - if(var == "HELLO_FROM_TEMPLATE") - return F("Hello world!"); - return String(); -} - -// ... - -server.serveStatic("/", SPIFFS, "/www/").setTemplateProcessor(processor); -``` - -## Param Rewrite With Matching -It is possible to rewrite the request url with parameter matchg. Here is an example with one parameter: -Rewrite for example "/radio/{frequence}" -> "/radio?f={frequence}" - -```cpp -class OneParamRewrite : public AsyncWebRewrite -{ - protected: - String _urlPrefix; - int _paramIndex; - String _paramsBackup; - - public: - OneParamRewrite(const char* from, const char* to) - : AsyncWebRewrite(from, to) { - - _paramIndex = _from.indexOf('{'); - - if( _paramIndex >=0 && _from.endsWith("}")) { - _urlPrefix = _from.substring(0, _paramIndex); - int index = _params.indexOf('{'); - if(index >= 0) { - _params = _params.substring(0, index); - } - } else { - _urlPrefix = _from; - } - _paramsBackup = _params; - } - - bool match(AsyncWebServerRequest *request) override { - if(request->url().startsWith(_urlPrefix)) { - if(_paramIndex >= 0) { - _params = _paramsBackup + request->url().substring(_paramIndex); - } else { - _params = _paramsBackup; - } - return true; - - } else { - return false; - } - } -}; -``` - -Usage: - -```cpp - server.addRewrite( new OneParamRewrite("/radio/{frequence}", "/radio?f={frequence}") ); -``` - -## Using filters -Filters can be set to `Rewrite` or `Handler` in order to control when to apply the rewrite and consider the handler. -A filter is a callback function that evaluates the request and return a boolean `true` to include the item -or `false` to exclude it. -Two filter callback are provided for convince: -* `ON_STA_FILTER` - return true when requests are made to the STA (station mode) interface. -* `ON_AP_FILTER` - return true when requests are made to the AP (access point) interface. - -### Serve different site files in AP mode -```cpp -server.serveStatic("/", SPIFFS, "/www/").setFilter(ON_STA_FILTER); -server.serveStatic("/", SPIFFS, "/ap/").setFilter(ON_AP_FILTER); -``` - -### Rewrite to different index on AP -```cpp -// Serve the file "/www/index-ap.htm" in AP, and the file "/www/index.htm" on STA -server.rewrite("/", "index.htm"); -server.rewrite("/index.htm", "index-ap.htm").setFilter(ON_AP_FILTER); -server.serveStatic("/", SPIFFS, "/www/"); -``` - -### Serving different hosts -```cpp -// Filter callback using request host -bool filterOnHost1(AsyncWebServerRequest *request) { return request->host() == "host1"; } - -// Server setup: server files in "/host1/" to requests for "host1", and files in "/www/" otherwise. -server.serveStatic("/", SPIFFS, "/host1/").setFilter(filterOnHost1); -server.serveStatic("/", SPIFFS, "/www/"); -``` - -### Determine interface inside callbacks -```cpp - String RedirectUrl = "http://"; - if (ON_STA_FILTER(request)) { - RedirectUrl += WiFi.localIP().toString(); - } else { - RedirectUrl += WiFi.softAPIP().toString(); - } - RedirectUrl += "/index.htm"; - request->redirect(RedirectUrl); -``` - -## Bad Responses -Some responses are implemented, but you should not use them, because they do not conform to HTTP. -The following example will lead to unclean close of the connection and more time wasted -than providing the length of the content - -### Respond with content using a callback without content length to HTTP/1.0 clients -```cpp -//This is used as fallback for chunked responses to HTTP/1.0 Clients -request->send("text/plain", 0, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t { - //Write up to "maxLen" bytes into "buffer" and return the amount written. - //You will be asked for more data until 0 is returned - //Keep in mind that you can not delay or yield waiting for more data! - return mySource.read(buffer, maxLen); -}); -``` - -## Async WebSocket Plugin -The server includes a web socket plugin which lets you define different WebSocket locations to connect to -without starting another listening service or using different port - -### Async WebSocket Event -```cpp - -void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ - if(type == WS_EVT_CONNECT){ - //client connected - os_printf("ws[%s][%u] connect\n", server->url(), client->id()); - client->printf("Hello Client %u :)", client->id()); - client->ping(); - } else if(type == WS_EVT_DISCONNECT){ - //client disconnected - os_printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id()); - } else if(type == WS_EVT_ERROR){ - //error was received from the other end - os_printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data); - } else if(type == WS_EVT_PONG){ - //pong message was received (in response to a ping request maybe) - os_printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:""); - } else if(type == WS_EVT_DATA){ - //data packet - AwsFrameInfo * info = (AwsFrameInfo*)arg; - if(info->final && info->index == 0 && info->len == len){ - //the whole message is in a single frame and we got all of it's data - os_printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len); - if(info->opcode == WS_TEXT){ - data[len] = 0; - os_printf("%s\n", (char*)data); - } else { - for(size_t i=0; i < info->len; i++){ - os_printf("%02x ", data[i]); - } - os_printf("\n"); - } - if(info->opcode == WS_TEXT) - client->text("I got your text message"); - else - client->binary("I got your binary message"); - } else { - //message is comprised of multiple frames or the frame is split into multiple packets - if(info->index == 0){ - if(info->num == 0) - os_printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); - os_printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len); - } - - os_printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len); - if(info->message_opcode == WS_TEXT){ - data[len] = 0; - os_printf("%s\n", (char*)data); - } else { - for(size_t i=0; i < len; i++){ - os_printf("%02x ", data[i]); - } - os_printf("\n"); - } - - if((info->index + len) == info->len){ - os_printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); - if(info->final){ - os_printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); - if(info->message_opcode == WS_TEXT) - client->text("I got your text message"); - else - client->binary("I got your binary message"); - } - } - } - } -} -``` - -### Methods for sending data to a socket client -```cpp - - - -//Server methods -AsyncWebSocket ws("/ws"); -//printf to a client -ws.printf((uint32_t)client_id, arguments...); -//printf to all clients -ws.printfAll(arguments...); -//printf_P to a client -ws.printf_P((uint32_t)client_id, PSTR(format), arguments...); -//printfAll_P to all clients -ws.printfAll_P(PSTR(format), arguments...); -//send text to a client -ws.text((uint32_t)client_id, (char*)text); -ws.text((uint32_t)client_id, (uint8_t*)text, (size_t)len); -//send text from PROGMEM to a client -ws.text((uint32_t)client_id, PSTR("text")); -const char flash_text[] PROGMEM = "Text to send" -ws.text((uint32_t)client_id, FPSTR(flash_text)); -//send text to all clients -ws.textAll((char*)text); -ws.textAll((uint8_t*)text, (size_t)len); -//send binary to a client -ws.binary((uint32_t)client_id, (char*)binary); -ws.binary((uint32_t)client_id, (uint8_t*)binary, (size_t)len); -//send binary from PROGMEM to a client -const uint8_t flash_binary[] PROGMEM = { 0x01, 0x02, 0x03, 0x04 }; -ws.binary((uint32_t)client_id, flash_binary, 4); -//send binary to all clients -ws.binaryAll((char*)binary); -ws.binaryAll((uint8_t*)binary, (size_t)len); -//HTTP Authenticate before switch to Websocket protocol -ws.setAuthentication("user", "pass"); - -//client methods -AsyncWebSocketClient * client; -//printf -client->printf(arguments...); -//printf_P -client->printf_P(PSTR(format), arguments...); -//send text -client->text((char*)text); -client->text((uint8_t*)text, (size_t)len); -//send text from PROGMEM -client->text(PSTR("text")); -const char flash_text[] PROGMEM = "Text to send"; -client->text(FPSTR(flash_text)); -//send binary -client->binary((char*)binary); -client->binary((uint8_t*)binary, (size_t)len); -//send binary from PROGMEM -const uint8_t flash_binary[] PROGMEM = { 0x01, 0x02, 0x03, 0x04 }; -client->binary(flash_binary, 4); -``` - -### Direct access to web socket message buffer -When sending a web socket message using the above methods a buffer is created. Under certain circumstances you might want to manipulate or populate this buffer directly from your application, for example to prevent unnecessary duplications of the data. This example below shows how to create a buffer and print data to it from an ArduinoJson object then send it. - -```cpp -void sendDataWs(AsyncWebSocketClient * client) -{ - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.createObject(); - root["a"] = "abc"; - root["b"] = "abcd"; - root["c"] = "abcde"; - root["d"] = "abcdef"; - root["e"] = "abcdefg"; - size_t len = root.measureLength(); - AsyncWebSocketMessageBuffer * buffer = ws.makeBuffer(len); // creates a buffer (len + 1) for you. - if (buffer) { - root.printTo((char *)buffer->get(), len + 1); - if (client) { - client->text(buffer); - } else { - ws.textAll(buffer); - } - } -} -``` - -### Limiting the number of web socket clients -Browsers sometimes do not correctly close the websocket connection, even when the close() function is called in javascript. This will eventually exhaust the web server's resources and will cause the server to crash. Periodically calling the cleanClients() function from the main loop() function limits the number of clients by closing the oldest client when the maximum number of clients has been exceeded. This can called be every cycle, however, if you wish to use less power, then calling as infrequently as once per second is sufficient. - -```cpp -void loop(){ - ws.cleanupClients(); -} -``` - - -## Async Event Source Plugin -The server includes EventSource (Server-Sent Events) plugin which can be used to send short text events to the browser. -Difference between EventSource and WebSockets is that EventSource is single direction, text-only protocol. - -### Setup Event Source on the server -```cpp -AsyncWebServer server(80); -AsyncEventSource events("/events"); - -void setup(){ - // setup ...... - events.onConnect([](AsyncEventSourceClient *client){ - if(client->lastId()){ - Serial.printf("Client reconnected! Last message ID that it gat is: %u\n", client->lastId()); - } - //send event with message "hello!", id current millis - // and set reconnect delay to 1 second - client->send("hello!",NULL,millis(),1000); - }); - //HTTP Basic authentication - events.setAuthentication("user", "pass"); - server.addHandler(&events); - // setup ...... -} - -void loop(){ - if(eventTriggered){ // your logic here - //send event "myevent" - events.send("my event content","myevent",millis()); - } -} -``` - -### Setup Event Source in the browser -```javascript -if (!!window.EventSource) { - var source = new EventSource('/events'); - - source.addEventListener('open', function(e) { - console.log("Events Connected"); - }, false); - - source.addEventListener('error', function(e) { - if (e.target.readyState != EventSource.OPEN) { - console.log("Events Disconnected"); - } - }, false); - - source.addEventListener('message', function(e) { - console.log("message", e.data); - }, false); - - source.addEventListener('myevent', function(e) { - console.log("myevent", e.data); - }, false); -} -``` - -## Scanning for available WiFi Networks -```cpp -//First request will return 0 results unless you start scan from somewhere else (loop/setup) -//Do not request more often than 3-5 seconds -server.on("/scan", HTTP_GET, [](AsyncWebServerRequest *request){ - String json = "["; - int n = WiFi.scanComplete(); - if(n == -2){ - WiFi.scanNetworks(true); - } else if(n){ - for (int i = 0; i < n; ++i){ - if(i) json += ","; - json += "{"; - json += "\"rssi\":"+String(WiFi.RSSI(i)); - json += ",\"ssid\":\""+WiFi.SSID(i)+"\""; - json += ",\"bssid\":\""+WiFi.BSSIDstr(i)+"\""; - json += ",\"channel\":"+String(WiFi.channel(i)); - json += ",\"secure\":"+String(WiFi.encryptionType(i)); - json += ",\"hidden\":"+String(WiFi.isHidden(i)?"true":"false"); - json += "}"; - } - WiFi.scanDelete(); - if(WiFi.scanComplete() == -2){ - WiFi.scanNetworks(true); - } - } - json += "]"; - request->send(200, "application/json", json); - json = String(); -}); -``` - -## Remove handlers and rewrites - -Server goes through handlers in same order as they were added. You can't simple add handler with same path to override them. -To remove handler: -```arduino -// save callback for particular URL path -auto handler = server.on("/some/path", [](AsyncWebServerRequest *request){ - //do something useful -}); -// when you don't need handler anymore remove it -server.removeHandler(&handler); - -// same with rewrites -server.removeRewrite(&someRewrite); - -server.onNotFound([](AsyncWebServerRequest *request){ - request->send(404); -}); - -// remove server.onNotFound handler -server.onNotFound(NULL); - -// remove all rewrites, handlers and onNotFound/onFileUpload/onRequestBody callbacks -server.reset(); -``` - -## Setting up the server -```cpp -#include "ESPAsyncTCP.h" -#include "ESPAsyncWebServer.h" - -AsyncWebServer server(80); -AsyncWebSocket ws("/ws"); // access at ws://[esp ip]/ws -AsyncEventSource events("/events"); // event source (Server-Sent events) - -const char* ssid = "your-ssid"; -const char* password = "your-pass"; -const char* http_username = "admin"; -const char* http_password = "admin"; - -//flag to use from web update to reboot the ESP -bool shouldReboot = false; - -void onRequest(AsyncWebServerRequest *request){ - //Handle Unknown Request - request->send(404); -} - -void onBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ - //Handle body -} - -void onUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ - //Handle upload -} - -void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ - //Handle WebSocket event -} - -void setup(){ - Serial.begin(115200); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - if (WiFi.waitForConnectResult() != WL_CONNECTED) { - Serial.printf("WiFi Failed!\n"); - return; - } - - // attach AsyncWebSocket - ws.onEvent(onEvent); - server.addHandler(&ws); - - // attach AsyncEventSource - server.addHandler(&events); - - // respond to GET requests on URL /heap - server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send(200, "text/plain", String(ESP.getFreeHeap())); - }); - - // upload a file to /upload - server.on("/upload", HTTP_POST, [](AsyncWebServerRequest *request){ - request->send(200); - }, onUpload); - - // send a file when /index is requested - server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){ - request->send(SPIFFS, "/index.htm"); - }); - - // HTTP basic authentication - server.on("/login", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!request->authenticate(http_username, http_password)) - return request->requestAuthentication(); - request->send(200, "text/plain", "Login Success!"); - }); - - // Simple Firmware Update Form - server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send(200, "text/html", "
"); - }); - server.on("/update", HTTP_POST, [](AsyncWebServerRequest *request){ - shouldReboot = !Update.hasError(); - AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot?"OK":"FAIL"); - response->addHeader("Connection", "close"); - request->send(response); - },[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ - if(!index){ - Serial.printf("Update Start: %s\n", filename.c_str()); - Update.runAsync(true); - if(!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)){ - Update.printError(Serial); - } - } - if(!Update.hasError()){ - if(Update.write(data, len) != len){ - Update.printError(Serial); - } - } - if(final){ - if(Update.end(true)){ - Serial.printf("Update Success: %uB\n", index+len); - } else { - Update.printError(Serial); - } - } - }); - - // attach filesystem root at URL /fs - server.serveStatic("/fs", SPIFFS, "/"); - - // Catch-All Handlers - // Any request that can not find a Handler that canHandle it - // ends in the callbacks below. - server.onNotFound(onRequest); - server.onFileUpload(onUpload); - server.onRequestBody(onBody); - - server.begin(); -} - -void loop(){ - if(shouldReboot){ - Serial.println("Rebooting..."); - delay(100); - ESP.restart(); - } - static char temp[128]; - sprintf(temp, "Seconds since boot: %u", millis()/1000); - events.send(temp, "time"); //send event "time" -} -``` - -### Setup global and class functions as request handlers - -```cpp -#include -#include -#include -#include - -void handleRequest(AsyncWebServerRequest *request){} - -class WebClass { -public : - AsyncWebServer classWebServer = AsyncWebServer(81); - - WebClass(){}; - - void classRequest (AsyncWebServerRequest *request){} - - void begin(){ - // attach global request handler - classWebServer.on("/example", HTTP_ANY, handleRequest); - - // attach class request handler - classWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, this, std::placeholders::_1)); - } -}; - -AsyncWebServer globalWebServer(80); -WebClass webClassInstance; - -void setup() { - // attach global request handler - globalWebServer.on("/example", HTTP_ANY, handleRequest); - - // attach class request handler - globalWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1)); -} - -void loop() { - -} -``` - -### Methods for controlling websocket connections - -```cpp - // Disable client connections if it was activated - if ( ws.enabled() ) - ws.enable(false); - - // enable client connections if it was disabled - if ( !ws.enabled() ) - ws.enable(true); -``` - -Example of OTA code - -```cpp - // OTA callbacks - ArduinoOTA.onStart([]() { - // Clean SPIFFS - SPIFFS.end(); - - // Disable client connections - ws.enable(false); - - // Advertise connected clients what's going on - ws.textAll("OTA Update Started"); - - // Close them - ws.closeAll(); - - }); - -``` - -### Adding Default Headers - -In some cases, such as when working with CORS, or with some sort of custom authentication system, -you might need to define a header that should get added to all responses (including static, websocket and EventSource). -The DefaultHeaders singleton allows you to do this. - -Example: - -```cpp -DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); -webServer.begin(); -``` - -*NOTE*: You will still need to respond to the OPTIONS method for CORS pre-flight in most cases. (unless you are only using GET) - -This is one option: - -```cpp -webServer.onNotFound([](AsyncWebServerRequest *request) { - if (request->method() == HTTP_OPTIONS) { - request->send(200); - } else { - request->send(404); - } -}); -``` - -### Path variable - -With path variable you can create a custom regex rule for a specific parameter in a route. -For example we want a `sensorId` parameter in a route rule to match only a integer. - -```cpp - server.on("^\\/sensor\\/([0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) { - String sensorId = request->pathArg(0); - }); -``` -*NOTE*: All regex patterns starts with `^` and ends with `$` - -To enable the `Path variable` support, you have to define the buildflag `-DASYNCWEBSERVER_REGEX`. - - -For Arduino IDE create/update `platform.local.txt`: - -`Windows`: C:\Users\(username)\AppData\Local\Arduino15\packages\\`{espxxxx}`\hardware\\`espxxxx`\\`{version}`\platform.local.txt - -`Linux`: ~/.arduino15/packages/`{espxxxx}`/hardware/`{espxxxx}`/`{version}`/platform.local.txt - -Add/Update the following line: -``` - compiler.cpp.extra_flags=-DDASYNCWEBSERVER_REGEX -``` - -For platformio modify `platformio.ini`: -```ini -[env:myboard] -build_flags = - -DASYNCWEBSERVER_REGEX -``` -*NOTE*: By enabling `ASYNCWEBSERVER_REGEX`, `` will be included. This will add an 100k to your binary. diff --git a/lib/ESPAsyncWebServer/_config.yml b/lib/ESPAsyncWebServer/_config.yml deleted file mode 100644 index c4192631..00000000 --- a/lib/ESPAsyncWebServer/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-cayman \ No newline at end of file diff --git a/lib/ESPAsyncWebServer/component.mk b/lib/ESPAsyncWebServer/component.mk deleted file mode 100644 index bb5bb161..00000000 --- a/lib/ESPAsyncWebServer/component.mk +++ /dev/null @@ -1,3 +0,0 @@ -COMPONENT_ADD_INCLUDEDIRS := src -COMPONENT_SRCDIRS := src -CXXFLAGS += -fno-rtti diff --git a/lib/ESPAsyncWebServer/examples/CaptivePortal/CaptivePortal.ino b/lib/ESPAsyncWebServer/examples/CaptivePortal/CaptivePortal.ino deleted file mode 100644 index f97f142a..00000000 --- a/lib/ESPAsyncWebServer/examples/CaptivePortal/CaptivePortal.ino +++ /dev/null @@ -1,47 +0,0 @@ -#include -#ifdef ESP32 -#include -#include -#elif defined(ESP8266) -#include -#include -#endif -#include "ESPAsyncWebServer.h" - -DNSServer dnsServer; -AsyncWebServer server(80); - -class CaptiveRequestHandler : public AsyncWebHandler { -public: - CaptiveRequestHandler() {} - virtual ~CaptiveRequestHandler() {} - - bool canHandle(AsyncWebServerRequest *request){ - //request->addInterestingHeader("ANY"); - return true; - } - - void handleRequest(AsyncWebServerRequest *request) { - AsyncResponseStream *response = request->beginResponseStream("text/html"); - response->print("Captive Portal"); - response->print("

This is out captive portal front page.

"); - response->printf("

You were trying to reach: http://%s%s

", request->host().c_str(), request->url().c_str()); - response->printf("

Try opening this link instead

", WiFi.softAPIP().toString().c_str()); - response->print(""); - request->send(response); - } -}; - - -void setup(){ - //your other setup stuff... - WiFi.softAP("esp-captive"); - dnsServer.start(53, "*", WiFi.softAPIP()); - server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);//only when requested from AP - //more handlers... - server.begin(); -} - -void loop(){ - dnsServer.processNextRequest(); -} diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino deleted file mode 100644 index bf42d003..00000000 --- a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino +++ /dev/null @@ -1,221 +0,0 @@ -#include -#ifdef ESP32 -#include -#include -#include -#include -#include -#elif defined(ESP8266) -#include -#include -#include -#endif -#include -#include - -// SKETCH BEGIN -AsyncWebServer server(80); -AsyncWebSocket ws("/ws"); -AsyncEventSource events("/events"); - -void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ - if(type == WS_EVT_CONNECT){ - Serial.printf("ws[%s][%u] connect\n", server->url(), client->id()); - client->printf("Hello Client %u :)", client->id()); - client->ping(); - } else if(type == WS_EVT_DISCONNECT){ - Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id()); - } else if(type == WS_EVT_ERROR){ - Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data); - } else if(type == WS_EVT_PONG){ - Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:""); - } else if(type == WS_EVT_DATA){ - AwsFrameInfo * info = (AwsFrameInfo*)arg; - String msg = ""; - if(info->final && info->index == 0 && info->len == len){ - //the whole message is in a single frame and we got all of it's data - Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len); - - if(info->opcode == WS_TEXT){ - for(size_t i=0; i < info->len; i++) { - msg += (char) data[i]; - } - } else { - char buff[3]; - for(size_t i=0; i < info->len; i++) { - sprintf(buff, "%02x ", (uint8_t) data[i]); - msg += buff ; - } - } - Serial.printf("%s\n",msg.c_str()); - - if(info->opcode == WS_TEXT) - client->text("I got your text message"); - else - client->binary("I got your binary message"); - } else { - //message is comprised of multiple frames or the frame is split into multiple packets - if(info->index == 0){ - if(info->num == 0) - Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); - Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len); - } - - Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len); - - if(info->opcode == WS_TEXT){ - for(size_t i=0; i < len; i++) { - msg += (char) data[i]; - } - } else { - char buff[3]; - for(size_t i=0; i < len; i++) { - sprintf(buff, "%02x ", (uint8_t) data[i]); - msg += buff ; - } - } - Serial.printf("%s\n",msg.c_str()); - - if((info->index + len) == info->len){ - Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); - if(info->final){ - Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); - if(info->message_opcode == WS_TEXT) - client->text("I got your text message"); - else - client->binary("I got your binary message"); - } - } - } - } -} - - -const char* ssid = "*******"; -const char* password = "*******"; -const char * hostName = "esp-async"; -const char* http_username = "admin"; -const char* http_password = "admin"; - -void setup(){ - Serial.begin(115200); - Serial.setDebugOutput(true); - WiFi.mode(WIFI_AP_STA); - WiFi.softAP(hostName); - WiFi.begin(ssid, password); - if (WiFi.waitForConnectResult() != WL_CONNECTED) { - Serial.printf("STA: Failed!\n"); - WiFi.disconnect(false); - delay(1000); - WiFi.begin(ssid, password); - } - - //Send OTA events to the browser - ArduinoOTA.onStart([]() { events.send("Update Start", "ota"); }); - ArduinoOTA.onEnd([]() { events.send("Update End", "ota"); }); - ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { - char p[32]; - sprintf(p, "Progress: %u%%\n", (progress/(total/100))); - events.send(p, "ota"); - }); - ArduinoOTA.onError([](ota_error_t error) { - if(error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota"); - else if(error == OTA_BEGIN_ERROR) events.send("Begin Failed", "ota"); - else if(error == OTA_CONNECT_ERROR) events.send("Connect Failed", "ota"); - else if(error == OTA_RECEIVE_ERROR) events.send("Recieve Failed", "ota"); - else if(error == OTA_END_ERROR) events.send("End Failed", "ota"); - }); - ArduinoOTA.setHostname(hostName); - ArduinoOTA.begin(); - - MDNS.addService("http","tcp",80); - - SPIFFS.begin(); - - ws.onEvent(onWsEvent); - server.addHandler(&ws); - - events.onConnect([](AsyncEventSourceClient *client){ - client->send("hello!",NULL,millis(),1000); - }); - server.addHandler(&events); - -#ifdef ESP32 - server.addHandler(new SPIFFSEditor(SPIFFS, http_username,http_password)); -#elif defined(ESP8266) - server.addHandler(new SPIFFSEditor(http_username,http_password)); -#endif - - server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send(200, "text/plain", String(ESP.getFreeHeap())); - }); - - server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm"); - - server.onNotFound([](AsyncWebServerRequest *request){ - Serial.printf("NOT_FOUND: "); - if(request->method() == HTTP_GET) - Serial.printf("GET"); - else if(request->method() == HTTP_POST) - Serial.printf("POST"); - else if(request->method() == HTTP_DELETE) - Serial.printf("DELETE"); - else if(request->method() == HTTP_PUT) - Serial.printf("PUT"); - else if(request->method() == HTTP_PATCH) - Serial.printf("PATCH"); - else if(request->method() == HTTP_HEAD) - Serial.printf("HEAD"); - else if(request->method() == HTTP_OPTIONS) - Serial.printf("OPTIONS"); - else - Serial.printf("UNKNOWN"); - Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str()); - - if(request->contentLength()){ - Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str()); - Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength()); - } - - int headers = request->headers(); - int i; - for(i=0;igetHeader(i); - Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); - } - - int params = request->params(); - for(i=0;igetParam(i); - if(p->isFile()){ - Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); - } else if(p->isPost()){ - Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); - } else { - Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); - } - } - - request->send(404); - }); - server.onFileUpload([](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){ - if(!index) - Serial.printf("UploadStart: %s\n", filename.c_str()); - Serial.printf("%s", (const char*)data); - if(final) - Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len); - }); - server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ - if(!index) - Serial.printf("BodyStart: %u\n", total); - Serial.printf("%s", (const char*)data); - if(index + len == total) - Serial.printf("BodyEnd: %u\n", total); - }); - server.begin(); -} - -void loop(){ - ArduinoOTA.handle(); - ws.cleanupClients(); -} diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/.exclude.files b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/.exclude.files deleted file mode 100644 index 955397fa..00000000 --- a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/.exclude.files +++ /dev/null @@ -1,2 +0,0 @@ -/*.js.gz -/.exclude.files diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ace.js.gz b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ace.js.gz deleted file mode 100644 index 7b175c1c..00000000 Binary files a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ace.js.gz and /dev/null differ diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ext-searchbox.js.gz b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ext-searchbox.js.gz deleted file mode 100644 index cf5b49f6..00000000 Binary files a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/ext-searchbox.js.gz and /dev/null differ diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/favicon.ico b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/favicon.ico deleted file mode 100644 index 71b25fe6..00000000 Binary files a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/favicon.ico and /dev/null differ diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/index.htm b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/index.htm deleted file mode 100644 index 28f47e99..00000000 --- a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/index.htm +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - WebSocketTester - - - - -

-    
- $ -
- - diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-css.js.gz b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-css.js.gz deleted file mode 100644 index ebd6fe94..00000000 Binary files a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-css.js.gz and /dev/null differ diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-html.js.gz b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-html.js.gz deleted file mode 100644 index 26b53532..00000000 Binary files a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-html.js.gz and /dev/null differ diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-javascript.js.gz b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-javascript.js.gz deleted file mode 100644 index c0451c1c..00000000 Binary files a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/mode-javascript.js.gz and /dev/null differ diff --git a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/worker-html.js.gz b/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/worker-html.js.gz deleted file mode 100644 index ec8aa87a..00000000 Binary files a/lib/ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/data/worker-html.js.gz and /dev/null differ diff --git a/lib/ESPAsyncWebServer/examples/regex_patterns/.test.build_flags b/lib/ESPAsyncWebServer/examples/regex_patterns/.test.build_flags deleted file mode 100644 index 9ea3bb74..00000000 --- a/lib/ESPAsyncWebServer/examples/regex_patterns/.test.build_flags +++ /dev/null @@ -1 +0,0 @@ --DASYNCWEBSERVER_REGEX=1 diff --git a/lib/ESPAsyncWebServer/examples/regex_patterns/regex_patterns.ino b/lib/ESPAsyncWebServer/examples/regex_patterns/regex_patterns.ino deleted file mode 100644 index fb013063..00000000 --- a/lib/ESPAsyncWebServer/examples/regex_patterns/regex_patterns.ino +++ /dev/null @@ -1,77 +0,0 @@ -// -// A simple server implementation with regex routes: -// * serve static messages -// * read GET and POST parameters -// * handle missing pages / 404s -// - -// Add buildflag ASYNCWEBSERVER_REGEX to enable the regex support - -// For platformio: platformio.ini: -// build_flags = -// -DASYNCWEBSERVER_REGEX - -// For arduino IDE: create/update platform.local.txt -// Windows: C:\Users\(username)\AppData\Local\Arduino15\packages\espxxxx\hardware\espxxxx\{version}\platform.local.txt -// Linux: ~/.arduino15/packages/espxxxx/hardware/espxxxx/{version}/platform.local.txt -// -// compiler.cpp.extra_flags=-DASYNCWEBSERVER_REGEX=1 - -#include -#ifdef ESP32 -#include -#include -#elif defined(ESP8266) -#include -#include -#endif -#include - -AsyncWebServer server(80); - -const char* ssid = "YOUR_SSID"; -const char* password = "YOUR_PASSWORD"; - -const char* PARAM_MESSAGE = "message"; - -void notFound(AsyncWebServerRequest *request) { - request->send(404, "text/plain", "Not found"); -} - -void setup() { - - Serial.begin(115200); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - if (WiFi.waitForConnectResult() != WL_CONNECTED) { - Serial.printf("WiFi Failed!\n"); - return; - } - - Serial.print("IP Address: "); - Serial.println(WiFi.localIP()); - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send(200, "text/plain", "Hello, world"); - }); - - // Send a GET request to /sensor/ - server.on("^\\/sensor\\/([0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) { - String sensorNumber = request->pathArg(0); - request->send(200, "text/plain", "Hello, sensor: " + sensorNumber); - }); - - // Send a GET request to /sensor//action/ - server.on("^\\/sensor\\/([0-9]+)\\/action\\/([a-zA-Z0-9]+)$", HTTP_GET, [] (AsyncWebServerRequest *request) { - String sensorNumber = request->pathArg(0); - String action = request->pathArg(1); - request->send(200, "text/plain", "Hello, sensor: " + sensorNumber + ", with action: " + action); - }); - - server.onNotFound(notFound); - - server.begin(); -} - -void loop() { -} diff --git a/lib/ESPAsyncWebServer/examples/simple_server/simple_server.ino b/lib/ESPAsyncWebServer/examples/simple_server/simple_server.ino deleted file mode 100644 index bdbcf60d..00000000 --- a/lib/ESPAsyncWebServer/examples/simple_server/simple_server.ino +++ /dev/null @@ -1,74 +0,0 @@ -// -// A simple server implementation showing how to: -// * serve static messages -// * read GET and POST parameters -// * handle missing pages / 404s -// - -#include -#ifdef ESP32 -#include -#include -#elif defined(ESP8266) -#include -#include -#endif -#include - -AsyncWebServer server(80); - -const char* ssid = "YOUR_SSID"; -const char* password = "YOUR_PASSWORD"; - -const char* PARAM_MESSAGE = "message"; - -void notFound(AsyncWebServerRequest *request) { - request->send(404, "text/plain", "Not found"); -} - -void setup() { - - Serial.begin(115200); - WiFi.mode(WIFI_STA); - WiFi.begin(ssid, password); - if (WiFi.waitForConnectResult() != WL_CONNECTED) { - Serial.printf("WiFi Failed!\n"); - return; - } - - Serial.print("IP Address: "); - Serial.println(WiFi.localIP()); - - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send(200, "text/plain", "Hello, world"); - }); - - // Send a GET request to /get?message= - server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) { - String message; - if (request->hasParam(PARAM_MESSAGE)) { - message = request->getParam(PARAM_MESSAGE)->value(); - } else { - message = "No message sent"; - } - request->send(200, "text/plain", "Hello, GET: " + message); - }); - - // Send a POST request to /post with a form field message set to - server.on("/post", HTTP_POST, [](AsyncWebServerRequest *request){ - String message; - if (request->hasParam(PARAM_MESSAGE, true)) { - message = request->getParam(PARAM_MESSAGE, true)->value(); - } else { - message = "No message sent"; - } - request->send(200, "text/plain", "Hello, POST: " + message); - }); - - server.onNotFound(notFound); - - server.begin(); -} - -void loop() { -} \ No newline at end of file diff --git a/lib/ESPAsyncWebServer/keywords.txt b/lib/ESPAsyncWebServer/keywords.txt deleted file mode 100644 index c391e6c4..00000000 --- a/lib/ESPAsyncWebServer/keywords.txt +++ /dev/null @@ -1,3 +0,0 @@ -JsonArray KEYWORD1 -add KEYWORD2 -createArray KEYWORD3 diff --git a/lib/ESPAsyncWebServer/library.json b/lib/ESPAsyncWebServer/library.json deleted file mode 100644 index 55659279..00000000 --- a/lib/ESPAsyncWebServer/library.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name":"ESP Async WebServer", - "description":"Asynchronous HTTP and WebSocket Server Library for ESP8266 and ESP32", - "keywords":"http,async,websocket,webserver", - "authors": - { - "name": "Hristo Gochkov", - "maintainer": true - }, - "repository": - { - "type": "git", - "url": "https://github.com/me-no-dev/ESPAsyncWebServer.git" - }, - "version": "1.2.3", - "license": "LGPL-3.0", - "frameworks": "arduino", - "platforms": ["espressif8266", "espressif32"], - "dependencies": [ - { - "name": "ESPAsyncTCP", - "platforms": "espressif8266" - }, - { - "name": "AsyncTCP", - "platforms": "espressif32" - }, - { - "name": "Hash", - "platforms": "espressif8266" - } - ] -} diff --git a/lib/ESPAsyncWebServer/library.properties b/lib/ESPAsyncWebServer/library.properties deleted file mode 100644 index 401b0417..00000000 --- a/lib/ESPAsyncWebServer/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=ESP Async WebServer -version=1.2.3 -author=Me-No-Dev -maintainer=Me-No-Dev -sentence=Async Web Server for ESP8266 and ESP31B -paragraph=Async Web Server for ESP8266 and ESP31B -category=Other -url=https://github.com/me-no-dev/ESPAsyncWebServer -architectures=* diff --git a/lib/ESPAsyncWebServer/src/AsyncEventSource.cpp b/lib/ESPAsyncWebServer/src/AsyncEventSource.cpp deleted file mode 100644 index f2914df5..00000000 --- a/lib/ESPAsyncWebServer/src/AsyncEventSource.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "Arduino.h" -#include "AsyncEventSource.h" - -static String generateEventMessage(const char *message, const char *event, uint32_t id, uint32_t reconnect){ - String ev = ""; - - if(reconnect){ - ev += "retry: "; - ev += String(reconnect); - ev += "\r\n"; - } - - if(id){ - ev += "id: "; - ev += String(id); - ev += "\r\n"; - } - - if(event != NULL){ - ev += "event: "; - ev += String(event); - ev += "\r\n"; - } - - if(message != NULL){ - size_t messageLen = strlen(message); - char * lineStart = (char *)message; - char * lineEnd; - do { - char * nextN = strchr(lineStart, '\n'); - char * nextR = strchr(lineStart, '\r'); - if(nextN == NULL && nextR == NULL){ - size_t llen = ((char *)message + messageLen) - lineStart; - char * ldata = (char *)malloc(llen+1); - if(ldata != NULL){ - memcpy(ldata, lineStart, llen); - ldata[llen] = 0; - ev += "data: "; - ev += ldata; - ev += "\r\n\r\n"; - free(ldata); - } - lineStart = (char *)message + messageLen; - } else { - char * nextLine = NULL; - if(nextN != NULL && nextR != NULL){ - if(nextR < nextN){ - lineEnd = nextR; - if(nextN == (nextR + 1)) - nextLine = nextN + 1; - else - nextLine = nextR + 1; - } else { - lineEnd = nextN; - if(nextR == (nextN + 1)) - nextLine = nextR + 1; - else - nextLine = nextN + 1; - } - } else if(nextN != NULL){ - lineEnd = nextN; - nextLine = nextN + 1; - } else { - lineEnd = nextR; - nextLine = nextR + 1; - } - - size_t llen = lineEnd - lineStart; - char * ldata = (char *)malloc(llen+1); - if(ldata != NULL){ - memcpy(ldata, lineStart, llen); - ldata[llen] = 0; - ev += "data: "; - ev += ldata; - ev += "\r\n"; - free(ldata); - } - lineStart = nextLine; - if(lineStart == ((char *)message + messageLen)) - ev += "\r\n"; - } - } while(lineStart < ((char *)message + messageLen)); - } - - return ev; -} - -// Message - -AsyncEventSourceMessage::AsyncEventSourceMessage(const char * data, size_t len) -: _data(nullptr), _len(len), _sent(0), _acked(0) -{ - _data = (uint8_t*)malloc(_len+1); - if(_data == nullptr){ - _len = 0; - } else { - memcpy(_data, data, len); - _data[_len] = 0; - } -} - -AsyncEventSourceMessage::~AsyncEventSourceMessage() { - if(_data != NULL) - free(_data); -} - -size_t AsyncEventSourceMessage::ack(size_t len, uint32_t time) { - (void)time; - // If the whole message is now acked... - if(_acked + len > _len){ - // Return the number of extra bytes acked (they will be carried on to the next message) - const size_t extra = _acked + len - _len; - _acked = _len; - return extra; - } - // Return that no extra bytes left. - _acked += len; - return 0; -} - -size_t AsyncEventSourceMessage::send(AsyncClient *client) { - const size_t len = _len - _sent; - if(client->space() < len){ - return 0; - } - size_t sent = client->add((const char *)_data, len); - if(client->canSend()) - client->send(); - _sent += sent; - return sent; -} - -// Client - -AsyncEventSourceClient::AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server) -: _messageQueue(LinkedList([](AsyncEventSourceMessage *m){ delete m; })) -{ - _client = request->client(); - _server = server; - _lastId = 0; - if(request->hasHeader("Last-Event-ID")) - _lastId = atoi(request->getHeader("Last-Event-ID")->value().c_str()); - - _client->setRxTimeout(0); - _client->onError(NULL, NULL); - _client->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; ((AsyncEventSourceClient*)(r))->_onAck(len, time); }, this); - _client->onPoll([](void *r, AsyncClient* c){ (void)c; ((AsyncEventSourceClient*)(r))->_onPoll(); }, this); - _client->onData(NULL, NULL); - _client->onTimeout([this](void *r, AsyncClient* c __attribute__((unused)), uint32_t time){ ((AsyncEventSourceClient*)(r))->_onTimeout(time); }, this); - _client->onDisconnect([this](void *r, AsyncClient* c){ ((AsyncEventSourceClient*)(r))->_onDisconnect(); delete c; }, this); - - _server->_addClient(this); - delete request; -} - -AsyncEventSourceClient::~AsyncEventSourceClient(){ - _messageQueue.free(); - close(); -} - -void AsyncEventSourceClient::_queueMessage(AsyncEventSourceMessage *dataMessage){ - if(dataMessage == NULL) - return; - if(!connected()){ - delete dataMessage; - return; - } - if(_messageQueue.length() >= SSE_MAX_QUEUED_MESSAGES){ - ets_printf("ERROR: Too many messages queued\n"); - delete dataMessage; - } else { - _messageQueue.add(dataMessage); - } - if(_client->canSend()) - _runQueue(); -} - -void AsyncEventSourceClient::_onAck(size_t len, uint32_t time){ - while(len && !_messageQueue.isEmpty()){ - len = _messageQueue.front()->ack(len, time); - if(_messageQueue.front()->finished()) - _messageQueue.remove(_messageQueue.front()); - } - - _runQueue(); -} - -void AsyncEventSourceClient::_onPoll(){ - if(!_messageQueue.isEmpty()){ - _runQueue(); - } -} - - -void AsyncEventSourceClient::_onTimeout(uint32_t time __attribute__((unused))){ - _client->close(true); -} - -void AsyncEventSourceClient::_onDisconnect(){ - _client = NULL; - _server->_handleDisconnect(this); -} - -void AsyncEventSourceClient::close(){ - if(_client != NULL) - _client->close(); -} - -void AsyncEventSourceClient::write(const char * message, size_t len){ - _queueMessage(new AsyncEventSourceMessage(message, len)); -} - -void AsyncEventSourceClient::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){ - String ev = generateEventMessage(message, event, id, reconnect); - _queueMessage(new AsyncEventSourceMessage(ev.c_str(), ev.length())); -} - -void AsyncEventSourceClient::_runQueue(){ - while(!_messageQueue.isEmpty() && _messageQueue.front()->finished()){ - _messageQueue.remove(_messageQueue.front()); - } - - for(auto i = _messageQueue.begin(); i != _messageQueue.end(); ++i) - { - if(!(*i)->sent()) - (*i)->send(_client); - } -} - - -// Handler - -AsyncEventSource::AsyncEventSource(const String& url) - : _url(url) - , _clients(LinkedList([](AsyncEventSourceClient *c){ delete c; })) - , _connectcb(NULL) -{} - -AsyncEventSource::~AsyncEventSource(){ - close(); -} - -void AsyncEventSource::onConnect(ArEventHandlerFunction cb){ - _connectcb = cb; -} - -void AsyncEventSource::_addClient(AsyncEventSourceClient * client){ - /*char * temp = (char *)malloc(2054); - if(temp != NULL){ - memset(temp+1,' ',2048); - temp[0] = ':'; - temp[2049] = '\r'; - temp[2050] = '\n'; - temp[2051] = '\r'; - temp[2052] = '\n'; - temp[2053] = 0; - client->write((const char *)temp, 2053); - free(temp); - }*/ - - _clients.add(client); - if(_connectcb) - _connectcb(client); -} - -void AsyncEventSource::_handleDisconnect(AsyncEventSourceClient * client){ - _clients.remove(client); -} - -void AsyncEventSource::close(){ - for(const auto &c: _clients){ - if(c->connected()) - c->close(); - } -} - -// pmb fix -size_t AsyncEventSource::avgPacketsWaiting() const { - if(_clients.isEmpty()) - return 0; - - size_t aql=0; - uint32_t nConnectedClients=0; - - for(const auto &c: _clients){ - if(c->connected()) { - aql+=c->packetsWaiting(); - ++nConnectedClients; - } - } -// return aql / nConnectedClients; - return ((aql) + (nConnectedClients/2))/(nConnectedClients); // round up -} - -void AsyncEventSource::send(const char *message, const char *event, uint32_t id, uint32_t reconnect){ - - - String ev = generateEventMessage(message, event, id, reconnect); - for(const auto &c: _clients){ - if(c->connected()) { - c->write(ev.c_str(), ev.length()); - } - } -} - -size_t AsyncEventSource::count() const { - return _clients.count_if([](AsyncEventSourceClient *c){ - return c->connected(); - }); -} - -bool AsyncEventSource::canHandle(AsyncWebServerRequest *request){ - if(request->method() != HTTP_GET || !request->url().equals(_url)) { - return false; - } - request->addInterestingHeader("Last-Event-ID"); - return true; -} - -void AsyncEventSource::handleRequest(AsyncWebServerRequest *request){ - if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) - return request->requestAuthentication(); - request->send(new AsyncEventSourceResponse(this)); -} - -// Response - -AsyncEventSourceResponse::AsyncEventSourceResponse(AsyncEventSource *server){ - _server = server; - _code = 200; - _contentType = "text/event-stream"; - _sendContentLength = false; - addHeader("Cache-Control", "no-cache"); - addHeader("Connection","keep-alive"); -} - -void AsyncEventSourceResponse::_respond(AsyncWebServerRequest *request){ - String out = _assembleHead(request->version()); - request->client()->write(out.c_str(), _headLength); - _state = RESPONSE_WAIT_ACK; -} - -size_t AsyncEventSourceResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time __attribute__((unused))){ - if(len){ - new AsyncEventSourceClient(request, _server); - } - return 0; -} - diff --git a/lib/ESPAsyncWebServer/src/AsyncEventSource.h b/lib/ESPAsyncWebServer/src/AsyncEventSource.h deleted file mode 100644 index b097fa62..00000000 --- a/lib/ESPAsyncWebServer/src/AsyncEventSource.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef ASYNCEVENTSOURCE_H_ -#define ASYNCEVENTSOURCE_H_ - -#include -#ifdef ESP32 -#include -#define SSE_MAX_QUEUED_MESSAGES 32 -#else -#include -#define SSE_MAX_QUEUED_MESSAGES 8 -#endif -#include - -#include "AsyncWebSynchronization.h" - -#ifdef ESP8266 -#include -#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library -#include <../src/Hash.h> -#endif -#endif - -#ifdef ESP32 -#define DEFAULT_MAX_SSE_CLIENTS 8 -#else -#define DEFAULT_MAX_SSE_CLIENTS 4 -#endif - -class AsyncEventSource; -class AsyncEventSourceResponse; -class AsyncEventSourceClient; -typedef std::function ArEventHandlerFunction; - -class AsyncEventSourceMessage { - private: - uint8_t * _data; - size_t _len; - size_t _sent; - //size_t _ack; - size_t _acked; - public: - AsyncEventSourceMessage(const char * data, size_t len); - ~AsyncEventSourceMessage(); - size_t ack(size_t len, uint32_t time __attribute__((unused))); - size_t send(AsyncClient *client); - bool finished(){ return _acked == _len; } - bool sent() { return _sent == _len; } -}; - -class AsyncEventSourceClient { - private: - AsyncClient *_client; - AsyncEventSource *_server; - uint32_t _lastId; - LinkedList _messageQueue; - void _queueMessage(AsyncEventSourceMessage *dataMessage); - void _runQueue(); - - public: - - AsyncEventSourceClient(AsyncWebServerRequest *request, AsyncEventSource *server); - ~AsyncEventSourceClient(); - - AsyncClient* client(){ return _client; } - void close(); - void write(const char * message, size_t len); - void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); - bool connected() const { return (_client != NULL) && _client->connected(); } - uint32_t lastId() const { return _lastId; } - size_t packetsWaiting() const { return _messageQueue.length(); } - - //system callbacks (do not call) - void _onAck(size_t len, uint32_t time); - void _onPoll(); - void _onTimeout(uint32_t time); - void _onDisconnect(); -}; - -class AsyncEventSource: public AsyncWebHandler { - private: - String _url; - LinkedList _clients; - ArEventHandlerFunction _connectcb; - public: - AsyncEventSource(const String& url); - ~AsyncEventSource(); - - const char * url() const { return _url.c_str(); } - void close(); - void onConnect(ArEventHandlerFunction cb); - void send(const char *message, const char *event=NULL, uint32_t id=0, uint32_t reconnect=0); - size_t count() const; //number clinets connected - size_t avgPacketsWaiting() const; - - //system callbacks (do not call) - void _addClient(AsyncEventSourceClient * client); - void _handleDisconnect(AsyncEventSourceClient * client); - virtual bool canHandle(AsyncWebServerRequest *request) override final; - virtual void handleRequest(AsyncWebServerRequest *request) override final; -}; - -class AsyncEventSourceResponse: public AsyncWebServerResponse { - private: - String _content; - AsyncEventSource *_server; - public: - AsyncEventSourceResponse(AsyncEventSource *server); - void _respond(AsyncWebServerRequest *request); - size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); - bool _sourceValid() const { return true; } -}; - - -#endif /* ASYNCEVENTSOURCE_H_ */ diff --git a/lib/ESPAsyncWebServer/src/AsyncJson.h b/lib/ESPAsyncWebServer/src/AsyncJson.h deleted file mode 100644 index 27b4a26f..00000000 --- a/lib/ESPAsyncWebServer/src/AsyncJson.h +++ /dev/null @@ -1,252 +0,0 @@ -// AsyncJson.h -/* - Async Response to use with ArduinoJson and AsyncWebServer - Written by Andrew Melvin (SticilFace) with help from me-no-dev and BBlanchon. - - Example of callback in use - - server.on("/json", HTTP_ANY, [](AsyncWebServerRequest * request) { - - AsyncJsonResponse * response = new AsyncJsonResponse(); - JsonObject& root = response->getRoot(); - root["key1"] = "key number one"; - JsonObject& nested = root.createNestedObject("nested"); - nested["key1"] = "key number one"; - - response->setLength(); - request->send(response); - }); - - -------------------- - - Async Request to use with ArduinoJson and AsyncWebServer - Written by Arsène von Wyss (avonwyss) - - Example - - AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/rest/endpoint"); - handler->onRequest([](AsyncWebServerRequest *request, JsonVariant &json) { - JsonObject& jsonObj = json.as(); - // ... - }); - server.addHandler(handler); - -*/ -#ifndef ASYNC_JSON_H_ -#define ASYNC_JSON_H_ -#include -#include -#include - -#if ARDUINOJSON_VERSION_MAJOR == 5 - #define ARDUINOJSON_5_COMPATIBILITY -#else - #define DYNAMIC_JSON_DOCUMENT_SIZE 1024 -#endif - -constexpr const char* JSON_MIMETYPE = "application/json"; - -/* - * Json Response - * */ - -class ChunkPrint : public Print { - private: - uint8_t* _destination; - size_t _to_skip; - size_t _to_write; - size_t _pos; - public: - ChunkPrint(uint8_t* destination, size_t from, size_t len) - : _destination(destination), _to_skip(from), _to_write(len), _pos{0} {} - virtual ~ChunkPrint(){} - size_t write(uint8_t c){ - if (_to_skip > 0) { - _to_skip--; - return 1; - } else if (_to_write > 0) { - _to_write--; - _destination[_pos++] = c; - return 1; - } - return 0; - } - size_t write(const uint8_t *buffer, size_t size) - { - return this->Print::write(buffer, size); - } -}; - -class AsyncJsonResponse: public AsyncAbstractResponse { - protected: - -#ifdef ARDUINOJSON_5_COMPATIBILITY - DynamicJsonBuffer _jsonBuffer; -#else - DynamicJsonDocument _jsonBuffer; -#endif - - JsonVariant _root; - bool _isValid; - - public: - -#ifdef ARDUINOJSON_5_COMPATIBILITY - AsyncJsonResponse(bool isArray=false): _isValid{false} { - _code = 200; - _contentType = JSON_MIMETYPE; - if(isArray) - _root = _jsonBuffer.createArray(); - else - _root = _jsonBuffer.createObject(); - } -#else - AsyncJsonResponse(bool isArray=false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) : _jsonBuffer(maxJsonBufferSize), _isValid{false} { - _code = 200; - _contentType = JSON_MIMETYPE; - if(isArray) - _root = _jsonBuffer.createNestedArray(); - else - _root = _jsonBuffer.createNestedObject(); - } -#endif - - ~AsyncJsonResponse() {} - JsonVariant & getRoot() { return _root; } - bool _sourceValid() const { return _isValid; } - size_t setLength() { - -#ifdef ARDUINOJSON_5_COMPATIBILITY - _contentLength = _root.measureLength(); -#else - _contentLength = measureJson(_root); -#endif - - if (_contentLength) { _isValid = true; } - return _contentLength; - } - - size_t getSize() { return _jsonBuffer.size(); } - - size_t _fillBuffer(uint8_t *data, size_t len){ - ChunkPrint dest(data, _sentLength, len); - -#ifdef ARDUINOJSON_5_COMPATIBILITY - _root.printTo( dest ) ; -#else - serializeJson(_root, dest); -#endif - return len; - } -}; - -class PrettyAsyncJsonResponse: public AsyncJsonResponse { -public: -#ifdef ARDUINOJSON_5_COMPATIBILITY - PrettyAsyncJsonResponse (bool isArray=false) : AsyncJsonResponse{isArray} {} -#else - PrettyAsyncJsonResponse (bool isArray=false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) : AsyncJsonResponse{isArray, maxJsonBufferSize} {} -#endif - size_t setLength () { -#ifdef ARDUINOJSON_5_COMPATIBILITY - _contentLength = _root.measurePrettyLength (); -#else - _contentLength = measureJsonPretty(_root); -#endif - if (_contentLength) {_isValid = true;} - return _contentLength; - } - size_t _fillBuffer (uint8_t *data, size_t len) { - ChunkPrint dest (data, _sentLength, len); -#ifdef ARDUINOJSON_5_COMPATIBILITY - _root.prettyPrintTo (dest); -#else - serializeJsonPretty(_root, dest); -#endif - return len; - } -}; - -typedef std::function ArJsonRequestHandlerFunction; - -class AsyncCallbackJsonWebHandler: public AsyncWebHandler { -private: -protected: - const String _uri; - WebRequestMethodComposite _method; - ArJsonRequestHandlerFunction _onRequest; - size_t _contentLength; -#ifndef ARDUINOJSON_5_COMPATIBILITY - const size_t maxJsonBufferSize; -#endif - size_t _maxContentLength; -public: -#ifdef ARDUINOJSON_5_COMPATIBILITY - AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest) - : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), _maxContentLength(16384) {} -#else - AsyncCallbackJsonWebHandler(const String& uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize=DYNAMIC_JSON_DOCUMENT_SIZE) - : _uri(uri), _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), _onRequest(onRequest), maxJsonBufferSize(maxJsonBufferSize), _maxContentLength(16384) {} -#endif - - void setMethod(WebRequestMethodComposite method){ _method = method; } - void setMaxContentLength(int maxContentLength){ _maxContentLength = maxContentLength; } - void onRequest(ArJsonRequestHandlerFunction fn){ _onRequest = fn; } - - virtual bool canHandle(AsyncWebServerRequest *request) override final{ - if(!_onRequest) - return false; - - if(!(_method & request->method())) - return false; - - if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) - return false; - - if ( !request->contentType().equalsIgnoreCase(JSON_MIMETYPE) ) - return false; - - request->addInterestingHeader("ANY"); - return true; - } - - virtual void handleRequest(AsyncWebServerRequest *request) override final { - if(_onRequest) { - if (request->_tempObject != NULL) { - -#ifdef ARDUINOJSON_5_COMPATIBILITY - DynamicJsonBuffer jsonBuffer; - JsonVariant json = jsonBuffer.parse((uint8_t*)(request->_tempObject)); - if (json.success()) { -#else - DynamicJsonDocument jsonBuffer(this->maxJsonBufferSize); - DeserializationError error = deserializeJson(jsonBuffer, (uint8_t*)(request->_tempObject)); - if(!error) { - JsonVariant json = jsonBuffer.as(); -#endif - - _onRequest(request, json); - return; - } - } - request->send(_contentLength > _maxContentLength ? 413 : 400); - } else { - request->send(500); - } - } - virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final { - } - virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { - if (_onRequest) { - _contentLength = total; - if (total > 0 && request->_tempObject == NULL && total < _maxContentLength) { - request->_tempObject = malloc(total); - } - if (request->_tempObject != NULL) { - memcpy((uint8_t*)(request->_tempObject) + index, data, len); - } - } - } - virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;} -}; -#endif diff --git a/lib/ESPAsyncWebServer/src/AsyncWebSocket.cpp b/lib/ESPAsyncWebServer/src/AsyncWebSocket.cpp deleted file mode 100644 index 52dcd75f..00000000 --- a/lib/ESPAsyncWebServer/src/AsyncWebSocket.cpp +++ /dev/null @@ -1,1303 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "Arduino.h" -#include "AsyncWebSocket.h" - -#include - -#ifndef ESP8266 -extern "C" { -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); -void SHA1Final(unsigned char digest[20], SHA1_CTX* context); -} -#else -#include -#endif - -#define MAX_PRINTF_LEN 64 - -size_t webSocketSendFrameWindow(AsyncClient *client){ - if(!client->canSend()) - return 0; - size_t space = client->space(); - if(space < 9) - return 0; - return space - 8; -} - -size_t webSocketSendFrame(AsyncClient *client, bool final, uint8_t opcode, bool mask, uint8_t *data, size_t len){ - if(!client->canSend()) - return 0; - size_t space = client->space(); - if(space < 2) - return 0; - uint8_t mbuf[4] = {0,0,0,0}; - uint8_t headLen = 2; - if(len && mask){ - headLen += 4; - mbuf[0] = rand() % 0xFF; - mbuf[1] = rand() % 0xFF; - mbuf[2] = rand() % 0xFF; - mbuf[3] = rand() % 0xFF; - } - if(len > 125) - headLen += 2; - if(space < headLen) - return 0; - space -= headLen; - - if(len > space) len = space; - - uint8_t *buf = (uint8_t*)malloc(headLen); - if(buf == NULL){ - //os_printf("could not malloc %u bytes for frame header\n", headLen); - return 0; - } - - buf[0] = opcode & 0x0F; - if(final) - buf[0] |= 0x80; - if(len < 126) - buf[1] = len & 0x7F; - else { - buf[1] = 126; - buf[2] = (uint8_t)((len >> 8) & 0xFF); - buf[3] = (uint8_t)(len & 0xFF); - } - if(len && mask){ - buf[1] |= 0x80; - memcpy(buf + (headLen - 4), mbuf, 4); - } - if(client->add((const char *)buf, headLen) != headLen){ - //os_printf("error adding %lu header bytes\n", headLen); - free(buf); - return 0; - } - free(buf); - - if(len){ - if(len && mask){ - size_t i; - for(i=0;iadd((const char *)data, len) != len){ - //os_printf("error adding %lu data bytes\n", len); - return 0; - } - } - if(!client->send()){ - //os_printf("error sending frame: %lu\n", headLen+len); - return 0; - } - return len; -} - - -/* - * AsyncWebSocketMessageBuffer - */ - - - -AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer() - :_data(nullptr) - ,_len(0) - ,_lock(false) - ,_count(0) -{ - -} - -AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(uint8_t * data, size_t size) - :_data(nullptr) - ,_len(size) - ,_lock(false) - ,_count(0) -{ - - if (!data) { - return; - } - - _data = new uint8_t[_len + 1]; - - if (_data) { - memcpy(_data, data, _len); - _data[_len] = 0; - } -} - - -AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(size_t size) - :_data(nullptr) - ,_len(size) - ,_lock(false) - ,_count(0) -{ - _data = new uint8_t[_len + 1]; - - if (_data) { - _data[_len] = 0; - } - -} - -AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(const AsyncWebSocketMessageBuffer & copy) - :_data(nullptr) - ,_len(0) - ,_lock(false) - ,_count(0) -{ - _len = copy._len; - _lock = copy._lock; - _count = 0; - - if (_len) { - _data = new uint8_t[_len + 1]; - _data[_len] = 0; - } - - if (_data) { - memcpy(_data, copy._data, _len); - _data[_len] = 0; - } - -} - -AsyncWebSocketMessageBuffer::AsyncWebSocketMessageBuffer(AsyncWebSocketMessageBuffer && copy) - :_data(nullptr) - ,_len(0) - ,_lock(false) - ,_count(0) -{ - _len = copy._len; - _lock = copy._lock; - _count = 0; - - if (copy._data) { - _data = copy._data; - copy._data = nullptr; - } - -} - -AsyncWebSocketMessageBuffer::~AsyncWebSocketMessageBuffer() -{ - if (_data) { - delete[] _data; - } -} - -bool AsyncWebSocketMessageBuffer::reserve(size_t size) -{ - _len = size; - - if (_data) { - delete[] _data; - _data = nullptr; - } - - _data = new uint8_t[_len + 1]; - - if (_data) { - _data[_len] = 0; - return true; - } else { - return false; - } - -} - - - -/* - * Control Frame - */ - -class AsyncWebSocketControl { - private: - uint8_t _opcode; - uint8_t *_data; - size_t _len; - bool _mask; - bool _finished; - public: - AsyncWebSocketControl(uint8_t opcode, uint8_t *data=NULL, size_t len=0, bool mask=false) - :_opcode(opcode) - ,_len(len) - ,_mask(len && mask) - ,_finished(false) - { - if(data == NULL) - _len = 0; - if(_len){ - if(_len > 125) - _len = 125; - _data = (uint8_t*)malloc(_len); - if(_data == NULL) - _len = 0; - else memcpy(_data, data, len); - } else _data = NULL; - } - virtual ~AsyncWebSocketControl(){ - if(_data != NULL) - free(_data); - } - virtual bool finished() const { return _finished; } - uint8_t opcode(){ return _opcode; } - uint8_t len(){ return _len + 2; } - size_t send(AsyncClient *client){ - _finished = true; - return webSocketSendFrame(client, true, _opcode & 0x0F, _mask, _data, _len); - } -}; - -/* - * Basic Buffered Message - */ - - -AsyncWebSocketBasicMessage::AsyncWebSocketBasicMessage(const char * data, size_t len, uint8_t opcode, bool mask) - :_len(len) - ,_sent(0) - ,_ack(0) - ,_acked(0) -{ - _opcode = opcode & 0x07; - _mask = mask; - _data = (uint8_t*)malloc(_len+1); - if(_data == NULL){ - _len = 0; - _status = WS_MSG_ERROR; - } else { - _status = WS_MSG_SENDING; - memcpy(_data, data, _len); - _data[_len] = 0; - } -} -AsyncWebSocketBasicMessage::AsyncWebSocketBasicMessage(uint8_t opcode, bool mask) - :_len(0) - ,_sent(0) - ,_ack(0) - ,_acked(0) - ,_data(NULL) -{ - _opcode = opcode & 0x07; - _mask = mask; - -} - - -AsyncWebSocketBasicMessage::~AsyncWebSocketBasicMessage() { - if(_data != NULL) - free(_data); -} - - void AsyncWebSocketBasicMessage::ack(size_t len, uint32_t time) { - (void)time; - _acked += len; - if(_sent == _len && _acked == _ack){ - _status = WS_MSG_SENT; - } -} - size_t AsyncWebSocketBasicMessage::send(AsyncClient *client) { - if(_status != WS_MSG_SENDING) - return 0; - if(_acked < _ack){ - return 0; - } - if(_sent == _len){ - if(_acked == _ack) - _status = WS_MSG_SENT; - return 0; - } - if(_sent > _len){ - _status = WS_MSG_ERROR; - return 0; - } - - size_t toSend = _len - _sent; - size_t window = webSocketSendFrameWindow(client); - - if(window < toSend) { - toSend = window; - } - - _sent += toSend; - _ack += toSend + ((toSend < 126)?2:4) + (_mask * 4); - - bool final = (_sent == _len); - uint8_t* dPtr = (uint8_t*)(_data + (_sent - toSend)); - uint8_t opCode = (toSend && _sent == toSend)?_opcode:(uint8_t)WS_CONTINUATION; - - size_t sent = webSocketSendFrame(client, final, opCode, _mask, dPtr, toSend); - _status = WS_MSG_SENDING; - if(toSend && sent != toSend){ - _sent -= (toSend - sent); - _ack -= (toSend - sent); - } - return sent; -} - -// bool AsyncWebSocketBasicMessage::reserve(size_t size) { -// if (size) { -// _data = (uint8_t*)malloc(size +1); -// if (_data) { -// memset(_data, 0, size); -// _len = size; -// _status = WS_MSG_SENDING; -// return true; -// } -// } -// return false; -// } - - -/* - * AsyncWebSocketMultiMessage Message - */ - - -AsyncWebSocketMultiMessage::AsyncWebSocketMultiMessage(AsyncWebSocketMessageBuffer * buffer, uint8_t opcode, bool mask) - :_len(0) - ,_sent(0) - ,_ack(0) - ,_acked(0) - ,_WSbuffer(nullptr) -{ - - _opcode = opcode & 0x07; - _mask = mask; - - if (buffer) { - _WSbuffer = buffer; - (*_WSbuffer)++; - _data = buffer->get(); - _len = buffer->length(); - _status = WS_MSG_SENDING; - //ets_printf("M: %u\n", _len); - } else { - _status = WS_MSG_ERROR; - } - -} - - -AsyncWebSocketMultiMessage::~AsyncWebSocketMultiMessage() { - if (_WSbuffer) { - (*_WSbuffer)--; // decreases the counter. - } -} - - void AsyncWebSocketMultiMessage::ack(size_t len, uint32_t time) { - (void)time; - _acked += len; - if(_sent >= _len && _acked >= _ack){ - _status = WS_MSG_SENT; - } - //ets_printf("A: %u\n", len); -} - size_t AsyncWebSocketMultiMessage::send(AsyncClient *client) { - if(_status != WS_MSG_SENDING) - return 0; - if(_acked < _ack){ - return 0; - } - if(_sent == _len){ - _status = WS_MSG_SENT; - return 0; - } - if(_sent > _len){ - _status = WS_MSG_ERROR; - //ets_printf("E: %u > %u\n", _sent, _len); - return 0; - } - - size_t toSend = _len - _sent; - size_t window = webSocketSendFrameWindow(client); - - if(window < toSend) { - toSend = window; - } - - _sent += toSend; - _ack += toSend + ((toSend < 126)?2:4) + (_mask * 4); - - //ets_printf("W: %u %u\n", _sent - toSend, toSend); - - bool final = (_sent == _len); - uint8_t* dPtr = (uint8_t*)(_data + (_sent - toSend)); - uint8_t opCode = (toSend && _sent == toSend)?_opcode:(uint8_t)WS_CONTINUATION; - - size_t sent = webSocketSendFrame(client, final, opCode, _mask, dPtr, toSend); - _status = WS_MSG_SENDING; - if(toSend && sent != toSend){ - //ets_printf("E: %u != %u\n", toSend, sent); - _sent -= (toSend - sent); - _ack -= (toSend - sent); - } - //ets_printf("S: %u %u\n", _sent, sent); - return sent; -} - - -/* - * Async WebSocket Client - */ - const char * AWSC_PING_PAYLOAD = "ESPAsyncWebServer-PING"; - const size_t AWSC_PING_PAYLOAD_LEN = 22; - -AsyncWebSocketClient::AsyncWebSocketClient(AsyncWebServerRequest *request, AsyncWebSocket *server) - : _controlQueue(LinkedList([](AsyncWebSocketControl *c){ delete c; })) - , _messageQueue(LinkedList([](AsyncWebSocketMessage *m){ delete m; })) - , _tempObject(NULL) -{ - _client = request->client(); - _server = server; - _clientId = _server->_getNextId(); - _status = WS_CONNECTED; - _pstate = 0; - _lastMessageTime = millis(); - _keepAlivePeriod = 0; - _client->setRxTimeout(0); - _client->onError([](void *r, AsyncClient* c, int8_t error){ (void)c; ((AsyncWebSocketClient*)(r))->_onError(error); }, this); - _client->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; ((AsyncWebSocketClient*)(r))->_onAck(len, time); }, this); - _client->onDisconnect([](void *r, AsyncClient* c){ ((AsyncWebSocketClient*)(r))->_onDisconnect(); delete c; }, this); - _client->onTimeout([](void *r, AsyncClient* c, uint32_t time){ (void)c; ((AsyncWebSocketClient*)(r))->_onTimeout(time); }, this); - _client->onData([](void *r, AsyncClient* c, void *buf, size_t len){ (void)c; ((AsyncWebSocketClient*)(r))->_onData(buf, len); }, this); - _client->onPoll([](void *r, AsyncClient* c){ (void)c; ((AsyncWebSocketClient*)(r))->_onPoll(); }, this); - _server->_addClient(this); - _server->_handleEvent(this, WS_EVT_CONNECT, request, NULL, 0); - delete request; -} - -AsyncWebSocketClient::~AsyncWebSocketClient(){ - _messageQueue.free(); - _controlQueue.free(); - _server->_handleEvent(this, WS_EVT_DISCONNECT, NULL, NULL, 0); -} - -void AsyncWebSocketClient::_onAck(size_t len, uint32_t time){ - _lastMessageTime = millis(); - if(!_controlQueue.isEmpty()){ - auto head = _controlQueue.front(); - if(head->finished()){ - len -= head->len(); - if(_status == WS_DISCONNECTING && head->opcode() == WS_DISCONNECT){ - _controlQueue.remove(head); - _status = WS_DISCONNECTED; - _client->close(true); - return; - } - _controlQueue.remove(head); - } - } - if(len && !_messageQueue.isEmpty()){ - _messageQueue.front()->ack(len, time); - } - _server->_cleanBuffers(); - _runQueue(); -} - -void AsyncWebSocketClient::_onPoll(){ - if(_client->canSend() && (!_controlQueue.isEmpty() || !_messageQueue.isEmpty())){ - _runQueue(); - } else if(_keepAlivePeriod > 0 && _controlQueue.isEmpty() && _messageQueue.isEmpty() && (millis() - _lastMessageTime) >= _keepAlivePeriod){ - ping((uint8_t *)AWSC_PING_PAYLOAD, AWSC_PING_PAYLOAD_LEN); - } -} - -void AsyncWebSocketClient::_runQueue(){ - while(!_messageQueue.isEmpty() && _messageQueue.front()->finished()){ - _messageQueue.remove(_messageQueue.front()); - } - - if(!_controlQueue.isEmpty() && (_messageQueue.isEmpty() || _messageQueue.front()->betweenFrames()) && webSocketSendFrameWindow(_client) > (size_t)(_controlQueue.front()->len() - 1)){ - _controlQueue.front()->send(_client); - } else if(!_messageQueue.isEmpty() && _messageQueue.front()->betweenFrames() && webSocketSendFrameWindow(_client)){ - _messageQueue.front()->send(_client); - } -} - -bool AsyncWebSocketClient::queueIsFull(){ - if((_messageQueue.length() >= WS_MAX_QUEUED_MESSAGES) || (_status != WS_CONNECTED) ) return true; - return false; -} - -void AsyncWebSocketClient::_queueMessage(AsyncWebSocketMessage *dataMessage){ - if(dataMessage == NULL) - return; - if(_status != WS_CONNECTED){ - delete dataMessage; - return; - } - if(_messageQueue.length() >= WS_MAX_QUEUED_MESSAGES){ - ets_printf("ERROR: Too many messages queued\n"); - delete dataMessage; - } else { - _messageQueue.add(dataMessage); - } - if(_client->canSend()) - _runQueue(); -} - -void AsyncWebSocketClient::_queueControl(AsyncWebSocketControl *controlMessage){ - if(controlMessage == NULL) - return; - _controlQueue.add(controlMessage); - if(_client->canSend()) - _runQueue(); -} - -void AsyncWebSocketClient::close(uint16_t code, const char * message){ - if(_status != WS_CONNECTED) - return; - if(code){ - uint8_t packetLen = 2; - if(message != NULL){ - size_t mlen = strlen(message); - if(mlen > 123) mlen = 123; - packetLen += mlen; - } - char * buf = (char*)malloc(packetLen); - if(buf != NULL){ - buf[0] = (uint8_t)(code >> 8); - buf[1] = (uint8_t)(code & 0xFF); - if(message != NULL){ - memcpy(buf+2, message, packetLen -2); - } - _queueControl(new AsyncWebSocketControl(WS_DISCONNECT,(uint8_t*)buf,packetLen)); - free(buf); - return; - } - } - _queueControl(new AsyncWebSocketControl(WS_DISCONNECT)); -} - -void AsyncWebSocketClient::ping(uint8_t *data, size_t len){ - if(_status == WS_CONNECTED) - _queueControl(new AsyncWebSocketControl(WS_PING, data, len)); -} - -void AsyncWebSocketClient::_onError(int8_t){} - -void AsyncWebSocketClient::_onTimeout(uint32_t time){ - (void)time; - _client->close(true); -} - -void AsyncWebSocketClient::_onDisconnect(){ - _client = NULL; - _server->_handleDisconnect(this); -} - -void AsyncWebSocketClient::_onData(void *pbuf, size_t plen){ - _lastMessageTime = millis(); - uint8_t *data = (uint8_t*)pbuf; - while(plen > 0){ - if(!_pstate){ - const uint8_t *fdata = data; - _pinfo.index = 0; - _pinfo.final = (fdata[0] & 0x80) != 0; - _pinfo.opcode = fdata[0] & 0x0F; - _pinfo.masked = (fdata[1] & 0x80) != 0; - _pinfo.len = fdata[1] & 0x7F; - data += 2; - plen -= 2; - if(_pinfo.len == 126){ - _pinfo.len = fdata[3] | (uint16_t)(fdata[2]) << 8; - data += 2; - plen -= 2; - } else if(_pinfo.len == 127){ - _pinfo.len = fdata[9] | (uint16_t)(fdata[8]) << 8 | (uint32_t)(fdata[7]) << 16 | (uint32_t)(fdata[6]) << 24 | (uint64_t)(fdata[5]) << 32 | (uint64_t)(fdata[4]) << 40 | (uint64_t)(fdata[3]) << 48 | (uint64_t)(fdata[2]) << 56; - data += 8; - plen -= 8; - } - - if(_pinfo.masked){ - memcpy(_pinfo.mask, data, 4); - data += 4; - plen -= 4; - } - } - - const size_t datalen = std::min((size_t)(_pinfo.len - _pinfo.index), plen); - const auto datalast = data[datalen]; - - if(_pinfo.masked){ - for(size_t i=0;i_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, (uint8_t*)data, datalen); - - _pinfo.index += datalen; - } else if((datalen + _pinfo.index) == _pinfo.len){ - _pstate = 0; - if(_pinfo.opcode == WS_DISCONNECT){ - if(datalen){ - uint16_t reasonCode = (uint16_t)(data[0] << 8) + data[1]; - char * reasonString = (char*)(data+2); - if(reasonCode > 1001){ - _server->_handleEvent(this, WS_EVT_ERROR, (void *)&reasonCode, (uint8_t*)reasonString, strlen(reasonString)); - } - } - if(_status == WS_DISCONNECTING){ - _status = WS_DISCONNECTED; - _client->close(true); - } else { - _status = WS_DISCONNECTING; - _client->ackLater(); - _queueControl(new AsyncWebSocketControl(WS_DISCONNECT, data, datalen)); - } - } else if(_pinfo.opcode == WS_PING){ - _queueControl(new AsyncWebSocketControl(WS_PONG, data, datalen)); - } else if(_pinfo.opcode == WS_PONG){ - if(datalen != AWSC_PING_PAYLOAD_LEN || memcmp(AWSC_PING_PAYLOAD, data, AWSC_PING_PAYLOAD_LEN) != 0) - _server->_handleEvent(this, WS_EVT_PONG, NULL, data, datalen); - } else if(_pinfo.opcode < 8){//continuation or text/binary frame - _server->_handleEvent(this, WS_EVT_DATA, (void *)&_pinfo, data, datalen); - } - } else { - //os_printf("frame error: len: %u, index: %llu, total: %llu\n", datalen, _pinfo.index, _pinfo.len); - //what should we do? - break; - } - - // restore byte as _handleEvent may have added a null terminator i.e., data[len] = 0; - if (datalen > 0) - data[datalen] = datalast; - - data += datalen; - plen -= datalen; - } -} - -size_t AsyncWebSocketClient::printf(const char *format, ...) { - va_list arg; - va_start(arg, format); - char* temp = new char[MAX_PRINTF_LEN]; - if(!temp){ - va_end(arg); - return 0; - } - char* buffer = temp; - size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg); - va_end(arg); - - if (len > (MAX_PRINTF_LEN - 1)) { - buffer = new char[len + 1]; - if (!buffer) { - delete[] temp; - return 0; - } - va_start(arg, format); - vsnprintf(buffer, len + 1, format, arg); - va_end(arg); - } - text(buffer, len); - if (buffer != temp) { - delete[] buffer; - } - delete[] temp; - return len; -} - -#ifndef ESP32 -size_t AsyncWebSocketClient::printf_P(PGM_P formatP, ...) { - va_list arg; - va_start(arg, formatP); - char* temp = new char[MAX_PRINTF_LEN]; - if(!temp){ - va_end(arg); - return 0; - } - char* buffer = temp; - size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg); - va_end(arg); - - if (len > (MAX_PRINTF_LEN - 1)) { - buffer = new char[len + 1]; - if (!buffer) { - delete[] temp; - return 0; - } - va_start(arg, formatP); - vsnprintf_P(buffer, len + 1, formatP, arg); - va_end(arg); - } - text(buffer, len); - if (buffer != temp) { - delete[] buffer; - } - delete[] temp; - return len; -} -#endif - -void AsyncWebSocketClient::text(const char * message, size_t len){ - _queueMessage(new AsyncWebSocketBasicMessage(message, len)); -} -void AsyncWebSocketClient::text(const char * message){ - text(message, strlen(message)); -} -void AsyncWebSocketClient::text(uint8_t * message, size_t len){ - text((const char *)message, len); -} -void AsyncWebSocketClient::text(char * message){ - text(message, strlen(message)); -} -void AsyncWebSocketClient::text(const String &message){ - text(message.c_str(), message.length()); -} -void AsyncWebSocketClient::text(const __FlashStringHelper *data){ - PGM_P p = reinterpret_cast(data); - size_t n = 0; - while (1) { - if (pgm_read_byte(p+n) == 0) break; - n += 1; - } - char * message = (char*) malloc(n+1); - if(message){ - for(size_t b=0; b(data); - char * message = (char*) malloc(len); - if(message){ - for(size_t b=0; bremoteIP(); -} - -uint16_t AsyncWebSocketClient::remotePort() { - if(!_client) { - return 0; - } - return _client->remotePort(); -} - - - -/* - * Async Web Socket - Each separate socket location - */ - -AsyncWebSocket::AsyncWebSocket(const String& url) - :_url(url) - ,_clients(LinkedList([](AsyncWebSocketClient *c){ delete c; })) - ,_cNextId(1) - ,_enabled(true) - ,_buffers(LinkedList([](AsyncWebSocketMessageBuffer *b){ delete b; })) -{ - _eventHandler = NULL; -} - -AsyncWebSocket::~AsyncWebSocket(){} - -void AsyncWebSocket::_handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ - if(_eventHandler != NULL){ - _eventHandler(this, client, type, arg, data, len); - } -} - -void AsyncWebSocket::_addClient(AsyncWebSocketClient * client){ - _clients.add(client); -} - -void AsyncWebSocket::_handleDisconnect(AsyncWebSocketClient * client){ - - _clients.remove_first([=](AsyncWebSocketClient * c){ - return c->id() == client->id(); - }); -} - -bool AsyncWebSocket::availableForWriteAll(){ - for(const auto& c: _clients){ - if(c->queueIsFull()) return false; - } - return true; -} - -bool AsyncWebSocket::availableForWrite(uint32_t id){ - for(const auto& c: _clients){ - if(c->queueIsFull() && (c->id() == id )) return false; - } - return true; -} - -size_t AsyncWebSocket::count() const { - return _clients.count_if([](AsyncWebSocketClient * c){ - return c->status() == WS_CONNECTED; - }); -} - -AsyncWebSocketClient * AsyncWebSocket::client(uint32_t id){ - for(const auto &c: _clients){ - if(c->id() == id && c->status() == WS_CONNECTED){ - return c; - } - } - return nullptr; -} - - -void AsyncWebSocket::close(uint32_t id, uint16_t code, const char * message){ - AsyncWebSocketClient * c = client(id); - if(c) - c->close(code, message); -} - -void AsyncWebSocket::closeAll(uint16_t code, const char * message){ - for(const auto& c: _clients){ - if(c->status() == WS_CONNECTED) - c->close(code, message); - } -} - -void AsyncWebSocket::cleanupClients(uint16_t maxClients) -{ - if (count() > maxClients){ - _clients.front()->close(); - } -} - -void AsyncWebSocket::ping(uint32_t id, uint8_t *data, size_t len){ - AsyncWebSocketClient * c = client(id); - if(c) - c->ping(data, len); -} - -void AsyncWebSocket::pingAll(uint8_t *data, size_t len){ - for(const auto& c: _clients){ - if(c->status() == WS_CONNECTED) - c->ping(data, len); - } -} - -void AsyncWebSocket::text(uint32_t id, const char * message, size_t len){ - AsyncWebSocketClient * c = client(id); - if(c) - c->text(message, len); -} - -void AsyncWebSocket::textAll(AsyncWebSocketMessageBuffer * buffer){ - if (!buffer) return; - buffer->lock(); - for(const auto& c: _clients){ - if(c->status() == WS_CONNECTED){ - c->text(buffer); - } - } - buffer->unlock(); - _cleanBuffers(); -} - - -void AsyncWebSocket::textAll(const char * message, size_t len){ - AsyncWebSocketMessageBuffer * WSBuffer = makeBuffer((uint8_t *)message, len); - textAll(WSBuffer); -} - -void AsyncWebSocket::binary(uint32_t id, const char * message, size_t len){ - AsyncWebSocketClient * c = client(id); - if(c) - c->binary(message, len); -} - -void AsyncWebSocket::binaryAll(const char * message, size_t len){ - AsyncWebSocketMessageBuffer * buffer = makeBuffer((uint8_t *)message, len); - binaryAll(buffer); -} - -void AsyncWebSocket::binaryAll(AsyncWebSocketMessageBuffer * buffer) -{ - if (!buffer) return; - buffer->lock(); - for(const auto& c: _clients){ - if(c->status() == WS_CONNECTED) - c->binary(buffer); - } - buffer->unlock(); - _cleanBuffers(); -} - -void AsyncWebSocket::message(uint32_t id, AsyncWebSocketMessage *message){ - AsyncWebSocketClient * c = client(id); - if(c) - c->message(message); -} - -void AsyncWebSocket::messageAll(AsyncWebSocketMultiMessage *message){ - for(const auto& c: _clients){ - if(c->status() == WS_CONNECTED) - c->message(message); - } - _cleanBuffers(); -} - -size_t AsyncWebSocket::printf(uint32_t id, const char *format, ...){ - AsyncWebSocketClient * c = client(id); - if(c){ - va_list arg; - va_start(arg, format); - size_t len = c->printf(format, arg); - va_end(arg); - return len; - } - return 0; -} - -size_t AsyncWebSocket::printfAll(const char *format, ...) { - va_list arg; - char* temp = new char[MAX_PRINTF_LEN]; - if(!temp){ - return 0; - } - va_start(arg, format); - size_t len = vsnprintf(temp, MAX_PRINTF_LEN, format, arg); - va_end(arg); - delete[] temp; - - AsyncWebSocketMessageBuffer * buffer = makeBuffer(len); - if (!buffer) { - return 0; - } - - va_start(arg, format); - vsnprintf( (char *)buffer->get(), len + 1, format, arg); - va_end(arg); - - textAll(buffer); - return len; -} - -#ifndef ESP32 -size_t AsyncWebSocket::printf_P(uint32_t id, PGM_P formatP, ...){ - AsyncWebSocketClient * c = client(id); - if(c != NULL){ - va_list arg; - va_start(arg, formatP); - size_t len = c->printf_P(formatP, arg); - va_end(arg); - return len; - } - return 0; -} -#endif - -size_t AsyncWebSocket::printfAll_P(PGM_P formatP, ...) { - va_list arg; - char* temp = new char[MAX_PRINTF_LEN]; - if(!temp){ - return 0; - } - va_start(arg, formatP); - size_t len = vsnprintf_P(temp, MAX_PRINTF_LEN, formatP, arg); - va_end(arg); - delete[] temp; - - AsyncWebSocketMessageBuffer * buffer = makeBuffer(len + 1); - if (!buffer) { - return 0; - } - - va_start(arg, formatP); - vsnprintf_P((char *)buffer->get(), len + 1, formatP, arg); - va_end(arg); - - textAll(buffer); - return len; -} - -void AsyncWebSocket::text(uint32_t id, const char * message){ - text(id, message, strlen(message)); -} -void AsyncWebSocket::text(uint32_t id, uint8_t * message, size_t len){ - text(id, (const char *)message, len); -} -void AsyncWebSocket::text(uint32_t id, char * message){ - text(id, message, strlen(message)); -} -void AsyncWebSocket::text(uint32_t id, const String &message){ - text(id, message.c_str(), message.length()); -} -void AsyncWebSocket::text(uint32_t id, const __FlashStringHelper *message){ - AsyncWebSocketClient * c = client(id); - if(c != NULL) - c->text(message); -} -void AsyncWebSocket::textAll(const char * message){ - textAll(message, strlen(message)); -} -void AsyncWebSocket::textAll(uint8_t * message, size_t len){ - textAll((const char *)message, len); -} -void AsyncWebSocket::textAll(char * message){ - textAll(message, strlen(message)); -} -void AsyncWebSocket::textAll(const String &message){ - textAll(message.c_str(), message.length()); -} -void AsyncWebSocket::textAll(const __FlashStringHelper *message){ - for(const auto& c: _clients){ - if(c->status() == WS_CONNECTED) - c->text(message); - } -} -void AsyncWebSocket::binary(uint32_t id, const char * message){ - binary(id, message, strlen(message)); -} -void AsyncWebSocket::binary(uint32_t id, uint8_t * message, size_t len){ - binary(id, (const char *)message, len); -} -void AsyncWebSocket::binary(uint32_t id, char * message){ - binary(id, message, strlen(message)); -} -void AsyncWebSocket::binary(uint32_t id, const String &message){ - binary(id, message.c_str(), message.length()); -} -void AsyncWebSocket::binary(uint32_t id, const __FlashStringHelper *message, size_t len){ - AsyncWebSocketClient * c = client(id); - if(c != NULL) - c-> binary(message, len); -} -void AsyncWebSocket::binaryAll(const char * message){ - binaryAll(message, strlen(message)); -} -void AsyncWebSocket::binaryAll(uint8_t * message, size_t len){ - binaryAll((const char *)message, len); -} -void AsyncWebSocket::binaryAll(char * message){ - binaryAll(message, strlen(message)); -} -void AsyncWebSocket::binaryAll(const String &message){ - binaryAll(message.c_str(), message.length()); -} -void AsyncWebSocket::binaryAll(const __FlashStringHelper *message, size_t len){ - for(const auto& c: _clients){ - if(c->status() == WS_CONNECTED) - c-> binary(message, len); - } - } - -const char * WS_STR_CONNECTION = "Connection"; -const char * WS_STR_UPGRADE = "Upgrade"; -const char * WS_STR_ORIGIN = "Origin"; -const char * WS_STR_VERSION = "Sec-WebSocket-Version"; -const char * WS_STR_KEY = "Sec-WebSocket-Key"; -const char * WS_STR_PROTOCOL = "Sec-WebSocket-Protocol"; -const char * WS_STR_ACCEPT = "Sec-WebSocket-Accept"; -const char * WS_STR_UUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - -bool AsyncWebSocket::canHandle(AsyncWebServerRequest *request){ - if(!_enabled) - return false; - - if(request->method() != HTTP_GET || !request->url().equals(_url) || !request->isExpectedRequestedConnType(RCT_WS)) - return false; - - request->addInterestingHeader(WS_STR_CONNECTION); - request->addInterestingHeader(WS_STR_UPGRADE); - request->addInterestingHeader(WS_STR_ORIGIN); - request->addInterestingHeader(WS_STR_VERSION); - request->addInterestingHeader(WS_STR_KEY); - request->addInterestingHeader(WS_STR_PROTOCOL); - return true; -} - -void AsyncWebSocket::handleRequest(AsyncWebServerRequest *request){ - if(!request->hasHeader(WS_STR_VERSION) || !request->hasHeader(WS_STR_KEY)){ - request->send(400); - return; - } - if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())){ - return request->requestAuthentication(); - } - AsyncWebHeader* version = request->getHeader(WS_STR_VERSION); - if(version->value().toInt() != 13){ - AsyncWebServerResponse *response = request->beginResponse(400); - response->addHeader(WS_STR_VERSION,"13"); - request->send(response); - return; - } - AsyncWebHeader* key = request->getHeader(WS_STR_KEY); - AsyncWebServerResponse *response = new AsyncWebSocketResponse(key->value(), this); - if(request->hasHeader(WS_STR_PROTOCOL)){ - AsyncWebHeader* protocol = request->getHeader(WS_STR_PROTOCOL); - //ToDo: check protocol - response->addHeader(WS_STR_PROTOCOL, protocol->value()); - } - request->send(response); -} - -AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(size_t size) -{ - AsyncWebSocketMessageBuffer * buffer = new AsyncWebSocketMessageBuffer(size); - if (buffer) { - AsyncWebLockGuard l(_lock); - _buffers.add(buffer); - } - return buffer; -} - -AsyncWebSocketMessageBuffer * AsyncWebSocket::makeBuffer(uint8_t * data, size_t size) -{ - AsyncWebSocketMessageBuffer * buffer = new AsyncWebSocketMessageBuffer(data, size); - - if (buffer) { - AsyncWebLockGuard l(_lock); - _buffers.add(buffer); - } - - return buffer; -} - -void AsyncWebSocket::_cleanBuffers() -{ - AsyncWebLockGuard l(_lock); - - for(AsyncWebSocketMessageBuffer * c: _buffers){ - if(c && c->canDelete()){ - _buffers.remove(c); - } - } -} - -AsyncWebSocket::AsyncWebSocketClientLinkedList AsyncWebSocket::getClients() const { - return _clients; -} - -/* - * Response to Web Socket request - sends the authorization and detaches the TCP Client from the web server - * Authentication code from https://github.com/Links2004/arduinoWebSockets/blob/master/src/WebSockets.cpp#L480 - */ - -AsyncWebSocketResponse::AsyncWebSocketResponse(const String& key, AsyncWebSocket *server){ - _server = server; - _code = 101; - _sendContentLength = false; - - uint8_t * hash = (uint8_t*)malloc(20); - if(hash == NULL){ - _state = RESPONSE_FAILED; - return; - } - char * buffer = (char *) malloc(33); - if(buffer == NULL){ - free(hash); - _state = RESPONSE_FAILED; - return; - } -#ifdef ESP8266 - sha1(key + WS_STR_UUID, hash); -#else - (String&)key += WS_STR_UUID; - SHA1_CTX ctx; - SHA1Init(&ctx); - SHA1Update(&ctx, (const unsigned char*)key.c_str(), key.length()); - SHA1Final(hash, &ctx); -#endif - base64_encodestate _state; - base64_init_encodestate(&_state); - int len = base64_encode_block((const char *) hash, 20, buffer, &_state); - len = base64_encode_blockend((buffer + len), &_state); - addHeader(WS_STR_CONNECTION, WS_STR_UPGRADE); - addHeader(WS_STR_UPGRADE, "websocket"); - addHeader(WS_STR_ACCEPT,buffer); - free(buffer); - free(hash); -} - -void AsyncWebSocketResponse::_respond(AsyncWebServerRequest *request){ - if(_state == RESPONSE_FAILED){ - request->client()->close(true); - return; - } - String out = _assembleHead(request->version()); - request->client()->write(out.c_str(), _headLength); - _state = RESPONSE_WAIT_ACK; -} - -size_t AsyncWebSocketResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ - (void)time; - if(len){ - new AsyncWebSocketClient(request, _server); - } - return 0; -} diff --git a/lib/ESPAsyncWebServer/src/AsyncWebSocket.h b/lib/ESPAsyncWebServer/src/AsyncWebSocket.h deleted file mode 100644 index 5b03aceb..00000000 --- a/lib/ESPAsyncWebServer/src/AsyncWebSocket.h +++ /dev/null @@ -1,350 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef ASYNCWEBSOCKET_H_ -#define ASYNCWEBSOCKET_H_ - -#include -#ifdef ESP32 -#include -#define WS_MAX_QUEUED_MESSAGES 32 -#else -#include -#define WS_MAX_QUEUED_MESSAGES 8 -#endif -#include - -#include "AsyncWebSynchronization.h" - -#ifdef ESP8266 -#include -#ifdef CRYPTO_HASH_h // include Hash.h from espressif framework if the first include was from the crypto library -#include <../src/Hash.h> -#endif -#endif - -#ifdef ESP32 -#define DEFAULT_MAX_WS_CLIENTS 8 -#else -#define DEFAULT_MAX_WS_CLIENTS 4 -#endif - -class AsyncWebSocket; -class AsyncWebSocketResponse; -class AsyncWebSocketClient; -class AsyncWebSocketControl; - -typedef struct { - /** Message type as defined by enum AwsFrameType. - * Note: Applications will only see WS_TEXT and WS_BINARY. - * All other types are handled by the library. */ - uint8_t message_opcode; - /** Frame number of a fragmented message. */ - uint32_t num; - /** Is this the last frame in a fragmented message ?*/ - uint8_t final; - /** Is this frame masked? */ - uint8_t masked; - /** Message type as defined by enum AwsFrameType. - * This value is the same as message_opcode for non-fragmented - * messages, but may also be WS_CONTINUATION in a fragmented message. */ - uint8_t opcode; - /** Length of the current frame. - * This equals the total length of the message if num == 0 && final == true */ - uint64_t len; - /** Mask key */ - uint8_t mask[4]; - /** Offset of the data inside the current frame. */ - uint64_t index; -} AwsFrameInfo; - -typedef enum { WS_DISCONNECTED, WS_CONNECTED, WS_DISCONNECTING } AwsClientStatus; -typedef enum { WS_CONTINUATION, WS_TEXT, WS_BINARY, WS_DISCONNECT = 0x08, WS_PING, WS_PONG } AwsFrameType; -typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus; -typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType; - -class AsyncWebSocketMessageBuffer { - private: - uint8_t * _data; - size_t _len; - bool _lock; - uint32_t _count; - - public: - AsyncWebSocketMessageBuffer(); - AsyncWebSocketMessageBuffer(size_t size); - AsyncWebSocketMessageBuffer(uint8_t * data, size_t size); - AsyncWebSocketMessageBuffer(const AsyncWebSocketMessageBuffer &); - AsyncWebSocketMessageBuffer(AsyncWebSocketMessageBuffer &&); - ~AsyncWebSocketMessageBuffer(); - void operator ++(int i) { (void)i; _count++; } - void operator --(int i) { (void)i; if (_count > 0) { _count--; } ; } - bool reserve(size_t size); - void lock() { _lock = true; } - void unlock() { _lock = false; } - uint8_t * get() { return _data; } - size_t length() { return _len; } - uint32_t count() { return _count; } - bool canDelete() { return (!_count && !_lock); } - - friend AsyncWebSocket; - -}; - -class AsyncWebSocketMessage { - protected: - uint8_t _opcode; - bool _mask; - AwsMessageStatus _status; - public: - AsyncWebSocketMessage():_opcode(WS_TEXT),_mask(false),_status(WS_MSG_ERROR){} - virtual ~AsyncWebSocketMessage(){} - virtual void ack(size_t len __attribute__((unused)), uint32_t time __attribute__((unused))){} - virtual size_t send(AsyncClient *client __attribute__((unused))){ return 0; } - virtual bool finished(){ return _status != WS_MSG_SENDING; } - virtual bool betweenFrames() const { return false; } -}; - -class AsyncWebSocketBasicMessage: public AsyncWebSocketMessage { - private: - size_t _len; - size_t _sent; - size_t _ack; - size_t _acked; - uint8_t * _data; -public: - AsyncWebSocketBasicMessage(const char * data, size_t len, uint8_t opcode=WS_TEXT, bool mask=false); - AsyncWebSocketBasicMessage(uint8_t opcode=WS_TEXT, bool mask=false); - virtual ~AsyncWebSocketBasicMessage() override; - virtual bool betweenFrames() const override { return _acked == _ack; } - virtual void ack(size_t len, uint32_t time) override ; - virtual size_t send(AsyncClient *client) override ; -}; - -class AsyncWebSocketMultiMessage: public AsyncWebSocketMessage { - private: - uint8_t * _data; - size_t _len; - size_t _sent; - size_t _ack; - size_t _acked; - AsyncWebSocketMessageBuffer * _WSbuffer; -public: - AsyncWebSocketMultiMessage(AsyncWebSocketMessageBuffer * buffer, uint8_t opcode=WS_TEXT, bool mask=false); - virtual ~AsyncWebSocketMultiMessage() override; - virtual bool betweenFrames() const override { return _acked == _ack; } - virtual void ack(size_t len, uint32_t time) override ; - virtual size_t send(AsyncClient *client) override ; -}; - -class AsyncWebSocketClient { - private: - AsyncClient *_client; - AsyncWebSocket *_server; - uint32_t _clientId; - AwsClientStatus _status; - - LinkedList _controlQueue; - LinkedList _messageQueue; - - uint8_t _pstate; - AwsFrameInfo _pinfo; - - uint32_t _lastMessageTime; - uint32_t _keepAlivePeriod; - - void _queueMessage(AsyncWebSocketMessage *dataMessage); - void _queueControl(AsyncWebSocketControl *controlMessage); - void _runQueue(); - - public: - void *_tempObject; - - AsyncWebSocketClient(AsyncWebServerRequest *request, AsyncWebSocket *server); - ~AsyncWebSocketClient(); - - //client id increments for the given server - uint32_t id(){ return _clientId; } - AwsClientStatus status(){ return _status; } - AsyncClient* client(){ return _client; } - AsyncWebSocket *server(){ return _server; } - AwsFrameInfo const &pinfo() const { return _pinfo; } - - IPAddress remoteIP(); - uint16_t remotePort(); - - //control frames - void close(uint16_t code=0, const char * message=NULL); - void ping(uint8_t *data=NULL, size_t len=0); - - //set auto-ping period in seconds. disabled if zero (default) - void keepAlivePeriod(uint16_t seconds){ - _keepAlivePeriod = seconds * 1000; - } - uint16_t keepAlivePeriod(){ - return (uint16_t)(_keepAlivePeriod / 1000); - } - - //data packets - void message(AsyncWebSocketMessage *message){ _queueMessage(message); } - bool queueIsFull(); - - size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3))); -#ifndef ESP32 - size_t printf_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); -#endif - void text(const char * message, size_t len); - void text(const char * message); - void text(uint8_t * message, size_t len); - void text(char * message); - void text(const String &message); - void text(const __FlashStringHelper *data); - void text(AsyncWebSocketMessageBuffer *buffer); - - void binary(const char * message, size_t len); - void binary(const char * message); - void binary(uint8_t * message, size_t len); - void binary(char * message); - void binary(const String &message); - void binary(const __FlashStringHelper *data, size_t len); - void binary(AsyncWebSocketMessageBuffer *buffer); - - bool canSend() { return _messageQueue.length() < WS_MAX_QUEUED_MESSAGES; } - - //system callbacks (do not call) - void _onAck(size_t len, uint32_t time); - void _onError(int8_t); - void _onPoll(); - void _onTimeout(uint32_t time); - void _onDisconnect(); - void _onData(void *pbuf, size_t plen); -}; - -typedef std::function AwsEventHandler; - -//WebServer Handler implementation that plays the role of a socket server -class AsyncWebSocket: public AsyncWebHandler { - public: - typedef LinkedList AsyncWebSocketClientLinkedList; - private: - String _url; - AsyncWebSocketClientLinkedList _clients; - uint32_t _cNextId; - AwsEventHandler _eventHandler; - bool _enabled; - AsyncWebLock _lock; - - public: - AsyncWebSocket(const String& url); - ~AsyncWebSocket(); - const char * url() const { return _url.c_str(); } - void enable(bool e){ _enabled = e; } - bool enabled() const { return _enabled; } - bool availableForWriteAll(); - bool availableForWrite(uint32_t id); - - size_t count() const; - AsyncWebSocketClient * client(uint32_t id); - bool hasClient(uint32_t id){ return client(id) != NULL; } - - void close(uint32_t id, uint16_t code=0, const char * message=NULL); - void closeAll(uint16_t code=0, const char * message=NULL); - void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS); - - void ping(uint32_t id, uint8_t *data=NULL, size_t len=0); - void pingAll(uint8_t *data=NULL, size_t len=0); // done - - void text(uint32_t id, const char * message, size_t len); - void text(uint32_t id, const char * message); - void text(uint32_t id, uint8_t * message, size_t len); - void text(uint32_t id, char * message); - void text(uint32_t id, const String &message); - void text(uint32_t id, const __FlashStringHelper *message); - - void textAll(const char * message, size_t len); - void textAll(const char * message); - void textAll(uint8_t * message, size_t len); - void textAll(char * message); - void textAll(const String &message); - void textAll(const __FlashStringHelper *message); // need to convert - void textAll(AsyncWebSocketMessageBuffer * buffer); - - void binary(uint32_t id, const char * message, size_t len); - void binary(uint32_t id, const char * message); - void binary(uint32_t id, uint8_t * message, size_t len); - void binary(uint32_t id, char * message); - void binary(uint32_t id, const String &message); - void binary(uint32_t id, const __FlashStringHelper *message, size_t len); - - void binaryAll(const char * message, size_t len); - void binaryAll(const char * message); - void binaryAll(uint8_t * message, size_t len); - void binaryAll(char * message); - void binaryAll(const String &message); - void binaryAll(const __FlashStringHelper *message, size_t len); - void binaryAll(AsyncWebSocketMessageBuffer * buffer); - - void message(uint32_t id, AsyncWebSocketMessage *message); - void messageAll(AsyncWebSocketMultiMessage *message); - - size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4))); - size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3))); -#ifndef ESP32 - size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__ ((format (printf, 3, 4))); -#endif - size_t printfAll_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3))); - - //event listener - void onEvent(AwsEventHandler handler){ - _eventHandler = handler; - } - - //system callbacks (do not call) - uint32_t _getNextId(){ return _cNextId++; } - void _addClient(AsyncWebSocketClient * client); - void _handleDisconnect(AsyncWebSocketClient * client); - void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len); - virtual bool canHandle(AsyncWebServerRequest *request) override final; - virtual void handleRequest(AsyncWebServerRequest *request) override final; - - - // messagebuffer functions/objects. - AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0); - AsyncWebSocketMessageBuffer * makeBuffer(uint8_t * data, size_t size); - LinkedList _buffers; - void _cleanBuffers(); - - AsyncWebSocketClientLinkedList getClients() const; -}; - -//WebServer response to authenticate the socket and detach the tcp client from the web server request -class AsyncWebSocketResponse: public AsyncWebServerResponse { - private: - String _content; - AsyncWebSocket *_server; - public: - AsyncWebSocketResponse(const String& key, AsyncWebSocket *server); - void _respond(AsyncWebServerRequest *request); - size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); - bool _sourceValid() const { return true; } -}; - - -#endif /* ASYNCWEBSOCKET_H_ */ diff --git a/lib/ESPAsyncWebServer/src/AsyncWebSynchronization.h b/lib/ESPAsyncWebServer/src/AsyncWebSynchronization.h deleted file mode 100644 index f36c52dc..00000000 --- a/lib/ESPAsyncWebServer/src/AsyncWebSynchronization.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef ASYNCWEBSYNCHRONIZATION_H_ -#define ASYNCWEBSYNCHRONIZATION_H_ - -// Synchronisation is only available on ESP32, as the ESP8266 isn't using FreeRTOS by default - -#include - -#ifdef ESP32 - -// This is the ESP32 version of the Sync Lock, using the FreeRTOS Semaphore -class AsyncWebLock -{ -private: - SemaphoreHandle_t _lock; - mutable void *_lockedBy; - -public: - AsyncWebLock() { - _lock = xSemaphoreCreateBinary(); - _lockedBy = NULL; - xSemaphoreGive(_lock); - } - - ~AsyncWebLock() { - vSemaphoreDelete(_lock); - } - - bool lock() const { - extern void *pxCurrentTCB; - if (_lockedBy != pxCurrentTCB) { - xSemaphoreTake(_lock, portMAX_DELAY); - _lockedBy = pxCurrentTCB; - return true; - } - return false; - } - - void unlock() const { - _lockedBy = NULL; - xSemaphoreGive(_lock); - } -}; - -#else - -// This is the 8266 version of the Sync Lock which is currently unimplemented -class AsyncWebLock -{ - -public: - AsyncWebLock() { - } - - ~AsyncWebLock() { - } - - bool lock() const { - return false; - } - - void unlock() const { - } -}; -#endif - -class AsyncWebLockGuard -{ -private: - const AsyncWebLock *_lock; - -public: - AsyncWebLockGuard(const AsyncWebLock &l) { - if (l.lock()) { - _lock = &l; - } else { - _lock = NULL; - } - } - - ~AsyncWebLockGuard() { - if (_lock) { - _lock->unlock(); - } - } -}; - -#endif // ASYNCWEBSYNCHRONIZATION_H_ \ No newline at end of file diff --git a/lib/ESPAsyncWebServer/src/ESPAsyncWebServer.h b/lib/ESPAsyncWebServer/src/ESPAsyncWebServer.h deleted file mode 100644 index 3b2fbd96..00000000 --- a/lib/ESPAsyncWebServer/src/ESPAsyncWebServer.h +++ /dev/null @@ -1,501 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef _ESPAsyncWebServer_H_ -#define _ESPAsyncWebServer_H_ - -#include - -#include "Arduino.h" -#include "FS.h" -#include "StringArray.h" - -#ifdef ESP32 -#include -#include -#elif defined(ESP8266) -#include -#include -#else -#error Platform not supported -#endif - -#ifdef ASYNCWEBSERVER_REGEX -#define ASYNCWEBSERVER_REGEX_ATTRIBUTE -#else -#define ASYNCWEBSERVER_REGEX_ATTRIBUTE __attribute__((warning("ASYNCWEBSERVER_REGEX not defined"))) -#endif - -#define DEBUGF(...) //Serial.printf(__VA_ARGS__) - -class AsyncWebServer; -class AsyncWebServerRequest; -class AsyncWebServerResponse; -class AsyncWebHeader; -class AsyncWebParameter; -class AsyncWebRewrite; -class AsyncWebHandler; -class AsyncStaticWebHandler; -class AsyncCallbackWebHandler; -class AsyncResponseStream; - -#ifdef ESP32 -#ifdef WEBSERVER_H -#define HTTP_ENUM -#endif -#elif defined(ESP8266) -#ifdef ESP8266WEBSERVER_H -#define HTTP_ENUM -#endif -#endif - -#ifndef HTTP_ENUM -typedef enum { HTTP_GET = 0b00000001, - HTTP_POST = 0b00000010, - HTTP_DELETE = 0b00000100, - HTTP_PUT = 0b00001000, - HTTP_PATCH = 0b00010000, - HTTP_HEAD = 0b00100000, - HTTP_OPTIONS = 0b01000000, - HTTP_ANY = 0b01111111, -} WebRequestMethod; -#endif - -//if this value is returned when asked for data, packet will not be sent and you will be asked for data again -#define RESPONSE_TRY_AGAIN 0xFFFFFFFF - -typedef uint8_t WebRequestMethodComposite; -typedef std::function ArDisconnectHandler; - -/* - * PARAMETER :: Chainable object to hold GET/POST and FILE parameters - * */ - -class AsyncWebParameter { - private: - String _name; - String _value; - size_t _size; - bool _isForm; - bool _isFile; - - public: - AsyncWebParameter(const String& name, const String& value, bool form = false, bool file = false, size_t size = 0) : _name(name), _value(value), _size(size), _isForm(form), _isFile(file) {} - const String& name() const { return _name; } - const String& value() const { return _value; } - size_t size() const { return _size; } - bool isPost() const { return _isForm; } - bool isFile() const { return _isFile; } -}; - -/* - * HEADER :: Chainable object to hold the headers - * */ - -class AsyncWebHeader { - private: - String _name; - String _value; - - public: - AsyncWebHeader(const String& name, const String& value) : _name(name), _value(value) {} - AsyncWebHeader(const String& data) : _name(), _value() { - if (!data) return; - int index = data.indexOf(':'); - if (index < 0) return; - _name = data.substring(0, index); - _value = data.substring(index + 2); - } - ~AsyncWebHeader() {} - const String& name() const { return _name; } - const String& value() const { return _value; } - String toString() const { return String(_name + ": " + _value + "\r\n"); } -}; - -/* - * REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect - * */ - -typedef enum { RCT_NOT_USED = -1, - RCT_DEFAULT = 0, - RCT_HTTP, - RCT_WS, - RCT_EVENT, - RCT_MAX } RequestedConnectionType; - -typedef std::function AwsResponseFiller; -typedef std::function AwsTemplateProcessor; - -class AsyncWebServerRequest { - using File = fs::File; - using FS = fs::FS; - friend class AsyncWebServer; - friend class AsyncCallbackWebHandler; - - private: - AsyncClient* _client; - AsyncWebServer* _server; - AsyncWebHandler* _handler; - AsyncWebServerResponse* _response; - StringArray _interestingHeaders; - ArDisconnectHandler _onDisconnectfn; - - String _temp; - uint8_t _parseState; - - uint8_t _version; - WebRequestMethodComposite _method; - String _url; - String _host; - String _contentType; - String _boundary; - String _authorization; - RequestedConnectionType _reqconntype; - void _removeNotInterestingHeaders(); - bool _isDigest; - bool _isMultipart; - bool _isPlainPost; - bool _expectingContinue; - size_t _contentLength; - size_t _parsedLength; - - LinkedList _headers; - LinkedList _params; - LinkedList _pathParams; - - uint8_t _multiParseState; - uint8_t _boundaryPosition; - size_t _itemStartIndex; - size_t _itemSize; - String _itemName; - String _itemFilename; - String _itemType; - String _itemValue; - uint8_t* _itemBuffer; - size_t _itemBufferIndex; - bool _itemIsFile; - - void _onPoll(); - void _onAck(size_t len, uint32_t time); - void _onError(int8_t error); - void _onTimeout(uint32_t time); - void _onDisconnect(); - void _onData(void* buf, size_t len); - - void _addParam(AsyncWebParameter*); - void _addPathParam(const char* param); - - bool _parseReqHead(); - bool _parseReqHeader(); - void _parseLine(); - void _parsePlainPostChar(uint8_t data); - void _parseMultipartPostByte(uint8_t data, bool last); - void _addGetParams(const String& params); - - void _handleUploadStart(); - void _handleUploadByte(uint8_t data, bool last); - void _handleUploadEnd(); - - public: - File _tempFile; - void* _tempObject; - - AsyncWebServerRequest(AsyncWebServer*, AsyncClient*); - ~AsyncWebServerRequest(); - - AsyncClient* client() { return _client; } - uint8_t version() const { return _version; } - WebRequestMethodComposite method() const { return _method; } - const String& url() const { return _url; } - const String& host() const { return _host; } - const String& contentType() const { return _contentType; } - size_t contentLength() const { return _contentLength; } - bool multipart() const { return _isMultipart; } - const char* methodToString() const; - const char* requestedConnTypeToString() const; - RequestedConnectionType requestedConnType() const { return _reqconntype; } - bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED); - void onDisconnect(ArDisconnectHandler fn); - - //hash is the string representation of: - // base64(user:pass) for basic or - // user:realm:md5(user:realm:pass) for digest - bool authenticate(const char* hash); - bool authenticate(const char* username, const char* password, const char* realm = NULL, bool passwordIsHash = false); - void requestAuthentication(const char* realm = NULL, bool isDigest = true); - - void setHandler(AsyncWebHandler* handler) { _handler = handler; } - void addInterestingHeader(const String& name); - - void redirect(const String& url); - - void send(AsyncWebServerResponse* response); - void send(int code, const String& contentType = String(), const String& content = String()); - void send(FS& fs, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); - void send(File content, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); - void send(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr); - void send(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); - void sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); - void send_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr); - void send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr); - - AsyncWebServerResponse* beginResponse(int code, const String& contentType = String(), const String& content = String()); - AsyncWebServerResponse* beginResponse(FS& fs, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); - AsyncWebServerResponse* beginResponse(File content, const String& path, const String& contentType = String(), bool download = false, AwsTemplateProcessor callback = nullptr); - AsyncWebServerResponse* beginResponse(Stream& stream, const String& contentType, size_t len, AwsTemplateProcessor callback = nullptr); - AsyncWebServerResponse* beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); - AsyncWebServerResponse* beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr); - AsyncResponseStream* beginResponseStream(const String& contentType, size_t bufferSize = 1460); - AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr); - AsyncWebServerResponse* beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback = nullptr); - - size_t headers() const; // get header count - bool hasHeader(const String& name) const; // check if header exists - bool hasHeader(const __FlashStringHelper* data) const; // check if header exists - - AsyncWebHeader* getHeader(const String& name) const; - AsyncWebHeader* getHeader(const __FlashStringHelper* data) const; - AsyncWebHeader* getHeader(size_t num) const; - - size_t params() const; // get arguments count - bool hasParam(const String& name, bool post = false, bool file = false) const; - bool hasParam(const __FlashStringHelper* data, bool post = false, bool file = false) const; - - AsyncWebParameter* getParam(const String& name, bool post = false, bool file = false) const; - AsyncWebParameter* getParam(const __FlashStringHelper* data, bool post, bool file) const; - AsyncWebParameter* getParam(size_t num) const; - - size_t args() const { return params(); } // get arguments count - const String& arg(const String& name) const; // get request argument value by name - const String& arg(const __FlashStringHelper* data) const; // get request argument value by F(name) - const String& arg(size_t i) const; // get request argument value by number - const String& argName(size_t i) const; // get request argument name by number - bool hasArg(const char* name) const; // check if argument exists - bool hasArg(const __FlashStringHelper* data) const; // check if F(argument) exists - - const String& ASYNCWEBSERVER_REGEX_ATTRIBUTE pathArg(size_t i) const; - - const String& header(const char* name) const; // get request header value by name - const String& header(const __FlashStringHelper* data) const; // get request header value by F(name) - const String& header(size_t i) const; // get request header value by number - const String& headerName(size_t i) const; // get request header name by number - String urlDecode(const String& text) const; -}; - -/* - * FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server) - * */ - -typedef std::function ArRequestFilterFunction; - -bool ON_STA_FILTER(AsyncWebServerRequest* request); - -bool ON_AP_FILTER(AsyncWebServerRequest* request); - -/* - * REWRITE :: One instance can be handle any Request (done by the Server) - * */ - -class AsyncWebRewrite { - protected: - String _from; - String _toUrl; - String _params; - ArRequestFilterFunction _filter; - - public: - AsyncWebRewrite(const char* from, const char* to) : _from(from), _toUrl(to), _params(String()), _filter(NULL) { - int index = _toUrl.indexOf('?'); - if (index > 0) { - _params = _toUrl.substring(index + 1); - _toUrl = _toUrl.substring(0, index); - } - } - virtual ~AsyncWebRewrite() {} - AsyncWebRewrite& setFilter(ArRequestFilterFunction fn) { - _filter = fn; - return *this; - } - bool filter(AsyncWebServerRequest* request) const { return _filter == NULL || _filter(request); } - const String& from(void) const { return _from; } - const String& toUrl(void) const { return _toUrl; } - const String& params(void) const { return _params; } - virtual bool match(AsyncWebServerRequest* request) { return from() == request->url() && filter(request); } -}; - -/* - * HANDLER :: One instance can be attached to any Request (done by the Server) - * */ - -class AsyncWebHandler { - protected: - ArRequestFilterFunction _filter; - String _username; - String _password; - - public: - AsyncWebHandler() : _username(""), _password("") {} - AsyncWebHandler& setFilter(ArRequestFilterFunction fn) { - _filter = fn; - return *this; - } - AsyncWebHandler& setAuthentication(const char* username, const char* password) { - _username = String(username); - _password = String(password); - return *this; - }; - bool filter(AsyncWebServerRequest* request) { return _filter == NULL || _filter(request); } - virtual ~AsyncWebHandler() {} - virtual bool canHandle(AsyncWebServerRequest* request __attribute__((unused))) { - return false; - } - virtual void handleRequest(AsyncWebServerRequest* request __attribute__((unused))) {} - virtual void handleUpload(AsyncWebServerRequest* request __attribute__((unused)), const String& filename __attribute__((unused)), size_t index __attribute__((unused)), uint8_t* data __attribute__((unused)), size_t len __attribute__((unused)), bool final __attribute__((unused))) {} - virtual void handleBody(AsyncWebServerRequest* request __attribute__((unused)), uint8_t* data __attribute__((unused)), size_t len __attribute__((unused)), size_t index __attribute__((unused)), size_t total __attribute__((unused))) {} - virtual bool isRequestHandlerTrivial() { return true; } -}; - -/* - * RESPONSE :: One instance is created for each Request (attached by the Handler) - * */ - -typedef enum { - RESPONSE_SETUP, - RESPONSE_HEADERS, - RESPONSE_CONTENT, - RESPONSE_WAIT_ACK, - RESPONSE_END, - RESPONSE_FAILED -} WebResponseState; - -class AsyncWebServerResponse { - protected: - int _code; - LinkedList _headers; - String _contentType; - size_t _contentLength; - bool _sendContentLength; - bool _chunked; - size_t _headLength; - size_t _sentLength; - size_t _ackedLength; - size_t _writtenLength; - WebResponseState _state; - const char* _responseCodeToString(int code); - - public: - AsyncWebServerResponse(); - virtual ~AsyncWebServerResponse(); - virtual void setCode(int code); - virtual void setContentLength(size_t len); - virtual void setContentType(const String& type); - virtual void addHeader(const String& name, const String& value); - virtual String _assembleHead(uint8_t version); - virtual bool _started() const; - virtual bool _finished() const; - virtual bool _failed() const; - virtual bool _sourceValid() const; - virtual void _respond(AsyncWebServerRequest* request); - virtual size_t _ack(AsyncWebServerRequest* request, size_t len, uint32_t time); -}; - -/* - * SERVER :: One instance - * */ - -typedef std::function ArRequestHandlerFunction; -typedef std::function ArUploadHandlerFunction; -typedef std::function ArBodyHandlerFunction; - -class AsyncWebServer { - protected: - AsyncServer _server; - LinkedList _rewrites; - LinkedList _handlers; - AsyncCallbackWebHandler* _catchAllHandler; - - public: - AsyncWebServer(uint16_t port); - ~AsyncWebServer(); - - void begin(); - void end(); - -#if ASYNC_TCP_SSL_ENABLED - void onSslFileRequest(AcSSlFileHandler cb, void* arg); - void beginSecure(const char* cert, const char* private_key_file, const char* password); -#endif - - AsyncWebRewrite& addRewrite(AsyncWebRewrite* rewrite); - bool removeRewrite(AsyncWebRewrite* rewrite); - AsyncWebRewrite& rewrite(const char* from, const char* to); - - AsyncWebHandler& addHandler(AsyncWebHandler* handler); - bool removeHandler(AsyncWebHandler* handler); - - AsyncCallbackWebHandler& on(const char* uri, ArRequestHandlerFunction onRequest); - AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest); - AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload); - AsyncCallbackWebHandler& on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody); - - AsyncStaticWebHandler& serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control = NULL); - - void onNotFound(ArRequestHandlerFunction fn); //called when handler is not assigned - void onFileUpload(ArUploadHandlerFunction fn); //handle file uploads - void onRequestBody(ArBodyHandlerFunction fn); //handle posts with plain body content (JSON often transmitted this way as a request) - - void reset(); //remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody - - void _handleDisconnect(AsyncWebServerRequest* request); - void _attachHandler(AsyncWebServerRequest* request); - void _rewriteRequest(AsyncWebServerRequest* request); -}; - -class DefaultHeaders { - using headers_t = LinkedList; - headers_t _headers; - - DefaultHeaders() - : _headers(headers_t([](AsyncWebHeader* h) { delete h; })) {} - - public: - using ConstIterator = headers_t::ConstIterator; - - void addHeader(const String& name, const String& value) { - _headers.add(new AsyncWebHeader(name, value)); - } - - ConstIterator begin() const { return _headers.begin(); } - ConstIterator end() const { return _headers.end(); } - - DefaultHeaders(DefaultHeaders const&) = delete; - DefaultHeaders& operator=(DefaultHeaders const&) = delete; - static DefaultHeaders& Instance() { - static DefaultHeaders instance; - return instance; - } -}; - -#include "AsyncEventSource.h" -#include "AsyncWebSocket.h" -#include "WebHandlerImpl.h" -#include "WebResponseImpl.h" - -#endif /* _AsyncWebServer_H_ */ diff --git a/lib/ESPAsyncWebServer/src/SPIFFSEditor.cpp b/lib/ESPAsyncWebServer/src/SPIFFSEditor.cpp deleted file mode 100644 index a84fa87d..00000000 --- a/lib/ESPAsyncWebServer/src/SPIFFSEditor.cpp +++ /dev/null @@ -1,544 +0,0 @@ -#include "SPIFFSEditor.h" -#include - -//File: edit.htm.gz, Size: 4151 -#define edit_htm_gz_len 4151 -const uint8_t edit_htm_gz[] PROGMEM = { - 0x1F, 0x8B, 0x08, 0x08, 0xB8, 0x94, 0xB1, 0x59, 0x00, 0x03, 0x65, 0x64, 0x69, 0x74, 0x2E, 0x68, - 0x74, 0x6D, 0x00, 0xB5, 0x3A, 0x0B, 0x7B, 0xDA, 0xB8, 0xB2, 0x7F, 0xC5, 0x71, 0xCF, 0x66, 0xED, - 0x83, 0x31, 0x90, 0xA4, 0xD9, 0xD6, 0xC4, 0xC9, 0x42, 0x92, 0x36, 0x6D, 0xF3, 0x6A, 0x80, 0xB6, - 0x69, 0x4F, 0xEE, 0x7E, 0xC2, 0x16, 0xA0, 0xC6, 0x96, 0x5D, 0x5B, 0x0E, 0x49, 0x59, 0xFE, 0xFB, - 0x9D, 0x91, 0x6C, 0xB0, 0x09, 0x69, 0x77, 0xCF, 0xBD, 0xBB, 0xDD, 0x2D, 0x92, 0x46, 0x33, 0x9A, - 0x19, 0xCD, 0x53, 0xDE, 0xBD, 0x8D, 0xA3, 0x8B, 0xC3, 0xFE, 0xF5, 0xE5, 0xB1, 0x36, 0x11, 0x61, - 0xB0, 0xBF, 0x87, 0x7F, 0x6B, 0x01, 0xE1, 0x63, 0x97, 0xF2, 0xFD, 0x3D, 0xC1, 0x44, 0x40, 0xF7, - 0x8F, 0x7B, 0x97, 0xDA, 0xB1, 0xCF, 0x44, 0x94, 0xEC, 0x35, 0xD4, 0xCA, 0x5E, 0x2A, 0x1E, 0x02, - 0xAA, 0x85, 0xD4, 0x67, 0xC4, 0x4D, 0xBD, 0x84, 0xC2, 0x66, 0xDB, 0x0B, 0x67, 0xDF, 0xEB, 0x8C, - 0xFB, 0xF4, 0xDE, 0xD9, 0x6E, 0x36, 0xDB, 0x71, 0x94, 0x32, 0xC1, 0x22, 0xEE, 0x90, 0x61, 0x1A, - 0x05, 0x99, 0xA0, 0xED, 0x80, 0x8E, 0x84, 0xF3, 0x3C, 0xBE, 0x6F, 0x0F, 0xA3, 0xC4, 0xA7, 0x89, - 0xD3, 0x8A, 0xEF, 0x35, 0x00, 0x31, 0x5F, 0x7B, 0xB6, 0xB3, 0xB3, 0xD3, 0x1E, 0x12, 0xEF, 0x76, - 0x9C, 0x44, 0x19, 0xF7, 0xEB, 0x5E, 0x14, 0x44, 0x89, 0xF3, 0x6C, 0xF4, 0x1C, 0xFF, 0xB4, 0x7D, - 0x96, 0xC6, 0x01, 0x79, 0x70, 0x78, 0xC4, 0x29, 0xE0, 0xDE, 0xD7, 0xD3, 0x09, 0xF1, 0xA3, 0xA9, - 0xD3, 0xD4, 0x9A, 0x5A, 0xAB, 0x09, 0x44, 0x92, 0xF1, 0x90, 0x18, 0x4D, 0x0B, 0xFF, 0xD8, 0x3B, - 0x66, 0x7B, 0x14, 0x71, 0x51, 0x4F, 0xD9, 0x77, 0xEA, 0xB4, 0xB6, 0xE0, 0x34, 0x39, 0x1D, 0x91, - 0x90, 0x05, 0x0F, 0x4E, 0x4A, 0x78, 0x5A, 0x4F, 0x69, 0xC2, 0x46, 0x6A, 0x79, 0x4A, 0xD9, 0x78, - 0x22, 0x9C, 0xDF, 0x9A, 0xCD, 0x39, 0xF0, 0xAF, 0x65, 0xC1, 0x2C, 0x60, 0x29, 0x20, 0xA3, 0x78, - 0xEA, 0x3C, 0x11, 0xC5, 0x4E, 0x53, 0xB1, 0xDE, 0x6C, 0x87, 0x24, 0x19, 0x33, 0x0E, 0x83, 0x98, - 0xF8, 0x3E, 0xE3, 0x63, 0x47, 0xA1, 0x05, 0x6C, 0xB6, 0x90, 0x36, 0xA1, 0x01, 0x11, 0xEC, 0x8E, - 0xB6, 0x43, 0xC6, 0xEB, 0x53, 0xE6, 0x8B, 0x89, 0xB3, 0x0B, 0x3C, 0xB6, 0xBD, 0x2C, 0x49, 0x41, - 0xA6, 0x38, 0x62, 0x5C, 0xD0, 0x44, 0xA2, 0xA5, 0x31, 0xE1, 0xB3, 0x5C, 0x54, 0x54, 0x40, 0x21, - 0x27, 0xE3, 0x01, 0xE3, 0xB4, 0x3E, 0x0C, 0x22, 0xEF, 0x76, 0x71, 0xD2, 0x6E, 0x7C, 0x9F, 0x9F, - 0xE5, 0x4C, 0xA2, 0x3B, 0x9A, 0xCC, 0x96, 0xEA, 0x92, 0xD8, 0x15, 0x60, 0x85, 0x34, 0xA5, 0x74, - 0x6E, 0x8B, 0xBB, 0x0C, 0xA0, 0x96, 0xFC, 0x05, 0x29, 0x17, 0xFC, 0x2F, 0x45, 0x5A, 0x11, 0x5C, - 0xA1, 0x30, 0x1E, 0x67, 0x62, 0xF6, 0xF8, 0x2A, 0xA3, 0x98, 0x78, 0x4C, 0x3C, 0xA0, 0xFC, 0xB0, - 0x6D, 0x86, 0xBA, 0x04, 0xAC, 0x24, 0x24, 0x81, 0x86, 0x3A, 0xD7, 0x3E, 0xD0, 0xC4, 0x27, 0x9C, - 0x58, 0x9D, 0x84, 0x91, 0xC0, 0xEA, 0x2D, 0xB5, 0x5E, 0x0F, 0xA3, 0xEF, 0xF5, 0x0C, 0xC6, 0x30, - 0x0F, 0xA8, 0x27, 0x94, 0x92, 0xE1, 0x1E, 0x86, 0xB7, 0x4C, 0x3C, 0x06, 0x3C, 0x5A, 0x28, 0xA9, - 0x4B, 0x2A, 0x69, 0xA2, 0x2E, 0xB0, 0x25, 0xD5, 0x83, 0x1C, 0x4B, 0xC9, 0x95, 0x50, 0xF5, 0x61, - 0x24, 0x44, 0x14, 0x4A, 0x93, 0x5B, 0x08, 0xAC, 0x49, 0xAB, 0x79, 0xF1, 0xE8, 0x46, 0xD6, 0x6B, - 0xBF, 0x44, 0xBE, 0x0D, 0x7A, 0x15, 0xCC, 0x23, 0x41, 0x9D, 0x04, 0x6C, 0xCC, 0x9D, 0x90, 0xF9, - 0x7E, 0x40, 0x4B, 0x56, 0xEB, 0x64, 0x49, 0x60, 0xF8, 0x44, 0x10, 0x87, 0x85, 0x64, 0x4C, 0x1B, - 0x31, 0x1F, 0x03, 0x34, 0xA5, 0xBB, 0x3B, 0x16, 0xFB, 0xD0, 0xBD, 0xB8, 0x9A, 0x36, 0xDF, 0xBD, - 0x1E, 0x47, 0x1D, 0xF8, 0xE7, 0xBC, 0x37, 0x98, 0x1C, 0x0F, 0xC6, 0x30, 0xEA, 0xE2, 0xB4, 0xF3, - 0xFE, 0xB0, 0xF3, 0x1E, 0x7E, 0x0E, 0x5B, 0xB5, 0xAF, 0xA3, 0x6F, 0xB8, 0xD0, 0x7D, 0xED, 0x77, - 0xFB, 0x83, 0xE3, 0x4E, 0xE7, 0x5D, 0xE3, 0xCD, 0xF9, 0xF4, 0xE3, 0xBB, 0x5D, 0x04, 0x77, 0x83, - 0xE6, 0xD5, 0x87, 0x49, 0x73, 0xB0, 0xF5, 0x32, 0xF4, 0x4F, 0xFC, 0x89, 0x17, 0x0E, 0x3A, 0xEF, - 0x3F, 0x5E, 0xDD, 0x5D, 0x87, 0x83, 0x71, 0xEF, 0x63, 0x6B, 0xF2, 0x79, 0xEB, 0x43, 0xEF, 0xF3, - 0xC7, 0x57, 0xB7, 0xF4, 0xD3, 0xC9, 0xDB, 0xCF, 0xFD, 0x29, 0x20, 0x1C, 0x45, 0xBD, 0xC1, 0x55, - 0xF7, 0x43, 0x77, 0xFC, 0xB9, 0xEB, 0x1D, 0xDF, 0x0F, 0x83, 0xF3, 0xEE, 0xEB, 0xCE, 0xB0, 0xB3, - 0xE5, 0x51, 0x3A, 0xEE, 0x5F, 0x75, 0xB3, 0x37, 0xEF, 0x2E, 0xC6, 0x8C, 0x4D, 0x7A, 0x9F, 0xCF, - 0xFB, 0xDE, 0xE1, 0xF3, 0xD3, 0xC1, 0x49, 0x87, 0x4D, 0xCE, 0xDF, 0x5E, 0x35, 0x6F, 0x5F, 0xBF, - 0x3B, 0x3C, 0xF2, 0xAE, 0xDF, 0x5E, 0xEF, 0x1E, 0x6D, 0x37, 0x7E, 0xFB, 0xED, 0xCC, 0xBF, 0x60, - 0xBC, 0x7F, 0xF7, 0xBD, 0x33, 0x3E, 0x9C, 0xBE, 0x78, 0x48, 0xFB, 0x93, 0x37, 0x77, 0xBC, 0xF1, - 0x21, 0xFA, 0xFA, 0xE6, 0xE1, 0x0C, 0xFE, 0xBB, 0xBC, 0xAC, 0x0D, 0x7B, 0xAD, 0x74, 0xF0, 0xFE, - 0xCD, 0x87, 0xAD, 0xF4, 0xE5, 0xF3, 0xB8, 0x7B, 0x74, 0x74, 0x17, 0x0E, 0x2F, 0x1B, 0xA1, 0x7F, - 0x3B, 0x12, 0x2F, 0xB6, 0x45, 0x7C, 0x3D, 0xCE, 0x3E, 0x7F, 0x7B, 0xFE, 0x76, 0xD2, 0xB8, 0xA0, - 0xE4, 0x7A, 0x52, 0x7B, 0xF8, 0xFE, 0xF0, 0x62, 0xD2, 0x3F, 0xB9, 0x3B, 0x0F, 0xC8, 0xFD, 0xF9, - 0xB9, 0xF7, 0x3D, 0xAC, 0x05, 0xE4, 0xE5, 0x45, 0x3F, 0x20, 0x49, 0x6B, 0xE0, 0x77, 0x1A, 0xB5, - 0xC3, 0xAD, 0xCE, 0x8E, 0x48, 0xAE, 0x0E, 0xF9, 0xD1, 0xF6, 0xD7, 0xDE, 0x8B, 0x6E, 0xB7, 0x15, - 0x0D, 0xBF, 0x6D, 0xBD, 0xBE, 0xDD, 0x7D, 0x3D, 0xD8, 0x7D, 0x3F, 0x7C, 0xDF, 0xE9, 0xED, 0x74, - 0x07, 0xE4, 0xBA, 0xF7, 0xBE, 0x33, 0xDA, 0x19, 0x4E, 0x26, 0xEF, 0xDE, 0xF5, 0x5F, 0xF9, 0x9D, - 0xEF, 0x49, 0xE7, 0x62, 0xDA, 0xB9, 0x3F, 0x1E, 0x74, 0x4E, 0x6A, 0xEF, 0x8E, 0xCF, 0x9A, 0xAD, - 0xDE, 0xF5, 0xF6, 0xF8, 0x6C, 0x77, 0xDA, 0x4D, 0x8F, 0x3B, 0xEF, 0xBB, 0xCD, 0xF1, 0xDB, 0x5A, - 0x48, 0x3E, 0x47, 0x87, 0xDB, 0xE3, 0x37, 0xBB, 0xEC, 0xF2, 0x9A, 0x74, 0xDE, 0x74, 0xDF, 0xA6, - 0xEC, 0x2A, 0x3C, 0x19, 0x34, 0x3B, 0x9D, 0xD3, 0x0B, 0xFA, 0xEA, 0x70, 0x9B, 0xBC, 0xDB, 0xF2, - 0x3E, 0x82, 0xFE, 0x07, 0x9F, 0xE8, 0x6F, 0xB5, 0xCE, 0xF4, 0xA2, 0x19, 0x78, 0x2F, 0x69, 0xFF, - 0xE4, 0xBA, 0x2F, 0x6F, 0xE7, 0x38, 0x78, 0xD5, 0xBF, 0xED, 0x65, 0xEF, 0xC3, 0xC3, 0x43, 0x53, - 0xE3, 0x51, 0x3D, 0xA1, 0x31, 0x25, 0xA2, 0x1C, 0xAE, 0x16, 0xFE, 0x01, 0xB6, 0xB5, 0xB4, 0xC2, - 0xDC, 0x4F, 0x05, 0xBD, 0x17, 0x75, 0x9F, 0x7A, 0x51, 0x42, 0xE4, 0x1E, 0x40, 0xA0, 0x09, 0x9A, - 0xD8, 0xFC, 0x77, 0x19, 0x3F, 0x35, 0x15, 0x3F, 0x35, 0xC2, 0x7D, 0xCD, 0x28, 0x1C, 0x01, 0x83, - 0x87, 0x4F, 0xEF, 0x98, 0x47, 0xEB, 0x31, 0xBB, 0xA7, 0x41, 0x5D, 0x22, 0x3B, 0x4D, 0x73, 0x26, - 0xFD, 0xAD, 0xD8, 0x46, 0x38, 0x98, 0x9A, 0xA4, 0x5A, 0x2C, 0xF8, 0x5F, 0x89, 0x47, 0x21, 0xB0, - 0x81, 0xCB, 0x84, 0xF8, 0xAB, 0x7C, 0x27, 0x4A, 0xEA, 0xC3, 0x6C, 0x3C, 0x62, 0xF7, 0xE0, 0xD0, - 0x23, 0xC6, 0x99, 0xA0, 0x5A, 0x2B, 0x9D, 0xFF, 0x5E, 0x90, 0xB9, 0xA5, 0x0F, 0xA3, 0x84, 0x84, - 0x34, 0xD5, 0xFE, 0x22, 0x99, 0xD9, 0x28, 0x89, 0xC2, 0x65, 0x10, 0x99, 0x8B, 0xA8, 0x34, 0x99, - 0xCF, 0x9F, 0x65, 0x71, 0x10, 0x11, 0x10, 0x73, 0x4D, 0xE4, 0x50, 0xF1, 0x34, 0x91, 0x6E, 0xB5, - 0x88, 0xAB, 0xB9, 0x9B, 0x6D, 0xA1, 0x5B, 0x96, 0xDD, 0x7A, 0x6B, 0x67, 0xE9, 0xBA, 0x75, 0xB9, - 0x17, 0xE3, 0xFD, 0x9A, 0x4C, 0x81, 0xF1, 0xA0, 0x14, 0xEE, 0x9E, 0x09, 0x50, 0xE9, 0x13, 0x87, - 0xCB, 0x43, 0xF2, 0xC8, 0xB0, 0x60, 0x40, 0x05, 0xEA, 0x96, 0x8C, 0xD4, 0x85, 0x24, 0xB0, 0x6F, - 0xFE, 0x8C, 0xCA, 0xBC, 0x67, 0x3D, 0x8B, 0x13, 0xB8, 0x0D, 0x3A, 0xFD, 0x11, 0xCD, 0x42, 0xA6, - 0x2A, 0x6D, 0x45, 0x53, 0x65, 0xBC, 0x5C, 0x84, 0x65, 0xDA, 0x93, 0xBC, 0x16, 0xA4, 0x1F, 0x4B, - 0x05, 0xE0, 0x05, 0x37, 0xCF, 0x91, 0x9B, 0x1F, 0x6A, 0x75, 0x7B, 0xF7, 0x97, 0x9C, 0x87, 0x9D, - 0xE6, 0x2F, 0x73, 0x3B, 0xDF, 0x5B, 0xA4, 0xE4, 0x56, 0x13, 0xFE, 0x29, 0x32, 0xEF, 0x8B, 0x25, - 0x0B, 0xC3, 0xE7, 0xF8, 0xA7, 0x60, 0x10, 0xE9, 0x94, 0x80, 0xDB, 0x3B, 0x2F, 0x5F, 0xF8, 0xC3, - 0x02, 0x98, 0x0B, 0xF6, 0x24, 0x3C, 0x21, 0x3E, 0xCB, 0x52, 0xE7, 0x79, 0xF3, 0x97, 0x5C, 0x9F, - 0x5B, 0x3B, 0x28, 0xFB, 0xE2, 0x2E, 0x71, 0xB2, 0xB4, 0xD8, 0x34, 0x66, 0x5C, 0xDB, 0x4A, 0x35, - 0xBC, 0x6F, 0x92, 0x2C, 0x0C, 0xB3, 0x92, 0xED, 0xE7, 0xBF, 0x2F, 0x4D, 0x13, 0xF7, 0xCF, 0x9A, - 0xBF, 0xCC, 0x44, 0x02, 0xD9, 0x64, 0x04, 0xB9, 0xC6, 0x49, 0x22, 0x41, 0x04, 0x35, 0x9A, 0xE6, - 0x1C, 0x84, 0x5B, 0x03, 0xD8, 0xDE, 0x6D, 0xFA, 0x74, 0x6C, 0xCE, 0xE7, 0x7B, 0x0D, 0x99, 0xD7, - 0xA0, 0x6C, 0xF1, 0x12, 0x16, 0x8B, 0xFD, 0x51, 0xC6, 0x3D, 0xE4, 0x41, 0x1B, 0x53, 0x83, 0x9A, - 0xB3, 0x84, 0x8A, 0x2C, 0xE1, 0x9A, 0x1F, 0x79, 0x19, 0x1A, 0xBB, 0x3D, 0xA6, 0xE2, 0x58, 0xD9, - 0x7D, 0xF7, 0xE1, 0x8D, 0x0F, 0x3B, 0xE6, 0x0B, 0x04, 0x6F, 0x2D, 0x02, 0x38, 0x30, 0x9C, 0x97, - 0xE3, 0x54, 0xF6, 0x43, 0x82, 0x01, 0x22, 0xEF, 0xE8, 0x83, 0x41, 0x2D, 0xB1, 0x40, 0xA4, 0x36, - 0xAE, 0x1B, 0xC5, 0x2E, 0x80, 0x71, 0x73, 0x76, 0x07, 0x4A, 0x20, 0x2E, 0xFD, 0x22, 0x6E, 0x2C, - 0xE6, 0x72, 0xF8, 0x69, 0xE7, 0xBB, 0xC9, 0x1E, 0x3B, 0xA8, 0xB7, 0x1C, 0xB2, 0xCF, 0x0E, 0x5A, - 0xE0, 0x5E, 0x65, 0x6E, 0xE4, 0xB9, 0xAF, 0x58, 0x40, 0x07, 0xB9, 0xC3, 0xE1, 0x31, 0x48, 0x6C, - 0xB1, 0x85, 0x28, 0xE2, 0x5B, 0xCD, 0xE6, 0x86, 0x4B, 0x0F, 0x48, 0x00, 0x39, 0xCC, 0xD0, 0x8F, - 0xAF, 0xAE, 0x2E, 0xAE, 0xBE, 0xE8, 0x35, 0x5A, 0xD3, 0x6F, 0x1C, 0x4D, 0xAF, 0x71, 0xD3, 0x11, - 0x76, 0x42, 0x47, 0x09, 0x4D, 0x27, 0x97, 0x44, 0x4C, 0x8C, 0xD4, 0xBE, 0x23, 0x41, 0x56, 0x16, - 0x84, 0xA1, 0xDC, 0xC8, 0xA2, 0x70, 0x39, 0x9D, 0x6A, 0xAF, 0x40, 0xCD, 0x47, 0x90, 0xEA, 0xDA, - 0xC2, 0x26, 0x71, 0x4C, 0xB9, 0x6F, 0xE8, 0x31, 0x20, 0xEA, 0x16, 0x35, 0xAD, 0x84, 0x7E, 0xCB, - 0x68, 0x2A, 0x52, 0x1B, 0x2C, 0xD7, 0xD0, 0x2F, 0x07, 0x7D, 0xDD, 0xD2, 0x1B, 0xE8, 0x47, 0x3A, - 0xF0, 0x46, 0xCC, 0x39, 0x52, 0x89, 0x5C, 0xD0, 0xA4, 0x3E, 0xCC, 0xC0, 0xA0, 0xB8, 0x6E, 0xB6, - 0x23, 0x9B, 0x71, 0x4E, 0x93, 0x93, 0xFE, 0xD9, 0xA9, 0xAB, 0x5F, 0x29, 0x46, 0xB4, 0x53, 0x28, - 0x48, 0x74, 0x4B, 0x5E, 0x51, 0x7E, 0xC8, 0xE1, 0x84, 0x05, 0xBE, 0x11, 0x99, 0x6D, 0x24, 0xE1, - 0x49, 0x12, 0xB2, 0x40, 0x01, 0x0A, 0x9E, 0x2D, 0x1E, 0x62, 0xEA, 0xEA, 0x23, 0x50, 0x86, 0x6E, - 0x79, 0x76, 0x98, 0x05, 0x82, 0xC5, 0x01, 0x75, 0x37, 0x5A, 0x30, 0xE3, 0x60, 0x41, 0xAE, 0x8E, - 0xB9, 0x19, 0x61, 0xCC, 0x77, 0x75, 0x15, 0xA1, 0xF2, 0xB8, 0xB6, 0xEE, 0x14, 0x4F, 0x9D, 0x92, - 0x56, 0x4E, 0x49, 0xCB, 0xB8, 0x4A, 0xE0, 0x34, 0x3F, 0x18, 0xC3, 0x3C, 0xCE, 0xD4, 0x51, 0x05, - 0xCC, 0xA7, 0x23, 0x02, 0x9C, 0x7C, 0x40, 0x6D, 0xBA, 0x7A, 0x63, 0xDD, 0x41, 0xA9, 0x3A, 0xC8, - 0xAF, 0x6A, 0xC4, 0x2F, 0x6B, 0x44, 0xDD, 0xEE, 0x3A, 0x64, 0x5F, 0x21, 0x07, 0x55, 0xE4, 0xA0, - 0x8C, 0x7C, 0x28, 0x8D, 0x64, 0x1D, 0x72, 0xA0, 0x90, 0x93, 0x8A, 0x88, 0x89, 0x14, 0x51, 0x85, - 0xBD, 0x3A, 0x6A, 0x13, 0x05, 0xD2, 0xAD, 0xA4, 0x22, 0x66, 0x62, 0x83, 0x97, 0x92, 0x61, 0x40, - 0x7D, 0x77, 0xA3, 0x09, 0x33, 0x2C, 0xB6, 0xDD, 0xAD, 0xE6, 0x9A, 0x33, 0x12, 0x75, 0x46, 0x56, - 0x65, 0x30, 0x2B, 0x33, 0xA8, 0xF5, 0xC8, 0x1D, 0xD5, 0xD6, 0x31, 0x98, 0x99, 0x56, 0x60, 0x47, - 0xDC, 0x0B, 0x98, 0x77, 0xEB, 0x2E, 0xBD, 0xC5, 0x9C, 0xB1, 0x85, 0x85, 0x5A, 0x5C, 0x06, 0xBA, - 0x01, 0x94, 0x5E, 0x8B, 0xA5, 0x7C, 0x80, 0xFA, 0x9E, 0x5B, 0xD9, 0x5A, 0x02, 0xDC, 0xA6, 0xF7, - 0xD4, 0x3B, 0x8C, 0xC2, 0x90, 0xA0, 0xED, 0xA6, 0xC0, 0x41, 0x3E, 0xD1, 0xCD, 0xB9, 0x15, 0xAD, - 0xC5, 0x79, 0xC2, 0x45, 0x2C, 0x7F, 0x3D, 0x8B, 0x23, 0x03, 0x5C, 0xCE, 0xF5, 0x6C, 0xD4, 0x61, - 0x6A, 0x83, 0x1E, 0xC7, 0x62, 0xF2, 0x13, 0x17, 0x2A, 0x0C, 0x54, 0xA2, 0x7C, 0x69, 0xDE, 0x58, - 0x0B, 0x91, 0x56, 0x7C, 0xEA, 0xA2, 0xB7, 0xE2, 0x54, 0xA8, 0xBC, 0x8A, 0x5D, 0x9A, 0x4B, 0x1D, - 0x94, 0x61, 0xB9, 0xBD, 0x2F, 0xA0, 0xFA, 0x7C, 0x0E, 0xE7, 0x01, 0xFF, 0x13, 0x68, 0xF9, 0xE8, - 0x5F, 0x17, 0x60, 0xC9, 0xA3, 0x34, 0x78, 0x8B, 0xBB, 0x0D, 0xE3, 0xC0, 0xF9, 0x8F, 0x6D, 0x7C, - 0xF9, 0x1F, 0xFB, 0xA6, 0x66, 0x9A, 0x07, 0xFF, 0x6A, 0x48, 0x0D, 0x1B, 0xC2, 0xFC, 0xD2, 0xBA, - 0xB1, 0x08, 0x80, 0xED, 0x7F, 0x9B, 0xFF, 0xB1, 0x25, 0xB8, 0x02, 0x6B, 0xDF, 0x45, 0x90, 0x49, - 0xF0, 0x24, 0x34, 0xB0, 0x68, 0xA4, 0x91, 0xCD, 0x4D, 0x43, 0xB8, 0xA4, 0x72, 0x8D, 0x35, 0x51, - 0xD3, 0x6D, 0x88, 0x53, 0x50, 0x5B, 0xAC, 0x04, 0xBF, 0x3E, 0x24, 0x7A, 0x15, 0x5B, 0x17, 0x00, - 0xC9, 0x3D, 0xCA, 0x0C, 0x3D, 0x22, 0x97, 0x52, 0xCB, 0x0C, 0x02, 0x42, 0xA7, 0x89, 0xE7, 0x2A, - 0xAD, 0x1D, 0x14, 0x30, 0x17, 0xA2, 0xE0, 0xBC, 0x1C, 0x2D, 0x15, 0xEA, 0xAA, 0xFD, 0x17, 0x0A, - 0xA3, 0xD6, 0x12, 0x8A, 0x04, 0x31, 0xAD, 0xD8, 0x79, 0xC6, 0x72, 0x75, 0x4C, 0x59, 0xBA, 0x35, - 0x59, 0x5D, 0x96, 0xAD, 0x04, 0xAE, 0x2F, 0x8D, 0xFE, 0xD7, 0x3D, 0x16, 0x8E, 0xB5, 0x12, 0x3F, - 0xF8, 0x97, 0xFB, 0x2B, 0x46, 0xE4, 0xCD, 0x3F, 0xBC, 0x21, 0x70, 0x05, 0xA6, 0x41, 0x6D, 0x1E, - 0x4D, 0x0D, 0xB3, 0xF6, 0xAB, 0xAE, 0x49, 0x8A, 0xAE, 0x1E, 0x92, 0xFB, 0xBC, 0xA7, 0xC4, 0x8C, - 0xD7, 0xD6, 0x70, 0x5E, 0xB4, 0x28, 0xF9, 0x82, 0xEC, 0xE6, 0x48, 0x26, 0xA2, 0xB6, 0x56, 0x64, - 0x52, 0xD5, 0xCA, 0xE8, 0x5A, 0x63, 0xFF, 0xD7, 0x4A, 0x40, 0xB7, 0x98, 0xBA, 0x4E, 0x15, 0x8C, - 0xB3, 0x00, 0x1C, 0x93, 0x3E, 0x1D, 0x69, 0x03, 0x26, 0x03, 0x75, 0x35, 0x46, 0x5A, 0x81, 0xC1, - 0xCC, 0x03, 0xC3, 0x2B, 0xFB, 0xF3, 0x1E, 0x16, 0xBF, 0xFB, 0x97, 0xAA, 0xAA, 0x81, 0xD4, 0x8B, - 0x33, 0x5D, 0x59, 0x59, 0xD5, 0x4B, 0xE0, 0xD2, 0x08, 0xA0, 0x5B, 0x8B, 0x3C, 0x3A, 0x8C, 0xFC, - 0x87, 0x52, 0xF6, 0x4D, 0xBB, 0x0F, 0x87, 0x01, 0x49, 0xD3, 0x73, 0xB8, 0x01, 0x43, 0xF7, 0x42, - 0x50, 0xB8, 0xB2, 0xC2, 0xFD, 0xE6, 0xE6, 0x66, 0x15, 0x29, 0xA1, 0x21, 0x14, 0xDB, 0x8A, 0x2B, - 0xF0, 0x49, 0xD3, 0xF1, 0x81, 0x30, 0x18, 0xD2, 0x1A, 0xC6, 0xF0, 0x25, 0xE3, 0x47, 0x5C, 0x71, - 0xF4, 0xF4, 0x22, 0xA6, 0xFC, 0x33, 0xDC, 0x95, 0x32, 0xCB, 0x1A, 0xAD, 0xA6, 0x68, 0xFA, 0x8F, - 0xD8, 0x3E, 0xCA, 0x0D, 0x76, 0xC1, 0x7A, 0xBA, 0x56, 0xA1, 0xFC, 0x9F, 0x61, 0xB9, 0x94, 0x28, - 0xD6, 0x70, 0x9C, 0x40, 0x80, 0x5A, 0xC3, 0x31, 0xC4, 0x1A, 0x41, 0x17, 0xFC, 0x26, 0x6B, 0xF9, - 0xCD, 0xFE, 0x19, 0x7E, 0x97, 0x76, 0x1E, 0x15, 0x25, 0x91, 0xAA, 0xAF, 0x50, 0x02, 0x9F, 0xDD, - 0xE9, 0xA6, 0x15, 0xB9, 0x55, 0x0A, 0x50, 0x1B, 0x46, 0x41, 0xD0, 0x8F, 0xE2, 0x83, 0x27, 0xD6, - 0x9D, 0xC5, 0x7A, 0x31, 0xC8, 0xD9, 0x5C, 0x6E, 0xB1, 0xBC, 0xB5, 0x44, 0x4F, 0xA1, 0xEC, 0x5F, - 0x4B, 0x15, 0x01, 0x3F, 0x23, 0x8B, 0x7B, 0xAC, 0xD4, 0xA5, 0x36, 0x28, 0x0F, 0x56, 0x3F, 0xD5, - 0x3C, 0xCB, 0x5F, 0xCC, 0xAE, 0x6B, 0x51, 0x9B, 0xC0, 0x38, 0x57, 0x92, 0x8B, 0x4A, 0xB2, 0xC8, - 0x13, 0x01, 0xA8, 0x58, 0xC7, 0x2E, 0xC4, 0x4D, 0x6B, 0x7A, 0x7C, 0xBF, 0x5C, 0x83, 0xC2, 0xDF, - 0xF5, 0xD5, 0x12, 0x33, 0x08, 0xC4, 0xD3, 0x95, 0x4B, 0x29, 0x5F, 0x37, 0x29, 0x8A, 0x0E, 0x62, - 0x47, 0xA3, 0x51, 0x4A, 0xC5, 0x47, 0x0C, 0x49, 0x56, 0xB2, 0x98, 0x9F, 0xC8, 0x90, 0x04, 0x8C, - 0x45, 0x3C, 0x8C, 0xB2, 0x94, 0x46, 0x99, 0xA8, 0xA4, 0x16, 0x63, 0x21, 0xCC, 0x5E, 0xFA, 0xE7, - 0x9F, 0x8B, 0xC9, 0x7E, 0x5A, 0x0B, 0x96, 0xD3, 0xEB, 0x3D, 0xBF, 0x34, 0xD9, 0xF7, 0x6B, 0x89, - 0xB9, 0x7A, 0xE9, 0xFF, 0x67, 0x4B, 0x21, 0x65, 0x4B, 0xF1, 0xB0, 0x54, 0x2E, 0x62, 0x62, 0x29, - 0xE6, 0xC9, 0x82, 0x91, 0x97, 0x7C, 0x16, 0x0D, 0x1A, 0x2B, 0x25, 0x55, 0x9E, 0x97, 0x7D, 0x95, - 0x43, 0x40, 0x59, 0x71, 0xE5, 0x35, 0x11, 0x06, 0x34, 0xE0, 0x63, 0x64, 0xF2, 0x41, 0xEB, 0xA7, - 0xD1, 0x94, 0x26, 0x87, 0x24, 0xA5, 0x06, 0x24, 0xCD, 0x65, 0xDC, 0x41, 0xA8, 0xE9, 0x04, 0xEB, - 0x76, 0x6D, 0x6E, 0x12, 0x05, 0xCE, 0x33, 0x77, 0xC4, 0xB1, 0x26, 0x03, 0xF9, 0xB2, 0xCA, 0x09, - 0xD4, 0xC6, 0xBE, 0x12, 0xA4, 0x3E, 0x52, 0x25, 0xA8, 0x61, 0x5A, 0xD0, 0x76, 0xC0, 0x35, 0x5F, - 0x26, 0x51, 0x4C, 0xC6, 0xB2, 0x07, 0x83, 0x35, 0x74, 0x0F, 0xA4, 0x66, 0x6D, 0x34, 0x91, 0x60, - 0xA9, 0x73, 0x29, 0xFC, 0x66, 0xD9, 0xC2, 0x70, 0x4B, 0x57, 0xC9, 0xB0, 0xBD, 0xF4, 0xA5, 0x35, - 0x59, 0x83, 0xE0, 0x0B, 0x6C, 0x62, 0xE0, 0x1E, 0x68, 0x64, 0xF2, 0x7B, 0x00, 0x77, 0x6B, 0xB6, - 0xA3, 0x3D, 0xD6, 0x8E, 0x6A, 0x35, 0x53, 0x55, 0xE9, 0xAE, 0x0B, 0x6D, 0x4E, 0x74, 0x23, 0x0B, - 0x4B, 0x10, 0xAA, 0x9A, 0x59, 0x0C, 0x38, 0x1B, 0x81, 0xAA, 0xBA, 0xC0, 0x11, 0xD6, 0x98, 0x66, - 0xA9, 0x23, 0xF1, 0x97, 0x1D, 0xC9, 0x13, 0xB5, 0x07, 0x95, 0xF5, 0x05, 0xD4, 0x31, 0xAB, 0x25, - 0x86, 0x30, 0xD3, 0x29, 0x13, 0xDE, 0x04, 0x03, 0x90, 0x07, 0x5A, 0xD5, 0x05, 0x14, 0xB5, 0x8E, - 0x1C, 0x4D, 0x44, 0xB8, 0x1C, 0x05, 0xF9, 0xF0, 0x6B, 0x9A, 0x0F, 0xBC, 0xB4, 0x18, 0xDD, 0x97, - 0x80, 0x50, 0xD2, 0xE6, 0xE0, 0x88, 0x8F, 0xF2, 0x21, 0xF4, 0xB2, 0x05, 0x9D, 0x02, 0x58, 0xFC, - 0xC6, 0x71, 0x3E, 0x8A, 0x27, 0xC5, 0x68, 0x42, 0xEF, 0x17, 0x78, 0x51, 0x01, 0xF5, 0xA9, 0xEE, - 0x28, 0x1B, 0xDB, 0x68, 0xCE, 0xF3, 0x41, 0x6B, 0x29, 0x7F, 0xF0, 0xFF, 0x28, 0x7F, 0xCC, 0xC7, - 0x85, 0x34, 0x71, 0x31, 0x1A, 0xB3, 0x42, 0x96, 0x61, 0x18, 0xFF, 0x90, 0x93, 0xA4, 0xD4, 0x13, - 0x97, 0x7A, 0x5A, 0xF1, 0xB3, 0xB6, 0x53, 0x98, 0x8E, 0x31, 0xAA, 0xF8, 0xE3, 0xC8, 0xF6, 0xF0, - 0xF7, 0x3C, 0xF2, 0x65, 0x6D, 0x69, 0x5A, 0xA1, 0x31, 0x82, 0x3A, 0x57, 0x37, 0xCB, 0x7E, 0x9A, - 0xFD, 0xB7, 0xAD, 0xE8, 0xD1, 0xF1, 0xE9, 0x71, 0xFF, 0xB8, 0x5C, 0x38, 0x23, 0xE7, 0x25, 0x93, - 0x8A, 0x2B, 0x5D, 0xFA, 0xB2, 0x22, 0x80, 0x02, 0x1B, 0x45, 0x01, 0x7B, 0xDD, 0xDC, 0x54, 0x7E, - 0xF1, 0xB6, 0x77, 0x71, 0x6E, 0xC7, 0x24, 0x01, 0x8F, 0x24, 0x15, 0xE6, 0xC2, 0x82, 0x44, 0xF9, - 0xE0, 0xD7, 0xC7, 0xA5, 0x72, 0x5D, 0x7E, 0x61, 0x70, 0xC4, 0xDC, 0x52, 0xA7, 0xA9, 0x7E, 0x78, - 0xE2, 0x62, 0x5D, 0x99, 0xBF, 0x04, 0x41, 0x72, 0x1A, 0x2D, 0x13, 0x55, 0x11, 0x67, 0x46, 0xE5, - 0x30, 0x2F, 0xEE, 0xB2, 0x75, 0x0D, 0xD3, 0xC8, 0xB4, 0xC4, 0x84, 0xA5, 0xE5, 0x46, 0xA5, 0x12, - 0x14, 0xFE, 0xA2, 0xB6, 0xE7, 0x8B, 0x91, 0x24, 0xB7, 0x5A, 0x73, 0xAB, 0x6F, 0x41, 0x2A, 0x3E, - 0x58, 0x04, 0x23, 0x66, 0x39, 0xDB, 0x16, 0x77, 0xA3, 0x43, 0xEE, 0x61, 0x5C, 0x7F, 0xBA, 0x35, - 0x78, 0xD2, 0x3C, 0x79, 0x61, 0x9E, 0xFC, 0xB1, 0x7B, 0x2E, 0x1C, 0x45, 0xF9, 0xDA, 0xE2, 0x98, - 0xF6, 0x10, 0x58, 0xBB, 0x6D, 0x2F, 0x7D, 0x18, 0x20, 0xD2, 0x83, 0xCB, 0x00, 0xF4, 0x63, 0x58, - 0xFF, 0x4A, 0xEE, 0x88, 0x7A, 0x09, 0xAA, 0xA2, 0xAD, 0x73, 0x54, 0xD8, 0xEE, 0xFD, 0x81, 0xA3, - 0xF2, 0xCE, 0x65, 0x18, 0x48, 0x97, 0xC3, 0x92, 0x37, 0x8B, 0x75, 0xC1, 0x61, 0x19, 0x31, 0x64, - 0x6C, 0x00, 0xE3, 0xCD, 0x5D, 0x49, 0x13, 0xD5, 0x1C, 0xB4, 0xF0, 0x1B, 0x08, 0x8A, 0x4F, 0x39, - 0xCE, 0x9A, 0x38, 0xAD, 0x62, 0x72, 0xC5, 0x23, 0xC8, 0x4A, 0x67, 0x89, 0xC0, 0x6E, 0x10, 0x0D, - 0x0D, 0x7C, 0x64, 0x9A, 0xA1, 0xB6, 0x1D, 0x3E, 0x37, 0xD7, 0xBC, 0xD9, 0x54, 0xFA, 0x4B, 0x62, - 0x79, 0xD5, 0xB0, 0x8B, 0x1C, 0x56, 0xCC, 0x75, 0x7D, 0x1F, 0xF4, 0xA3, 0x4E, 0x29, 0xAF, 0x48, - 0xA4, 0x53, 0xD1, 0x83, 0xC4, 0x86, 0xA2, 0x41, 0xBE, 0x91, 0x40, 0x44, 0x72, 0x4A, 0x33, 0x5D, - 0xC7, 0xCA, 0xD2, 0x0B, 0x28, 0x49, 0x7A, 0xB2, 0x73, 0x95, 0x49, 0x6B, 0x25, 0x06, 0xFE, 0xC8, - 0xD7, 0xF0, 0xC7, 0xA1, 0xD0, 0xA3, 0x83, 0x9B, 0x49, 0x2B, 0x83, 0xA4, 0x23, 0x64, 0x83, 0xA9, - 0x37, 0xE4, 0xBB, 0xA8, 0x2D, 0x2F, 0xCB, 0xB4, 0x16, 0x50, 0x70, 0x71, 0x83, 0xBB, 0x11, 0x30, - 0x52, 0x5A, 0xC4, 0x9E, 0x94, 0xA8, 0xC7, 0x8F, 0x10, 0x1F, 0x53, 0x4A, 0x20, 0x06, 0x20, 0xA6, - 0x40, 0xD0, 0xA7, 0x42, 0x8A, 0x54, 0xE6, 0x92, 0x53, 0x2A, 0x20, 0xCA, 0x48, 0xCD, 0xE2, 0xC1, - 0x85, 0x78, 0xD4, 0x46, 0xD6, 0x80, 0xFD, 0xDC, 0xBD, 0x73, 0x33, 0xDE, 0x90, 0x68, 0x09, 0x56, - 0x36, 0x3D, 0x9A, 0xA6, 0x52, 0x5C, 0x54, 0xC7, 0x19, 0xF8, 0xA8, 0xA1, 0x03, 0x5A, 0x23, 0x84, - 0x11, 0x1E, 0x84, 0x8A, 0x01, 0x40, 0x7F, 0x42, 0xC3, 0x1C, 0x22, 0x70, 0x08, 0x20, 0x82, 0xA0, - 0x7F, 0x49, 0x0D, 0xF7, 0x64, 0x05, 0xC9, 0xF8, 0xD8, 0x6D, 0x35, 0xF0, 0x9D, 0x66, 0x95, 0xEC, - 0x20, 0xA5, 0xBD, 0x68, 0x24, 0xFA, 0x64, 0x98, 0x1A, 0x50, 0x00, 0xAC, 0xD9, 0x01, 0xA0, 0x1E, - 0x24, 0x5E, 0x63, 0x2B, 0x3F, 0xEF, 0x04, 0x2A, 0xBB, 0x00, 0xAB, 0xBB, 0x8E, 0x87, 0x5F, 0x39, - 0x4F, 0x19, 0xA7, 0x39, 0x26, 0x00, 0x7B, 0x93, 0x68, 0x7A, 0x99, 0x30, 0x2E, 0xCE, 0x64, 0x1B, - 0x6A, 0x6C, 0xB4, 0xE4, 0xF5, 0xA9, 0x87, 0x15, 0x79, 0x3F, 0xC5, 0x8B, 0xCB, 0x0C, 0xF3, 0xBA, - 0x53, 0x79, 0x77, 0xB1, 0x86, 0x70, 0x21, 0x50, 0x66, 0x38, 0xB3, 0x29, 0x74, 0xB0, 0xFA, 0xA1, - 0x48, 0x82, 0x7A, 0x4F, 0xB7, 0x42, 0xE2, 0xC1, 0x44, 0xED, 0x81, 0xF9, 0xDC, 0xC2, 0xD8, 0xE1, - 0x94, 0x83, 0x5A, 0x0A, 0xB5, 0x02, 0x45, 0xC6, 0x95, 0xCD, 0x98, 0x35, 0x1D, 0x6A, 0x58, 0x88, - 0x61, 0xE0, 0xAF, 0xFE, 0x05, 0x0F, 0x1E, 0x1C, 0xC8, 0x55, 0x3F, 0xE1, 0x23, 0xE3, 0x7E, 0xF4, - 0x23, 0x3E, 0x3E, 0xAF, 0xF0, 0xF1, 0x79, 0x1D, 0x1F, 0xB4, 0xAA, 0x3C, 0x98, 0x0C, 0x80, 0xEC, - 0x19, 0xE1, 0x64, 0x4C, 0x13, 0x58, 0xC0, 0x43, 0x50, 0x25, 0x7F, 0x8B, 0xB3, 0x84, 0xFE, 0x98, - 0xB3, 0xDE, 0x84, 0x8D, 0xC4, 0x23, 0xFE, 0x8A, 0xD5, 0xFF, 0x82, 0x4B, 0x3C, 0x70, 0x3D, 0x97, - 0x79, 0x6D, 0x5A, 0x49, 0x28, 0x3F, 0x7E, 0x2B, 0x91, 0x7E, 0xE4, 0x42, 0x78, 0xA9, 0x38, 0xC8, - 0xDF, 0xB7, 0xF4, 0x00, 0xBC, 0x11, 0xF8, 0x29, 0x35, 0x75, 0xBC, 0x0B, 0xA5, 0xFC, 0x29, 0x30, - 0x64, 0xA8, 0xC0, 0x47, 0xDD, 0xD9, 0xDC, 0x12, 0xAE, 0x01, 0x8A, 0xF1, 0xA3, 0x29, 0xB0, 0xEA, - 0xC9, 0x02, 0xD7, 0x9E, 0x40, 0x26, 0x04, 0x91, 0xE0, 0x48, 0xC8, 0xA7, 0x8D, 0x2F, 0x07, 0x9B, - 0x37, 0x35, 0xC8, 0x43, 0x2E, 0xFC, 0x98, 0x2E, 0x0C, 0x36, 0x6F, 0xFE, 0x6D, 0x36, 0xC6, 0xCC, - 0x5A, 0x76, 0xA4, 0x96, 0x4C, 0xF6, 0xF4, 0x0B, 0xBF, 0x71, 0x09, 0x48, 0x5D, 0x49, 0x78, 0x45, - 0x34, 0x03, 0x6B, 0x43, 0x61, 0xE1, 0x07, 0xFF, 0x47, 0x09, 0xF8, 0x91, 0x9E, 0x07, 0xCE, 0xBD, - 0xE6, 0x3D, 0x5E, 0x2F, 0x3E, 0x85, 0xE9, 0x56, 0xE9, 0xC1, 0x4A, 0xC7, 0xEF, 0x53, 0x3A, 0x76, - 0x59, 0xA2, 0x14, 0x4A, 0x14, 0x59, 0x88, 0x1A, 0x6A, 0x50, 0x0E, 0x51, 0x98, 0x89, 0x17, 0xCD, - 0x81, 0x02, 0x9B, 0x73, 0x34, 0x5B, 0x3A, 0x02, 0x0F, 0xF4, 0xF5, 0x45, 0xEE, 0xFC, 0x74, 0x76, - 0x7A, 0x22, 0x44, 0x7C, 0xA5, 0x62, 0x22, 0xD0, 0xAA, 0x2E, 0x2C, 0x2F, 0xCF, 0x9C, 0x89, 0xE4, - 0xA1, 0x28, 0x75, 0x30, 0x31, 0x28, 0x87, 0xFE, 0x74, 0x31, 0xFC, 0x0A, 0x71, 0xD6, 0xD0, 0xCF, - 0x52, 0x48, 0x58, 0x5B, 0x36, 0xA2, 0xF7, 0xFB, 0x97, 0xF6, 0xAE, 0xDD, 0x84, 0xBA, 0x00, 0xB4, - 0x0A, 0x69, 0x19, 0xEE, 0x7D, 0xFE, 0xB7, 0x90, 0xB7, 0xFF, 0x1E, 0x32, 0x83, 0xA8, 0x95, 0x42, - 0x58, 0x2A, 0xF0, 0xAB, 0xB8, 0x93, 0x24, 0x9A, 0x4A, 0xB4, 0xE3, 0x24, 0xC1, 0x4B, 0xE9, 0x43, - 0x85, 0xA2, 0x0D, 0x61, 0x31, 0xA5, 0x89, 0xE6, 0x47, 0x34, 0xD5, 0x78, 0x24, 0xB4, 0x34, 0x8B, - 0x63, 0x68, 0x5C, 0x56, 0xF4, 0x61, 0xEB, 0xC5, 0xEB, 0xCB, 0xFB, 0x8C, 0x66, 0xD4, 0xCF, 0x97, - 0x69, 0x52, 0xD1, 0x0B, 0x56, 0x50, 0xDF, 0x10, 0xEE, 0x7E, 0xB9, 0xC9, 0xEB, 0xA9, 0x8C, 0x73, - 0x8C, 0xA2, 0x1B, 0x2D, 0x35, 0x07, 0xE9, 0x26, 0x40, 0xD5, 0xE5, 0x59, 0x10, 0xCC, 0xDB, 0x2B, - 0xB4, 0xA0, 0xF1, 0x8A, 0x44, 0x24, 0x9F, 0xCB, 0x67, 0x7F, 0xE4, 0xC9, 0xA9, 0xE2, 0x82, 0x50, - 0xF2, 0x54, 0xA9, 0x36, 0xAD, 0x0D, 0x63, 0x83, 0x6A, 0x8C, 0xA7, 0x82, 0x70, 0x0F, 0xAF, 0x51, - 0xE9, 0xC2, 0x2C, 0x6A, 0x29, 0xDC, 0xDE, 0x46, 0x5F, 0xCB, 0x6D, 0xE9, 0x89, 0x7C, 0x2A, 0x25, - 0xE3, 0xAE, 0xAE, 0x63, 0x55, 0x45, 0xB1, 0x3E, 0x25, 0x61, 0x5A, 0x26, 0x5B, 0x54, 0x06, 0x26, - 0x77, 0x0B, 0x70, 0x9B, 0x06, 0x29, 0x1C, 0xBD, 0x7E, 0x7F, 0xCE, 0x46, 0xD1, 0xCE, 0x11, 0x80, - 0x69, 0xC5, 0x3E, 0x93, 0xD7, 0xE0, 0x24, 0xCC, 0x73, 0x07, 0x32, 0xE9, 0x4A, 0x03, 0x0E, 0xA9, - 0x98, 0x44, 0xFE, 0x81, 0x7E, 0xA0, 0x3B, 0x3A, 0xFC, 0xBB, 0x09, 0x35, 0x47, 0xCD, 0xA5, 0xD0, - 0xA4, 0xFA, 0x74, 0x70, 0xF5, 0x06, 0xC2, 0x53, 0x0C, 0xA5, 0x01, 0x17, 0x50, 0x34, 0xD7, 0x74, - 0x7C, 0x7A, 0x7D, 0x0C, 0x29, 0xC8, 0x7F, 0x21, 0x37, 0x66, 0xBB, 0xAA, 0x6C, 0xB8, 0xF3, 0xEA, - 0x75, 0x56, 0x2E, 0x03, 0x7A, 0x61, 0x8C, 0x58, 0x0F, 0x29, 0x7E, 0xFB, 0x7B, 0xF4, 0x9E, 0x8D, - 0x15, 0xD2, 0x6A, 0x5D, 0x6F, 0xCE, 0x76, 0x90, 0x67, 0x89, 0xD5, 0x43, 0x2C, 0x70, 0x97, 0x1F, - 0x29, 0x59, 0x95, 0x35, 0xDC, 0xF6, 0x48, 0x10, 0xE0, 0xC7, 0x5A, 0x03, 0x1B, 0x6A, 0x22, 0xB2, - 0xD4, 0x42, 0x22, 0x29, 0x08, 0x90, 0xD2, 0x3E, 0x84, 0x39, 0xD3, 0x92, 0x65, 0x86, 0xB2, 0xA1, - 0xBC, 0xFF, 0xC5, 0x9A, 0xA3, 0x64, 0x46, 0xE8, 0xCE, 0xF9, 0x6C, 0x73, 0x53, 0xD8, 0x85, 0x99, - 0x18, 0x05, 0x52, 0x8A, 0x01, 0x1C, 0x9A, 0x7D, 0x68, 0x2D, 0x8C, 0xB2, 0x90, 0x58, 0xAB, 0x3D, - 0xD2, 0xB6, 0x51, 0x55, 0x03, 0x54, 0x7C, 0x46, 0x01, 0x03, 0xCE, 0xB2, 0x24, 0x80, 0xA8, 0x8B, - 0x39, 0xBA, 0xB2, 0x2D, 0xC5, 0xBA, 0xD0, 0x84, 0x0E, 0xEC, 0x67, 0xC8, 0x12, 0x95, 0x97, 0xAD, - 0xA2, 0x27, 0x12, 0xC5, 0x77, 0x95, 0x9E, 0xC8, 0x6F, 0xE5, 0x84, 0xAA, 0xC8, 0x77, 0x88, 0x2F, - 0x13, 0x5C, 0xD4, 0xD1, 0x13, 0xA0, 0x24, 0x83, 0x52, 0x34, 0x60, 0x2A, 0x2C, 0x37, 0xEE, 0xEB, - 0xD3, 0xE9, 0xB4, 0x8E, 0xDF, 0x6A, 0xEB, 0x70, 0x82, 0xB2, 0x02, 0x5F, 0x5F, 0xC7, 0x21, 0x47, - 0x15, 0x58, 0xF8, 0x6E, 0xE1, 0xAC, 0xBA, 0xE8, 0x42, 0x7F, 0x2B, 0xDE, 0xD4, 0xAA, 0xD2, 0x59, - 0xE1, 0x73, 0x79, 0xDB, 0x7B, 0x3B, 0x2B, 0x20, 0x32, 0xC4, 0xAF, 0xB2, 0x90, 0x69, 0x20, 0x0D, - 0x3B, 0xE5, 0x46, 0x56, 0x25, 0x85, 0x65, 0x5C, 0xB0, 0xE3, 0x2C, 0x9D, 0x18, 0x33, 0x60, 0xDD, - 0x11, 0x96, 0xD2, 0x95, 0x43, 0x2D, 0x65, 0xB7, 0x0E, 0xB7, 0x0A, 0xFB, 0x70, 0x30, 0x83, 0x94, - 0x79, 0xFB, 0xF3, 0x4F, 0x39, 0x5B, 0xDE, 0xF6, 0x92, 0x62, 0x71, 0xE1, 0xF3, 0xFC, 0xA9, 0x35, - 0xAF, 0x69, 0xA5, 0xD1, 0xAF, 0xC4, 0x97, 0xBD, 0x46, 0xFE, 0x19, 0x3B, 0xFF, 0x9C, 0xAD, 0x81, - 0xB1, 0x43, 0x23, 0x2A, 0xDC, 0x4C, 0x8C, 0xEA, 0x2F, 0x34, 0xE6, 0x63, 0x79, 0x29, 0xBF, 0x2D, - 0xA0, 0x54, 0xA9, 0xD3, 0x68, 0x78, 0x3E, 0xFF, 0x9A, 0x42, 0x19, 0x1D, 0x65, 0xFE, 0x28, 0x20, - 0x09, 0xC5, 0x82, 0xA3, 0x41, 0xBE, 0x92, 0xFB, 0x46, 0xC0, 0x86, 0x69, 0x03, 0x93, 0x6D, 0xCB, - 0xDE, 0xB2, 0x77, 0x71, 0x64, 0x7F, 0x4D, 0xF7, 0x57, 0x4F, 0xD8, 0x5F, 0x34, 0x69, 0x58, 0x0B, - 0xE7, 0xB5, 0xAB, 0x8A, 0x4D, 0x6A, 0x83, 0xFB, 0xC4, 0xA7, 0x70, 0x3D, 0x6F, 0xB3, 0xCC, 0xB6, - 0x1A, 0xE4, 0x5F, 0x60, 0xD4, 0x31, 0xBA, 0x95, 0x2F, 0x92, 0xF4, 0x81, 0x7B, 0x18, 0x5B, 0x17, - 0x54, 0x26, 0x70, 0x49, 0xD5, 0x87, 0x34, 0xB9, 0xD3, 0x9C, 0x2F, 0x39, 0xC3, 0xB7, 0x3C, 0xA8, - 0x03, 0xE4, 0x37, 0x9C, 0x72, 0x39, 0xB0, 0xBF, 0x07, 0x5D, 0x33, 0x2A, 0x41, 0x79, 0xB1, 0x26, - 0x9B, 0xE6, 0x7C, 0x02, 0x82, 0x01, 0x70, 0xB1, 0xA3, 0x48, 0xCD, 0x2B, 0xCB, 0x98, 0x9B, 0x57, - 0x96, 0x54, 0xE2, 0x5F, 0x59, 0xCC, 0xDB, 0x9F, 0xFC, 0xDB, 0x4C, 0xF9, 0x7F, 0x5B, 0x28, 0x36, - 0x32, 0xF9, 0xE1, 0x09, 0xF7, 0x56, 0x3F, 0x45, 0xAD, 0x47, 0x51, 0xBB, 0xF7, 0xFF, 0x17, 0x53, - 0xE8, 0x9D, 0x36, 0x92, 0x29, 0x00, 0x00 -}; - -#define SPIFFS_MAXLENGTH_FILEPATH 32 -const char *excludeListFile = "/.exclude.files"; - -typedef struct ExcludeListS { - char *item; - ExcludeListS *next; -} ExcludeList; - -static ExcludeList *excludes = NULL; - -static bool matchWild(const char *pattern, const char *testee) { - const char *nxPat = NULL, *nxTst = NULL; - - while (*testee) { - if (( *pattern == '?' ) || (*pattern == *testee)){ - pattern++;testee++; - continue; - } - if (*pattern=='*'){ - nxPat=pattern++; nxTst=testee; - continue; - } - if (nxPat){ - pattern = nxPat+1; testee=++nxTst; - continue; - } - return false; - } - while (*pattern=='*'){pattern++;} - return (*pattern == 0); -} - -static bool addExclude(const char *item){ - size_t len = strlen(item); - if(!len){ - return false; - } - ExcludeList *e = (ExcludeList *)malloc(sizeof(ExcludeList)); - if(!e){ - return false; - } - e->item = (char *)malloc(len+1); - if(!e->item){ - free(e); - return false; - } - memcpy(e->item, item, len+1); - e->next = excludes; - excludes = e; - return true; -} - -static void loadExcludeList(fs::FS &_fs, const char *filename){ - static char linebuf[SPIFFS_MAXLENGTH_FILEPATH]; - fs::File excludeFile=_fs.open(filename, "r"); - if(!excludeFile){ - //addExclude("/*.js.gz"); - return; - } -#ifdef ESP32 - if(excludeFile.isDirectory()){ - excludeFile.close(); - return; - } -#endif - if (excludeFile.size() > 0){ - uint8_t idx; - bool isOverflowed = false; - while (excludeFile.available()){ - linebuf[0] = '\0'; - idx = 0; - int lastChar; - do { - lastChar = excludeFile.read(); - if(lastChar != '\r'){ - linebuf[idx++] = (char) lastChar; - } - } while ((lastChar >= 0) && (lastChar != '\n') && (idx < SPIFFS_MAXLENGTH_FILEPATH)); - - if(isOverflowed){ - isOverflowed = (lastChar != '\n'); - continue; - } - isOverflowed = (idx >= SPIFFS_MAXLENGTH_FILEPATH); - linebuf[idx-1] = '\0'; - if(!addExclude(linebuf)){ - excludeFile.close(); - return; - } - } - } - excludeFile.close(); -} - -static bool isExcluded(fs::FS &_fs, const char *filename) { - if(excludes == NULL){ - loadExcludeList(_fs, excludeListFile); - } - ExcludeList *e = excludes; - while(e){ - if (matchWild(e->item, filename)){ - return true; - } - e = e->next; - } - return false; -} - -// WEB HANDLER IMPLEMENTATION - -#ifdef ESP32 -SPIFFSEditor::SPIFFSEditor(const fs::FS& fs, const String& username, const String& password) -#else -SPIFFSEditor::SPIFFSEditor(const String& username, const String& password, const fs::FS& fs) -#endif -:_fs(fs) -,_username(username) -,_password(password) -,_authenticated(false) -,_startTime(0) -{} - -bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request){ - if(request->url().equalsIgnoreCase("/edit")){ - if(request->method() == HTTP_GET){ - if(request->hasParam("list")) - return true; - if(request->hasParam("edit")){ - request->_tempFile = _fs.open(request->arg("edit"), "r"); - if(!request->_tempFile){ - return false; - } -#ifdef ESP32 - if(request->_tempFile.isDirectory()){ - request->_tempFile.close(); - return false; - } -#endif - } - if(request->hasParam("download")){ - request->_tempFile = _fs.open(request->arg("download"), "r"); - if(!request->_tempFile){ - return false; - } -#ifdef ESP32 - if(request->_tempFile.isDirectory()){ - request->_tempFile.close(); - return false; - } -#endif - } - request->addInterestingHeader("If-Modified-Since"); - return true; - } - else if(request->method() == HTTP_POST) - return true; - else if(request->method() == HTTP_DELETE) - return true; - else if(request->method() == HTTP_PUT) - return true; - - } - return false; -} - - -void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request){ - if(_username.length() && _password.length() && !request->authenticate(_username.c_str(), _password.c_str())) - return request->requestAuthentication(); - - if(request->method() == HTTP_GET){ - if(request->hasParam("list")){ - String path = request->getParam("list")->value(); -#ifdef ESP32 - File dir = _fs.open(path); -#else - Dir dir = _fs.openDir(path); -#endif - path = String(); - String output = "["; -#ifdef ESP32 - File entry = dir.openNextFile(); - while(entry){ -#else - while(dir.next()){ - fs::File entry = dir.openFile("r"); -#endif - if (isExcluded(_fs, entry.name())) { -#ifdef ESP32 - entry = dir.openNextFile(); -#endif - continue; - } - if (output != "[") output += ','; - output += "{\"type\":\""; - output += "file"; - output += "\",\"name\":\""; - output += String(entry.name()); - output += "\",\"size\":"; - output += String(entry.size()); - output += "}"; -#ifdef ESP32 - entry = dir.openNextFile(); -#else - entry.close(); -#endif - } -#ifdef ESP32 - dir.close(); -#endif - output += "]"; - request->send(200, "application/json", output); - output = String(); - } - else if(request->hasParam("edit") || request->hasParam("download")){ - request->send(request->_tempFile, request->_tempFile.name(), String(), request->hasParam("download")); - } - else { - const char * buildTime = __DATE__ " " __TIME__ " GMT"; - if (request->header("If-Modified-Since").equals(buildTime)) { - request->send(304); - } else { - AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", edit_htm_gz, edit_htm_gz_len); - response->addHeader("Content-Encoding", "gzip"); - response->addHeader("Last-Modified", buildTime); - request->send(response); - } - } - } else if(request->method() == HTTP_DELETE){ - if(request->hasParam("path", true)){ - _fs.remove(request->getParam("path", true)->value()); - request->send(200, "", "DELETE: "+request->getParam("path", true)->value()); - } else - request->send(404); - } else if(request->method() == HTTP_POST){ - if(request->hasParam("data", true, true) && _fs.exists(request->getParam("data", true, true)->value())) - request->send(200, "", "UPLOADED: "+request->getParam("data", true, true)->value()); - else - request->send(500); - } else if(request->method() == HTTP_PUT){ - if(request->hasParam("path", true)){ - String filename = request->getParam("path", true)->value(); - if(_fs.exists(filename)){ - request->send(200); - } else { - fs::File f = _fs.open(filename, "w"); - if(f){ - f.write((uint8_t)0x00); - f.close(); - request->send(200, "", "CREATE: "+filename); - } else { - request->send(500); - } - } - } else - request->send(400); - } -} - -void SPIFFSEditor::handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){ - if(!index){ - if(!_username.length() || request->authenticate(_username.c_str(),_password.c_str())){ - _authenticated = true; - request->_tempFile = _fs.open(filename, "w"); - _startTime = millis(); - } - } - if(_authenticated && request->_tempFile){ - if(len){ - request->_tempFile.write(data,len); - } - if(final){ - request->_tempFile.close(); - } - } -} diff --git a/lib/ESPAsyncWebServer/src/SPIFFSEditor.h b/lib/ESPAsyncWebServer/src/SPIFFSEditor.h deleted file mode 100644 index 00e87293..00000000 --- a/lib/ESPAsyncWebServer/src/SPIFFSEditor.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SPIFFSEditor_H_ -#define SPIFFSEditor_H_ -#include - -#ifdef ESP8266 -#include -#endif - -class SPIFFSEditor : public AsyncWebHandler { - private: - fs::FS _fs; - String _username; - String _password; - bool _authenticated; - uint32_t _startTime; - - public: -#ifdef ESP32 - SPIFFSEditor(const fs::FS& fs, const String& username = String(), const String& password = String()); -#else - SPIFFSEditor(const String& username = String(), const String& password = String(), const fs::FS& fs = LittleFS); -#endif - virtual bool canHandle(AsyncWebServerRequest* request) override final; - virtual void handleRequest(AsyncWebServerRequest* request) override final; - virtual void handleUpload(AsyncWebServerRequest* request, const String& filename, size_t index, uint8_t* data, size_t len, bool final) override final; - virtual bool isRequestHandlerTrivial() override final { return false; } -}; - -#endif diff --git a/lib/ESPAsyncWebServer/src/StringArray.h b/lib/ESPAsyncWebServer/src/StringArray.h deleted file mode 100644 index 4c0aa701..00000000 --- a/lib/ESPAsyncWebServer/src/StringArray.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef STRINGARRAY_H_ -#define STRINGARRAY_H_ - -#include "stddef.h" -#include "WString.h" - -template -class LinkedListNode { - T _value; - public: - LinkedListNode* next; - LinkedListNode(const T val): _value(val), next(nullptr) {} - ~LinkedListNode(){} - const T& value() const { return _value; }; - T& value(){ return _value; } -}; - -template class Item = LinkedListNode> -class LinkedList { - public: - typedef Item ItemType; - typedef std::function OnRemove; - typedef std::function Predicate; - private: - ItemType* _root; - OnRemove _onRemove; - - class Iterator { - ItemType* _node; - public: - Iterator(ItemType* current = nullptr) : _node(current) {} - Iterator(const Iterator& i) : _node(i._node) {} - Iterator& operator ++() { _node = _node->next; return *this; } - bool operator != (const Iterator& i) const { return _node != i._node; } - const T& operator * () const { return _node->value(); } - const T* operator -> () const { return &_node->value(); } - }; - - public: - typedef const Iterator ConstIterator; - ConstIterator begin() const { return ConstIterator(_root); } - ConstIterator end() const { return ConstIterator(nullptr); } - - LinkedList(OnRemove onRemove) : _root(nullptr), _onRemove(onRemove) {} - ~LinkedList(){} - void add(const T& t){ - auto it = new ItemType(t); - if(!_root){ - _root = it; - } else { - auto i = _root; - while(i->next) i = i->next; - i->next = it; - } - } - T& front() const { - return _root->value(); - } - - bool isEmpty() const { - return _root == nullptr; - } - size_t length() const { - size_t i = 0; - auto it = _root; - while(it){ - i++; - it = it->next; - } - return i; - } - size_t count_if(Predicate predicate) const { - size_t i = 0; - auto it = _root; - while(it){ - if (!predicate){ - i++; - } - else if (predicate(it->value())) { - i++; - } - it = it->next; - } - return i; - } - const T* nth(size_t N) const { - size_t i = 0; - auto it = _root; - while(it){ - if(i++ == N) - return &(it->value()); - it = it->next; - } - return nullptr; - } - bool remove(const T& t){ - auto it = _root; - auto pit = _root; - while(it){ - if(it->value() == t){ - if(it == _root){ - _root = _root->next; - } else { - pit->next = it->next; - } - - if (_onRemove) { - _onRemove(it->value()); - } - - delete it; - return true; - } - pit = it; - it = it->next; - } - return false; - } - bool remove_first(Predicate predicate){ - auto it = _root; - auto pit = _root; - while(it){ - if(predicate(it->value())){ - if(it == _root){ - _root = _root->next; - } else { - pit->next = it->next; - } - if (_onRemove) { - _onRemove(it->value()); - } - delete it; - return true; - } - pit = it; - it = it->next; - } - return false; - } - - void free(){ - while(_root != nullptr){ - auto it = _root; - _root = _root->next; - if (_onRemove) { - _onRemove(it->value()); - } - delete it; - } - _root = nullptr; - } -}; - - -class StringArray : public LinkedList { -public: - - StringArray() : LinkedList(nullptr) {} - - bool containsIgnoreCase(const String& str){ - for (const auto& s : *this) { - if (str.equalsIgnoreCase(s)) { - return true; - } - } - return false; - } -}; - - - - -#endif /* STRINGARRAY_H_ */ diff --git a/lib/ESPAsyncWebServer/src/WebAuthentication.cpp b/lib/ESPAsyncWebServer/src/WebAuthentication.cpp deleted file mode 100644 index 2feca542..00000000 --- a/lib/ESPAsyncWebServer/src/WebAuthentication.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "WebAuthentication.h" -#include -#ifdef ESP32 -#include "mbedtls/md5.h" -#else -#include "md5.h" -#endif - - -// Basic Auth hash = base64("username:password") - -bool checkBasicAuthentication(const char * hash, const char * username, const char * password){ - if(username == NULL || password == NULL || hash == NULL) - return false; - - size_t toencodeLen = strlen(username)+strlen(password)+1; - size_t encodedLen = base64_encode_expected_len(toencodeLen); - if(strlen(hash) != encodedLen) - return false; - - char *toencode = new char[toencodeLen+1]; - if(toencode == NULL){ - return false; - } - char *encoded = new char[base64_encode_expected_len(toencodeLen)+1]; - if(encoded == NULL){ - delete[] toencode; - return false; - } - sprintf(toencode, "%s:%s", username, password); - if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0){ - delete[] toencode; - delete[] encoded; - return true; - } - delete[] toencode; - delete[] encoded; - return false; -} - -static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or more -#ifdef ESP32 - mbedtls_md5_context _ctx; -#else - md5_context_t _ctx; -#endif - uint8_t i; - uint8_t * _buf = (uint8_t*)malloc(16); - if(_buf == NULL) - return false; - memset(_buf, 0x00, 16); -#ifdef ESP32 - mbedtls_md5_init(&_ctx); - mbedtls_md5_starts(&_ctx); - mbedtls_md5_update(&_ctx, data, len); - mbedtls_md5_finish(&_ctx, _buf); -#else - MD5Init(&_ctx); - MD5Update(&_ctx, data, len); - MD5Final(_buf, &_ctx); -#endif - for(i = 0; i < 16; i++) { - sprintf(output + (i * 2), "%02x", _buf[i]); - } - free(_buf); - return true; -} - -static String genRandomMD5(){ -#ifdef ESP8266 - uint32_t r = RANDOM_REG32; -#else - uint32_t r = rand(); -#endif - char * out = (char*)malloc(33); - if(out == NULL || !getMD5((uint8_t*)(&r), 4, out)) - return ""; - String res = String(out); - free(out); - return res; -} - -static String stringMD5(const String& in){ - char * out = (char*)malloc(33); - if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out)) - return ""; - String res = String(out); - free(out); - return res; -} - -String generateDigestHash(const char * username, const char * password, const char * realm){ - if(username == NULL || password == NULL || realm == NULL){ - return ""; - } - char * out = (char*)malloc(33); - String res = String(username); - res.concat(":"); - res.concat(realm); - res.concat(":"); - String in = res; - in.concat(password); - if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out)) - return ""; - res.concat(out); - free(out); - return res; -} - -String requestDigestAuthentication(const char * realm){ - String header = "realm=\""; - if(realm == NULL) - header.concat("asyncesp"); - else - header.concat(realm); - header.concat( "\", qop=\"auth\", nonce=\""); - header.concat(genRandomMD5()); - header.concat("\", opaque=\""); - header.concat(genRandomMD5()); - header.concat("\""); - return header; -} - -bool checkDigestAuthentication(const char * header, const char * method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri){ - if(username == NULL || password == NULL || header == NULL || method == NULL){ - //os_printf("AUTH FAIL: missing requred fields\n"); - return false; - } - - String myHeader = String(header); - int nextBreak = myHeader.indexOf(","); - if(nextBreak < 0){ - //os_printf("AUTH FAIL: no variables\n"); - return false; - } - - String myUsername = String(); - String myRealm = String(); - String myNonce = String(); - String myUri = String(); - String myResponse = String(); - String myQop = String(); - String myNc = String(); - String myCnonce = String(); - - myHeader += ", "; - do { - String avLine = myHeader.substring(0, nextBreak); - avLine.trim(); - myHeader = myHeader.substring(nextBreak+1); - nextBreak = myHeader.indexOf(","); - - int eqSign = avLine.indexOf("="); - if(eqSign < 0){ - //os_printf("AUTH FAIL: no = sign\n"); - return false; - } - String varName = avLine.substring(0, eqSign); - avLine = avLine.substring(eqSign + 1); - if(avLine.startsWith("\"")){ - avLine = avLine.substring(1, avLine.length() - 1); - } - - if(varName.equals("username")){ - if(!avLine.equals(username)){ - //os_printf("AUTH FAIL: username\n"); - return false; - } - myUsername = avLine; - } else if(varName.equals("realm")){ - if(realm != NULL && !avLine.equals(realm)){ - //os_printf("AUTH FAIL: realm\n"); - return false; - } - myRealm = avLine; - } else if(varName.equals("nonce")){ - if(nonce != NULL && !avLine.equals(nonce)){ - //os_printf("AUTH FAIL: nonce\n"); - return false; - } - myNonce = avLine; - } else if(varName.equals("opaque")){ - if(opaque != NULL && !avLine.equals(opaque)){ - //os_printf("AUTH FAIL: opaque\n"); - return false; - } - } else if(varName.equals("uri")){ - if(uri != NULL && !avLine.equals(uri)){ - //os_printf("AUTH FAIL: uri\n"); - return false; - } - myUri = avLine; - } else if(varName.equals("response")){ - myResponse = avLine; - } else if(varName.equals("qop")){ - myQop = avLine; - } else if(varName.equals("nc")){ - myNc = avLine; - } else if(varName.equals("cnonce")){ - myCnonce = avLine; - } - } while(nextBreak > 0); - - String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ":" + myRealm + ":" + String(password)); - String ha2 = String(method) + ":" + myUri; - String response = ha1 + ":" + myNonce + ":" + myNc + ":" + myCnonce + ":" + myQop + ":" + stringMD5(ha2); - - if(myResponse.equals(stringMD5(response))){ - //os_printf("AUTH SUCCESS\n"); - return true; - } - - //os_printf("AUTH FAIL: password\n"); - return false; -} diff --git a/lib/ESPAsyncWebServer/src/WebAuthentication.h b/lib/ESPAsyncWebServer/src/WebAuthentication.h deleted file mode 100644 index ff68265d..00000000 --- a/lib/ESPAsyncWebServer/src/WebAuthentication.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef WEB_AUTHENTICATION_H_ -#define WEB_AUTHENTICATION_H_ - -#include "Arduino.h" - -bool checkBasicAuthentication(const char * header, const char * username, const char * password); -String requestDigestAuthentication(const char * realm); -bool checkDigestAuthentication(const char * header, const char * method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri); - -//for storing hashed versions on the device that can be authenticated against -String generateDigestHash(const char * username, const char * password, const char * realm); - -#endif diff --git a/lib/ESPAsyncWebServer/src/WebHandlerImpl.h b/lib/ESPAsyncWebServer/src/WebHandlerImpl.h deleted file mode 100644 index d121fa7a..00000000 --- a/lib/ESPAsyncWebServer/src/WebHandlerImpl.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef ASYNCWEBSERVERHANDLERIMPL_H_ -#define ASYNCWEBSERVERHANDLERIMPL_H_ - -#include -#ifdef ASYNCWEBSERVER_REGEX -#include -#endif - -#include "stddef.h" -#include - -class AsyncStaticWebHandler: public AsyncWebHandler { - using File = fs::File; - using FS = fs::FS; - private: - bool _getFile(AsyncWebServerRequest *request); - bool _fileExists(AsyncWebServerRequest *request, const String& path); - uint8_t _countBits(const uint8_t value) const; - protected: - FS _fs; - String _uri; - String _path; - String _default_file; - String _cache_control; - String _last_modified; - AwsTemplateProcessor _callback; - bool _isDir; - bool _gzipFirst; - uint8_t _gzipStats; - public: - AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control); - virtual bool canHandle(AsyncWebServerRequest *request) override final; - virtual void handleRequest(AsyncWebServerRequest *request) override final; - AsyncStaticWebHandler& setIsDir(bool isDir); - AsyncStaticWebHandler& setDefaultFile(const char* filename); - AsyncStaticWebHandler& setCacheControl(const char* cache_control); - AsyncStaticWebHandler& setLastModified(const char* last_modified); - AsyncStaticWebHandler& setLastModified(struct tm* last_modified); - #ifdef ESP8266 - AsyncStaticWebHandler& setLastModified(time_t last_modified); - AsyncStaticWebHandler& setLastModified(); //sets to current time. Make sure sntp is runing and time is updated - #endif - AsyncStaticWebHandler& setTemplateProcessor(AwsTemplateProcessor newCallback) {_callback = newCallback; return *this;} -}; - -class AsyncCallbackWebHandler: public AsyncWebHandler { - private: - protected: - String _uri; - WebRequestMethodComposite _method; - ArRequestHandlerFunction _onRequest; - ArUploadHandlerFunction _onUpload; - ArBodyHandlerFunction _onBody; - bool _isRegex; - public: - AsyncCallbackWebHandler() : _uri(), _method(HTTP_ANY), _onRequest(NULL), _onUpload(NULL), _onBody(NULL), _isRegex(false) {} - void setUri(const String& uri){ - _uri = uri; - _isRegex = uri.startsWith("^") && uri.endsWith("$"); - } - void setMethod(WebRequestMethodComposite method){ _method = method; } - void onRequest(ArRequestHandlerFunction fn){ _onRequest = fn; } - void onUpload(ArUploadHandlerFunction fn){ _onUpload = fn; } - void onBody(ArBodyHandlerFunction fn){ _onBody = fn; } - - virtual bool canHandle(AsyncWebServerRequest *request) override final{ - - if(!_onRequest) - return false; - - if(!(_method & request->method())) - return false; - -#ifdef ASYNCWEBSERVER_REGEX - if (_isRegex) { - std::regex pattern(_uri.c_str()); - std::smatch matches; - std::string s(request->url().c_str()); - if(std::regex_search(s, matches, pattern)) { - for (size_t i = 1; i < matches.size(); ++i) { // start from 1 - request->_addPathParam(matches[i].str().c_str()); - } - } else { - return false; - } - } else -#endif - if (_uri.length() && _uri.endsWith("*")) { - String uriTemplate = String(_uri); - uriTemplate = uriTemplate.substring(0, uriTemplate.length() - 1); - if (!request->url().startsWith(uriTemplate)) - return false; - } - else if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) - return false; - - request->addInterestingHeader("ANY"); - return true; - } - - virtual void handleRequest(AsyncWebServerRequest *request) override final { - if(_onRequest) - _onRequest(request); - else - request->send(500); - } - virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final { - if(_onUpload) - _onUpload(request, filename, index, data, len, final); - } - virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { - if(_onBody) - _onBody(request, data, len, index, total); - } - virtual bool isRequestHandlerTrivial() override final {return _onRequest ? false : true;} -}; - -#endif /* ASYNCWEBSERVERHANDLERIMPL_H_ */ diff --git a/lib/ESPAsyncWebServer/src/WebHandlers.cpp b/lib/ESPAsyncWebServer/src/WebHandlers.cpp deleted file mode 100644 index 1f435e68..00000000 --- a/lib/ESPAsyncWebServer/src/WebHandlers.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "ESPAsyncWebServer.h" -#include "WebHandlerImpl.h" - -AsyncStaticWebHandler::AsyncStaticWebHandler(const char* uri, FS& fs, const char* path, const char* cache_control) - : _fs(fs), _uri(uri), _path(path), _default_file("index.htm"), _cache_control(cache_control), _last_modified(""), _callback(nullptr) -{ - // Ensure leading '/' - if (_uri.length() == 0 || _uri[0] != '/') _uri = "/" + _uri; - if (_path.length() == 0 || _path[0] != '/') _path = "/" + _path; - - // If path ends with '/' we assume a hint that this is a directory to improve performance. - // However - if it does not end with '/' we, can't assume a file, path can still be a directory. - _isDir = _path[_path.length()-1] == '/'; - - // Remove the trailing '/' so we can handle default file - // Notice that root will be "" not "/" - if (_uri[_uri.length()-1] == '/') _uri = _uri.substring(0, _uri.length()-1); - if (_path[_path.length()-1] == '/') _path = _path.substring(0, _path.length()-1); - - // Reset stats - _gzipFirst = false; - _gzipStats = 0xF8; -} - -AsyncStaticWebHandler& AsyncStaticWebHandler::setIsDir(bool isDir){ - _isDir = isDir; - return *this; -} - -AsyncStaticWebHandler& AsyncStaticWebHandler::setDefaultFile(const char* filename){ - _default_file = String(filename); - return *this; -} - -AsyncStaticWebHandler& AsyncStaticWebHandler::setCacheControl(const char* cache_control){ - _cache_control = String(cache_control); - return *this; -} - -AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(const char* last_modified){ - _last_modified = String(last_modified); - return *this; -} - -AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(struct tm* last_modified){ - char result[30]; - strftime (result,30,"%a, %d %b %Y %H:%M:%S %Z", last_modified); - return setLastModified((const char *)result); -} - -#ifdef ESP8266 -AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(time_t last_modified){ - return setLastModified((struct tm *)gmtime(&last_modified)); -} - -AsyncStaticWebHandler& AsyncStaticWebHandler::setLastModified(){ - time_t last_modified; - if(time(&last_modified) == 0) //time is not yet set - return *this; - return setLastModified(last_modified); -} -#endif -bool AsyncStaticWebHandler::canHandle(AsyncWebServerRequest *request){ - if(request->method() != HTTP_GET - || !request->url().startsWith(_uri) - || !request->isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP) - ){ - return false; - } - if (_getFile(request)) { - // We interested in "If-Modified-Since" header to check if file was modified - if (_last_modified.length()) - request->addInterestingHeader("If-Modified-Since"); - - if(_cache_control.length()) - request->addInterestingHeader("If-None-Match"); - - DEBUGF("[AsyncStaticWebHandler::canHandle] TRUE\n"); - return true; - } - - return false; -} - -bool AsyncStaticWebHandler::_getFile(AsyncWebServerRequest *request) -{ - // Remove the found uri - String path = request->url().substring(_uri.length()); - - // We can skip the file check and look for default if request is to the root of a directory or that request path ends with '/' - bool canSkipFileCheck = (_isDir && path.length() == 0) || (path.length() && path[path.length()-1] == '/'); - - path = _path + path; - - // Do we have a file or .gz file - if (!canSkipFileCheck && _fileExists(request, path)) - return true; - - // Can't handle if not default file - if (_default_file.length() == 0) - return false; - - // Try to add default file, ensure there is a trailing '/' ot the path. - if (path.length() == 0 || path[path.length()-1] != '/') - path += "/"; - path += _default_file; - - return _fileExists(request, path); -} - -#ifdef ESP32 -#define FILE_IS_REAL(f) (f == true && !f.isDirectory()) -#else -#define FILE_IS_REAL(f) (f == true) -#endif - -bool AsyncStaticWebHandler::_fileExists(AsyncWebServerRequest *request, const String& path) -{ - bool fileFound = false; - bool gzipFound = false; - - String gzip = path + ".gz"; - - if (_gzipFirst) { - request->_tempFile = _fs.open(gzip, "r"); - gzipFound = FILE_IS_REAL(request->_tempFile); - if (!gzipFound){ - request->_tempFile = _fs.open(path, "r"); - fileFound = FILE_IS_REAL(request->_tempFile); - } - } else { - request->_tempFile = _fs.open(path, "r"); - fileFound = FILE_IS_REAL(request->_tempFile); - if (!fileFound){ - request->_tempFile = _fs.open(gzip, "r"); - gzipFound = FILE_IS_REAL(request->_tempFile); - } - } - - bool found = fileFound || gzipFound; - - if (found) { - // Extract the file name from the path and keep it in _tempObject - size_t pathLen = path.length(); - char * _tempPath = (char*)malloc(pathLen+1); - snprintf(_tempPath, pathLen+1, "%s", path.c_str()); - request->_tempObject = (void*)_tempPath; - - // Calculate gzip statistic - _gzipStats = (_gzipStats << 1) + (gzipFound ? 1 : 0); - if (_gzipStats == 0x00) _gzipFirst = false; // All files are not gzip - else if (_gzipStats == 0xFF) _gzipFirst = true; // All files are gzip - else _gzipFirst = _countBits(_gzipStats) > 4; // IF we have more gzip files - try gzip first - } - - return found; -} - -uint8_t AsyncStaticWebHandler::_countBits(const uint8_t value) const -{ - uint8_t w = value; - uint8_t n; - for (n=0; w!=0; n++) w&=w-1; - return n; -} - -void AsyncStaticWebHandler::handleRequest(AsyncWebServerRequest *request) -{ - // Get the filename from request->_tempObject and free it - String filename = String((char*)request->_tempObject); - free(request->_tempObject); - request->_tempObject = NULL; - if((_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str())) - return request->requestAuthentication(); - - if (request->_tempFile == true) { - String etag = String(request->_tempFile.size()); - if (_last_modified.length() && _last_modified == request->header("If-Modified-Since")) { - request->_tempFile.close(); - request->send(304); // Not modified - } else if (_cache_control.length() && request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag)) { - request->_tempFile.close(); - AsyncWebServerResponse * response = new AsyncBasicResponse(304); // Not modified - response->addHeader("Cache-Control", _cache_control); - response->addHeader("ETag", etag); - request->send(response); - } else { - AsyncWebServerResponse * response = new AsyncFileResponse(request->_tempFile, filename, String(), false, _callback); - if (_last_modified.length()) - response->addHeader("Last-Modified", _last_modified); - if (_cache_control.length()){ - response->addHeader("Cache-Control", _cache_control); - response->addHeader("ETag", etag); - } - request->send(response); - } - } else { - request->send(404); - } -} diff --git a/lib/ESPAsyncWebServer/src/WebRequest.cpp b/lib/ESPAsyncWebServer/src/WebRequest.cpp deleted file mode 100644 index bbce5ca4..00000000 --- a/lib/ESPAsyncWebServer/src/WebRequest.cpp +++ /dev/null @@ -1,1008 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "ESPAsyncWebServer.h" -#include "WebResponseImpl.h" -#include "WebAuthentication.h" - -#ifndef ESP8266 -#define os_strlen strlen -#endif - -static const String SharedEmptyString = String(); - -#define __is_param_char(c) ((c) && ((c) != '{') && ((c) != '[') && ((c) != '&') && ((c) != '=')) - -enum { PARSE_REQ_START, PARSE_REQ_HEADERS, PARSE_REQ_BODY, PARSE_REQ_END, PARSE_REQ_FAIL }; - -AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c) - : _client(c) - , _server(s) - , _handler(NULL) - , _response(NULL) - , _temp() - , _parseState(0) - , _version(0) - , _method(HTTP_ANY) - , _url() - , _host() - , _contentType() - , _boundary() - , _authorization() - , _reqconntype(RCT_HTTP) - , _isDigest(false) - , _isMultipart(false) - , _isPlainPost(false) - , _expectingContinue(false) - , _contentLength(0) - , _parsedLength(0) - , _headers(LinkedList([](AsyncWebHeader *h){ delete h; })) - , _params(LinkedList([](AsyncWebParameter *p){ delete p; })) - , _pathParams(LinkedList([](String *p){ delete p; })) - , _multiParseState(0) - , _boundaryPosition(0) - , _itemStartIndex(0) - , _itemSize(0) - , _itemName() - , _itemFilename() - , _itemType() - , _itemValue() - , _itemBuffer(0) - , _itemBufferIndex(0) - , _itemIsFile(false) - , _tempObject(NULL) -{ - c->onError([](void *r, AsyncClient* c, int8_t error){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onError(error); }, this); - c->onAck([](void *r, AsyncClient* c, size_t len, uint32_t time){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onAck(len, time); }, this); - c->onDisconnect([](void *r, AsyncClient* c){ AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onDisconnect(); delete c; }, this); - c->onTimeout([](void *r, AsyncClient* c, uint32_t time){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onTimeout(time); }, this); - c->onData([](void *r, AsyncClient* c, void *buf, size_t len){ (void)c; AsyncWebServerRequest *req = (AsyncWebServerRequest*)r; req->_onData(buf, len); }, this); - c->onPoll([](void *r, AsyncClient* c){ (void)c; AsyncWebServerRequest *req = ( AsyncWebServerRequest*)r; req->_onPoll(); }, this); -} - -AsyncWebServerRequest::~AsyncWebServerRequest(){ - _headers.free(); - - _params.free(); - _pathParams.free(); - - _interestingHeaders.free(); - - if(_response != NULL){ - delete _response; - } - - if(_tempObject != NULL){ - free(_tempObject); - } - - if(_tempFile){ - _tempFile.close(); - } -} - -void AsyncWebServerRequest::_onData(void *buf, size_t len){ - size_t i = 0; - while (true) { - - if(_parseState < PARSE_REQ_BODY){ - // Find new line in buf - char *str = (char*)buf; - for (i = 0; i < len; i++) { - if (str[i] == '\n') { - break; - } - } - if (i == len) { // No new line, just add the buffer in _temp - char ch = str[len-1]; - str[len-1] = 0; - _temp.reserve(_temp.length()+len); - _temp.concat(str); - _temp.concat(ch); - } else { // Found new line - extract it and parse - str[i] = 0; // Terminate the string at the end of the line. - _temp.concat(str); - _temp.trim(); - _parseLine(); - if (++i < len) { - // Still have more buffer to process - buf = str+i; - len-= i; - continue; - } - } - } else if(_parseState == PARSE_REQ_BODY){ - // A handler should be already attached at this point in _parseLine function. - // If handler does nothing (_onRequest is NULL), we don't need to really parse the body. - const bool needParse = _handler && !_handler->isRequestHandlerTrivial(); - if(_isMultipart){ - if(needParse){ - size_t i; - for(i=0; i end) equal = end; - String name = params.substring(start, equal); - String value = equal + 1 < end ? params.substring(equal + 1, end) : String(); - _addParam(new AsyncWebParameter(urlDecode(name), urlDecode(value))); - start = end + 1; - } -} - -bool AsyncWebServerRequest::_parseReqHead(){ - // Split the head into method, url and version - int index = _temp.indexOf(' '); - String m = _temp.substring(0, index); - index = _temp.indexOf(' ', index+1); - String u = _temp.substring(m.length()+1, index); - _temp = _temp.substring(index+1); - - if(m == "GET"){ - _method = HTTP_GET; - } else if(m == "POST"){ - _method = HTTP_POST; - } else if(m == "DELETE"){ - _method = HTTP_DELETE; - } else if(m == "PUT"){ - _method = HTTP_PUT; - } else if(m == "PATCH"){ - _method = HTTP_PATCH; - } else if(m == "HEAD"){ - _method = HTTP_HEAD; - } else if(m == "OPTIONS"){ - _method = HTTP_OPTIONS; - } - - String g = String(); - index = u.indexOf('?'); - if(index > 0){ - g = u.substring(index +1); - u = u.substring(0, index); - } - _url = urlDecode(u); - _addGetParams(g); - - if(!_temp.startsWith("HTTP/1.0")) - _version = 1; - - _temp = String(); - return true; -} - -bool strContains(String src, String find, bool mindcase = true) { - int pos=0, i=0; - const int slen = src.length(); - const int flen = find.length(); - - if (slen < flen) return false; - while (pos <= (slen - flen)) { - for (i=0; i < flen; i++) { - if (mindcase) { - if (src[pos+i] != find[i]) i = flen + 1; // no match - } else if (tolower(src[pos+i]) != tolower(find[i])) i = flen + 1; // no match - } - if (i == flen) return true; - pos++; - } - return false; -} - -bool AsyncWebServerRequest::_parseReqHeader(){ - int index = _temp.indexOf(':'); - if(index){ - String name = _temp.substring(0, index); - String value = _temp.substring(index + 2); - if(name.equalsIgnoreCase("Host")){ - _host = value; - } else if(name.equalsIgnoreCase("Content-Type")){ - _contentType = value.substring(0, value.indexOf(';')); - if (value.startsWith("multipart/")){ - _boundary = value.substring(value.indexOf('=')+1); - _boundary.replace("\"",""); - _isMultipart = true; - } - } else if(name.equalsIgnoreCase("Content-Length")){ - _contentLength = atoi(value.c_str()); - } else if(name.equalsIgnoreCase("Expect") && value == "100-continue"){ - _expectingContinue = true; - } else if(name.equalsIgnoreCase("Authorization")){ - if(value.length() > 5 && value.substring(0,5).equalsIgnoreCase("Basic")){ - _authorization = value.substring(6); - } else if(value.length() > 6 && value.substring(0,6).equalsIgnoreCase("Digest")){ - _isDigest = true; - _authorization = value.substring(7); - } - } else { - if(name.equalsIgnoreCase("Upgrade") && value.equalsIgnoreCase("websocket")){ - // WebSocket request can be uniquely identified by header: [Upgrade: websocket] - _reqconntype = RCT_WS; - } else { - if(name.equalsIgnoreCase("Accept") && strContains(value, "text/event-stream", false)){ - // WebEvent request can be uniquely identified by header: [Accept: text/event-stream] - _reqconntype = RCT_EVENT; - } - } - } - _headers.add(new AsyncWebHeader(name, value)); - } - _temp = String(); - return true; -} - -void AsyncWebServerRequest::_parsePlainPostChar(uint8_t data){ - if(data && (char)data != '&') - _temp += (char)data; - if(!data || (char)data == '&' || _parsedLength == _contentLength){ - String name = "body"; - String value = _temp; - if(!_temp.startsWith("{") && !_temp.startsWith("[") && _temp.indexOf('=') > 0){ - name = _temp.substring(0, _temp.indexOf('=')); - value = _temp.substring(_temp.indexOf('=') + 1); - } - _addParam(new AsyncWebParameter(urlDecode(name), urlDecode(value), true)); - _temp = String(); - } -} - -void AsyncWebServerRequest::_handleUploadByte(uint8_t data, bool last){ - _itemBuffer[_itemBufferIndex++] = data; - - if(last || _itemBufferIndex == 1460){ - //check if authenticated before calling the upload - if(_handler) - _handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, false); - _itemBufferIndex = 0; - } -} - -enum { - EXPECT_BOUNDARY, - PARSE_HEADERS, - WAIT_FOR_RETURN1, - EXPECT_FEED1, - EXPECT_DASH1, - EXPECT_DASH2, - BOUNDARY_OR_DATA, - DASH3_OR_RETURN2, - EXPECT_FEED2, - PARSING_FINISHED, - PARSE_ERROR -}; - -void AsyncWebServerRequest::_parseMultipartPostByte(uint8_t data, bool last){ -#define itemWriteByte(b) do { _itemSize++; if(_itemIsFile) _handleUploadByte(b, last); else _itemValue+=(char)(b); } while(0) - - if(!_parsedLength){ - _multiParseState = EXPECT_BOUNDARY; - _temp = String(); - _itemName = String(); - _itemFilename = String(); - _itemType = String(); - } - - if(_multiParseState == WAIT_FOR_RETURN1){ - if(data != '\r'){ - itemWriteByte(data); - } else { - _multiParseState = EXPECT_FEED1; - } - } else if(_multiParseState == EXPECT_BOUNDARY){ - if(_parsedLength < 2 && data != '-'){ - _multiParseState = PARSE_ERROR; - return; - } else if(_parsedLength - 2 < _boundary.length() && _boundary.c_str()[_parsedLength - 2] != data){ - _multiParseState = PARSE_ERROR; - return; - } else if(_parsedLength - 2 == _boundary.length() && data != '\r'){ - _multiParseState = PARSE_ERROR; - return; - } else if(_parsedLength - 3 == _boundary.length()){ - if(data != '\n'){ - _multiParseState = PARSE_ERROR; - return; - } - _multiParseState = PARSE_HEADERS; - _itemIsFile = false; - } - } else if(_multiParseState == PARSE_HEADERS){ - if((char)data != '\r' && (char)data != '\n') - _temp += (char)data; - if((char)data == '\n'){ - if(_temp.length()){ - if(_temp.length() > 12 && _temp.substring(0, 12).equalsIgnoreCase("Content-Type")){ - _itemType = _temp.substring(14); - _itemIsFile = true; - } else if(_temp.length() > 19 && _temp.substring(0, 19).equalsIgnoreCase("Content-Disposition")){ - _temp = _temp.substring(_temp.indexOf(';') + 2); - while(_temp.indexOf(';') > 0){ - String name = _temp.substring(0, _temp.indexOf('=')); - String nameVal = _temp.substring(_temp.indexOf('=') + 2, _temp.indexOf(';') - 1); - if(name == "name"){ - _itemName = nameVal; - } else if(name == "filename"){ - _itemFilename = nameVal; - _itemIsFile = true; - } - _temp = _temp.substring(_temp.indexOf(';') + 2); - } - String name = _temp.substring(0, _temp.indexOf('=')); - String nameVal = _temp.substring(_temp.indexOf('=') + 2, _temp.length() - 1); - if(name == "name"){ - _itemName = nameVal; - } else if(name == "filename"){ - _itemFilename = nameVal; - _itemIsFile = true; - } - } - _temp = String(); - } else { - _multiParseState = WAIT_FOR_RETURN1; - //value starts from here - _itemSize = 0; - _itemStartIndex = _parsedLength; - _itemValue = String(); - if(_itemIsFile){ - if(_itemBuffer) - free(_itemBuffer); - _itemBuffer = (uint8_t*)malloc(1460); - if(_itemBuffer == NULL){ - _multiParseState = PARSE_ERROR; - return; - } - _itemBufferIndex = 0; - } - } - } - } else if(_multiParseState == EXPECT_FEED1){ - if(data != '\n'){ - _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); _parseMultipartPostByte(data, last); - } else { - _multiParseState = EXPECT_DASH1; - } - } else if(_multiParseState == EXPECT_DASH1){ - if(data != '-'){ - _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); _parseMultipartPostByte(data, last); - } else { - _multiParseState = EXPECT_DASH2; - } - } else if(_multiParseState == EXPECT_DASH2){ - if(data != '-'){ - _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); _parseMultipartPostByte(data, last); - } else { - _multiParseState = BOUNDARY_OR_DATA; - _boundaryPosition = 0; - } - } else if(_multiParseState == BOUNDARY_OR_DATA){ - if(_boundaryPosition < _boundary.length() && _boundary.c_str()[_boundaryPosition] != data){ - _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); - uint8_t i; - for(i=0; i<_boundaryPosition; i++) - itemWriteByte(_boundary.c_str()[i]); - _parseMultipartPostByte(data, last); - } else if(_boundaryPosition == _boundary.length() - 1){ - _multiParseState = DASH3_OR_RETURN2; - if(!_itemIsFile){ - _addParam(new AsyncWebParameter(_itemName, _itemValue, true)); - } else { - if(_itemSize){ - //check if authenticated before calling the upload - if(_handler) _handler->handleUpload(this, _itemFilename, _itemSize - _itemBufferIndex, _itemBuffer, _itemBufferIndex, true); - _itemBufferIndex = 0; - _addParam(new AsyncWebParameter(_itemName, _itemFilename, true, true, _itemSize)); - } - free(_itemBuffer); - _itemBuffer = NULL; - } - - } else { - _boundaryPosition++; - } - } else if(_multiParseState == DASH3_OR_RETURN2){ - if(data == '-' && (_contentLength - _parsedLength - 4) != 0){ - //os_printf("ERROR: The parser got to the end of the POST but is expecting %u bytes more!\nDrop an issue so we can have more info on the matter!\n", _contentLength - _parsedLength - 4); - _contentLength = _parsedLength + 4;//lets close the request gracefully - } - if(data == '\r'){ - _multiParseState = EXPECT_FEED2; - } else if(data == '-' && _contentLength == (_parsedLength + 4)){ - _multiParseState = PARSING_FINISHED; - } else { - _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); - uint8_t i; for(i=0; i<_boundary.length(); i++) itemWriteByte(_boundary.c_str()[i]); - _parseMultipartPostByte(data, last); - } - } else if(_multiParseState == EXPECT_FEED2){ - if(data == '\n'){ - _multiParseState = PARSE_HEADERS; - _itemIsFile = false; - } else { - _multiParseState = WAIT_FOR_RETURN1; - itemWriteByte('\r'); itemWriteByte('\n'); itemWriteByte('-'); itemWriteByte('-'); - uint8_t i; for(i=0; i<_boundary.length(); i++) itemWriteByte(_boundary.c_str()[i]); - itemWriteByte('\r'); _parseMultipartPostByte(data, last); - } - } -} - -void AsyncWebServerRequest::_parseLine(){ - if(_parseState == PARSE_REQ_START){ - if(!_temp.length()){ - _parseState = PARSE_REQ_FAIL; - _client->close(); - } else { - _parseReqHead(); - _parseState = PARSE_REQ_HEADERS; - } - return; - } - - if(_parseState == PARSE_REQ_HEADERS){ - if(!_temp.length()){ - //end of headers - _server->_rewriteRequest(this); - _server->_attachHandler(this); - _removeNotInterestingHeaders(); - if(_expectingContinue){ - const char * response = "HTTP/1.1 100 Continue\r\n\r\n"; - _client->write(response, os_strlen(response)); - } - //check handler for authentication - if(_contentLength){ - _parseState = PARSE_REQ_BODY; - } else { - _parseState = PARSE_REQ_END; - if(_handler) _handler->handleRequest(this); - else send(501); - } - } else _parseReqHeader(); - } -} - -size_t AsyncWebServerRequest::headers() const{ - return _headers.length(); -} - -bool AsyncWebServerRequest::hasHeader(const String& name) const { - for(const auto& h: _headers){ - if(h->name().equalsIgnoreCase(name)){ - return true; - } - } - return false; -} - -bool AsyncWebServerRequest::hasHeader(const __FlashStringHelper * data) const { - PGM_P p = reinterpret_cast(data); - size_t n = 0; - while (1) { - if (pgm_read_byte(p+n) == 0) break; - n += 1; - } - char * name = (char*) malloc(n+1); - name[n] = 0; - if (name) { - for(size_t b=0; bname().equalsIgnoreCase(name)){ - return h; - } - } - return nullptr; -} - -AsyncWebHeader* AsyncWebServerRequest::getHeader(const __FlashStringHelper * data) const { - PGM_P p = reinterpret_cast(data); - size_t n = strlen_P(p); - char * name = (char*) malloc(n+1); - if (name) { - strcpy_P(name, p); - AsyncWebHeader* result = getHeader( String(name)); - free(name); - return result; - } else { - return nullptr; - } -} - -AsyncWebHeader* AsyncWebServerRequest::getHeader(size_t num) const { - auto header = _headers.nth(num); - return header ? *header : nullptr; -} - -size_t AsyncWebServerRequest::params() const { - return _params.length(); -} - -bool AsyncWebServerRequest::hasParam(const String& name, bool post, bool file) const { - for(const auto& p: _params){ - if(p->name() == name && p->isPost() == post && p->isFile() == file){ - return true; - } - } - return false; -} - -bool AsyncWebServerRequest::hasParam(const __FlashStringHelper * data, bool post, bool file) const { - PGM_P p = reinterpret_cast(data); - size_t n = strlen_P(p); - - char * name = (char*) malloc(n+1); - name[n] = 0; - if (name) { - strcpy_P(name,p); - bool result = hasParam( name, post, file); - free(name); - return result; - } else { - return false; - } -} - -AsyncWebParameter* AsyncWebServerRequest::getParam(const String& name, bool post, bool file) const { - for(const auto& p: _params){ - if(p->name() == name && p->isPost() == post && p->isFile() == file){ - return p; - } - } - return nullptr; -} - -AsyncWebParameter* AsyncWebServerRequest::getParam(const __FlashStringHelper * data, bool post, bool file) const { - PGM_P p = reinterpret_cast(data); - size_t n = strlen_P(p); - char * name = (char*) malloc(n+1); - if (name) { - strcpy_P(name, p); - AsyncWebParameter* result = getParam(name, post, file); - free(name); - return result; - } else { - return nullptr; - } -} - -AsyncWebParameter* AsyncWebServerRequest::getParam(size_t num) const { - auto param = _params.nth(num); - return param ? *param : nullptr; -} - -void AsyncWebServerRequest::addInterestingHeader(const String& name){ - if(!_interestingHeaders.containsIgnoreCase(name)) - _interestingHeaders.add(name); -} - -void AsyncWebServerRequest::send(AsyncWebServerResponse *response){ - _response = response; - if(_response == NULL){ - _client->close(true); - _onDisconnect(); - return; - } - if(!_response->_sourceValid()){ - delete response; - _response = NULL; - send(500); - } - else { - _client->setRxTimeout(0); - _response->_respond(this); - } -} - -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(int code, const String& contentType, const String& content){ - return new AsyncBasicResponse(code, contentType, content); -} - -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ - if(fs.exists(path) || (!download && fs.exists(path+".gz"))) - return new AsyncFileResponse(fs, path, contentType, download, callback); - return NULL; -} - -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ - if(content == true) - return new AsyncFileResponse(content, path, contentType, download, callback); - return NULL; -} - -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback){ - return new AsyncStreamResponse(stream, contentType, len, callback); -} - -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ - return new AsyncCallbackResponse(contentType, len, callback, templateCallback); -} - -AsyncWebServerResponse * AsyncWebServerRequest::beginChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ - if(_version) - return new AsyncChunkedResponse(contentType, callback, templateCallback); - return new AsyncCallbackResponse(contentType, 0, callback, templateCallback); -} - -AsyncResponseStream * AsyncWebServerRequest::beginResponseStream(const String& contentType, size_t bufferSize){ - return new AsyncResponseStream(contentType, bufferSize); -} - -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback){ - return new AsyncProgmemResponse(code, contentType, content, len, callback); -} - -AsyncWebServerResponse * AsyncWebServerRequest::beginResponse_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback){ - return beginResponse_P(code, contentType, (const uint8_t *)content, strlen_P(content), callback); -} - -void AsyncWebServerRequest::send(int code, const String& contentType, const String& content){ - send(beginResponse(code, contentType, content)); -} - -void AsyncWebServerRequest::send(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ - if(fs.exists(path) || (!download && fs.exists(path+".gz"))){ - send(beginResponse(fs, path, contentType, download, callback)); - } else send(404); -} - -void AsyncWebServerRequest::send(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback){ - if(content == true){ - send(beginResponse(content, path, contentType, download, callback)); - } else send(404); -} - -void AsyncWebServerRequest::send(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback){ - send(beginResponse(stream, contentType, len, callback)); -} - -void AsyncWebServerRequest::send(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ - send(beginResponse(contentType, len, callback, templateCallback)); -} - -void AsyncWebServerRequest::sendChunked(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback){ - send(beginChunkedResponse(contentType, callback, templateCallback)); -} - -void AsyncWebServerRequest::send_P(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback){ - send(beginResponse_P(code, contentType, content, len, callback)); -} - -void AsyncWebServerRequest::send_P(int code, const String& contentType, PGM_P content, AwsTemplateProcessor callback){ - send(beginResponse_P(code, contentType, content, callback)); -} - -void AsyncWebServerRequest::redirect(const String& url){ - AsyncWebServerResponse * response = beginResponse(302); - response->addHeader("Location",url); - send(response); -} - -bool AsyncWebServerRequest::authenticate(const char * username, const char * password, const char * realm, bool passwordIsHash){ - if(_authorization.length()){ - if(_isDigest) - return checkDigestAuthentication(_authorization.c_str(), methodToString(), username, password, realm, passwordIsHash, NULL, NULL, NULL); - else if(!passwordIsHash) - return checkBasicAuthentication(_authorization.c_str(), username, password); - else - return _authorization.equals(password); - } - return false; -} - -bool AsyncWebServerRequest::authenticate(const char * hash){ - if(!_authorization.length() || hash == NULL) - return false; - - if(_isDigest){ - String hStr = String(hash); - int separator = hStr.indexOf(":"); - if(separator <= 0) - return false; - String username = hStr.substring(0, separator); - hStr = hStr.substring(separator + 1); - separator = hStr.indexOf(":"); - if(separator <= 0) - return false; - String realm = hStr.substring(0, separator); - hStr = hStr.substring(separator + 1); - return checkDigestAuthentication(_authorization.c_str(), methodToString(), username.c_str(), hStr.c_str(), realm.c_str(), true, NULL, NULL, NULL); - } - - return (_authorization.equals(hash)); -} - -void AsyncWebServerRequest::requestAuthentication(const char * realm, bool isDigest){ - AsyncWebServerResponse * r = beginResponse(401); - if(!isDigest && realm == NULL){ - r->addHeader("WWW-Authenticate", "Basic realm=\"Login Required\""); - } else if(!isDigest){ - String header = "Basic realm=\""; - header.concat(realm); - header.concat("\""); - r->addHeader("WWW-Authenticate", header); - } else { - String header = "Digest "; - header.concat(requestDigestAuthentication(realm)); - r->addHeader("WWW-Authenticate", header); - } - send(r); -} - -bool AsyncWebServerRequest::hasArg(const char* name) const { - for(const auto& arg: _params){ - if(arg->name() == name){ - return true; - } - } - return false; -} - -bool AsyncWebServerRequest::hasArg(const __FlashStringHelper * data) const { - PGM_P p = reinterpret_cast(data); - size_t n = strlen_P(p); - char * name = (char*) malloc(n+1); - if (name) { - strcpy_P(name, p); - bool result = hasArg( name ); - free(name); - return result; - } else { - return false; - } -} - - -const String& AsyncWebServerRequest::arg(const String& name) const { - for(const auto& arg: _params){ - if(arg->name() == name){ - return arg->value(); - } - } - return SharedEmptyString; -} - -const String& AsyncWebServerRequest::arg(const __FlashStringHelper * data) const { - PGM_P p = reinterpret_cast(data); - size_t n = strlen_P(p); - char * name = (char*) malloc(n+1); - if (name) { - strcpy_P(name, p); - const String & result = arg( String(name) ); - free(name); - return result; - } else { - return SharedEmptyString; - } - -} - -const String& AsyncWebServerRequest::arg(size_t i) const { - return getParam(i)->value(); -} - -const String& AsyncWebServerRequest::argName(size_t i) const { - return getParam(i)->name(); -} - -const String& AsyncWebServerRequest::pathArg(size_t i) const { - auto param = _pathParams.nth(i); - return param ? **param : SharedEmptyString; -} - -const String& AsyncWebServerRequest::header(const char* name) const { - AsyncWebHeader* h = getHeader(String(name)); - return h ? h->value() : SharedEmptyString; -} - -const String& AsyncWebServerRequest::header(const __FlashStringHelper * data) const { - PGM_P p = reinterpret_cast(data); - size_t n = strlen_P(p); - char * name = (char*) malloc(n+1); - if (name) { - strcpy_P(name, p); - const String & result = header( (const char *)name ); - free(name); - return result; - } else { - return SharedEmptyString; - } -}; - - -const String& AsyncWebServerRequest::header(size_t i) const { - AsyncWebHeader* h = getHeader(i); - return h ? h->value() : SharedEmptyString; -} - -const String& AsyncWebServerRequest::headerName(size_t i) const { - AsyncWebHeader* h = getHeader(i); - return h ? h->name() : SharedEmptyString; -} - -String AsyncWebServerRequest::urlDecode(const String& text) const { - char temp[] = "0x00"; - unsigned int len = text.length(); - unsigned int i = 0; - String decoded = String(); - decoded.reserve(len); // Allocate the string internal buffer - never longer from source text - while (i < len){ - char decodedChar; - char encodedChar = text.charAt(i++); - if ((encodedChar == '%') && (i + 1 < len)){ - temp[2] = text.charAt(i++); - temp[3] = text.charAt(i++); - decodedChar = strtol(temp, NULL, 16); - } else if (encodedChar == '+') { - decodedChar = ' '; - } else { - decodedChar = encodedChar; // normal ascii char - } - decoded.concat(decodedChar); - } - return decoded; -} - - -const char * AsyncWebServerRequest::methodToString() const { - if(_method == HTTP_ANY) return "ANY"; - else if(_method & HTTP_GET) return "GET"; - else if(_method & HTTP_POST) return "POST"; - else if(_method & HTTP_DELETE) return "DELETE"; - else if(_method & HTTP_PUT) return "PUT"; - else if(_method & HTTP_PATCH) return "PATCH"; - else if(_method & HTTP_HEAD) return "HEAD"; - else if(_method & HTTP_OPTIONS) return "OPTIONS"; - return "UNKNOWN"; -} - -const char *AsyncWebServerRequest::requestedConnTypeToString() const { - switch (_reqconntype) { - case RCT_NOT_USED: return "RCT_NOT_USED"; - case RCT_DEFAULT: return "RCT_DEFAULT"; - case RCT_HTTP: return "RCT_HTTP"; - case RCT_WS: return "RCT_WS"; - case RCT_EVENT: return "RCT_EVENT"; - default: return "ERROR"; - } -} - -bool AsyncWebServerRequest::isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2, RequestedConnectionType erct3) { - bool res = false; - if ((erct1 != RCT_NOT_USED) && (erct1 == _reqconntype)) res = true; - if ((erct2 != RCT_NOT_USED) && (erct2 == _reqconntype)) res = true; - if ((erct3 != RCT_NOT_USED) && (erct3 == _reqconntype)) res = true; - return res; -} diff --git a/lib/ESPAsyncWebServer/src/WebResponseImpl.h b/lib/ESPAsyncWebServer/src/WebResponseImpl.h deleted file mode 100644 index 9a64e3a5..00000000 --- a/lib/ESPAsyncWebServer/src/WebResponseImpl.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef ASYNCWEBSERVERRESPONSEIMPL_H_ -#define ASYNCWEBSERVERRESPONSEIMPL_H_ - -#ifdef Arduino_h -// arduino is not compatible with std::vector -#undef min -#undef max -#endif -#include -// It is possible to restore these defines, but one can use _min and _max instead. Or std::min, std::max. - -class AsyncBasicResponse: public AsyncWebServerResponse { - private: - String _content; - public: - AsyncBasicResponse(int code, const String& contentType=String(), const String& content=String()); - void _respond(AsyncWebServerRequest *request); - size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); - bool _sourceValid() const { return true; } -}; - -class AsyncAbstractResponse: public AsyncWebServerResponse { - private: - String _head; - // Data is inserted into cache at begin(). - // This is inefficient with vector, but if we use some other container, - // we won't be able to access it as contiguous array of bytes when reading from it, - // so by gaining performance in one place, we'll lose it in another. - std::vector _cache; - size_t _readDataFromCacheOrContent(uint8_t* data, const size_t len); - size_t _fillBufferAndProcessTemplates(uint8_t* buf, size_t maxLen); - protected: - AwsTemplateProcessor _callback; - public: - AsyncAbstractResponse(AwsTemplateProcessor callback=nullptr); - void _respond(AsyncWebServerRequest *request); - size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time); - bool _sourceValid() const { return false; } - virtual size_t _fillBuffer(uint8_t *buf __attribute__((unused)), size_t maxLen __attribute__((unused))) { return 0; } -}; - -#ifndef TEMPLATE_PLACEHOLDER -#define TEMPLATE_PLACEHOLDER '%' -#endif - -#define TEMPLATE_PARAM_NAME_LENGTH 32 -class AsyncFileResponse: public AsyncAbstractResponse { - using File = fs::File; - using FS = fs::FS; - private: - File _content; - String _path; - void _setContentType(const String& path); - public: - AsyncFileResponse(FS &fs, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); - AsyncFileResponse(File content, const String& path, const String& contentType=String(), bool download=false, AwsTemplateProcessor callback=nullptr); - ~AsyncFileResponse(); - bool _sourceValid() const { return !!(_content); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; -}; - -class AsyncStreamResponse: public AsyncAbstractResponse { - private: - Stream *_content; - public: - AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback=nullptr); - bool _sourceValid() const { return !!(_content); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; -}; - -class AsyncCallbackResponse: public AsyncAbstractResponse { - private: - AwsResponseFiller _content; - size_t _filledLength; - public: - AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); - bool _sourceValid() const { return !!(_content); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; -}; - -class AsyncChunkedResponse: public AsyncAbstractResponse { - private: - AwsResponseFiller _content; - size_t _filledLength; - public: - AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback=nullptr); - bool _sourceValid() const { return !!(_content); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; -}; - -class AsyncProgmemResponse: public AsyncAbstractResponse { - private: - const uint8_t * _content; - size_t _readLength; - public: - AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback=nullptr); - bool _sourceValid() const { return true; } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; -}; - -class cbuf; - -class AsyncResponseStream: public AsyncAbstractResponse, public Print { - private: - cbuf *_content; - public: - AsyncResponseStream(const String& contentType, size_t bufferSize); - ~AsyncResponseStream(); - bool _sourceValid() const { return (_state < RESPONSE_END); } - virtual size_t _fillBuffer(uint8_t *buf, size_t maxLen) override; - size_t write(const uint8_t *data, size_t len); - size_t write(uint8_t data); - using Print::write; -}; - -#endif /* ASYNCWEBSERVERRESPONSEIMPL_H_ */ diff --git a/lib/ESPAsyncWebServer/src/WebResponses.cpp b/lib/ESPAsyncWebServer/src/WebResponses.cpp deleted file mode 100644 index a22e991a..00000000 --- a/lib/ESPAsyncWebServer/src/WebResponses.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "ESPAsyncWebServer.h" -#include "WebResponseImpl.h" -#include "cbuf.h" - -// Since ESP8266 does not link memchr by default, here's its implementation. -void* memchr(void* ptr, int ch, size_t count) -{ - unsigned char* p = static_cast(ptr); - while(count--) - if(*p++ == static_cast(ch)) - return --p; - return nullptr; -} - - -/* - * Abstract Response - * */ -const char* AsyncWebServerResponse::_responseCodeToString(int code) { - switch (code) { - case 100: return "Continue"; - case 101: return "Switching Protocols"; - case 200: return "OK"; - case 201: return "Created"; - case 202: return "Accepted"; - case 203: return "Non-Authoritative Information"; - case 204: return "No Content"; - case 205: return "Reset Content"; - case 206: return "Partial Content"; - case 300: return "Multiple Choices"; - case 301: return "Moved Permanently"; - case 302: return "Found"; - case 303: return "See Other"; - case 304: return "Not Modified"; - case 305: return "Use Proxy"; - case 307: return "Temporary Redirect"; - case 400: return "Bad Request"; - case 401: return "Unauthorized"; - case 402: return "Payment Required"; - case 403: return "Forbidden"; - case 404: return "Not Found"; - case 405: return "Method Not Allowed"; - case 406: return "Not Acceptable"; - case 407: return "Proxy Authentication Required"; - case 408: return "Request Time-out"; - case 409: return "Conflict"; - case 410: return "Gone"; - case 411: return "Length Required"; - case 412: return "Precondition Failed"; - case 413: return "Request Entity Too Large"; - case 414: return "Request-URI Too Large"; - case 415: return "Unsupported Media Type"; - case 416: return "Requested range not satisfiable"; - case 417: return "Expectation Failed"; - case 500: return "Internal Server Error"; - case 501: return "Not Implemented"; - case 502: return "Bad Gateway"; - case 503: return "Service Unavailable"; - case 504: return "Gateway Time-out"; - case 505: return "HTTP Version not supported"; - default: return ""; - } -} - -AsyncWebServerResponse::AsyncWebServerResponse() - : _code(0) - , _headers(LinkedList([](AsyncWebHeader *h){ delete h; })) - , _contentType() - , _contentLength(0) - , _sendContentLength(true) - , _chunked(false) - , _headLength(0) - , _sentLength(0) - , _ackedLength(0) - , _writtenLength(0) - , _state(RESPONSE_SETUP) -{ - for(auto header: DefaultHeaders::Instance()) { - _headers.add(new AsyncWebHeader(header->name(), header->value())); - } -} - -AsyncWebServerResponse::~AsyncWebServerResponse(){ - _headers.free(); -} - -void AsyncWebServerResponse::setCode(int code){ - if(_state == RESPONSE_SETUP) - _code = code; -} - -void AsyncWebServerResponse::setContentLength(size_t len){ - if(_state == RESPONSE_SETUP) - _contentLength = len; -} - -void AsyncWebServerResponse::setContentType(const String& type){ - if(_state == RESPONSE_SETUP) - _contentType = type; -} - -void AsyncWebServerResponse::addHeader(const String& name, const String& value){ - _headers.add(new AsyncWebHeader(name, value)); -} - -String AsyncWebServerResponse::_assembleHead(uint8_t version){ - if(version){ - addHeader("Accept-Ranges","none"); - if(_chunked) - addHeader("Transfer-Encoding","chunked"); - } - String out = String(); - int bufSize = 300; - char buf[bufSize]; - - snprintf(buf, bufSize, "HTTP/1.%d %d %s\r\n", version, _code, _responseCodeToString(_code)); - out.concat(buf); - - if(_sendContentLength) { - snprintf(buf, bufSize, "Content-Length: %d\r\n", _contentLength); - out.concat(buf); - } - if(_contentType.length()) { - snprintf(buf, bufSize, "Content-Type: %s\r\n", _contentType.c_str()); - out.concat(buf); - } - - for(const auto& header: _headers){ - snprintf(buf, bufSize, "%s: %s\r\n", header->name().c_str(), header->value().c_str()); - out.concat(buf); - } - _headers.free(); - - out.concat("\r\n"); - _headLength = out.length(); - return out; -} - -bool AsyncWebServerResponse::_started() const { return _state > RESPONSE_SETUP; } -bool AsyncWebServerResponse::_finished() const { return _state > RESPONSE_WAIT_ACK; } -bool AsyncWebServerResponse::_failed() const { return _state == RESPONSE_FAILED; } -bool AsyncWebServerResponse::_sourceValid() const { return false; } -void AsyncWebServerResponse::_respond(AsyncWebServerRequest *request){ _state = RESPONSE_END; request->client()->close(); } -size_t AsyncWebServerResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ (void)request; (void)len; (void)time; return 0; } - -/* - * String/Code Response - * */ -AsyncBasicResponse::AsyncBasicResponse(int code, const String& contentType, const String& content){ - _code = code; - _content = content; - _contentType = contentType; - if(_content.length()){ - _contentLength = _content.length(); - if(!_contentType.length()) - _contentType = "text/plain"; - } - addHeader("Connection","close"); -} - -void AsyncBasicResponse::_respond(AsyncWebServerRequest *request){ - _state = RESPONSE_HEADERS; - String out = _assembleHead(request->version()); - size_t outLen = out.length(); - size_t space = request->client()->space(); - if(!_contentLength && space >= outLen){ - _writtenLength += request->client()->write(out.c_str(), outLen); - _state = RESPONSE_WAIT_ACK; - } else if(_contentLength && space >= outLen + _contentLength){ - out += _content; - outLen += _contentLength; - _writtenLength += request->client()->write(out.c_str(), outLen); - _state = RESPONSE_WAIT_ACK; - } else if(space && space < outLen){ - String partial = out.substring(0, space); - _content = out.substring(space) + _content; - _contentLength += outLen - space; - _writtenLength += request->client()->write(partial.c_str(), partial.length()); - _state = RESPONSE_CONTENT; - } else if(space > outLen && space < (outLen + _contentLength)){ - size_t shift = space - outLen; - outLen += shift; - _sentLength += shift; - out += _content.substring(0, shift); - _content = _content.substring(shift); - _writtenLength += request->client()->write(out.c_str(), outLen); - _state = RESPONSE_CONTENT; - } else { - _content = out + _content; - _contentLength += outLen; - _state = RESPONSE_CONTENT; - } -} - -size_t AsyncBasicResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ - (void)time; - _ackedLength += len; - if(_state == RESPONSE_CONTENT){ - size_t available = _contentLength - _sentLength; - size_t space = request->client()->space(); - //we can fit in this packet - if(space > available){ - _writtenLength += request->client()->write(_content.c_str(), available); - _content = String(); - _state = RESPONSE_WAIT_ACK; - return available; - } - //send some data, the rest on ack - String out = _content.substring(0, space); - _content = _content.substring(space); - _sentLength += space; - _writtenLength += request->client()->write(out.c_str(), space); - return space; - } else if(_state == RESPONSE_WAIT_ACK){ - if(_ackedLength >= _writtenLength){ - _state = RESPONSE_END; - } - } - return 0; -} - - -/* - * Abstract Response - * */ - -AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback): _callback(callback) -{ - // In case of template processing, we're unable to determine real response size - if(callback) { - _contentLength = 0; - _sendContentLength = false; - _chunked = true; - } -} - -void AsyncAbstractResponse::_respond(AsyncWebServerRequest *request){ - addHeader("Connection","close"); - _head = _assembleHead(request->version()); - _state = RESPONSE_HEADERS; - _ack(request, 0, 0); -} - -size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, uint32_t time){ - (void)time; - if(!_sourceValid()){ - _state = RESPONSE_FAILED; - request->client()->close(); - return 0; - } - _ackedLength += len; - size_t space = request->client()->space(); - - size_t headLen = _head.length(); - if(_state == RESPONSE_HEADERS){ - if(space >= headLen){ - _state = RESPONSE_CONTENT; - space -= headLen; - } else { - String out = _head.substring(0, space); - _head = _head.substring(space); - _writtenLength += request->client()->write(out.c_str(), out.length()); - return out.length(); - } - } - - if(_state == RESPONSE_CONTENT){ - size_t outLen; - if(_chunked){ - if(space <= 8){ - return 0; - } - outLen = space; - } else if(!_sendContentLength){ - outLen = space; - } else { - outLen = ((_contentLength - _sentLength) > space)?space:(_contentLength - _sentLength); - } - - uint8_t *buf = (uint8_t *)malloc(outLen+headLen); - if (!buf) { - // os_printf("_ack malloc %d failed\n", outLen+headLen); - return 0; - } - - if(headLen){ - memcpy(buf, _head.c_str(), _head.length()); - } - - size_t readLen = 0; - - if(_chunked){ - // HTTP 1.1 allows leading zeros in chunk length. Or spaces may be added. - // See RFC2616 sections 2, 3.6.1. - readLen = _fillBufferAndProcessTemplates(buf+headLen+6, outLen - 8); - if(readLen == RESPONSE_TRY_AGAIN){ - free(buf); - return 0; - } - outLen = sprintf((char*)buf+headLen, "%x", readLen) + headLen; - while(outLen < headLen + 4) buf[outLen++] = ' '; - buf[outLen++] = '\r'; - buf[outLen++] = '\n'; - outLen += readLen; - buf[outLen++] = '\r'; - buf[outLen++] = '\n'; - } else { - readLen = _fillBufferAndProcessTemplates(buf+headLen, outLen); - if(readLen == RESPONSE_TRY_AGAIN){ - free(buf); - return 0; - } - outLen = readLen + headLen; - } - - if(headLen){ - _head = String(); - } - - if(outLen){ - _writtenLength += request->client()->write((const char*)buf, outLen); - } - - if(_chunked){ - _sentLength += readLen; - } else { - _sentLength += outLen - headLen; - } - - free(buf); - - if((_chunked && readLen == 0) || (!_sendContentLength && outLen == 0) || (!_chunked && _sentLength == _contentLength)){ - _state = RESPONSE_WAIT_ACK; - } - return outLen; - - } else if(_state == RESPONSE_WAIT_ACK){ - if(!_sendContentLength || _ackedLength >= _writtenLength){ - _state = RESPONSE_END; - if(!_chunked && !_sendContentLength) - request->client()->close(true); - } - } - return 0; -} - -size_t AsyncAbstractResponse::_readDataFromCacheOrContent(uint8_t* data, const size_t len) -{ - // If we have something in cache, copy it to buffer - const size_t readFromCache = std::min(len, _cache.size()); - if(readFromCache) { - memcpy(data, _cache.data(), readFromCache); - _cache.erase(_cache.begin(), _cache.begin() + readFromCache); - } - // If we need to read more... - const size_t needFromFile = len - readFromCache; - const size_t readFromContent = _fillBuffer(data + readFromCache, needFromFile); - return readFromCache + readFromContent; -} - -size_t AsyncAbstractResponse::_fillBufferAndProcessTemplates(uint8_t* data, size_t len) -{ - if(!_callback) - return _fillBuffer(data, len); - - const size_t originalLen = len; - len = _readDataFromCacheOrContent(data, len); - // Now we've read 'len' bytes, either from cache or from file - // Search for template placeholders - uint8_t* pTemplateStart = data; - while((pTemplateStart < &data[len]) && (pTemplateStart = (uint8_t*)memchr(pTemplateStart, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart + 1))) { // data[0] ... data[len - 1] - uint8_t* pTemplateEnd = (pTemplateStart < &data[len - 1]) ? (uint8_t*)memchr(pTemplateStart + 1, TEMPLATE_PLACEHOLDER, &data[len - 1] - pTemplateStart) : nullptr; - // temporary buffer to hold parameter name - uint8_t buf[TEMPLATE_PARAM_NAME_LENGTH + 1]; - String paramName; - // If closing placeholder is found: - if(pTemplateEnd) { - // prepare argument to callback - const size_t paramNameLength = std::min(sizeof(buf) - 1, (unsigned int)(pTemplateEnd - pTemplateStart - 1)); - if(paramNameLength) { - memcpy(buf, pTemplateStart + 1, paramNameLength); - buf[paramNameLength] = 0; - paramName = String(reinterpret_cast(buf)); - } else { // double percent sign encountered, this is single percent sign escaped. - // remove the 2nd percent sign - memmove(pTemplateEnd, pTemplateEnd + 1, &data[len] - pTemplateEnd - 1); - len += _readDataFromCacheOrContent(&data[len - 1], 1) - 1; - ++pTemplateStart; - } - } else if(&data[len - 1] - pTemplateStart + 1 < TEMPLATE_PARAM_NAME_LENGTH + 2) { // closing placeholder not found, check if it's in the remaining file data - memcpy(buf, pTemplateStart + 1, &data[len - 1] - pTemplateStart); - const size_t readFromCacheOrContent = _readDataFromCacheOrContent(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PARAM_NAME_LENGTH + 2 - (&data[len - 1] - pTemplateStart + 1)); - if(readFromCacheOrContent) { - pTemplateEnd = (uint8_t*)memchr(buf + (&data[len - 1] - pTemplateStart), TEMPLATE_PLACEHOLDER, readFromCacheOrContent); - if(pTemplateEnd) { - // prepare argument to callback - *pTemplateEnd = 0; - paramName = String(reinterpret_cast(buf)); - // Copy remaining read-ahead data into cache - _cache.insert(_cache.begin(), pTemplateEnd + 1, buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent); - pTemplateEnd = &data[len - 1]; - } - else // closing placeholder not found in file data, store found percent symbol as is and advance to the next position - { - // but first, store read file data in cache - _cache.insert(_cache.begin(), buf + (&data[len - 1] - pTemplateStart), buf + (&data[len - 1] - pTemplateStart) + readFromCacheOrContent); - ++pTemplateStart; - } - } - else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position - ++pTemplateStart; - } - else // closing placeholder not found in content data, store found percent symbol as is and advance to the next position - ++pTemplateStart; - if(paramName.length()) { - // call callback and replace with result. - // Everything in range [pTemplateStart, pTemplateEnd] can be safely replaced with parameter value. - // Data after pTemplateEnd may need to be moved. - // The first byte of data after placeholder is located at pTemplateEnd + 1. - // It should be located at pTemplateStart + numBytesCopied (to begin right after inserted parameter value). - const String paramValue(_callback(paramName)); - const char* pvstr = paramValue.c_str(); - const unsigned int pvlen = paramValue.length(); - const size_t numBytesCopied = std::min(pvlen, static_cast(&data[originalLen - 1] - pTemplateStart + 1)); - // make room for param value - // 1. move extra data to cache if parameter value is longer than placeholder AND if there is no room to store - if((pTemplateEnd + 1 < pTemplateStart + numBytesCopied) && (originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1) < len)) { - _cache.insert(_cache.begin(), &data[originalLen - (pTemplateStart + numBytesCopied - pTemplateEnd - 1)], &data[len]); - //2. parameter value is longer than placeholder text, push the data after placeholder which not saved into cache further to the end - memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[originalLen] - pTemplateStart - numBytesCopied); - len = originalLen; // fix issue with truncated data, not sure if it has any side effects - } else if(pTemplateEnd + 1 != pTemplateStart + numBytesCopied) - //2. Either parameter value is shorter than placeholder text OR there is enough free space in buffer to fit. - // Move the entire data after the placeholder - memmove(pTemplateStart + numBytesCopied, pTemplateEnd + 1, &data[len] - pTemplateEnd - 1); - // 3. replace placeholder with actual value - memcpy(pTemplateStart, pvstr, numBytesCopied); - // If result is longer than buffer, copy the remainder into cache (this could happen only if placeholder text itself did not fit entirely in buffer) - if(numBytesCopied < pvlen) { - _cache.insert(_cache.begin(), pvstr + numBytesCopied, pvstr + pvlen); - } else if(pTemplateStart + numBytesCopied < pTemplateEnd + 1) { // result is copied fully; if result is shorter than placeholder text... - // there is some free room, fill it from cache - const size_t roomFreed = pTemplateEnd + 1 - pTemplateStart - numBytesCopied; - const size_t totalFreeRoom = originalLen - len + roomFreed; - len += _readDataFromCacheOrContent(&data[len - roomFreed], totalFreeRoom) - roomFreed; - } else { // result is copied fully; it is longer than placeholder text - const size_t roomTaken = pTemplateStart + numBytesCopied - pTemplateEnd - 1; - len = std::min(len + roomTaken, originalLen); - } - } - } // while(pTemplateStart) - return len; -} - - -/* - * File Response - * */ - -AsyncFileResponse::~AsyncFileResponse(){ - if(_content) - _content.close(); -} - -void AsyncFileResponse::_setContentType(const String& path){ - if (path.endsWith(".html")) _contentType = "text/html"; - else if (path.endsWith(".htm")) _contentType = "text/html"; - else if (path.endsWith(".css")) _contentType = "text/css"; - else if (path.endsWith(".json")) _contentType = "application/json"; - else if (path.endsWith(".js")) _contentType = "application/javascript"; - else if (path.endsWith(".png")) _contentType = "image/png"; - else if (path.endsWith(".gif")) _contentType = "image/gif"; - else if (path.endsWith(".jpg")) _contentType = "image/jpeg"; - else if (path.endsWith(".ico")) _contentType = "image/x-icon"; - else if (path.endsWith(".svg")) _contentType = "image/svg+xml"; - else if (path.endsWith(".eot")) _contentType = "font/eot"; - else if (path.endsWith(".woff")) _contentType = "font/woff"; - else if (path.endsWith(".woff2")) _contentType = "font/woff2"; - else if (path.endsWith(".ttf")) _contentType = "font/ttf"; - else if (path.endsWith(".xml")) _contentType = "text/xml"; - else if (path.endsWith(".pdf")) _contentType = "application/pdf"; - else if (path.endsWith(".zip")) _contentType = "application/zip"; - else if(path.endsWith(".gz")) _contentType = "application/x-gzip"; - else _contentType = "text/plain"; -} - -AsyncFileResponse::AsyncFileResponse(FS &fs, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){ - _code = 200; - _path = path; - - if(!download && !fs.exists(_path) && fs.exists(_path+".gz")){ - _path = _path+".gz"; - addHeader("Content-Encoding", "gzip"); - _callback = nullptr; // Unable to process zipped templates - _sendContentLength = true; - _chunked = false; - } - - _content = fs.open(_path, "r"); - _contentLength = _content.size(); - - if(contentType == "") - _setContentType(path); - else - _contentType = contentType; - - int filenameStart = path.lastIndexOf('/') + 1; - char buf[26+path.length()-filenameStart]; - char* filename = (char*)path.c_str() + filenameStart; - - if(download) { - // set filename and force download - snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", filename); - } else { - // set filename and force rendering - snprintf(buf, sizeof (buf), "inline; filename=\"%s\"", filename); - } - addHeader("Content-Disposition", buf); -} - -AsyncFileResponse::AsyncFileResponse(File content, const String& path, const String& contentType, bool download, AwsTemplateProcessor callback): AsyncAbstractResponse(callback){ - _code = 200; - _path = path; - - if(!download && String(content.name()).endsWith(".gz") && !path.endsWith(".gz")){ - addHeader("Content-Encoding", "gzip"); - _callback = nullptr; // Unable to process gzipped templates - _sendContentLength = true; - _chunked = false; - } - - _content = content; - _contentLength = _content.size(); - - if(contentType == "") - _setContentType(path); - else - _contentType = contentType; - - int filenameStart = path.lastIndexOf('/') + 1; - char buf[26+path.length()-filenameStart]; - char* filename = (char*)path.c_str() + filenameStart; - - if(download) { - snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", filename); - } else { - snprintf(buf, sizeof (buf), "inline; filename=\"%s\"", filename); - } - addHeader("Content-Disposition", buf); -} - -size_t AsyncFileResponse::_fillBuffer(uint8_t *data, size_t len){ - return _content.read(data, len); -} - -/* - * Stream Response - * */ - -AsyncStreamResponse::AsyncStreamResponse(Stream &stream, const String& contentType, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) { - _code = 200; - _content = &stream; - _contentLength = len; - _contentType = contentType; -} - -size_t AsyncStreamResponse::_fillBuffer(uint8_t *data, size_t len){ - size_t available = _content->available(); - size_t outLen = (available > len)?len:available; - size_t i; - for(i=0;iread(); - return outLen; -} - -/* - * Callback Response - * */ - -AsyncCallbackResponse::AsyncCallbackResponse(const String& contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback): AsyncAbstractResponse(templateCallback) { - _code = 200; - _content = callback; - _contentLength = len; - if(!len) - _sendContentLength = false; - _contentType = contentType; - _filledLength = 0; -} - -size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){ - size_t ret = _content(data, len, _filledLength); - if(ret != RESPONSE_TRY_AGAIN){ - _filledLength += ret; - } - return ret; -} - -/* - * Chunked Response - * */ - -AsyncChunkedResponse::AsyncChunkedResponse(const String& contentType, AwsResponseFiller callback, AwsTemplateProcessor processorCallback): AsyncAbstractResponse(processorCallback) { - _code = 200; - _content = callback; - _contentLength = 0; - _contentType = contentType; - _sendContentLength = false; - _chunked = true; - _filledLength = 0; -} - -size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){ - size_t ret = _content(data, len, _filledLength); - if(ret != RESPONSE_TRY_AGAIN){ - _filledLength += ret; - } - return ret; -} - -/* - * Progmem Response - * */ - -AsyncProgmemResponse::AsyncProgmemResponse(int code, const String& contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback): AsyncAbstractResponse(callback) { - _code = code; - _content = content; - _contentType = contentType; - _contentLength = len; - _readLength = 0; -} - -size_t AsyncProgmemResponse::_fillBuffer(uint8_t *data, size_t len){ - size_t left = _contentLength - _readLength; - if (left > len) { - memcpy_P(data, _content + _readLength, len); - _readLength += len; - return len; - } - memcpy_P(data, _content + _readLength, left); - _readLength += left; - return left; -} - - -/* - * Response Stream (You can print/write/printf to it, up to the contentLen bytes) - * */ - -AsyncResponseStream::AsyncResponseStream(const String& contentType, size_t bufferSize){ - _code = 200; - _contentLength = 0; - _contentType = contentType; - _content = new cbuf(bufferSize); -} - -AsyncResponseStream::~AsyncResponseStream(){ - delete _content; -} - -size_t AsyncResponseStream::_fillBuffer(uint8_t *buf, size_t maxLen){ - return _content->read((char*)buf, maxLen); -} - -size_t AsyncResponseStream::write(const uint8_t *data, size_t len){ - if(_started()) - return 0; - - if(len > _content->room()){ - size_t needed = len - _content->room(); - _content->resizeAdd(needed); - } - size_t written = _content->write((const char*)data, len); - _contentLength += written; - return written; -} - -size_t AsyncResponseStream::write(uint8_t data){ - return write(&data, 1); -} diff --git a/lib/ESPAsyncWebServer/src/WebServer.cpp b/lib/ESPAsyncWebServer/src/WebServer.cpp deleted file mode 100644 index 95c2dd69..00000000 --- a/lib/ESPAsyncWebServer/src/WebServer.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - Asynchronous WebServer library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include "ESPAsyncWebServer.h" -#include "WebHandlerImpl.h" - -bool ON_STA_FILTER(AsyncWebServerRequest *request) { - return WiFi.localIP() == request->client()->localIP(); -} - -bool ON_AP_FILTER(AsyncWebServerRequest *request) { - return WiFi.localIP() != request->client()->localIP(); -} - - -AsyncWebServer::AsyncWebServer(uint16_t port) - : _server(port) - , _rewrites(LinkedList([](AsyncWebRewrite* r){ delete r; })) - , _handlers(LinkedList([](AsyncWebHandler* h){ delete h; })) -{ - _catchAllHandler = new AsyncCallbackWebHandler(); - if(_catchAllHandler == NULL) - return; - _server.onClient([](void *s, AsyncClient* c){ - if(c == NULL) - return; - c->setRxTimeout(3); - AsyncWebServerRequest *r = new AsyncWebServerRequest((AsyncWebServer*)s, c); - if(r == NULL){ - c->close(true); - c->free(); - delete c; - } - }, this); -} - -AsyncWebServer::~AsyncWebServer(){ - reset(); - end(); - if(_catchAllHandler) delete _catchAllHandler; -} - -AsyncWebRewrite& AsyncWebServer::addRewrite(AsyncWebRewrite* rewrite){ - _rewrites.add(rewrite); - return *rewrite; -} - -bool AsyncWebServer::removeRewrite(AsyncWebRewrite *rewrite){ - return _rewrites.remove(rewrite); -} - -AsyncWebRewrite& AsyncWebServer::rewrite(const char* from, const char* to){ - return addRewrite(new AsyncWebRewrite(from, to)); -} - -AsyncWebHandler& AsyncWebServer::addHandler(AsyncWebHandler* handler){ - _handlers.add(handler); - return *handler; -} - -bool AsyncWebServer::removeHandler(AsyncWebHandler *handler){ - return _handlers.remove(handler); -} - -void AsyncWebServer::begin(){ - _server.setNoDelay(true); - _server.begin(); -} - -void AsyncWebServer::end(){ - _server.end(); -} - -#if ASYNC_TCP_SSL_ENABLED -void AsyncWebServer::onSslFileRequest(AcSSlFileHandler cb, void* arg){ - _server.onSslFileRequest(cb, arg); -} - -void AsyncWebServer::beginSecure(const char *cert, const char *key, const char *password){ - _server.beginSecure(cert, key, password); -} -#endif - -void AsyncWebServer::_handleDisconnect(AsyncWebServerRequest *request){ - delete request; -} - -void AsyncWebServer::_rewriteRequest(AsyncWebServerRequest *request){ - for(const auto& r: _rewrites){ - if (r->match(request)){ - request->_url = r->toUrl(); - request->_addGetParams(r->params()); - } - } -} - -void AsyncWebServer::_attachHandler(AsyncWebServerRequest *request){ - for(const auto& h: _handlers){ - if (h->filter(request) && h->canHandle(request)){ - request->setHandler(h); - return; - } - } - - request->addInterestingHeader("ANY"); - request->setHandler(_catchAllHandler); -} - - -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody){ - AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); - handler->setUri(uri); - handler->setMethod(method); - handler->onRequest(onRequest); - handler->onUpload(onUpload); - handler->onBody(onBody); - addHandler(handler); - return *handler; -} - -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload){ - AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); - handler->setUri(uri); - handler->setMethod(method); - handler->onRequest(onRequest); - handler->onUpload(onUpload); - addHandler(handler); - return *handler; -} - -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){ - AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); - handler->setUri(uri); - handler->setMethod(method); - handler->onRequest(onRequest); - addHandler(handler); - return *handler; -} - -AsyncCallbackWebHandler& AsyncWebServer::on(const char* uri, ArRequestHandlerFunction onRequest){ - AsyncCallbackWebHandler* handler = new AsyncCallbackWebHandler(); - handler->setUri(uri); - handler->onRequest(onRequest); - addHandler(handler); - return *handler; -} - -AsyncStaticWebHandler& AsyncWebServer::serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_control){ - AsyncStaticWebHandler* handler = new AsyncStaticWebHandler(uri, fs, path, cache_control); - addHandler(handler); - return *handler; -} - -void AsyncWebServer::onNotFound(ArRequestHandlerFunction fn){ - _catchAllHandler->onRequest(fn); -} - -void AsyncWebServer::onFileUpload(ArUploadHandlerFunction fn){ - _catchAllHandler->onUpload(fn); -} - -void AsyncWebServer::onRequestBody(ArBodyHandlerFunction fn){ - _catchAllHandler->onBody(fn); -} - -void AsyncWebServer::reset(){ - _rewrites.free(); - _handlers.free(); - - if (_catchAllHandler != NULL){ - _catchAllHandler->onRequest(NULL); - _catchAllHandler->onUpload(NULL); - _catchAllHandler->onBody(NULL); - } -} - diff --git a/lib/ESPAsyncWebServer/src/edit.htm b/lib/ESPAsyncWebServer/src/edit.htm deleted file mode 100644 index 43d49845..00000000 --- a/lib/ESPAsyncWebServer/src/edit.htm +++ /dev/null @@ -1,627 +0,0 @@ - - - - -ESP Editor - - - - - - -
-
-
-
- - - - diff --git a/lib/GyverFilters/examples/GFilterRA/GFilterRA.ino b/lib/GyverFilters/examples/GFilterRA/GFilterRA.ino deleted file mode 100644 index c6db1517..00000000 --- a/lib/GyverFilters/examples/GFilterRA/GFilterRA.ino +++ /dev/null @@ -1,16 +0,0 @@ -#include "GyverFilters.h" -GFilterRA analog0; // фильтр назовём analog0 - -void setup() { - Serial.begin(9600); - - // установка коэффициента фильтрации (0.0... 1.0). Чем меньше, тем плавнее фильтр - analog0.setCoef(0.01); - - // установка шага фильтрации (мс). Чем меньше, тем резче фильтр - analog0.setStep(10); -} - -void loop() { - Serial.println(analog0.filteredTime(analogRead(0))); -} diff --git a/lib/GyverFilters/examples/GLinear_arrays/GLinear_arrays.ino b/lib/GyverFilters/examples/GLinear_arrays/GLinear_arrays.ino deleted file mode 100644 index 6c407ec4..00000000 --- a/lib/GyverFilters/examples/GLinear_arrays/GLinear_arrays.ino +++ /dev/null @@ -1,32 +0,0 @@ -/* - Пример линейной аппроксимации методом наименьших квадратов - Два массива: по оси Х и по оси У - Линейная аппроксимация повозоляет получить уравнение прямой, - равноудалённой от точек на плоскости ХУ. Удобно для расчёта - роста изменяющейся шумящей величины. Уравнение вида у = A*x + B - В папке с данным примером есть скриншот из excel, - иллюстрирующий работу аппроксимации с такими же исходными -*/ - -// два массива с данными (одинаковой размероности и размера) -int x_array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; -int y_array[] = {1, 5, 2, 8, 3, 9, 10, 5, 15, 12}; - -#include -GLinear test; // указываем тип данных в <> - -void setup() { - Serial.begin(9600); - - // передаём массивы и размер одного из них - test.compute((int*)x_array, (int*)y_array, sizeof(x_array)); - - // Уравнение вида у = A*x + B - Serial.println(test.getA()); // получить коэффициент А - Serial.println(test.getB()); // получить коэффициент В - Serial.println(test.getDelta()); // получить изменение (аппроксимированное) -} - -void loop() { - -} \ No newline at end of file diff --git a/lib/GyverFilters/examples/GLinear_arrays/excel.jpg b/lib/GyverFilters/examples/GLinear_arrays/excel.jpg deleted file mode 100644 index 9cd71117..00000000 Binary files a/lib/GyverFilters/examples/GLinear_arrays/excel.jpg and /dev/null differ diff --git a/lib/GyverFilters/examples/GLinear_running/GLinear_running.ino b/lib/GyverFilters/examples/GLinear_running/GLinear_running.ino deleted file mode 100644 index 575c50dc..00000000 --- a/lib/GyverFilters/examples/GLinear_running/GLinear_running.ino +++ /dev/null @@ -1,34 +0,0 @@ -/* - Пример линейной аппроксимации методом наименьших квадратов - Два массива: по оси Х и по оси У - Наполнение массивов осуществляется динамически: сдвигом и записью в крайнюю ячейку, - то есть аппроксимация по последним ARRAY_SIZE изменениям!! -*/ -#define ARRAY_SIZE 10 // размер пространства для аппроксимации - -// два массива с данными (одинаковой размероности и размера) -int x_array[ARRAY_SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // ось x от 1 до 10, допустим СЕКУНД -int y_array[ARRAY_SIZE]; // значения по оси У будем брать с датчика - -#include -GLinear test; // указываем тип данных в <> - -void setup() { - Serial.begin(9600); -} - -void loop() { - for (byte i = 0; i < ARRAY_SIZE - 1; i++) { // счётчик от 0 до ARRAY_SIZE - y_array[i] = y_array[i + 1]; // сдвинуть массив давлений КРОМЕ ПОСЛЕДНЕЙ ЯЧЕЙКИ на шаг назад - } - // последний элемент массива теперь - новое значение (просто с аналог. датчика) - y_array[ARRAY_SIZE - 1] = analogRead(0); - - // передаём массивы и размер одного из них - test.compute((int*)x_array, (int*)y_array, sizeof(x_array)); - - // по нашим исходным данным это будет производная, т.е. "изменение единиц в секунду" - Serial.println(test.getDelta()); // получить изменение (аппроксимированное) - - delay(1000); // секундная задержка -} diff --git a/lib/GyverFilters/examples/alphabeta_example/alphabeta_example.ino b/lib/GyverFilters/examples/alphabeta_example/alphabeta_example.ino deleted file mode 100644 index 8f43b77a..00000000 --- a/lib/GyverFilters/examples/alphabeta_example/alphabeta_example.ino +++ /dev/null @@ -1,24 +0,0 @@ -/* - Пример альфа-бета фильтра -*/ - -#include "GyverFilters.h" - -// параметры: период дискретизации (измерений), process variation, noise variation -GABfilter testFilter(0.08, 40, 1); - -void setup() { - Serial.begin(9600); -} - -void loop() { - delay(80); - int value = analogRead(0); - value += random(2) * random(-1, 2) * random(10, 70); - Serial.print("$"); - Serial.print(value); - Serial.print(" "); - value = testFilter.filtered((int)value); - Serial.print(value); - Serial.println(";"); -} diff --git a/lib/GyverFilters/examples/filters_comparsion/filters_comparsion.ino b/lib/GyverFilters/examples/filters_comparsion/filters_comparsion.ino deleted file mode 100644 index b981993a..00000000 --- a/lib/GyverFilters/examples/filters_comparsion/filters_comparsion.ino +++ /dev/null @@ -1,30 +0,0 @@ -/* - Сравнение калмана и бегущего среднего -*/ -#include "GyverFilters.h" - -// параметры: разброс измерения, разброс оценки, скорость изменения значений -// разброс измерения: шум измерений -// разброс оценки: подстраивается сам, можно поставить таким же как разброс измерения -// скорость изменения значений: 0.001-1, варьировать самому - -GKalman kalman(90, 90, 0.5); -GFilterRA average(0.5, 80); - -void setup() { - Serial.begin(9600); -} - -void loop() { - int value = analogRead(0); - value += random(2) * random(-1, 2) * random(50, 100); - Serial.print("$"); - Serial.print(value); - Serial.print(" "); - - Serial.print((int)kalman.filtered(value)); - Serial.print(" "); - Serial.print((int)average.filtered(value)); - Serial.println(";"); - delay(80); -} diff --git a/lib/GyverFilters/examples/kalman_example/kalman_example.ino b/lib/GyverFilters/examples/kalman_example/kalman_example.ino deleted file mode 100644 index 802307af..00000000 --- a/lib/GyverFilters/examples/kalman_example/kalman_example.ino +++ /dev/null @@ -1,31 +0,0 @@ -/* - Пример простого одномерного фильтра -*/ - -#include "GyverFilters.h" - -// параметры: разброс измерения, разброс оценки, скорость изменения значений -// разброс измерения: шум измерений -// разброс оценки: подстраивается сам, можно поставить таким же как разброс измерения -// скорость изменения значений: 0.001-1, варьировать самому - -GKalman testFilter(40, 40, 0.5); - -// также может быть объявлен как (разброс измерения, скорость изменения значений) -// GKalman testFilter(40, 0.5); - -void setup() { - Serial.begin(9600); -} - -void loop() { - delay(80); - int value = analogRead(0); - value += random(2) * random(-1, 2) * random(10, 70); - Serial.print("$"); - Serial.print(value); - Serial.print(" "); - value = testFilter.filtered((int)value); - Serial.print(value); - Serial.println(";"); -} diff --git a/lib/GyverFilters/examples/median3_example/median3_example.ino b/lib/GyverFilters/examples/median3_example/median3_example.ino deleted file mode 100644 index c99176bc..00000000 --- a/lib/GyverFilters/examples/median3_example/median3_example.ino +++ /dev/null @@ -1,21 +0,0 @@ -/* - Пример использования быстрого медианного фильтра 3 порядка -*/ - -#include "GyverFilters.h" -GMedian3 testFilter; // указываем тип данных в <> - -void setup() { - Serial.begin(9600); -} - -void loop() { - int value = analogRead(0); - // добавляем шум "выбросы" - value += random(2) * random(2) * random(-1, 2) * random(50, 250); - Serial.print(value); - Serial.print(','); - value = testFilter.filtered(value); - Serial.println(value); - delay(80); -} diff --git a/lib/GyverFilters/examples/median_example/median_example.ino b/lib/GyverFilters/examples/median_example/median_example.ino deleted file mode 100644 index c3fb0067..00000000 --- a/lib/GyverFilters/examples/median_example/median_example.ino +++ /dev/null @@ -1,23 +0,0 @@ -/* - Пример использования медианного фильтра. -*/ - -#include "GyverFilters.h" - -// указываем размер окна и тип данных в <> -GMedian<10, int> testFilter; - -void setup() { - Serial.begin(9600); -} - -void loop() { - delay(80); - int value = analogRead(0); - // добавляем шум "выбросы" - value += random(2) * random(2) * random(-1, 2) * random(50, 250); - Serial.print(value); - Serial.print(','); - value = testFilter.filtered(value); - Serial.println(value); -} \ No newline at end of file diff --git a/lib/GyverFilters/keywords.txt b/lib/GyverFilters/keywords.txt deleted file mode 100644 index 57f38dbc..00000000 --- a/lib/GyverFilters/keywords.txt +++ /dev/null @@ -1,28 +0,0 @@ -####################################### -# Syntax Coloring Map For GyverFilters -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -GyverFilters KEYWORD1 -GFilterRA KEYWORD1 -GMedian3 KEYWORD1 -GMedian KEYWORD1 -GABfilter KEYWORD1 -GKalman KEYWORD1 -GLinear KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -setCoef KEYWORD2 -setStep KEYWORD2 -filteredTime KEYWORD2 -filtered KEYWORD2 -setParameters KEYWORD2 -getA KEYWORD2 -getB KEYWORD2 -getDelta KEYWORD2 \ No newline at end of file diff --git a/lib/GyverFilters/library.properties b/lib/GyverFilters/library.properties deleted file mode 100644 index 2c0c881a..00000000 --- a/lib/GyverFilters/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=GyverFilters -version=2.1 -author=AlexGyver -maintainer=AlexGyver -sentence=Library with few filters for data. -paragraph=Includes median, running average, AB, simplified Kalman and linear approximation filtering algorithms. -category=Data Processing -url=https://github.com/AlexGyver/GyverLibs -architectures=* \ No newline at end of file diff --git a/lib/GyverFilters/src/GyverFilters.h b/lib/GyverFilters/src/GyverFilters.h deleted file mode 100644 index cb35777c..00000000 --- a/lib/GyverFilters/src/GyverFilters.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -/* - GyverFilters - библиотека с некоторыми удобными фильтрами. - Документация: https://alexgyver.ru/gyverfilters/ - - GFilterRA - компактная альтернатива фильтра экспоненциальное бегущее среднее (Running Average) - - GMedian3 - быстрый медианный фильтр 3-го порядка (отсекает выбросы) - - GMedian - медианный фильтр N-го порядка. Порядок настраивается в GyverFilters.h - MEDIAN_FILTER_SIZE - - GABfilter - альфа-бета фильтр (разновидность Калмана для одномерного случая) - - GKalman - упрощённый Калман для одномерного случая (на мой взгляд лучший из фильтров) - - GLinear - линейная аппроксимация методом наименьших квадратов для двух массивов - - Версии - - 1.6 от 12.11.2019 - - 1.7: исправлен GLinear - - 1.8: небольшие улучшения - - 2.0: - - Улучшен и исправлен median и median3 - - Улучшен linear - - Смотрите примеры! Использование этих фильтров чуть изменилось - - 2.1: Исправлен расчёт дельты в линейном фильтре -*/ \ No newline at end of file diff --git a/lib/GyverFilters/src/filters/alfaBeta.h b/lib/GyverFilters/src/filters/alfaBeta.h deleted file mode 100644 index 51b09726..00000000 --- a/lib/GyverFilters/src/filters/alfaBeta.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include - -// альфа-бета фильтр -class GABfilter { -public: - // период дискретизации (измерений), process variation, noise variation - GABfilter(float delta, float sigma_process, float sigma_noise) {setParameters(delta, sigma_process, sigma_noise);} - - // период дискретизации (измерений), process variation, noise variation - void setParameters(float delta, float sigma_process, float sigma_noise) { - dt = delta; - float lambda = (float)sigma_process * dt * dt / sigma_noise; - float r = (4 + lambda - (float)sqrt(8 * lambda + lambda * lambda)) / 4; - a = (float)1 - r * r; - b = (float)2 * (2 - a) - 4 * (float)sqrt(1 - a); - } - - // возвращает фильтрованное значение - float filtered(float value) { - xm = value; - xk = xk_1 + ((float) vk_1 * dt ); - vk = vk_1; - rk = xm - xk; - xk += (float)a * rk; - vk += (float)( b * rk ) / dt; - xk_1 = xk; - vk_1 = vk; - return xk_1; - } - -private: - float dt; - float xk_1, vk_1, a, b; - float xk, vk, rk; - float xm; -}; \ No newline at end of file diff --git a/lib/GyverFilters/src/filters/kalman.h b/lib/GyverFilters/src/filters/kalman.h deleted file mode 100644 index 10458090..00000000 --- a/lib/GyverFilters/src/filters/kalman.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include - -// упрощённый Калман для одномерного случая -class GKalman { -public: - // разброс измерения, разброс оценки, скорость изменения значений - GKalman(float mea_e, float est_e, float q) { setParameters(mea_e, est_e, q); } - - // разброс измерения, скорость изменения значений (разброс измерения принимается равным разбросу оценки) - GKalman(float mea_e, float q) {GKalman::setParameters(mea_e, mea_e, q);} - - // разброс измерения, разброс оценки, скорость изменения значений - void setParameters(float mea_e, float est_e, float q) { - _err_measure = mea_e; - _err_estimate = est_e; - _q = q; - } - - // разброс измерения, скорость изменения значений (разброс измерения принимается равным разбросу оценки) - void setParameters(float mea_e, float q) {setParameters(mea_e, mea_e, q);} - - // возвращает фильтрованное значение - float filtered(float value) { - float _kalman_gain, _current_estimate; - _kalman_gain = _err_estimate / (_err_estimate + _err_measure); - _current_estimate = _last_estimate + _kalman_gain * (value - _last_estimate); - _err_estimate = (1.0 - _kalman_gain)*_err_estimate + fabs(_last_estimate-_current_estimate)*_q; - _last_estimate=_current_estimate; - return _current_estimate; - } - -private: - float _err_measure = 0.0; - float _err_estimate = 0.0; - float _q = 0.0; - float _last_estimate = 0.0; -}; \ No newline at end of file diff --git a/lib/GyverFilters/src/filters/linear.h b/lib/GyverFilters/src/filters/linear.h deleted file mode 100644 index a3f320a2..00000000 --- a/lib/GyverFilters/src/filters/linear.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -#include - -// линейная аппроксимация методом наименьших квадратов -template < typename TYPE > -class GLinear { -public: - GLinear(){}; - void compute(TYPE *x_array, TYPE *y_array, int arrSize) { // аппроксимировать - int32_t sumX = 0, sumY = 0, sumX2 = 0, sumXY = 0; - arrSize /= sizeof(int); - for (int i = 0; i < arrSize; i++) { // для всех элементов массива - sumX += x_array[i]; - sumY += (long)y_array[i]; - sumX2 += x_array[i] * x_array[i]; - sumXY += (long)y_array[i] * x_array[i]; - } - a = (long)arrSize * sumXY; // расчёт коэффициента наклона приямой - a = a - (long)sumX * sumY; - a = (float)a / (arrSize * sumX2 - sumX * sumX); - b = (float)(sumY - (float)a * sumX) / arrSize; - delta = a * (x_array[arrSize-1] - x_array[0]); // расчёт изменения - } - float getA() {return a;} // получить коэффициент А - float getB() {return b;} // получить коэффициент В - float getDelta() {return delta;} // получить аппроксимированное изменение - -private: - float a, b, delta; -}; - -/* -Сам алгоритм выглядит так: -void loop() { - sumX = 0; - sumY = 0; - sumX2 = 0; - sumXY = 0; - for (int i = 0; i < steps; i++) { - sumX += X[i]; - sumY += Y[i]; - sumX2 += X[i] * X[i]; - sumXY += X[i] * Y[i]; - } - a = (steps * sumXY - sumX * sumY) / (steps * sumX2 - sumX * sumX); - b = (sumY - a * sumX) / steps; - int delta = steps * a; -} -*/ \ No newline at end of file diff --git a/lib/GyverFilters/src/filters/median.h b/lib/GyverFilters/src/filters/median.h deleted file mode 100644 index f7580806..00000000 --- a/lib/GyverFilters/src/filters/median.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -// медианный фильтр N-го порядка -template < int SIZE, typename TYPE > -class GMedian { -public: - TYPE filtered(TYPE newVal) { - buffer[_count] = newVal; - if ((_count < _numRead - 1) && (buffer[_count] > buffer[_count + 1])) { - for (int i = _count; i < _numRead - 1; i++) { - if (buffer[i] > buffer[i + 1]) { - float buff = buffer[i]; - buffer[i] = buffer[i + 1]; - buffer[i + 1] = buff; - } - } - } else { - if ((_count > 0) and (buffer[_count - 1] > buffer[_count])) { - for (int i = _count; i > 0; i--) { - if (buffer[i] < buffer[i - 1]) { - float buff = buffer[i]; - buffer[i] = buffer[i - 1]; - buffer[i - 1] = buff; - } - } - } - } - if (++_count >= _numRead) _count = 0; - return buffer[(int)_numRead / 2]; - } -private: - TYPE buffer[SIZE]; - byte _count = 0; - byte _numRead = SIZE; -}; \ No newline at end of file diff --git a/lib/GyverFilters/src/filters/median3.h b/lib/GyverFilters/src/filters/median3.h deleted file mode 100644 index 8b99cc1e..00000000 --- a/lib/GyverFilters/src/filters/median3.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -// быстрый медианный фильтр 3-го порядка -template < typename TYPE > -class GMedian3 { -public: - TYPE filtered(TYPE value) { // возвращает фильтрованное значение - buffer[_counter] = value; - if (++_counter > 2) _counter = 0; - - TYPE middle; - - if ((buffer[0] <= buffer[1]) && (buffer[0] <= buffer[2])) { - middle = (buffer[1] <= buffer[2]) ? buffer[1] : buffer[2]; - } - else { - if ((buffer[1] <= buffer[0]) && (buffer[1] <= buffer[2])) { - middle = (buffer[0] <= buffer[2]) ? buffer[0] : buffer[2]; - } - else { - middle = (buffer[0] <= buffer[1]) ? buffer[0] : buffer[1]; - } - } - return middle; - } - -private: - TYPE buffer[3]; - uint8_t _counter = 0; -}; \ No newline at end of file diff --git a/lib/GyverFilters/src/filters/runningAverage.cpp b/lib/GyverFilters/src/filters/runningAverage.cpp deleted file mode 100644 index 9a1b2b03..00000000 --- a/lib/GyverFilters/src/filters/runningAverage.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include - -GFilterRA::GFilterRA() {} - -GFilterRA::GFilterRA(float coef, uint16_t interval) { - _coef = coef; - _filterInterval = interval; -} - -GFilterRA::GFilterRA(float coef) { - _coef = coef; -} - -void GFilterRA::setCoef(float coef) { - _coef = coef; -} -void GFilterRA::setStep(uint16_t interval) { - _filterInterval = interval; -} - -float GFilterRA::filteredTime(int16_t value) { - if (millis() - _filterTimer >= _filterInterval) { - _filterTimer = millis(); - return GFilterRA::filtered(value); - } -} - -float GFilterRA::filteredTime(float value) { - if (millis() - _filterTimer >= _filterInterval) { - _filterTimer = millis(); - return GFilterRA::filtered(value); - } -} - -float GFilterRA::filtered(int16_t value) { - _lastValue += (float)(value - _lastValue) * _coef; - return _lastValue; -} - -float GFilterRA::filtered(float value) { - _lastValue += (float)(value - _lastValue) * _coef; - return _lastValue; -} \ No newline at end of file diff --git a/lib/GyverFilters/src/filters/runningAverage.h b/lib/GyverFilters/src/filters/runningAverage.h deleted file mode 100644 index 7910a0fe..00000000 --- a/lib/GyverFilters/src/filters/runningAverage.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include - -// экспоненциальное бегущее среднее -class GFilterRA -{ -public: - GFilterRA(); // инициализация фильтра - GFilterRA(float coef); // расширенная инициализация фильтра (коэффициент) - GFilterRA(float coef, uint16_t interval); // расширенная инициализация фильтра (коэффициент, шаг фильтрации) - void setCoef(float coef); // настройка коэффициента фильтрации (0.00 - 1.00). Чем меньше, тем плавнее - void setStep(uint16_t interval); // установка шага фильтрации (мс). Чем меньше, тем резче фильтр - - float filteredTime(int16_t value); // возвращает фильтрованное значение с опорой на встроенный таймер - float filtered(int16_t value); // возвращает фильтрованное значение - - float filteredTime(float value); // возвращает фильтрованное значение с опорой на встроенный таймер - float filtered(float value); // возвращает фильтрованное значение - -private: - float _coef = 0.0, _lastValue = 0.0; - uint32_t _filterTimer = 0; - uint16_t _filterInterval = 0; -}; \ No newline at end of file diff --git a/lib/LITTLEFS/LICENSE b/lib/LITTLEFS/LICENSE deleted file mode 100644 index d159169d..00000000 --- a/lib/LITTLEFS/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/lib/LITTLEFS/README.md b/lib/LITTLEFS/README.md deleted file mode 100644 index 55309ba7..00000000 --- a/lib/LITTLEFS/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# LittleFS_esp32 - -## LittleFS library for arduino-esp32 - -- A LittleFS wrapper for Arduino ESP32 of [ARMmbed LittleFS](https://github.com/ARMmbed/littlefs) -- Based on [ESP-IDF port of joltwallet/esp_littlefs](https://github.com/joltwallet/esp_littlefs) , thank you Brian! -- As a reference, see [LillteFS library for ESP8266 core](https://github.com/esp8266/Arduino/tree/master/libraries/LittleFS) -- [PR at esp32 core development](https://github.com/espressif/arduino-esp32/pull/4096) -- [PR at esp-idf development](https://github.com/espressif/esp-idf/pull/5469) -- The functionality is similar to SPIFFS - -### Installation - -- Use **Arduino Library Manager** -- Or download / use **git** to have latest repository of **LITTLEFS** added to Arduino IDE **/libraries** folder -(File > Preferences > Sketchbook location). -- See ``` #define CONFIG_LITTLEFS_FOR_IDF_3_2 ``` in **esp_littlefs.c**. -When defined, code builds with any IDF 3.2 - 4.x. -On IDF newer than 3.2, it **can** be commented to enable file timestamp feature. -See LITTLEFS_time example. -- The other ``` #define CONFIG_LITTLEFS_xxxxx ``` are set to optimal default values. -Read [here](https://github.com/joltwallet/esp_littlefs/blob/master/Kconfig) and [here](https://github.com/ARMmbed/littlefs/blob/master/README.md) if you want to modify. - -### Usage - -- Use LITTLEFS same way as SPIFFS -- A quick startup based on your existing code you can re-define SPIFFS -``` -#define USE_LittleFS - -#include -#ifdef USE_LittleFS - #define SPIFFS LITTLEFS - #include -#else - #include -#endif - ``` - - Note, this may not work if your sketch uses other libraries that use SPIFFS themselves. - -### Differences with SPIFFS - -- LittleFS has folders, you need to iterate files in folders. See **To Do** below. -- At root a "/folder" = "folder" -- Requires a label for mount point, NULL will not work -- maxOpenFiles parameter is unused, kept for compatibility -- LITTLEFS.mkdir(path) and LITTLEFS.rmdir(path) work as expected for folders -- Speed comparison based on **LittleFS_test.ino** sketch (for a file 1048576 bytes): - -|Filesystem|Read time [ms]|Write time [ms]| -|----|----|----| -|FAT|276|14493| -|LITTLEFS|446*|16387| -|SPIFFS|767|65622| - -*The read speed improved by changing ```#define CONFIG_LITTLEFS_CACHE_SIZE``` from 128 to 512 - - -### Arduino ESP32 LittleFS filesystem upload tool - -- Use (replace if exists) [arduino-esp32fs-plugin](https://github.com/me-no-dev/arduino-esp32fs-plugin/pull/23 ) with [this variant](https://github.com/lorol/arduino-esp32fs-plugin), which supports SPIFFS, LittleFS and FatFS -- Requires [mklittlefs executable](https://github.com/earlephilhower/mklittlefs) which is available [in releases section here](https://github.com/lorol/arduino-esp32fs-plugin ) or download the zipped binary [here](https://github.com/earlephilhower/mklittlefs/releases) or from **esp-quick-toolchain** releases [here](https://github.com/earlephilhower/esp-quick-toolchain/releases) -- Copy it to **/tools** folder of esp32 platform where **espota** and **esptool** (.py or.exe) tools are located -- Restart Arduino IDE. - -### PlatformIO - -- See [LITTLEFS_PlatformIO example here](https://github.com/lorol/LITTLEFS/tree/master/examples/LITTLEFS_PlatformIO) - ( based on notes below from [BlueAndi](https://github.com/BlueAndi) ) -- Add to _platformio.ini_: - `extra_scripts = replace_fs.py` - -- Add _replace_fs.py_ to project root directory (where platformio.ini is located): - - ```python - Import("env") - print("Replace MKSPIFFSTOOL with mklittlefs.exe") - env.Replace (MKSPIFFSTOOL = "mklittlefs.exe") - ``` - -- Add _mklittlefs.exe_ to project root directory as well. - -## Credits and license - -- This work is based on [ARMmbed LittleFS](https://github.com/ARMmbed/littlefs) , [ESP-IDF port of joltwallet/esp_littlefs](https://github.com/joltwallet/esp_littlefs) , [Espressif Arduino core for the ESP32, the ESP-IDF - SPIFFS Library](https://github.com/espressif/arduino-esp32/tree/master/libraries/SPIFFS) -- Licensed under GPL v2 ([text](LICENSE)) - -## To Do - - [x] Submit to be added to Arduino Library Manager - - [ ] Decide on more compatibility (or not) with SPIFFS' lack of folders, similar to esp8266' way: - - [recursive folders auto creation](https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.cpp#L60) when a new file is created at non-existing path - - [recursive folders auto deletion](https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.h#L149) on "last file" deletion (SPIFFS cannot have "folder w/o file") - - review other differences: opendir(), rmdir(), unlink() - - [ ] Follow-up / eventually retire this library if LittleFS gets implemented through IDF / esp32 Arduino core. diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/.gitignore b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/.gitignore deleted file mode 100644 index 87515a62..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.pio -.vscode -mklittlefs.exe -mklittlefs \ No newline at end of file diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/README.md b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/README.md deleted file mode 100644 index 773445b6..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# How to run on PlatformIO IDE - -- Download and extract to this project root a **mklittlefs** executable for your OS [from a zipped binary here](https://github.com/earlephilhower/mklittlefs/releases) -- Open **LITTLEFS_PlatformIO** folder -- Run PlatformIO project task: **Upload Filesystem Image** -- Run PlatformIO project task: **Upload and Monitor** -- You will see a Serial output like: -``` ---- Miniterm on COM5 115200,8,N,1 --- ---- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- -ets Jun 8 2016 00:22:57 - -rst:0x1 (POWERON_RESET),boot:0x13 (Snfigsip: 0, SPIWP:0xee -clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 -mode:DIO, clock div:2 -load:0x3fff0018,len:4 -load:0x3fff001c,len:1044 -load:0x40078000,len:10044 -load:0x40080400,len:5872 -entry 0x400806ac -Listing directory: / - FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 - DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 -Creating Dir: /mydir -Dir created -Writing file: /mydir/hello2.txt -- file written -Listing directory: / - FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 - DIR : /mydir LAST WRITE: 1970-01-01 00:00:00 -Listing directory: /mydir - FILE: /mydir/hello2.txt SIZE: 6 LAST WRITE: 1970-01-01 00:00:00 - DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 -Listing directory: /testfolder - FILE: /testfolder/test2.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 -Deleting file: /mydir/hello2.txt -- file deleted -Removing Dir: /mydir -Dir removed -Listing directory: / - FILE: /file1.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 - DIR : /testfolder LAST WRITE: 2020-10-06 15:10:33 -Listing directory: /testfolder - FILE: /testfolder/test2.txt SIZE: 3 LAST WRITE: 2020-10-06 15:10:33 -Writing file: /hello.txt -- file written -Appending to file: /hello.txt -- message appended -Reading file: /hello.txt -- read from file: -Hello World! -Renaming file /hello.txt to /foo.txt -- file renamed -Reading file: /foo.txt -- read from file: -Hello World! -Deleting file: /foo.txt -- file deleted -Testing file I/O with /test.txt -- writing................................................................ - - 1048576 bytes written in 12006 ms -- reading................................................................ -- 1048576 bytes read in 547 ms -Deleting file: /test.txt -- file deleted -Test complete -``` -- If you have a module with more than 4MB flash, you can uncomment **partitions_custom.csv** in **platformio.ini** and modify the csv file accordingly \ No newline at end of file diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/data/file1.txt b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/data/file1.txt deleted file mode 100644 index 7c4a013e..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/data/file1.txt +++ /dev/null @@ -1 +0,0 @@ -aaa \ No newline at end of file diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt deleted file mode 100644 index 01f02e32..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/data/testfolder/test2.txt +++ /dev/null @@ -1 +0,0 @@ -bbb \ No newline at end of file diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/include/.placeholder.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/lib/.placeholder.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py deleted file mode 100644 index 93937e29..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/littlefsbuilder.py +++ /dev/null @@ -1,2 +0,0 @@ -Import("env") -env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/mklittlefs' ) \ No newline at end of file diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv deleted file mode 100644 index 97846fa5..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/partitions_custom.csv +++ /dev/null @@ -1,6 +0,0 @@ -# Name, Type, SubType, Offset, Size, Flags -ota_0, app, ota_0, 0x10000, 0x1A0000, -ota_1, app, ota_1, , 0x1A0000, -otadata, data, ota, 0x350000, 0x2000, -nvs, data, nvs, , 0x6000, -data, data, spiffs, , 0xA8000, diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/platformio.ini b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/platformio.ini deleted file mode 100644 index 43e34ec0..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/platformio.ini +++ /dev/null @@ -1,35 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[platformio] -default_envs = esp32 - -[env] -framework = arduino - -[env:esp32] -platform = espressif32 -;platform = https://github.com/platformio/platform-espressif32.git -;board_build.mcu = esp32 -platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git - -build_flags = - ${env.build_flags} - -D=${PIOENV} - ;-D CONFIG_LITTLEFS_FOR_IDF_3_2 - -lib_deps = https://github.com/lorol/LITTLEFS.git - -board = esp32dev -;board_build.partitions = partitions_custom.csv -monitor_filters = esp32_exception_decoder -monitor_speed = 115200 - -extra_scripts = ./littlefsbuilder.py diff --git a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/src/main.cpp b/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/src/main.cpp deleted file mode 100644 index 5ff2765b..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_PlatformIO/src/main.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include -#include "FS.h" -#include - -#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 - #include -#endif - -/* You only need to format LITTLEFS the first time you run a - test or else use the LITTLEFS plugin to create a partition - https://github.com/lorol/arduino-esp32littlefs-plugin */ - -#define FORMAT_LITTLEFS_IF_FAILED true - -void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ - Serial.printf("Listing directory: %s\r\n", dirname); - - File root = fs.open(dirname); - if(!root){ - Serial.println("- failed to open directory"); - return; - } - if(!root.isDirectory()){ - Serial.println(" - not a directory"); - return; - } - - File file = root.openNextFile(); - while(file){ - if(file.isDirectory()){ - Serial.print(" DIR : "); - -#ifdef CONFIG_LITTLEFS_FOR_IDF_3_2 - Serial.println(file.name()); -#else - Serial.print(file.name()); - time_t t= file.getLastWrite(); - struct tm * tmstruct = localtime(&t); - Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); -#endif - - if(levels){ - listDir(fs, file.name(), levels -1); - } - } else { - Serial.print(" FILE: "); - Serial.print(file.name()); - Serial.print(" SIZE: "); - -#ifdef CONFIG_LITTLEFS_FOR_IDF_3_2 - Serial.println(file.size()); -#else - Serial.print(file.size()); - time_t t= file.getLastWrite(); - struct tm * tmstruct = localtime(&t); - Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); -#endif - } - file = root.openNextFile(); - } -} - -void createDir(fs::FS &fs, const char * path){ - Serial.printf("Creating Dir: %s\n", path); - if(fs.mkdir(path)){ - Serial.println("Dir created"); - } else { - Serial.println("mkdir failed"); - } -} - -void removeDir(fs::FS &fs, const char * path){ - Serial.printf("Removing Dir: %s\n", path); - if(fs.rmdir(path)){ - Serial.println("Dir removed"); - } else { - Serial.println("rmdir failed"); - } -} - -void readFile(fs::FS &fs, const char * path){ - Serial.printf("Reading file: %s\r\n", path); - - File file = fs.open(path); - if(!file || file.isDirectory()){ - Serial.println("- failed to open file for reading"); - return; - } - - Serial.println("- read from file:"); - while(file.available()){ - Serial.write(file.read()); - } - file.close(); -} - -void writeFile(fs::FS &fs, const char * path, const char * message){ - Serial.printf("Writing file: %s\r\n", path); - - File file = fs.open(path, FILE_WRITE); - if(!file){ - Serial.println("- failed to open file for writing"); - return; - } - if(file.print(message)){ - Serial.println("- file written"); - } else { - Serial.println("- write failed"); - } - file.close(); -} - -void appendFile(fs::FS &fs, const char * path, const char * message){ - Serial.printf("Appending to file: %s\r\n", path); - - File file = fs.open(path, FILE_APPEND); - if(!file){ - Serial.println("- failed to open file for appending"); - return; - } - if(file.print(message)){ - Serial.println("- message appended"); - } else { - Serial.println("- append failed"); - } - file.close(); -} - -void renameFile(fs::FS &fs, const char * path1, const char * path2){ - Serial.printf("Renaming file %s to %s\r\n", path1, path2); - if (fs.rename(path1, path2)) { - Serial.println("- file renamed"); - } else { - Serial.println("- rename failed"); - } -} - -void deleteFile(fs::FS &fs, const char * path){ - Serial.printf("Deleting file: %s\r\n", path); - if(fs.remove(path)){ - Serial.println("- file deleted"); - } else { - Serial.println("- delete failed"); - } -} - -// SPIFFS-like write and delete file - -// See: https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.cpp#L60 -void writeFile2(fs::FS &fs, const char * path, const char * message){ - if(!fs.exists(path)){ - if (strchr(path, '/')) { - Serial.printf("Create missing folders of: %s\r\n", path); - char *pathStr = strdup(path); - if (pathStr) { - char *ptr = strchr(pathStr, '/'); - while (ptr) { - *ptr = 0; - fs.mkdir(pathStr); - *ptr = '/'; - ptr = strchr(ptr+1, '/'); - } - } - free(pathStr); - } - } - - Serial.printf("Writing file to: %s\r\n", path); - File file = fs.open(path, FILE_WRITE); - if(!file){ - Serial.println("- failed to open file for writing"); - return; - } - if(file.print(message)){ - Serial.println("- file written"); - } else { - Serial.println("- write failed"); - } - file.close(); -} - -// See: https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.h#L149 -void deleteFile2(fs::FS &fs, const char * path){ - Serial.printf("Deleting file and empty folders on path: %s\r\n", path); - - if(fs.remove(path)){ - Serial.println("- file deleted"); - } else { - Serial.println("- delete failed"); - } - - char *pathStr = strdup(path); - if (pathStr) { - char *ptr = strrchr(pathStr, '/'); - if (ptr) { - Serial.printf("Removing all empty folders on path: %s\r\n", path); - } - while (ptr) { - *ptr = 0; - fs.rmdir(pathStr); - ptr = strrchr(pathStr, '/'); - } - free(pathStr); - } -} - -void testFileIO(fs::FS &fs, const char * path){ - Serial.printf("Testing file I/O with %s\r\n", path); - - static uint8_t buf[512]; - size_t len = 0; - File file = fs.open(path, FILE_WRITE); - if(!file){ - Serial.println("- failed to open file for writing"); - return; - } - - size_t i; - Serial.print("- writing" ); - uint32_t start = millis(); - for(i=0; i<2048; i++){ - if ((i & 0x001F) == 0x001F){ - Serial.print("."); - } - file.write(buf, 512); - } - Serial.println(""); - uint32_t end = millis() - start; - Serial.printf(" - %u bytes written in %u ms\r\n", 2048 * 512, end); - file.close(); - - file = fs.open(path); - start = millis(); - end = start; - i = 0; - if(file && !file.isDirectory()){ - len = file.size(); - size_t flen = len; - start = millis(); - Serial.print("- reading" ); - while(len){ - size_t toRead = len; - if(toRead > 512){ - toRead = 512; - } - file.read(buf, toRead); - if ((i++ & 0x001F) == 0x001F){ - Serial.print("."); - } - len -= toRead; - } - Serial.println(""); - end = millis() - start; - Serial.printf("- %u bytes read in %u ms\r\n", flen, end); - file.close(); - } else { - Serial.println("- failed to open file for reading"); - } -} - -void setup(){ - Serial.begin(115200); - if(!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ - Serial.println("LITTLEFS Mount Failed"); - return; - } - - listDir(LITTLEFS, "/", 0); - createDir(LITTLEFS, "/mydir"); - writeFile(LITTLEFS, "/mydir/hello2.txt", "Hello2"); - //writeFile(LITTLEFS, "/mydir/newdir2/newdir3/hello3.txt", "Hello3"); - writeFile2(LITTLEFS, "/mydir/newdir2/newdir3/hello3.txt", "Hello3"); - listDir(LITTLEFS, "/", 3); - deleteFile(LITTLEFS, "/mydir/hello2.txt"); - //deleteFile(LITTLEFS, "/mydir/newdir2/newdir3/hello3.txt"); - deleteFile2(LITTLEFS, "/mydir/newdir2/newdir3/hello3.txt"); - removeDir(LITTLEFS, "/mydir"); - listDir(LITTLEFS, "/", 3); - writeFile(LITTLEFS, "/hello.txt", "Hello "); - appendFile(LITTLEFS, "/hello.txt", "World!\r\n"); - readFile(LITTLEFS, "/hello.txt"); - renameFile(LITTLEFS, "/hello.txt", "/foo.txt"); - readFile(LITTLEFS, "/foo.txt"); - deleteFile(LITTLEFS, "/foo.txt"); - testFileIO(LITTLEFS, "/test.txt"); - deleteFile(LITTLEFS, "/test.txt"); - - Serial.println( "Test complete" ); -} - -void loop(){ - -} diff --git a/lib/LITTLEFS/examples/LITTLEFS_time/LITTLEFS_time.ino b/lib/LITTLEFS/examples/LITTLEFS_time/LITTLEFS_time.ino deleted file mode 100644 index a88af28b..00000000 --- a/lib/LITTLEFS/examples/LITTLEFS_time/LITTLEFS_time.ino +++ /dev/null @@ -1,219 +0,0 @@ -#include "FS.h" -//#include "SPIFFS.h" -#include "LITTLEFS.h" -#include -#include - -#define SPIFFS LITTLEFS - -/* This examples uses "quick re-define" of SPIFFS to run - an existing sketch with LITTLEFS instead of SPIFFS - - To get time/date stamps by file.getLastWrite(), you need an - esp32 core on IDF 3.3 and comment a line in file esp_littlefs.c: - - //#define CONFIG_LITTLEFS_FOR_IDF_3_2 - - You only need to format LITTLEFS the first time you run a - test or else use the LITTLEFS plugin to create a partition - https://github.com/lorol/arduino-esp32littlefs-plugin */ - -#define FORMAT_LITTLEFS_IF_FAILED true - -const char* ssid = "yourssid"; -const char* password = "yourpass"; - -long timezone = 1; -byte daysavetime = 1; - -void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ - Serial.printf("Listing directory: %s\n", dirname); - - File root = fs.open(dirname); - if(!root){ - Serial.println("Failed to open directory"); - return; - } - if(!root.isDirectory()){ - Serial.println("Not a directory"); - return; - } - - File file = root.openNextFile(); - while(file){ - if(file.isDirectory()){ - Serial.print(" DIR : "); - Serial.print (file.name()); - time_t t= file.getLastWrite(); - struct tm * tmstruct = localtime(&t); - Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); - if(levels){ - listDir(fs, file.name(), levels -1); - } - } else { - Serial.print(" FILE: "); - Serial.print(file.name()); - Serial.print(" SIZE: "); - Serial.print(file.size()); - time_t t= file.getLastWrite(); - struct tm * tmstruct = localtime(&t); - Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec); - } - file = root.openNextFile(); - } -} - -void createDir(fs::FS &fs, const char * path){ - Serial.printf("Creating Dir: %s\n", path); - if(fs.mkdir(path)){ - Serial.println("Dir created"); - } else { - Serial.println("mkdir failed"); - } -} - -void removeDir(fs::FS &fs, const char * path){ - Serial.printf("Removing Dir: %s\n", path); - if(fs.rmdir(path)){ - Serial.println("Dir removed"); - } else { - Serial.println("rmdir failed"); - } -} - -void readFile(fs::FS &fs, const char * path){ - Serial.printf("Reading file: %s\n", path); - - File file = fs.open(path); - if(!file){ - Serial.println("Failed to open file for reading"); - return; - } - - Serial.print("Read from file: "); - while(file.available()){ - Serial.write(file.read()); - } - file.close(); -} - -void writeFile(fs::FS &fs, const char * path, const char * message){ - Serial.printf("Writing file: %s\n", path); - - File file = fs.open(path, FILE_WRITE); - if(!file){ - Serial.println("Failed to open file for writing"); - return; - } - if(file.print(message)){ - Serial.println("File written"); - } else { - Serial.println("Write failed"); - } - file.close(); -} - -void appendFile(fs::FS &fs, const char * path, const char * message){ - Serial.printf("Appending to file: %s\n", path); - - File file = fs.open(path, FILE_APPEND); - if(!file){ - Serial.println("Failed to open file for appending"); - return; - } - if(file.print(message)){ - Serial.println("Message appended"); - } else { - Serial.println("Append failed"); - } - file.close(); -} - -void renameFile(fs::FS &fs, const char * path1, const char * path2){ - Serial.printf("Renaming file %s to %s\n", path1, path2); - if (fs.rename(path1, path2)) { - Serial.println("File renamed"); - } else { - Serial.println("Rename failed"); - } -} - -void deleteFile(fs::FS &fs, const char * path){ - Serial.printf("Deleting file: %s\n", path); - if(fs.remove(path)){ - Serial.println("File deleted"); - } else { - Serial.println("Delete failed"); - } -} - -void setup(){ - Serial.begin(115200); - // We start by connecting to a WiFi network - Serial.println(); - Serial.println(); - Serial.print("Connecting to "); - Serial.println(ssid); - - WiFi.begin(ssid, password); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - } - Serial.println("WiFi connected"); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println("Contacting Time Server"); - configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org"); - struct tm tmstruct ; - delay(2000); - tmstruct.tm_year = 0; - getLocalTime(&tmstruct, 5000); - Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct.tm_year)+1900,( tmstruct.tm_mon)+1, tmstruct.tm_mday,tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec); - Serial.println(""); - - if(!SPIFFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ - Serial.println("LITTLEFS Mount Failed"); - return; - } - - Serial.println("----list 1----"); - listDir(SPIFFS, "/", 1); - - Serial.println("----remove old dir----"); - removeDir(SPIFFS, "/mydir"); - - Serial.println("----create a new dir----"); - createDir(SPIFFS, "/mydir"); - - Serial.println("----remove the new dir----"); - removeDir(SPIFFS, "/mydir"); - - Serial.println("----create the new again----"); - createDir(SPIFFS, "/mydir"); - - Serial.println("----create and work with file----"); - writeFile(SPIFFS, "/mydir/hello.txt", "Hello "); - appendFile(SPIFFS, "/mydir/hello.txt", "World!\n"); - - Serial.println("----list 2----"); - listDir(SPIFFS, "/", 1); - - Serial.println("----attempt to remove dir w/ file----"); - removeDir(SPIFFS, "/mydir"); - - Serial.println("----remove dir after deleting file----"); - deleteFile(SPIFFS, "/mydir/hello.txt"); - removeDir(SPIFFS, "/mydir"); - - Serial.println("----list 3----"); - listDir(SPIFFS, "/", 1); - - Serial.println( "Test complete" ); - -} - -void loop(){ - -} diff --git a/lib/LITTLEFS/examples/LittleFS_test/LittleFS_test.ino b/lib/LITTLEFS/examples/LittleFS_test/LittleFS_test.ino deleted file mode 100644 index 528bfd18..00000000 --- a/lib/LITTLEFS/examples/LittleFS_test/LittleFS_test.ino +++ /dev/null @@ -1,272 +0,0 @@ -#include -#include "FS.h" -#include - -/* You only need to format LITTLEFS the first time you run a - test or else use the LITTLEFS plugin to create a partition - https://github.com/lorol/arduino-esp32littlefs-plugin */ - -#define FORMAT_LITTLEFS_IF_FAILED true - -void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ - Serial.printf("Listing directory: %s\r\n", dirname); - - File root = fs.open(dirname); - if(!root){ - Serial.println("- failed to open directory"); - return; - } - if(!root.isDirectory()){ - Serial.println(" - not a directory"); - return; - } - - File file = root.openNextFile(); - while(file){ - if(file.isDirectory()){ - Serial.print(" DIR : "); - Serial.println(file.name()); - if(levels){ - listDir(fs, file.name(), levels -1); - } - } else { - Serial.print(" FILE: "); - Serial.print(file.name()); - Serial.print("\tSIZE: "); - Serial.println(file.size()); - } - file = root.openNextFile(); - } -} - -void createDir(fs::FS &fs, const char * path){ - Serial.printf("Creating Dir: %s\n", path); - if(fs.mkdir(path)){ - Serial.println("Dir created"); - } else { - Serial.println("mkdir failed"); - } -} - -void removeDir(fs::FS &fs, const char * path){ - Serial.printf("Removing Dir: %s\n", path); - if(fs.rmdir(path)){ - Serial.println("Dir removed"); - } else { - Serial.println("rmdir failed"); - } -} - -void readFile(fs::FS &fs, const char * path){ - Serial.printf("Reading file: %s\r\n", path); - - File file = fs.open(path); - if(!file || file.isDirectory()){ - Serial.println("- failed to open file for reading"); - return; - } - - Serial.println("- read from file:"); - while(file.available()){ - Serial.write(file.read()); - } - file.close(); -} - -void writeFile(fs::FS &fs, const char * path, const char * message){ - Serial.printf("Writing file: %s\r\n", path); - - File file = fs.open(path, FILE_WRITE); - if(!file){ - Serial.println("- failed to open file for writing"); - return; - } - if(file.print(message)){ - Serial.println("- file written"); - } else { - Serial.println("- write failed"); - } - file.close(); -} - -void appendFile(fs::FS &fs, const char * path, const char * message){ - Serial.printf("Appending to file: %s\r\n", path); - - File file = fs.open(path, FILE_APPEND); - if(!file){ - Serial.println("- failed to open file for appending"); - return; - } - if(file.print(message)){ - Serial.println("- message appended"); - } else { - Serial.println("- append failed"); - } - file.close(); -} - -void renameFile(fs::FS &fs, const char * path1, const char * path2){ - Serial.printf("Renaming file %s to %s\r\n", path1, path2); - if (fs.rename(path1, path2)) { - Serial.println("- file renamed"); - } else { - Serial.println("- rename failed"); - } -} - -void deleteFile(fs::FS &fs, const char * path){ - Serial.printf("Deleting file: %s\r\n", path); - if(fs.remove(path)){ - Serial.println("- file deleted"); - } else { - Serial.println("- delete failed"); - } -} - -// SPIFFS-like write and delete file - -// See: https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.cpp#L60 -void writeFile2(fs::FS &fs, const char * path, const char * message){ - if(!fs.exists(path)){ - if (strchr(path, '/')) { - Serial.printf("Create missing folders of: %s\r\n", path); - char *pathStr = strdup(path); - if (pathStr) { - char *ptr = strchr(pathStr, '/'); - while (ptr) { - *ptr = 0; - fs.mkdir(pathStr); - *ptr = '/'; - ptr = strchr(ptr+1, '/'); - } - } - free(pathStr); - } - } - - Serial.printf("Writing file to: %s\r\n", path); - File file = fs.open(path, FILE_WRITE); - if(!file){ - Serial.println("- failed to open file for writing"); - return; - } - if(file.print(message)){ - Serial.println("- file written"); - } else { - Serial.println("- write failed"); - } - file.close(); -} - -// See: https://github.com/esp8266/Arduino/blob/master/libraries/LittleFS/src/LittleFS.h#L149 -void deleteFile2(fs::FS &fs, const char * path){ - Serial.printf("Deleting file and empty folders on path: %s\r\n", path); - - if(fs.remove(path)){ - Serial.println("- file deleted"); - } else { - Serial.println("- delete failed"); - } - - char *pathStr = strdup(path); - if (pathStr) { - char *ptr = strrchr(pathStr, '/'); - if (ptr) { - Serial.printf("Removing all empty folders on path: %s\r\n", path); - } - while (ptr) { - *ptr = 0; - fs.rmdir(pathStr); - ptr = strrchr(pathStr, '/'); - } - free(pathStr); - } -} - -void testFileIO(fs::FS &fs, const char * path){ - Serial.printf("Testing file I/O with %s\r\n", path); - - static uint8_t buf[512]; - size_t len = 0; - File file = fs.open(path, FILE_WRITE); - if(!file){ - Serial.println("- failed to open file for writing"); - return; - } - - size_t i; - Serial.print("- writing" ); - uint32_t start = millis(); - for(i=0; i<2048; i++){ - if ((i & 0x001F) == 0x001F){ - Serial.print("."); - } - file.write(buf, 512); - } - Serial.println(""); - uint32_t end = millis() - start; - Serial.printf(" - %u bytes written in %u ms\r\n", 2048 * 512, end); - file.close(); - - file = fs.open(path); - start = millis(); - end = start; - i = 0; - if(file && !file.isDirectory()){ - len = file.size(); - size_t flen = len; - start = millis(); - Serial.print("- reading" ); - while(len){ - size_t toRead = len; - if(toRead > 512){ - toRead = 512; - } - file.read(buf, toRead); - if ((i++ & 0x001F) == 0x001F){ - Serial.print("."); - } - len -= toRead; - } - Serial.println(""); - end = millis() - start; - Serial.printf("- %u bytes read in %u ms\r\n", flen, end); - file.close(); - } else { - Serial.println("- failed to open file for reading"); - } -} - -void setup(){ - Serial.begin(115200); - if(!LITTLEFS.begin(FORMAT_LITTLEFS_IF_FAILED)){ - Serial.println("LITTLEFS Mount Failed"); - return; - } - Serial.println( "SPIFFS-like write file to new path and delete it w/folders" ); - writeFile2(LITTLEFS, "/new1/new2/new3/hello3.txt", "Hello3"); - listDir(LITTLEFS, "/", 3); - deleteFile2(LITTLEFS, "/new1/new2/new3/hello3.txt"); - - listDir(LITTLEFS, "/", 3); - createDir(LITTLEFS, "/mydir"); - writeFile(LITTLEFS, "/mydir/hello2.txt", "Hello2"); - listDir(LITTLEFS, "/", 1); - deleteFile(LITTLEFS, "/mydir/hello2.txt"); - removeDir(LITTLEFS, "/mydir"); - listDir(LITTLEFS, "/", 1); - writeFile(LITTLEFS, "/hello.txt", "Hello "); - appendFile(LITTLEFS, "/hello.txt", "World!\r\n"); - readFile(LITTLEFS, "/hello.txt"); - renameFile(LITTLEFS, "/hello.txt", "/foo.txt"); - readFile(LITTLEFS, "/foo.txt"); - deleteFile(LITTLEFS, "/foo.txt"); - testFileIO(LITTLEFS, "/test.txt"); - deleteFile(LITTLEFS, "/test.txt"); - - Serial.println( "Test complete" ); -} - -void loop(){ - -} diff --git a/lib/LITTLEFS/library.json b/lib/LITTLEFS/library.json deleted file mode 100644 index adb1e5b1..00000000 --- a/lib/LITTLEFS/library.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name":"LittleFS_esp32", - "description":"LittleFS for esp32", - "keywords":"littlefs, spiffs", - "authors": - { - "name": "lorol", - "maintainer": true - }, - "repository": - { - "type": "git", - "url": "https://github.com/lorol/LITTLEFS.git" - }, - "version": "1.0", - "license": "LGPL-2.0", - "frameworks": "arduino", - "platforms": "espressif32", - "build": { - "libCompatMode": 2 - } -} \ No newline at end of file diff --git a/lib/LITTLEFS/library.properties b/lib/LITTLEFS/library.properties deleted file mode 100644 index 179f6df0..00000000 --- a/lib/LITTLEFS/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=LittleFS_esp32 -version=1.0 -author=lorol -maintainer=lorol -sentence=LittleFS for esp32 -paragraph=LittleFS for esp32 -category=Data Storage -url=https://github.com/lorol/LITTLEFS -architectures=esp32 \ No newline at end of file diff --git a/lib/LITTLEFS/src/LITTLEFS.cpp b/lib/LITTLEFS/src/LITTLEFS.cpp deleted file mode 100644 index 32dce386..00000000 --- a/lib/LITTLEFS/src/LITTLEFS.cpp +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -static constexpr const char LFS_NAME[] = "spiffs"; - -#include "vfs_api.h" - -extern "C" { -#include -#include -#include -#include "esp_littlefs.h" -} - -#include "LITTLEFS.h" - -using namespace fs; - -LITTLEFSFS::LITTLEFSFS() : FS(FSImplPtr(new VFSImpl())) -{ - -} - -bool LITTLEFSFS::begin(bool formatOnFail, const char * basePath, uint8_t maxOpenFiles) -{ - if(esp_littlefs_mounted(LFS_NAME)){ - log_w("LITTLEFS Already Mounted!"); - return true; - } - - esp_vfs_littlefs_conf_t conf = { - .base_path = basePath, - .partition_label = LFS_NAME, - //.max_files = maxOpenFiles, - .format_if_mount_failed = false - }; - - esp_err_t err = esp_vfs_littlefs_register(&conf); - if(err == ESP_FAIL && formatOnFail){ - if(format()){ - err = esp_vfs_littlefs_register(&conf); - } - } - if(err != ESP_OK){ - log_e("Mounting LITTLEFS failed! Error: %d", err); - return false; - } - _impl->mountpoint(basePath); - return true; -} - -void LITTLEFSFS::end() -{ - if(esp_littlefs_mounted(LFS_NAME)){ - esp_err_t err = esp_vfs_littlefs_unregister(LFS_NAME); - if(err){ - log_e("Unmounting LITTLEFS failed! Error: %d", err); - return; - } - _impl->mountpoint(NULL); - } -} - -bool LITTLEFSFS::format() -{ - disableCore0WDT(); - esp_err_t err = esp_littlefs_format(LFS_NAME); - enableCore0WDT(); - if(err){ - log_e("Formatting LITTLEFS failed! Error: %d", err); - return false; - } - return true; -} - -size_t LITTLEFSFS::totalBytes() -{ - size_t total,used; - if(esp_littlefs_info(LFS_NAME, &total, &used)){ - return 0; - } - return total; -} - -size_t LITTLEFSFS::usedBytes() -{ - size_t total,used; - if(esp_littlefs_info(LFS_NAME, &total, &used)){ - return 0; - } - return used; -} - -LITTLEFSFS LITTLEFS; - diff --git a/lib/LITTLEFS/src/LITTLEFS.h b/lib/LITTLEFS/src/LITTLEFS.h deleted file mode 100644 index fbd6f09e..00000000 --- a/lib/LITTLEFS/src/LITTLEFS.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef _LITTLEFS_H_ -#define _LITTLEFS_H_ - -#include "FS.h" - -namespace fs -{ - -class LITTLEFSFS : public FS -{ -public: - LITTLEFSFS(); - bool begin(bool formatOnFail=false, const char * basePath="/littlefs", uint8_t maxOpenFiles=5); - bool format(); - size_t totalBytes(); - size_t usedBytes(); - void end(); -}; - -} - -extern fs::LITTLEFSFS LITTLEFS; - - -#endif diff --git a/lib/LITTLEFS/src/esp_littlefs.c b/lib/LITTLEFS/src/esp_littlefs.c deleted file mode 100644 index 63a114a0..00000000 --- a/lib/LITTLEFS/src/esp_littlefs.c +++ /dev/null @@ -1,1513 +0,0 @@ -/** - * @file esp_littlefs.c - * @brief Maps LittleFS <-> ESP_VFS - * @author Brian Pugh - * - * @note Modified and used by lorol for Arduino esp32 core - * - * Copyright 2020 Brian Pugh - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -//#define LOG_LOCAL_LEVEL 4 -#define CONFIG_LITTLEFS_FOR_IDF_3_2 /* For old IDF - like in release 1.0.4 */ - -#include "esp_log.h" -#include "esp_spi_flash.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include -#include -#include -#include -#include -#include - -#if __has_include("esp32/rom/spi_flash.h") -#include "esp32/rom/spi_flash.h" -#else -#include "rom/spi_flash.h" -#endif - -#include "esp_system.h" - -#include "esp_littlefs.h" -#include "littlefs_api.h" - -static const char TAG[] = "esp_littlefs"; - -#define CONFIG_LITTLEFS_BLOCK_SIZE 4096 /* ESP32 can only operate at 4kb */ - -/* File Descriptor Caching Params */ -#define CONFIG_LITTLEFS_FD_CACHE_REALLOC_FACTOR 2 /* Amount to resize FD cache by */ -#define CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE 4 /* Minimum size of FD cache */ -#define CONFIG_LITTLEFS_FD_CACHE_HYST 4 /* When shrinking, leave this many trailing FD slots available */ - -#define CONFIG_LITTLEFS_MAX_PARTITIONS 3 -#define CONFIG_LITTLEFS_PAGE_SIZE 256 -#define CONFIG_LITTLEFS_OBJ_NAME_LEN 64 -#define CONFIG_LITTLEFS_READ_SIZE 128 -#define CONFIG_LITTLEFS_WRITE_SIZE 128 -#define CONFIG_LITTLEFS_LOOKAHEAD_SIZE 128 -#define CONFIG_LITTLEFS_CACHE_SIZE 512 -#define CONFIG_LITTLEFS_BLOCK_CYCLES 512 - -//#define CONFIG_SECURE_FLASH_ENC_ENABLED 1 /* For encrypted, in part.csv: flash_test, data, spiffs, , 512K, encrypted */ - -#ifdef CONFIG_LITTLEFS_FOR_IDF_3_2 -#define CONFIG_LITTLEFS_USE_MTIME 0 -#else -#define CONFIG_LITTLEFS_USE_MTIME 1 -#define CONFIG_LITTLEFS_MTIME_USE_SECONDS 1 -#endif - - -/** - * @brief littlefs DIR structure - */ -typedef struct { - DIR dir; /*!< VFS DIR struct */ - lfs_dir_t d; /*!< littlefs DIR struct */ - struct dirent e; /*!< Last open dirent */ - long offset; /*!< Offset of the current dirent */ - char *path; /*!< Requested directory name */ -} vfs_littlefs_dir_t; - -static int vfs_littlefs_open(void* ctx, const char * path, int flags, int mode); -static ssize_t vfs_littlefs_write(void* ctx, int fd, const void * data, size_t size); -static ssize_t vfs_littlefs_read(void* ctx, int fd, void * dst, size_t size); -static int vfs_littlefs_close(void* ctx, int fd); -static off_t vfs_littlefs_lseek(void* ctx, int fd, off_t offset, int mode); -static int vfs_littlefs_stat(void* ctx, const char * path, struct stat * st); -static int vfs_littlefs_unlink(void* ctx, const char *path); -static int vfs_littlefs_rename(void* ctx, const char *src, const char *dst); -static DIR* vfs_littlefs_opendir(void* ctx, const char* name); -static int vfs_littlefs_closedir(void* ctx, DIR* pdir); -static struct dirent* vfs_littlefs_readdir(void* ctx, DIR* pdir); -static int vfs_littlefs_readdir_r(void* ctx, DIR* pdir, - struct dirent* entry, struct dirent** out_dirent); -static long vfs_littlefs_telldir(void* ctx, DIR* pdir); -static void vfs_littlefs_seekdir(void* ctx, DIR* pdir, long offset); -static int vfs_littlefs_mkdir(void* ctx, const char* name, mode_t mode); -static int vfs_littlefs_rmdir(void* ctx, const char* name); -static int vfs_littlefs_fsync(void* ctx, int fd); - -static esp_err_t esp_littlefs_init(const esp_vfs_littlefs_conf_t* conf); -static esp_err_t esp_littlefs_erase_partition(const char *partition_label); -static esp_err_t esp_littlefs_by_label(const char* label, int * index); -static esp_err_t esp_littlefs_get_empty(int *index); -static void esp_littlefs_free(esp_littlefs_t ** efs); -static void esp_littlefs_dir_free(vfs_littlefs_dir_t *dir); -static int esp_littlefs_flags_conv(int m); -#if CONFIG_LITTLEFS_USE_MTIME -static int vfs_littlefs_utime(void *ctx, const char *path, const struct utimbuf *times); -static void vfs_littlefs_update_mtime(esp_littlefs_t *efs, const char *path); -static int vfs_littlefs_update_mtime_value(esp_littlefs_t *efs, const char *path, time_t t); -static time_t vfs_littlefs_get_mtime(esp_littlefs_t *efs, const char *path); -#endif - -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH -/* The only way in LittleFS to get info is via a path (lfs_stat), so it cannot - * be done if the path isn't stored. */ -static int vfs_littlefs_fstat(void* ctx, int fd, struct stat * st); -#endif - -static int sem_take(esp_littlefs_t *efs); -static int sem_give(esp_littlefs_t *efs); - -static SemaphoreHandle_t _efs_lock = NULL; -static esp_littlefs_t * _efs[CONFIG_LITTLEFS_MAX_PARTITIONS] = { 0 }; - -/******************** - * Helper Functions * - ********************/ -void esp_littlefs_free_fds(esp_littlefs_t * efs) { - /* Need to free all files that were opened */ - while (efs->file) { - vfs_littlefs_file_t * next = efs->file->next; - free(efs->file); - efs->file = next; - } - free(efs->cache); - efs->cache = 0; - efs->cache_size = efs->fd_count = 0; -} - - -/******************** - * Public Functions * - ********************/ - -bool esp_littlefs_mounted(const char* partition_label) { - int index; - esp_err_t err; - - err = esp_littlefs_by_label(partition_label, &index); - if(err != ESP_OK) return false; - return _efs[index]->cache_size > 0; -} - -esp_err_t esp_littlefs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes){ - int index; - esp_err_t err; - esp_littlefs_t *efs = NULL; - - err = esp_littlefs_by_label(partition_label, &index); - if(err != ESP_OK) return false; - efs = _efs[index]; - - if(total_bytes) *total_bytes = efs->cfg.block_size * efs->cfg.block_count; - if(used_bytes) *used_bytes = efs->cfg.block_size * lfs_fs_size(efs->fs); - - return ESP_OK; -} - -esp_err_t esp_vfs_littlefs_register(const esp_vfs_littlefs_conf_t * conf) -{ - assert(conf->base_path); - const esp_vfs_t vfs = { - .flags = ESP_VFS_FLAG_CONTEXT_PTR, - .write_p = &vfs_littlefs_write, - .lseek_p = &vfs_littlefs_lseek, - .read_p = &vfs_littlefs_read, - .open_p = &vfs_littlefs_open, - .close_p = &vfs_littlefs_close, -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - .fstat_p = &vfs_littlefs_fstat, -#else - .fstat_p = NULL, /* Not supported */ -#endif - .stat_p = &vfs_littlefs_stat, - .link_p = NULL, /* Not Supported */ - .unlink_p = &vfs_littlefs_unlink, - .rename_p = &vfs_littlefs_rename, - .opendir_p = &vfs_littlefs_opendir, - .closedir_p = &vfs_littlefs_closedir, - .readdir_p = &vfs_littlefs_readdir, - .readdir_r_p = &vfs_littlefs_readdir_r, - .seekdir_p = &vfs_littlefs_seekdir, - .telldir_p = &vfs_littlefs_telldir, - .mkdir_p = &vfs_littlefs_mkdir, - .rmdir_p = &vfs_littlefs_rmdir, - .fsync_p = &vfs_littlefs_fsync, -#ifndef CONFIG_LITTLEFS_FOR_IDF_3_2 -#if CONFIG_LITTLEFS_USE_MTIME - .utime_p = &vfs_littlefs_utime, -#else - .utime_p = NULL, -#endif // CONFIG_LITTLEFS_USE_MTIME -#endif //CONFIG_LITTLEFS_FOR_IDF_3_2 - }; - - esp_err_t err = esp_littlefs_init(conf); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to initialize LittleFS"); - return err; - } - - int index; - if (esp_littlefs_by_label(conf->partition_label, &index) != ESP_OK) { - ESP_LOGE(TAG, "Unable to find partition \"%s\"", conf->partition_label); - return ESP_ERR_NOT_FOUND; - } - - strlcat(_efs[index]->base_path, conf->base_path, ESP_VFS_PATH_MAX + 1); - err = esp_vfs_register(conf->base_path, &vfs, _efs[index]); - if (err != ESP_OK) { - esp_littlefs_free(&_efs[index]); - ESP_LOGE(TAG, "Failed to register Littlefs to \"%s\"", conf->base_path); - return err; - } - - ESP_LOGV(TAG, "Successfully registered LittleFS to \"%s\"", conf->base_path); - return ESP_OK; -} - -esp_err_t esp_vfs_littlefs_unregister(const char* partition_label) -{ - assert(partition_label); - int index; - if (esp_littlefs_by_label(partition_label, &index) != ESP_OK) { - ESP_LOGE(TAG, "Partition was never registered."); - return ESP_ERR_INVALID_STATE; - } - ESP_LOGV(TAG, "Unregistering \"%s\"", partition_label); - esp_err_t err = esp_vfs_unregister(_efs[index]->base_path); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to unregister \"%s\"", partition_label); - return err; - } - esp_littlefs_free(&_efs[index]); - _efs[index] = NULL; - return ESP_OK; -} - -esp_err_t esp_littlefs_format(const char* partition_label) { - assert( partition_label ); - - bool was_mounted = false; - bool efs_free = false; - int index = -1; - esp_err_t err; - esp_littlefs_t *efs = NULL; - - ESP_LOGV(TAG, "Formatting \"%s\"", partition_label); - - /* Get a context */ - err = esp_littlefs_by_label(partition_label, &index); - - if( err != ESP_OK ){ - /* Create a tmp context */ - ESP_LOGV(TAG, "Temporarily creating EFS context."); - efs_free = true; - const esp_vfs_littlefs_conf_t conf = { - /* base_name not necessary for initializing */ - .dont_mount = true, - .partition_label = partition_label, - }; - err = esp_littlefs_init(&conf); /* Internally MIGHT call esp_littlefs_format */ - if( err != ESP_OK ) { - ESP_LOGE(TAG, "Failed to initialize to format."); - goto exit; - } - - err = esp_littlefs_by_label(partition_label, &index); - if ( err != ESP_OK) { - ESP_LOGE(TAG, "Error obtaining context."); - goto exit; - } - } - - efs = _efs[index]; - assert( efs ); - - /* Unmount if mounted */ - if(efs->cache_size > 0){ - int res; - ESP_LOGV(TAG, "Partition was mounted. Unmounting..."); - was_mounted = true; - res = lfs_unmount(efs->fs); - if(res != LFS_ERR_OK){ - ESP_LOGE(TAG, "Failed to unmount."); - return ESP_FAIL; - } - esp_littlefs_free_fds(efs); - } - - /* Erase and Format */ - { - int res; - ESP_LOGV(TAG, "Formatting filesystem"); - esp_littlefs_erase_partition(partition_label); - res = lfs_format(efs->fs, &efs->cfg); - if( res != LFS_ERR_OK ) { - ESP_LOGE(TAG, "Failed to format filesystem"); - return ESP_FAIL; - } - } - - /* Mount filesystem */ - if( was_mounted ) { - int res; - /* Remount the partition */ - ESP_LOGV(TAG, "Remounting formatted partition"); - res = lfs_mount(efs->fs, &efs->cfg); - if( res != LFS_ERR_OK ) { - ESP_LOGE(TAG, "Failed to re-mount filesystem"); - return ESP_FAIL; - } - efs->cache_size = CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE; // Initial size of cache; will resize ondemand - efs->cache = calloc(sizeof(*efs->cache), efs->cache_size); - } - ESP_LOGV(TAG, "Format Success!"); - - err = ESP_OK; - -exit: - if(efs_free && index>=0) esp_littlefs_free(&_efs[index]); - return err; -} - -#if CONFIG_LITTLEFS_HUMAN_READABLE -/** - * @brief converts an enumerated lfs error into a string. - * @param lfs_error The littlefs error. - */ -const char * esp_littlefs_errno(enum lfs_error lfs_errno) { - switch(lfs_errno){ - case LFS_ERR_OK: return "LFS_ERR_OK"; - case LFS_ERR_IO: return "LFS_ERR_IO"; - case LFS_ERR_CORRUPT: return "LFS_ERR_CORRUPT"; - case LFS_ERR_NOENT: return "LFS_ERR_NOENT"; - case LFS_ERR_EXIST: return "LFS_ERR_EXIST"; - case LFS_ERR_NOTDIR: return "LFS_ERR_NOTDIR"; - case LFS_ERR_ISDIR: return "LFS_ERR_ISDIR"; - case LFS_ERR_NOTEMPTY: return "LFS_ERR_NOTEMPTY"; - case LFS_ERR_BADF: return "LFS_ERR_BADF"; - case LFS_ERR_FBIG: return "LFS_ERR_FBIG"; - case LFS_ERR_INVAL: return "LFS_ERR_INVAL"; - case LFS_ERR_NOSPC: return "LFS_ERR_NOSPC"; - case LFS_ERR_NOMEM: return "LFS_ERR_NOMEM"; - case LFS_ERR_NOATTR: return "LFS_ERR_NOATTR"; - case LFS_ERR_NAMETOOLONG: return "LFS_ERR_NAMETOOLONG"; - default: return "LFS_ERR_UNDEFINED"; - } - return ""; -} -#else -#define esp_littlefs_errno(x) "" -#endif - -/******************** - * Static Functions * - ********************/ - -/*** Helpers ***/ - -/** - * @brief Free and clear a littlefs definition structure. - * @param efs Pointer to pointer to struct. Done this way so we can also zero - * out the pointer. - */ -static void esp_littlefs_free(esp_littlefs_t ** efs) -{ - esp_littlefs_t * e = *efs; - if (e == NULL) return; - *efs = NULL; - - if (e->fs) { - if(e->cache_size > 0) lfs_unmount(e->fs); - free(e->fs); - } - if(e->lock) vSemaphoreDelete(e->lock); - esp_littlefs_free_fds(e); - free(e); -} - -/** - * @brief Free a vfs_littlefs_dir_t struct. - */ -static void esp_littlefs_dir_free(vfs_littlefs_dir_t *dir){ - if(dir == NULL) return; - if(dir->path) free(dir->path); - free(dir); -} - -/** - * Get a mounted littlefs filesystem by label. - * @param[in] label - * @param[out] index index into _efs - * @return ESP_OK on success - */ -static esp_err_t esp_littlefs_by_label(const char* label, int * index){ - int i; - esp_littlefs_t * p; - - if(!label || !index) return ESP_ERR_INVALID_ARG; - - ESP_LOGV(TAG, "Searching for existing filesystem for partition \"%s\"", label); - - for (i = 0; i < CONFIG_LITTLEFS_MAX_PARTITIONS; i++) { - p = _efs[i]; - if (p) { - if (strncmp(label, p->partition->label, 17) == 0) { - *index = i; - ESP_LOGV(TAG, "Found existing filesystem \"%s\" at index %d", label, *index); - return ESP_OK; - } - } - } - - ESP_LOGV(TAG, "Existing filesystem \%s\" not found", label); - return ESP_ERR_NOT_FOUND; -} - -/** - * @brief Get the index of an unallocated LittleFS slot. - * @param[out] index Indexd of free LittleFS slot - * @return ESP_OK on success - */ -static esp_err_t esp_littlefs_get_empty(int *index) { - assert(index); - for(uint8_t i=0; i < CONFIG_LITTLEFS_MAX_PARTITIONS; i++){ - if( _efs[i] == NULL ){ - *index = i; - return ESP_OK; - } - } - ESP_LOGE(TAG, "No more free partitions available."); - return ESP_FAIL; -} - -/** - * @brief erase a partition; make sure LittleFS is unmounted first. - * @param partition_label NULL-terminated string of partition to erase - * @return ESP_OK on success - */ -static esp_err_t esp_littlefs_erase_partition(const char *partition_label) { - ESP_LOGV(TAG, "Erasing partition..."); - - const esp_partition_t* partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, - partition_label); - if (!partition) { - ESP_LOGE(TAG, "partition \"%s\" could not be found", partition_label); - return ESP_ERR_NOT_FOUND; - } - - if( esp_partition_erase_range(partition, 0, partition->size) != ESP_OK ) { - ESP_LOGE(TAG, "Failed to erase partition"); - return ESP_FAIL; - } - - return ESP_OK; -} - -/** - * @brief Convert fcntl flags to littlefs flags - * @param m fcntl flags - * @return lfs flags - */ -static int esp_littlefs_flags_conv(int m) { - int lfs_flags = 0; - if (m == O_APPEND) {ESP_LOGV(TAG, "O_APPEND"); lfs_flags |= LFS_O_APPEND;} - if (m == O_RDONLY) {ESP_LOGV(TAG, "O_RDONLY"); lfs_flags |= LFS_O_RDONLY;} - if (m & O_WRONLY) {ESP_LOGV(TAG, "O_WRONLY"); lfs_flags |= LFS_O_WRONLY;} - if (m & O_RDWR) {ESP_LOGV(TAG, "O_RDWR"); lfs_flags |= LFS_O_RDWR;} - if (m & O_EXCL) {ESP_LOGV(TAG, "O_EXCL"); lfs_flags |= LFS_O_EXCL;} - if (m & O_CREAT) {ESP_LOGV(TAG, "O_CREAT"); lfs_flags |= LFS_O_CREAT;} - if (m & O_TRUNC) {ESP_LOGV(TAG, "O_TRUNC"); lfs_flags |= LFS_O_TRUNC;} - return lfs_flags; -} - -/** - * @brief Initialize and mount littlefs - * @param[in] conf Filesystem Configuration - * @return ESP_OK on success - */ -static esp_err_t esp_littlefs_init(const esp_vfs_littlefs_conf_t* conf) -{ - int index = -1; - esp_err_t err = ESP_FAIL; - const esp_partition_t* partition = NULL; - esp_littlefs_t * efs = NULL; - - if( _efs_lock == NULL ){ - static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; - portENTER_CRITICAL(&mux); - if( _efs_lock == NULL ){ - _efs_lock = xSemaphoreCreateMutex(); - assert(_efs_lock); - } - portEXIT_CRITICAL(&mux); - } - - xSemaphoreTake(_efs_lock, portMAX_DELAY); - - if (esp_littlefs_get_empty(&index) != ESP_OK) { - ESP_LOGE(TAG, "max mounted partitions reached"); - err = ESP_ERR_INVALID_STATE; - goto exit; - } - - /* Input and Environment Validation */ - if (esp_littlefs_by_label(conf->partition_label, &index) == ESP_OK) { - ESP_LOGE(TAG, "Partition already used"); - err = ESP_ERR_INVALID_STATE; - goto exit; - } - - { - uint32_t flash_page_size = g_rom_flashchip.page_size; - uint32_t log_page_size = CONFIG_LITTLEFS_PAGE_SIZE; - if (log_page_size % flash_page_size != 0) { - ESP_LOGE(TAG, "LITTLEFS_PAGE_SIZE is not multiple of flash chip page size (%d)", - flash_page_size); - err = ESP_ERR_INVALID_ARG; - goto exit; - } - } - - if ( NULL == conf->partition_label ) { - ESP_LOGE(TAG, "Partition label must be provided."); - err = ESP_ERR_INVALID_ARG; - goto exit; - } - - partition = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, - conf->partition_label); - - if (!partition) { - ESP_LOGE(TAG, "partition \"%s\" could not be found", conf->partition_label); - err = ESP_ERR_NOT_FOUND; - goto exit; - } - - /* Allocate Context */ - efs = calloc(1, sizeof(esp_littlefs_t)); - if (efs == NULL) { - ESP_LOGE(TAG, "esp_littlefs could not be malloced"); - err = ESP_ERR_NO_MEM; - goto exit; - } - efs->partition = partition; - - { /* LittleFS Configuration */ - efs->cfg.context = efs; - - // block device operations - efs->cfg.read = littlefs_api_read; - efs->cfg.prog = littlefs_api_prog; - efs->cfg.erase = littlefs_api_erase; - efs->cfg.sync = littlefs_api_sync; - - // block device configuration - efs->cfg.read_size = CONFIG_LITTLEFS_READ_SIZE; - efs->cfg.prog_size = CONFIG_LITTLEFS_WRITE_SIZE; - efs->cfg.block_size = CONFIG_LITTLEFS_BLOCK_SIZE;; - efs->cfg.block_count = efs->partition->size / efs->cfg.block_size; - efs->cfg.cache_size = CONFIG_LITTLEFS_CACHE_SIZE; - efs->cfg.lookahead_size = CONFIG_LITTLEFS_LOOKAHEAD_SIZE; - efs->cfg.block_cycles = CONFIG_LITTLEFS_BLOCK_CYCLES; - } - - efs->lock = xSemaphoreCreateRecursiveMutex(); - if (efs->lock == NULL) { - ESP_LOGE(TAG, "mutex lock could not be created"); - err = ESP_ERR_NO_MEM; - goto exit; - } - - efs->fs = calloc(1, sizeof(lfs_t)); - if (efs->fs == NULL) { - ESP_LOGE(TAG, "littlefs could not be malloced"); - err = ESP_ERR_NO_MEM; - goto exit; - } - - // Mount and Error Check - _efs[index] = efs; - if(!conf->dont_mount){ - int res = lfs_mount(efs->fs, &efs->cfg); - - if (conf->format_if_mount_failed && res != LFS_ERR_OK) { - esp_err_t err; - ESP_LOGW(TAG, "mount failed, %s (%i). formatting...", esp_littlefs_errno(res), res); - err = esp_littlefs_format(efs->partition->label); - if(err != ESP_OK) { - ESP_LOGE(TAG, "format failed"); - err = ESP_FAIL; - goto exit; - } - res = lfs_mount(efs->fs, &efs->cfg); - } - if (res != LFS_ERR_OK) { - ESP_LOGE(TAG, "mount failed, %s (%i)", esp_littlefs_errno(res), res); - err = ESP_FAIL; - goto exit; - } - efs->cache_size = 4; - efs->cache = calloc(sizeof(*efs->cache), efs->cache_size); - } - - err = ESP_OK; - -exit: - if(err != ESP_OK){ - if( index >= 0 ) { - esp_littlefs_free(&_efs[index]); - } - else{ - esp_littlefs_free(&efs); - } - } - xSemaphoreGive(_efs_lock); - return err; -} - -/** - * @brief - * @parameter efs file system context - */ -static inline int sem_take(esp_littlefs_t *efs) { - int res; -#if LOG_LOCAL_LEVEL >= 5 - ESP_LOGV(TAG, "------------------------ Sem Taking [%s]", pcTaskGetTaskName(NULL)); -#endif - res = xSemaphoreTakeRecursive(efs->lock, portMAX_DELAY); -#if LOG_LOCAL_LEVEL >= 5 - ESP_LOGV(TAG, "--------------------->>> Sem Taken [%s]", pcTaskGetTaskName(NULL)); -#endif - return res; -} - -/** - * @brief - * @parameter efs file system context - */ -static inline int sem_give(esp_littlefs_t *efs) { -#if LOG_LOCAL_LEVEL >= 5 - ESP_LOGV(TAG, "---------------------<<< Sem Give [%s]", pcTaskGetTaskName(NULL)); -#endif - return xSemaphoreGiveRecursive(efs->lock); -} - - -/* We are using a double allocation system here, which an array and a linked list. - The array contains the pointer to the file descriptor (the index in the array is what's returned to the user). - The linked list is used for file descriptors. - This means that position of nodes in the list must stay consistent: - - Allocation is obvious (append to the list from the head, and realloc the pointers array) - There is still a O(N) search in the cache for a free position to store - - Searching is a O(1) process (good) - - Deallocation is more tricky. That is, for example, - if you need to remove node 5 in a 12 nodes list, you'll have to: - 1) Mark the 5th position as freed (if it's the last position of the array realloc smaller) - 2) Walk the list until finding the pointer to the node O(N) and scrub the node so the chained list stays consistent - 3) Deallocate the node -*/ - -/** - * @brief Get a file descriptor - * @param[in,out] efs file system context - * @param[out] file pointer to a file that'll be filled with a file object - * @param[in] path_len the length of the filepath in bytes (including terminating zero byte) - * @return integer file descriptor. Returns -1 if a FD cannot be obtained. - * @warning This must be called with lock taken - */ -static int esp_littlefs_allocate_fd(esp_littlefs_t *efs, vfs_littlefs_file_t ** file -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - , const size_t path_len -#endif - ) -{ - int i = -1; - - assert( efs->fd_count < UINT16_MAX ); - assert( efs->cache_size < UINT16_MAX ); - - /* Make sure there is enough space in the cache to store new fd */ - if (efs->fd_count + 1 > efs->cache_size) { - uint16_t new_size = (uint16_t)MIN(UINT16_MAX, CONFIG_LITTLEFS_FD_CACHE_REALLOC_FACTOR * efs->cache_size); - /* Resize the cache */ - vfs_littlefs_file_t ** new_cache = realloc(efs->cache, new_size * sizeof(*efs->cache)); - if (!new_cache) { - ESP_LOGE(TAG, "Unable to allocate file cache"); - return -1; /* If it fails here, no harm is done to the filesystem, so it's safe */ - } - /* Zero out the new portions of the cache */ - memset(&new_cache[efs->cache_size], 0, (new_size - efs->cache_size) * sizeof(*efs->cache)); - efs->cache = new_cache; - efs->cache_size = new_size; - } - - - /* Allocate file descriptor here now */ -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - *file = calloc(1, sizeof(**file) + path_len); -#else - *file = calloc(1, sizeof(**file)); -#endif - - if (*file == NULL) { - /* If it fails here, the file system might have a larger cache, but it's harmless, no need to reverse it */ - ESP_LOGE(TAG, "Unable to allocate FD"); - return -1; - } - - /* Starting from here, nothing can fail anymore */ - -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - /* The trick here is to avoid dual allocation so the path pointer - should point to the next byte after it: - file => [ lfs_file | # | next | path | free_space ] - | /\ - |__/ - */ - (*file)->path = (char*)(*file) + sizeof(**file); -#endif - - /* Now find a free place in cache */ - for(i=0; i < efs->cache_size; i++) { - if (efs->cache[i] == NULL) { - efs->cache[i] = *file; - break; - } - } - /* Save file in the list */ - (*file)->next = efs->file; - efs->file = *file; - efs->fd_count++; - return i; -} - -/** - * @brief Release a file descriptor - * @param[in,out] efs file system context - * @param[in] fd File Descriptor to release - * @return 0 on success. -1 if a FD cannot be obtained. - * @warning This must be called with lock taken - */ -static int esp_littlefs_free_fd(esp_littlefs_t *efs, int fd){ - vfs_littlefs_file_t * file, * head; - - if((uint32_t)fd >= efs->cache_size) { - ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); - return -1; - } - - /* Get the file descriptor to free it */ - file = efs->cache[fd]; - head = efs->file; - /* Search for file in SLL to remove it */ - if (file == head) { - /* Last file, can't fail */ - efs->file = efs->file->next; - } else { - while (head && head->next != file) { - head = head->next; - } - if (!head) { - ESP_LOGE(TAG, "Inconsistent list"); - return -1; - } - /* Transaction starts here and can't fail anymore */ - head->next = file->next; - } - efs->cache[fd] = NULL; - efs->fd_count--; - - ESP_LOGV(TAG, "Clearing FD"); - free(file); - -#if 0 - /* Realloc smaller if its possible - * * Find and realloc based on number of trailing NULL ptrs in cache - * * Leave some hysteris to prevent thrashing around resize points - * This is disabled for now because it adds unnecessary complexity - * and binary size increase that outweights its ebenfits. - */ - if(efs->cache_size > CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE) { - uint16_t n_free; - uint16_t new_size = efs->cache_size / CONFIG_LITTLEFS_FD_CACHE_REALLOC_FACTOR; - - if(new_size >= CONFIG_LITTLEFS_FD_CACHE_MIN_SIZE) { - /* Count number of trailing NULL ptrs */ - for(n_free=0; n_free < efs->cache_size; n_free++) { - if(efs->cache[efs->cache_size - n_free - 1] != NULL) { - break; - } - } - - if(n_free >= (efs->cache_size - new_size)){ - new_size += CONFIG_LITTLEFS_FD_CACHE_HYST; - ESP_LOGV(TAG, "Reallocating cache %i -> %i", efs->cache_size, new_size); - vfs_littlefs_file_t ** new_cache; - new_cache = realloc(efs->cache, new_size * sizeof(*efs->cache)); - /* No harm on realloc failure, continue using the oversized cache */ - if(new_cache) { - efs->cache = new_cache; - efs->cache_size = new_size; - } - } - } - } -#endif - - return 0; -} - -/** - * @brief Compute the 32bit DJB2 hash of the given string. - * @param[in] path the path to hash - * @returns the hash for this path - */ -static uint32_t compute_hash(const char * path) { - uint32_t hash = 5381; - char c; - - while ((c = *path++)) - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - return hash; -} - -/** - * @brief finds an open file descriptor by file name. - * @param[in,out] efs file system context - * @param[in] path File path to check. - * @returns integer file descriptor. Returns -1 if not found. - * @warning This must be called with lock taken - * @warning if CONFIG_LITTLEFS_USE_ONLY_HASH, there is a slim chance an - * erroneous FD may be returned on hash collision. - */ -static int esp_littlefs_get_fd_by_name(esp_littlefs_t *efs, const char *path){ - uint32_t hash = compute_hash(path); - - for(uint16_t i=0, j=0; i < efs->cache_size && j < efs->fd_count; i++){ - if (efs->cache[i]) { - ++j; - - if ( - efs->cache[i]->hash == hash // Faster than strcmp -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - && strcmp(path, efs->cache[i]->path) == 0 // May as well check incase of hash collision. Usually short-circuited. -#endif - ) { - ESP_LOGV(TAG, "Found \"%s\" at FD %d.", path, i); - return i; - } - } - } - ESP_LOGV(TAG, "Unable to get a find FD for \"%s\"", path); - return -1; -} - -/*** Filesystem Hooks ***/ - -static int vfs_littlefs_open(void* ctx, const char * path, int flags, int mode) { - /* Note: mode is currently unused */ - int fd=-1, lfs_flags, res; - esp_littlefs_t *efs = (esp_littlefs_t *)ctx; - vfs_littlefs_file_t *file = NULL; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - size_t path_len = strlen(path) + 1; // include NULL terminator -#endif - assert(path); - - ESP_LOGV(TAG, "Opening %s", path); - - /* Convert flags to lfs flags */ - lfs_flags = esp_littlefs_flags_conv(flags); - - /* Get a FD */ - sem_take(efs); - fd = esp_littlefs_allocate_fd(efs, &file -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - , path_len -#endif - ); - if(fd < 0) { - errno = -fd; - sem_give(efs); - ESP_LOGV(TAG, "Error obtaining FD"); - return LFS_ERR_INVAL; - } - /* Open File */ - res = lfs_file_open(efs->fs, &file->file, path, lfs_flags); - - if( res < 0 ) { - errno = -res; - esp_littlefs_free_fd(efs, fd); - sem_give(efs); - ESP_LOGV(TAG, "Failed to open file. Error %s (%d)", - esp_littlefs_errno(res), res); - return LFS_ERR_INVAL; - } - - file->hash = compute_hash(path); -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - memcpy(file->path, path, path_len); -#endif - -#if CONFIG_LITTLEFS_USE_MTIME - if (lfs_flags != LFS_O_RDONLY) { - /* If this is being opened as not read-only */ - vfs_littlefs_update_mtime(efs, path); - } -#endif - - sem_give(efs); - ESP_LOGV(TAG, "Done opening %s", path); - return fd; -} - -static ssize_t vfs_littlefs_write(void* ctx, int fd, const void * data, size_t size) { - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - ssize_t res; - vfs_littlefs_file_t *file = NULL; - - sem_take(efs); - if((uint32_t)fd > efs->cache_size) { - sem_give(efs); - ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); - return LFS_ERR_BADF; - } - file = efs->cache[fd]; - res = lfs_file_write(efs->fs, &file->file, data, size); - sem_give(efs); - - if(res < 0){ - errno = -res; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to write FD %d; path \"%s\". Error %s (%d)", - fd, file->path, esp_littlefs_errno(res), res); -#else - ESP_LOGV(TAG, "Failed to write FD %d. Error %s (%d)", - fd, esp_littlefs_errno(res), res); -#endif - return res; - } - - return res; -} - -static ssize_t vfs_littlefs_read(void* ctx, int fd, void * dst, size_t size) { - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - ssize_t res; - vfs_littlefs_file_t *file = NULL; - - - sem_take(efs); - if((uint32_t)fd > efs->cache_size) { - sem_give(efs); - ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); - return LFS_ERR_BADF; - } - file = efs->cache[fd]; - res = lfs_file_read(efs->fs, &file->file, dst, size); - sem_give(efs); - - if(res < 0){ - errno = -res; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to read file \"%s\". Error %s (%d)", - file->path, esp_littlefs_errno(res), res); -#else - ESP_LOGV(TAG, "Failed to read FD %d. Error %s (%d)", - fd, esp_littlefs_errno(res), res); -#endif - return res; - } - - return res; -} - -static int vfs_littlefs_close(void* ctx, int fd) { - // TODO update mtime on close? SPIFFS doesn't do this - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - int res; - vfs_littlefs_file_t *file = NULL; - - sem_take(efs); - if((uint32_t)fd > efs->cache_size) { - sem_give(efs); - ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); - return LFS_ERR_BADF; - } - file = efs->cache[fd]; - res = lfs_file_close(efs->fs, &file->file); - if(res < 0){ - errno = -res; - sem_give(efs); -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to close file \"%s\". Error %s (%d)", - file->path, esp_littlefs_errno(res), res); -#else - ESP_LOGV(TAG, "Failed to close Fd %d. Error %s (%d)", - fd, esp_littlefs_errno(res), res); -#endif - return res; - } - esp_littlefs_free_fd(efs, fd); - sem_give(efs); - return res; -} - -static off_t vfs_littlefs_lseek(void* ctx, int fd, off_t offset, int mode) { - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - lfs_soff_t res; - vfs_littlefs_file_t *file = NULL; - int whence; - - switch (mode) { - case SEEK_SET: whence = LFS_SEEK_SET; break; - case SEEK_CUR: whence = LFS_SEEK_CUR; break; - case SEEK_END: whence = LFS_SEEK_END; break; - default: - ESP_LOGE(TAG, "Invalid mode"); - return -1; - } - - sem_take(efs); - if((uint32_t)fd > efs->cache_size) { - sem_give(efs); - ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); - return LFS_ERR_BADF; - } - file = efs->cache[fd]; - res = lfs_file_seek(efs->fs, &file->file, offset, whence); - sem_give(efs); - - if(res < 0){ - errno = -res; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to seek file \"%s\" to offset %08x. Error %s (%d)", - file->path, (unsigned int)offset, esp_littlefs_errno(res), res); -#else - ESP_LOGV(TAG, "Failed to seek FD %d to offset %08x. Error (%d)", - fd, (unsigned int)offset, res); -#endif - return res; - } - - return res; -} - -static int vfs_littlefs_fsync(void* ctx, int fd) -{ - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - ssize_t res; - vfs_littlefs_file_t *file = NULL; - - - sem_take(efs); - if((uint32_t)fd > efs->cache_size) { - sem_give(efs); - ESP_LOGE(TAG, "FD %d must be <%d.", fd, efs->cache_size); - return LFS_ERR_BADF; - } - file = efs->cache[fd]; - res = lfs_file_sync(efs->fs, &file->file); - sem_give(efs); - - if(res < 0){ - errno = -res; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to sync file \"%s\". Error %s (%d)", - file->path, esp_littlefs_errno(res), res); -#else - ESP_LOGV(TAG, "Failed to sync file %d. Error %d", fd, res); -#endif - return res; - } - - return res; -} - - -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH -static int vfs_littlefs_fstat(void* ctx, int fd, struct stat * st) { - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - struct lfs_info info; - int res; - vfs_littlefs_file_t *file = NULL; - - memset(st, 0, sizeof(struct stat)); - st->st_blksize = efs->cfg.block_size; - - sem_take(efs); - if((uint32_t)fd > efs->cache_size) { - sem_give(efs); - ESP_LOGE(TAG, "FD must be <%d.", efs->cache_size); - return LFS_ERR_BADF; - } - file = efs->cache[fd]; - res = lfs_stat(efs->fs, file->path, &info); - if (res < 0) { - errno = -res; - sem_give(efs); - ESP_LOGV(TAG, "Failed to stat file \"%s\". Error %s (%d)", - file->path, esp_littlefs_errno(res), res); - return res; - } - -#if CONFIG_LITTLEFS_USE_MTIME - st->st_mtime = vfs_littlefs_get_mtime(efs, file->path); -#endif - - sem_give(efs); - - st->st_size = info.size; - st->st_mode = ((info.type==LFS_TYPE_REG)?S_IFREG:S_IFDIR); - return 0; -} -#endif - -static int vfs_littlefs_stat(void* ctx, const char * path, struct stat * st) { - assert(path); - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - struct lfs_info info; - int res; - - memset(st, 0, sizeof(struct stat)); - st->st_blksize = efs->cfg.block_size; - - sem_take(efs); - res = lfs_stat(efs->fs, path, &info); - if (res < 0) { - errno = -res; - sem_give(efs); - /* Not strictly an error, since stat can be used to check - * if a file exists */ - ESP_LOGV(TAG, "Failed to stat path \"%s\". Error %s (%d)", - path, esp_littlefs_errno(res), res); - return res; - } -#if CONFIG_LITTLEFS_USE_MTIME - st->st_mtime = vfs_littlefs_get_mtime(efs, path); -#endif - sem_give(efs); - st->st_size = info.size; - st->st_mode = ((info.type==LFS_TYPE_REG)?S_IFREG:S_IFDIR); - return 0; -} - -static int vfs_littlefs_unlink(void* ctx, const char *path) { -#define fail_str_1 "Failed to unlink path \"%s\"." - assert(path); - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - struct lfs_info info; - int res; - - sem_take(efs); - res = lfs_stat(efs->fs, path, &info); - if (res < 0) { - errno = -res; - sem_give(efs); - ESP_LOGV(TAG, fail_str_1 " Error %s (%d)", - path, esp_littlefs_errno(res), res); - return res; - } - - if(esp_littlefs_get_fd_by_name(efs, path) >= 0) { - sem_give(efs); - ESP_LOGE(TAG, fail_str_1 " Has open FD.", path); - return -1; - } - - //if (info.type == LFS_TYPE_DIR) { - // sem_give(efs); - // ESP_LOGV(TAG, "Cannot unlink a directory."); - // return LFS_ERR_ISDIR; - //} - - res = lfs_remove(efs->fs, path); - if (res < 0) { - errno = -res; - sem_give(efs); - ESP_LOGV(TAG, fail_str_1 " Error %s (%d)", - path, esp_littlefs_errno(res), res); - return res; - } - - sem_give(efs); - - return 0; -#undef fail_str_1 -} - -static int vfs_littlefs_rename(void* ctx, const char *src, const char *dst) { - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - int res; - - sem_take(efs); - - if(esp_littlefs_get_fd_by_name(efs, src) >= 0){ - sem_give(efs); - ESP_LOGE(TAG, "Cannot rename; src \"%s\" is open.", src); - return -1; - } - else if(esp_littlefs_get_fd_by_name(efs, dst) >= 0){ - sem_give(efs); - ESP_LOGE(TAG, "Cannot rename; dst \"%s\" is open.", dst); - return -1; - } - - res = lfs_rename(efs->fs, src, dst); - sem_give(efs); - if (res < 0) { - errno = -res; - ESP_LOGV(TAG, "Failed to rename \"%s\" -> \"%s\". Error %s (%d)", - src, dst, esp_littlefs_errno(res), res); - return res; - } - - return 0; -} - -static DIR* vfs_littlefs_opendir(void* ctx, const char* name) { - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - int res; - vfs_littlefs_dir_t *dir = NULL; - - dir = calloc(1, sizeof(vfs_littlefs_dir_t)); - if( dir == NULL ) { - ESP_LOGE(TAG, "dir struct could not be malloced"); - goto exit; - } - - dir->path = strdup(name); - if(dir->path == NULL){ - ESP_LOGE(TAG, "dir path name could not be malloced"); - goto exit; - } - - sem_take(efs); - res = lfs_dir_open(efs->fs, &dir->d, dir->path); - sem_give(efs); - if (res < 0) { - errno = -res; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to opendir \"%s\". Error %s (%d)", - dir->path, esp_littlefs_errno(res), res); -#else - ESP_LOGV(TAG, "Failed to opendir \"%s\". Error %d", dir->path, res); -#endif - goto exit; - } - - return (DIR *)dir; - -exit: - esp_littlefs_dir_free(dir); - return NULL; -} - -static int vfs_littlefs_closedir(void* ctx, DIR* pdir) { - assert(pdir); - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; - int res; - - sem_take(efs); - res = lfs_dir_close(efs->fs, &dir->d); - sem_give(efs); - if (res < 0) { - errno = -res; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to closedir \"%s\". Error %s (%d)", - dir->path, esp_littlefs_errno(res), res); -#else - ESP_LOGV(TAG, "Failed to closedir \"%s\". Error %d", dir->path, res); -#endif - return res; - } - - esp_littlefs_dir_free(dir); - return 0; -} - -static struct dirent* vfs_littlefs_readdir(void* ctx, DIR* pdir) { - assert(pdir); - vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; - int res; - struct dirent* out_dirent; - - res = vfs_littlefs_readdir_r(ctx, pdir, &dir->e, &out_dirent); - if (res != 0) return NULL; - return out_dirent; -} - -static int vfs_littlefs_readdir_r(void* ctx, DIR* pdir, - struct dirent* entry, struct dirent** out_dirent) { - assert(pdir); - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; - int res; - struct lfs_info info = { 0 }; - - sem_take(efs); - do{ /* Read until we get a real object name */ - res = lfs_dir_read(efs->fs, &dir->d, &info); - }while( res>0 && (strcmp(info.name, ".") == 0 || strcmp(info.name, "..") == 0)); - sem_give(efs); - if (res < 0) { - errno = -res; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to readdir \"%s\". Error %s (%d)", - dir->path, esp_littlefs_errno(res), res); -#else - ESP_LOGV(TAG, "Failed to readdir \"%s\". Error %d", dir->path, res); -#endif - return -1; - } - - if(info.type == LFS_TYPE_REG) { - ESP_LOGV(TAG, "readdir a file of size %d named \"%s\"", - info.size, info.name); - } - else { - ESP_LOGV(TAG, "readdir a dir named \"%s\"", info.name); - } - - if(res == 0) { - /* End of Objs */ - ESP_LOGV(TAG, "Reached the end of the directory."); - *out_dirent = NULL; - } - else { - entry->d_ino = 0; - entry->d_type = info.type == LFS_TYPE_REG ? DT_REG : DT_DIR; - strncpy(entry->d_name, info.name, sizeof(entry->d_name)); - *out_dirent = entry; - } - dir->offset++; - - return 0; -} - -static long vfs_littlefs_telldir(void* ctx, DIR* pdir) { - assert(pdir); - vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; - return dir->offset; -} - -static void vfs_littlefs_seekdir(void* ctx, DIR* pdir, long offset) { - assert(pdir); - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - vfs_littlefs_dir_t * dir = (vfs_littlefs_dir_t *) pdir; - int res; - - if (offset < dir->offset) { - /* close and re-open dir to rewind to beginning */ - sem_take(efs); - res = lfs_dir_rewind(efs->fs, &dir->d); - sem_give(efs); - if (res < 0) { - errno = -res; - ESP_LOGV(TAG, "Failed to rewind dir \"%s\". Error %s (%d)", - dir->path, esp_littlefs_errno(res), res); - return; - } - dir->offset = 0; - } - - while(dir->offset < offset){ - struct dirent *out_dirent; - res = vfs_littlefs_readdir_r(ctx, pdir, &dir->e, &out_dirent); - if( res != 0 ){ - ESP_LOGE(TAG, "Error readdir_r"); - return; - } - } -} - -static int vfs_littlefs_mkdir(void* ctx, const char* name, mode_t mode) { - /* Note: mode is currently unused */ - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - int res; - ESP_LOGV(TAG, "mkdir \"%s\"", name); - - sem_take(efs); - res = lfs_mkdir(efs->fs, name); - sem_give(efs); - if (res < 0) { - errno = -res; - ESP_LOGV(TAG, "Failed to mkdir \"%s\". Error %s (%d)", - name, esp_littlefs_errno(res), res); - return res; - } - return 0; -} - -static int vfs_littlefs_rmdir(void* ctx, const char* name) { - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - struct lfs_info info; - int res; - - /* Error Checking */ - sem_take(efs); - res = lfs_stat(efs->fs, name, &info); - if (res < 0) { - errno = -res; - sem_give(efs); - ESP_LOGV(TAG, "\"%s\" doesn't exist.", name); - return -1; - } - - if (info.type != LFS_TYPE_DIR) { - sem_give(efs); - ESP_LOGV(TAG, "\"%s\" is not a directory.", name); - return -1; - } - - /* Unlink the dir */ - res = lfs_remove(efs->fs, name); - sem_give(efs); - if ( res < 0) { - errno = -res; - ESP_LOGV(TAG, "Failed to unlink path \"%s\". Error %s (%d)", - name, esp_littlefs_errno(res), res); - return -1; - } - - return 0; -} - -#if CONFIG_LITTLEFS_USE_MTIME -/** - * Sets the mtime attr to t. - */ -static int vfs_littlefs_update_mtime_value(esp_littlefs_t *efs, const char *path, time_t t) -{ - int res; - res = lfs_setattr(efs->fs, path, LITTLEFS_ATTR_MTIME, - &t, sizeof(t)); - if( res < 0 ) { - errno = -res; - ESP_LOGV(TAG, "Failed to update mtime (%d)", res); - } - - return res; -} - -/** - * Sets the mtime attr to an appropriate value - */ -static void vfs_littlefs_update_mtime(esp_littlefs_t *efs, const char *path) -{ - vfs_littlefs_utime(efs, path, NULL); -} - - -static int vfs_littlefs_utime(void *ctx, const char *path, const struct utimbuf *times) -{ - esp_littlefs_t * efs = (esp_littlefs_t *)ctx; - time_t t; - - assert(path); - - if (times) { - t = times->modtime; - } else { -#if CONFIG_LITTLEFS_MTIME_USE_SECONDS - // use current time - t = time(NULL); -#elif CONFIG_LITTLEFS_MTIME_USE_NONCE - assert( sizeof(time_t) == 4 ); - t = vfs_littlefs_get_mtime(efs, path); - if( 0 == t ) t = esp_random(); - else t += 1; - - if( 0 == t ) t = 1; -#else -#error "Invalid MTIME configuration" -#endif - } - - int ret = vfs_littlefs_update_mtime_value(efs, path, t); - return ret; -} - -static time_t vfs_littlefs_get_mtime(esp_littlefs_t *efs, const char *path) -{ - time_t t = 0; - int size; - size = lfs_getattr(efs->fs, path, LITTLEFS_ATTR_MTIME, - &t, sizeof(t)); - if( size < 0 ) { - errno = -size; -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - ESP_LOGV(TAG, "Failed to get mtime attribute %s (%d)", - esp_littlefs_errno(size), size); -#else - ESP_LOGV(TAG, "Failed to get mtime attribute %d", size); -#endif - } - return t; -} -#endif //CONFIG_LITTLEFS_USE_MTIME diff --git a/lib/LITTLEFS/src/esp_littlefs.h b/lib/LITTLEFS/src/esp_littlefs.h deleted file mode 100644 index d65e9547..00000000 --- a/lib/LITTLEFS/src/esp_littlefs.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef ESP_LITTLEFS_H__ -#define ESP_LITTLEFS_H__ - -#include -#include -#include -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" -#include "esp_err.h" -#include -#include -#include -#include -//#include -#include -#include -#include -#include "sdkconfig.h" - -#include "lfs.h" //#include "littlefs/lfs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Last Modified Time - * - * Use 't' for LITTLEFS_ATTR_MTIME to match example: - * https://github.com/ARMmbed/littlefs/issues/23#issuecomment-482293539 - * And to match other external tools such as: - * https://github.com/earlephilhower/mklittlefs - */ -#define LITTLEFS_ATTR_MTIME ((uint8_t) 't') - -/** - *Configuration structure for esp_vfs_littlefs_register. - */ -typedef struct { - const char *base_path; /**< Mounting point. */ - const char *partition_label; /**< Label of partition to use. */ - uint8_t format_if_mount_failed:1; /**< Format the file system if it fails to mount. */ - uint8_t dont_mount:1; /**< Don't attempt to mount or format. Overrides format_if_mount_failed */ -} esp_vfs_littlefs_conf_t; - -/** - * Register and mount littlefs to VFS with given path prefix. - * - * @param conf Pointer to esp_vfs_littlefs_conf_t configuration structure - * - * @return - * - ESP_OK if success - * - ESP_ERR_NO_MEM if objects could not be allocated - * - ESP_ERR_INVALID_STATE if already mounted or partition is encrypted - * - ESP_ERR_NOT_FOUND if partition for littlefs was not found - * - ESP_FAIL if mount or format fails - */ -esp_err_t esp_vfs_littlefs_register(const esp_vfs_littlefs_conf_t * conf); - -/** - * Unregister and unmount littlefs from VFS - * - * @param partition_label Label of the partition to unregister. - * - * @return - * - ESP_OK if successful - * - ESP_ERR_INVALID_STATE already unregistered - */ -esp_err_t esp_vfs_littlefs_unregister(const char* partition_label); - -/** - * Check if littlefs is mounted - * - * @param partition_label Label of the partition to check. - * - * @return - * - true if mounted - * - false if not mounted - */ -bool esp_littlefs_mounted(const char* partition_label); - -/** - * Format the littlefs partition - * - * @param partition_label Label of the partition to format. - * @return - * - ESP_OK if successful - * - ESP_FAIL on error - */ -esp_err_t esp_littlefs_format(const char* partition_label); - -/** - * Get information for littlefs - * - * @param partition_label Optional, label of the partition to get info for. - * @param[out] total_bytes Size of the file system - * @param[out] used_bytes Current used bytes in the file system - * - * @return - * - ESP_OK if success - * - ESP_ERR_INVALID_STATE if not mounted - */ -esp_err_t esp_littlefs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes); - -#if CONFIG_LITTLEFS_HUMAN_READABLE -/** - * @brief converts an enumerated lfs error into a string. - * @param lfs_errno The enumerated littlefs error. - */ -const char * esp_littlefs_errno(enum lfs_error lfs_errno); -#endif - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif diff --git a/lib/LITTLEFS/src/lfs.c b/lib/LITTLEFS/src/lfs.c deleted file mode 100644 index eb832fa0..00000000 --- a/lib/LITTLEFS/src/lfs.c +++ /dev/null @@ -1,4913 +0,0 @@ -/* - * The little filesystem - * - * Copyright (c) 2017, Arm Limited. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause - */ -#include "lfs.h" -#include "lfs_util.h" - -#define LFS_BLOCK_NULL ((lfs_block_t)-1) -#define LFS_BLOCK_INLINE ((lfs_block_t)-2) - -/// Caching block device operations /// -static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) { - // do not zero, cheaper if cache is readonly or only going to be - // written with identical data (during relocates) - (void)lfs; - rcache->block = LFS_BLOCK_NULL; -} - -static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) { - // zero to avoid information leak - memset(pcache->buffer, 0xff, lfs->cfg->cache_size); - pcache->block = LFS_BLOCK_NULL; -} - -static int lfs_bd_read(lfs_t *lfs, - const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, - lfs_block_t block, lfs_off_t off, - void *buffer, lfs_size_t size) { - uint8_t *data = buffer; - if (block >= lfs->cfg->block_count || - off+size > lfs->cfg->block_size) { - return LFS_ERR_CORRUPT; - } - - while (size > 0) { - lfs_size_t diff = size; - - if (pcache && block == pcache->block && - off < pcache->off + pcache->size) { - if (off >= pcache->off) { - // is already in pcache? - diff = lfs_min(diff, pcache->size - (off-pcache->off)); - memcpy(data, &pcache->buffer[off-pcache->off], diff); - - data += diff; - off += diff; - size -= diff; - continue; - } - - // pcache takes priority - diff = lfs_min(diff, pcache->off-off); - } - - if (block == rcache->block && - off < rcache->off + rcache->size) { - if (off >= rcache->off) { - // is already in rcache? - diff = lfs_min(diff, rcache->size - (off-rcache->off)); - memcpy(data, &rcache->buffer[off-rcache->off], diff); - - data += diff; - off += diff; - size -= diff; - continue; - } - - // rcache takes priority - diff = lfs_min(diff, rcache->off-off); - } - - if (size >= hint && off % lfs->cfg->read_size == 0 && - size >= lfs->cfg->read_size) { - // bypass cache? - diff = lfs_aligndown(diff, lfs->cfg->read_size); - int err = lfs->cfg->read(lfs->cfg, block, off, data, diff); - if (err) { - return err; - } - - data += diff; - off += diff; - size -= diff; - continue; - } - - // load to cache, first condition can no longer fail - LFS_ASSERT(block < lfs->cfg->block_count); - rcache->block = block; - rcache->off = lfs_aligndown(off, lfs->cfg->read_size); - rcache->size = lfs_min( - lfs_min( - lfs_alignup(off+hint, lfs->cfg->read_size), - lfs->cfg->block_size) - - rcache->off, - lfs->cfg->cache_size); - int err = lfs->cfg->read(lfs->cfg, rcache->block, - rcache->off, rcache->buffer, rcache->size); - LFS_ASSERT(err <= 0); - if (err) { - return err; - } - } - - return 0; -} - -enum { - LFS_CMP_EQ = 0, - LFS_CMP_LT = 1, - LFS_CMP_GT = 2, -}; - -static int lfs_bd_cmp(lfs_t *lfs, - const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, - lfs_block_t block, lfs_off_t off, - const void *buffer, lfs_size_t size) { - const uint8_t *data = buffer; - - for (lfs_off_t i = 0; i < size; i++) { - uint8_t dat; - int err = lfs_bd_read(lfs, - pcache, rcache, hint-i, - block, off+i, &dat, 1); - if (err) { - return err; - } - - if (dat != data[i]) { - return (dat < data[i]) ? LFS_CMP_LT : LFS_CMP_GT; - } - } - - return LFS_CMP_EQ; -} - -static int lfs_bd_flush(lfs_t *lfs, - lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { - if (pcache->block != LFS_BLOCK_NULL && pcache->block != LFS_BLOCK_INLINE) { - LFS_ASSERT(pcache->block < lfs->cfg->block_count); - lfs_size_t diff = lfs_alignup(pcache->size, lfs->cfg->prog_size); - int err = lfs->cfg->prog(lfs->cfg, pcache->block, - pcache->off, pcache->buffer, diff); - LFS_ASSERT(err <= 0); - if (err) { - return err; - } - - if (validate) { - // check data on disk - lfs_cache_drop(lfs, rcache); - int res = lfs_bd_cmp(lfs, - NULL, rcache, diff, - pcache->block, pcache->off, pcache->buffer, diff); - if (res < 0) { - return res; - } - - if (res != LFS_CMP_EQ) { - return LFS_ERR_CORRUPT; - } - } - - lfs_cache_zero(lfs, pcache); - } - - return 0; -} - -static int lfs_bd_sync(lfs_t *lfs, - lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { - lfs_cache_drop(lfs, rcache); - - int err = lfs_bd_flush(lfs, pcache, rcache, validate); - if (err) { - return err; - } - - err = lfs->cfg->sync(lfs->cfg); - LFS_ASSERT(err <= 0); - return err; -} - -static int lfs_bd_prog(lfs_t *lfs, - lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate, - lfs_block_t block, lfs_off_t off, - const void *buffer, lfs_size_t size) { - const uint8_t *data = buffer; - LFS_ASSERT(block == LFS_BLOCK_INLINE || block < lfs->cfg->block_count); - LFS_ASSERT(off + size <= lfs->cfg->block_size); - - while (size > 0) { - if (block == pcache->block && - off >= pcache->off && - off < pcache->off + lfs->cfg->cache_size) { - // already fits in pcache? - lfs_size_t diff = lfs_min(size, - lfs->cfg->cache_size - (off-pcache->off)); - memcpy(&pcache->buffer[off-pcache->off], data, diff); - - data += diff; - off += diff; - size -= diff; - - pcache->size = lfs_max(pcache->size, off - pcache->off); - if (pcache->size == lfs->cfg->cache_size) { - // eagerly flush out pcache if we fill up - int err = lfs_bd_flush(lfs, pcache, rcache, validate); - if (err) { - return err; - } - } - - continue; - } - - // pcache must have been flushed, either by programming and - // entire block or manually flushing the pcache - LFS_ASSERT(pcache->block == LFS_BLOCK_NULL); - - // prepare pcache, first condition can no longer fail - pcache->block = block; - pcache->off = lfs_aligndown(off, lfs->cfg->prog_size); - pcache->size = 0; - } - - return 0; -} - -static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { - LFS_ASSERT(block < lfs->cfg->block_count); - int err = lfs->cfg->erase(lfs->cfg, block); - LFS_ASSERT(err <= 0); - return err; -} - - -/// Small type-level utilities /// -// operations on block pairs -static inline void lfs_pair_swap(lfs_block_t pair[2]) { - lfs_block_t t = pair[0]; - pair[0] = pair[1]; - pair[1] = t; -} - -static inline bool lfs_pair_isnull(const lfs_block_t pair[2]) { - return pair[0] == LFS_BLOCK_NULL || pair[1] == LFS_BLOCK_NULL; -} - -static inline int lfs_pair_cmp( - const lfs_block_t paira[2], - const lfs_block_t pairb[2]) { - return !(paira[0] == pairb[0] || paira[1] == pairb[1] || - paira[0] == pairb[1] || paira[1] == pairb[0]); -} - -static inline bool lfs_pair_sync( - const lfs_block_t paira[2], - const lfs_block_t pairb[2]) { - return (paira[0] == pairb[0] && paira[1] == pairb[1]) || - (paira[0] == pairb[1] && paira[1] == pairb[0]); -} - -static inline void lfs_pair_fromle32(lfs_block_t pair[2]) { - pair[0] = lfs_fromle32(pair[0]); - pair[1] = lfs_fromle32(pair[1]); -} - -static inline void lfs_pair_tole32(lfs_block_t pair[2]) { - pair[0] = lfs_tole32(pair[0]); - pair[1] = lfs_tole32(pair[1]); -} - -// operations on 32-bit entry tags -typedef uint32_t lfs_tag_t; -typedef int32_t lfs_stag_t; - -#define LFS_MKTAG(type, id, size) \ - (((lfs_tag_t)(type) << 20) | ((lfs_tag_t)(id) << 10) | (lfs_tag_t)(size)) - -#define LFS_MKTAG_IF(cond, type, id, size) \ - ((cond) ? LFS_MKTAG(type, id, size) : LFS_MKTAG(LFS_FROM_NOOP, 0, 0)) - -#define LFS_MKTAG_IF_ELSE(cond, type1, id1, size1, type2, id2, size2) \ - ((cond) ? LFS_MKTAG(type1, id1, size1) : LFS_MKTAG(type2, id2, size2)) - -static inline bool lfs_tag_isvalid(lfs_tag_t tag) { - return !(tag & 0x80000000); -} - -static inline bool lfs_tag_isdelete(lfs_tag_t tag) { - return ((int32_t)(tag << 22) >> 22) == -1; -} - -static inline uint16_t lfs_tag_type1(lfs_tag_t tag) { - return (tag & 0x70000000) >> 20; -} - -static inline uint16_t lfs_tag_type3(lfs_tag_t tag) { - return (tag & 0x7ff00000) >> 20; -} - -static inline uint8_t lfs_tag_chunk(lfs_tag_t tag) { - return (tag & 0x0ff00000) >> 20; -} - -static inline int8_t lfs_tag_splice(lfs_tag_t tag) { - return (int8_t)lfs_tag_chunk(tag); -} - -static inline uint16_t lfs_tag_id(lfs_tag_t tag) { - return (tag & 0x000ffc00) >> 10; -} - -static inline lfs_size_t lfs_tag_size(lfs_tag_t tag) { - return tag & 0x000003ff; -} - -static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) { - return sizeof(tag) + lfs_tag_size(tag + lfs_tag_isdelete(tag)); -} - -// operations on attributes in attribute lists -struct lfs_mattr { - lfs_tag_t tag; - const void *buffer; -}; - -struct lfs_diskoff { - lfs_block_t block; - lfs_off_t off; -}; - -#define LFS_MKATTRS(...) \ - (struct lfs_mattr[]){__VA_ARGS__}, \ - sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr) - -// operations on global state -static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) { - for (int i = 0; i < 3; i++) { - ((uint32_t*)a)[i] ^= ((const uint32_t*)b)[i]; - } -} - -static inline bool lfs_gstate_iszero(const lfs_gstate_t *a) { - for (int i = 0; i < 3; i++) { - if (((uint32_t*)a)[i] != 0) { - return false; - } - } - return true; -} - -static inline bool lfs_gstate_hasorphans(const lfs_gstate_t *a) { - return lfs_tag_size(a->tag); -} - -static inline uint8_t lfs_gstate_getorphans(const lfs_gstate_t *a) { - return lfs_tag_size(a->tag); -} - -static inline bool lfs_gstate_hasmove(const lfs_gstate_t *a) { - return lfs_tag_type1(a->tag); -} - -static inline bool lfs_gstate_hasmovehere(const lfs_gstate_t *a, - const lfs_block_t *pair) { - return lfs_tag_type1(a->tag) && lfs_pair_cmp(a->pair, pair) == 0; -} - -static inline void lfs_gstate_fromle32(lfs_gstate_t *a) { - a->tag = lfs_fromle32(a->tag); - a->pair[0] = lfs_fromle32(a->pair[0]); - a->pair[1] = lfs_fromle32(a->pair[1]); -} - -static inline void lfs_gstate_tole32(lfs_gstate_t *a) { - a->tag = lfs_tole32(a->tag); - a->pair[0] = lfs_tole32(a->pair[0]); - a->pair[1] = lfs_tole32(a->pair[1]); -} - -// other endianness operations -static void lfs_ctz_fromle32(struct lfs_ctz *ctz) { - ctz->head = lfs_fromle32(ctz->head); - ctz->size = lfs_fromle32(ctz->size); -} - -static void lfs_ctz_tole32(struct lfs_ctz *ctz) { - ctz->head = lfs_tole32(ctz->head); - ctz->size = lfs_tole32(ctz->size); -} - -static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) { - superblock->version = lfs_fromle32(superblock->version); - superblock->block_size = lfs_fromle32(superblock->block_size); - superblock->block_count = lfs_fromle32(superblock->block_count); - superblock->name_max = lfs_fromle32(superblock->name_max); - superblock->file_max = lfs_fromle32(superblock->file_max); - superblock->attr_max = lfs_fromle32(superblock->attr_max); -} - -static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { - superblock->version = lfs_tole32(superblock->version); - superblock->block_size = lfs_tole32(superblock->block_size); - superblock->block_count = lfs_tole32(superblock->block_count); - superblock->name_max = lfs_tole32(superblock->name_max); - superblock->file_max = lfs_tole32(superblock->file_max); - superblock->attr_max = lfs_tole32(superblock->attr_max); -} - - -/// Internal operations predeclared here /// -static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, - const struct lfs_mattr *attrs, int attrcount); -static int lfs_dir_compact(lfs_t *lfs, - lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, - lfs_mdir_t *source, uint16_t begin, uint16_t end); -static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file); -static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file); -static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans); -static void lfs_fs_prepmove(lfs_t *lfs, - uint16_t id, const lfs_block_t pair[2]); -static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2], - lfs_mdir_t *pdir); -static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2], - lfs_mdir_t *parent); -static int lfs_fs_relocate(lfs_t *lfs, - const lfs_block_t oldpair[2], lfs_block_t newpair[2]); -int lfs_fs_traverseraw(lfs_t *lfs, - int (*cb)(void *data, lfs_block_t block), void *data, - bool includeorphans); -static int lfs_fs_forceconsistency(lfs_t *lfs); -static int lfs_deinit(lfs_t *lfs); -#ifdef LFS_MIGRATE -static int lfs1_traverse(lfs_t *lfs, - int (*cb)(void*, lfs_block_t), void *data); -#endif - -/// Block allocator /// -static int lfs_alloc_lookahead(void *p, lfs_block_t block) { - lfs_t *lfs = (lfs_t*)p; - lfs_block_t off = ((block - lfs->free.off) - + lfs->cfg->block_count) % lfs->cfg->block_count; - - if (off < lfs->free.size) { - lfs->free.buffer[off / 32] |= 1U << (off % 32); - } - - return 0; -} - -static void lfs_alloc_ack(lfs_t *lfs) { - lfs->free.ack = lfs->cfg->block_count; -} - -// Invalidate the lookahead buffer. This is done during mounting and -// failed traversals -static void lfs_alloc_reset(lfs_t *lfs) { - lfs->free.off = lfs->seed % lfs->cfg->block_size; - lfs->free.size = 0; - lfs->free.i = 0; - lfs_alloc_ack(lfs); -} - -static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { - while (true) { - while (lfs->free.i != lfs->free.size) { - lfs_block_t off = lfs->free.i; - lfs->free.i += 1; - lfs->free.ack -= 1; - - if (!(lfs->free.buffer[off / 32] & (1U << (off % 32)))) { - // found a free block - *block = (lfs->free.off + off) % lfs->cfg->block_count; - - // eagerly find next off so an alloc ack can - // discredit old lookahead blocks - while (lfs->free.i != lfs->free.size && - (lfs->free.buffer[lfs->free.i / 32] - & (1U << (lfs->free.i % 32)))) { - lfs->free.i += 1; - lfs->free.ack -= 1; - } - - return 0; - } - } - - // check if we have looked at all blocks since last ack - if (lfs->free.ack == 0) { - LFS_ERROR("No more free space %"PRIu32, - lfs->free.i + lfs->free.off); - return LFS_ERR_NOSPC; - } - - lfs->free.off = (lfs->free.off + lfs->free.size) - % lfs->cfg->block_count; - lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, lfs->free.ack); - lfs->free.i = 0; - - // find mask of free blocks from tree - memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); - int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); - if (err) { - lfs_alloc_reset(lfs); - return err; - } - } -} - -/// Metadata pair and directory operations /// -static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir, - lfs_tag_t gmask, lfs_tag_t gtag, - lfs_off_t goff, void *gbuffer, lfs_size_t gsize) { - lfs_off_t off = dir->off; - lfs_tag_t ntag = dir->etag; - lfs_stag_t gdiff = 0; - - if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair) && - lfs_tag_id(gmask) != 0 && - lfs_tag_id(lfs->gdisk.tag) <= lfs_tag_id(gtag)) { - // synthetic moves - gdiff -= LFS_MKTAG(0, 1, 0); - } - - // iterate over dir block backwards (for faster lookups) - while (off >= sizeof(lfs_tag_t) + lfs_tag_dsize(ntag)) { - off -= lfs_tag_dsize(ntag); - lfs_tag_t tag = ntag; - int err = lfs_bd_read(lfs, - NULL, &lfs->rcache, sizeof(ntag), - dir->pair[0], off, &ntag, sizeof(ntag)); - if (err) { - return err; - } - - ntag = (lfs_frombe32(ntag) ^ tag) & 0x7fffffff; - - if (lfs_tag_id(gmask) != 0 && - lfs_tag_type1(tag) == LFS_TYPE_SPLICE && - lfs_tag_id(tag) <= lfs_tag_id(gtag - gdiff)) { - if (tag == (LFS_MKTAG(LFS_TYPE_CREATE, 0, 0) | - (LFS_MKTAG(0, 0x3ff, 0) & (gtag - gdiff)))) { - // found where we were created - return LFS_ERR_NOENT; - } - - // move around splices - gdiff += LFS_MKTAG(0, lfs_tag_splice(tag), 0); - } - - if ((gmask & tag) == (gmask & (gtag - gdiff))) { - if (lfs_tag_isdelete(tag)) { - return LFS_ERR_NOENT; - } - - lfs_size_t diff = lfs_min(lfs_tag_size(tag), gsize); - err = lfs_bd_read(lfs, - NULL, &lfs->rcache, diff, - dir->pair[0], off+sizeof(tag)+goff, gbuffer, diff); - if (err) { - return err; - } - - memset((uint8_t*)gbuffer + diff, 0, gsize - diff); - - return tag + gdiff; - } - } - - return LFS_ERR_NOENT; -} - -static lfs_stag_t lfs_dir_get(lfs_t *lfs, const lfs_mdir_t *dir, - lfs_tag_t gmask, lfs_tag_t gtag, void *buffer) { - return lfs_dir_getslice(lfs, dir, - gmask, gtag, - 0, buffer, lfs_tag_size(gtag)); -} - -static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir, - const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, - lfs_tag_t gmask, lfs_tag_t gtag, - lfs_off_t off, void *buffer, lfs_size_t size) { - uint8_t *data = buffer; - if (off+size > lfs->cfg->block_size) { - return LFS_ERR_CORRUPT; - } - - while (size > 0) { - lfs_size_t diff = size; - - if (pcache && pcache->block == LFS_BLOCK_INLINE && - off < pcache->off + pcache->size) { - if (off >= pcache->off) { - // is already in pcache? - diff = lfs_min(diff, pcache->size - (off-pcache->off)); - memcpy(data, &pcache->buffer[off-pcache->off], diff); - - data += diff; - off += diff; - size -= diff; - continue; - } - - // pcache takes priority - diff = lfs_min(diff, pcache->off-off); - } - - if (rcache->block == LFS_BLOCK_INLINE && - off < rcache->off + rcache->size) { - if (off >= rcache->off) { - // is already in rcache? - diff = lfs_min(diff, rcache->size - (off-rcache->off)); - memcpy(data, &rcache->buffer[off-rcache->off], diff); - - data += diff; - off += diff; - size -= diff; - continue; - } - - // rcache takes priority - diff = lfs_min(diff, rcache->off-off); - } - - // load to cache, first condition can no longer fail - rcache->block = LFS_BLOCK_INLINE; - rcache->off = lfs_aligndown(off, lfs->cfg->read_size); - rcache->size = lfs_min(lfs_alignup(off+hint, lfs->cfg->read_size), - lfs->cfg->cache_size); - int err = lfs_dir_getslice(lfs, dir, gmask, gtag, - rcache->off, rcache->buffer, rcache->size); - if (err < 0) { - return err; - } - } - - return 0; -} - -static int lfs_dir_traverse_filter(void *p, - lfs_tag_t tag, const void *buffer) { - lfs_tag_t *filtertag = p; - (void)buffer; - - // which mask depends on unique bit in tag structure - uint32_t mask = (tag & LFS_MKTAG(0x100, 0, 0)) - ? LFS_MKTAG(0x7ff, 0x3ff, 0) - : LFS_MKTAG(0x700, 0x3ff, 0); - - // check for redundancy - if ((mask & tag) == (mask & *filtertag) || - lfs_tag_isdelete(*filtertag) || - (LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) == ( - LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | - (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) { - return true; - } - - // check if we need to adjust for created/deleted tags - if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE && - lfs_tag_id(tag) <= lfs_tag_id(*filtertag)) { - *filtertag += LFS_MKTAG(0, lfs_tag_splice(tag), 0); - } - - return false; -} - -static int lfs_dir_traverse(lfs_t *lfs, - const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag, - const struct lfs_mattr *attrs, int attrcount, - lfs_tag_t tmask, lfs_tag_t ttag, - uint16_t begin, uint16_t end, int16_t diff, - int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) { - // iterate over directory and attrs - while (true) { - lfs_tag_t tag; - const void *buffer; - struct lfs_diskoff disk; - if (off+lfs_tag_dsize(ptag) < dir->off) { - off += lfs_tag_dsize(ptag); - int err = lfs_bd_read(lfs, - NULL, &lfs->rcache, sizeof(tag), - dir->pair[0], off, &tag, sizeof(tag)); - if (err) { - return err; - } - - tag = (lfs_frombe32(tag) ^ ptag) | 0x80000000; - disk.block = dir->pair[0]; - disk.off = off+sizeof(lfs_tag_t); - buffer = &disk; - ptag = tag; - } else if (attrcount > 0) { - tag = attrs[0].tag; - buffer = attrs[0].buffer; - attrs += 1; - attrcount -= 1; - } else { - return 0; - } - - lfs_tag_t mask = LFS_MKTAG(0x7ff, 0, 0); - if ((mask & tmask & tag) != (mask & tmask & ttag)) { - continue; - } - - // do we need to filter? inlining the filtering logic here allows - // for some minor optimizations - if (lfs_tag_id(tmask) != 0) { - // scan for duplicates and update tag based on creates/deletes - int filter = lfs_dir_traverse(lfs, - dir, off, ptag, attrs, attrcount, - 0, 0, 0, 0, 0, - lfs_dir_traverse_filter, &tag); - if (filter < 0) { - return filter; - } - - if (filter) { - continue; - } - - // in filter range? - if (!(lfs_tag_id(tag) >= begin && lfs_tag_id(tag) < end)) { - continue; - } - } - - // handle special cases for mcu-side operations - if (lfs_tag_type3(tag) == LFS_FROM_NOOP) { - // do nothing - } else if (lfs_tag_type3(tag) == LFS_FROM_MOVE) { - uint16_t fromid = lfs_tag_size(tag); - uint16_t toid = lfs_tag_id(tag); - int err = lfs_dir_traverse(lfs, - buffer, 0, 0xffffffff, NULL, 0, - LFS_MKTAG(0x600, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, 0, 0), - fromid, fromid+1, toid-fromid+diff, - cb, data); - if (err) { - return err; - } - } else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) { - for (unsigned i = 0; i < lfs_tag_size(tag); i++) { - const struct lfs_attr *a = buffer; - int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type, - lfs_tag_id(tag) + diff, a[i].size), a[i].buffer); - if (err) { - return err; - } - } - } else { - int err = cb(data, tag + LFS_MKTAG(0, diff, 0), buffer); - if (err) { - return err; - } - } - } -} - -static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, - lfs_mdir_t *dir, const lfs_block_t pair[2], - lfs_tag_t fmask, lfs_tag_t ftag, uint16_t *id, - int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) { - // we can find tag very efficiently during a fetch, since we're already - // scanning the entire directory - lfs_stag_t besttag = -1; - - // if either block address is invalid we return LFS_ERR_CORRUPT here, - // otherwise later writes to the pair could fail - if (pair[0] >= lfs->cfg->block_count || pair[1] >= lfs->cfg->block_count) { - return LFS_ERR_CORRUPT; - } - - // find the block with the most recent revision - uint32_t revs[2] = {0, 0}; - int r = 0; - for (int i = 0; i < 2; i++) { - int err = lfs_bd_read(lfs, - NULL, &lfs->rcache, sizeof(revs[i]), - pair[i], 0, &revs[i], sizeof(revs[i])); - revs[i] = lfs_fromle32(revs[i]); - if (err && err != LFS_ERR_CORRUPT) { - return err; - } - - if (err != LFS_ERR_CORRUPT && - lfs_scmp(revs[i], revs[(i+1)%2]) > 0) { - r = i; - } - } - - dir->pair[0] = pair[(r+0)%2]; - dir->pair[1] = pair[(r+1)%2]; - dir->rev = revs[(r+0)%2]; - dir->off = 0; // nonzero = found some commits - - // now scan tags to fetch the actual dir and find possible match - for (int i = 0; i < 2; i++) { - lfs_off_t off = 0; - lfs_tag_t ptag = 0xffffffff; - - uint16_t tempcount = 0; - lfs_block_t temptail[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; - bool tempsplit = false; - lfs_stag_t tempbesttag = besttag; - - dir->rev = lfs_tole32(dir->rev); - uint32_t crc = lfs_crc(0xffffffff, &dir->rev, sizeof(dir->rev)); - dir->rev = lfs_fromle32(dir->rev); - - while (true) { - // extract next tag - lfs_tag_t tag; - off += lfs_tag_dsize(ptag); - int err = lfs_bd_read(lfs, - NULL, &lfs->rcache, lfs->cfg->block_size, - dir->pair[0], off, &tag, sizeof(tag)); - if (err) { - if (err == LFS_ERR_CORRUPT) { - // can't continue? - dir->erased = false; - break; - } - return err; - } - - crc = lfs_crc(crc, &tag, sizeof(tag)); - tag = lfs_frombe32(tag) ^ ptag; - - // next commit not yet programmed or we're not in valid range - if (!lfs_tag_isvalid(tag)) { - dir->erased = (lfs_tag_type1(ptag) == LFS_TYPE_CRC && - dir->off % lfs->cfg->prog_size == 0); - break; - } else if (off + lfs_tag_dsize(tag) > lfs->cfg->block_size) { - dir->erased = false; - break; - } - - ptag = tag; - - if (lfs_tag_type1(tag) == LFS_TYPE_CRC) { - // check the crc attr - uint32_t dcrc; - err = lfs_bd_read(lfs, - NULL, &lfs->rcache, lfs->cfg->block_size, - dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc)); - if (err) { - if (err == LFS_ERR_CORRUPT) { - dir->erased = false; - break; - } - return err; - } - dcrc = lfs_fromle32(dcrc); - - if (crc != dcrc) { - dir->erased = false; - break; - } - - // reset the next bit if we need to - ptag ^= (lfs_tag_t)(lfs_tag_chunk(tag) & 1U) << 31; - - // toss our crc into the filesystem seed for - // pseudorandom numbers - lfs->seed ^= crc; - - // update with what's found so far - besttag = tempbesttag; - dir->off = off + lfs_tag_dsize(tag); - dir->etag = ptag; - dir->count = tempcount; - dir->tail[0] = temptail[0]; - dir->tail[1] = temptail[1]; - dir->split = tempsplit; - - // reset crc - crc = 0xffffffff; - continue; - } - - // crc the entry first, hopefully leaving it in the cache - for (lfs_off_t j = sizeof(tag); j < lfs_tag_dsize(tag); j++) { - uint8_t dat; - err = lfs_bd_read(lfs, - NULL, &lfs->rcache, lfs->cfg->block_size, - dir->pair[0], off+j, &dat, 1); - if (err) { - if (err == LFS_ERR_CORRUPT) { - dir->erased = false; - break; - } - return err; - } - - crc = lfs_crc(crc, &dat, 1); - } - - // directory modification tags? - if (lfs_tag_type1(tag) == LFS_TYPE_NAME) { - // increase count of files if necessary - if (lfs_tag_id(tag) >= tempcount) { - tempcount = lfs_tag_id(tag) + 1; - } - } else if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE) { - tempcount += lfs_tag_splice(tag); - - if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | - (LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) { - tempbesttag |= 0x80000000; - } else if (tempbesttag != -1 && - lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) { - tempbesttag += LFS_MKTAG(0, lfs_tag_splice(tag), 0); - } - } else if (lfs_tag_type1(tag) == LFS_TYPE_TAIL) { - tempsplit = (lfs_tag_chunk(tag) & 1); - - err = lfs_bd_read(lfs, - NULL, &lfs->rcache, lfs->cfg->block_size, - dir->pair[0], off+sizeof(tag), &temptail, 8); - if (err) { - if (err == LFS_ERR_CORRUPT) { - dir->erased = false; - break; - } - } - lfs_pair_fromle32(temptail); - } - - // found a match for our fetcher? - if ((fmask & tag) == (fmask & ftag)) { - int res = cb(data, tag, &(struct lfs_diskoff){ - dir->pair[0], off+sizeof(tag)}); - if (res < 0) { - if (res == LFS_ERR_CORRUPT) { - dir->erased = false; - break; - } - return res; - } - - if (res == LFS_CMP_EQ) { - // found a match - tempbesttag = tag; - } else if ((LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) == - (LFS_MKTAG(0x7ff, 0x3ff, 0) & tempbesttag)) { - // found an identical tag, but contents didn't match - // this must mean that our besttag has been overwritten - tempbesttag = -1; - } else if (res == LFS_CMP_GT && - lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) { - // found a greater match, keep track to keep things sorted - tempbesttag = tag | 0x80000000; - } - } - } - - // consider what we have good enough - if (dir->off > 0) { - // synthetic move - if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair)) { - if (lfs_tag_id(lfs->gdisk.tag) == lfs_tag_id(besttag)) { - besttag |= 0x80000000; - } else if (besttag != -1 && - lfs_tag_id(lfs->gdisk.tag) < lfs_tag_id(besttag)) { - besttag -= LFS_MKTAG(0, 1, 0); - } - } - - // found tag? or found best id? - if (id) { - *id = lfs_min(lfs_tag_id(besttag), dir->count); - } - - if (lfs_tag_isvalid(besttag)) { - return besttag; - } else if (lfs_tag_id(besttag) < dir->count) { - return LFS_ERR_NOENT; - } else { - return 0; - } - } - - // failed, try the other block? - lfs_pair_swap(dir->pair); - dir->rev = revs[(r+1)%2]; - } - - LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}", - dir->pair[0], dir->pair[1]); - return LFS_ERR_CORRUPT; -} - -static int lfs_dir_fetch(lfs_t *lfs, - lfs_mdir_t *dir, const lfs_block_t pair[2]) { - // note, mask=-1, tag=-1 can never match a tag since this - // pattern has the invalid bit set - return (int)lfs_dir_fetchmatch(lfs, dir, pair, - (lfs_tag_t)-1, (lfs_tag_t)-1, NULL, NULL, NULL); -} - -static int lfs_dir_getgstate(lfs_t *lfs, const lfs_mdir_t *dir, - lfs_gstate_t *gstate) { - lfs_gstate_t temp; - lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x7ff, 0, 0), - LFS_MKTAG(LFS_TYPE_MOVESTATE, 0, sizeof(temp)), &temp); - if (res < 0 && res != LFS_ERR_NOENT) { - return res; - } - - if (res != LFS_ERR_NOENT) { - // xor together to find resulting gstate - lfs_gstate_fromle32(&temp); - lfs_gstate_xor(gstate, &temp); - } - - return 0; -} - -static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir, - uint16_t id, struct lfs_info *info) { - if (id == 0x3ff) { - // special case for root - strcpy(info->name, "/"); - info->type = LFS_TYPE_DIR; - return 0; - } - - lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name); - if (tag < 0) { - return (int)tag; - } - - info->type = lfs_tag_type3(tag); - - struct lfs_ctz ctz; - tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz); - if (tag < 0) { - return (int)tag; - } - lfs_ctz_fromle32(&ctz); - - if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) { - info->size = ctz.size; - } else if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) { - info->size = lfs_tag_size(tag); - } - - return 0; -} - -struct lfs_dir_find_match { - lfs_t *lfs; - const void *name; - lfs_size_t size; -}; - -static int lfs_dir_find_match(void *data, - lfs_tag_t tag, const void *buffer) { - struct lfs_dir_find_match *name = data; - lfs_t *lfs = name->lfs; - const struct lfs_diskoff *disk = buffer; - - // compare with disk - lfs_size_t diff = lfs_min(name->size, lfs_tag_size(tag)); - int res = lfs_bd_cmp(lfs, - NULL, &lfs->rcache, diff, - disk->block, disk->off, name->name, diff); - if (res != LFS_CMP_EQ) { - return res; - } - - // only equal if our size is still the same - if (name->size != lfs_tag_size(tag)) { - return (name->size < lfs_tag_size(tag)) ? LFS_CMP_LT : LFS_CMP_GT; - } - - // found a match! - return LFS_CMP_EQ; -} - -static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, - const char **path, uint16_t *id) { - // we reduce path to a single name if we can find it - const char *name = *path; - if (id) { - *id = 0x3ff; - } - - // default to root dir - lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0); - dir->tail[0] = lfs->root[0]; - dir->tail[1] = lfs->root[1]; - - while (true) { -nextname: - // skip slashes - name += strspn(name, "/"); - lfs_size_t namelen = strcspn(name, "/"); - - // skip '.' and root '..' - if ((namelen == 1 && memcmp(name, ".", 1) == 0) || - (namelen == 2 && memcmp(name, "..", 2) == 0)) { - name += namelen; - goto nextname; - } - - // skip if matched by '..' in name - const char *suffix = name + namelen; - lfs_size_t sufflen; - int depth = 1; - while (true) { - suffix += strspn(suffix, "/"); - sufflen = strcspn(suffix, "/"); - if (sufflen == 0) { - break; - } - - if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { - depth -= 1; - if (depth == 0) { - name = suffix + sufflen; - goto nextname; - } - } else { - depth += 1; - } - - suffix += sufflen; - } - - // found path - if (name[0] == '\0') { - return tag; - } - - // update what we've found so far - *path = name; - - // only continue if we hit a directory - if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { - return LFS_ERR_NOTDIR; - } - - // grab the entry data - if (lfs_tag_id(tag) != 0x3ff) { - lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), dir->tail); - if (res < 0) { - return res; - } - lfs_pair_fromle32(dir->tail); - } - - // find entry matching name - while (true) { - tag = lfs_dir_fetchmatch(lfs, dir, dir->tail, - LFS_MKTAG(0x780, 0, 0), - LFS_MKTAG(LFS_TYPE_NAME, 0, namelen), - // are we last name? - (strchr(name, '/') == NULL) ? id : NULL, - lfs_dir_find_match, &(struct lfs_dir_find_match){ - lfs, name, namelen}); - if (tag < 0) { - return tag; - } - - if (tag) { - break; - } - - if (!dir->split) { - return LFS_ERR_NOENT; - } - } - - // to next name - name += namelen; - } -} - -// commit logic -struct lfs_commit { - lfs_block_t block; - lfs_off_t off; - lfs_tag_t ptag; - uint32_t crc; - - lfs_off_t begin; - lfs_off_t end; -}; - -static int lfs_dir_commitprog(lfs_t *lfs, struct lfs_commit *commit, - const void *buffer, lfs_size_t size) { - int err = lfs_bd_prog(lfs, - &lfs->pcache, &lfs->rcache, false, - commit->block, commit->off , - (const uint8_t*)buffer, size); - if (err) { - return err; - } - - commit->crc = lfs_crc(commit->crc, buffer, size); - commit->off += size; - return 0; -} - -static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, - lfs_tag_t tag, const void *buffer) { - // check if we fit - lfs_size_t dsize = lfs_tag_dsize(tag); - if (commit->off + dsize > commit->end) { - return LFS_ERR_NOSPC; - } - - // write out tag - lfs_tag_t ntag = lfs_tobe32((tag & 0x7fffffff) ^ commit->ptag); - int err = lfs_dir_commitprog(lfs, commit, &ntag, sizeof(ntag)); - if (err) { - return err; - } - - if (!(tag & 0x80000000)) { - // from memory - err = lfs_dir_commitprog(lfs, commit, buffer, dsize-sizeof(tag)); - if (err) { - return err; - } - } else { - // from disk - const struct lfs_diskoff *disk = buffer; - for (lfs_off_t i = 0; i < dsize-sizeof(tag); i++) { - // rely on caching to make this efficient - uint8_t dat; - err = lfs_bd_read(lfs, - NULL, &lfs->rcache, dsize-sizeof(tag)-i, - disk->block, disk->off+i, &dat, 1); - if (err) { - return err; - } - - err = lfs_dir_commitprog(lfs, commit, &dat, 1); - if (err) { - return err; - } - } - } - - commit->ptag = tag & 0x7fffffff; - return 0; -} - -static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { - const lfs_off_t off1 = commit->off; - const uint32_t crc1 = commit->crc; - // align to program units - const lfs_off_t end = lfs_alignup(off1 + 2*sizeof(uint32_t), - lfs->cfg->prog_size); - - // create crc tags to fill up remainder of commit, note that - // padding is not crced, which lets fetches skip padding but - // makes committing a bit more complicated - while (commit->off < end) { - lfs_off_t off = commit->off + sizeof(lfs_tag_t); - lfs_off_t noff = lfs_min(end - off, 0x3fe) + off; - if (noff < end) { - noff = lfs_min(noff, end - 2*sizeof(uint32_t)); - } - - // read erased state from next program unit - lfs_tag_t tag = 0xffffffff; - int err = lfs_bd_read(lfs, - NULL, &lfs->rcache, sizeof(tag), - commit->block, noff, &tag, sizeof(tag)); - if (err && err != LFS_ERR_CORRUPT) { - return err; - } - - // build crc tag - bool reset = ~lfs_frombe32(tag) >> 31; - tag = LFS_MKTAG(LFS_TYPE_CRC + reset, 0x3ff, noff - off); - - // write out crc - uint32_t footer[2]; - footer[0] = lfs_tobe32(tag ^ commit->ptag); - commit->crc = lfs_crc(commit->crc, &footer[0], sizeof(footer[0])); - footer[1] = lfs_tole32(commit->crc); - err = lfs_bd_prog(lfs, - &lfs->pcache, &lfs->rcache, false, - commit->block, commit->off, &footer, sizeof(footer)); - if (err) { - return err; - } - - commit->off += sizeof(tag)+lfs_tag_size(tag); - commit->ptag = tag ^ ((lfs_tag_t)reset << 31); - commit->crc = 0xffffffff; // reset crc for next "commit" - } - - // flush buffers - int err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false); - if (err) { - return err; - } - - // successful commit, check checksums to make sure - lfs_off_t off = commit->begin; - lfs_off_t noff = off1 + sizeof(uint32_t); - while (off < end) { - uint32_t crc = 0xffffffff; - for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) { - // check against written crc, may catch blocks that - // become readonly and match our commit size exactly - if (i == off1 && crc != crc1) { - return LFS_ERR_CORRUPT; - } - - // leave it up to caching to make this efficient - uint8_t dat; - err = lfs_bd_read(lfs, - NULL, &lfs->rcache, noff+sizeof(uint32_t)-i, - commit->block, i, &dat, 1); - if (err) { - return err; - } - - crc = lfs_crc(crc, &dat, 1); - } - - // detected write error? - if (crc != 0) { - return LFS_ERR_CORRUPT; - } - - // skip padding - off = lfs_min(end - noff, 0x3fe) + noff; - if (off < end) { - off = lfs_min(off, end - 2*sizeof(uint32_t)); - } - noff = off + sizeof(uint32_t); - } - - return 0; -} - -static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { - // allocate pair of dir blocks (backwards, so we write block 1 first) - for (int i = 0; i < 2; i++) { - int err = lfs_alloc(lfs, &dir->pair[(i+1)%2]); - if (err) { - return err; - } - } - - // zero for reproducability in case initial block is unreadable - dir->rev = 0; - - // rather than clobbering one of the blocks we just pretend - // the revision may be valid - int err = lfs_bd_read(lfs, - NULL, &lfs->rcache, sizeof(dir->rev), - dir->pair[0], 0, &dir->rev, sizeof(dir->rev)); - dir->rev = lfs_fromle32(dir->rev); - if (err && err != LFS_ERR_CORRUPT) { - return err; - } - - // make sure we don't immediately evict - dir->rev += dir->rev & 1; - - // set defaults - dir->off = sizeof(dir->rev); - dir->etag = 0xffffffff; - dir->count = 0; - dir->tail[0] = LFS_BLOCK_NULL; - dir->tail[1] = LFS_BLOCK_NULL; - dir->erased = false; - dir->split = false; - - // don't write out yet, let caller take care of that - return 0; -} - -static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) { - // steal state - int err = lfs_dir_getgstate(lfs, tail, &lfs->gdelta); - if (err) { - return err; - } - - // steal tail - lfs_pair_tole32(tail->tail); - err = lfs_dir_commit(lfs, dir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_TAIL + tail->split, 0x3ff, 8), tail->tail})); - lfs_pair_fromle32(tail->tail); - if (err) { - return err; - } - - return 0; -} - -static int lfs_dir_split(lfs_t *lfs, - lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, - lfs_mdir_t *source, uint16_t split, uint16_t end) { - // create tail directory - lfs_alloc_ack(lfs); - lfs_mdir_t tail; - int err = lfs_dir_alloc(lfs, &tail); - if (err) { - return err; - } - - tail.split = dir->split; - tail.tail[0] = dir->tail[0]; - tail.tail[1] = dir->tail[1]; - - err = lfs_dir_compact(lfs, &tail, attrs, attrcount, source, split, end); - if (err) { - return err; - } - - dir->tail[0] = tail.pair[0]; - dir->tail[1] = tail.pair[1]; - dir->split = true; - - // update root if needed - if (lfs_pair_cmp(dir->pair, lfs->root) == 0 && split == 0) { - lfs->root[0] = tail.pair[0]; - lfs->root[1] = tail.pair[1]; - } - - return 0; -} - -static int lfs_dir_commit_size(void *p, lfs_tag_t tag, const void *buffer) { - lfs_size_t *size = p; - (void)buffer; - - *size += lfs_tag_dsize(tag); - return 0; -} - -struct lfs_dir_commit_commit { - lfs_t *lfs; - struct lfs_commit *commit; -}; - -static int lfs_dir_commit_commit(void *p, lfs_tag_t tag, const void *buffer) { - struct lfs_dir_commit_commit *commit = p; - return lfs_dir_commitattr(commit->lfs, commit->commit, tag, buffer); -} - -static int lfs_dir_compact(lfs_t *lfs, - lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, - lfs_mdir_t *source, uint16_t begin, uint16_t end) { - // save some state in case block is bad - const lfs_block_t oldpair[2] = {dir->pair[0], dir->pair[1]}; - bool relocated = false; - bool tired = false; - - // should we split? - while (end - begin > 1) { - // find size - lfs_size_t size = 0; - int err = lfs_dir_traverse(lfs, - source, 0, 0xffffffff, attrs, attrcount, - LFS_MKTAG(0x400, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_NAME, 0, 0), - begin, end, -begin, - lfs_dir_commit_size, &size); - if (err) { - return err; - } - - // space is complicated, we need room for tail, crc, gstate, - // cleanup delete, and we cap at half a block to give room - // for metadata updates. - if (end - begin < 0xff && - size <= lfs_min(lfs->cfg->block_size - 36, - lfs_alignup(lfs->cfg->block_size/2, - lfs->cfg->prog_size))) { - break; - } - - // can't fit, need to split, we should really be finding the - // largest size that fits with a small binary search, but right now - // it's not worth the code size - uint16_t split = (end - begin) / 2; - err = lfs_dir_split(lfs, dir, attrs, attrcount, - source, begin+split, end); - if (err) { - // if we fail to split, we may be able to overcompact, unless - // we're too big for even the full block, in which case our - // only option is to error - if (err == LFS_ERR_NOSPC && size <= lfs->cfg->block_size - 36) { - break; - } - return err; - } - - end = begin + split; - } - - // increment revision count - dir->rev += 1; - // If our revision count == n * block_cycles, we should force a relocation, - // this is how littlefs wear-levels at the metadata-pair level. Note that we - // actually use (block_cycles+1)|1, this is to avoid two corner cases: - // 1. block_cycles = 1, which would prevent relocations from terminating - // 2. block_cycles = 2n, which, due to aliasing, would only ever relocate - // one metadata block in the pair, effectively making this useless - if (lfs->cfg->block_cycles > 0 && - (dir->rev % ((lfs->cfg->block_cycles+1)|1) == 0)) { - if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { - // oh no! we're writing too much to the superblock, - // should we expand? - lfs_ssize_t res = lfs_fs_size(lfs); - if (res < 0) { - return res; - } - - // do we have extra space? littlefs can't reclaim this space - // by itself, so expand cautiously - if ((lfs_size_t)res < lfs->cfg->block_count/2) { - LFS_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev); - int err = lfs_dir_split(lfs, dir, attrs, attrcount, - source, begin, end); - if (err && err != LFS_ERR_NOSPC) { - return err; - } - - // welp, we tried, if we ran out of space there's not much - // we can do, we'll error later if we've become frozen - if (!err) { - end = begin; - } - } -#ifdef LFS_MIGRATE - } else if (lfs->lfs1) { - // do not proactively relocate blocks during migrations, this - // can cause a number of failure states such: clobbering the - // v1 superblock if we relocate root, and invalidating directory - // pointers if we relocate the head of a directory. On top of - // this, relocations increase the overall complexity of - // lfs_migration, which is already a delicate operation. -#endif - } else { - // we're writing too much, time to relocate - tired = true; - goto relocate; - } - } - - // begin loop to commit compaction to blocks until a compact sticks - while (true) { - { - // setup commit state - struct lfs_commit commit = { - .block = dir->pair[1], - .off = 0, - .ptag = 0xffffffff, - .crc = 0xffffffff, - - .begin = 0, - .end = lfs->cfg->block_size - 8, - }; - - // erase block to write to - int err = lfs_bd_erase(lfs, dir->pair[1]); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - // write out header - dir->rev = lfs_tole32(dir->rev); - err = lfs_dir_commitprog(lfs, &commit, - &dir->rev, sizeof(dir->rev)); - dir->rev = lfs_fromle32(dir->rev); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - // traverse the directory, this time writing out all unique tags - err = lfs_dir_traverse(lfs, - source, 0, 0xffffffff, attrs, attrcount, - LFS_MKTAG(0x400, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_NAME, 0, 0), - begin, end, -begin, - lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){ - lfs, &commit}); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - // commit tail, which may be new after last size check - if (!lfs_pair_isnull(dir->tail)) { - lfs_pair_tole32(dir->tail); - err = lfs_dir_commitattr(lfs, &commit, - LFS_MKTAG(LFS_TYPE_TAIL + dir->split, 0x3ff, 8), - dir->tail); - lfs_pair_fromle32(dir->tail); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - } - - // bring over gstate? - lfs_gstate_t delta = {0}; - if (!relocated) { - lfs_gstate_xor(&delta, &lfs->gdisk); - lfs_gstate_xor(&delta, &lfs->gstate); - } - lfs_gstate_xor(&delta, &lfs->gdelta); - delta.tag &= ~LFS_MKTAG(0, 0, 0x3ff); - - err = lfs_dir_getgstate(lfs, dir, &delta); - if (err) { - return err; - } - - if (!lfs_gstate_iszero(&delta)) { - lfs_gstate_tole32(&delta); - err = lfs_dir_commitattr(lfs, &commit, - LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff, - sizeof(delta)), &delta); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - } - - // complete commit with crc - err = lfs_dir_commitcrc(lfs, &commit); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - // successful compaction, swap dir pair to indicate most recent - LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); - lfs_pair_swap(dir->pair); - dir->count = end - begin; - dir->off = commit.off; - dir->etag = commit.ptag; - // update gstate - lfs->gdelta = (lfs_gstate_t){0}; - if (!relocated) { - lfs->gdisk = lfs->gstate; - } - } - break; - -relocate: - // commit was corrupted, drop caches and prepare to relocate block - relocated = true; - lfs_cache_drop(lfs, &lfs->pcache); - if (!tired) { - LFS_DEBUG("Bad block at 0x%"PRIx32, dir->pair[1]); - } - - // can't relocate superblock, filesystem is now frozen - if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { - LFS_WARN("Superblock 0x%"PRIx32" has become unwritable", - dir->pair[1]); - return LFS_ERR_NOSPC; - } - - // relocate half of pair - int err = lfs_alloc(lfs, &dir->pair[1]); - if (err && (err != LFS_ERR_NOSPC || !tired)) { - return err; - } - - tired = false; - continue; - } - - if (relocated) { - // update references if we relocated - LFS_DEBUG("Relocating {0x%"PRIx32", 0x%"PRIx32"} " - "-> {0x%"PRIx32", 0x%"PRIx32"}", - oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); - int err = lfs_fs_relocate(lfs, oldpair, dir->pair); - if (err) { - return err; - } - } - - return 0; -} - -static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, - const struct lfs_mattr *attrs, int attrcount) { - // check for any inline files that aren't RAM backed and - // forcefully evict them, needed for filesystem consistency - for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { - if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 && - f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) && - f->ctz.size > lfs->cfg->cache_size) { - int err = lfs_file_outline(lfs, f); - if (err) { - return err; - } - - err = lfs_file_flush(lfs, f); - if (err) { - return err; - } - } - } - - // calculate changes to the directory - lfs_mdir_t olddir = *dir; - bool hasdelete = false; - for (int i = 0; i < attrcount; i++) { - if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE) { - dir->count += 1; - } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE) { - LFS_ASSERT(dir->count > 0); - dir->count -= 1; - hasdelete = true; - } else if (lfs_tag_type1(attrs[i].tag) == LFS_TYPE_TAIL) { - dir->tail[0] = ((lfs_block_t*)attrs[i].buffer)[0]; - dir->tail[1] = ((lfs_block_t*)attrs[i].buffer)[1]; - dir->split = (lfs_tag_chunk(attrs[i].tag) & 1); - lfs_pair_fromle32(dir->tail); - } - } - - // should we actually drop the directory block? - if (hasdelete && dir->count == 0) { - lfs_mdir_t pdir; - int err = lfs_fs_pred(lfs, dir->pair, &pdir); - if (err && err != LFS_ERR_NOENT) { - *dir = olddir; - return err; - } - - if (err != LFS_ERR_NOENT && pdir.split) { - err = lfs_dir_drop(lfs, &pdir, dir); - if (err) { - *dir = olddir; - return err; - } - } - } - - if (dir->erased || dir->count >= 0xff) { - // try to commit - struct lfs_commit commit = { - .block = dir->pair[0], - .off = dir->off, - .ptag = dir->etag, - .crc = 0xffffffff, - - .begin = dir->off, - .end = lfs->cfg->block_size - 8, - }; - - // traverse attrs that need to be written out - lfs_pair_tole32(dir->tail); - int err = lfs_dir_traverse(lfs, - dir, dir->off, dir->etag, attrs, attrcount, - 0, 0, 0, 0, 0, - lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){ - lfs, &commit}); - lfs_pair_fromle32(dir->tail); - if (err) { - if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { - goto compact; - } - *dir = olddir; - return err; - } - - // commit any global diffs if we have any - lfs_gstate_t delta = {0}; - lfs_gstate_xor(&delta, &lfs->gstate); - lfs_gstate_xor(&delta, &lfs->gdisk); - lfs_gstate_xor(&delta, &lfs->gdelta); - delta.tag &= ~LFS_MKTAG(0, 0, 0x3ff); - if (!lfs_gstate_iszero(&delta)) { - err = lfs_dir_getgstate(lfs, dir, &delta); - if (err) { - *dir = olddir; - return err; - } - - lfs_gstate_tole32(&delta); - err = lfs_dir_commitattr(lfs, &commit, - LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff, - sizeof(delta)), &delta); - if (err) { - if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { - goto compact; - } - *dir = olddir; - return err; - } - } - - // finalize commit with the crc - err = lfs_dir_commitcrc(lfs, &commit); - if (err) { - if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { - goto compact; - } - *dir = olddir; - return err; - } - - // successful commit, update dir - LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); - dir->off = commit.off; - dir->etag = commit.ptag; - // and update gstate - lfs->gdisk = lfs->gstate; - lfs->gdelta = (lfs_gstate_t){0}; - } else { -compact: - // fall back to compaction - lfs_cache_drop(lfs, &lfs->pcache); - - int err = lfs_dir_compact(lfs, dir, attrs, attrcount, - dir, 0, dir->count); - if (err) { - *dir = olddir; - return err; - } - } - - // this complicated bit of logic is for fixing up any active - // metadata-pairs that we may have affected - // - // note we have to make two passes since the mdir passed to - // lfs_dir_commit could also be in this list, and even then - // we need to copy the pair so they don't get clobbered if we refetch - // our mdir. - for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { - if (&d->m != dir && lfs_pair_cmp(d->m.pair, olddir.pair) == 0) { - d->m = *dir; - for (int i = 0; i < attrcount; i++) { - if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE && - d->id == lfs_tag_id(attrs[i].tag)) { - d->m.pair[0] = LFS_BLOCK_NULL; - d->m.pair[1] = LFS_BLOCK_NULL; - } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE && - d->id > lfs_tag_id(attrs[i].tag)) { - d->id -= 1; - if (d->type == LFS_TYPE_DIR) { - ((lfs_dir_t*)d)->pos -= 1; - } - } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE && - d->id >= lfs_tag_id(attrs[i].tag)) { - d->id += 1; - if (d->type == LFS_TYPE_DIR) { - ((lfs_dir_t*)d)->pos += 1; - } - } - } - } - } - - for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { - if (lfs_pair_cmp(d->m.pair, olddir.pair) == 0) { - while (d->id >= d->m.count && d->m.split) { - // we split and id is on tail now - d->id -= d->m.count; - int err = lfs_dir_fetch(lfs, &d->m, d->m.tail); - if (err) { - return err; - } - } - } - } - - return 0; -} - - -/// Top level directory operations /// -int lfs_mkdir(lfs_t *lfs, const char *path) { - LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path); - // deorphan if we haven't yet, needed at most once after poweron - int err = lfs_fs_forceconsistency(lfs); - if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); - return err; - } - - struct lfs_mlist cwd; - cwd.next = lfs->mlist; - uint16_t id; - err = lfs_dir_find(lfs, &cwd.m, &path, &id); - if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { - LFS_TRACE("lfs_mkdir -> %d", (err < 0) ? err : LFS_ERR_EXIST); - return (err < 0) ? err : LFS_ERR_EXIST; - } - - // check that name fits - lfs_size_t nlen = strlen(path); - if (nlen > lfs->name_max) { - LFS_TRACE("lfs_mkdir -> %d", LFS_ERR_NAMETOOLONG); - return LFS_ERR_NAMETOOLONG; - } - - // build up new directory - lfs_alloc_ack(lfs); - lfs_mdir_t dir; - err = lfs_dir_alloc(lfs, &dir); - if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); - return err; - } - - // find end of list - lfs_mdir_t pred = cwd.m; - while (pred.split) { - err = lfs_dir_fetch(lfs, &pred, pred.tail); - if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); - return err; - } - } - - // setup dir - lfs_pair_tole32(pred.tail); - err = lfs_dir_commit(lfs, &dir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail})); - lfs_pair_fromle32(pred.tail); - if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); - return err; - } - - // current block end of list? - if (cwd.m.split) { - // update tails, this creates a desync - lfs_fs_preporphans(lfs, +1); - - // it's possible our predecessor has to be relocated, and if - // our parent is our predecessor's predecessor, this could have - // caused our parent to go out of date, fortunately we can hook - // ourselves into littlefs to catch this - cwd.type = 0; - cwd.id = 0; - lfs->mlist = &cwd; - - lfs_pair_tole32(dir.pair); - err = lfs_dir_commit(lfs, &pred, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); - lfs_pair_fromle32(dir.pair); - if (err) { - lfs->mlist = cwd.next; - LFS_TRACE("lfs_mkdir -> %d", err); - return err; - } - - lfs->mlist = cwd.next; - lfs_fs_preporphans(lfs, -1); - } - - // now insert into our parent block - lfs_pair_tole32(dir.pair); - err = lfs_dir_commit(lfs, &cwd.m, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_CREATE, id, 0), NULL}, - {LFS_MKTAG(LFS_TYPE_DIR, id, nlen), path}, - {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, id, 8), dir.pair}, - {LFS_MKTAG_IF(!cwd.m.split, - LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); - lfs_pair_fromle32(dir.pair); - if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); - return err; - } - - LFS_TRACE("lfs_mkdir -> %d", 0); - return 0; -} - -int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { - LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path); - lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL); - if (tag < 0) { - LFS_TRACE("lfs_dir_open -> %"PRId32, tag); - return tag; - } - - if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { - LFS_TRACE("lfs_dir_open -> %d", LFS_ERR_NOTDIR); - return LFS_ERR_NOTDIR; - } - - lfs_block_t pair[2]; - if (lfs_tag_id(tag) == 0x3ff) { - // handle root dir separately - pair[0] = lfs->root[0]; - pair[1] = lfs->root[1]; - } else { - // get dir pair from parent - lfs_stag_t res = lfs_dir_get(lfs, &dir->m, LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair); - if (res < 0) { - LFS_TRACE("lfs_dir_open -> %"PRId32, res); - return res; - } - lfs_pair_fromle32(pair); - } - - // fetch first pair - int err = lfs_dir_fetch(lfs, &dir->m, pair); - if (err) { - LFS_TRACE("lfs_dir_open -> %d", err); - return err; - } - - // setup entry - dir->head[0] = dir->m.pair[0]; - dir->head[1] = dir->m.pair[1]; - dir->id = 0; - dir->pos = 0; - - // add to list of mdirs - dir->type = LFS_TYPE_DIR; - dir->next = (lfs_dir_t*)lfs->mlist; - lfs->mlist = (struct lfs_mlist*)dir; - - LFS_TRACE("lfs_dir_open -> %d", 0); - return 0; -} - -int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir); - // remove from list of mdirs - for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { - if (*p == (struct lfs_mlist*)dir) { - *p = (*p)->next; - break; - } - } - - LFS_TRACE("lfs_dir_close -> %d", 0); - return 0; -} - -int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { - LFS_TRACE("lfs_dir_read(%p, %p, %p)", - (void*)lfs, (void*)dir, (void*)info); - memset(info, 0, sizeof(*info)); - - // special offset for '.' and '..' - if (dir->pos == 0) { - info->type = LFS_TYPE_DIR; - strcpy(info->name, "."); - dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); - return true; - } else if (dir->pos == 1) { - info->type = LFS_TYPE_DIR; - strcpy(info->name, ".."); - dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); - return true; - } - - while (true) { - if (dir->id == dir->m.count) { - if (!dir->m.split) { - LFS_TRACE("lfs_dir_read -> %d", false); - return false; - } - - int err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); - if (err) { - LFS_TRACE("lfs_dir_read -> %d", err); - return err; - } - - dir->id = 0; - } - - int err = lfs_dir_getinfo(lfs, &dir->m, dir->id, info); - if (err && err != LFS_ERR_NOENT) { - LFS_TRACE("lfs_dir_read -> %d", err); - return err; - } - - dir->id += 1; - if (err != LFS_ERR_NOENT) { - break; - } - } - - dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); - return true; -} - -int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { - LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")", - (void*)lfs, (void*)dir, off); - // simply walk from head dir - int err = lfs_dir_rewind(lfs, dir); - if (err) { - LFS_TRACE("lfs_dir_seek -> %d", err); - return err; - } - - // first two for ./.. - dir->pos = lfs_min(2, off); - off -= dir->pos; - - // skip superblock entry - dir->id = (off > 0 && lfs_pair_cmp(dir->head, lfs->root) == 0); - - while (off > 0) { - int diff = lfs_min(dir->m.count - dir->id, off); - dir->id += diff; - dir->pos += diff; - off -= diff; - - if (dir->id == dir->m.count) { - if (!dir->m.split) { - LFS_TRACE("lfs_dir_seek -> %d", LFS_ERR_INVAL); - return LFS_ERR_INVAL; - } - - err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); - if (err) { - LFS_TRACE("lfs_dir_seek -> %d", err); - return err; - } - - dir->id = 0; - } - } - - LFS_TRACE("lfs_dir_seek -> %d", 0); - return 0; -} - -lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir); - (void)lfs; - LFS_TRACE("lfs_dir_tell -> %"PRId32, dir->pos); - return dir->pos; -} - -int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir); - // reload the head dir - int err = lfs_dir_fetch(lfs, &dir->m, dir->head); - if (err) { - LFS_TRACE("lfs_dir_rewind -> %d", err); - return err; - } - - dir->id = 0; - dir->pos = 0; - LFS_TRACE("lfs_dir_rewind -> %d", 0); - return 0; -} - - -/// File index list operations /// -static int lfs_ctz_index(lfs_t *lfs, lfs_off_t *off) { - lfs_off_t size = *off; - lfs_off_t b = lfs->cfg->block_size - 2*4; - lfs_off_t i = size / b; - if (i == 0) { - return 0; - } - - i = (size - 4*(lfs_popc(i-1)+2)) / b; - *off = size - b*i - 4*lfs_popc(i); - return i; -} - -static int lfs_ctz_find(lfs_t *lfs, - const lfs_cache_t *pcache, lfs_cache_t *rcache, - lfs_block_t head, lfs_size_t size, - lfs_size_t pos, lfs_block_t *block, lfs_off_t *off) { - if (size == 0) { - *block = LFS_BLOCK_NULL; - *off = 0; - return 0; - } - - lfs_off_t current = lfs_ctz_index(lfs, &(lfs_off_t){size-1}); - lfs_off_t target = lfs_ctz_index(lfs, &pos); - - while (current > target) { - lfs_size_t skip = lfs_min( - lfs_npw2(current-target+1) - 1, - lfs_ctz(current)); - - int err = lfs_bd_read(lfs, - pcache, rcache, sizeof(head), - head, 4*skip, &head, sizeof(head)); - head = lfs_fromle32(head); - if (err) { - return err; - } - - current -= 1 << skip; - } - - *block = head; - *off = pos; - return 0; -} - -static int lfs_ctz_extend(lfs_t *lfs, - lfs_cache_t *pcache, lfs_cache_t *rcache, - lfs_block_t head, lfs_size_t size, - lfs_block_t *block, lfs_off_t *off) { - while (true) { - // go ahead and grab a block - lfs_block_t nblock; - int err = lfs_alloc(lfs, &nblock); - if (err) { - return err; - } - - { - err = lfs_bd_erase(lfs, nblock); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - if (size == 0) { - *block = nblock; - *off = 0; - return 0; - } - - lfs_size_t noff = size - 1; - lfs_off_t index = lfs_ctz_index(lfs, &noff); - noff = noff + 1; - - // just copy out the last block if it is incomplete - if (noff != lfs->cfg->block_size) { - for (lfs_off_t i = 0; i < noff; i++) { - uint8_t data; - err = lfs_bd_read(lfs, - NULL, rcache, noff-i, - head, i, &data, 1); - if (err) { - return err; - } - - err = lfs_bd_prog(lfs, - pcache, rcache, true, - nblock, i, &data, 1); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - } - - *block = nblock; - *off = noff; - return 0; - } - - // append block - index += 1; - lfs_size_t skips = lfs_ctz(index) + 1; - lfs_block_t nhead = head; - for (lfs_off_t i = 0; i < skips; i++) { - nhead = lfs_tole32(nhead); - err = lfs_bd_prog(lfs, pcache, rcache, true, - nblock, 4*i, &nhead, 4); - nhead = lfs_fromle32(nhead); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - if (i != skips-1) { - err = lfs_bd_read(lfs, - NULL, rcache, sizeof(nhead), - nhead, 4*i, &nhead, sizeof(nhead)); - nhead = lfs_fromle32(nhead); - if (err) { - return err; - } - } - } - - *block = nblock; - *off = 4*skips; - return 0; - } - -relocate: - LFS_DEBUG("Bad block at 0x%"PRIx32, nblock); - - // just clear cache and try a new block - lfs_cache_drop(lfs, pcache); - } -} - -static int lfs_ctz_traverse(lfs_t *lfs, - const lfs_cache_t *pcache, lfs_cache_t *rcache, - lfs_block_t head, lfs_size_t size, - int (*cb)(void*, lfs_block_t), void *data) { - if (size == 0) { - return 0; - } - - lfs_off_t index = lfs_ctz_index(lfs, &(lfs_off_t){size-1}); - - while (true) { - int err = cb(data, head); - if (err) { - return err; - } - - if (index == 0) { - return 0; - } - - lfs_block_t heads[2]; - int count = 2 - (index & 1); - err = lfs_bd_read(lfs, - pcache, rcache, count*sizeof(head), - head, 0, &heads, count*sizeof(head)); - heads[0] = lfs_fromle32(heads[0]); - heads[1] = lfs_fromle32(heads[1]); - if (err) { - return err; - } - - for (int i = 0; i < count-1; i++) { - err = cb(data, heads[i]); - if (err) { - return err; - } - } - - head = heads[count-1]; - index -= count; - } -} - - -/// Top level file operations /// -int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, - const char *path, int flags, - const struct lfs_file_config *cfg) { - LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {" - ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", - (void*)lfs, (void*)file, path, flags, - (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); - - // deorphan if we haven't yet, needed at most once after poweron - if ((flags & 3) != LFS_O_RDONLY) { - int err = lfs_fs_forceconsistency(lfs); - if (err) { - LFS_TRACE("lfs_file_opencfg -> %d", err); - return err; - } - } - - // setup simple file details - int err; - file->cfg = cfg; - file->flags = flags | LFS_F_OPENED; - file->pos = 0; - file->off = 0; - file->cache.buffer = NULL; - - // allocate entry for file if it doesn't exist - lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id); - if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) { - err = tag; - goto cleanup; - } - - // get id, add to list of mdirs to catch update changes - file->type = LFS_TYPE_REG; - file->next = (lfs_file_t*)lfs->mlist; - lfs->mlist = (struct lfs_mlist*)file; - - if (tag == LFS_ERR_NOENT) { - if (!(flags & LFS_O_CREAT)) { - err = LFS_ERR_NOENT; - goto cleanup; - } - - // check that name fits - lfs_size_t nlen = strlen(path); - if (nlen > lfs->name_max) { - err = LFS_ERR_NAMETOOLONG; - goto cleanup; - } - - // get next slot and create entry to remember name - err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0), NULL}, - {LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path}, - {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL})); - if (err) { - err = LFS_ERR_NAMETOOLONG; - goto cleanup; - } - - tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0); - } else if (flags & LFS_O_EXCL) { - err = LFS_ERR_EXIST; - goto cleanup; - } else if (lfs_tag_type3(tag) != LFS_TYPE_REG) { - err = LFS_ERR_ISDIR; - goto cleanup; - } else if (flags & LFS_O_TRUNC) { - // truncate if requested - tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0); - file->flags |= LFS_F_DIRTY; - } else { - // try to load what's on disk, if it's inlined we'll fix it later - tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz); - if (tag < 0) { - err = tag; - goto cleanup; - } - lfs_ctz_fromle32(&file->ctz); - } - - // fetch attrs - for (unsigned i = 0; i < file->cfg->attr_count; i++) { - if ((file->flags & 3) != LFS_O_WRONLY) { - lfs_stag_t res = lfs_dir_get(lfs, &file->m, - LFS_MKTAG(0x7ff, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type, - file->id, file->cfg->attrs[i].size), - file->cfg->attrs[i].buffer); - if (res < 0 && res != LFS_ERR_NOENT) { - err = res; - goto cleanup; - } - } - - if ((file->flags & 3) != LFS_O_RDONLY) { - if (file->cfg->attrs[i].size > lfs->attr_max) { - err = LFS_ERR_NOSPC; - goto cleanup; - } - - file->flags |= LFS_F_DIRTY; - } - } - - // allocate buffer if needed - if (file->cfg->buffer) { - file->cache.buffer = file->cfg->buffer; - } else { - file->cache.buffer = lfs_malloc(lfs->cfg->cache_size); - if (!file->cache.buffer) { - err = LFS_ERR_NOMEM; - goto cleanup; - } - } - - // zero to avoid information leak - lfs_cache_zero(lfs, &file->cache); - - if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) { - // load inline files - file->ctz.head = LFS_BLOCK_INLINE; - file->ctz.size = lfs_tag_size(tag); - file->flags |= LFS_F_INLINE; - file->cache.block = file->ctz.head; - file->cache.off = 0; - file->cache.size = lfs->cfg->cache_size; - - // don't always read (may be new/trunc file) - if (file->ctz.size > 0) { - lfs_stag_t res = lfs_dir_get(lfs, &file->m, - LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, file->id, - lfs_min(file->cache.size, 0x3fe)), - file->cache.buffer); - if (res < 0) { - err = res; - goto cleanup; - } - } - } - - LFS_TRACE("lfs_file_opencfg -> %d", 0); - return 0; - -cleanup: - // clean up lingering resources - file->flags |= LFS_F_ERRED; - lfs_file_close(lfs, file); - LFS_TRACE("lfs_file_opencfg -> %d", err); - return err; -} - -int lfs_file_open(lfs_t *lfs, lfs_file_t *file, - const char *path, int flags) { - LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)", - (void*)lfs, (void*)file, path, flags); - static const struct lfs_file_config defaults = {0}; - int err = lfs_file_opencfg(lfs, file, path, flags, &defaults); - LFS_TRACE("lfs_file_open -> %d", err); - return err; -} - -int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); - - int err = lfs_file_sync(lfs, file); - - // remove from list of mdirs - for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { - if (*p == (struct lfs_mlist*)file) { - *p = (*p)->next; - break; - } - } - - // clean up memory - if (!file->cfg->buffer) { - lfs_free(file->cache.buffer); - } - - file->flags &= ~LFS_F_OPENED; - LFS_TRACE("lfs_file_close -> %d", err); - return err; -} - -static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { - LFS_ASSERT(file->flags & LFS_F_OPENED); - - while (true) { - // just relocate what exists into new block - lfs_block_t nblock; - int err = lfs_alloc(lfs, &nblock); - if (err) { - return err; - } - - err = lfs_bd_erase(lfs, nblock); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - // either read from dirty cache or disk - for (lfs_off_t i = 0; i < file->off; i++) { - uint8_t data; - if (file->flags & LFS_F_INLINE) { - err = lfs_dir_getread(lfs, &file->m, - // note we evict inline files before they can be dirty - NULL, &file->cache, file->off-i, - LFS_MKTAG(0xfff, 0x1ff, 0), - LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), - i, &data, 1); - if (err) { - return err; - } - } else { - err = lfs_bd_read(lfs, - &file->cache, &lfs->rcache, file->off-i, - file->block, i, &data, 1); - if (err) { - return err; - } - } - - err = lfs_bd_prog(lfs, - &lfs->pcache, &lfs->rcache, true, - nblock, i, &data, 1); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - } - - // copy over new state of file - memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->cache_size); - file->cache.block = lfs->pcache.block; - file->cache.off = lfs->pcache.off; - file->cache.size = lfs->pcache.size; - lfs_cache_zero(lfs, &lfs->pcache); - - file->block = nblock; - file->flags |= LFS_F_WRITING; - return 0; - -relocate: - LFS_DEBUG("Bad block at 0x%"PRIx32, nblock); - - // just clear cache and try a new block - lfs_cache_drop(lfs, &lfs->pcache); - } -} - -static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { - file->off = file->pos; - lfs_alloc_ack(lfs); - int err = lfs_file_relocate(lfs, file); - if (err) { - return err; - } - - file->flags &= ~LFS_F_INLINE; - return 0; -} - -static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { - LFS_ASSERT(file->flags & LFS_F_OPENED); - - if (file->flags & LFS_F_READING) { - if (!(file->flags & LFS_F_INLINE)) { - lfs_cache_drop(lfs, &file->cache); - } - file->flags &= ~LFS_F_READING; - } - - if (file->flags & LFS_F_WRITING) { - lfs_off_t pos = file->pos; - - if (!(file->flags & LFS_F_INLINE)) { - // copy over anything after current branch - lfs_file_t orig = { - .ctz.head = file->ctz.head, - .ctz.size = file->ctz.size, - .flags = LFS_O_RDONLY | LFS_F_OPENED, - .pos = file->pos, - .cache = lfs->rcache, - }; - lfs_cache_drop(lfs, &lfs->rcache); - - while (file->pos < file->ctz.size) { - // copy over a byte at a time, leave it up to caching - // to make this efficient - uint8_t data; - lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1); - if (res < 0) { - return res; - } - - res = lfs_file_write(lfs, file, &data, 1); - if (res < 0) { - return res; - } - - // keep our reference to the rcache in sync - if (lfs->rcache.block != LFS_BLOCK_NULL) { - lfs_cache_drop(lfs, &orig.cache); - lfs_cache_drop(lfs, &lfs->rcache); - } - } - - // write out what we have - while (true) { - int err = lfs_bd_flush(lfs, &file->cache, &lfs->rcache, true); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - return err; - } - - break; - -relocate: - LFS_DEBUG("Bad block at 0x%"PRIx32, file->block); - err = lfs_file_relocate(lfs, file); - if (err) { - return err; - } - } - } else { - file->pos = lfs_max(file->pos, file->ctz.size); - } - - // actual file updates - file->ctz.head = file->block; - file->ctz.size = file->pos; - file->flags &= ~LFS_F_WRITING; - file->flags |= LFS_F_DIRTY; - - file->pos = pos; - } - - return 0; -} - -int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); - - if (file->flags & LFS_F_ERRED) { - // it's not safe to do anything if our file errored - LFS_TRACE("lfs_file_sync -> %d", 0); - return 0; - } - - int err = lfs_file_flush(lfs, file); - if (err) { - file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_sync -> %d", err); - return err; - } - - if ((file->flags & LFS_F_DIRTY) && - !lfs_pair_isnull(file->m.pair)) { - // update dir entry - uint16_t type; - const void *buffer; - lfs_size_t size; - struct lfs_ctz ctz; - if (file->flags & LFS_F_INLINE) { - // inline the whole file - type = LFS_TYPE_INLINESTRUCT; - buffer = file->cache.buffer; - size = file->ctz.size; - } else { - // update the ctz reference - type = LFS_TYPE_CTZSTRUCT; - // copy ctz so alloc will work during a relocate - ctz = file->ctz; - lfs_ctz_tole32(&ctz); - buffer = &ctz; - size = sizeof(ctz); - } - - // commit file data and attributes - err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( - {LFS_MKTAG(type, file->id, size), buffer}, - {LFS_MKTAG(LFS_FROM_USERATTRS, file->id, - file->cfg->attr_count), file->cfg->attrs})); - if (err) { - file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_sync -> %d", err); - return err; - } - - file->flags &= ~LFS_F_DIRTY; - } - - LFS_TRACE("lfs_file_sync -> %d", 0); - return 0; -} - -lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, - void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", - (void*)lfs, (void*)file, buffer, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_WRONLY); - - uint8_t *data = buffer; - lfs_size_t nsize = size; - - if (file->flags & LFS_F_WRITING) { - // flush out any writes - int err = lfs_file_flush(lfs, file); - if (err) { - LFS_TRACE("lfs_file_read -> %d", err); - return err; - } - } - - if (file->pos >= file->ctz.size) { - // eof if past end - LFS_TRACE("lfs_file_read -> %d", 0); - return 0; - } - - size = lfs_min(size, file->ctz.size - file->pos); - nsize = size; - - while (nsize > 0) { - // check if we need a new block - if (!(file->flags & LFS_F_READING) || - file->off == lfs->cfg->block_size) { - if (!(file->flags & LFS_F_INLINE)) { - int err = lfs_ctz_find(lfs, NULL, &file->cache, - file->ctz.head, file->ctz.size, - file->pos, &file->block, &file->off); - if (err) { - LFS_TRACE("lfs_file_read -> %d", err); - return err; - } - } else { - file->block = LFS_BLOCK_INLINE; - file->off = file->pos; - } - - file->flags |= LFS_F_READING; - } - - // read as much as we can in current block - lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); - if (file->flags & LFS_F_INLINE) { - int err = lfs_dir_getread(lfs, &file->m, - NULL, &file->cache, lfs->cfg->block_size, - LFS_MKTAG(0xfff, 0x1ff, 0), - LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), - file->off, data, diff); - if (err) { - LFS_TRACE("lfs_file_read -> %d", err); - return err; - } - } else { - int err = lfs_bd_read(lfs, - NULL, &file->cache, lfs->cfg->block_size, - file->block, file->off, data, diff); - if (err) { - LFS_TRACE("lfs_file_read -> %d", err); - return err; - } - } - - file->pos += diff; - file->off += diff; - data += diff; - nsize -= diff; - } - - LFS_TRACE("lfs_file_read -> %"PRId32, size); - return size; -} - -lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, - const void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", - (void*)lfs, (void*)file, buffer, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); - - const uint8_t *data = buffer; - lfs_size_t nsize = size; - - if (file->flags & LFS_F_READING) { - // drop any reads - int err = lfs_file_flush(lfs, file); - if (err) { - LFS_TRACE("lfs_file_write -> %d", err); - return err; - } - } - - if ((file->flags & LFS_O_APPEND) && file->pos < file->ctz.size) { - file->pos = file->ctz.size; - } - - if (file->pos + size > lfs->file_max) { - // Larger than file limit? - LFS_TRACE("lfs_file_write -> %d", LFS_ERR_FBIG); - return LFS_ERR_FBIG; - } - - if (!(file->flags & LFS_F_WRITING) && file->pos > file->ctz.size) { - // fill with zeros - lfs_off_t pos = file->pos; - file->pos = file->ctz.size; - - while (file->pos < pos) { - lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); - if (res < 0) { - LFS_TRACE("lfs_file_write -> %"PRId32, res); - return res; - } - } - } - - if ((file->flags & LFS_F_INLINE) && - lfs_max(file->pos+nsize, file->ctz.size) > - lfs_min(0x3fe, lfs_min( - lfs->cfg->cache_size, lfs->cfg->block_size/8))) { - // inline file doesn't fit anymore - int err = lfs_file_outline(lfs, file); - if (err) { - file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); - return err; - } - } - - while (nsize > 0) { - // check if we need a new block - if (!(file->flags & LFS_F_WRITING) || - file->off == lfs->cfg->block_size) { - if (!(file->flags & LFS_F_INLINE)) { - if (!(file->flags & LFS_F_WRITING) && file->pos > 0) { - // find out which block we're extending from - int err = lfs_ctz_find(lfs, NULL, &file->cache, - file->ctz.head, file->ctz.size, - file->pos-1, &file->block, &file->off); - if (err) { - file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); - return err; - } - - // mark cache as dirty since we may have read data into it - lfs_cache_zero(lfs, &file->cache); - } - - // extend file with new blocks - lfs_alloc_ack(lfs); - int err = lfs_ctz_extend(lfs, &file->cache, &lfs->rcache, - file->block, file->pos, - &file->block, &file->off); - if (err) { - file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); - return err; - } - } else { - file->block = LFS_BLOCK_INLINE; - file->off = file->pos; - } - - file->flags |= LFS_F_WRITING; - } - - // program as much as we can in current block - lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); - while (true) { - int err = lfs_bd_prog(lfs, &file->cache, &lfs->rcache, true, - file->block, file->off, data, diff); - if (err) { - if (err == LFS_ERR_CORRUPT) { - goto relocate; - } - file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); - return err; - } - - break; -relocate: - err = lfs_file_relocate(lfs, file); - if (err) { - file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); - return err; - } - } - - file->pos += diff; - file->off += diff; - data += diff; - nsize -= diff; - - lfs_alloc_ack(lfs); - } - - file->flags &= ~LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %"PRId32, size); - return size; -} - -lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, - lfs_soff_t off, int whence) { - LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", - (void*)lfs, (void*)file, off, whence); - LFS_ASSERT(file->flags & LFS_F_OPENED); - - // write out everything beforehand, may be noop if rdonly - int err = lfs_file_flush(lfs, file); - if (err) { - LFS_TRACE("lfs_file_seek -> %d", err); - return err; - } - - // find new pos - lfs_off_t npos = file->pos; - if (whence == LFS_SEEK_SET) { - npos = off; - } else if (whence == LFS_SEEK_CUR) { - npos = file->pos + off; - } else if (whence == LFS_SEEK_END) { - npos = file->ctz.size + off; - } - - if (npos > lfs->file_max) { - // file position out of range - LFS_TRACE("lfs_file_seek -> %d", LFS_ERR_INVAL); - return LFS_ERR_INVAL; - } - - // update pos - file->pos = npos; - LFS_TRACE("lfs_file_seek -> %"PRId32, npos); - return npos; -} - -int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { - LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", - (void*)lfs, (void*)file, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); - - if (size > LFS_FILE_MAX) { - LFS_TRACE("lfs_file_truncate -> %d", LFS_ERR_INVAL); - return LFS_ERR_INVAL; - } - - lfs_off_t pos = file->pos; - lfs_off_t oldsize = lfs_file_size(lfs, file); - if (size < oldsize) { - // need to flush since directly changing metadata - int err = lfs_file_flush(lfs, file); - if (err) { - LFS_TRACE("lfs_file_truncate -> %d", err); - return err; - } - - // lookup new head in ctz skip list - err = lfs_ctz_find(lfs, NULL, &file->cache, - file->ctz.head, file->ctz.size, - size, &file->block, &file->off); - if (err) { - LFS_TRACE("lfs_file_truncate -> %d", err); - return err; - } - - file->ctz.head = file->block; - file->ctz.size = size; - file->flags |= LFS_F_DIRTY | LFS_F_READING; - } else if (size > oldsize) { - // flush+seek if not already at end - if (file->pos != oldsize) { - lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_END); - if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); - return (int)res; - } - } - - // fill with zeros - while (file->pos < size) { - lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); - if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); - return (int)res; - } - } - } - - // restore pos - lfs_soff_t res = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET); - if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); - return (int)res; - } - - LFS_TRACE("lfs_file_truncate -> %d", 0); - return 0; -} - -lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); - (void)lfs; - LFS_TRACE("lfs_file_tell -> %"PRId32, file->pos); - return file->pos; -} - -int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file); - lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_SET); - if (res < 0) { - LFS_TRACE("lfs_file_rewind -> %"PRId32, res); - return (int)res; - } - - LFS_TRACE("lfs_file_rewind -> %d", 0); - return 0; -} - -lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); - (void)lfs; - if (file->flags & LFS_F_WRITING) { - LFS_TRACE("lfs_file_size -> %"PRId32, - lfs_max(file->pos, file->ctz.size)); - return lfs_max(file->pos, file->ctz.size); - } else { - LFS_TRACE("lfs_file_size -> %"PRId32, file->ctz.size); - return file->ctz.size; - } -} - - -/// General fs operations /// -int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { - LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info); - lfs_mdir_t cwd; - lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); - if (tag < 0) { - LFS_TRACE("lfs_stat -> %"PRId32, tag); - return (int)tag; - } - - int err = lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info); - LFS_TRACE("lfs_stat -> %d", err); - return err; -} - -int lfs_remove(lfs_t *lfs, const char *path) { - LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path); - // deorphan if we haven't yet, needed at most once after poweron - int err = lfs_fs_forceconsistency(lfs); - if (err) { - LFS_TRACE("lfs_remove -> %d", err); - return err; - } - - lfs_mdir_t cwd; - lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); - if (tag < 0 || lfs_tag_id(tag) == 0x3ff) { - LFS_TRACE("lfs_remove -> %"PRId32, (tag < 0) ? tag : LFS_ERR_INVAL); - return (tag < 0) ? (int)tag : LFS_ERR_INVAL; - } - - struct lfs_mlist dir; - dir.next = lfs->mlist; - if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { - // must be empty before removal - lfs_block_t pair[2]; - lfs_stag_t res = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair); - if (res < 0) { - LFS_TRACE("lfs_remove -> %"PRId32, res); - return (int)res; - } - lfs_pair_fromle32(pair); - - err = lfs_dir_fetch(lfs, &dir.m, pair); - if (err) { - LFS_TRACE("lfs_remove -> %d", err); - return err; - } - - if (dir.m.count > 0 || dir.m.split) { - LFS_TRACE("lfs_remove -> %d", LFS_ERR_NOTEMPTY); - return LFS_ERR_NOTEMPTY; - } - - // mark fs as orphaned - lfs_fs_preporphans(lfs, +1); - - // I know it's crazy but yes, dir can be changed by our parent's - // commit (if predecessor is child) - dir.type = 0; - dir.id = 0; - lfs->mlist = &dir; - } - - // delete the entry - err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(tag), 0), NULL})); - if (err) { - lfs->mlist = dir.next; - LFS_TRACE("lfs_remove -> %d", err); - return err; - } - - lfs->mlist = dir.next; - if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { - // fix orphan - lfs_fs_preporphans(lfs, -1); - - err = lfs_fs_pred(lfs, dir.m.pair, &cwd); - if (err) { - LFS_TRACE("lfs_remove -> %d", err); - return err; - } - - err = lfs_dir_drop(lfs, &cwd, &dir.m); - if (err) { - LFS_TRACE("lfs_remove -> %d", err); - return err; - } - } - - LFS_TRACE("lfs_remove -> %d", 0); - return 0; -} - -int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { - LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath); - - // deorphan if we haven't yet, needed at most once after poweron - int err = lfs_fs_forceconsistency(lfs); - if (err) { - LFS_TRACE("lfs_rename -> %d", err); - return err; - } - - // find old entry - lfs_mdir_t oldcwd; - lfs_stag_t oldtag = lfs_dir_find(lfs, &oldcwd, &oldpath, NULL); - if (oldtag < 0 || lfs_tag_id(oldtag) == 0x3ff) { - LFS_TRACE("lfs_rename -> %"PRId32, - (oldtag < 0) ? oldtag : LFS_ERR_INVAL); - return (oldtag < 0) ? (int)oldtag : LFS_ERR_INVAL; - } - - // find new entry - lfs_mdir_t newcwd; - uint16_t newid; - lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid); - if ((prevtag < 0 || lfs_tag_id(prevtag) == 0x3ff) && - !(prevtag == LFS_ERR_NOENT && newid != 0x3ff)) { - LFS_TRACE("lfs_rename -> %"PRId32, - (prevtag < 0) ? prevtag : LFS_ERR_INVAL); - return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL; - } - - // if we're in the same pair there's a few special cases... - bool samepair = (lfs_pair_cmp(oldcwd.pair, newcwd.pair) == 0); - uint16_t newoldid = lfs_tag_id(oldtag); - - struct lfs_mlist prevdir; - prevdir.next = lfs->mlist; - if (prevtag == LFS_ERR_NOENT) { - // check that name fits - lfs_size_t nlen = strlen(newpath); - if (nlen > lfs->name_max) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_NAMETOOLONG); - return LFS_ERR_NAMETOOLONG; - } - - // there is a small chance we are being renamed in the same - // directory/ to an id less than our old id, the global update - // to handle this is a bit messy - if (samepair && newid <= newoldid) { - newoldid += 1; - } - } else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_ISDIR); - return LFS_ERR_ISDIR; - } else if (samepair && newid == newoldid) { - // we're renaming to ourselves?? - LFS_TRACE("lfs_rename -> %d", 0); - return 0; - } else if (lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { - // must be empty before removal - lfs_block_t prevpair[2]; - lfs_stag_t res = lfs_dir_get(lfs, &newcwd, LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair); - if (res < 0) { - LFS_TRACE("lfs_rename -> %"PRId32, res); - return (int)res; - } - lfs_pair_fromle32(prevpair); - - // must be empty before removal - err = lfs_dir_fetch(lfs, &prevdir.m, prevpair); - if (err) { - LFS_TRACE("lfs_rename -> %d", err); - return err; - } - - if (prevdir.m.count > 0 || prevdir.m.split) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_NOTEMPTY); - return LFS_ERR_NOTEMPTY; - } - - // mark fs as orphaned - lfs_fs_preporphans(lfs, +1); - - // I know it's crazy but yes, dir can be changed by our parent's - // commit (if predecessor is child) - prevdir.type = 0; - prevdir.id = 0; - lfs->mlist = &prevdir; - } - - if (!samepair) { - lfs_fs_prepmove(lfs, newoldid, oldcwd.pair); - } - - // move over all attributes - err = lfs_dir_commit(lfs, &newcwd, LFS_MKATTRS( - {LFS_MKTAG_IF(prevtag != LFS_ERR_NOENT, - LFS_TYPE_DELETE, newid, 0), NULL}, - {LFS_MKTAG(LFS_TYPE_CREATE, newid, 0), NULL}, - {LFS_MKTAG(lfs_tag_type3(oldtag), newid, strlen(newpath)), newpath}, - {LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd}, - {LFS_MKTAG_IF(samepair, - LFS_TYPE_DELETE, newoldid, 0), NULL})); - if (err) { - lfs->mlist = prevdir.next; - LFS_TRACE("lfs_rename -> %d", err); - return err; - } - - // let commit clean up after move (if we're different! otherwise move - // logic already fixed it for us) - if (!samepair && lfs_gstate_hasmove(&lfs->gstate)) { - // prep gstate and delete move id - lfs_fs_prepmove(lfs, 0x3ff, NULL); - err = lfs_dir_commit(lfs, &oldcwd, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(oldtag), 0), NULL})); - if (err) { - lfs->mlist = prevdir.next; - LFS_TRACE("lfs_rename -> %d", err); - return err; - } - } - - lfs->mlist = prevdir.next; - if (prevtag != LFS_ERR_NOENT && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { - // fix orphan - lfs_fs_preporphans(lfs, -1); - - err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd); - if (err) { - LFS_TRACE("lfs_rename -> %d", err); - return err; - } - - err = lfs_dir_drop(lfs, &newcwd, &prevdir.m); - if (err) { - LFS_TRACE("lfs_rename -> %d", err); - return err; - } - } - - LFS_TRACE("lfs_rename -> %d", 0); - return 0; -} - -lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, - uint8_t type, void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", - (void*)lfs, path, type, buffer, size); - lfs_mdir_t cwd; - lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); - if (tag < 0) { - LFS_TRACE("lfs_getattr -> %"PRId32, tag); - return tag; - } - - uint16_t id = lfs_tag_id(tag); - if (id == 0x3ff) { - // special case for root - id = 0; - int err = lfs_dir_fetch(lfs, &cwd, lfs->root); - if (err) { - LFS_TRACE("lfs_getattr -> %d", err); - return err; - } - } - - tag = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x7ff, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_USERATTR + type, - id, lfs_min(size, lfs->attr_max)), - buffer); - if (tag < 0) { - if (tag == LFS_ERR_NOENT) { - LFS_TRACE("lfs_getattr -> %d", LFS_ERR_NOATTR); - return LFS_ERR_NOATTR; - } - - LFS_TRACE("lfs_getattr -> %"PRId32, tag); - return tag; - } - - size = lfs_tag_size(tag); - LFS_TRACE("lfs_getattr -> %"PRId32, size); - return size; -} - -static int lfs_commitattr(lfs_t *lfs, const char *path, - uint8_t type, const void *buffer, lfs_size_t size) { - lfs_mdir_t cwd; - lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); - if (tag < 0) { - return tag; - } - - uint16_t id = lfs_tag_id(tag); - if (id == 0x3ff) { - // special case for root - id = 0; - int err = lfs_dir_fetch(lfs, &cwd, lfs->root); - if (err) { - return err; - } - } - - return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer})); -} - -int lfs_setattr(lfs_t *lfs, const char *path, - uint8_t type, const void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", - (void*)lfs, path, type, buffer, size); - if (size > lfs->attr_max) { - LFS_TRACE("lfs_setattr -> %d", LFS_ERR_NOSPC); - return LFS_ERR_NOSPC; - } - - int err = lfs_commitattr(lfs, path, type, buffer, size); - LFS_TRACE("lfs_setattr -> %d", err); - return err; -} - -int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { - LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type); - int err = lfs_commitattr(lfs, path, type, NULL, 0x3ff); - LFS_TRACE("lfs_removeattr -> %d", err); - return err; -} - - -/// Filesystem operations /// -static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { - lfs->cfg = cfg; - int err = 0; - - // validate that the lfs-cfg sizes were initiated properly before - // performing any arithmetic logics with them - LFS_ASSERT(lfs->cfg->read_size != 0); - LFS_ASSERT(lfs->cfg->prog_size != 0); - LFS_ASSERT(lfs->cfg->cache_size != 0); - - // check that block size is a multiple of cache size is a multiple - // of prog and read sizes - LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->read_size == 0); - LFS_ASSERT(lfs->cfg->cache_size % lfs->cfg->prog_size == 0); - LFS_ASSERT(lfs->cfg->block_size % lfs->cfg->cache_size == 0); - - // check that the block size is large enough to fit ctz pointers - LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) - <= lfs->cfg->block_size); - - // block_cycles = 0 is no longer supported. - // - // block_cycles is the number of erase cycles before littlefs evicts - // metadata logs as a part of wear leveling. Suggested values are in the - // range of 100-1000, or set block_cycles to -1 to disable block-level - // wear-leveling. - LFS_ASSERT(lfs->cfg->block_cycles != 0); - - - // setup read cache - if (lfs->cfg->read_buffer) { - lfs->rcache.buffer = lfs->cfg->read_buffer; - } else { - lfs->rcache.buffer = lfs_malloc(lfs->cfg->cache_size); - if (!lfs->rcache.buffer) { - err = LFS_ERR_NOMEM; - goto cleanup; - } - } - - // setup program cache - if (lfs->cfg->prog_buffer) { - lfs->pcache.buffer = lfs->cfg->prog_buffer; - } else { - lfs->pcache.buffer = lfs_malloc(lfs->cfg->cache_size); - if (!lfs->pcache.buffer) { - err = LFS_ERR_NOMEM; - goto cleanup; - } - } - - // zero to avoid information leaks - lfs_cache_zero(lfs, &lfs->rcache); - lfs_cache_zero(lfs, &lfs->pcache); - - // setup lookahead, must be multiple of 64-bits, 32-bit aligned - LFS_ASSERT(lfs->cfg->lookahead_size > 0); - LFS_ASSERT(lfs->cfg->lookahead_size % 8 == 0 && - (uintptr_t)lfs->cfg->lookahead_buffer % 4 == 0); - if (lfs->cfg->lookahead_buffer) { - lfs->free.buffer = lfs->cfg->lookahead_buffer; - } else { - lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead_size); - if (!lfs->free.buffer) { - err = LFS_ERR_NOMEM; - goto cleanup; - } - } - - // check that the size limits are sane - LFS_ASSERT(lfs->cfg->name_max <= LFS_NAME_MAX); - lfs->name_max = lfs->cfg->name_max; - if (!lfs->name_max) { - lfs->name_max = LFS_NAME_MAX; - } - - LFS_ASSERT(lfs->cfg->file_max <= LFS_FILE_MAX); - lfs->file_max = lfs->cfg->file_max; - if (!lfs->file_max) { - lfs->file_max = LFS_FILE_MAX; - } - - LFS_ASSERT(lfs->cfg->attr_max <= LFS_ATTR_MAX); - lfs->attr_max = lfs->cfg->attr_max; - if (!lfs->attr_max) { - lfs->attr_max = LFS_ATTR_MAX; - } - - // setup default state - lfs->root[0] = LFS_BLOCK_NULL; - lfs->root[1] = LFS_BLOCK_NULL; - lfs->mlist = NULL; - lfs->seed = 0; - lfs->gdisk = (lfs_gstate_t){0}; - lfs->gstate = (lfs_gstate_t){0}; - lfs->gdelta = (lfs_gstate_t){0}; -#ifdef LFS_MIGRATE - lfs->lfs1 = NULL; -#endif - - return 0; - -cleanup: - lfs_deinit(lfs); - return err; -} - -static int lfs_deinit(lfs_t *lfs) { - // free allocated memory - if (!lfs->cfg->read_buffer) { - lfs_free(lfs->rcache.buffer); - } - - if (!lfs->cfg->prog_buffer) { - lfs_free(lfs->pcache.buffer); - } - - if (!lfs->cfg->lookahead_buffer) { - lfs_free(lfs->free.buffer); - } - - return 0; -} - -int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_format(%p, %p {.context=%p, " - ".read=%p, .prog=%p, .erase=%p, .sync=%p, " - ".read_size=%"PRIu32", .prog_size=%"PRIu32", " - ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); - int err = 0; - { - err = lfs_init(lfs, cfg); - if (err) { - LFS_TRACE("lfs_format -> %d", err); - return err; - } - - // create free lookahead - memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); - lfs->free.off = 0; - lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, - lfs->cfg->block_count); - lfs->free.i = 0; - lfs_alloc_ack(lfs); - - // create root dir - lfs_mdir_t root; - err = lfs_dir_alloc(lfs, &root); - if (err) { - goto cleanup; - } - - // write one superblock - lfs_superblock_t superblock = { - .version = LFS_DISK_VERSION, - .block_size = lfs->cfg->block_size, - .block_count = lfs->cfg->block_count, - .name_max = lfs->name_max, - .file_max = lfs->file_max, - .attr_max = lfs->attr_max, - }; - - lfs_superblock_tole32(&superblock); - err = lfs_dir_commit(lfs, &root, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL}, - {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, - {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), - &superblock})); - if (err) { - goto cleanup; - } - - // sanity check that fetch works - err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1}); - if (err) { - goto cleanup; - } - - // force compaction to prevent accidentally mounting any - // older version of littlefs that may live on disk - root.erased = false; - err = lfs_dir_commit(lfs, &root, NULL, 0); - if (err) { - goto cleanup; - } - } - -cleanup: - lfs_deinit(lfs); - LFS_TRACE("lfs_format -> %d", err); - return err; -} - -int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_mount(%p, %p {.context=%p, " - ".read=%p, .prog=%p, .erase=%p, .sync=%p, " - ".read_size=%"PRIu32", .prog_size=%"PRIu32", " - ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); - int err = lfs_init(lfs, cfg); - if (err) { - LFS_TRACE("lfs_mount -> %d", err); - return err; - } - - // scan directory blocks for superblock and any global updates - lfs_mdir_t dir = {.tail = {0, 1}}; - lfs_block_t cycle = 0; - while (!lfs_pair_isnull(dir.tail)) { - if (cycle >= lfs->cfg->block_count/2) { - // loop detected - err = LFS_ERR_CORRUPT; - goto cleanup; - } - cycle += 1; - - // fetch next block in tail list - lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail, - LFS_MKTAG(0x7ff, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), - NULL, - lfs_dir_find_match, &(struct lfs_dir_find_match){ - lfs, "littlefs", 8}); - if (tag < 0) { - err = tag; - goto cleanup; - } - - // has superblock? - if (tag && !lfs_tag_isdelete(tag)) { - // update root - lfs->root[0] = dir.pair[0]; - lfs->root[1] = dir.pair[1]; - - // grab superblock - lfs_superblock_t superblock; - tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), - &superblock); - if (tag < 0) { - err = tag; - goto cleanup; - } - lfs_superblock_fromle32(&superblock); - - // check version - uint16_t major_version = (0xffff & (superblock.version >> 16)); - uint16_t minor_version = (0xffff & (superblock.version >> 0)); - if ((major_version != LFS_DISK_VERSION_MAJOR || - minor_version > LFS_DISK_VERSION_MINOR)) { - LFS_ERROR("Invalid version v%"PRIu16".%"PRIu16, - major_version, minor_version); - err = LFS_ERR_INVAL; - goto cleanup; - } - - // check superblock configuration - if (superblock.name_max) { - if (superblock.name_max > lfs->name_max) { - LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")", - superblock.name_max, lfs->name_max); - err = LFS_ERR_INVAL; - goto cleanup; - } - - lfs->name_max = superblock.name_max; - } - - if (superblock.file_max) { - if (superblock.file_max > lfs->file_max) { - LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")", - superblock.file_max, lfs->file_max); - err = LFS_ERR_INVAL; - goto cleanup; - } - - lfs->file_max = superblock.file_max; - } - - if (superblock.attr_max) { - if (superblock.attr_max > lfs->attr_max) { - LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")", - superblock.attr_max, lfs->attr_max); - err = LFS_ERR_INVAL; - goto cleanup; - } - - lfs->attr_max = superblock.attr_max; - } - } - - // has gstate? - err = lfs_dir_getgstate(lfs, &dir, &lfs->gstate); - if (err) { - goto cleanup; - } - } - - // found superblock? - if (lfs_pair_isnull(lfs->root)) { - err = LFS_ERR_INVAL; - goto cleanup; - } - - // update littlefs with gstate - if (!lfs_gstate_iszero(&lfs->gstate)) { - LFS_DEBUG("Found pending gstate 0x%08"PRIx32"%08"PRIx32"%08"PRIx32, - lfs->gstate.tag, - lfs->gstate.pair[0], - lfs->gstate.pair[1]); - } - lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag); - lfs->gdisk = lfs->gstate; - - // setup free lookahead - lfs_alloc_reset(lfs); - - LFS_TRACE("lfs_mount -> %d", 0); - return 0; - -cleanup: - lfs_unmount(lfs); - LFS_TRACE("lfs_mount -> %d", err); - return err; -} - -int lfs_unmount(lfs_t *lfs) { - LFS_TRACE("lfs_unmount(%p)", (void*)lfs); - int err = lfs_deinit(lfs); - LFS_TRACE("lfs_unmount -> %d", err); - return err; -} - - -/// Filesystem filesystem operations /// -int lfs_fs_traverseraw(lfs_t *lfs, - int (*cb)(void *data, lfs_block_t block), void *data, - bool includeorphans) { - // iterate over metadata pairs - lfs_mdir_t dir = {.tail = {0, 1}}; - -#ifdef LFS_MIGRATE - // also consider v1 blocks during migration - if (lfs->lfs1) { - int err = lfs1_traverse(lfs, cb, data); - if (err) { - return err; - } - - dir.tail[0] = lfs->root[0]; - dir.tail[1] = lfs->root[1]; - } -#endif - - lfs_block_t cycle = 0; - while (!lfs_pair_isnull(dir.tail)) { - if (cycle >= lfs->cfg->block_count/2) { - // loop detected - return LFS_ERR_CORRUPT; - } - cycle += 1; - - for (int i = 0; i < 2; i++) { - int err = cb(data, dir.tail[i]); - if (err) { - return err; - } - } - - // iterate through ids in directory - int err = lfs_dir_fetch(lfs, &dir, dir.tail); - if (err) { - return err; - } - - for (uint16_t id = 0; id < dir.count; id++) { - struct lfs_ctz ctz; - lfs_stag_t tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz); - if (tag < 0) { - if (tag == LFS_ERR_NOENT) { - continue; - } - return tag; - } - lfs_ctz_fromle32(&ctz); - - if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) { - err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache, - ctz.head, ctz.size, cb, data); - if (err) { - return err; - } - } else if (includeorphans && - lfs_tag_type3(tag) == LFS_TYPE_DIRSTRUCT) { - for (int i = 0; i < 2; i++) { - err = cb(data, (&ctz.head)[i]); - if (err) { - return err; - } - } - } - } - } - - // iterate over any open files - for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { - if (f->type != LFS_TYPE_REG) { - continue; - } - - if ((f->flags & LFS_F_DIRTY) && !(f->flags & LFS_F_INLINE)) { - int err = lfs_ctz_traverse(lfs, &f->cache, &lfs->rcache, - f->ctz.head, f->ctz.size, cb, data); - if (err) { - return err; - } - } - - if ((f->flags & LFS_F_WRITING) && !(f->flags & LFS_F_INLINE)) { - int err = lfs_ctz_traverse(lfs, &f->cache, &lfs->rcache, - f->block, f->pos, cb, data); - if (err) { - return err; - } - } - } - - return 0; -} - -int lfs_fs_traverse(lfs_t *lfs, - int (*cb)(void *data, lfs_block_t block), void *data) { - LFS_TRACE("lfs_fs_traverse(%p, %p, %p)", - (void*)lfs, (void*)(uintptr_t)cb, data); - int err = lfs_fs_traverseraw(lfs, cb, data, true); - LFS_TRACE("lfs_fs_traverse -> %d", 0); - return err; -} - -static int lfs_fs_pred(lfs_t *lfs, - const lfs_block_t pair[2], lfs_mdir_t *pdir) { - // iterate over all directory directory entries - pdir->tail[0] = 0; - pdir->tail[1] = 1; - lfs_block_t cycle = 0; - while (!lfs_pair_isnull(pdir->tail)) { - if (cycle >= lfs->cfg->block_count/2) { - // loop detected - return LFS_ERR_CORRUPT; - } - cycle += 1; - - if (lfs_pair_cmp(pdir->tail, pair) == 0) { - return 0; - } - - int err = lfs_dir_fetch(lfs, pdir, pdir->tail); - if (err) { - return err; - } - } - - return LFS_ERR_NOENT; -} - -struct lfs_fs_parent_match { - lfs_t *lfs; - const lfs_block_t pair[2]; -}; - -static int lfs_fs_parent_match(void *data, - lfs_tag_t tag, const void *buffer) { - struct lfs_fs_parent_match *find = data; - lfs_t *lfs = find->lfs; - const struct lfs_diskoff *disk = buffer; - (void)tag; - - lfs_block_t child[2]; - int err = lfs_bd_read(lfs, - &lfs->pcache, &lfs->rcache, lfs->cfg->block_size, - disk->block, disk->off, &child, sizeof(child)); - if (err) { - return err; - } - - lfs_pair_fromle32(child); - return (lfs_pair_cmp(child, find->pair) == 0) ? LFS_CMP_EQ : LFS_CMP_LT; -} - -static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2], - lfs_mdir_t *parent) { - // use fetchmatch with callback to find pairs - parent->tail[0] = 0; - parent->tail[1] = 1; - lfs_block_t cycle = 0; - while (!lfs_pair_isnull(parent->tail)) { - if (cycle >= lfs->cfg->block_count/2) { - // loop detected - return LFS_ERR_CORRUPT; - } - cycle += 1; - - lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail, - LFS_MKTAG(0x7ff, 0, 0x3ff), - LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, 8), - NULL, - lfs_fs_parent_match, &(struct lfs_fs_parent_match){ - lfs, {pair[0], pair[1]}}); - if (tag && tag != LFS_ERR_NOENT) { - return tag; - } - } - - return LFS_ERR_NOENT; -} - -static int lfs_fs_relocate(lfs_t *lfs, - const lfs_block_t oldpair[2], lfs_block_t newpair[2]) { - // update internal root - if (lfs_pair_cmp(oldpair, lfs->root) == 0) { - lfs->root[0] = newpair[0]; - lfs->root[1] = newpair[1]; - } - - // update internally tracked dirs - for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { - if (lfs_pair_cmp(oldpair, d->m.pair) == 0) { - d->m.pair[0] = newpair[0]; - d->m.pair[1] = newpair[1]; - } - - if (d->type == LFS_TYPE_DIR && - lfs_pair_cmp(oldpair, ((lfs_dir_t*)d)->head) == 0) { - ((lfs_dir_t*)d)->head[0] = newpair[0]; - ((lfs_dir_t*)d)->head[1] = newpair[1]; - } - } - - // find parent - lfs_mdir_t parent; - lfs_stag_t tag = lfs_fs_parent(lfs, oldpair, &parent); - if (tag < 0 && tag != LFS_ERR_NOENT) { - return tag; - } - - if (tag != LFS_ERR_NOENT) { - // update disk, this creates a desync - lfs_fs_preporphans(lfs, +1); - - // fix pending move in this pair? this looks like an optimization but - // is in fact _required_ since relocating may outdate the move. - uint16_t moveid = 0x3ff; - if (lfs_gstate_hasmovehere(&lfs->gstate, parent.pair)) { - moveid = lfs_tag_id(lfs->gstate.tag); - LFS_DEBUG("Fixing move while relocating " - "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", - parent.pair[0], parent.pair[1], moveid); - lfs_fs_prepmove(lfs, 0x3ff, NULL); - if (moveid < lfs_tag_id(tag)) { - tag -= LFS_MKTAG(0, 1, 0); - } - } - - lfs_pair_tole32(newpair); - int err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS( - {LFS_MKTAG_IF(moveid != 0x3ff, - LFS_TYPE_DELETE, moveid, 0), NULL}, - {tag, newpair})); - lfs_pair_fromle32(newpair); - if (err) { - return err; - } - - // next step, clean up orphans - lfs_fs_preporphans(lfs, -1); - } - - // find pred - int err = lfs_fs_pred(lfs, oldpair, &parent); - if (err && err != LFS_ERR_NOENT) { - return err; - } - - // if we can't find dir, it must be new - if (err != LFS_ERR_NOENT) { - // fix pending move in this pair? this looks like an optimization but - // is in fact _required_ since relocating may outdate the move. - uint16_t moveid = 0x3ff; - if (lfs_gstate_hasmovehere(&lfs->gstate, parent.pair)) { - moveid = lfs_tag_id(lfs->gstate.tag); - LFS_DEBUG("Fixing move while relocating " - "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", - parent.pair[0], parent.pair[1], moveid); - lfs_fs_prepmove(lfs, 0x3ff, NULL); - } - - // replace bad pair, either we clean up desync, or no desync occured - lfs_pair_tole32(newpair); - err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS( - {LFS_MKTAG_IF(moveid != 0x3ff, - LFS_TYPE_DELETE, moveid, 0), NULL}, - {LFS_MKTAG(LFS_TYPE_TAIL + parent.split, 0x3ff, 8), newpair})); - lfs_pair_fromle32(newpair); - if (err) { - return err; - } - } - - return 0; -} - -static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) { - LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0 || orphans >= 0); - lfs->gstate.tag += orphans; - lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) | - ((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31)); -} - -static void lfs_fs_prepmove(lfs_t *lfs, - uint16_t id, const lfs_block_t pair[2]) { - lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x7ff, 0x3ff, 0)) | - ((id != 0x3ff) ? LFS_MKTAG(LFS_TYPE_DELETE, id, 0) : 0)); - lfs->gstate.pair[0] = (id != 0x3ff) ? pair[0] : 0; - lfs->gstate.pair[1] = (id != 0x3ff) ? pair[1] : 0; -} - -static int lfs_fs_demove(lfs_t *lfs) { - if (!lfs_gstate_hasmove(&lfs->gdisk)) { - return 0; - } - - // Fix bad moves - LFS_DEBUG("Fixing move {0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16, - lfs->gdisk.pair[0], - lfs->gdisk.pair[1], - lfs_tag_id(lfs->gdisk.tag)); - - // fetch and delete the moved entry - lfs_mdir_t movedir; - int err = lfs_dir_fetch(lfs, &movedir, lfs->gdisk.pair); - if (err) { - return err; - } - - // prep gstate and delete move id - uint16_t moveid = lfs_tag_id(lfs->gdisk.tag); - lfs_fs_prepmove(lfs, 0x3ff, NULL); - err = lfs_dir_commit(lfs, &movedir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_DELETE, moveid, 0), NULL})); - if (err) { - return err; - } - - return 0; -} - -static int lfs_fs_deorphan(lfs_t *lfs) { - if (!lfs_gstate_hasorphans(&lfs->gstate)) { - return 0; - } - - // Fix any orphans - lfs_mdir_t pdir = {.split = true, .tail = {0, 1}}; - lfs_mdir_t dir; - - // iterate over all directory directory entries - while (!lfs_pair_isnull(pdir.tail)) { - int err = lfs_dir_fetch(lfs, &dir, pdir.tail); - if (err) { - return err; - } - - // check head blocks for orphans - if (!pdir.split) { - // check if we have a parent - lfs_mdir_t parent; - lfs_stag_t tag = lfs_fs_parent(lfs, pdir.tail, &parent); - if (tag < 0 && tag != LFS_ERR_NOENT) { - return tag; - } - - if (tag == LFS_ERR_NOENT) { - // we are an orphan - LFS_DEBUG("Fixing orphan {0x%"PRIx32", 0x%"PRIx32"}", - pdir.tail[0], pdir.tail[1]); - - err = lfs_dir_drop(lfs, &pdir, &dir); - if (err) { - return err; - } - - // refetch tail - continue; - } - - lfs_block_t pair[2]; - lfs_stag_t res = lfs_dir_get(lfs, &parent, - LFS_MKTAG(0x7ff, 0x3ff, 0), tag, pair); - if (res < 0) { - return res; - } - lfs_pair_fromle32(pair); - - if (!lfs_pair_sync(pair, pdir.tail)) { - // we have desynced - LFS_DEBUG("Fixing half-orphan {0x%"PRIx32", 0x%"PRIx32"} " - "-> {0x%"PRIx32", 0x%"PRIx32"}", - pdir.tail[0], pdir.tail[1], pair[0], pair[1]); - - lfs_pair_tole32(pair); - err = lfs_dir_commit(lfs, &pdir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pair})); - lfs_pair_fromle32(pair); - if (err) { - return err; - } - - // refetch tail - continue; - } - } - - pdir = dir; - } - - // mark orphans as fixed - lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate)); - return 0; -} - -static int lfs_fs_forceconsistency(lfs_t *lfs) { - int err = lfs_fs_demove(lfs); - if (err) { - return err; - } - - err = lfs_fs_deorphan(lfs); - if (err) { - return err; - } - - return 0; -} - -static int lfs_fs_size_count(void *p, lfs_block_t block) { - (void)block; - lfs_size_t *size = p; - *size += 1; - return 0; -} - -lfs_ssize_t lfs_fs_size(lfs_t *lfs) { - LFS_TRACE("lfs_fs_size(%p)", (void*)lfs); - lfs_size_t size = 0; - int err = lfs_fs_traverseraw(lfs, lfs_fs_size_count, &size, false); - if (err) { - LFS_TRACE("lfs_fs_size -> %d", err); - return err; - } - - LFS_TRACE("lfs_fs_size -> %d", err); - return size; -} - -#ifdef LFS_MIGRATE -////// Migration from littelfs v1 below this ////// - -/// Version info /// - -// Software library version -// Major (top-nibble), incremented on backwards incompatible changes -// Minor (bottom-nibble), incremented on feature additions -#define LFS1_VERSION 0x00010007 -#define LFS1_VERSION_MAJOR (0xffff & (LFS1_VERSION >> 16)) -#define LFS1_VERSION_MINOR (0xffff & (LFS1_VERSION >> 0)) - -// Version of On-disk data structures -// Major (top-nibble), incremented on backwards incompatible changes -// Minor (bottom-nibble), incremented on feature additions -#define LFS1_DISK_VERSION 0x00010001 -#define LFS1_DISK_VERSION_MAJOR (0xffff & (LFS1_DISK_VERSION >> 16)) -#define LFS1_DISK_VERSION_MINOR (0xffff & (LFS1_DISK_VERSION >> 0)) - - -/// v1 Definitions /// - -// File types -enum lfs1_type { - LFS1_TYPE_REG = 0x11, - LFS1_TYPE_DIR = 0x22, - LFS1_TYPE_SUPERBLOCK = 0x2e, -}; - -typedef struct lfs1 { - lfs_block_t root[2]; -} lfs1_t; - -typedef struct lfs1_entry { - lfs_off_t off; - - struct lfs1_disk_entry { - uint8_t type; - uint8_t elen; - uint8_t alen; - uint8_t nlen; - union { - struct { - lfs_block_t head; - lfs_size_t size; - } file; - lfs_block_t dir[2]; - } u; - } d; -} lfs1_entry_t; - -typedef struct lfs1_dir { - struct lfs1_dir *next; - lfs_block_t pair[2]; - lfs_off_t off; - - lfs_block_t head[2]; - lfs_off_t pos; - - struct lfs1_disk_dir { - uint32_t rev; - lfs_size_t size; - lfs_block_t tail[2]; - } d; -} lfs1_dir_t; - -typedef struct lfs1_superblock { - lfs_off_t off; - - struct lfs1_disk_superblock { - uint8_t type; - uint8_t elen; - uint8_t alen; - uint8_t nlen; - lfs_block_t root[2]; - uint32_t block_size; - uint32_t block_count; - uint32_t version; - char magic[8]; - } d; -} lfs1_superblock_t; - - -/// Low-level wrappers v1->v2 /// -static void lfs1_crc(uint32_t *crc, const void *buffer, size_t size) { - *crc = lfs_crc(*crc, buffer, size); -} - -static int lfs1_bd_read(lfs_t *lfs, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size) { - // if we ever do more than writes to alternating pairs, - // this may need to consider pcache - return lfs_bd_read(lfs, &lfs->pcache, &lfs->rcache, size, - block, off, buffer, size); -} - -static int lfs1_bd_crc(lfs_t *lfs, lfs_block_t block, - lfs_off_t off, lfs_size_t size, uint32_t *crc) { - for (lfs_off_t i = 0; i < size; i++) { - uint8_t c; - int err = lfs1_bd_read(lfs, block, off+i, &c, 1); - if (err) { - return err; - } - - lfs1_crc(crc, &c, 1); - } - - return 0; -} - - -/// Endian swapping functions /// -static void lfs1_dir_fromle32(struct lfs1_disk_dir *d) { - d->rev = lfs_fromle32(d->rev); - d->size = lfs_fromle32(d->size); - d->tail[0] = lfs_fromle32(d->tail[0]); - d->tail[1] = lfs_fromle32(d->tail[1]); -} - -static void lfs1_dir_tole32(struct lfs1_disk_dir *d) { - d->rev = lfs_tole32(d->rev); - d->size = lfs_tole32(d->size); - d->tail[0] = lfs_tole32(d->tail[0]); - d->tail[1] = lfs_tole32(d->tail[1]); -} - -static void lfs1_entry_fromle32(struct lfs1_disk_entry *d) { - d->u.dir[0] = lfs_fromle32(d->u.dir[0]); - d->u.dir[1] = lfs_fromle32(d->u.dir[1]); -} - -static void lfs1_entry_tole32(struct lfs1_disk_entry *d) { - d->u.dir[0] = lfs_tole32(d->u.dir[0]); - d->u.dir[1] = lfs_tole32(d->u.dir[1]); -} - -static void lfs1_superblock_fromle32(struct lfs1_disk_superblock *d) { - d->root[0] = lfs_fromle32(d->root[0]); - d->root[1] = lfs_fromle32(d->root[1]); - d->block_size = lfs_fromle32(d->block_size); - d->block_count = lfs_fromle32(d->block_count); - d->version = lfs_fromle32(d->version); -} - - -///// Metadata pair and directory operations /// -static inline lfs_size_t lfs1_entry_size(const lfs1_entry_t *entry) { - return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; -} - -static int lfs1_dir_fetch(lfs_t *lfs, - lfs1_dir_t *dir, const lfs_block_t pair[2]) { - // copy out pair, otherwise may be aliasing dir - const lfs_block_t tpair[2] = {pair[0], pair[1]}; - bool valid = false; - - // check both blocks for the most recent revision - for (int i = 0; i < 2; i++) { - struct lfs1_disk_dir test; - int err = lfs1_bd_read(lfs, tpair[i], 0, &test, sizeof(test)); - lfs1_dir_fromle32(&test); - if (err) { - if (err == LFS_ERR_CORRUPT) { - continue; - } - return err; - } - - if (valid && lfs_scmp(test.rev, dir->d.rev) < 0) { - continue; - } - - if ((0x7fffffff & test.size) < sizeof(test)+4 || - (0x7fffffff & test.size) > lfs->cfg->block_size) { - continue; - } - - uint32_t crc = 0xffffffff; - lfs1_dir_tole32(&test); - lfs1_crc(&crc, &test, sizeof(test)); - lfs1_dir_fromle32(&test); - err = lfs1_bd_crc(lfs, tpair[i], sizeof(test), - (0x7fffffff & test.size) - sizeof(test), &crc); - if (err) { - if (err == LFS_ERR_CORRUPT) { - continue; - } - return err; - } - - if (crc != 0) { - continue; - } - - valid = true; - - // setup dir in case it's valid - dir->pair[0] = tpair[(i+0) % 2]; - dir->pair[1] = tpair[(i+1) % 2]; - dir->off = sizeof(dir->d); - dir->d = test; - } - - if (!valid) { - LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}", - tpair[0], tpair[1]); - return LFS_ERR_CORRUPT; - } - - return 0; -} - -static int lfs1_dir_next(lfs_t *lfs, lfs1_dir_t *dir, lfs1_entry_t *entry) { - while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) { - if (!(0x80000000 & dir->d.size)) { - entry->off = dir->off; - return LFS_ERR_NOENT; - } - - int err = lfs1_dir_fetch(lfs, dir, dir->d.tail); - if (err) { - return err; - } - - dir->off = sizeof(dir->d); - dir->pos += sizeof(dir->d) + 4; - } - - int err = lfs1_bd_read(lfs, dir->pair[0], dir->off, - &entry->d, sizeof(entry->d)); - lfs1_entry_fromle32(&entry->d); - if (err) { - return err; - } - - entry->off = dir->off; - dir->off += lfs1_entry_size(entry); - dir->pos += lfs1_entry_size(entry); - return 0; -} - -/// littlefs v1 specific operations /// -int lfs1_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { - if (lfs_pair_isnull(lfs->lfs1->root)) { - return 0; - } - - // iterate over metadata pairs - lfs1_dir_t dir; - lfs1_entry_t entry; - lfs_block_t cwd[2] = {0, 1}; - - while (true) { - for (int i = 0; i < 2; i++) { - int err = cb(data, cwd[i]); - if (err) { - return err; - } - } - - int err = lfs1_dir_fetch(lfs, &dir, cwd); - if (err) { - return err; - } - - // iterate over contents - while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) { - err = lfs1_bd_read(lfs, dir.pair[0], dir.off, - &entry.d, sizeof(entry.d)); - lfs1_entry_fromle32(&entry.d); - if (err) { - return err; - } - - dir.off += lfs1_entry_size(&entry); - if ((0x70 & entry.d.type) == (0x70 & LFS1_TYPE_REG)) { - err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache, - entry.d.u.file.head, entry.d.u.file.size, cb, data); - if (err) { - return err; - } - } - } - - // we also need to check if we contain a threaded v2 directory - lfs_mdir_t dir2 = {.split=true, .tail={cwd[0], cwd[1]}}; - while (dir2.split) { - err = lfs_dir_fetch(lfs, &dir2, dir2.tail); - if (err) { - break; - } - - for (int i = 0; i < 2; i++) { - err = cb(data, dir2.pair[i]); - if (err) { - return err; - } - } - } - - cwd[0] = dir.d.tail[0]; - cwd[1] = dir.d.tail[1]; - - if (lfs_pair_isnull(cwd)) { - break; - } - } - - return 0; -} - -static int lfs1_moved(lfs_t *lfs, const void *e) { - if (lfs_pair_isnull(lfs->lfs1->root)) { - return 0; - } - - // skip superblock - lfs1_dir_t cwd; - int err = lfs1_dir_fetch(lfs, &cwd, (const lfs_block_t[2]){0, 1}); - if (err) { - return err; - } - - // iterate over all directory directory entries - lfs1_entry_t entry; - while (!lfs_pair_isnull(cwd.d.tail)) { - err = lfs1_dir_fetch(lfs, &cwd, cwd.d.tail); - if (err) { - return err; - } - - while (true) { - err = lfs1_dir_next(lfs, &cwd, &entry); - if (err && err != LFS_ERR_NOENT) { - return err; - } - - if (err == LFS_ERR_NOENT) { - break; - } - - if (!(0x80 & entry.d.type) && - memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) { - return true; - } - } - } - - return false; -} - -/// Filesystem operations /// -static int lfs1_mount(lfs_t *lfs, struct lfs1 *lfs1, - const struct lfs_config *cfg) { - int err = 0; - { - err = lfs_init(lfs, cfg); - if (err) { - return err; - } - - lfs->lfs1 = lfs1; - lfs->lfs1->root[0] = LFS_BLOCK_NULL; - lfs->lfs1->root[1] = LFS_BLOCK_NULL; - - // setup free lookahead - lfs->free.off = 0; - lfs->free.size = 0; - lfs->free.i = 0; - lfs_alloc_ack(lfs); - - // load superblock - lfs1_dir_t dir; - lfs1_superblock_t superblock; - err = lfs1_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); - if (err && err != LFS_ERR_CORRUPT) { - goto cleanup; - } - - if (!err) { - err = lfs1_bd_read(lfs, dir.pair[0], sizeof(dir.d), - &superblock.d, sizeof(superblock.d)); - lfs1_superblock_fromle32(&superblock.d); - if (err) { - goto cleanup; - } - - lfs->lfs1->root[0] = superblock.d.root[0]; - lfs->lfs1->root[1] = superblock.d.root[1]; - } - - if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { - LFS_ERROR("Invalid superblock at {0x%"PRIx32", 0x%"PRIx32"}", - 0, 1); - err = LFS_ERR_CORRUPT; - goto cleanup; - } - - uint16_t major_version = (0xffff & (superblock.d.version >> 16)); - uint16_t minor_version = (0xffff & (superblock.d.version >> 0)); - if ((major_version != LFS1_DISK_VERSION_MAJOR || - minor_version > LFS1_DISK_VERSION_MINOR)) { - LFS_ERROR("Invalid version v%d.%d", major_version, minor_version); - err = LFS_ERR_INVAL; - goto cleanup; - } - - return 0; - } - -cleanup: - lfs_deinit(lfs); - return err; -} - -static int lfs1_unmount(lfs_t *lfs) { - return lfs_deinit(lfs); -} - -/// v1 migration /// -int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_migrate(%p, %p {.context=%p, " - ".read=%p, .prog=%p, .erase=%p, .sync=%p, " - ".read_size=%"PRIu32", .prog_size=%"PRIu32", " - ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); - struct lfs1 lfs1; - int err = lfs1_mount(lfs, &lfs1, cfg); - if (err) { - LFS_TRACE("lfs_migrate -> %d", err); - return err; - } - - { - // iterate through each directory, copying over entries - // into new directory - lfs1_dir_t dir1; - lfs_mdir_t dir2; - dir1.d.tail[0] = lfs->lfs1->root[0]; - dir1.d.tail[1] = lfs->lfs1->root[1]; - while (!lfs_pair_isnull(dir1.d.tail)) { - // iterate old dir - err = lfs1_dir_fetch(lfs, &dir1, dir1.d.tail); - if (err) { - goto cleanup; - } - - // create new dir and bind as temporary pretend root - err = lfs_dir_alloc(lfs, &dir2); - if (err) { - goto cleanup; - } - - dir2.rev = dir1.d.rev; - dir1.head[0] = dir1.pair[0]; - dir1.head[1] = dir1.pair[1]; - lfs->root[0] = dir2.pair[0]; - lfs->root[1] = dir2.pair[1]; - - err = lfs_dir_commit(lfs, &dir2, NULL, 0); - if (err) { - goto cleanup; - } - - while (true) { - lfs1_entry_t entry1; - err = lfs1_dir_next(lfs, &dir1, &entry1); - if (err && err != LFS_ERR_NOENT) { - goto cleanup; - } - - if (err == LFS_ERR_NOENT) { - break; - } - - // check that entry has not been moved - if (entry1.d.type & 0x80) { - int moved = lfs1_moved(lfs, &entry1.d.u); - if (moved < 0) { - err = moved; - goto cleanup; - } - - if (moved) { - continue; - } - - entry1.d.type &= ~0x80; - } - - // also fetch name - char name[LFS_NAME_MAX+1]; - memset(name, 0, sizeof(name)); - err = lfs1_bd_read(lfs, dir1.pair[0], - entry1.off + 4+entry1.d.elen+entry1.d.alen, - name, entry1.d.nlen); - if (err) { - goto cleanup; - } - - bool isdir = (entry1.d.type == LFS1_TYPE_DIR); - - // create entry in new dir - err = lfs_dir_fetch(lfs, &dir2, lfs->root); - if (err) { - goto cleanup; - } - - uint16_t id; - err = lfs_dir_find(lfs, &dir2, &(const char*){name}, &id); - if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { - err = (err < 0) ? err : LFS_ERR_EXIST; - goto cleanup; - } - - lfs1_entry_tole32(&entry1.d); - err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_CREATE, id, 0)}, - {LFS_MKTAG_IF_ELSE(isdir, - LFS_TYPE_DIR, id, entry1.d.nlen, - LFS_TYPE_REG, id, entry1.d.nlen), - name}, - {LFS_MKTAG_IF_ELSE(isdir, - LFS_TYPE_DIRSTRUCT, id, sizeof(entry1.d.u), - LFS_TYPE_CTZSTRUCT, id, sizeof(entry1.d.u)), - &entry1.d.u})); - lfs1_entry_fromle32(&entry1.d); - if (err) { - goto cleanup; - } - } - - if (!lfs_pair_isnull(dir1.d.tail)) { - // find last block and update tail to thread into fs - err = lfs_dir_fetch(lfs, &dir2, lfs->root); - if (err) { - goto cleanup; - } - - while (dir2.split) { - err = lfs_dir_fetch(lfs, &dir2, dir2.tail); - if (err) { - goto cleanup; - } - } - - lfs_pair_tole32(dir2.pair); - err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir1.d.tail})); - lfs_pair_fromle32(dir2.pair); - if (err) { - goto cleanup; - } - } - - // Copy over first block to thread into fs. Unfortunately - // if this fails there is not much we can do. - LFS_DEBUG("Migrating {0x%"PRIx32", 0x%"PRIx32"} " - "-> {0x%"PRIx32", 0x%"PRIx32"}", - lfs->root[0], lfs->root[1], dir1.head[0], dir1.head[1]); - - err = lfs_bd_erase(lfs, dir1.head[1]); - if (err) { - goto cleanup; - } - - err = lfs_dir_fetch(lfs, &dir2, lfs->root); - if (err) { - goto cleanup; - } - - for (lfs_off_t i = 0; i < dir2.off; i++) { - uint8_t dat; - err = lfs_bd_read(lfs, - NULL, &lfs->rcache, dir2.off, - dir2.pair[0], i, &dat, 1); - if (err) { - goto cleanup; - } - - err = lfs_bd_prog(lfs, - &lfs->pcache, &lfs->rcache, true, - dir1.head[1], i, &dat, 1); - if (err) { - goto cleanup; - } - } - - err = lfs_bd_flush(lfs, &lfs->pcache, &lfs->rcache, true); - if (err) { - goto cleanup; - } - } - - // Create new superblock. This marks a successful migration! - err = lfs1_dir_fetch(lfs, &dir1, (const lfs_block_t[2]){0, 1}); - if (err) { - goto cleanup; - } - - dir2.pair[0] = dir1.pair[0]; - dir2.pair[1] = dir1.pair[1]; - dir2.rev = dir1.d.rev; - dir2.off = sizeof(dir2.rev); - dir2.etag = 0xffffffff; - dir2.count = 0; - dir2.tail[0] = lfs->lfs1->root[0]; - dir2.tail[1] = lfs->lfs1->root[1]; - dir2.erased = false; - dir2.split = true; - - lfs_superblock_t superblock = { - .version = LFS_DISK_VERSION, - .block_size = lfs->cfg->block_size, - .block_count = lfs->cfg->block_count, - .name_max = lfs->name_max, - .file_max = lfs->file_max, - .attr_max = lfs->attr_max, - }; - - lfs_superblock_tole32(&superblock); - err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0)}, - {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, - {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), - &superblock})); - if (err) { - goto cleanup; - } - - // sanity check that fetch works - err = lfs_dir_fetch(lfs, &dir2, (const lfs_block_t[2]){0, 1}); - if (err) { - goto cleanup; - } - - // force compaction to prevent accidentally mounting v1 - dir2.erased = false; - err = lfs_dir_commit(lfs, &dir2, NULL, 0); - if (err) { - goto cleanup; - } - } - -cleanup: - lfs1_unmount(lfs); - LFS_TRACE("lfs_migrate -> %d", err); - return err; -} - -#endif diff --git a/lib/LITTLEFS/src/lfs.h b/lib/LITTLEFS/src/lfs.h deleted file mode 100644 index 35bbbabf..00000000 --- a/lib/LITTLEFS/src/lfs.h +++ /dev/null @@ -1,655 +0,0 @@ -/* - * The little filesystem - * - * Copyright (c) 2017, Arm Limited. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause - */ -#ifndef LFS_H -#define LFS_H - -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - - -/// Version info /// - -// Software library version -// Major (top-nibble), incremented on backwards incompatible changes -// Minor (bottom-nibble), incremented on feature additions -#define LFS_VERSION 0x00020002 -#define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) -#define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) - -// Version of On-disk data structures -// Major (top-nibble), incremented on backwards incompatible changes -// Minor (bottom-nibble), incremented on feature additions -#define LFS_DISK_VERSION 0x00020000 -#define LFS_DISK_VERSION_MAJOR (0xffff & (LFS_DISK_VERSION >> 16)) -#define LFS_DISK_VERSION_MINOR (0xffff & (LFS_DISK_VERSION >> 0)) - - -/// Definitions /// - -// Type definitions -typedef uint32_t lfs_size_t; -typedef uint32_t lfs_off_t; - -typedef int32_t lfs_ssize_t; -typedef int32_t lfs_soff_t; - -typedef uint32_t lfs_block_t; - -// Maximum name size in bytes, may be redefined to reduce the size of the -// info struct. Limited to <= 1022. Stored in superblock and must be -// respected by other littlefs drivers. -#ifndef LFS_NAME_MAX -#define LFS_NAME_MAX 255 -#endif - -// Maximum size of a file in bytes, may be redefined to limit to support other -// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the -// functions lfs_file_seek, lfs_file_size, and lfs_file_tell will return -// incorrect values due to using signed integers. Stored in superblock and -// must be respected by other littlefs drivers. -#ifndef LFS_FILE_MAX -#define LFS_FILE_MAX 2147483647 -#endif - -// Maximum size of custom attributes in bytes, may be redefined, but there is -// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. -#ifndef LFS_ATTR_MAX -#define LFS_ATTR_MAX 1022 -#endif - -// Possible error codes, these are negative to allow -// valid positive return values -enum lfs_error { - LFS_ERR_OK = 0, // No error - LFS_ERR_IO = -5, // Error during device operation - LFS_ERR_CORRUPT = -84, // Corrupted - LFS_ERR_NOENT = -2, // No directory entry - LFS_ERR_EXIST = -17, // Entry already exists - LFS_ERR_NOTDIR = -20, // Entry is not a dir - LFS_ERR_ISDIR = -21, // Entry is a dir - LFS_ERR_NOTEMPTY = -39, // Dir is not empty - LFS_ERR_BADF = -9, // Bad file number - LFS_ERR_FBIG = -27, // File too large - LFS_ERR_INVAL = -22, // Invalid parameter - LFS_ERR_NOSPC = -28, // No space left on device - LFS_ERR_NOMEM = -12, // No more memory available - LFS_ERR_NOATTR = -61, // No data/attr available - LFS_ERR_NAMETOOLONG = -36, // File name too long -}; - -// File types -enum lfs_type { - // file types - LFS_TYPE_REG = 0x001, - LFS_TYPE_DIR = 0x002, - - // internally used types - LFS_TYPE_SPLICE = 0x400, - LFS_TYPE_NAME = 0x000, - LFS_TYPE_STRUCT = 0x200, - LFS_TYPE_USERATTR = 0x300, - LFS_TYPE_FROM = 0x100, - LFS_TYPE_TAIL = 0x600, - LFS_TYPE_GLOBALS = 0x700, - LFS_TYPE_CRC = 0x500, - - // internally used type specializations - LFS_TYPE_CREATE = 0x401, - LFS_TYPE_DELETE = 0x4ff, - LFS_TYPE_SUPERBLOCK = 0x0ff, - LFS_TYPE_DIRSTRUCT = 0x200, - LFS_TYPE_CTZSTRUCT = 0x202, - LFS_TYPE_INLINESTRUCT = 0x201, - LFS_TYPE_SOFTTAIL = 0x600, - LFS_TYPE_HARDTAIL = 0x601, - LFS_TYPE_MOVESTATE = 0x7ff, - - // internal chip sources - LFS_FROM_NOOP = 0x000, - LFS_FROM_MOVE = 0x101, - LFS_FROM_USERATTRS = 0x102, -}; - -// File open flags -enum lfs_open_flags { - // open flags - LFS_O_RDONLY = 1, // Open a file as read only - LFS_O_WRONLY = 2, // Open a file as write only - LFS_O_RDWR = 3, // Open a file as read and write - LFS_O_CREAT = 0x0100, // Create a file if it does not exist - LFS_O_EXCL = 0x0200, // Fail if a file already exists - LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size - LFS_O_APPEND = 0x0800, // Move to end of file on every write - - // internally used flags - LFS_F_DIRTY = 0x010000, // File does not match storage - LFS_F_WRITING = 0x020000, // File has been written since last flush - LFS_F_READING = 0x040000, // File has been read since last flush - LFS_F_ERRED = 0x080000, // An error occured during write - LFS_F_INLINE = 0x100000, // Currently inlined in directory entry - LFS_F_OPENED = 0x200000, // File has been opened -}; - -// File seek flags -enum lfs_whence_flags { - LFS_SEEK_SET = 0, // Seek relative to an absolute position - LFS_SEEK_CUR = 1, // Seek relative to the current file position - LFS_SEEK_END = 2, // Seek relative to the end of the file -}; - - -// Configuration provided during initialization of the littlefs -struct lfs_config { - // Opaque user provided context that can be used to pass - // information to the block device operations - void *context; - - // Read a region in a block. Negative error codes are propogated - // to the user. - int (*read)(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size); - - // Program a region in a block. The block must have previously - // been erased. Negative error codes are propogated to the user. - // May return LFS_ERR_CORRUPT if the block should be considered bad. - int (*prog)(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size); - - // Erase a block. A block must be erased before being programmed. - // The state of an erased block is undefined. Negative error codes - // are propogated to the user. - // May return LFS_ERR_CORRUPT if the block should be considered bad. - int (*erase)(const struct lfs_config *c, lfs_block_t block); - - // Sync the state of the underlying block device. Negative error codes - // are propogated to the user. - int (*sync)(const struct lfs_config *c); - - // Minimum size of a block read. All read operations will be a - // multiple of this value. - lfs_size_t read_size; - - // Minimum size of a block program. All program operations will be a - // multiple of this value. - lfs_size_t prog_size; - - // Size of an erasable block. This does not impact ram consumption and - // may be larger than the physical erase size. However, non-inlined files - // take up at minimum one block. Must be a multiple of the read - // and program sizes. - lfs_size_t block_size; - - // Number of erasable blocks on the device. - lfs_size_t block_count; - - // Number of erase cycles before littlefs evicts metadata logs and moves - // the metadata to another block. Suggested values are in the - // range 100-1000, with large values having better performance at the cost - // of less consistent wear distribution. - // - // Set to -1 to disable block-level wear-leveling. - int32_t block_cycles; - - // Size of block caches. Each cache buffers a portion of a block in RAM. - // The littlefs needs a read cache, a program cache, and one additional - // cache per file. Larger caches can improve performance by storing more - // data and reducing the number of disk accesses. Must be a multiple of - // the read and program sizes, and a factor of the block size. - lfs_size_t cache_size; - - // Size of the lookahead buffer in bytes. A larger lookahead buffer - // increases the number of blocks found during an allocation pass. The - // lookahead buffer is stored as a compact bitmap, so each byte of RAM - // can track 8 blocks. Must be a multiple of 8. - lfs_size_t lookahead_size; - - // Optional statically allocated read buffer. Must be cache_size. - // By default lfs_malloc is used to allocate this buffer. - void *read_buffer; - - // Optional statically allocated program buffer. Must be cache_size. - // By default lfs_malloc is used to allocate this buffer. - void *prog_buffer; - - // Optional statically allocated lookahead buffer. Must be lookahead_size - // and aligned to a 32-bit boundary. By default lfs_malloc is used to - // allocate this buffer. - void *lookahead_buffer; - - // Optional upper limit on length of file names in bytes. No downside for - // larger names except the size of the info struct which is controlled by - // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in - // superblock and must be respected by other littlefs drivers. - lfs_size_t name_max; - - // Optional upper limit on files in bytes. No downside for larger files - // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored - // in superblock and must be respected by other littlefs drivers. - lfs_size_t file_max; - - // Optional upper limit on custom attributes in bytes. No downside for - // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to - // LFS_ATTR_MAX when zero. - lfs_size_t attr_max; -}; - -// File info structure -struct lfs_info { - // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR - uint8_t type; - - // Size of the file, only valid for REG files. Limited to 32-bits. - lfs_size_t size; - - // Name of the file stored as a null-terminated string. Limited to - // LFS_NAME_MAX+1, which can be changed by redefining LFS_NAME_MAX to - // reduce RAM. LFS_NAME_MAX is stored in superblock and must be - // respected by other littlefs drivers. - char name[LFS_NAME_MAX+1]; -}; - -// Custom attribute structure, used to describe custom attributes -// committed atomically during file writes. -struct lfs_attr { - // 8-bit type of attribute, provided by user and used to - // identify the attribute - uint8_t type; - - // Pointer to buffer containing the attribute - void *buffer; - - // Size of attribute in bytes, limited to LFS_ATTR_MAX - lfs_size_t size; -}; - -// Optional configuration provided during lfs_file_opencfg -struct lfs_file_config { - // Optional statically allocated file buffer. Must be cache_size. - // By default lfs_malloc is used to allocate this buffer. - void *buffer; - - // Optional list of custom attributes related to the file. If the file - // is opened with read access, these attributes will be read from disk - // during the open call. If the file is opened with write access, the - // attributes will be written to disk every file sync or close. This - // write occurs atomically with update to the file's contents. - // - // Custom attributes are uniquely identified by an 8-bit type and limited - // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller - // than the buffer, it will be padded with zeros. If the stored attribute - // is larger, then it will be silently truncated. If the attribute is not - // found, it will be created implicitly. - struct lfs_attr *attrs; - - // Number of custom attributes in the list - lfs_size_t attr_count; -}; - - -/// internal littlefs data structures /// -typedef struct lfs_cache { - lfs_block_t block; - lfs_off_t off; - lfs_size_t size; - uint8_t *buffer; -} lfs_cache_t; - -typedef struct lfs_mdir { - lfs_block_t pair[2]; - uint32_t rev; - lfs_off_t off; - uint32_t etag; - uint16_t count; - bool erased; - bool split; - lfs_block_t tail[2]; -} lfs_mdir_t; - -// littlefs directory type -typedef struct lfs_dir { - struct lfs_dir *next; - uint16_t id; - uint8_t type; - lfs_mdir_t m; - - lfs_off_t pos; - lfs_block_t head[2]; -} lfs_dir_t; - -// littlefs file type -typedef struct lfs_file { - struct lfs_file *next; - uint16_t id; - uint8_t type; - lfs_mdir_t m; - - struct lfs_ctz { - lfs_block_t head; - lfs_size_t size; - } ctz; - - uint32_t flags; - lfs_off_t pos; - lfs_block_t block; - lfs_off_t off; - lfs_cache_t cache; - - const struct lfs_file_config *cfg; -} lfs_file_t; - -typedef struct lfs_superblock { - uint32_t version; - lfs_size_t block_size; - lfs_size_t block_count; - lfs_size_t name_max; - lfs_size_t file_max; - lfs_size_t attr_max; -} lfs_superblock_t; - -typedef struct lfs_gstate { - uint32_t tag; - lfs_block_t pair[2]; -} lfs_gstate_t; - -// The littlefs filesystem type -typedef struct lfs { - lfs_cache_t rcache; - lfs_cache_t pcache; - - lfs_block_t root[2]; - struct lfs_mlist { - struct lfs_mlist *next; - uint16_t id; - uint8_t type; - lfs_mdir_t m; - } *mlist; - uint32_t seed; - - lfs_gstate_t gstate; - lfs_gstate_t gdisk; - lfs_gstate_t gdelta; - - struct lfs_free { - lfs_block_t off; - lfs_block_t size; - lfs_block_t i; - lfs_block_t ack; - uint32_t *buffer; - } free; - - const struct lfs_config *cfg; - lfs_size_t name_max; - lfs_size_t file_max; - lfs_size_t attr_max; - -#ifdef LFS_MIGRATE - struct lfs1 *lfs1; -#endif -} lfs_t; - - -/// Filesystem functions /// - -// Format a block device with the littlefs -// -// Requires a littlefs object and config struct. This clobbers the littlefs -// object, and does not leave the filesystem mounted. The config struct must -// be zeroed for defaults and backwards compatibility. -// -// Returns a negative error code on failure. -int lfs_format(lfs_t *lfs, const struct lfs_config *config); - -// Mounts a littlefs -// -// Requires a littlefs object and config struct. Multiple filesystems -// may be mounted simultaneously with multiple littlefs objects. Both -// lfs and config must be allocated while mounted. The config struct must -// be zeroed for defaults and backwards compatibility. -// -// Returns a negative error code on failure. -int lfs_mount(lfs_t *lfs, const struct lfs_config *config); - -// Unmounts a littlefs -// -// Does nothing besides releasing any allocated resources. -// Returns a negative error code on failure. -int lfs_unmount(lfs_t *lfs); - -/// General operations /// - -// Removes a file or directory -// -// If removing a directory, the directory must be empty. -// Returns a negative error code on failure. -int lfs_remove(lfs_t *lfs, const char *path); - -// Rename or move a file or directory -// -// If the destination exists, it must match the source in type. -// If the destination is a directory, the directory must be empty. -// -// Returns a negative error code on failure. -int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); - -// Find info about a file or directory -// -// Fills out the info structure, based on the specified file or directory. -// Returns a negative error code on failure. -int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); - -// Get a custom attribute -// -// Custom attributes are uniquely identified by an 8-bit type and limited -// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than -// the buffer, it will be padded with zeros. If the stored attribute is larger, -// then it will be silently truncated. If no attribute is found, the error -// LFS_ERR_NOATTR is returned and the buffer is filled with zeros. -// -// Returns the size of the attribute, or a negative error code on failure. -// Note, the returned size is the size of the attribute on disk, irrespective -// of the size of the buffer. This can be used to dynamically allocate a buffer -// or check for existance. -lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, - uint8_t type, void *buffer, lfs_size_t size); - -// Set custom attributes -// -// Custom attributes are uniquely identified by an 8-bit type and limited -// to LFS_ATTR_MAX bytes. If an attribute is not found, it will be -// implicitly created. -// -// Returns a negative error code on failure. -int lfs_setattr(lfs_t *lfs, const char *path, - uint8_t type, const void *buffer, lfs_size_t size); - -// Removes a custom attribute -// -// If an attribute is not found, nothing happens. -// -// Returns a negative error code on failure. -int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); - - -/// File operations /// - -// Open a file -// -// The mode that the file is opened in is determined by the flags, which -// are values from the enum lfs_open_flags that are bitwise-ored together. -// -// Returns a negative error code on failure. -int lfs_file_open(lfs_t *lfs, lfs_file_t *file, - const char *path, int flags); - -// Open a file with extra configuration -// -// The mode that the file is opened in is determined by the flags, which -// are values from the enum lfs_open_flags that are bitwise-ored together. -// -// The config struct provides additional config options per file as described -// above. The config struct must be allocated while the file is open, and the -// config struct must be zeroed for defaults and backwards compatibility. -// -// Returns a negative error code on failure. -int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, - const char *path, int flags, - const struct lfs_file_config *config); - -// Close a file -// -// Any pending writes are written out to storage as though -// sync had been called and releases any allocated resources. -// -// Returns a negative error code on failure. -int lfs_file_close(lfs_t *lfs, lfs_file_t *file); - -// Synchronize a file on storage -// -// Any pending writes are written out to storage. -// Returns a negative error code on failure. -int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); - -// Read data from file -// -// Takes a buffer and size indicating where to store the read data. -// Returns the number of bytes read, or a negative error code on failure. -lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, - void *buffer, lfs_size_t size); - -// Write data to file -// -// Takes a buffer and size indicating the data to write. The file will not -// actually be updated on the storage until either sync or close is called. -// -// Returns the number of bytes written, or a negative error code on failure. -lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, - const void *buffer, lfs_size_t size); - -// Change the position of the file -// -// The change in position is determined by the offset and whence flag. -// Returns the new position of the file, or a negative error code on failure. -lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, - lfs_soff_t off, int whence); - -// Truncates the size of the file to the specified size -// -// Returns a negative error code on failure. -int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size); - -// Return the position of the file -// -// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) -// Returns the position of the file, or a negative error code on failure. -lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file); - -// Change the position of the file to the beginning of the file -// -// Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET) -// Returns a negative error code on failure. -int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); - -// Return the size of the file -// -// Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END) -// Returns the size of the file, or a negative error code on failure. -lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); - - -/// Directory operations /// - -// Create a directory -// -// Returns a negative error code on failure. -int lfs_mkdir(lfs_t *lfs, const char *path); - -// Open a directory -// -// Once open a directory can be used with read to iterate over files. -// Returns a negative error code on failure. -int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path); - -// Close a directory -// -// Releases any allocated resources. -// Returns a negative error code on failure. -int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir); - -// Read an entry in the directory -// -// Fills out the info structure, based on the specified file or directory. -// Returns a positive value on success, 0 at the end of directory, -// or a negative error code on failure. -int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info); - -// Change the position of the directory -// -// The new off must be a value previous returned from tell and specifies -// an absolute offset in the directory seek. -// -// Returns a negative error code on failure. -int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off); - -// Return the position of the directory -// -// The returned offset is only meant to be consumed by seek and may not make -// sense, but does indicate the current position in the directory iteration. -// -// Returns the position of the directory, or a negative error code on failure. -lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir); - -// Change the position of the directory to the beginning of the directory -// -// Returns a negative error code on failure. -int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); - - -/// Filesystem-level filesystem operations - -// Finds the current size of the filesystem -// -// Note: Result is best effort. If files share COW structures, the returned -// size may be larger than the filesystem actually is. -// -// Returns the number of allocated blocks, or a negative error code on failure. -lfs_ssize_t lfs_fs_size(lfs_t *lfs); - -// Traverse through all blocks in use by the filesystem -// -// The provided callback will be called with each block address that is -// currently in use by the filesystem. This can be used to determine which -// blocks are in use or how much of the storage is available. -// -// Returns a negative error code on failure. -int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); - -#ifdef LFS_MIGRATE -// Attempts to migrate a previous version of littlefs -// -// Behaves similarly to the lfs_format function. Attempts to mount -// the previous version of littlefs and update the filesystem so it can be -// mounted with the current version of littlefs. -// -// Requires a littlefs object and config struct. This clobbers the littlefs -// object, and does not leave the filesystem mounted. The config struct must -// be zeroed for defaults and backwards compatibility. -// -// Returns a negative error code on failure. -int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); -#endif - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/lib/LITTLEFS/src/lfs_util.c b/lib/LITTLEFS/src/lfs_util.c deleted file mode 100644 index 0b60e3b4..00000000 --- a/lib/LITTLEFS/src/lfs_util.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * lfs util functions - * - * Copyright (c) 2017, Arm Limited. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause - */ -#include "lfs_util.h" - -// Only compile if user does not provide custom config -#ifndef LFS_CONFIG - - -// Software CRC implementation with small lookup table -uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { - static const uint32_t rtable[16] = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, - }; - - const uint8_t *data = buffer; - - for (size_t i = 0; i < size; i++) { - crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; - crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; - } - - return crc; -} - - -#endif diff --git a/lib/LITTLEFS/src/lfs_util.h b/lib/LITTLEFS/src/lfs_util.h deleted file mode 100644 index dbb4c5ba..00000000 --- a/lib/LITTLEFS/src/lfs_util.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * lfs utility functions - * - * Copyright (c) 2017, Arm Limited. All rights reserved. - * SPDX-License-Identifier: BSD-3-Clause - */ -#ifndef LFS_UTIL_H -#define LFS_UTIL_H - -// Users can override lfs_util.h with their own configuration by defining -// LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). -// -// If LFS_CONFIG is used, none of the default utils will be emitted and must be -// provided by the config file. To start, I would suggest copying lfs_util.h -// and modifying as needed. -#ifdef LFS_CONFIG -#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) -#define LFS_STRINGIZE2(x) #x -#include LFS_STRINGIZE(LFS_CONFIG) -#else - -// System includes -#include -#include -#include -#include - -#ifndef LFS_NO_MALLOC -#include -#endif -#ifndef LFS_NO_ASSERT -#include -#endif -#if !defined(LFS_NO_DEBUG) || \ - !defined(LFS_NO_WARN) || \ - !defined(LFS_NO_ERROR) || \ - defined(LFS_YES_TRACE) -#include -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - - -// Macros, may be replaced by system specific wrappers. Arguments to these -// macros must not have side-effects as the macros can be removed for a smaller -// code footprint - -// Logging functions -#ifdef LFS_YES_TRACE -#define LFS_TRACE_(fmt, ...) \ - printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) -#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") -#else -#define LFS_TRACE(...) -#endif - -#ifndef LFS_NO_DEBUG -#define LFS_DEBUG_(fmt, ...) \ - printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) -#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") -#else -#define LFS_DEBUG(...) -#endif - -#ifndef LFS_NO_WARN -#define LFS_WARN_(fmt, ...) \ - printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) -#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") -#else -#define LFS_WARN(...) -#endif - -#ifndef LFS_NO_ERROR -#define LFS_ERROR_(fmt, ...) \ - printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) -#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") -#else -#define LFS_ERROR(...) -#endif - -// Runtime assertions -#ifndef LFS_NO_ASSERT -#define LFS_ASSERT(test) assert(test) -#else -#define LFS_ASSERT(test) -#endif - - -// Builtin functions, these may be replaced by more efficient -// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more -// expensive basic C implementation for debugging purposes - -// Min/max functions for unsigned 32-bit numbers -static inline uint32_t lfs_max(uint32_t a, uint32_t b) { - return (a > b) ? a : b; -} - -static inline uint32_t lfs_min(uint32_t a, uint32_t b) { - return (a < b) ? a : b; -} - -// Align to nearest multiple of a size -static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { - return a - (a % alignment); -} - -static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { - return lfs_aligndown(a + alignment-1, alignment); -} - -// Find the smallest power of 2 greater than or equal to a -static inline uint32_t lfs_npw2(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) - return 32 - __builtin_clz(a-1); -#else - uint32_t r = 0; - uint32_t s; - a -= 1; - s = (a > 0xffff) << 4; a >>= s; r |= s; - s = (a > 0xff ) << 3; a >>= s; r |= s; - s = (a > 0xf ) << 2; a >>= s; r |= s; - s = (a > 0x3 ) << 1; a >>= s; r |= s; - return (r | (a >> 1)) + 1; -#endif -} - -// Count the number of trailing binary zeros in a -// lfs_ctz(0) may be undefined -static inline uint32_t lfs_ctz(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) - return __builtin_ctz(a); -#else - return lfs_npw2((a & -a) + 1) - 1; -#endif -} - -// Count the number of binary ones in a -static inline uint32_t lfs_popc(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) - return __builtin_popcount(a); -#else - a = a - ((a >> 1) & 0x55555555); - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); - return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; -#endif -} - -// Find the sequence comparison of a and b, this is the distance -// between a and b ignoring overflow -static inline int lfs_scmp(uint32_t a, uint32_t b) { - return (int)(unsigned)(a - b); -} - -// Convert between 32-bit little-endian and native order -static inline uint32_t lfs_fromle32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - return a; -#elif !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - return __builtin_bswap32(a); -#else - return (((uint8_t*)&a)[0] << 0) | - (((uint8_t*)&a)[1] << 8) | - (((uint8_t*)&a)[2] << 16) | - (((uint8_t*)&a)[3] << 24); -#endif -} - -static inline uint32_t lfs_tole32(uint32_t a) { - return lfs_fromle32(a); -} - -// Convert between 32-bit big-endian and native order -static inline uint32_t lfs_frombe32(uint32_t a) { -#if !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) - return __builtin_bswap32(a); -#elif !defined(LFS_NO_INTRINSICS) && ( \ - (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ - (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) - return a; -#else - return (((uint8_t*)&a)[0] << 24) | - (((uint8_t*)&a)[1] << 16) | - (((uint8_t*)&a)[2] << 8) | - (((uint8_t*)&a)[3] << 0); -#endif -} - -static inline uint32_t lfs_tobe32(uint32_t a) { - return lfs_frombe32(a); -} - -// Calculate CRC-32 with polynomial = 0x04c11db7 -uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); - -// Allocate memory, only used if buffers are not provided to littlefs -// Note, memory must be 64-bit aligned -static inline void *lfs_malloc(size_t size) { -#ifndef LFS_NO_MALLOC - return malloc(size); -#else - (void)size; - return NULL; -#endif -} - -// Deallocate memory, only used if buffers are not provided to littlefs -static inline void lfs_free(void *p) { -#ifndef LFS_NO_MALLOC - free(p); -#else - (void)p; -#endif -} - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif -#endif diff --git a/lib/LITTLEFS/src/littlefs_api.c b/lib/LITTLEFS/src/littlefs_api.c deleted file mode 100644 index d823b487..00000000 --- a/lib/LITTLEFS/src/littlefs_api.c +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @file littlefs_api.c - * @brief Maps the HAL of esp_partition <-> littlefs - * @author Brian Pugh - * - * Copyright 2020 Brian Pugh - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#define ESP_LOCAL_LOG_LEVEL ESP_LOG_INFO - -#include "esp_log.h" -#include "esp_partition.h" -#include "esp_vfs.h" -#include "lfs.h" -#include "esp_littlefs.h" -#include "littlefs_api.h" - -static const char TAG[] = "esp_littlefs_api"; - -int littlefs_api_read(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size) { - esp_littlefs_t * efs = c->context; - size_t part_off = (block * c->block_size) + off; - esp_err_t err = esp_partition_read(efs->partition, part_off, buffer, size); - if (err) { - ESP_LOGE(TAG, "failed to read addr %08x, size %08x, err %d", part_off, size, err); - return LFS_ERR_IO; - } - return 0; -} - -int littlefs_api_prog(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size) { - esp_littlefs_t * efs = c->context; - size_t part_off = (block * c->block_size) + off; - esp_err_t err = esp_partition_write(efs->partition, part_off, buffer, size); - if (err) { - ESP_LOGE(TAG, "failed to write addr %08x, size %08x, err %d", part_off, size, err); - return LFS_ERR_IO; - } - return 0; -} - -int littlefs_api_erase(const struct lfs_config *c, lfs_block_t block) { - esp_littlefs_t * efs = c->context; - size_t part_off = block * c->block_size; - esp_err_t err = esp_partition_erase_range(efs->partition, part_off, c->block_size); - if (err) { - ESP_LOGE(TAG, "failed to erase addr %08x, size %08x, err %d", part_off, c->block_size, err); - return LFS_ERR_IO; - } - return 0; - -} - -int littlefs_api_sync(const struct lfs_config *c) { - /* Unnecessary for esp-idf */ - return 0; -} - diff --git a/lib/LITTLEFS/src/littlefs_api.h b/lib/LITTLEFS/src/littlefs_api.h deleted file mode 100644 index c1b2adc9..00000000 --- a/lib/LITTLEFS/src/littlefs_api.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef ESP_LITTLEFS_API_H__ -#define ESP_LITTLEFS_API_H__ - -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "esp_vfs.h" -#include "esp_partition.h" -#include "lfs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief a file descriptor - * That's also a singly linked list used for keeping tracks of all opened file descriptor - * - * Shortcomings/potential issues of 32-bit hash (when CONFIG_LITTLEFS_USE_ONLY_HASH) listed here: - * * unlink - If a different file is open that generates a hash collision, it will report an - * error that it cannot unlink an open file. - * * rename - If a different file is open that generates a hash collision with - * src or dst, it will report an error that it cannot rename an open file. - * Potential consequences: - * 1. A file cannot be deleted while a collision-geneating file is open. - * Worst-case, if the other file is always open during the lifecycle - * of your app, it's collision file cannot be deleted, which in the - * worst-case could cause storage-capacity issues. - * 2. Same as (1), but for renames - */ -typedef struct _vfs_littlefs_file_t { - lfs_file_t file; - uint32_t hash; - struct _vfs_littlefs_file_t * next; /*!< Pointer to next file in Singly Linked List */ -#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH - char * path; -#endif -} vfs_littlefs_file_t; - -/** - * @brief littlefs definition structure - */ -typedef struct { - lfs_t *fs; /*!< Handle to the underlying littlefs */ - SemaphoreHandle_t lock; /*!< FS lock */ - const esp_partition_t* partition; /*!< The partition on which littlefs is located */ - char base_path[ESP_VFS_PATH_MAX+1]; /*!< Mount point */ - - struct lfs_config cfg; /*!< littlefs Mount configuration */ - - vfs_littlefs_file_t *file; /*!< Singly Linked List of files */ - - vfs_littlefs_file_t **cache; /*!< A cache of pointers to the opened files */ - uint16_t cache_size; /*!< The cache allocated size (in pointers) */ - uint16_t fd_count; /*!< The count of opened file descriptor used to speed up computation */ -} esp_littlefs_t; - -/** - * @brief Read a region in a block. - * - * Negative error codes are propogated to the user. - * - * @return errorcode. 0 on success. - */ -int littlefs_api_read(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, void *buffer, lfs_size_t size); - -/** - * @brief Program a region in a block. - * - * The block must have previously been erased. - * Negative error codes are propogated to the user. - * May return LFS_ERR_CORRUPT if the block should be considered bad. - * - * @return errorcode. 0 on success. - */ -int littlefs_api_prog(const struct lfs_config *c, lfs_block_t block, - lfs_off_t off, const void *buffer, lfs_size_t size); - -/** - * @brief Erase a block. - * - * A block must be erased before being programmed. - * The state of an erased block is undefined. - * Negative error codes are propogated to the user. - * May return LFS_ERR_CORRUPT if the block should be considered bad. - * @return errorcode. 0 on success. - */ -int littlefs_api_erase(const struct lfs_config *c, lfs_block_t block); - -/** - * @brief Sync the state of the underlying block device. - * - * Negative error codes are propogated to the user. - * - * @return errorcode. 0 on success. - */ -int littlefs_api_sync(const struct lfs_config *c); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/ModbusMaster/.github/ISSUE_TEMPLATE.md b/lib/ModbusMaster/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 7ae83e53..00000000 --- a/lib/ModbusMaster/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,66 +0,0 @@ - - - -### ModbusMaster version -[Version of the project where you are encountering the issue] - -### Arduino IDE version -[Version of Arduino IDE in your environment] - -### Arduino Hardware -[Hardware information, including board and processor] - -### Platform Details -[Operating system distribution and release version] - ---- - -### Scenario: -[What you are trying to achieve and you can't?] - -### Steps to Reproduce: -[If you are filing an issue what are the things we need to do in order to repro your problem? How are you using this project or any resources it includes?] - -### Expected Result: -[What are you expecting to happen as the consequence of above reproduction steps?] - -### Actual Result: -[What actually happens after the reproduction steps? Include the error output or a link to a gist if possible.] - ---- - -### Feature Request - -#### Narrative: - -```` text -As a [role] -I want [feature] -So that [benefit] -```` - -#### Acceptance Criteria: - -```` text -Scenario 1: Title -Given [context] - And [some more context]... -When [event] -Then [outcome] - And [another outcome]... -```` diff --git a/lib/ModbusMaster/.github/PULL_REQUEST_TEMPLATE.md b/lib/ModbusMaster/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 1039f974..00000000 --- a/lib/ModbusMaster/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,37 +0,0 @@ - -### Description -[Describe what this change achieves] - -### Issues Resolved -[List any existing issues this PR resolves; include Fixes #xxx or Closes #xxx (where xxx is issue number)] - -### Check List - -General - -- [ ] Code follows coding style defined in STYLE.md -- [ ] Doxygen comments are included inline with code -- [ ] No unnecessary whitespace; check with `git diff --check` before committing. - -The following have been modified to reflect new features, if warranted - -- [ ] README.md -- [ ] keywords.txt (use tabs as whitespace separators) -- [ ] library.properties -- [ ] examples/ - update or create new ones, as warranted - -The following have **NOT** been modified - -- [ ] doc/ - will be updated upon versioned release -- [ ] .ruby-gemset -- [ ] .ruby-version -- [ ] CHANGELOG.md - will be updated upon versioned release (HISTORY.md is deprecated) -- [ ] Gemfile -- [ ] LICENSE -- [ ] VERSION - will be updated upon versioned release diff --git a/lib/ModbusMaster/.github_changelog_generator b/lib/ModbusMaster/.github_changelog_generator deleted file mode 100644 index 1a846259..00000000 --- a/lib/ModbusMaster/.github_changelog_generator +++ /dev/null @@ -1,8 +0,0 @@ -add_issues_wo_labels=false -add_pr_wo_labels=false -enhancement-labels=Type: Enhancement -bug-labels=Type: Bug -exclude-labels=Type: Question -header=# ModbusMaster CHANGELOG -include-labels=Type: Bug,Type: Enhancement,Type: Feature Request,Type: Maintenance -future-release=Unreleased diff --git a/lib/ModbusMaster/.gitignore b/lib/ModbusMaster/.gitignore deleted file mode 100644 index d52f89eb..00000000 --- a/lib/ModbusMaster/.gitignore +++ /dev/null @@ -1,56 +0,0 @@ -#---------------------------------------------------------------- ModbusMaster -doc/html/ -doc/latex/ - - -#-------------- https://github.com/github/gitignore/blob/master/Ruby.gitignore -*.gem -*.rbc -/.config -/coverage/ -/InstalledFiles -/pkg/ -/spec/reports/ -/spec/examples.txt -/test/tmp/ -/test/version_tmp/ -/tmp/ - -# Used by dotenv library to load environment variables. -# .env - -## Specific to RubyMotion: -.dat* -.repl_history -build/ -*.bridgesupport -build-iPhoneOS/ -build-iPhoneSimulator/ - -## Specific to RubyMotion (use of CocoaPods): -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# vendor/Pods/ - -## Documentation cache and generated files: -/.yardoc/ -/_yardoc/ -/doc/ -/rdoc/ - -## Environment normalization: -/.bundle/ -/vendor/bundle -/lib/bundler/man/ - -# for a library or gem, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# Gemfile.lock -# .ruby-version -# .ruby-gemset - -# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: -.rvmrc diff --git a/lib/ModbusMaster/.ruby-gemset b/lib/ModbusMaster/.ruby-gemset deleted file mode 100644 index b47d0eb8..00000000 --- a/lib/ModbusMaster/.ruby-gemset +++ /dev/null @@ -1 +0,0 @@ -global diff --git a/lib/ModbusMaster/.ruby-version b/lib/ModbusMaster/.ruby-version deleted file mode 100644 index 2bf1c1cc..00000000 --- a/lib/ModbusMaster/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.3.1 diff --git a/lib/ModbusMaster/.travis.yml b/lib/ModbusMaster/.travis.yml deleted file mode 100644 index a9cbf868..00000000 --- a/lib/ModbusMaster/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: python - -python: - - 2.7 - -sudo: false - -cache: - directories: - - ~/.platformio - -# update Makefile if target boards added -env: - - PLATFORMIO_BOARD=uno - - PLATFORMIO_BOARD=due - - PLATFORMIO_BOARD=huzzah - - PLATFORMIO_BOARD=genuino101 - - PLATFORMIO_BOARD=teensy31 - -install: - - pip install -U platformio - -before_script: - - env - - echo $HOME - - echo $TRAVIS_BUILD_DIR - - ls -al $PWD - -script: - - make build diff --git a/lib/ModbusMaster/CHANGELOG.md b/lib/ModbusMaster/CHANGELOG.md deleted file mode 100644 index c5d1fe02..00000000 --- a/lib/ModbusMaster/CHANGELOG.md +++ /dev/null @@ -1,141 +0,0 @@ -# ModbusMaster CHANGELOG - -## [v2.0.0](https://github.com/4-20ma/ModbusMaster/tree/v2.0.0) (2016-09-24) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v1.0.0...v2.0.0) - -**Implemented enhancements:** - -- BREAK: Update library to match IDE 1.5 spec v2.1 [\#81](https://github.com/4-20ma/ModbusMaster/pull/81) ([4-20ma](https://github.com/4-20ma)) -- Use platformio to build multiple boards [\#79](https://github.com/4-20ma/ModbusMaster/pull/79) ([4-20ma](https://github.com/4-20ma)) - -**Closed issues:** - -- Use platformio to build against multiple boards [\#78](https://github.com/4-20ma/ModbusMaster/issues/78) -- Add ruby files to .gitignore [\#75](https://github.com/4-20ma/ModbusMaster/issues/75) -- Reorder Installation section of README [\#73](https://github.com/4-20ma/ModbusMaster/issues/73) -- Update README [\#71](https://github.com/4-20ma/ModbusMaster/issues/71) -- Rename HISTORY to CHANGELOG [\#47](https://github.com/4-20ma/ModbusMaster/issues/47) -- Update library to match 1.5 specification [\#14](https://github.com/4-20ma/ModbusMaster/issues/14) - -**Merged pull requests:** - -- Use relative path to examples [\#80](https://github.com/4-20ma/ModbusMaster/pull/80) ([4-20ma](https://github.com/4-20ma)) -- Add files to .gitignore [\#76](https://github.com/4-20ma/ModbusMaster/pull/76) ([4-20ma](https://github.com/4-20ma)) -- Reorder installation section of README [\#74](https://github.com/4-20ma/ModbusMaster/pull/74) ([4-20ma](https://github.com/4-20ma)) -- Update README [\#72](https://github.com/4-20ma/ModbusMaster/pull/72) ([4-20ma](https://github.com/4-20ma)) -- Automate CHANGELOG generation [\#68](https://github.com/4-20ma/ModbusMaster/pull/68) ([4-20ma](https://github.com/4-20ma)) - -## [v1.0.0](https://github.com/4-20ma/ModbusMaster/tree/v1.0.0) (2016-09-12) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.11.0...v1.0.0) - -**Implemented enhancements:** - -- Add LICENSE, convert project to Apache 2.0 [\#67](https://github.com/4-20ma/ModbusMaster/pull/67) ([4-20ma](https://github.com/4-20ma)) -- Add example sketch for half-duplex RS485 [\#66](https://github.com/4-20ma/ModbusMaster/pull/66) ([kintel](https://github.com/kintel)) -- Add continuous integration testing with Travis CI [\#63](https://github.com/4-20ma/ModbusMaster/pull/63) ([4-20ma](https://github.com/4-20ma)) -- Disable \_\_MODBUSMASTER\_DEBUG\_\_ mode by default [\#43](https://github.com/4-20ma/ModbusMaster/pull/43) ([kintel](https://github.com/kintel)) - -**Closed issues:** - -- Fix documentation references in ModbusMaster.h, .cpp [\#69](https://github.com/4-20ma/ModbusMaster/issues/69) -- Clean up template wording [\#64](https://github.com/4-20ma/ModbusMaster/issues/64) -- Add Label section to CONTRIBUTING [\#60](https://github.com/4-20ma/ModbusMaster/issues/60) -- Update README contact information [\#58](https://github.com/4-20ma/ModbusMaster/issues/58) -- Add continuous integration testing with travis [\#55](https://github.com/4-20ma/ModbusMaster/issues/55) -- Add Code of Conduct [\#54](https://github.com/4-20ma/ModbusMaster/issues/54) -- Create PULL\_REQUEST\_TEMPLATE [\#49](https://github.com/4-20ma/ModbusMaster/issues/49) -- Create ISSUE\_TEMPLATE [\#48](https://github.com/4-20ma/ModbusMaster/issues/48) -- Change license to Apache 2.0 [\#45](https://github.com/4-20ma/ModbusMaster/issues/45) -- Set \_\_MODBUSMASTER\_DEBUG\_\_ to 0 by default [\#35](https://github.com/4-20ma/ModbusMaster/issues/35) -- Pass Stream object instead of integer reference [\#17](https://github.com/4-20ma/ModbusMaster/issues/17) - -**Merged pull requests:** - -- Add documentation cross-references [\#70](https://github.com/4-20ma/ModbusMaster/pull/70) ([4-20ma](https://github.com/4-20ma)) -- Clean up ISSUE/PULL\_REQUEST templates [\#65](https://github.com/4-20ma/ModbusMaster/pull/65) ([4-20ma](https://github.com/4-20ma)) -- Add initial .travis.yml configuration [\#62](https://github.com/4-20ma/ModbusMaster/pull/62) ([4-20ma](https://github.com/4-20ma)) -- Add label guidance to CONTRIBUTING [\#61](https://github.com/4-20ma/ModbusMaster/pull/61) ([4-20ma](https://github.com/4-20ma)) -- Update README contact information [\#59](https://github.com/4-20ma/ModbusMaster/pull/59) ([4-20ma](https://github.com/4-20ma)) -- Add email address to CODE\_OF\_CONDUCT [\#57](https://github.com/4-20ma/ModbusMaster/pull/57) ([4-20ma](https://github.com/4-20ma)) -- Add CODE\_OF\_CONDUCT [\#56](https://github.com/4-20ma/ModbusMaster/pull/56) ([4-20ma](https://github.com/4-20ma)) -- Add initial PULL\_REQUEST\_TEMPLATE [\#53](https://github.com/4-20ma/ModbusMaster/pull/53) ([4-20ma](https://github.com/4-20ma)) -- Clarify instructions in ISSUE\_TEMPLATE [\#52](https://github.com/4-20ma/ModbusMaster/pull/52) ([4-20ma](https://github.com/4-20ma)) -- Add ISSUE\_TEMPLATE title reqs, separator lines [\#51](https://github.com/4-20ma/ModbusMaster/pull/51) ([4-20ma](https://github.com/4-20ma)) -- Add initial ISSUE\_TEMPLATE [\#50](https://github.com/4-20ma/ModbusMaster/pull/50) ([4-20ma](https://github.com/4-20ma)) -- Add preTransmission\(\), postTransmission\(\) for half-duplex [\#44](https://github.com/4-20ma/ModbusMaster/pull/44) ([kintel](https://github.com/kintel)) -- Add STYLE coding style guide [\#29](https://github.com/4-20ma/ModbusMaster/pull/29) ([4-20ma](https://github.com/4-20ma)) - -## [v0.11.0](https://github.com/4-20ma/ModbusMaster/tree/v0.11.0) (2015-05-22) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.10.3...v0.11.0) - -**Implemented enhancements:** - -- Update architecture switch [\#28](https://github.com/4-20ma/ModbusMaster/pull/28) ([4-20ma](https://github.com/4-20ma)) - -**Closed issues:** - -- Update architecture switch to match Arduino convention [\#27](https://github.com/4-20ma/ModbusMaster/issues/27) -- Request timeout is impatient [\#3](https://github.com/4-20ma/ModbusMaster/issues/3) - -## [v0.10.3](https://github.com/4-20ma/ModbusMaster/tree/v0.10.3) (2015-05-22) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.10.2...v0.10.3) - -**Closed issues:** - -- Inconsistent Doxygen comments [\#25](https://github.com/4-20ma/ModbusMaster/issues/25) -- Replace C macros with inline functions [\#18](https://github.com/4-20ma/ModbusMaster/issues/18) - -**Merged pull requests:** - -- Adjust doxygen comments to be consistent [\#26](https://github.com/4-20ma/ModbusMaster/pull/26) ([4-20ma](https://github.com/4-20ma)) -- Replace C macros w/inline functions [\#24](https://github.com/4-20ma/ModbusMaster/pull/24) ([4-20ma](https://github.com/4-20ma)) - -## [v0.10.2](https://github.com/4-20ma/ModbusMaster/tree/v0.10.2) (2015-05-22) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.9.1...v0.10.2) - -**Implemented enhancements:** - -- Implement CRC16 for SAM3X8E microprocessor [\#11](https://github.com/4-20ma/ModbusMaster/pull/11) ([4-20ma](https://github.com/4-20ma)) -- Add rx flush, change response timeout to 2000 ms [\#10](https://github.com/4-20ma/ModbusMaster/pull/10) ([agprimatic](https://github.com/agprimatic)) - -**Fixed bugs:** - -- Fix documentation build error [\#23](https://github.com/4-20ma/ModbusMaster/pull/23) ([4-20ma](https://github.com/4-20ma)) -- Work around HardwareSerial for SAM3 micro [\#12](https://github.com/4-20ma/ModbusMaster/pull/12) ([4-20ma](https://github.com/4-20ma)) - -**Merged pull requests:** - -- Update pointers to match C++ convention [\#22](https://github.com/4-20ma/ModbusMaster/pull/22) ([4-20ma](https://github.com/4-20ma)) -- Rename markdown file extensions [\#21](https://github.com/4-20ma/ModbusMaster/pull/21) ([4-20ma](https://github.com/4-20ma)) - -## [v0.9.1](https://github.com/4-20ma/ModbusMaster/tree/v0.9.1) (2013-01-02) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.9...v0.9.1) - -## [v0.9](https://github.com/4-20ma/ModbusMaster/tree/v0.9) (2011-12-27) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.8...v0.9) - -## [v0.8](https://github.com/4-20ma/ModbusMaster/tree/v0.8) (2011-11-09) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.7...v0.8) - -## [v0.7](https://github.com/4-20ma/ModbusMaster/tree/v0.7) (2010-02-10) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.6...v0.7) - -## [v0.6](https://github.com/4-20ma/ModbusMaster/tree/v0.6) (2010-02-05) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.5...v0.6) - -## [v0.5](https://github.com/4-20ma/ModbusMaster/tree/v0.5) (2010-01-30) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.4...v0.5) - -## [v0.4](https://github.com/4-20ma/ModbusMaster/tree/v0.4) (2010-01-30) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.3...v0.4) - -## [v0.3](https://github.com/4-20ma/ModbusMaster/tree/v0.3) (2010-01-29) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.2...v0.3) - -## [v0.2](https://github.com/4-20ma/ModbusMaster/tree/v0.2) (2010-01-26) -[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.1...v0.2) - -## [v0.1](https://github.com/4-20ma/ModbusMaster/tree/v0.1) (2010-01-25) - - -\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/lib/ModbusMaster/CODE_OF_CONDUCT.md b/lib/ModbusMaster/CODE_OF_CONDUCT.md deleted file mode 100644 index eca5ac5b..00000000 --- a/lib/ModbusMaster/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,78 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project owner at 4-20ma@wvfans.net. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Project Maintainers - -- Doc Walker <<4-20ma@wvfans.net>> - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/lib/ModbusMaster/CONTRIBUTING.md b/lib/ModbusMaster/CONTRIBUTING.md deleted file mode 100644 index 0bcf721a..00000000 --- a/lib/ModbusMaster/CONTRIBUTING.md +++ /dev/null @@ -1,58 +0,0 @@ -Contributing -============ - -- Fork, then clone the repo: - ```` - git clone git@github.com:your_username/ModbusMaster.git - ```` - -- Create a topic branch from where you want to base your work - - This is usually the master branch - - Only target release branches if you are certain your fix must be on that branch - - To quickly create a topic branch based on master; `git checkout -b fix/master/my_contribution master`. Please avoid working directly on the `master` branch. - -- Follow the [style guide](https://github.com/4-20ma/ModbusMaster/blob/master/STYLE.md) - -- Test your change - - ```` bash - $ make - ```` - - Project must build successfully using `make` in order for contribution to be considered. - -- Make commits of logical units - - Check for unnecessary whitespace with `git diff --check` before committing - - Each commit should represent one atomic change and should stand on its own - - Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) - -- Push to your fork and [submit a pull request](https://github.com/4-20ma/ModbusMaster/compare/) -- [Code of conduct](https://github.com/4-20ma/ModbusMaster/blob/master/CODE_OF_CONDUCT.md) - -### Labels - -Project maintainers assign labels to Issues and Pull Requests (PRs) to categorize, prioritize, and provide status. The following guidelines and conventions are used in this project: - -#### Type - -- `Bug` - existing code does not behave as described in the project documentation; _requires_ clear test case and be _reproducible_ by project maintainer -- `Enhancement` - improvement to an existing feature (Issue or Pull Request) -- `Feature Requst` - new functionality; _requires_ a well-written, clear user story (Issue) -- `Maintenance` - minor administrative change that does not provide enhancement or introduce new feature -- `Question` - self-explanatory - -#### Priority - -- `Low` - default priority; new issues generally start here -- `Medium` - issues are escalated, depending on severity of the issue -- `High` - issues are escalated, depending on severity of the issue -- `Critical` - these issues are to be resolved ahead of any other - -#### Status - -- `Abandoned` - issue/PR closed due to inactivity -- `Blocked` - issue/PR will not be resolved/merged (some projects label these items as `wontfix`; include explanation in issue/PR) -- `In Progress` - issue has been assigned and is actively being addressed; re-label issue `On Hold` with explanation if there will be a significant delay -- `Maintainer Review Needed` - last step prior to merge; PR passes continuous integration tests and is able to be cleanly merged - awaiting review for style, code cleanliness, etc. -- `On Hold` - implementation delayed; provide explanation in issue/PR -- `Pending Contributor Response` - issue/PR closed after 14 days of inactivity (re-label `Abandoned` at closure) diff --git a/lib/ModbusMaster/Gemfile b/lib/ModbusMaster/Gemfile deleted file mode 100644 index 9ed64664..00000000 --- a/lib/ModbusMaster/Gemfile +++ /dev/null @@ -1,30 +0,0 @@ -# encoding: utf-8 -# Gemfile style guide derived from: -# http://mcdowall.info/posts/gemfile-best-practices-and-discourse/ - -# Use `bundle install` after changing this file -# `bundle update [gemname]` to force update of gem -# `bundle show [gemname]` to see where a bundled gem is installed -# `bundle open [gemname]` to edit a bundled gem -# `bundle package` to add gem to vendor/cache - -source 'https://rubygems.org' - - -# place gems sourced from github.com in this section _________________________ - - -# place gems sourced from a project path in this section _____________________ - - -# place general project gems in this section (alphabetical order) ____________ -gem 'git', '~> 1.3.0' # git management -gem 'github_changelog_generator', '~> 1.13.1' -gem 'rake', '~> 11.2.2' -gem 'version', '~> 1.0.0' # version management gem - - -# place gems related to test/specs in this section (alphabetical order) ______ - - -# place gems related to development in this section (alphabetical order) _____ diff --git a/lib/ModbusMaster/Gemfile.lock b/lib/ModbusMaster/Gemfile.lock deleted file mode 100644 index cdec1471..00000000 --- a/lib/ModbusMaster/Gemfile.lock +++ /dev/null @@ -1,47 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.4.0) - colorize (0.8.1) - descendants_tracker (0.0.4) - thread_safe (~> 0.3, >= 0.3.1) - faraday (0.9.2) - multipart-post (>= 1.2, < 3) - git (1.3.0) - github_api (0.14.5) - addressable (~> 2.4.0) - descendants_tracker (~> 0.0.4) - faraday (~> 0.8, < 0.10) - hashie (>= 3.4) - oauth2 (~> 1.0) - github_changelog_generator (1.13.1) - colorize (~> 0.7) - github_api (~> 0.12) - rake (>= 10.0) - hashie (3.4.4) - jwt (1.5.4) - multi_json (1.12.1) - multi_xml (0.5.5) - multipart-post (2.0.0) - oauth2 (1.2.0) - faraday (>= 0.8, < 0.10) - jwt (~> 1.0) - multi_json (~> 1.3) - multi_xml (~> 0.5) - rack (>= 1.2, < 3) - rack (2.0.1) - rake (11.2.2) - thread_safe (0.3.5) - version (1.0.0) - -PLATFORMS - ruby - -DEPENDENCIES - git (~> 1.3.0) - github_changelog_generator (~> 1.13.1) - rake (~> 11.2.2) - version (~> 1.0.0) - -BUNDLED WITH - 1.12.1 diff --git a/lib/ModbusMaster/LICENSE b/lib/ModbusMaster/LICENSE deleted file mode 100644 index 261eeb9e..00000000 --- a/lib/ModbusMaster/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/lib/ModbusMaster/Makefile b/lib/ModbusMaster/Makefile deleted file mode 100644 index fba3392d..00000000 --- a/lib/ModbusMaster/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -#-------------------------------------------------------------------- settings -FIND := find -DIR := examples -CRITERIA := \( -name "*.ino" -o -name "*.pde" \) -EACH_EXAMPLE := $(FIND) $(DIR) $(CRITERIA) -exec -BUILD := platformio ci -LIB := src - -#--------------------------------------------------------------------- targets -# update .travis.yml if target boards added -all: uno due huzzah genuino101 teensy31 - -uno due huzzah genuino101 teensy31: - PLATFORMIO_BOARD=$@ $(MAKE) build - -build: - $(EACH_EXAMPLE) $(BUILD) --board=$(PLATFORMIO_BOARD) --lib=$(LIB) {} \; - -.PHONY: all uno due huzzah genuino101 teensy31 build diff --git a/lib/ModbusMaster/README.md b/lib/ModbusMaster/README.md deleted file mode 100644 index 5c5719e4..00000000 --- a/lib/ModbusMaster/README.md +++ /dev/null @@ -1,167 +0,0 @@ -# ModbusMaster -[![GitHub release](https://img.shields.io/github/release/4-20ma/ModbusMaster.svg?maxAge=3600)][GitHub release] -[![Travis](https://img.shields.io/travis/4-20ma/ModbusMaster.svg?maxAge=3600)][Travis] -[![license](https://img.shields.io/github/license/4-20ma/ModbusMaster.svg?maxAge=3600)][license] -[![code of conduct](https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-blue.svg?maxAge=3600)][code of conduct] - -[GitHub release]: https://github.com/4-20ma/ModbusMaster -[Travis]: https://travis-ci.org/4-20ma/ModbusMaster -[license]: LICENSE -[code of conduct]: CODE_OF_CONDUCT.md - - -## Overview -This is an Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol). - - -## Features -The following Modbus functions are available: - -Discrete Coils/Flags - - - 0x01 - Read Coils - - 0x02 - Read Discrete Inputs - - 0x05 - Write Single Coil - - 0x0F - Write Multiple Coils - -Registers - - - 0x03 - Read Holding Registers - - 0x04 - Read Input Registers - - 0x06 - Write Single Register - - 0x10 - Write Multiple Registers - - 0x16 - Mask Write Register - - 0x17 - Read Write Multiple Registers - -Both full-duplex and half-duplex RS232/485 transceivers are supported. Callback functions are provided to toggle Data Enable (DE) and Receiver Enable (/RE) pins. - - -## Installation - -#### Library Manager -Install the library into your Arduino IDE using the Library Manager (available from IDE version 1.6.2). Open the IDE and click Sketch > Include Library > Manage Libraries… - -Scroll or search for `ModbusMaster`, then select the version of the library you want to install. Quit/re-launch the IDE to refresh the list; new versions are automatically added to the list, once released on GitHub. - -Refer to Arduino Tutorials > Libraries [Using the Library Manager](https://www.arduino.cc/en/Guide/Libraries#toc3). - -#### Zip Library -Refer to Arduino Tutorials > Libraries [Importing a .zip Library](https://www.arduino.cc/en/Guide/Libraries#toc4). - -#### Manual -Refer to Arduino Tutorials > Libraries [Manual Installation](https://www.arduino.cc/en/Guide/Libraries#toc5). - - -## Hardware -This library has been tested with an Arduino [Duemilanove](http://www.arduino.cc/en/Main/ArduinoBoardDuemilanove), PHOENIX CONTACT [nanoLine](https://www.phoenixcontact.com/online/portal/us?1dmy&urile=wcm%3apath%3a/usen/web/main/products/subcategory_pages/standard_logic_modules_p-21-03-03/3329dd38-7c6a-46e1-8260-b9208235d6fe/3329dd38-7c6a-46e1-8260-b9208235d6fe) controller, connected via RS485 using a Maxim [MAX488EPA](http://www.maxim-ic.com/quick_view2.cfm/qv_pk/1111) transceiver. - - -## Caveats -Conforms to Arduino IDE 1.5 Library Specification v2.1 which requires Arduino IDE >= 1.5. - -Arduinos prior to the Mega have one serial port which must be connected to USB (FTDI) for uploading sketches and to the RS232/485 device/network for running sketches. You will need to disconnect pin 0 (RX) while uploading sketches. After a successful upload, you can reconnect pin 0. - - -## Support -Please [submit an issue](https://github.com/4-20ma/ModbusMaster/issues) for all questions, bug reports, and feature requests. Email requests will be politely redirected to the issue tracker so others may contribute to the discussion and requestors get a more timely response. - - -## Example -The library contains a few sketches that demonstrate use of the `ModbusMaster` library. You can find these in the [examples](https://github.com/4-20ma/ModbusMaster/tree/master/examples) folder. - -``` cpp -/* - - Basic.pde - example using ModbusMaster library - - Library:: ModbusMaster - Author:: Doc Walker <4-20ma@wvfans.net> - - Copyright:: 2009-2016 Doc Walker - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -#include - - -// instantiate ModbusMaster object -ModbusMaster node; - - -void setup() -{ - // use Serial (port 0); initialize Modbus communication baud rate - Serial.begin(19200); - - // communicate with Modbus slave ID 2 over Serial (port 0) - node.begin(2, Serial); -} - - -void loop() -{ - static uint32_t i; - uint8_t j, result; - uint16_t data[6]; - - i++; - - // set word 0 of TX buffer to least-significant word of counter (bits 15..0) - node.setTransmitBuffer(0, lowWord(i)); - - // set word 1 of TX buffer to most-significant word of counter (bits 31..16) - node.setTransmitBuffer(1, highWord(i)); - - // slave: write TX buffer to (2) 16-bit registers starting at register 0 - result = node.writeMultipleRegisters(0, 2); - - // slave: read (6) 16-bit registers starting at register 2 to RX buffer - result = node.readHoldingRegisters(2, 6); - - // do something with data if read is successful - if (result == node.ku8MBSuccess) - { - for (j = 0; j < 6; j++) - { - data[j] = node.getResponseBuffer(j); - } - } -} -``` - -_Project inspired by [Arduino Modbus Master](http://sites.google.com/site/jpmzometa/arduino-mbrt/arduino-modbus-master)._ - - -## License & Authors - -- Author:: Doc Walker ([4-20ma@wvfans.net](mailto:4-20ma@wvfans.net)) -- Author:: Ag Primatic ([agprimatic@gmail.com](mailto:agprimatic@gmail.com)) -- Author:: Marius Kintel ([marius@kintel.net](mailto:marius@kintel.net)) - -``` -Copyright:: 2009-2016 Doc Walker - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -``` diff --git a/lib/ModbusMaster/Rakefile b/lib/ModbusMaster/Rakefile deleted file mode 100644 index b0619918..00000000 --- a/lib/ModbusMaster/Rakefile +++ /dev/null @@ -1,218 +0,0 @@ -# encoding: utf-8 -# -# Copyright:: 2009-2016 Doc Walker -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require 'git' -require 'github_changelog_generator/task' -require 'rake' -require 'rubygems' -require 'rake/version_task' # gem install version -require 'version' - -# requires additional packages on MacOS (including Homebrew): -# $ /usr/bin/ruby -e "$(curl -fsSL \ -# https://raw.githubusercontent.com/Homebrew/install/master/install)" -# $ brew install doxygen # generates documentation from source code -# $ brew cask install mactex # MacTeX - -Rake::VersionTask.new do |task| - # prevent auto-commit on version bump - task.with_git = false -end - -# adjust as appropriate -CWD = File.expand_path(File.dirname(__FILE__)) -DOXYFILE = 'Doxyfile' -GITHUB_USERNAME = '4-20ma' -GITHUB_REPO = 'ModbusMaster' -HEADER_FILE = "#{GITHUB_REPO}.h" -CHANGELOG_FILE = 'CHANGELOG.md' -PROPERTIES_FILE = 'library.properties' -VERSION_FILE = Version.version_file('').basename.to_s - - -task :default => :info - -desc 'Display instructions for public release' -task :info do - puts <<-EOF.gsub(/^\s{2}/, '') - - Instructions for public release - - - Update version, as appropriate: - - $ rake version:bump # or - $ rake version:bump:minor # or - $ rake version:bump:major # or - edit 'VERSION' file directly - - - Prepare release date, 'CHANGELOG.md' file, documentation: - - $ rake prepare - - - Review changes to 'CHANGELOG.md' file - This file is assembled using git commit messages; review for completeness. - - - Review html documentation files - These files are assembled using source code Doxygen tags; review for - for completeness. - - - Add & commit source files, tag, push to origin/master; - add & commit documentation files, push to origin/gh-pages: - - $ rake release - - EOF -end # task :info - - -desc "Prepare #{CHANGELOG_FILE} for release" -task :prepare => 'prepare:default' - -namespace :prepare do - task :default => [ - :release_date, - :library_properties, - :changelog, - :documentation - ] - - desc 'Prepare documentation' - task :documentation do - version = Version.current.to_s - - # update parameters in Doxyfile - file = File.join(CWD, 'doc', DOXYFILE) - - contents = IO.read(file) - contents.sub!(/(^PROJECT_NUMBER\s*=)(.*)$/) do |match| - "#{$1} v#{version}" - end # contents.sub!(...) - IO.write(file, contents) - - # chdir to doc/ and call doxygen to update documentation - Dir.chdir(to = File.join(CWD, 'doc')) - system('doxygen', DOXYFILE) - - # chdir to doc/latex and call doxygen to update documentation - Dir.chdir(from = File.join(CWD, 'doc', 'latex')) - system('make') - - # move/rename file to 'extras/GITHUB_REPO reference-x.y.pdf' - to = File.join(CWD, 'extras') - FileUtils.mv(File.join(from, 'refman.pdf'), - File.join(to, "#{GITHUB_REPO} reference-#{version}.pdf")) - end # task :documentation - - desc 'Prepare release history' - GitHubChangelogGenerator::RakeTask.new(:changelog) do |config| - config.add_issues_wo_labels = false - config.add_pr_wo_labels = false - config.enhancement_labels = [ - 'Type: Enhancement' - ] - config.bug_labels = ['Type: Bug'] - config.exclude_labels = ['Type: Question'] - config.header = '# ModbusMaster CHANGELOG' - config.include_labels = [ - 'Type: Bug', - 'Type: Enhancement', - 'Type: Feature Request', - 'Type: Maintenance' - ] - # config.since_tag = '0.1.0' - config.future_release = "v#{Version.current.to_s}" - config.user = GITHUB_USERNAME - config.project = GITHUB_REPO - end # GitHubChangelogGenerator::RakeTask.new - - desc 'Update version in library properties file' - task :library_properties do - version = Version.current.to_s - - file = File.join(CWD, PROPERTIES_FILE) - - contents = IO.read(file) - contents.sub!(/(version=\s*)(.*)$/) do |match| - "#{$1}#{version}" - end # contents.sub!(...) - IO.write(file, contents) - end # task :library_properties - - desc 'Update release date in header file' - task :release_date do - file = File.join(CWD, 'src', HEADER_FILE) - - contents = IO.read(file) - contents.sub!(/(\\date\s*)(.*)$/) do |match| - "#{$1}#{Time.now.strftime('%-d %b %Y')}" - end # contents.sub!(...) - IO.write(file, contents) - end # task :release_date - -end # namespace :prepare - - -desc 'Release source & documentation' -task :release => 'release:default' - -namespace :release do - task :default => [:source, :documentation] - - desc 'Commit documentation changes related to version bump' - task :documentation do - version = Version.current.to_s - cwd = File.expand_path(File.join(File.dirname(__FILE__), 'doc', 'html')) - g = Git.open(cwd) - - # `git add .` - g.add - - # remove each deleted item - g.status.deleted.each do |item| - g.remove(item[0]) - end # g.status.deleted.each - - # commit changes if items added, changed, or deleted - if g.status.added.size > 0 || g.status.changed.size > 0 || - g.status.deleted.size > 0 then - message = "Update documentation for v#{version}" - puts g.commit(message) - else - puts "No changes to commit v#{version}" - end # if g.status.added.size > 0 || g.status.changed.size > 0... - - g.push('origin', 'gh-pages') - end # task :documentation - - desc 'Commit source changes related to version bump' - task :source do - version = Version.current.to_s - `git add \ - doc/#{DOXYFILE} \ - "extras/#{GITHUB_REPO} reference-#{version}.pdf" \ - src/#{HEADER_FILE} \ - #{CHANGELOG_FILE} \ - #{PROPERTIES_FILE} \ - #{VERSION_FILE} \ - ` - `git commit -m 'Version bump to v#{version}'` - `git tag -a -f -m 'Version v#{version}' v#{version}` - `git push origin master` - `git push --tags` - end # task :source - -end # namespace :release diff --git a/lib/ModbusMaster/STYLE.md b/lib/ModbusMaster/STYLE.md deleted file mode 100644 index 00516e0f..00000000 --- a/lib/ModbusMaster/STYLE.md +++ /dev/null @@ -1,372 +0,0 @@ -ModbusMaster Style Guide -======================== - -The following references provide sound guidance for writing C/C++ code for the Arduino platform. - -- [Arduino API Style Guide (AASG)](http://www.arduino.cc/en/Reference/APIStyleGuide) -- [Bjarne Stroustrup's C++ Style Guide](http://www.stroustrup.com/bs_faq2.html) -- [JSF Air Vehicle C++ Coding Standards (JSFAV)](http://www.stroustrup.com/JSF-AV-rules.pdf) - -Opinions about style and generally accepted usage patterns may vary widely. I've carefully chosen a few key items to emphasize and enforce for this library in order to promote readability, usability, and safe coding practices. **Pull requests will follow these guidelines in order to be considered**. - - -General \[AASG\] -------- - -Use the established Arduino core libraries and styles. - -- Use `read()` to read inputs, and `write()` to write to outputs, e.g. `digitalRead()`, `analogWrite()`, etc. -- Use the `Stream.h` and `Print.h` libraries when dealing with byte streams. If it’s not appropriate, at least try to use its API as a model. For more on this, see below. -- For network applications, use the Client and Server libraries as the basis. -- Use `begin()` to initialize a library instance, usually with some settings. Use `end()` to stop it. -- Use camelCase function names, not underscore. For example, `analogRead`, not `analog_read`. Or `myNewFunction`, not `my_new_function`. We've adopted this from Processing.org for readability's sake. Refer to AV Rule 45 and AV Rule 51. -- When using serial communication, allow the user to specify any `Stream` object, rather than hard-coding `Serial`. This will make the library compatible with all serial ports on Mega and the Due, and can also use alternate interfaces like `SoftwareSerial`. The `Stream` object can be passed to the library's constructor or to a `begin()` function (as a reference, not a pointer). See Firmata 2.3 or XBee 0.4 for examples of each approach. - - -Rules \[JSFAV 4.2\] ------ - -#### Should, Will, and Shall Rules - -There are three types of rules: **should**, **will**, and **shall** rules. Each rule contains either a **"should"**, **"will"** or a **"shall"** in bold letters indicating its type. - -- **Should** rules are advisory rules. They strongly suggest the recommended way of doing things. -- **Will** rules are intended to be mandatory requirements. It is expected that they will be followed, but they do not require verification. They are limited to non-safety-critical requirements that cannot be easily verified (e.g., naming conventions). -- **Shall** rules are mandatory requirements. They must be followed and they require verification (either automatic or manual). - - -Pre-Processing Directives \[JSFAV 4.6\] -------------------------- -Since the pre-processor knows nothing about C++, it should not be used to do what can otherwise be done in C++. - -- AV Rule 26 - - Only the following pre-processor directives shall be used: - - 1. `#ifndef` - 1. `#define` - 1. `#endif` - 1. `#include` - - **Rationale**: Limit the use of the pre-processor to those cases where it is necessary. - -#### \#ifndef and \#endif Pre-Processing Directives - -- AV Rule 27 - - `#ifndef`, `#define` and `#endif` **will** be used to prevent multiple inclusions of the same header file. Other techniques to prevent the multiple inclusions of header files **will not** be used. - - **Rationale**: Eliminate multiple inclusions of the same header file in a standard way. - -- AV Rule 28 - - The `#ifndef` and `#endif` pre-processor directives **will** only be used as defined in AV Rule 27 to prevent multiple inclusions of the same header file. - - **Rationale**: Conditional code compilation should be kept to a minimum as it can significantly obscure testing and maintenance efforts. - -#### \#define Pre-Processing Directive - -- AV Rule 29 - - The `#define` pre-processor directive **shall not** be used to create inline macros. Inline functions **shall** be used instead. - - **Rationale**: Inline functions do not require text substitutions and behave well when called with arguments (e.g. type checking is performed). - -- AV Rule 30 - - The `#define` pre-processor directive **shall not** be used to define constant values. Instead, the `const` qualifier shall be applied to variable declarations to specify constant values. - - **Rationale**: `const` variables follow scope rules, are subject to type checking and do not require text substitutions (which can be confusing or misleading). - -- AV Rule 31 - - The `#define` pre-processor directive **will** only be used as part of the technique to prevent multiple inclusions of the same header file. - - **Rationale**: `#define` can be used to specify conditional compilation (AV Rule 27 and AV Rule 28), inline macros (AV Rule 29) and constants (AV Rule 30). This rule specifies that the only allowable use of `#define` is to prevent multiple includes of the same header file (AV Rule 27). - -#### \#include Pre-Processing Directive - -- AV Rule 32 - - The `#include` pre-processor directive **will** only be used to include header (\*.h) files. - - **Rationale**: Clarity. The only files included in a .cpp file should be the relevant header (\*.h) files. - - -Header Files \[JSFAV 4.7\] ------------- - -- AV Rule 33 - - The `#include` directive **shall** use the `` notation to include header files. - - **Rationale**: The include form `"filename.h"` is typically used to include local header files. However, due to the unfortunate divergence in vendor implementations, only the `` form will be used. - -- AV Rule 35 - - A header file **will** contain a mechanism that prevents multiple inclusions of itself. - - **Rationale**: Avoid accidental header file recursion. Note AV Rule 27 specifies the mechanism by which multiple inclusions are to be eliminated whereas this rule (AV Rule 35) specifies that each header file must use that mechanism. - -- AV Rule 37 - - Header (include) files **should** include only those header files that are required for them to successfully compile. Files that are only used by the associated .cpp file should be placed in the .cpp file—not the .h file. - - **Rationale**: The `#include` statements in a header file define the dependencies of the file. Fewer dependencies imply looser couplings and hence a smaller ripple-effect when the header file is required to change. - - -Style \[JSFAV 4.9\] ------ -Imposing constraints on the format of syntactic elements makes source code easier to read due to consistency in form and appearance. - -- AV Rule 41 (modified) - - Source lines **will** be kept to a length of 78 characters or less. - - **Rationale**: Readability and style. Very long source lines can be difficult to read and understand. - -- AV Rule 42 - - Each expression-statement **will** be on a separate line. - - **Rationale**: Simplicity, readability, and style. - -- AV Rule 43 (modified) - - Tabs **will** be avoided. - - **Rationale**: Tabs are interpreted differently across various editors and printers. - -- AV Rule 44 - - All indentations **will** be at least two spaces and be consistent within the same source file. - - **Rationale**: Readability and style. - -#### Naming Identifiers - -The choice of identifier names should: - -- Suggest the usage of the identifier. -- Consist of a descriptive name that is short yet meaningful. -- Be long enough to avoid name conflicts, but not excessive in length. -- Include abbreviations that are generally accepted. - -Note: In general, the above guidelines should be followed. However, conventional usage of simple identifiers (i, x, y, p, etc.) in small scopes can lead to cleaner code and will therefore be permitted. - -Additionally, the term ‘word’ in the following naming convention rules may be used to refer to a word, an acronym, an abbreviation, or a number. - -- AV Rule 45 - - All words in an identifier **will** be separated by the '\_' character. - - **Exception**: Function names follow the camelCase convention according to the Arduino API Style Guide. Refer to AV Rule 51. - - **Rationale**: Readability and Style. - -- AV Rule 47 (modified) - - Identifiers **should not** begin with the underscore character '\_'. - - **Exception**: Currently, private members of the `ModbusMaster` class begin with '\_'. - - **Rationale**: '\_' is often used as the first character in the name of library functions (e.g. `_main`, `_exit`, etc.) In order to avoid name collisions, identifiers should not begin with '\_'. - -- AV Rule 49 - - All acronyms in an identifier **will** be composed of uppercase letters. - - Note: An acronym will always be in uppercase, even if the acronym is located in a portion of an identifier that is specified to be lowercase by other rules. - - **Rationale**: Readability. - -- AV Rule 50 - - The first word of the name of a class, structure, namespace, enumeration, or type created with typedef **will** begin with an uppercase letter. All others letters will be lowercase. - - **Rationale**: Style. - - **Exception**: The first letter of a typedef name may be in lowercase in order to conform to a standard library interface or when used as a replacement for fundamental types. - -- AV Rule 51 (modified) - - All letters contained in *function* names **will** be composed of a mix of lowercase and uppercase letters in camelCase format (e.g. first letter of first word is lowercase and first letter of each subsequent word is uppercase). This is to maintain consistency with the Arduion API Style Guide. Refer to AV Rule 45. - - All letters contained in *variable* names **will** be composed entirely of lowercase letters. - - **Rationale**: Style. - -- AV Rule 52 - - Identifiers for constant and enumerator values **shall** be lowercase. - - **Rationale**: Although it is an accepted convention to use uppercase letters for constants and enumerators, it is possible for third party libraries to replace constant/enumerator names as part of the macro substitution process (macros are also typically represented with uppercase letters). - -#### Classes - -- AV Rule 57 - - The public, protected, and private sections of a class **will** be declared in that order (the public section is declared before the protected section which is declared before the private section). - - **Rationale**: By placing the public section first, everything that is of interest to a user is gathered in the beginning of the class definition. The protected section may be of interest to designers when considering inheriting from the class. The private section contains details that should be of the least general interest. - -#### Functions - -- AV Rule 58 - - When declaring and defining functions with more than two parameters, the leading parenthesis and the first argument **will** be written on the same line as the function name. Each additional argument will be written on a separate line (with the closing parenthesis directly after the last argument). - - **Rationale**: Readability and style. - -#### Blocks - -- AV Rule 59 - - The statements forming the body of an `if`, `else if`, `else`, `while`, `do...while` or `for` statement **shall** always be enclosed in braces, even if the braces form an empty block. - - **Rationale**: Readability. It can be difficult to see ';' when it appears by itself. - -- AV Rule 60 - - Braces ('{}') which enclose a block will be placed in the same column, on separate lines directly before and after the block. - - **Example**: - ``` - if (var_name == true) - { - } - else - { - } - ``` - -- AV Rule 61 - - Braces ('{}') which enclose a block **will** have nothing else on the line except comments (if necessary). - -#### Pointers and References - -- AV Rule 62 - - The dereference operator '\*' and the address-of operator '&' **will** be directly connected with the type-specifier. - - **Rationale**: The `int32* p;` form emphasizes type over syntax while the `int32 *p;` form emphasizes syntax over type. Although both forms are equally valid C++, the heavy emphasis on types in C++ suggests that `int32* p;` is the preferable form. - - **Examples**: - ``` - int32* p; // correct - int32 *p; // incorrect - int32* p, q; // probable error - ``` - -#### Miscellaneous - -- AV Rule 63 - - Spaces **will not** be used around '.' or '->', nor between unary operators and operands. - - **Rationale**: Readability and style. - - -Classes \[JSFAV 4.10\] -------- - -#### const Member Functions - -- AV Rule 69 - - A member function that does not affect the state of an object (its instance variables) **will** be declared `const`. - - Member functions should be `const` by default. Only when there is a clear, explicit reason should the `const` modifier on member functions be omitted. - - **Rationale**: Declaring a member function `const` is a means of ensuring that objects will not be modified when they should not. Furthermore, C++ allows member functions to be overloaded on their `const`-ness. - - -Initialization \[JSFAV 4.16\] --------------- - -- AV Rule 142 - - All variables **shall** be initialized before use. - - **Rationale**: Prevent the use of variables before they have been properly initialized. - -- AV Rule 143 - - Variables **will not** be introduced until they can be initialized with meaningful values. - - **Rationale**: Prevent clients from accessing variables without meaningful values. - - -Constants \[JSFAV 4.18\] ---------- - -- AV Rule 149 - - Octal constants (other than zero) **shall not** be used. - - **Rationale**: Any integer constant beginning with a zero ('0') is defined by the C++ standard to be an octal constant. Due to the confusion this causes, octal constants should be avoided. - - Note: Hexadecimal numbers and zero (which is also an octal constant) are allowed. - -- AV Rule 150 - - Hexadecimal constants **will** be represented using all uppercase letters. - - -Variables \[JSFAV 4.19\] ---------- - -- AV Rule 152 - - Multiple variable declarations **shall not** be allowed on the same line. - - **Rationale**: Increases readability and prevents confusion (see also AV Rule 62). - - **Examples**: - ``` - int32 p; // correct - int32 q; // correct - int32 p, q; // probable error - int32 first_button_on_the_left_box, i; // incorrect; easy to overlook i - ``` - - -Flow Control Structures \[JSFAV 4.24\] ------------------------ - -- AV Rule 188 - - Labels **will** not be used, except in switch statements. - - **Rationale**: Labels are typically either used in switch statements or are as the targets for goto statements. See exception given in AV Rule 189. - -- AV Rule 189 - - The `goto` statement **shall not** be used. - - **Rationale**: Frequent use of the `goto` statement tends to lead to code that is both difficult to read and maintain. - -- AV Rule 190 - - The `continue` statement **shall not** be used. - -- AV Rule 191 - - The `break` statement **shall not** be used (except to terminate the cases of a switch statement). - - **Exception**: The `break` statement may be used to "break" out of a single loop provided the alternative would obscure or otherwise significantly complicate the control logic. - -- AV Rule 192 - - All `if`, `else if` constructs **will** contain either a final `else` clause or a comment indicating why a final `else` clause is not necessary. - - **Rationale**: Provide a defensive strategy to ensure that all cases are handled by an `else if` series. - - Note: This rule only applies when an `if` statement is followed by one or more `else if`’s. - -- AV Rule 193 - - Every non-empty `case` clause in a `switch` statement **shall** be terminated with a `break` statement. - - **Rationale**: Eliminates potentially confusing behavior since execution will fall through to the code of the next `case` clause if a `break` statement does not terminate the previous `case` clause. diff --git a/lib/ModbusMaster/VERSION b/lib/ModbusMaster/VERSION deleted file mode 100644 index 38f77a65..00000000 --- a/lib/ModbusMaster/VERSION +++ /dev/null @@ -1 +0,0 @@ -2.0.1 diff --git a/lib/ModbusMaster/examples/Basic/Basic.pde b/lib/ModbusMaster/examples/Basic/Basic.pde deleted file mode 100644 index 74c199b1..00000000 --- a/lib/ModbusMaster/examples/Basic/Basic.pde +++ /dev/null @@ -1,69 +0,0 @@ -/* - - Basic.pde - example using ModbusMaster library - - Library:: ModbusMaster - Author:: Doc Walker <4-20ma@wvfans.net> - - Copyright:: 2009-2016 Doc Walker - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -#include - - -// instantiate ModbusMaster object -ModbusMaster node; - - -void setup() -{ - // use Serial (port 0); initialize Modbus communication baud rate - Serial.begin(19200); - - // communicate with Modbus slave ID 2 over Serial (port 0) - node.begin(2, Serial); -} - - -void loop() -{ - static uint32_t i; - uint8_t j, result; - uint16_t data[6]; - - i++; - - // set word 0 of TX buffer to least-significant word of counter (bits 15..0) - node.setTransmitBuffer(0, lowWord(i)); - - // set word 1 of TX buffer to most-significant word of counter (bits 31..16) - node.setTransmitBuffer(1, highWord(i)); - - // slave: write TX buffer to (2) 16-bit registers starting at register 0 - result = node.writeMultipleRegisters(0, 2); - - // slave: read (6) 16-bit registers starting at register 2 to RX buffer - result = node.readHoldingRegisters(2, 6); - - // do something with data if read is successful - if (result == node.ku8MBSuccess) - { - for (j = 0; j < 6; j++) - { - data[j] = node.getResponseBuffer(j); - } - } -} diff --git a/lib/ModbusMaster/examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde b/lib/ModbusMaster/examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde deleted file mode 100644 index e91fb338..00000000 --- a/lib/ModbusMaster/examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde +++ /dev/null @@ -1,143 +0,0 @@ -/* - - PhoenixContact_nanoLC.pde - example using ModbusMaster library - to communicate with PHOENIX CONTACT nanoLine controller. - - Library:: ModbusMaster - Author:: Doc Walker <4-20ma@wvfans.net> - - Copyright:: 2009-2016 Doc Walker - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -#include - -// discrete coils -#define NANO_DO(n) (0x0000 + n) ///< returns nanoLC discrete output address -#define NANO_FLAG(n) (0x1000 + n) ///< returns nanoLC flag address - -// discrete inputs -#define NANO_DI(n) (0x0000 + n) ///< returns nanoLC discrete input address - -// analog holding registers -#define NANO_REG(n) (0x0000 + 2 * n) ///< returns nanoLC holding register address -#define NANO_AO(n) (0x1000 + 2 * n) ///< returns nanoLC analog output address -#define NANO_TCP(n) (0x2000 + 2 * n) ///< returns nanoLC timer/counter preset address -#define NANO_OTP(n) (0x3000 + 2 * n) ///< returns nanoLC discrete output preset address -#define NANO_HSP(n) (0x4000 + 2 * n) ///< returns nanoLC high-speed counter preset address -#define NANO_TCA(n) (0x5000 + 2 * n) ///< returns nanoLC timer/counter accumulator address -#define NANO_OTA(n) (0x6000 + 2 * n) ///< returns nanoLC discrete output accumulator address -#define NANO_HSA(n) (0x7000 + 2 * n) ///< returns nanoLC high-speed counter accumulator address - -// analog input registers -#define NANO_AI(n) (0x0000 + 2 * n) ///< returns nanoLC analog input address - - -// instantiate ModbusMaster object -ModbusMaster nanoLC; - - -void setup() -{ - // use Serial (port 0); initialize Modbus communication baud rate - Serial.begin(19200); - - // communicate with Modbus slave ID 1 over Serial (port 0) - nanoLC.begin(1, Serial); -} - - -void loop() -{ - static uint32_t u32ShiftRegister; - static uint32_t i; - uint8_t u8Status; - - u32ShiftRegister = ((u32ShiftRegister < 0x01000000) ? (u32ShiftRegister << 4) : 1); - if (u32ShiftRegister == 0) u32ShiftRegister = 1; - i++; - - // set word 0 of TX buffer to least-significant word of u32ShiftRegister (bits 15..0) - nanoLC.setTransmitBuffer(0, lowWord(u32ShiftRegister)); - - // set word 1 of TX buffer to most-significant word of u32ShiftRegister (bits 31..16) - nanoLC.setTransmitBuffer(1, highWord(u32ShiftRegister)); - - // set word 2 of TX buffer to least-significant word of i (bits 15..0) - nanoLC.setTransmitBuffer(2, lowWord(i)); - - // set word 3 of TX buffer to most-significant word of i (bits 31..16) - nanoLC.setTransmitBuffer(3, highWord(i)); - - // write TX buffer to (4) 16-bit registers starting at NANO_REG(1) - // read (4) 16-bit registers starting at NANO_REG(0) to RX buffer - // data is available via nanoLC.getResponseBuffer(0..3) - nanoLC.readWriteMultipleRegisters(NANO_REG(0), 4, NANO_REG(1), 4); - - // write lowWord(u32ShiftRegister) to single 16-bit register starting at NANO_REG(3) - nanoLC.writeSingleRegister(NANO_REG(3), lowWord(u32ShiftRegister)); - - // write highWord(u32ShiftRegister) to single 16-bit register starting at NANO_REG(3) + 1 - nanoLC.writeSingleRegister(NANO_REG(3) + 1, highWord(u32ShiftRegister)); - - // set word 0 of TX buffer to nanoLC.getResponseBuffer(0) (bits 15..0) - nanoLC.setTransmitBuffer(0, nanoLC.getResponseBuffer(0)); - - // set word 1 of TX buffer to nanoLC.getResponseBuffer(1) (bits 31..16) - nanoLC.setTransmitBuffer(1, nanoLC.getResponseBuffer(1)); - - // write TX buffer to (2) 16-bit registers starting at NANO_REG(4) - nanoLC.writeMultipleRegisters(NANO_REG(4), 2); - - // read 17 coils starting at NANO_FLAG(0) to RX buffer - // bits 15..0 are available via nanoLC.getResponseBuffer(0) - // bit 16 is available via zero-padded nanoLC.getResponseBuffer(1) - nanoLC.readCoils(NANO_FLAG(0), 17); - - // read (66) 16-bit registers starting at NANO_REG(0) to RX buffer - // generates Modbus exception ku8MBIllegalDataAddress (0x02) - u8Status = nanoLC.readHoldingRegisters(NANO_REG(0), 66); - if (u8Status == nanoLC.ku8MBIllegalDataAddress) - { - // read (64) 16-bit registers starting at NANO_REG(0) to RX buffer - // data is available via nanoLC.getResponseBuffer(0..63) - u8Status = nanoLC.readHoldingRegisters(NANO_REG(0), 64); - } - - // read (8) 16-bit registers starting at NANO_AO(0) to RX buffer - // data is available via nanoLC.getResponseBuffer(0..7) - nanoLC.readHoldingRegisters(NANO_AO(0), 8); - - // read (64) 16-bit registers starting at NANO_TCP(0) to RX buffer - // data is available via nanoLC.getResponseBuffer(0..63) - nanoLC.readHoldingRegisters(NANO_TCP(0), 64); - - // read (64) 16-bit registers starting at NANO_OTP(0) to RX buffer - // data is available via nanoLC.getResponseBuffer(0..63) - nanoLC.readHoldingRegisters(NANO_OTP(0), 64); - - // read (64) 16-bit registers starting at NANO_TCA(0) to RX buffer - // data is available via nanoLC.getResponseBuffer(0..63) - nanoLC.readHoldingRegisters(NANO_TCA(0), 64); - - // read (64) 16-bit registers starting at NANO_OTA(0) to RX buffer - // data is available via nanoLC.getResponseBuffer(0..63) - nanoLC.readHoldingRegisters(NANO_OTA(0), 64); - - // read (8) 16-bit registers starting at NANO_AI(0) to RX buffer - // data is available via nanoLC.getResponseBuffer(0..7) - nanoLC.readInputRegisters(NANO_AI(0), 8); -} - diff --git a/lib/ModbusMaster/examples/RS485_HalfDuplex/RS485_HalfDuplex.ino b/lib/ModbusMaster/examples/RS485_HalfDuplex/RS485_HalfDuplex.ino deleted file mode 100644 index c19607f0..00000000 --- a/lib/ModbusMaster/examples/RS485_HalfDuplex/RS485_HalfDuplex.ino +++ /dev/null @@ -1,98 +0,0 @@ -/* - - RS485_HalfDuplex.pde - example using ModbusMaster library to communicate - with EPSolar LS2024B controller using a half-duplex RS485 transceiver. - - This example is tested against an EPSolar LS2024B solar charge controller. - See here for protocol specs: - http://www.solar-elektro.cz/data/dokumenty/1733_modbus_protocol.pdf - - Library:: ModbusMaster - Author:: Marius Kintel - - Copyright:: 2009-2016 Doc Walker - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -#include - -/*! - We're using a MAX485-compatible RS485 Transceiver. - Rx/Tx is hooked up to the hardware serial port at 'Serial'. - The Data Enable and Receiver Enable pins are hooked up as follows: -*/ -#define MAX485_DE 3 -#define MAX485_RE_NEG 2 - -// instantiate ModbusMaster object -ModbusMaster node; - -void preTransmission() -{ - digitalWrite(MAX485_RE_NEG, 1); - digitalWrite(MAX485_DE, 1); -} - -void postTransmission() -{ - digitalWrite(MAX485_RE_NEG, 0); - digitalWrite(MAX485_DE, 0); -} - -void setup() -{ - pinMode(MAX485_RE_NEG, OUTPUT); - pinMode(MAX485_DE, OUTPUT); - // Init in receive mode - digitalWrite(MAX485_RE_NEG, 0); - digitalWrite(MAX485_DE, 0); - - // Modbus communication runs at 115200 baud - Serial.begin(115200); - - // Modbus slave ID 1 - node.begin(1, Serial); - // Callbacks allow us to configure the RS485 transceiver correctly - node.preTransmission(preTransmission); - node.postTransmission(postTransmission); -} - -bool state = true; - -void loop() -{ - uint8_t result; - uint16_t data[6]; - - // Toggle the coil at address 0x0002 (Manual Load Control) - result = node.writeSingleCoil(0x0002, state); - state = !state; - - // Read 16 registers starting at 0x3100) - result = node.readInputRegisters(0x3100, 16); - if (result == node.ku8MBSuccess) - { - Serial.print("Vbatt: "); - Serial.println(node.getResponseBuffer(0x04)/100.0f); - Serial.print("Vload: "); - Serial.println(node.getResponseBuffer(0xC0)/100.0f); - Serial.print("Pload: "); - Serial.println((node.getResponseBuffer(0x0D) + - node.getResponseBuffer(0x0E) << 16)/100.0f); - } - - delay(1000); -} - diff --git a/lib/ModbusMaster/extras/ModbusMaster reference-2.0.1.pdf b/lib/ModbusMaster/extras/ModbusMaster reference-2.0.1.pdf deleted file mode 100644 index cce1e04e..00000000 Binary files a/lib/ModbusMaster/extras/ModbusMaster reference-2.0.1.pdf and /dev/null differ diff --git a/lib/ModbusMaster/extras/README.txt b/lib/ModbusMaster/extras/README.txt deleted file mode 100644 index a5720f68..00000000 --- a/lib/ModbusMaster/extras/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -Documentation is available at: - http://4-20ma.github.com/ModbusMaster - -Alternatively, you can download the HTML files at: - [tarball] https://github.com/4-20ma/ModbusMaster/tarball/gh-pages - [zipball] https://github.com/4-20ma/ModbusMaster/zipball/gh-pages diff --git a/lib/ModbusMaster/keywords.txt b/lib/ModbusMaster/keywords.txt deleted file mode 100644 index fd92fdb4..00000000 --- a/lib/ModbusMaster/keywords.txt +++ /dev/null @@ -1,50 +0,0 @@ -####################################### -# Syntax Coloring Map For ModbusMaster -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -ModbusMaster KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -lowWord KEYWORD2 -highWord KEYWORD2 -LONG KEYWORD2 - -begin KEYWORD2 - -getResponseBuffer KEYWORD2 -clearResponseBuffer KEYWORD2 -setTransmitBuffer KEYWORD2 -clearTransmitBuffer KEYWORD2 - -readCoils KEYWORD2 -readDiscreteInputs KEYWORD2 -readHoldingRegisters KEYWORD2 -readInputRegisters KEYWORD2 -writeSingleCoil KEYWORD2 -writeSingleRegister KEYWORD2 -writeMultipleCoils KEYWORD2 -writeMultipleRegisters KEYWORD2 -maskWriteRegister KEYWORD2 -readWriteMultipleRegisters KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### - -ku8MBIllegalFunction LITERAL1 -ku8MBIllegalDataAddress LITERAL1 -ku8MBIllegalDataValue LITERAL1 -ku8MBSlaveDeviceFailure LITERAL1 - -ku8MBSuccess LITERAL1 -ku8MBInvalidSlaveID LITERAL1 -ku8MBInvalidFunction LITERAL1 -ku8MBResponseTimedOut LITERAL1 -ku8MBInvalidCRC LITERAL1 diff --git a/lib/ModbusMaster/library.properties b/lib/ModbusMaster/library.properties deleted file mode 100644 index a2be2fa7..00000000 --- a/lib/ModbusMaster/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=ModbusMaster -version=2.0.1 -author=Doc Walker -maintainer=Doc Walker <4-20ma@wvfans.net> -sentence=Enlighten your Arduino to be a Modbus master. -paragraph=Enables communication with Modbus slaves over RS232/485 (via RTU protocol). Requires an RS232/485 transceiver. -category=Communication -url=https://github.com/4-20ma/ModbusMaster -architectures=* -includes=ModbusMaster.h diff --git a/lib/ModbusMaster/src/ModbusMaster.cpp b/lib/ModbusMaster/src/ModbusMaster.cpp deleted file mode 100644 index 4169e585..00000000 --- a/lib/ModbusMaster/src/ModbusMaster.cpp +++ /dev/null @@ -1,876 +0,0 @@ -/** -@file -Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol). -*/ -/* - - ModbusMaster.cpp - Arduino library for communicating with Modbus slaves - over RS232/485 (via RTU protocol). - - Library:: ModbusMaster - - Copyright:: 2009-2016 Doc Walker - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - - -/* _____PROJECT INCLUDES_____________________________________________________ */ -#include "ModbusMaster.h" - - -/* _____GLOBAL VARIABLES_____________________________________________________ */ - - -/* _____PUBLIC FUNCTIONS_____________________________________________________ */ -/** -Constructor. - -Creates class object; initialize it using ModbusMaster::begin(). - -@ingroup setup -*/ -ModbusMaster::ModbusMaster(void) -{ - _idle = 0; - _preTransmission = 0; - _postTransmission = 0; -} - -/** -Initialize class object. - -Assigns the Modbus slave ID and serial port. -Call once class has been instantiated, typically within setup(). - -@param slave Modbus slave ID (1..255) -@param &serial reference to serial port object (Serial, Serial1, ... Serial3) -@ingroup setup -*/ -void ModbusMaster::begin(uint8_t slave, Stream &serial) -{ -// txBuffer = (uint16_t*) calloc(ku8MaxBufferSize, sizeof(uint16_t)); - _u8MBSlave = slave; - _serial = &serial; - _u8TransmitBufferIndex = 0; - u16TransmitBufferLength = 0; - -#if __MODBUSMASTER_DEBUG__ - pinMode(__MODBUSMASTER_DEBUG_PIN_A__, OUTPUT); - pinMode(__MODBUSMASTER_DEBUG_PIN_B__, OUTPUT); -#endif -} - - -void ModbusMaster::beginTransmission(uint16_t u16Address) -{ - _u16WriteAddress = u16Address; - _u8TransmitBufferIndex = 0; - u16TransmitBufferLength = 0; -} - -// eliminate this function in favor of using existing MB request functions -uint8_t ModbusMaster::requestFrom(uint16_t address, uint16_t quantity) -{ - uint8_t read; - // clamp to buffer length - if (quantity > ku8MaxBufferSize) - { - quantity = ku8MaxBufferSize; - } - // set rx buffer iterator vars - _u8ResponseBufferIndex = 0; - _u8ResponseBufferLength = read; - - return read; -} - - -void ModbusMaster::sendBit(bool data) -{ - uint8_t txBitIndex = u16TransmitBufferLength % 16; - if ((u16TransmitBufferLength >> 4) < ku8MaxBufferSize) - { - if (0 == txBitIndex) - { - _u16TransmitBuffer[_u8TransmitBufferIndex] = 0; - } - bitWrite(_u16TransmitBuffer[_u8TransmitBufferIndex], txBitIndex, data); - u16TransmitBufferLength++; - _u8TransmitBufferIndex = u16TransmitBufferLength >> 4; - } -} - - -void ModbusMaster::send(uint16_t data) -{ - if (_u8TransmitBufferIndex < ku8MaxBufferSize) - { - _u16TransmitBuffer[_u8TransmitBufferIndex++] = data; - u16TransmitBufferLength = _u8TransmitBufferIndex << 4; - } -} - - -void ModbusMaster::send(uint32_t data) -{ - send(lowWord(data)); - send(highWord(data)); -} - - -void ModbusMaster::send(uint8_t data) -{ - send(word(data)); -} - - - - - - - - - -uint8_t ModbusMaster::available(void) -{ - return _u8ResponseBufferLength - _u8ResponseBufferIndex; -} - - -uint16_t ModbusMaster::receive(void) -{ - if (_u8ResponseBufferIndex < _u8ResponseBufferLength) - { - return _u16ResponseBuffer[_u8ResponseBufferIndex++]; - } - else - { - return 0xFFFF; - } -} - - - - - - - - -/** -Set idle time callback function (cooperative multitasking). - -This function gets called in the idle time between transmission of data -and response from slave. Do not call functions that read from the serial -buffer that is used by ModbusMaster. Use of i2c/TWI, 1-Wire, other -serial ports, etc. is permitted within callback function. - -@see ModbusMaster::ModbusMasterTransaction() -*/ -void ModbusMaster::idle(void (*idle)()) -{ - _idle = idle; -} - -/** -Set pre-transmission callback function. - -This function gets called just before a Modbus message is sent over serial. -Typical usage of this callback is to enable an RS485 transceiver's -Driver Enable pin, and optionally disable its Receiver Enable pin. - -@see ModbusMaster::ModbusMasterTransaction() -@see ModbusMaster::postTransmission() -*/ -void ModbusMaster::preTransmission(void (*preTransmission)()) -{ - _preTransmission = preTransmission; -} - -/** -Set post-transmission callback function. - -This function gets called after a Modbus message has finished sending -(i.e. after all data has been physically transmitted onto the serial -bus). - -Typical usage of this callback is to enable an RS485 transceiver's -Receiver Enable pin, and disable its Driver Enable pin. - -@see ModbusMaster::ModbusMasterTransaction() -@see ModbusMaster::preTransmission() -*/ -void ModbusMaster::postTransmission(void (*postTransmission)()) -{ - _postTransmission = postTransmission; -} - - -/** -Retrieve data from response buffer. - -@see ModbusMaster::clearResponseBuffer() -@param u8Index index of response buffer array (0x00..0x3F) -@return value in position u8Index of response buffer (0x0000..0xFFFF) -@ingroup buffer -*/ -uint16_t ModbusMaster::getResponseBuffer(uint8_t u8Index) -{ - if (u8Index < ku8MaxBufferSize) - { - return _u16ResponseBuffer[u8Index]; - } - else - { - return 0xFFFF; - } -} - - -/** -Clear Modbus response buffer. - -@see ModbusMaster::getResponseBuffer(uint8_t u8Index) -@ingroup buffer -*/ -void ModbusMaster::clearResponseBuffer() -{ - uint8_t i; - - for (i = 0; i < ku8MaxBufferSize; i++) - { - _u16ResponseBuffer[i] = 0; - } -} - - -/** -Place data in transmit buffer. - -@see ModbusMaster::clearTransmitBuffer() -@param u8Index index of transmit buffer array (0x00..0x3F) -@param u16Value value to place in position u8Index of transmit buffer (0x0000..0xFFFF) -@return 0 on success; exception number on failure -@ingroup buffer -*/ -uint8_t ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value) -{ - if (u8Index < ku8MaxBufferSize) - { - _u16TransmitBuffer[u8Index] = u16Value; - return ku8MBSuccess; - } - else - { - return ku8MBIllegalDataAddress; - } -} - - -/** -Clear Modbus transmit buffer. - -@see ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value) -@ingroup buffer -*/ -void ModbusMaster::clearTransmitBuffer() -{ - uint8_t i; - - for (i = 0; i < ku8MaxBufferSize; i++) - { - _u16TransmitBuffer[i] = 0; - } -} - - -/** -Modbus function 0x01 Read Coils. - -This function code is used to read from 1 to 2000 contiguous status of -coils in a remote device. The request specifies the starting address, -i.e. the address of the first coil specified, and the number of coils. -Coils are addressed starting at zero. - -The coils in the response buffer are packed as one coil per bit of the -data field. Status is indicated as 1=ON and 0=OFF. The LSB of the first -data word contains the output addressed in the query. The other coils -follow toward the high order end of this word and from low order to high -order in subsequent words. - -If the returned quantity is not a multiple of sixteen, the remaining -bits in the final data word will be padded with zeros (toward the high -order end of the word). - -@param u16ReadAddress address of first coil (0x0000..0xFFFF) -@param u16BitQty quantity of coils to read (1..2000, enforced by remote device) -@return 0 on success; exception number on failure -@ingroup discrete -*/ -uint8_t ModbusMaster::readCoils(uint16_t u16ReadAddress, uint16_t u16BitQty) -{ - _u16ReadAddress = u16ReadAddress; - _u16ReadQty = u16BitQty; - return ModbusMasterTransaction(ku8MBReadCoils); -} - - -/** -Modbus function 0x02 Read Discrete Inputs. - -This function code is used to read from 1 to 2000 contiguous status of -discrete inputs in a remote device. The request specifies the starting -address, i.e. the address of the first input specified, and the number -of inputs. Discrete inputs are addressed starting at zero. - -The discrete inputs in the response buffer are packed as one input per -bit of the data field. Status is indicated as 1=ON; 0=OFF. The LSB of -the first data word contains the input addressed in the query. The other -inputs follow toward the high order end of this word, and from low order -to high order in subsequent words. - -If the returned quantity is not a multiple of sixteen, the remaining -bits in the final data word will be padded with zeros (toward the high -order end of the word). - -@param u16ReadAddress address of first discrete input (0x0000..0xFFFF) -@param u16BitQty quantity of discrete inputs to read (1..2000, enforced by remote device) -@return 0 on success; exception number on failure -@ingroup discrete -*/ -uint8_t ModbusMaster::readDiscreteInputs(uint16_t u16ReadAddress, - uint16_t u16BitQty) -{ - _u16ReadAddress = u16ReadAddress; - _u16ReadQty = u16BitQty; - return ModbusMasterTransaction(ku8MBReadDiscreteInputs); -} - - -/** -Modbus function 0x03 Read Holding Registers. - -This function code is used to read the contents of a contiguous block of -holding registers in a remote device. The request specifies the starting -register address and the number of registers. Registers are addressed -starting at zero. - -The register data in the response buffer is packed as one word per -register. - -@param u16ReadAddress address of the first holding register (0x0000..0xFFFF) -@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device) -@return 0 on success; exception number on failure -@ingroup register -*/ -uint8_t ModbusMaster::readHoldingRegisters(uint16_t u16ReadAddress, - uint16_t u16ReadQty) -{ - _u16ReadAddress = u16ReadAddress; - _u16ReadQty = u16ReadQty; - return ModbusMasterTransaction(ku8MBReadHoldingRegisters); -} - - -/** -Modbus function 0x04 Read Input Registers. - -This function code is used to read from 1 to 125 contiguous input -registers in a remote device. The request specifies the starting -register address and the number of registers. Registers are addressed -starting at zero. - -The register data in the response buffer is packed as one word per -register. - -@param u16ReadAddress address of the first input register (0x0000..0xFFFF) -@param u16ReadQty quantity of input registers to read (1..125, enforced by remote device) -@return 0 on success; exception number on failure -@ingroup register -*/ -uint8_t ModbusMaster::readInputRegisters(uint16_t u16ReadAddress, - uint8_t u16ReadQty) -{ - _u16ReadAddress = u16ReadAddress; - _u16ReadQty = u16ReadQty; - return ModbusMasterTransaction(ku8MBReadInputRegisters); -} - - -/** -Modbus function 0x05 Write Single Coil. - -This function code is used to write a single output to either ON or OFF -in a remote device. The requested ON/OFF state is specified by a -constant in the state field. A non-zero value requests the output to be -ON and a value of 0 requests it to be OFF. The request specifies the -address of the coil to be forced. Coils are addressed starting at zero. - -@param u16WriteAddress address of the coil (0x0000..0xFFFF) -@param u8State 0=OFF, non-zero=ON (0x00..0xFF) -@return 0 on success; exception number on failure -@ingroup discrete -*/ -uint8_t ModbusMaster::writeSingleCoil(uint16_t u16WriteAddress, uint8_t u8State) -{ - _u16WriteAddress = u16WriteAddress; - _u16WriteQty = (u8State ? 0xFF00 : 0x0000); - return ModbusMasterTransaction(ku8MBWriteSingleCoil); -} - - -/** -Modbus function 0x06 Write Single Register. - -This function code is used to write a single holding register in a -remote device. The request specifies the address of the register to be -written. Registers are addressed starting at zero. - -@param u16WriteAddress address of the holding register (0x0000..0xFFFF) -@param u16WriteValue value to be written to holding register (0x0000..0xFFFF) -@return 0 on success; exception number on failure -@ingroup register -*/ -uint8_t ModbusMaster::writeSingleRegister(uint16_t u16WriteAddress, - uint16_t u16WriteValue) -{ - _u16WriteAddress = u16WriteAddress; - _u16WriteQty = 0; - _u16TransmitBuffer[0] = u16WriteValue; - return ModbusMasterTransaction(ku8MBWriteSingleRegister); -} - - -/** -Modbus function 0x0F Write Multiple Coils. - -This function code is used to force each coil in a sequence of coils to -either ON or OFF in a remote device. The request specifies the coil -references to be forced. Coils are addressed starting at zero. - -The requested ON/OFF states are specified by contents of the transmit -buffer. A logical '1' in a bit position of the buffer requests the -corresponding output to be ON. A logical '0' requests it to be OFF. - -@param u16WriteAddress address of the first coil (0x0000..0xFFFF) -@param u16BitQty quantity of coils to write (1..2000, enforced by remote device) -@return 0 on success; exception number on failure -@ingroup discrete -*/ -uint8_t ModbusMaster::writeMultipleCoils(uint16_t u16WriteAddress, - uint16_t u16BitQty) -{ - _u16WriteAddress = u16WriteAddress; - _u16WriteQty = u16BitQty; - return ModbusMasterTransaction(ku8MBWriteMultipleCoils); -} -uint8_t ModbusMaster::writeMultipleCoils() -{ - _u16WriteQty = u16TransmitBufferLength; - return ModbusMasterTransaction(ku8MBWriteMultipleCoils); -} - - -/** -Modbus function 0x10 Write Multiple Registers. - -This function code is used to write a block of contiguous registers (1 -to 123 registers) in a remote device. - -The requested written values are specified in the transmit buffer. Data -is packed as one word per register. - -@param u16WriteAddress address of the holding register (0x0000..0xFFFF) -@param u16WriteQty quantity of holding registers to write (1..123, enforced by remote device) -@return 0 on success; exception number on failure -@ingroup register -*/ -uint8_t ModbusMaster::writeMultipleRegisters(uint16_t u16WriteAddress, - uint16_t u16WriteQty) -{ - _u16WriteAddress = u16WriteAddress; - _u16WriteQty = u16WriteQty; - return ModbusMasterTransaction(ku8MBWriteMultipleRegisters); -} - -// new version based on Wire.h -uint8_t ModbusMaster::writeMultipleRegisters() -{ - _u16WriteQty = _u8TransmitBufferIndex; - return ModbusMasterTransaction(ku8MBWriteMultipleRegisters); -} - - -/** -Modbus function 0x16 Mask Write Register. - -This function code is used to modify the contents of a specified holding -register using a combination of an AND mask, an OR mask, and the -register's current contents. The function can be used to set or clear -individual bits in the register. - -The request specifies the holding register to be written, the data to be -used as the AND mask, and the data to be used as the OR mask. Registers -are addressed starting at zero. - -The function's algorithm is: - -Result = (Current Contents && And_Mask) || (Or_Mask && (~And_Mask)) - -@param u16WriteAddress address of the holding register (0x0000..0xFFFF) -@param u16AndMask AND mask (0x0000..0xFFFF) -@param u16OrMask OR mask (0x0000..0xFFFF) -@return 0 on success; exception number on failure -@ingroup register -*/ -uint8_t ModbusMaster::maskWriteRegister(uint16_t u16WriteAddress, - uint16_t u16AndMask, uint16_t u16OrMask) -{ - _u16WriteAddress = u16WriteAddress; - _u16TransmitBuffer[0] = u16AndMask; - _u16TransmitBuffer[1] = u16OrMask; - return ModbusMasterTransaction(ku8MBMaskWriteRegister); -} - - -/** -Modbus function 0x17 Read Write Multiple Registers. - -This function code performs a combination of one read operation and one -write operation in a single MODBUS transaction. The write operation is -performed before the read. Holding registers are addressed starting at -zero. - -The request specifies the starting address and number of holding -registers to be read as well as the starting address, and the number of -holding registers. The data to be written is specified in the transmit -buffer. - -@param u16ReadAddress address of the first holding register (0x0000..0xFFFF) -@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device) -@param u16WriteAddress address of the first holding register (0x0000..0xFFFF) -@param u16WriteQty quantity of holding registers to write (1..121, enforced by remote device) -@return 0 on success; exception number on failure -@ingroup register -*/ -uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress, - uint16_t u16ReadQty, uint16_t u16WriteAddress, uint16_t u16WriteQty) -{ - _u16ReadAddress = u16ReadAddress; - _u16ReadQty = u16ReadQty; - _u16WriteAddress = u16WriteAddress; - _u16WriteQty = u16WriteQty; - return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters); -} -uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress, - uint16_t u16ReadQty) -{ - _u16ReadAddress = u16ReadAddress; - _u16ReadQty = u16ReadQty; - _u16WriteQty = _u8TransmitBufferIndex; - return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters); -} - - -/* _____PRIVATE FUNCTIONS____________________________________________________ */ -/** -Modbus transaction engine. -Sequence: - - assemble Modbus Request Application Data Unit (ADU), - based on particular function called - - transmit request over selected serial port - - wait for/retrieve response - - evaluate/disassemble response - - return status (success/exception) - -@param u8MBFunction Modbus function (0x01..0xFF) -@return 0 on success; exception number on failure -*/ -uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) -{ - uint8_t u8ModbusADU[256]; - uint8_t u8ModbusADUSize = 0; - uint8_t i, u8Qty; - uint16_t u16CRC; - uint32_t u32StartTime; - uint8_t u8BytesLeft = 8; - uint8_t u8MBStatus = ku8MBSuccess; - - // assemble Modbus Request Application Data Unit - u8ModbusADU[u8ModbusADUSize++] = _u8MBSlave; - u8ModbusADU[u8ModbusADUSize++] = u8MBFunction; - - switch(u8MBFunction) - { - case ku8MBReadCoils: - case ku8MBReadDiscreteInputs: - case ku8MBReadInputRegisters: - case ku8MBReadHoldingRegisters: - case ku8MBReadWriteMultipleRegisters: - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadAddress); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadAddress); - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadQty); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadQty); - break; - } - - switch(u8MBFunction) - { - case ku8MBWriteSingleCoil: - case ku8MBMaskWriteRegister: - case ku8MBWriteMultipleCoils: - case ku8MBWriteSingleRegister: - case ku8MBWriteMultipleRegisters: - case ku8MBReadWriteMultipleRegisters: - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteAddress); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteAddress); - break; - } - - switch(u8MBFunction) - { - case ku8MBWriteSingleCoil: - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty); - break; - - case ku8MBWriteSingleRegister: - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]); - break; - - case ku8MBWriteMultipleCoils: - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty); - u8Qty = (_u16WriteQty % 8) ? ((_u16WriteQty >> 3) + 1) : (_u16WriteQty >> 3); - u8ModbusADU[u8ModbusADUSize++] = u8Qty; - for (i = 0; i < u8Qty; i++) - { - switch(i % 2) - { - case 0: // i is even - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i >> 1]); - break; - - case 1: // i is odd - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i >> 1]); - break; - } - } - break; - - case ku8MBWriteMultipleRegisters: - case ku8MBReadWriteMultipleRegisters: - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty << 1); - - for (i = 0; i < lowByte(_u16WriteQty); i++) - { - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i]); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i]); - } - break; - - case ku8MBMaskWriteRegister: - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]); - u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[1]); - u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[1]); - break; - } - - // append CRC - u16CRC = 0xFFFF; - for (i = 0; i < u8ModbusADUSize; i++) - { - u16CRC = crc16_update(u16CRC, u8ModbusADU[i]); - } - u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC); - u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC); - u8ModbusADU[u8ModbusADUSize] = 0; - - // flush receive buffer before transmitting request - while (_serial->read() != -1); - - // transmit request - if (_preTransmission) - { - _preTransmission(); - } - for (i = 0; i < u8ModbusADUSize; i++) - { - _serial->write(u8ModbusADU[i]); - } - - u8ModbusADUSize = 0; - _serial->flush(); // flush transmit buffer - if (_postTransmission) - { - _postTransmission(); - } - - // loop until we run out of time or bytes, or an error occurs - u32StartTime = millis(); - while (u8BytesLeft && !u8MBStatus) - { - if (_serial->available()) - { -#if __MODBUSMASTER_DEBUG__ - digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true); -#endif - u8ModbusADU[u8ModbusADUSize++] = _serial->read(); - u8BytesLeft--; -#if __MODBUSMASTER_DEBUG__ - digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false); -#endif - } - else - { -#if __MODBUSMASTER_DEBUG__ - digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, true); -#endif - if (_idle) - { - _idle(); - } -#if __MODBUSMASTER_DEBUG__ - digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false); -#endif - } - - // evaluate slave ID, function code once enough bytes have been read - if (u8ModbusADUSize == 5) - { - // verify response is for correct Modbus slave - if (u8ModbusADU[0] != _u8MBSlave) - { - u8MBStatus = ku8MBInvalidSlaveID; - break; - } - - // verify response is for correct Modbus function code (mask exception bit 7) - if ((u8ModbusADU[1] & 0x7F) != u8MBFunction) - { - u8MBStatus = ku8MBInvalidFunction; - break; - } - - // check whether Modbus exception occurred; return Modbus Exception Code - if (bitRead(u8ModbusADU[1], 7)) - { - u8MBStatus = u8ModbusADU[2]; - break; - } - - // evaluate returned Modbus function code - switch(u8ModbusADU[1]) - { - case ku8MBReadCoils: - case ku8MBReadDiscreteInputs: - case ku8MBReadInputRegisters: - case ku8MBReadHoldingRegisters: - case ku8MBReadWriteMultipleRegisters: - u8BytesLeft = u8ModbusADU[2]; - break; - - case ku8MBWriteSingleCoil: - case ku8MBWriteMultipleCoils: - case ku8MBWriteSingleRegister: - case ku8MBWriteMultipleRegisters: - u8BytesLeft = 3; - break; - - case ku8MBMaskWriteRegister: - u8BytesLeft = 5; - break; - } - } - if ((millis() - u32StartTime) > ku16MBResponseTimeout) - { - u8MBStatus = ku8MBResponseTimedOut; - } - } - - // verify response is large enough to inspect further - if (!u8MBStatus && u8ModbusADUSize >= 5) - { - // calculate CRC - u16CRC = 0xFFFF; - for (i = 0; i < (u8ModbusADUSize - 2); i++) - { - u16CRC = crc16_update(u16CRC, u8ModbusADU[i]); - } - - // verify CRC - if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] || - highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1])) - { - u8MBStatus = ku8MBInvalidCRC; - } - } - - // disassemble ADU into words - if (!u8MBStatus) - { - // evaluate returned Modbus function code - switch(u8ModbusADU[1]) - { - case ku8MBReadCoils: - case ku8MBReadDiscreteInputs: - // load bytes into word; response bytes are ordered L, H, L, H, ... - for (i = 0; i < (u8ModbusADU[2] >> 1); i++) - { - if (i < ku8MaxBufferSize) - { - _u16ResponseBuffer[i] = word(u8ModbusADU[2 * i + 4], u8ModbusADU[2 * i + 3]); - } - - _u8ResponseBufferLength = i; - } - - // in the event of an odd number of bytes, load last byte into zero-padded word - if (u8ModbusADU[2] % 2) - { - if (i < ku8MaxBufferSize) - { - _u16ResponseBuffer[i] = word(0, u8ModbusADU[2 * i + 3]); - } - - _u8ResponseBufferLength = i + 1; - } - break; - - case ku8MBReadInputRegisters: - case ku8MBReadHoldingRegisters: - case ku8MBReadWriteMultipleRegisters: - // load bytes into word; response bytes are ordered H, L, H, L, ... - for (i = 0; i < (u8ModbusADU[2] >> 1); i++) - { - if (i < ku8MaxBufferSize) - { - _u16ResponseBuffer[i] = word(u8ModbusADU[2 * i + 3], u8ModbusADU[2 * i + 4]); - } - - _u8ResponseBufferLength = i; - } - break; - } - } - - _u8TransmitBufferIndex = 0; - u16TransmitBufferLength = 0; - _u8ResponseBufferIndex = 0; - return u8MBStatus; -} diff --git a/lib/ModbusMaster/src/ModbusMaster.h b/lib/ModbusMaster/src/ModbusMaster.h deleted file mode 100644 index b8c566a4..00000000 --- a/lib/ModbusMaster/src/ModbusMaster.h +++ /dev/null @@ -1,270 +0,0 @@ -/** -@file -Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol). - -@defgroup setup ModbusMaster Object Instantiation/Initialization -@defgroup buffer ModbusMaster Buffer Management -@defgroup discrete Modbus Function Codes for Discrete Coils/Inputs -@defgroup register Modbus Function Codes for Holding/Input Registers -@defgroup constant Modbus Function Codes, Exception Codes -*/ -/* - - ModbusMaster.h - Arduino library for communicating with Modbus slaves - over RS232/485 (via RTU protocol). - - Library:: ModbusMaster - - Copyright:: 2009-2016 Doc Walker - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - - -#ifndef ModbusMaster_h -#define ModbusMaster_h - - -/** -@def __MODBUSMASTER_DEBUG__ (0) -Set to 1 to enable debugging features within class: - - PIN A cycles for each byte read in the Modbus response - - PIN B cycles for each millisecond timeout during the Modbus response -*/ -#define __MODBUSMASTER_DEBUG__ (0) -#define __MODBUSMASTER_DEBUG_PIN_A__ 4 -#define __MODBUSMASTER_DEBUG_PIN_B__ 5 - -/* _____STANDARD INCLUDES____________________________________________________ */ -// include types & constants of Wiring core API -#include "Arduino.h" - -/* _____UTILITY MACROS_______________________________________________________ */ - - -/* _____PROJECT INCLUDES_____________________________________________________ */ -// functions to calculate Modbus Application Data Unit CRC -#include "util/crc16.h" - -// functions to manipulate words -#include "util/word.h" - - -/* _____CLASS DEFINITIONS____________________________________________________ */ -/** -Arduino class library for communicating with Modbus slaves over -RS232/485 (via RTU protocol). -*/ -class ModbusMaster -{ - public: - ModbusMaster(); - - void begin(uint8_t, Stream &serial); - void idle(void (*)()); - void preTransmission(void (*)()); - void postTransmission(void (*)()); - - // Modbus exception codes - /** - Modbus protocol illegal function exception. - - The function code received in the query is not an allowable action for - the server (or slave). This may be because the function code is only - applicable to newer devices, and was not implemented in the unit - selected. It could also indicate that the server (or slave) is in the - wrong state to process a request of this type, for example because it is - unconfigured and is being asked to return register values. - - @ingroup constant - */ - static const uint8_t ku8MBIllegalFunction = 0x01; - - /** - Modbus protocol illegal data address exception. - - The data address received in the query is not an allowable address for - the server (or slave). More specifically, the combination of reference - number and transfer length is invalid. For a controller with 100 - registers, the ADU addresses the first register as 0, and the last one - as 99. If a request is submitted with a starting register address of 96 - and a quantity of registers of 4, then this request will successfully - operate (address-wise at least) on registers 96, 97, 98, 99. If a - request is submitted with a starting register address of 96 and a - quantity of registers of 5, then this request will fail with Exception - Code 0x02 "Illegal Data Address" since it attempts to operate on - registers 96, 97, 98, 99 and 100, and there is no register with address - 100. - - @ingroup constant - */ - static const uint8_t ku8MBIllegalDataAddress = 0x02; - - /** - Modbus protocol illegal data value exception. - - A value contained in the query data field is not an allowable value for - server (or slave). This indicates a fault in the structure of the - remainder of a complex request, such as that the implied length is - incorrect. It specifically does NOT mean that a data item submitted for - storage in a register has a value outside the expectation of the - application program, since the MODBUS protocol is unaware of the - significance of any particular value of any particular register. - - @ingroup constant - */ - static const uint8_t ku8MBIllegalDataValue = 0x03; - - /** - Modbus protocol slave device failure exception. - - An unrecoverable error occurred while the server (or slave) was - attempting to perform the requested action. - - @ingroup constant - */ - static const uint8_t ku8MBSlaveDeviceFailure = 0x04; - - // Class-defined success/exception codes - /** - ModbusMaster success. - - Modbus transaction was successful; the following checks were valid: - - slave ID - - function code - - response code - - data - - CRC - - @ingroup constant - */ - static const uint8_t ku8MBSuccess = 0x00; - - /** - ModbusMaster invalid response slave ID exception. - - The slave ID in the response does not match that of the request. - - @ingroup constant - */ - static const uint8_t ku8MBInvalidSlaveID = 0xE0; - - /** - ModbusMaster invalid response function exception. - - The function code in the response does not match that of the request. - - @ingroup constant - */ - static const uint8_t ku8MBInvalidFunction = 0xE1; - - /** - ModbusMaster response timed out exception. - - The entire response was not received within the timeout period, - ModbusMaster::ku8MBResponseTimeout. - - @ingroup constant - */ - static const uint8_t ku8MBResponseTimedOut = 0xE2; - - /** - ModbusMaster invalid response CRC exception. - - The CRC in the response does not match the one calculated. - - @ingroup constant - */ - static const uint8_t ku8MBInvalidCRC = 0xE3; - - uint16_t getResponseBuffer(uint8_t); - void clearResponseBuffer(); - uint8_t setTransmitBuffer(uint8_t, uint16_t); - void clearTransmitBuffer(); - - void beginTransmission(uint16_t); - uint8_t requestFrom(uint16_t, uint16_t); - void sendBit(bool); - void send(uint8_t); - void send(uint16_t); - void send(uint32_t); - uint8_t available(void); - uint16_t receive(void); - - - uint8_t readCoils(uint16_t, uint16_t); - uint8_t readDiscreteInputs(uint16_t, uint16_t); - uint8_t readHoldingRegisters(uint16_t, uint16_t); - uint8_t readInputRegisters(uint16_t, uint8_t); - uint8_t writeSingleCoil(uint16_t, uint8_t); - uint8_t writeSingleRegister(uint16_t, uint16_t); - uint8_t writeMultipleCoils(uint16_t, uint16_t); - uint8_t writeMultipleCoils(); - uint8_t writeMultipleRegisters(uint16_t, uint16_t); - uint8_t writeMultipleRegisters(); - uint8_t maskWriteRegister(uint16_t, uint16_t, uint16_t); - uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t); - uint8_t readWriteMultipleRegisters(uint16_t, uint16_t); - - private: - Stream* _serial; ///< reference to serial port object - uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in begin() - static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers - uint16_t _u16ReadAddress; ///< slave register from which to read - uint16_t _u16ReadQty; ///< quantity of words to read - uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer() - uint16_t _u16WriteAddress; ///< slave register to which to write - uint16_t _u16WriteQty; ///< quantity of words to write - uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer() - uint16_t* txBuffer; // from Wire.h -- need to clean this up Rx - uint8_t _u8TransmitBufferIndex; - uint16_t u16TransmitBufferLength; - uint16_t* rxBuffer; // from Wire.h -- need to clean this up Rx - uint8_t _u8ResponseBufferIndex; - uint8_t _u8ResponseBufferLength; - - // Modbus function codes for bit access - static const uint8_t ku8MBReadCoils = 0x01; ///< Modbus function 0x01 Read Coils - static const uint8_t ku8MBReadDiscreteInputs = 0x02; ///< Modbus function 0x02 Read Discrete Inputs - static const uint8_t ku8MBWriteSingleCoil = 0x05; ///< Modbus function 0x05 Write Single Coil - static const uint8_t ku8MBWriteMultipleCoils = 0x0F; ///< Modbus function 0x0F Write Multiple Coils - - // Modbus function codes for 16 bit access - static const uint8_t ku8MBReadHoldingRegisters = 0x03; ///< Modbus function 0x03 Read Holding Registers - static const uint8_t ku8MBReadInputRegisters = 0x04; ///< Modbus function 0x04 Read Input Registers - static const uint8_t ku8MBWriteSingleRegister = 0x06; ///< Modbus function 0x06 Write Single Register - static const uint8_t ku8MBWriteMultipleRegisters = 0x10; ///< Modbus function 0x10 Write Multiple Registers - static const uint8_t ku8MBMaskWriteRegister = 0x16; ///< Modbus function 0x16 Mask Write Register - static const uint8_t ku8MBReadWriteMultipleRegisters = 0x17; ///< Modbus function 0x17 Read Write Multiple Registers - - // Modbus timeout [milliseconds] - static const uint16_t ku16MBResponseTimeout = 150; ///< Modbus timeout [milliseconds] - - // master function that conducts Modbus transactions - uint8_t ModbusMasterTransaction(uint8_t u8MBFunction); - - // idle callback function; gets called during idle time between TX and RX - void (*_idle)(); - // preTransmission callback function; gets called before writing a Modbus message - void (*_preTransmission)(); - // postTransmission callback function; gets called after a Modbus message has been sent - void (*_postTransmission)(); -}; -#endif - -/** -@example examples/Basic/Basic.pde -@example examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde -@example examples/RS485_HalfDuplex/RS485_HalfDuplex.ino -*/ diff --git a/lib/ModbusMaster/src/util/crc16.h b/lib/ModbusMaster/src/util/crc16.h deleted file mode 100644 index 27ea89ec..00000000 --- a/lib/ModbusMaster/src/util/crc16.h +++ /dev/null @@ -1,88 +0,0 @@ -/** -@file -CRC Computations - -@defgroup util_crc16 "util/crc16.h": CRC Computations -@code#include "util/crc16.h"@endcode - -This header file provides functions for calculating -cyclic redundancy checks (CRC) using common polynomials. -Modified by Doc Walker to be processor-independent (removed inline -assembler to allow it to compile on SAM3X8E processors). - -@par References: -Jack Crenshaw's "Implementing CRCs" article in the January 1992 issue of @e -Embedded @e Systems @e Programming. This may be difficult to find, but it -explains CRC's in very clear and concise terms. Well worth the effort to -obtain a copy. - -*/ -/* Copyright (c) 2002, 2003, 2004 Marek Michalkiewicz - Copyright (c) 2005, 2007 Joerg Wunsch - Copyright (c) 2013 Dave Hylands - Copyright (c) 2013 Frederic Nadeau - Copyright (c) 2015 Doc Walker - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the name of the copyright holders nor the names of - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. */ - - -#ifndef _UTIL_CRC16_H_ -#define _UTIL_CRC16_H_ - - -/** @ingroup util_crc16 - Processor-independent CRC-16 calculation. - - Polynomial: x^16 + x^15 + x^2 + 1 (0xA001)
- Initial value: 0xFFFF - - This CRC is normally used in disk-drive controllers. - - @param uint16_t crc (0x0000..0xFFFF) - @param uint8_t a (0x00..0xFF) - @return calculated CRC (0x0000..0xFFFF) -*/ -static uint16_t crc16_update(uint16_t crc, uint8_t a) -{ - int i; - - crc ^= a; - for (i = 0; i < 8; ++i) - { - if (crc & 1) - crc = (crc >> 1) ^ 0xA001; - else - crc = (crc >> 1); - } - - return crc; -} - - -#endif /* _UTIL_CRC16_H_ */ diff --git a/lib/ModbusMaster/src/util/word.h b/lib/ModbusMaster/src/util/word.h deleted file mode 100644 index c72ad944..00000000 --- a/lib/ModbusMaster/src/util/word.h +++ /dev/null @@ -1,64 +0,0 @@ -/** -@file -Utility Functions for Manipulating Words - -@defgroup util_word "util/word.h": Utility Functions for Manipulating Words -@code#include "util/word.h"@endcode - -This header file provides utility functions for manipulating words. - -*/ -/* - - word.h - Utility Functions for Manipulating Words - - This file is part of ModbusMaster. - - ModbusMaster is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ModbusMaster is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ModbusMaster. If not, see . - - Written by Doc Walker (Rx) - Copyright © 2009-2015 Doc Walker <4-20ma at wvfans dot net> - -*/ - - -#ifndef _UTIL_WORD_H_ -#define _UTIL_WORD_H_ - - -/** @ingroup util_word - Return low word of a 32-bit integer. - - @param uint32_t ww (0x00000000..0xFFFFFFFF) - @return low word of input (0x0000..0xFFFF) -*/ -static inline uint16_t lowWord(uint32_t ww) -{ - return (uint16_t) ((ww) & 0xFFFF); -} - - -/** @ingroup util_word - Return high word of a 32-bit integer. - - @param uint32_t ww (0x00000000..0xFFFFFFFF) - @return high word of input (0x0000..0xFFFF) -*/ -static inline uint16_t highWord(uint32_t ww) -{ - return (uint16_t) ((ww) >> 16); -} - - -#endif /* _UTIL_WORD_H_ */ diff --git a/lib/README b/lib/README deleted file mode 100644 index 6debab1e..00000000 --- a/lib/README +++ /dev/null @@ -1,46 +0,0 @@ - -This directory is intended for project specific (private) libraries. -PlatformIO will compile them to static libraries and link into executable file. - -The source code of each library should be placed in a an own separate directory -("lib/your_library_name/[here are source files]"). - -For example, see a structure of the following two libraries `Foo` and `Bar`: - -|--lib -| | -| |--Bar -| | |--docs -| | |--examples -| | |--src -| | |- Bar.c -| | |- Bar.h -| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html -| | -| |--Foo -| | |- Foo.c -| | |- Foo.h -| | -| |- README --> THIS FILE -| -|- platformio.ini -|--src - |- main.c - -and a contents of `src/main.c`: -``` -#include -#include - -int main (void) -{ - ... -} - -``` - -PlatformIO Library Dependency Finder will find automatically dependent -libraries scanning project source files. - -More information about PlatformIO Library Dependency Finder -- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/lib/TickerScheduler/README.md b/lib/TickerScheduler/README.md deleted file mode 100644 index 33f0182e..00000000 --- a/lib/TickerScheduler/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# TickerScheduler -Simple scheduler for ESP8266 Arduino based on Ticker - -### Initialization - -`TickerScheduler(uint size);` - -| Param | Description | -| --- | --- | -| size | Amount of task Tickers to initialize | - -**Example**: - -`TickerScheduler ts(5)` - - -### Add task - -`boolean add(uint i, uint32_t period, tscallback_t f, boolean shouldFireNow = false); ` - -| Param | Description | -| --- | --- | -| i | Task ID | -| period | Task execution period in ms | -| f | Task callback | -| shouldFireNow| `true` if you want to execute task right after first scheduler update or wait next scheduled start | - -**Returns**: - -`true` - task added sucessfully - -`false` - task was not added - -**Example**: - -`ts.add(0, 3000, sendData)` - -### Execute scheduler in `loop()` - -`ts.update()` - -### Remove task - -`boolean remove(uint i)` - -**Returns**: - -`true` - task removed sucessfully - -`false` - task was not removed - -| Param | Description | -| --- | --- | -| i | Task ID | - -### Enable/Disable task - -`boolean enable(uint i)` - -`boolean disable(uint i)` - -**Returns**: - -`true` - task enabled/disabled sucessfully - -`false` - task was not enabled/disabled - -| Param | Description | -| --- | --- | -| i | Task ID | - -### Enable / disable all tasks - -`void enableAll()` - -`void disableAll()` - -### TODO - -* Task callback parameters support -* ... diff --git a/lib/TickerScheduler/TickerScheduler.cpp b/lib/TickerScheduler/TickerScheduler.cpp deleted file mode 100644 index af47ffa1..00000000 --- a/lib/TickerScheduler/TickerScheduler.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "TickerScheduler.h" - -TickerScheduler::TickerScheduler(uint8_t size) -{ - this->items = new TickerSchedulerItem[size]; - this->size = size; -} - -TickerScheduler::~TickerScheduler() -{ - for (uint8_t i = 0; i < this->size; i++) - { - this->remove(i); - yield(); - } - - delete[] this->items; - this->items = NULL; - this->size = 0; -} - -void TickerScheduler::handleTickerFlag(bool * flag) -{ - if (!*flag) - *flag = true; -} - -void TickerScheduler::handleTicker(tscallback_t f, void * arg, bool * flag) -{ - if (*flag) - { - yield(); - *flag = false; - yield(); - f(arg); - yield(); - } -} - -bool TickerScheduler::add(uint8_t i, uint32_t period, tscallback_t f, void* arg, boolean shouldFireNow) -{ - if (i >= this->size || this->items[i].is_used) - return false; - - this->items[i].cb = f; - this->items[i].cb_arg = arg; - this->items[i].flag = shouldFireNow; - this->items[i].period = period; - this->items[i].is_used = true; - - enable(i); - - return true; -} - -bool TickerScheduler::remove(uint8_t i) -{ - if (i >= this->size || !this->items[i].is_used) - return false; - - this->items[i].is_used = false; - this->items[i].t.detach(); - this->items[i].flag = false; - this->items[i].cb = NULL; - - return true; -} - -bool TickerScheduler::disable(uint8_t i) -{ - if (i >= this->size || !this->items[i].is_used) - return false; - - this->items[i].t.detach(); - - return true; -} - -bool TickerScheduler::enable(uint8_t i) -{ - if (i >= this->size || !this->items[i].is_used) - return false; - - bool * flag = &this->items[i].flag; - this->items[i].t.attach_ms(this->items[i].period, TickerScheduler::handleTickerFlag, flag); - - return true; -} - -void TickerScheduler::disableAll() -{ - for (uint8_t i = 0; i < this->size; i++) - disable(i); -} - -void TickerScheduler::enableAll() -{ - for (uint8_t i = 0; i < this->size; i++) - enable(i); -} - -void TickerScheduler::update() -{ - for (uint8_t i = 0; i < this->size; i++) - { - if (this->items[i].is_used) - { - #ifdef ARDUINO_ARCH_AVR - this->items[i].t.Tick(); - #endif - - handleTicker(this->items[i].cb, this->items[i].cb_arg, &this->items[i].flag); - } - yield(); - } -} diff --git a/lib/TickerScheduler/TickerScheduler.h b/lib/TickerScheduler/TickerScheduler.h deleted file mode 100644 index 98ae1f05..00000000 --- a/lib/TickerScheduler/TickerScheduler.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef TICKERSCHEDULER_H -#define TICKERSCHEDULER_H - -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#endif -#include - - -#ifdef ARDUINO_ARCH_AVR -class Ticker -{ - typedef void(*ticker_callback_t)(bool*); - -private: - bool is_attached = false; - uint32_t period = 0; - uint32_t last_tick = 0; - ticker_callback_t callback; - bool *callback_argument; -public: - void Tick() - { - if (is_attached && millis() - last_tick >= period) - { - callback(callback_argument); - last_tick = millis(); - } - } - - void detach() - { - this->is_attached = true; - } - - template void attach_ms(uint32_t milliseconds, void(*callback)(TArg), TArg arg) - { - this->period = milliseconds; - this->callback = callback; - this->callback_argument = arg; - this->is_attached = true; - } -}; -#endif - -//#ifdef ARDUINO_ARCH_ESP8266 -#include -#include -//#endif - -void tickerFlagHandle(volatile bool * flag); - -#ifdef _GLIBCXX_FUNCTIONAL -typedef std::function tscallback_t; -#else -typedef void(*tscallback_t)(void*); -#endif - -struct TickerSchedulerItem -{ - Ticker t; - bool flag = false; - tscallback_t cb; - void * cb_arg; - uint32_t period; - volatile bool is_used = false; -}; - -class TickerScheduler -{ -private: - uint8_t size; - TickerSchedulerItem *items = NULL; - - void handleTicker(tscallback_t, void *, bool * flag); - static void handleTickerFlag(bool * flag); - -public: - TickerScheduler(uint8_t size); - ~TickerScheduler(); - - bool add(uint8_t i, uint32_t period, tscallback_t, void *, boolean shouldFireNow = false); - bool remove(uint8_t i); - bool enable(uint8_t i); - bool disable(uint8_t i); - void enableAll(); - void disableAll(); - void update(); -}; - -#endif diff --git a/lib/TickerScheduler/example/blink/blink/blink.ino b/lib/TickerScheduler/example/blink/blink/blink.ino deleted file mode 100644 index 49afc470..00000000 --- a/lib/TickerScheduler/example/blink/blink/blink.ino +++ /dev/null @@ -1,29 +0,0 @@ -#include - -#define LED1 4 -#define LED2 5 - -TickerScheduler ts(2); - -void blink1() { - digitalWrite(LED1, !digitalRead(LED1)); -} - -void blink2() { - digitalWrite(LED2, !digitalRead(LED2)); -} - -void setup() { - pinMode(LED1, OUTPUT); - digitalWrite(LED1, LOW); - - pinMode(LED2, OUTPUT); - digitalWrite(LED2, LOW); - - ts.add(0, 1000, [&](void *) { blink1(); }, nullptr, true); - ts.add(1, 3000, [&](void *) { blink2(); }, nullptr, true); -} - -void loop() { - ts.update(); -} diff --git a/partitions_custom.csv b/partitions_custom.csv deleted file mode 100644 index 86202b53..00000000 --- a/partitions_custom.csv +++ /dev/null @@ -1,6 +0,0 @@ -# Name, Type, SubType, Offset, Size, Flags -ota_0, app, ota_0, 0x10000, 0x1A0000 -ota_1, app, ota_1, , 0x1A0000 -otadata, data, ota, 0x350000, 0x2000 -nvs, data, nvs, , 0x6000 -data, data, spiffs, , 0xA8000 \ No newline at end of file diff --git a/platformio.ini b/platformio.ini deleted file mode 100644 index a60ef27d..00000000 --- a/platformio.ini +++ /dev/null @@ -1,80 +0,0 @@ - -[platformio] -default_envs = esp8266 -build_cache_dir = .cache - -;============================================================================================================================================= -[common_env_data] -lib_ldf_mode = chain+ -lib_deps_external = - bblanchon/ArduinoJson @5.* - thomasfredericks/Bounce2 - knolleary/PubSubClient - beegee-tokyo/DHT sensor library for ESPx - adafruit/Adafruit BMP280 Library - adafruit/Adafruit BME280 Library - milesburton/DallasTemperature -lib_deps_internal = - ESP Async WebServer - GyverFilters - OneWire -;============================================================================================================================================= -[env:esp32] -framework = arduino -board = esp32dev -platform = https://github.com/platformio/platform-espressif32.git -lib_deps = - ${common_env_data.lib_deps_external} - ${common_env_data.lib_deps_internal} - AsyncTCP - madhephaestus/ESP32Servo - luc-github/ESP32SSDP - CTBot -monitor_filters = esp32_exception_decoder -upload_speed = 921600 -monitor_speed = 115200 -board_build.filesystem = littlefs -extra_scripts = - tools/littlefsbuilder.py - ${scripts_defaults.extra_scripts} -;============================================================================================================================================= -[env:esp8266_01_1m] -framework = arduino -board = esp01_1m -board_build.ldscript = eagle.flash.1m512.ld -platform = https://github.com/platformio/platform-espressif8266.git -lib_deps = - ${common_env_data.lib_deps_external} - ${common_env_data.lib_deps_internal} - ESPAsyncTCP - ESPAsyncUDP - EspSoftwareSerial - CTBot -monitor_filters = esp8266_exception_decoder -upload_speed = 921600 -monitor_speed = 115200 -board_build.filesystem = littlefs -;============================================================================================================================================= -[env:esp8266] -framework = arduino -board = nodemcuv2 -platform = https://github.com/platformio/platform-espressif8266.git -lib_deps = - ${common_env_data.lib_deps_external} - ${common_env_data.lib_deps_internal} - ESPAsyncTCP - ESPAsyncUDP - EspSoftwareSerial - CTBot -monitor_filters = esp8266_exception_decoder -upload_speed = 921600 -monitor_speed = 115200 -board_build.filesystem = littlefs -extra_scripts = - ${scripts_defaults.extra_scripts} -;============================================================================================================================================= - -[scripts_defaults] -extra_scripts = - tools/name-firmware.py - tools/gzip-firmware.py diff --git a/src/BufferExecute.cpp b/src/BufferExecute.cpp deleted file mode 100644 index ecba8a91..00000000 --- a/src/BufferExecute.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include "BufferExecute.h" -#include "items/SensorDallas.h" -#include "Global.h" -#include "Module/Terminal.h" - -void loopCmdAdd(const String& cmdStr) { - orderBuf += cmdStr; - if (!cmdStr.endsWith(",")) { - orderBuf += ","; - } -} - -void fileCmdExecute(const String& filename) { - String cmdStr = readFile(filename, 4096); - csvCmdExecute(cmdStr); -} - -void csvCmdExecute(String& cmdStr) { - cmdStr.replace(";", " "); - cmdStr += "\r\n"; - cmdStr.replace("\r\n", "\n"); - cmdStr.replace("\r", "\n"); - int count = 0; - while (cmdStr.length()) { - String buf = selectToMarker(cmdStr, "\n"); - - - - buf = deleteBeforeDelimiter(buf, " "); //отсечка чекбокса - - count++; - if (count > 1) { - SerialPrint("I", "Items", buf); - String order = selectToMarker(buf, " "); //отсечка самой команды - - if (order == F("button-out")) { - sCmd.addCommand(order.c_str(), buttonOut); - } - else if (order == F("pwm-out")) { - sCmd.addCommand(order.c_str(), pwmOut); - } - else if (order == F("button-in")) { - sCmd.addCommand(order.c_str(), buttonIn); - } - else if (order == F("input-digit")) { - sCmd.addCommand(order.c_str(), inputDigit); - } - else if (order == F("input-time")) { - sCmd.addCommand(order.c_str(), inputTime); - } - else if (order == F("output-text")) { - sCmd.addCommand(order.c_str(), textOut); - } - else if (order == F("analog-adc")) { - sCmd.addCommand(order.c_str(), analogAdc); - } - else if (order == F("ultrasonic-cm")) { - sCmd.addCommand(order.c_str(), ultrasonicCm); - } - else if (order == F("dallas-temp")) { - sCmd.addCommand(order.c_str(), dallas); - } - else if (order == F("dht-temp")) { - sCmd.addCommand(order.c_str(), dhtTemp); - } - else if (order == F("dht-hum")) { - sCmd.addCommand(order.c_str(), dhtHum); - } - else if (order == F("bme280-temp")) { - sCmd.addCommand(order.c_str(), bme280Temp); - } - else if (order == F("bme280-hum")) { - sCmd.addCommand(order.c_str(), bme280Hum); - } - else if (order == F("bme280-press")) { - sCmd.addCommand(order.c_str(), bme280Press); - } - else if (order == F("bmp280-temp")) { - sCmd.addCommand(order.c_str(), bmp280Temp); - } - else if (order == F("bmp280-press")) { - sCmd.addCommand(order.c_str(), bmp280Press); - } - else if (order == F("modbus")) { - //sCmd.addCommand(order.c_str(), modbus); - } - else if (order == F("uptime")) { - sCmd.addCommand(order.c_str(), sysUptime); - } - else if (order == F("logging")) { - sCmd.addCommand(order.c_str(), logging); - } - else if (order == F("impuls-out")) { - sCmd.addCommand(order.c_str(), impuls); - } - - - - sCmd.readStr(buf); - } - cmdStr = deleteBeforeDelimiter(cmdStr, "\n"); - } -} - -void spaceCmdExecute(String& cmdStr) { - cmdStr += "\r\n"; - cmdStr.replace("\r\n", "\n"); - cmdStr.replace("\r", "\n"); - while (cmdStr.length()) { - String buf = selectToMarker(cmdStr, "\n"); - sCmd.readStr(buf); - cmdStr = deleteBeforeDelimiter(cmdStr, "\n"); - } -} - -void loopCmdExecute() { - if (orderBuf.length()) { - String tmp = selectToMarker(orderBuf, ","); //выделяем первую команду rel 5 1, - SerialPrint("I", "CMD", "do: " + tmp); - sCmd.readStr(tmp); //выполняем - orderBuf = deleteBeforeDelimiter(orderBuf, ","); //осекаем - } -} - -void sensorsInit() { - ts.add( - SENSORS10SEC, 10000, [&](void*) { - String buf = sensorReadingMap10sec; - while (buf.length()) { - String tmp = selectToMarker(buf, ","); - sCmd.readStr(tmp); - buf = deleteBeforeDelimiter(buf, ","); - } - }, - nullptr, true); - - ts.add( - SENSORS30SEC, 30000, [&](void*) { - String buf = sensorReadingMap30sec; - while (buf.length()) { - String tmp = selectToMarker(buf, ","); - sCmd.readStr(tmp); - buf = deleteBeforeDelimiter(buf, ","); - } - }, - nullptr, true); -} - -void addKey(String& key, String& keyNumberTable, int number) { - keyNumberTable += key + " " + String(number) + ","; -} - -int getKeyNum(String& key, String& keyNumberTable) { - String keyNumberTableBuf = keyNumberTable; - - int number = -1; - while (keyNumberTableBuf.length()) { - String tmp = selectToMarker(keyNumberTableBuf, ","); - String keyIncomming = selectToMarker(tmp, " "); - if (keyIncomming == key) { - number = selectToMarkerLast(tmp, " ").toInt(); - } - keyNumberTableBuf = deleteBeforeDelimiter(keyNumberTableBuf, ","); - } - return number; -} diff --git a/src/Bus.cpp b/src/Bus.cpp deleted file mode 100644 index 12cbcf6a..00000000 --- a/src/Bus.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "Bus.h" -#include "Class/NotAsync.h" -#include "Global.h" - -void busInit() { - myNotAsyncActions->add( - do_BUSSCAN, [&](void*) { - String tmp = i2c_scan(); - if (tmp == "error") { - tmp = i2c_scan(); - Serial.println(tmp); - jsonWriteStr(configLiveJson, "i2c", tmp); - } else { - Serial.println(tmp); - jsonWriteStr(configLiveJson, "i2c", tmp); - } - }, - nullptr); -} - -String i2c_scan() { - String out; - byte count = 0; - Wire.begin(); - for (byte i = 8; i < 120; i++) { - Wire.beginTransmission(i); - if (Wire.endTransmission() == 0) { - count++; - out += String(count) + ". 0x" + String(i, HEX) + "; "; - delay(1); - } - } - if (count == 0) { - return "error"; - } else { - return out; - } -} \ No newline at end of file diff --git a/src/Class/CallBackTest.cpp b/src/Class/CallBackTest.cpp deleted file mode 100644 index 55252e5e..00000000 --- a/src/Class/CallBackTest.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "Class/CallBackTest.h" - -CallBackTest::CallBackTest(){}; - -void CallBackTest::loop() { - count++; - if (count > 5000) { - // Проверяем что переменная содержит указатель - не пустая не null - // и непосредственно вызываем то, на что это указывает - // просто пишем имя - без () - это указатель на фунецию. - // () - вызываем функцию - с пустым набором параметров - - if (_cb != NULL) { - _cb(); - } - //или ровно тоже самое - //if (_cb) _cb(); - - if (_pcb) { - if (_pcb("SomeTextValue")) { - Serial.println("Got true!"); - } else { - Serial.println("Got false!"); - } - } - - count = 0; - } -} - -//передаем внутрь класса функцию любую void функцию без агрументов -void CallBackTest::setCallback(AsyncActionCb cb) { - _cb = cb; -} - -//передаем внутрь класса функцию любую void функцию с аргументами -void CallBackTest::setCallback(AsyncParamActionCb pcb) { - _pcb = pcb; -} -//CallBackTest* CB; - -//CB->setCallback([]() { -// Serial.println("123"); -//}); -// -//CB->setCallback([](const String str) { -// Serial.println(str); -// return true; -//}); \ No newline at end of file diff --git a/src/Class/LineParsing.cpp b/src/Class/LineParsing.cpp deleted file mode 100644 index 9e9e7ac0..00000000 --- a/src/Class/LineParsing.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "Class/LineParsing.h" -LineParsing myLineParsing; \ No newline at end of file diff --git a/src/Class/NotAsync.cpp b/src/Class/NotAsync.cpp deleted file mode 100644 index 75c2ce24..00000000 --- a/src/Class/NotAsync.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "Class/NotAsync.h" - -NotAsync::NotAsync(uint8_t size) { - this->items = new NotAsyncItem[size]; - this->size = size; -} - -NotAsync::~NotAsync() {} - -void NotAsync::add(uint8_t i, NotAsyncCb f, void* arg) { - this->items[i].cb = f; - this->items[i].cb_arg = arg; - this->items[i].is_used = true; -} - -void NotAsync::loop() { - if (this->items[task].is_used) { - handle(this->items[task].cb, this->items[task].cb_arg); - task = 0; - } -} - -void NotAsync::make(uint8_t task) { - this->task = task; -} - -void NotAsync::handle(NotAsyncCb f, void* arg) { - f(arg); -} -NotAsync* myNotAsyncActions; \ No newline at end of file diff --git a/src/Class/ScenarioClass3.cpp b/src/Class/ScenarioClass3.cpp deleted file mode 100644 index 1876711f..00000000 --- a/src/Class/ScenarioClass3.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "Class/ScenarioClass3.h" -Scenario* myScenario; - -//void eventGen(String event_name, String number) { -// if (!jsonReadBool(configSetupJson, "scen")) { -// return; -// } -// SerialPrint("", "", event_name); -// eventBuf += event_name + number + ","; -//} - -void eventGen2(String eventName, String eventValue) { - if (!jsonReadBool(configSetupJson, "scen")) { - return; - } - //Serial.println(eventName + " " + eventValue); - eventBuf += eventName + " " + eventValue + ","; -} \ No newline at end of file diff --git a/src/Clock.cpp b/src/Clock.cpp deleted file mode 100644 index 888f9d5b..00000000 --- a/src/Clock.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "Clock.h" - -#include "Global.h" - -Clock* timeNow; -void clock_init() { - timeNow = new Clock; - timeNow->setNtpPool(jsonReadStr(configSetupJson, "ntp")); - timeNow->setTimezone(jsonReadStr(configSetupJson, "timezone").toInt()); - - ts.add( - TIME_SYNC, 30000, [&](void*) { - timeNow->hasSync(); - }, - nullptr, true); -} diff --git a/src/FSEditor.cpp b/src/FSEditor.cpp deleted file mode 100644 index 5f33d075..00000000 --- a/src/FSEditor.cpp +++ /dev/null @@ -1,341 +0,0 @@ -#include "FSEditor.h" - -#ifdef ESP32 -#include "LITTLEFS.h" -#define LittleFS LITTLEFS -#endif -#ifdef ESP8266 -#include -#endif - -#define FS_MAXLENGTH_FILEPATH 32 - -const char *excludeListFile = "/.exclude.files"; - -typedef struct ExcludeListS { - char *item; - ExcludeListS *next; -} ExcludeList; - -static ExcludeList *excludes = NULL; - -static bool matchWild(const char *pattern, const char *testee) { - const char *nxPat = NULL, *nxTst = NULL; - - while (*testee) { - if ((*pattern == '?') || (*pattern == *testee)) { - pattern++; - testee++; - continue; - } - if (*pattern == '*') { - nxPat = pattern++; - nxTst = testee; - continue; - } - if (nxPat) { - pattern = nxPat + 1; - testee = ++nxTst; - continue; - } - return false; - } - while (*pattern == '*') { - pattern++; - } - return (*pattern == 0); -} - -static bool addExclude(const char *item) { - size_t len = strlen(item); - if (!len) { - return false; - } - ExcludeList *e = (ExcludeList *)malloc(sizeof(ExcludeList)); - if (!e) { - return false; - } - e->item = (char *)malloc(len + 1); - if (!e->item) { - free(e); - return false; - } - memcpy(e->item, item, len + 1); - e->next = excludes; - excludes = e; - return true; -} - -static void loadExcludeList(fs::FS &_fs, const char *filename) { - static char linebuf[FS_MAXLENGTH_FILEPATH]; - fs::File excludeFile = _fs.open(filename, "r"); - if (!excludeFile) { - return; - } - if (excludeFile.isDirectory()) { - excludeFile.close(); - return; - } - if (excludeFile.size() > 0) { - uint8_t idx; - bool isOverflowed = false; - while (excludeFile.available()) { - linebuf[0] = '\0'; - idx = 0; - int lastChar; - do { - lastChar = excludeFile.read(); - if (lastChar != '\r') { - linebuf[idx++] = (char)lastChar; - } - } while ((lastChar >= 0) && (lastChar != '\n') && (idx < FS_MAXLENGTH_FILEPATH)); - - if (isOverflowed) { - isOverflowed = (lastChar != '\n'); - continue; - } - isOverflowed = (idx >= FS_MAXLENGTH_FILEPATH); - linebuf[idx - 1] = '\0'; - if (!addExclude(linebuf)) { - excludeFile.close(); - return; - } - } - } - excludeFile.close(); -} - -static bool isExcluded(fs::FS &_fs, const char *filename) { - if (excludes == NULL) { - loadExcludeList(_fs, excludeListFile); - } - if (strcmp(excludeListFile, filename) == 0) return true; - ExcludeList *e = excludes; - while (e) { - if (matchWild(e->item, filename)) { - return true; - } - e = e->next; - } - return false; -} - -// WEB HANDLER IMPLEMENTATION - -#ifdef ESP32 -FSEditor::FSEditor(const fs::FS &fs, const String &username, const String &password) -#else -FSEditor::FSEditor(const String &username, const String &password, const fs::FS &fs) -#endif - : _fs(fs), _username(username), _password(password), _authenticated(false), _startTime(0) { -} - -bool FSEditor::canHandle(AsyncWebServerRequest *request) { - if (request->url().equalsIgnoreCase("/edit")) { - if (request->method() == HTTP_GET) { - if (request->hasParam("list")) - return true; - if (request->hasParam("edit")) { - request->_tempFile = _fs.open(request->arg("edit"), "r"); - if (!request->_tempFile) { - return false; - } - if (request->_tempFile.isDirectory()) { - request->_tempFile.close(); - return false; - } - } - if (request->hasParam("download")) { - request->_tempFile = _fs.open(request->arg("download"), "r"); - if (!request->_tempFile) { - return false; - } - if (request->_tempFile.isDirectory()) { - request->_tempFile.close(); - return false; - } - } - request->addInterestingHeader("If-Modified-Since"); - return true; - } else if (request->method() == HTTP_POST) - return true; - else if (request->method() == HTTP_DELETE) - return true; - else if (request->method() == HTTP_PUT) - return true; - } - return false; -} - -#ifdef ESP8266 -void FSEditor::getDirList(const String &path, String &output) { - auto dir = _fs.openDir(path.c_str()); - while (dir.next()) { - String fname = dir.fileName(); - if (!path.endsWith("/") && !fname.startsWith("/")) { - fname = "/" + fname; - } - fname = path + fname; - if (isExcluded(_fs, fname.c_str())) { - continue; - } - if (dir.isDirectory()) { - getDirList(fname, output); - continue; - } - if (output != "[") output += ','; - char buf[128]; - sprintf(buf, "{\"type\":\"file\",\"name\":\"%s\",\"size\":%d}", fname.c_str(), dir.fileSize()); - output += buf; - } -} -#else -void FSEditor::getDirList(const String &path, String &output) { - auto dir = _fs.open(path, FILE_READ); - dir.rewindDirectory(); - while (dir.openNextFile()) { - String fname = dir.name(); - if (!path.endsWith("/") && !fname.startsWith("/")) { - fname = "/" + fname; - } - fname = path + fname; - if (isExcluded(_fs, fname.c_str())) { - continue; - } - if (dir.isDirectory()) { - getDirList(fname, output); - continue; - } - if (output != "[") output += ','; - char buf[128]; - sprintf(buf, "{\"type\":\"file\",\"name\":\"%s\",\"size\":%d}", fname.c_str(), dir.size()); - output += buf; - } -} -#endif - -void FSEditor::handleRequest(AsyncWebServerRequest *request) { - if (_username.length() && _password.length() && !request->authenticate(_username.c_str(), _password.c_str())) - return request->requestAuthentication(); - - if (request->method() == HTTP_GET) { - if (request->hasParam("list")) { - if (request->hasParam("list")) { - String path = request->getParam("list")->value(); - String output = "["; - getDirList(path, output); - output += "]"; - request->send(200, "application/json", output); - output = String(); - } - } else if (request->hasParam("edit") || request->hasParam("download")) { -#ifdef ESP8266 - request->send(request->_tempFile, request->_tempFile.fullName(), String(), request->hasParam("download")); -#else - request->send(request->_tempFile, request->_tempFile.name(), String(), request->hasParam("download")); -#endif - } else { - const char *buildTime = __DATE__ " " __TIME__ " GMT"; - if (request->header("If-Modified-Since").equals(buildTime)) { - request->send(304); - } else { - AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/edit.htm", "text/html"); - // response->addHeader("Content-Encoding", "gzip"); - response->addHeader("Last-Modified", buildTime); - request->send(response); - } - } - } else if (request->method() == HTTP_DELETE) { - if (request->hasParam("path", true)) { - if (!(_fs.remove(request->getParam("path", true)->value()))) { -#ifdef ESP32 - _fs.rmdir(request->getParam("path", true)->value()); // try rmdir for littlefs -#endif - } - - request->send(200, "", "DELETE: " + request->getParam("path", true)->value()); - } else - request->send(404); - } else if (request->method() == HTTP_POST) { - if (request->hasParam("data", true, true) && _fs.exists(request->getParam("data", true, true)->value())) - request->send(200, "", "UPLOADED: " + request->getParam("data", true, true)->value()); - - else if (request->hasParam("rawname", true) && request->hasParam("raw0", true)) { - String rawnam = request->getParam("rawname", true)->value(); - - if (_fs.exists(rawnam)) _fs.remove(rawnam); // delete it to allow a mode - - int k = 0; - uint16_t i = 0; - fs::File f = _fs.open(rawnam, "a"); - - while (request->hasParam("raw" + String(k), true)) { //raw0 .. raw1 - if (f) { - i += f.print(request->getParam("raw" + String(k), true)->value()); - } - k++; - } - f.close(); - request->send(200, "", "IPADWRITE: " + rawnam + ":" + String(i)); - - } else { - request->send(500); - } - - } else if (request->method() == HTTP_PUT) { - if (request->hasParam("path", true)) { - String filename = request->getParam("path", true)->value(); - if (_fs.exists(filename)) { - request->send(200); - } else { -/*******************************************************/ -#ifdef ESP32 - if (strchr(filename.c_str(), '/')) { - // For file creation, silently make subdirs as needed. If any fail, - // it will be caught by the real file open later on - char *pathStr = strdup(filename.c_str()); - if (pathStr) { - // Make dirs up to the final fnamepart - char *ptr = strchr(pathStr, '/'); - while (ptr) { - *ptr = 0; - _fs.mkdir(pathStr); - *ptr = '/'; - ptr = strchr(ptr + 1, '/'); - } - } - free(pathStr); - } -#endif - /*******************************************************/ - fs::File f = _fs.open(filename, "w"); - if (f) { - f.write((uint8_t)0x00); - f.close(); - request->send(200, "", "CREATE: " + filename); - } else { - request->send(500); - } - } - } else - request->send(400); - } -} - -void FSEditor::handleUpload(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) { - if (!index) { - if (!_username.length() || request->authenticate(_username.c_str(), _password.c_str())) { - _authenticated = true; - request->_tempFile = _fs.open(filename, "w"); - _startTime = millis(); - } - } - if (_authenticated && request->_tempFile) { - if (len) { - request->_tempFile.write(data, len); - } - if (final) { - request->_tempFile.close(); - } - } -} diff --git a/src/Global.cpp b/src/Global.cpp deleted file mode 100644 index 75203c97..00000000 --- a/src/Global.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "Global.h" - -#ifdef WS_enable -AsyncWebSocket ws; -//AsyncEventSource events; -#endif - -TickerScheduler ts(TEST + 1); -WiFiClient espClient; -PubSubClient mqtt(espClient); -StringCommand sCmd; -AsyncWebServer server(80); -OneWire *oneWire; -DallasTemperature sensors; - -/* -* Global vars -*/ - -boolean just_load = true; -boolean telegramInitBeen = false; - -// Json -String configSetupJson = "{}"; -String configLiveJson = "{}"; -String configOptionJson = "{}"; - -// Mqtt -String chipId = ""; -String prex = ""; -String all_widgets = ""; -String scenario = ""; - -//orders and events -String orderBuf = ""; -String eventBuf = ""; -String itemsFile = ""; -String itemsLine = ""; - -//key lists and numbers -String impulsKeyList = ""; -int impulsEnterCounter = -1; - - -// Sensors -String sensorReadingMap10sec; -String sensorReadingMap30sec; - -// Logging -String loggingKeyList; -int enter_to_logging_counter; - -// Upgrade -String serverIP; - -// Scenario -int scenario_line_status[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; -int lastVersion; - -boolean busScanFlag = false; -boolean fsCheckFlag = false; -boolean delElementFlag = false; - diff --git a/src/Init.cpp b/src/Init.cpp deleted file mode 100644 index f49654c4..00000000 --- a/src/Init.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "Init.h" -#include "BufferExecute.h" -#include "Cmd.h" -#include "Global.h" -#include "items/LoggingClass.h" -#include "items/ImpulsOutClass.h" -#include "items/SensorDallas.h" - -void loadConfig() { - configSetupJson = readFile("config.json", 4096); - //configSetupJson.replace(" ", ""); - configSetupJson.replace("\r\n", ""); - - jsonWriteStr(configSetupJson, "chipID", chipId); - jsonWriteInt(configSetupJson, "firmware_version", FIRMWARE_VERSION); - - prex = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + chipId; - - Serial.println(configSetupJson); - - serverIP = jsonReadStr(configSetupJson, "serverip"); -} - -void all_init() { - Device_init(); - loadScenario(); - Timer_countdown_init(); -} - -void Device_init() { - - sensorReadingMap10sec = ""; - - //======clear dallas params====== - if (mySensorDallas2 != nullptr) { - mySensorDallas2->clear(); - } - //======clear logging params====== - if (myLogging != nullptr) { - myLogging->clear(); - } - loggingKeyList = ""; - //======clear impuls params======= - if (myImpulsOut != nullptr) { - myImpulsOut->clear(); - } - impulsKeyList = ""; - impulsEnterCounter = -1; - //================================ - - -#ifdef LAYOUT_IN_RAM - all_widgets = ""; -#else - removeFile(String("layout.txt")); -#endif - - fileCmdExecute(String(DEVICE_CONFIG_FILE)); - //outcoming_date(); -} -//-------------------------------сценарии----------------------------------------------------- - -void loadScenario() { - if (jsonReadStr(configSetupJson, "scen") == "1") { - scenario = readFile(String(DEVICE_SCENARIO_FILE), 2048); - } -} - -void uptime_init() { - ts.add( - UPTIME, 5000, [&](void*) { - handle_uptime(); - }, - nullptr, true); -} - -void handle_uptime() { - jsonWriteStr(configSetupJson, "uptime", timeNow->getUptime()); -} - -//void handle_statistics() { -// if (isNetworkActive()) { -// String urls = "http://backup.privet.lv/visitors/?"; -// //----------------------------------------------------------------- -// urls += WiFi.macAddress().c_str(); -// urls += "&"; -// //----------------------------------------------------------------- -//#ifdef ESP8266 -// urls += "iot-manager_esp8266"; -//#endif -//#ifdef ESP32 -// urls += "iot-manager_esp32"; -//#endif -// urls += "&"; -//#ifdef ESP8266 -// urls += ESP.getResetReason(); -//#endif -//#ifdef ESP32 -// urls += "Power on"; -//#endif -// urls += "&"; -// urls += String(FIRMWARE_VERSION); -// String stat = getURL(urls); -// } -//} \ No newline at end of file diff --git a/src/ItemsCmd.cpp b/src/ItemsCmd.cpp deleted file mode 100644 index be6330ac..00000000 --- a/src/ItemsCmd.cpp +++ /dev/null @@ -1,334 +0,0 @@ -//#include "BufferExecute.h" -// -//#include "BufferExecute.h" -//#include "Class/NotAsync.h" -//#include "Cmd.h" -//#include "Global.h" -//#include "Module/Terminal.h" -//#include "Servo/Servos.h" -// -//#include "items/SensorDallas.h" -// -//Terminal *term = nullptr; -// -//boolean but[NUM_BUTTONS]; -//Bounce *buttons = new Bounce[NUM_BUTTONS]; -// -//#ifdef ESP8266 -//SoftwareSerial *mySerial = nullptr; -//#else -//HardwareSerial *mySerial = nullptr; -//#endif -// -//void getData(); -// -//void cmd_init() { - //sCmd.addCommand("button-out", buttonOut); - //sCmd.addCommand("pwm-out", pwmOut); - //sCmd.addCommand("button-in", buttonIn); - - //sCmd.addCommand("input-digit", inputDigit); - //sCmd.addCommand("input-time", inputTime); - //sCmd.addCommand("output-text", textOut); - - //sCmd.addCommand("analog-adc", analogAdc); - //sCmd.addCommand("ultrasonic-cm", ultrasonicCm); - //sCmd.addCommand("dallas-temp", dallas); - - //sCmd.addCommand("dht-temp", dhtTemp); - //sCmd.addCommand("dht-hum", dhtHum); - - //sCmd.addCommand("bme280-temp", bme280Temp); - //sCmd.addCommand("bme280-hum", bme280Hum); - //sCmd.addCommand("bme280-press", bme280Press); - - //sCmd.addCommand("bmp280-temp", bmp280Temp); - //sCmd.addCommand("bmp280-press", bmp280Press); - - //sCmd.addCommand("modbus", modbus); - - //sCmd.addCommand("uptime", sysUptime); - - //sCmd.addCommand("logging", logging); - - //sCmd.addCommand("impuls-out", impuls); - - -//} - -// sCmd.addCommand("timerStart", timerStart_); -// sCmd.addCommand("timerStop", timerStop_); - -//#ifdef DHT_ENABLED -// sCmd.addCommand("dhtT", dhtT); -// sCmd.addCommand("dhtH", dhtH); -// sCmd.addCommand("dhtPerception", dhtP); -// sCmd.addCommand("dhtComfort", dhtC); -// sCmd.addCommand("dhtDewpoint", dhtD); -//#endif - -//#ifdef BMP_ENABLED -// sCmd.addCommand("bmp280T", bmp280T); -// sCmd.addCommand("bmp280P", bmp280P); -//#endif -// -//#ifdef BME_ENABLED -// sCmd.addCommand("bme280T", bme280T); -// sCmd.addCommand("bme280P", bme280P); -// sCmd.addCommand("bme280H", bme280H); -// sCmd.addCommand("bme280A", bme280A); -//#endif -// -//#ifdef STEPPER_ENABLED -// sCmd.addCommand("stepper", stepper); -// sCmd.addCommand("stepperSet", stepperSet); -//#endif -// -//#ifdef SERVO_ENABLED -// sCmd.addCommand("servo", servo_); -// sCmd.addCommand("servoSet", servoSet); -//#endif -// -//#ifdef SERIAL_ENABLED -// sCmd.addCommand("serialBegin", serialBegin); -// sCmd.addCommand("serialWrite", serialWrite); -// sCmd.addCommand("getData", getData); -//#endif -// -//#ifdef LOGGING_ENABLED -// sCmd.addCommand("logging", logging); -//#endif -// -// sCmd.addCommand("mqtt", mqttOrderSend); -// sCmd.addCommand("http", httpOrderSend); -// -//#ifdef PUSH_ENABLED -// sCmd.addCommand("push", pushControl); -//#endif -// -// sCmd.addCommand("firmwareUpdate", firmwareUpdate); -// sCmd.addCommand("firmwareVersion", firmwareVersion); - -//void text() { -// String number = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String page_number = sCmd.next(); -// -// createWidget(widget_name, page_name, page_number, "anydata", "text" + number); -//} -// -//void textSet() { -// String number = sCmd.next(); -// String text = sCmd.next(); -// text.replace("_", " "); -// -// if (text.indexOf("-time") >= 0) { -// text.replace("-time", ""); -// text.replace("#", " "); -// text = text + " " + timeNow->getDateTimeDotFormated(); -// } -// -// jsonWriteStr(configLiveJson, "text" + number, text); -// publishStatus("text" + number, text); -//} -//===================================================================================================================================== -////=========================================Модуль шагового мотора====================================================================== -//#ifdef STEPPER_ENABLED -////stepper 1 12 13 -//void stepper() { -// String stepper_number = sCmd.next(); -// String pin_step = sCmd.next(); -// String pin_dir = sCmd.next(); -// -// jsonWriteStr(configOptionJson, "stepper" + stepper_number, pin_step + " " + pin_dir); -// pinMode(pin_step.toInt(), OUTPUT); -// pinMode(pin_dir.toInt(), OUTPUT); -//} -// -////stepperSet 1 100 5 -//void stepperSet() { -// String stepper_number = sCmd.next(); -// String steps = sCmd.next(); -// jsonWriteStr(configOptionJson, "steps" + stepper_number, steps); -// String stepper_speed = sCmd.next(); -// String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper" + stepper_number), " "); -// String pin_dir = deleteBeforeDelimiter(jsonReadStr(configOptionJson, "stepper" + stepper_number), " "); -// Serial.println(pin_step); -// Serial.println(pin_dir); -// if (steps.toInt() > 0) digitalWrite(pin_dir.toInt(), HIGH); -// if (steps.toInt() < 0) digitalWrite(pin_dir.toInt(), LOW); -// if (stepper_number == "1") { -// ts.add( -// STEPPER1, stepper_speed.toInt(), [&](void *) { -// int steps_int = abs(jsonReadInt(configOptionJson, "steps1") * 2); -// static int count; -// count++; -// String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper1"), " "); -// digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt())); -// yield(); -// if (count > steps_int) { -// digitalWrite(pin_step.toInt(), LOW); -// ts.remove(STEPPER1); -// count = 0; -// } -// }, -// nullptr, true); -// } -// if (stepper_number == "2") { -// ts.add( -// STEPPER2, stepper_speed.toInt(), [&](void *) { -// int steps_int = abs(jsonReadInt(configOptionJson, "steps2") * 2); -// static int count; -// count++; -// String pin_step = selectToMarker(jsonReadStr(configOptionJson, "stepper2"), " "); -// digitalWrite(pin_step.toInt(), !digitalRead(pin_step.toInt())); -// yield(); -// if (count > steps_int) { -// digitalWrite(pin_step.toInt(), LOW); -// ts.remove(STEPPER2); -// count = 0; -// } -// }, -// nullptr, true); -// } -//} -//#endif -////==================================================================================================================================================== -////=================================================================Сервоприводы======================================================================= -//#ifdef SERVO_ENABLED -////servo 1 13 50 Мой#сервопривод Сервоприводы 0 100 0 180 2 -//void servo_() { -// String number = sCmd.next(); -// uint8_t pin = String(sCmd.next()).toInt(); -// int value = String(sCmd.next()).toInt(); -// -// String widget = sCmd.next(); -// String page = sCmd.next(); -// -// int min_value = String(sCmd.next()).toInt(); -// int max_value = String(sCmd.next()).toInt(); -// int min_deg = String(sCmd.next()).toInt(); -// int max_deg = String(sCmd.next()).toInt(); -// -// String pageNumber = sCmd.next(); -// -// jsonWriteStr(configOptionJson, "servo_pin" + number, String(pin, DEC)); -// -// value = map(value, min_value, max_value, min_deg, max_deg); -// -// Servo *servo = myServo.create(number.toInt(), pin); -// servo->write(value); -//#ifdef ESP32 -// myServo1.attach(servo_pin.toInt(), 500, 2400); -// myServo1.write(start_state_int); -//#endif -// -// jsonWriteInt(configOptionJson, "s_min_val" + number, min_value); -// jsonWriteInt(configOptionJson, "s_max_val" + number, max_value); -// jsonWriteInt(configOptionJson, "s_min_deg" + number, min_deg); -// jsonWriteInt(configOptionJson, "s_max_deg" + number, max_deg); -// -// jsonWriteInt(configLiveJson, "servo" + number, value); -// -// createWidgetParam(widget, page, pageNumber, "range", "servo" + number, "min", String(min_value), "max", String(max_value), "k", "1"); -//} -// -//void servoSet() { -// String number = sCmd.next(); -// int value = String(sCmd.next()).toInt(); -// -// value = map(value, -// jsonReadInt(configOptionJson, "s_min_val" + number), -// jsonReadInt(configOptionJson, "s_max_val" + number), -// jsonReadInt(configOptionJson, "s_min_deg" + number), -// jsonReadInt(configOptionJson, "s_max_deg" + number)); -// -// Servo *servo = myServo.get(number.toInt()); -// if (servo) { -// servo->write(value); -// } -// -// eventGen2("servo", number); -// jsonWriteInt(configLiveJson, "servo" + number, value); -// publishStatus("servo" + number, String(value, DEC)); -//} -//#endif -////==================================================================================================================================================== -////=============================================================Модуль сериал порта======================================================================= -// -//#ifdef SERIAL_ENABLED -//void serialBegin() { -// String s_speed = sCmd.next(); -// String rxPin = sCmd.next(); -// String txPin = sCmd.next(); -// -// if (mySerial) { -// delete mySerial; -// } -// -//#ifdef ESP8266 -// mySerial = new SoftwareSerial(rxPin.toInt(), txPin.toInt()); -// mySerial->begin(s_speed.toInt()); -//#else -// mySerial = new HardwareSerial(2); -// mySerial->begin(rxPin.toInt(), txPin.toInt()); -//#endif -// -// term = new Terminal(mySerial); -// term->setEOL(LF); -// term->enableColors(false); -// term->enableControlCodes(false); -// term->enableEcho(false); -// term->setOnReadLine([](const char *str) { -// String line = String(str); -// loopCmdAdd(line); -// }); -//} -// -//void getData() { -// String param = sCmd.next(); -// String res = param.length() ? jsonReadStr(configLiveJson, param) : configLiveJson; -// if (term) { -// term->println(res.c_str()); -// } -//} -// -//void serialWrite() { -// String payload = sCmd.next(); -// if (term) { -// term->println(payload.c_str()); -// } -//} -//#endif -////==================================================================================================================================================== -////=================================================Глобальные команды удаленного управления=========================================================== -// -//void mqttOrderSend() { -// String id = sCmd.next(); -// String order = sCmd.next(); -// -// String all_line = jsonReadStr(configSetupJson, "mqttPrefix") + "/" + id + "/order"; -// mqtt.publish(all_line.c_str(), order.c_str(), false); -//} -// -//void httpOrderSend() { -// String ip = sCmd.next(); -// String order = sCmd.next(); -// order.replace("_", "%20"); -// String url = "http://" + ip + "/cmd?command=" + order; -// getURL(url); -//} -// -//void firmwareUpdate() { -// myNotAsyncActions->make(do_UPGRADE); -//} -// -//void firmwareVersion() { -// String widget = sCmd.next(); -// String page = sCmd.next(); -// String pageNumber = sCmd.next(); -// -// jsonWriteStr(configLiveJson, "firmver", FIRMWARE_VERSION); -// createWidget(widget, page, pageNumber, "anydata", "firmver"); -//} diff --git a/src/ItemsList.cpp b/src/ItemsList.cpp deleted file mode 100644 index d4d1cf8a..00000000 --- a/src/ItemsList.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "ItemsList.h" - -#include "Class/NotAsync.h" -#include "Init.h" -#include "Utils/StringUtils.h" - -static const char* firstLine PROGMEM = "Удалить;Тип элемента;Id;Виджет;Имя вкладки;Имя виджета;Позиция виджета"; - -void itemsListInit() { - myNotAsyncActions->add( - do_deviceInit, [&](void*) { - Device_init(); - }, - nullptr); - - myNotAsyncActions->add( - do_delChoosingItems, [&](void*) { - delChoosingItems(); - }, - nullptr); -} - -void addItem(String name) { - String item = readFile("items/" + name + ".txt", 1024); - - name = deleteToMarkerLast(name, "."); - - item.replace("id", name + "-" + String(getNewElementNumber("id.txt"))); - item.replace("order", String(getNewElementNumber("order.txt"))); - - if (item.indexOf("pin") != -1) { //all cases (random pins from available) - item.replace("pin", "pin[" + String(getFreePinAll()) + "]"); - } else - - if (item.indexOf("gol") != -1) { //analog - item.replace("gol", "pin[" + String(getFreePinAnalog()) + "]"); - } else - - if (item.indexOf("cin") != -1) { //ultrasonic - item.replace("cin", "pin[" + String(getFreePinAll()) + "," + String(getFreePinAll()) + "]"); - } else - - if (item.indexOf("sal") != -1) { //dallas - item.replace("sal", "pin[2]"); - } else - - if (item.indexOf("thd") != -1) { //dht11/22 - item.replace("thd", "pin[2]"); - } - - item.replace("\r\n", ""); - item.replace("\r", ""); - item.replace("\n", ""); - addFile(DEVICE_CONFIG_FILE, "\n" + item); -} - -void addPreset(String name) { - String preset = readFile("presets/" + name + ".txt", 4048); - addFile(DEVICE_CONFIG_FILE, "\n" + preset); - - name.replace(".c",".s"); - - String scenario = readFile("presets/" + name + ".txt", 4048); - removeFile(DEVICE_SCENARIO_FILE); - addFile(DEVICE_SCENARIO_FILE, scenario); -} - -void delAllItems() { - removeFile(DEVICE_CONFIG_FILE); - addFile(DEVICE_CONFIG_FILE, String(firstLine)); - removeFile("id.txt"); - removeFile("order.txt"); - removeFile("pins.txt"); -} - -uint8_t getNewElementNumber(String file) { - uint8_t number = readFile(file, 100).toInt(); - number++; - removeFile(file); - addFile(file, String(number)); - return number; -} - -uint8_t getFreePinAll() { -#ifdef ESP8266 - uint8_t pins[] = {0, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5}; -#endif -#ifdef ESP32 - uint8_t pins[] = {0, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5}; -#endif - uint8_t array_sz = sizeof(pins) / sizeof(pins[0]); - uint8_t i = getNewElementNumber("pins.txt"); - if (i < array_sz) { - return pins[i]; - } else { - return 0; - } -} - -uint8_t getFreePinAnalog() { -#ifdef ESP8266 - return 0; -#endif -} - -void delChoosingItems() { - File configFile = LittleFS.open("/" + String(DEVICE_CONFIG_FILE), "r"); - if (!configFile) { - return; - } - configFile.seek(0, SeekSet); - String finalConf; - bool firstLine = true; - while (configFile.position() != configFile.size()) { - String item = configFile.readStringUntil('\n'); - if (firstLine) { - finalConf += item; - } else { - int checkbox = selectToMarker(item, ";").toInt(); - if (checkbox == 0) { - finalConf += "\n" + item; - } - } - firstLine = false; - } - removeFile(String(DEVICE_CONFIG_FILE)); - addFile(String(DEVICE_CONFIG_FILE), finalConf); - Serial.println(finalConf); - configFile.close(); -} \ No newline at end of file diff --git a/src/Module/Telnet.cpp b/src/Module/Telnet.cpp deleted file mode 100644 index d8bec643..00000000 --- a/src/Module/Telnet.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "Module/Telnet.h" - -bool Telnet::onInit() { - _server = new WiFiServer(_port); - _term = new Terminal(); - _term->enableControlCodes(); - _term->enableEcho(false); - _term->setStream(&_client); - return true; -} - -void Telnet::onEnd() { - delete _server; -} - -bool Telnet::onStart() { - _server->begin(); - _server->setNoDelay(true); - return true; -} - -void Telnet::onStop() { - if (hasClient()) { - _client.stop(); - } - _server->stop(); -} - -bool Telnet::hasClient() { return _client.connected(); } - -void Telnet::sendData(const String& data) { - if (hasClient()) { - _client.write(data.c_str()); - } -} - -void Telnet::setCommandShell(CommandShell* shell) { - _shell = shell; - _shell->setTerm(_term); -} - -void Telnet::setEventHandler(TelnetEventHandler h) { _eventHandler = h; } - -void Telnet::onLoop() { - if (_server->hasClient()) { - if (!_client) { - _client = _server->available(); - } else { - if (!_client.connected()) { - _server->stop(); - _client = _server->available(); - } else { - WiFiClient rejected; - rejected = _server->available(); - rejected.stop(); - } - } - } - - if (_lastConnected != hasClient()) { - _lastConnected = hasClient(); - if (_lastConnected) { - onConnect(); - } else { - onDisconnect(); - } - } - - if (hasClient() && _shell != nullptr) _shell->loop(); -} - -bool Telnet::isShellActive() { - return _shell->active(); -} - -void Telnet::onConnect() { - if (_eventHandler) { - _eventHandler(TE_CONNECTED, &_client); - } -} - -void Telnet::onDisconnect() { - if (_eventHandler) { - _eventHandler(TE_DISCONNECTED, nullptr); - } -} diff --git a/src/Module/Terminal.cpp b/src/Module/Terminal.cpp deleted file mode 100644 index 38c03b97..00000000 --- a/src/Module/Terminal.cpp +++ /dev/null @@ -1,320 +0,0 @@ -#include "Module/Terminal.h" - -#include "Utils/TimeUtils.h" - -#define INPUT_MAX_LENGHT 255 - -Terminal::Terminal(Stream *stream) : _stream{stream}, - _line(INPUT_MAX_LENGHT), - _cc_pos(0), - _color(false), - _controlCodes(false), - _echo(false), - _eol(CRLF) { state = ST_NORMAL; }; - -void Terminal::setStream(Stream *stream) { - _stream = stream; -} - -void Terminal::setOnReadLine(TerminalInputEventHandler h) { inputHandler_ = h; } - -void Terminal::setOnEvent(TerminalEventHandler h) { eventHandler_ = h; } - -bool Terminal::available() { - return _stream != nullptr ? _stream->available() : false; -} - -void Terminal::setEOL(EOLType_t eol) { - _eol = eol; -} - -void Terminal::enableEcho(bool enabled) { - _echo = enabled; -} - -void Terminal::enableColors(bool enabled) { - _color = enabled; -} - -void Terminal::enableControlCodes(bool enabled) { - _controlCodes = enabled; -} - -void Terminal::quit() {} - -void Terminal::loop() { - if (_stream == nullptr || !_stream->available()) return; - - byte moveX = 0; - byte moveY = 0; - - char c = _stream->read(); - - _lastReceived = millis(); - - if (state == ST_INACTIVE) { - // wait for CR - if (c == CHAR_CR) { - if (eventHandler_) { - eventHandler_(EVENT_OPEN, _stream); - state = ST_NORMAL; - } - } - // or ignore all other - return; - } - - if (c == CHAR_LF || c == CHAR_NULL || c == CHAR_BIN) - return; - - // Esc - if (c == CHAR_ESC || c == 195) { - state = ST_ESC_SEQ; - _cc_pos = 0; - for (size_t i = 0; i < 2; ++i) { - bool timeout = false; - while (!_stream->available() && - !(timeout = millis_since(_lastReceived) > 10)) { - delay(0); - } - if (timeout) { - state = ST_NORMAL; - break; - } - _lastReceived = millis(); - c = _stream->read(); - _cc_buf[_cc_pos] = c; - if ((c == '[') || ((c >= 'A' && c <= 'Z') || c == '~')) { - _cc_pos++; - _cc_buf[++_cc_pos] = '\x00'; - } - } - uint8_t i; - for (i = 0; i < 10; ++i) { - if (strcmp(_cc_buf, keyMap[i].cc) == 0) { - c = keyMap[i].ch; - state = ST_NORMAL; - } - } - } - - if (state == ST_ESC_SEQ) { - state = ST_NORMAL; - return; - } - - // WHEN NORMAL - if (state == ST_NORMAL) { - if (c == CHAR_ESC) { - if (!_line.available()) { - // QUIT - state = ST_INACTIVE; - if (eventHandler_) - eventHandler_(EVENT_CLOSE, _stream); - } else { - // CLEAR - _line.clear(); - if (_controlCodes) { - clear_line(); - } else { - println(); - } - } - return; - } - - switch (c) { - case CHAR_CR: - println(); - if (inputHandler_) - inputHandler_(_line.c_str()); - _line.clear(); - moveY++; - break; - case CHAR_TAB: - if (eventHandler_) - eventHandler_(EVENT_TAB, _stream); - return; - case KEY_LEFT: - if (_line.prev()) - moveX--; - break; - case KEY_RIGHT: - if (_line.next()) - moveX++; - break; - case KEY_HOME: - moveX = -1 * _line.home(); - break; - case KEY_END: - moveX = _line.end(); - break; - case CHAR_BS: - case KEY_DEL: - if (_line.backspace()) { - backsp(); - moveX--; - } - break; - default: - // printable ascii 7bit or printable 8bit ISO8859 - if ((c & '\x7F') >= 32 && (c & '\x7F') < 127) - if (_line.write(c)) { - if (_echo) write(c); - moveX++; - } - break; - } - - // if (controlCodesEnabled) - // move(startY + moveY, startX + moveX); - } -} - -bool Terminal::setLine(const uint8_t *ptr, size_t size) { - _line.clear(); - if (_line.write(ptr, size)) - print(_line.c_str()); - return true; -} - -CharBuffer &Terminal::getLine() { return _line; } - -void Terminal::start() { - if (_controlCodes) initscr(); - println(); -} - -void Terminal::initscr() { - write_P(SEQ_LOAD_G1); - attrset(A_NORMAL); - move(0, 0); - clear(); -} - -void Terminal::attrset(const uint16_t attr) { - uint8_t i; - - if (attr != this->attr) { - this->write_P(SEQ_ATTRSET); - - i = (attr & F_COLOR) >> 8; - - if (i >= 1 && i <= 8) { - this->write_P(SEQ_ATTRSET_FCOLOR); - this->write(i - 1 + '0'); - } - - i = (attr & B_COLOR) >> 12; - - if (i >= 1 && i <= 8) { - this->write_P(SEQ_ATTRSET_BCOLOR); - this->write(i - 1 + '0'); - } - - if (attr & A_REVERSE) - this->write_P(SEQ_ATTRSET_REVERSE); - if (attr & A_UNDERLINE) - this->write_P(SEQ_ATTRSET_UNDERLINE); - if (attr & A_BLINK) - this->write_P(SEQ_ATTRSET_BLINK); - if (attr & A_BOLD) - this->write_P(SEQ_ATTRSET_BOLD); - if (attr & A_DIM) - this->write_P(SEQ_ATTRSET_DIM); - this->write('m'); - this->attr = attr; - } -} - -void Terminal::clear() { write_P(SEQ_CLEAR); } - -void Terminal::clear_line() { - write(CHAR_CR); - write_P(ESC_CLEAR_EOL); -} - -void Terminal::move(uint8_t y, uint8_t x) { - write_P(SEQ_CSI); - writeByDigit(y + 1); - write(';'); - writeByDigit(x + 1); - write('H'); - curY = y; - curX = x; -} - -void Terminal::writeByDigit(uint8_t i) { - uint8_t ii; - if (i >= 10) { - if (i >= 100) { - ii = i / 100; - write(ii + '0'); - i -= 100 * ii; - } - ii = i / 10; - write(ii + '0'); - i -= 10 * ii; - } - write(i + '0'); -} - -void Terminal::backsp() { - write(CHAR_BS); - write(CHAR_SPACE); - write(CHAR_BS); -} - -size_t Terminal::println(const char *str) { - size_t n = print(str); - return n += println(); -} - -size_t Terminal::println(void) { - size_t n = 0; - switch (_eol) { - case CRLF: - n += write(CHAR_CR); - n += write(CHAR_LF); - break; - case LF: - n += write(CHAR_LF); - break; - case LFCR: - n += write(CHAR_LF); - n += write(CHAR_CR); - break; - case CR: - n += write(CHAR_CR); - break; - } - return n; -} - -size_t Terminal::write(uint8_t ch) { - size_t n = 0; - if (_stream) - n = _stream->write(ch); - return n; -} - -size_t Terminal::write_P(PGM_P str) { - uint8_t ch; - size_t n = 0; - while ((ch = pgm_read_byte(str + n)) != '\x0') { - _stream->write(ch); - n++; - } - return n; -} - -size_t Terminal::write(const uint8_t *buf, size_t size) { - size_t n = 0; - while (size--) { - if (_stream->write(*buf++)) - n++; - else - break; - } - return n; -} \ No newline at end of file diff --git a/src/MqttClient.cpp b/src/MqttClient.cpp deleted file mode 100644 index 2210cbb3..00000000 --- a/src/MqttClient.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "MqttClient.h" - -#include -#include "items/LoggingClass.h" -#include "Class/NotAsync.h" -#include "Global.h" -#include "Init.h" - -String mqttPrefix; -String mqttRootDevice; - -void mqttInit() { - myNotAsyncActions->add( - do_MQTTPARAMSCHANGED, [&](void*) { - mqttReconnect(); - }, - nullptr); - - mqtt.setCallback(mqttCallback); - - ts.add( - WIFI_MQTT_CONNECTION_CHECK, MQTT_RECONNECT_INTERVAL, - [&](void*) { - if (WiFi.status() == WL_CONNECTED) { - SerialPrint("I", "WIFI", "OK"); - if (mqtt.connected()) { - SerialPrint("I", "MQTT", "OK"); - setLedStatus(LED_OFF); - } - else { - SerialPrint("E", "MQTT", "lost connection"); - mqttConnect(); - } - } - else { - SerialPrint("E", "WIFI", "Lost WiFi connection"); - ts.remove(WIFI_MQTT_CONNECTION_CHECK); - startAPMode(); - } - }, - nullptr, true); -} - -void mqttDisconnect() { - SerialPrint("I", "MQTT", "disconnect"); - mqtt.disconnect(); -} - -void mqttReconnect() { - mqttDisconnect(); - mqttConnect(); -} - -void mqttLoop() { - if (!isNetworkActive() || !mqtt.connected()) { - return; - } - mqtt.loop(); -} - -void mqttSubscribe() { - SerialPrint("I", "MQTT", "subscribe"); - mqtt.subscribe(mqttPrefix.c_str()); - mqtt.subscribe((mqttRootDevice + "/+/control").c_str()); - mqtt.subscribe((mqttRootDevice + "/order").c_str()); - mqtt.subscribe((mqttRootDevice + "/update").c_str()); - mqtt.subscribe((mqttRootDevice + "/devc").c_str()); - mqtt.subscribe((mqttRootDevice + "/devs").c_str()); -} - -boolean mqttConnect() { - SerialPrint("I", "MQTT", "start connection"); - String addr = jsonReadStr(configSetupJson, "mqttServer"); - if (!addr) { - SerialPrint("E", "MQTT", "no broker address"); - return false; - } - int port = jsonReadInt(configSetupJson, "mqttPort"); - String user = jsonReadStr(configSetupJson, "mqttUser"); - String pass = jsonReadStr(configSetupJson, "mqttPass"); - mqttPrefix = jsonReadStr(configSetupJson, "mqttPrefix"); - mqttRootDevice = mqttPrefix + "/" + chipId; - SerialPrint("I", "MQTT", "broker " + addr + ":" + String(port, DEC)); - SerialPrint("I", "MQTT", "topic " + mqttRootDevice); - setLedStatus(LED_FAST); - mqtt.setServer(addr.c_str(), port); - bool res = false; - if (!mqtt.connected()) { - if (mqtt.connect(chipId.c_str(), user.c_str(), pass.c_str())) { - SerialPrint("I", "MQTT", "connected"); - setLedStatus(LED_OFF); - mqttSubscribe(); - res = true; - } - else { - SerialPrint("E", "MQTT", "could't connect, retry in " + String(MQTT_RECONNECT_INTERVAL / 1000) + "s"); - setLedStatus(LED_FAST); - } - } - return res; -} - -void mqttCallback(char* topic, uint8_t* payload, size_t length) { - String topicStr = String(topic); - SerialPrint("I", "MQTT", topicStr); - String payloadStr; - payloadStr.reserve(length + 1); - for (size_t i = 0; i < length; i++) { - payloadStr += (char)payload[i]; - } - - SerialPrint("I", "MQTT", payloadStr); - - if (payloadStr.startsWith("HELLO")) { - SerialPrint("I", "MQTT", "Full update"); - publishWidgets(); - publishState(); -#ifdef LOGGING_ENABLED - choose_log_date_and_send(); -#endif - - } - else if (topicStr.indexOf("control")) { - - String key = selectFromMarkerToMarker(topicStr, "/", 3); - - orderBuf += key; - orderBuf += " "; - orderBuf += payloadStr; - orderBuf += ","; - - } - else if (topicStr.indexOf("order")) { - payloadStr.replace("_", " "); - orderBuf += payloadStr; - orderBuf += ","; - - } - else if (topicStr.indexOf("update")) { - if (payloadStr == "1") { - myNotAsyncActions->make(do_UPGRADE); - } - } -} - -boolean publish(const String& topic, const String& data) { - if (mqtt.beginPublish(topic.c_str(), data.length(), false)) { - mqtt.print(data); - return mqtt.endPublish(); - } - return false; -} - -boolean publishData(const String& topic, const String& data) { - String path = mqttRootDevice + "/" + topic; - if (!publish(path, data)) { - SerialPrint("[E]", "MQTT", "on publish data"); - return false; - } - return true; -} - -boolean publishChart(const String& topic, const String& data) { - String path = mqttRootDevice + "/" + topic + "/status"; - if (!publish(path, data)) { - SerialPrint("[E]", "MQTT", "on publish chart"); - return false; - } - return true; -} - -boolean publishControl(String id, String topic, String state) { - String path = mqttPrefix + "/" + id + "/" + topic + "/control"; - return mqtt.publish(path.c_str(), state.c_str(), false); -} - -boolean publishChart_test(const String& topic, const String& data) { - String path = mqttRootDevice + "/" + topic + "/status"; - return mqtt.publish(path.c_str(), data.c_str(), false); -} - -boolean publishStatus(const String& topic, const String& data) { - String path = mqttRootDevice + "/" + topic + "/status"; - String json = "{}"; - jsonWriteStr(json, "status", data); - return mqtt.publish(path.c_str(), json.c_str(), false); -} - -#ifdef LAYOUT_IN_RAM -void publishWidgets() { - if (all_widgets != "") { - int counter = 0; - String line; - int psn_1 = 0; - int psn_2; - do { - psn_2 = all_widgets.indexOf("\r\n", psn_1); //\r\n - line = all_widgets.substring(psn_1, psn_2); - line.replace("\n", ""); - line.replace("\r\n", ""); - //jsonWriteStr(line, "id", String(counter)); - //jsonWriteStr(line, "pageId", String(counter)); - counter++; - sendMQTT("config", line); - Serial.println("[V] " + line); - psn_1 = psn_2 + 1; - } while (psn_2 + 2 < all_widgets.length()); - getMemoryLoad("I after send all widgets"); - } -} -#endif - -#ifndef LAYOUT_IN_RAM -void publishWidgets() { - auto file = seekFile("layout.txt"); - if (!file) { - SerialPrint("[E]", "MQTT", "no file layout.txt"); - return; - } - while (file.available()) { - String payload = file.readStringUntil('\n'); - SerialPrint("I", "MQTT", "widgets: " + payload); - publishData("config", payload); - } - file.close(); -} -#endif - -void publishState() { - // берет строку json и ключи превращает в топики а значения колючей в них посылает - String str = configLiveJson; - str.replace("{", ""); - str.replace("}", ""); - str += ","; - - while (str.length()) { - String tmp = selectToMarker(str, ","); - - String topic = selectToMarker(tmp, "\":"); - topic.replace("\"", ""); - - String state = selectToMarkerLast(tmp, "\":"); - state.replace("\"", ""); - - if (topic != "timenow") { - publishStatus(topic, state); - } - str = deleteBeforeDelimiter(str, ","); - } -} - -const String getStateStr() { - switch (mqtt.state()) { - case -4: - return F("no respond"); - break; - case -3: - return F("connection was broken"); - break; - case -2: - return F("connection failed"); - break; - case -1: - return F("client disconnected"); - break; - case 0: - return F("client connected"); - break; - case 1: - return F("doesn't support the requested version"); - break; - case 2: - return F("rejected the client identifier"); - break; - case 3: - return F("unable to accept the connection"); - break; - case 4: - return F("wrong username/password"); - break; - case 5: - return F("not authorized to connect"); - break; - default: - return F("unspecified"); - break; - } -} diff --git a/src/MqttDiscovery.cpp b/src/MqttDiscovery.cpp deleted file mode 100644 index 7ccd0bc1..00000000 --- a/src/MqttDiscovery.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "MqttDiscovery.h" - -namespace Discovery { - -static const char json_is_defined[] = "is_defined"; -static const char jsonId[] = "id"; -static const char jsonBatt[] = "batt"; -static const char jsonLux[] = "lux"; -static const char jsonPres[] = "pres"; -static const char jsonFer[] = "fer"; -static const char jsonMoi[] = "moi"; -static const char jsonHum[] = "hum"; -static const char jsonTemp[] = "tem"; -static const char jsonStep[] = "steps"; -static const char jsonWeight[] = "weight"; -static const char jsonPresence[] = "presence"; -static const char jsonAltim[] = "altim"; -static const char jsonAltif[] = "altift"; -static const char jsonTempf[] = "tempf"; -static const char jsonMsg[] = "message"; -static const char jsonVal[] = "value"; -static const char jsonVolt[] = "volt"; -static const char jsonCurrent[] = "current"; -static const char jsonPower[] = "power"; -static const char jsonGpio[] = "gpio"; -static const char jsonFtcd[] = "ftcd"; -static const char jsonWm2[] = "wattsm2"; -static const char jsonAdc[] = "adc"; -static const char jsonPa[] = "pa"; - -const String getValueJson(const char* str) { - char buf[32]; - sprintf(buf, "{{ value_json.%s }}", str); - return buf; -} - -void createDiscovery( - const char* type, const char* name, const char* clazz, - const char* value_template, const char* payload_on, const char* payload_off, - const char* maasure_unit, int off_delay, const char* has_payload, const char* no_payload, - const char* avail_topi, const char* cmd_topic, const char* state_topic, bool child) { - //const char* unique_id = getUniqueId(name).c_str(); -} - -void createADC(const char* name) { - createDiscovery( - "Type", "Name", "Clazz", - "Value", "Payload", "NoPayload", - "Measure", 0, "HasPayload", "NoPayload", - "", "", "", false); -} - -void createSwitch(const char* name) { - createDiscovery( - "Type", "Name", "Clazz", - "Value", "Payload", "NoPayload", - "Measure", 0, "HasPayload", "NoPayload", - "", "", "", false); -} -// component, -// type, -// name, -// availability topic, -// device class, -// value template, payload on, payload off, unit of measurement -const char* BMEsensor[6][8] = { - {"sensor", "tempc", "bme", "temperature", "", "", "°C"}, //jsonTemp - {"sensor", "tempf", "bme", "temperature", "", "", "°F"}, //jsonTempf - {"sensor", "pa", "bme", "", "", "", "hPa"}, //jsonPa - {"sensor", "hum", "bme", "humidity", "", "", "%"}, // jsonHum - {"sensor", "altim", "bme", "", "", "", "m"}, //jsonAltim - {"sensor", "altift", "bme", "", "", "", "ft"} // jsonAltif -}; - -} // namespace Discovery diff --git a/src/PushingBox.cpp b/src/PushingBox.cpp deleted file mode 100644 index 5c2f91e4..00000000 --- a/src/PushingBox.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "Global.h" - -void Push_init() { - server.on("/pushingboxDate", HTTP_GET, [](AsyncWebServerRequest* request) { - if (request->hasArg("pushingbox_id")) { - jsonWriteStr(configSetupJson, "pushingbox_id", request->getParam("pushingbox_id")->value()); - } - - saveConfig(); - - request->send(200, "text/text", "ok"); // отправляем ответ о выполнении - }); -} - -void pushControl() { - String title = sCmd.next(); - title.replace("#", " "); - String body = sCmd.next(); - body.replace("#", " "); - - static String body_old; - - const char* logServer = "api.pushingbox.com"; - String deviceId = jsonReadStr(configSetupJson, "pushingbox_id"); - - //Serial.println("- starting client"); - - WiFiClient client_push; - - //Serial.println("- connecting to pushing server: " + String(logServer)); - if (!client_push.connect(logServer, 80)) { - //Serial.println("- not connected"); - } else { - //Serial.println("- succesfully connected"); - - String postStr = "devid="; - postStr += String(deviceId); - - postStr += "&title="; - postStr += String(title); - - postStr += "&body="; - postStr += String(body); - - postStr += "\r\n\r\n"; - - //Serial.println("- sending data..."); - - client_push.print(F("POST /pushingbox HTTP/1.1\n")); - client_push.print(F("Host: api.pushingbox.com\n")); - client_push.print(F("Connection: close\n")); - client_push.print(F("Content-Type: application/x-www-form-urlencoded\n")); - client_push.print(F("Content-Length: ")); - client_push.print(postStr.length()); - client_push.print("\n\n"); - client_push.print(postStr); - } - client_push.stop(); - //Serial.println("- stopping the client"); -} diff --git a/src/RemoteOrdersUdp.cpp b/src/RemoteOrdersUdp.cpp deleted file mode 100644 index 6187d0bd..00000000 --- a/src/RemoteOrdersUdp.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "RemoteOrdersUdp.h" -#include -#include "Global.h" - -#ifdef UDP_ENABLED -AsyncUDP asyncUdp; - -void asyncUdpInit() { - //if (asyncUdp.listen(1234)) { - if (asyncUdp.listenMulticast(IPAddress(239, 255, 255, 255), 1234)) { - asyncUdp.onPacket([](AsyncUDPPacket packet) { - //Serial.print("UDP Packet Type: "); - //Serial.print(packet.isBroadcast() ? "Broadcast" : packet.isMulticast() ? "Multicast" : "Unicast"); - // - //Serial.print(", From: "); - //Serial.print(packet.remoteIP()); - //Serial.print(":"); - //Serial.print(packet.remotePort()); - // - //Serial.print(", To: "); - //Serial.print(packet.localIP()); - //Serial.print(":"); - //Serial.print(packet.localPort()); - // - //Serial.print(", Length: "); - //Serial.print(packet.length()); - // - //Serial.print(", Data: "); - //Serial.write(packet.data(), packet.length()); - - String data = uint8tToString(packet.data(), packet.length()); - Serial.print("[i] [udp] Packet received: '"); - Serial.print(data); - if (udpPacketValidation(data)) { - udpPacketParse(data); - //Serial.println("', Packet valid"); - } else { - //Serial.println("', Packet invalid"); - } - - //reply to the client - - packet.printf("Got %u bytes of data", packet.length()); - }); - } -} - -String uint8tToString(uint8_t* data, size_t len) { - String ret; - while (len--) { - ret += (char)*data++; - } - return ret; -} - -bool udpPacketValidation(String& data) { - if (data.indexOf("iotm;") != -1 && data.indexOf(getChipId()) != -1) { - return true; - } else { - return false; - } -} - -//iotm;chipid;button-out-1_1 -void udpPacketParse(String& data) { - data = selectFromMarkerToMarker(data, ";", 2); - data.replace("_", " "); - orderBuf += data + ","; -} -#endif \ No newline at end of file diff --git a/src/SSDP.cpp b/src/SSDP.cpp deleted file mode 100644 index c84d99ca..00000000 --- a/src/SSDP.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "SSDP.h" - -#include "Global.h" - -#ifdef SSDP_ENABLED -#ifdef ESP8266 -#include -#endif -#ifdef ESP32 -#include -#endif - -String xmlNode(String tags, String data); - -String decToHex(uint32_t decValue, byte desiredStringLength); - -void SsdpInit() { - server.on("/description.xml", HTTP_GET, [](AsyncWebServerRequest* request) { - String ssdpSend = F(""); - String ssdpHeder = xmlNode(F("major"), "1"); - ssdpHeder += xmlNode(F("minor"), "0"); - ssdpHeder = xmlNode(F("specVersion"), ssdpHeder); - ssdpHeder += xmlNode(F("URLBase"), "http://" + WiFi.localIP().toString()); - String ssdpDescription = xmlNode(F("deviceType"), F("upnp:rootdevice")); - ssdpDescription += xmlNode(F("friendlyName"), jsonReadStr(configSetupJson, F("name"))); - ssdpDescription += xmlNode(F("presentationURL"), "/"); - ssdpDescription += xmlNode(F("serialNumber"), getChipId()); -#ifdef ESP8266 - ssdpDescription += xmlNode(F("modelName"), F("ESP8266")); -#endif -#ifdef ESP32 - ssdpDescription += xmlNode(F("modelName"), F("ESP32")); -#endif - ssdpDescription += xmlNode(F("modelNumber"), getChipId()); - ssdpDescription += xmlNode(F("modelURL"), F("https://github.com/IoTManagerProject/IoTManager/wiki")); - ssdpDescription += xmlNode(F("manufacturer"), F("Borisenko Dmitry")); - ssdpDescription += xmlNode(F("manufacturerURL"), F("https://github.com/IoTManagerProject/IoTManager")); - ssdpDescription += xmlNode(F("UDN"), "uuid:38323636-4558-4dda-9188-cda0e6" + decToHex(ESP_getChipId(), 6)); - ssdpDescription = xmlNode("device", ssdpDescription); - ssdpHeder += ssdpDescription; - ssdpSend += ssdpHeder; - ssdpSend += ""; - Serial.println("->!!!SSDP Get request received"); - request->send(200, "text/xml", ssdpSend); - }); - //Если версия 2.0.0 закаментируйте следующую строчку - SSDP.setDeviceType(F("upnp:rootdevice")); - SSDP.setSchemaURL(F("description.xml")); - SSDP.begin(); -} - -String xmlNode(String tags, String data) { - String temp = "<" + tags + ">" + data + ""; - return temp; -} - -String decToHex(uint32_t decValue, byte desiredStringLength) { - String hexString = String(decValue, HEX); - while (hexString.length() < desiredStringLength) hexString = "0" + hexString; - return hexString; -} -#endif \ No newline at end of file diff --git a/src/Sensors.cpp b/src/Sensors.cpp deleted file mode 100644 index 4b657757..00000000 --- a/src/Sensors.cpp +++ /dev/null @@ -1,405 +0,0 @@ -//#include "Cmd.h" -//#include "Global.h" - -//GMedian<10, int> medianFilter; -// -//Adafruit_BMP280 bmp; -//Adafruit_Sensor *bmp_temp = bmp.getTemperatureSensor(); -//Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor(); -// -//Adafruit_BME280 bme; -//Adafruit_Sensor *bme_temp = bme.getTemperatureSensor(); -//Adafruit_Sensor *bme_pressure = bme.getPressureSensor(); -//Adafruit_Sensor *bme_humidity = bme.getHumiditySensor(); - -///const String perceptionStr(byte value); -///const String comfortStr(ComfortState value); - -//void bmp280T_reading(); - - - - - -////========================================================================================================================================= -////=========================================Модуль сенсоров DHT============================================================================= -//#ifdef DHT_ENABLED -////dhtT t 2 dht11 Температура#DHT,#t°C Датчики any-data 1 -//void dhtT() { -// String value_name = sCmd.next(); -// String pin = sCmd.next(); -// String sensor_type = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String type = sCmd.next(); -// String page_number = sCmd.next(); -// //dhtT_value_name = value_name; -// if (sensor_type == "dht11") { -// dht.setup(pin.toInt(), DHTesp::DHT11); -// } -// if (sensor_type == "dht22") { -// dht.setup(pin.toInt(), DHTesp::DHT22); -// } -// createWidgetByType(widget_name, page_name, page_number, type, value_name); -// //sensors_reading_map[4] = 1; -//} -// -//void dhtT_reading() { -// float value = 0; -// static int counter; -// if (dht.getStatus() != 0 && counter < 5) { -// // publishStatus(dhtT_value_name, String(dht.getStatusString())); -// counter++; -// } else { -// counter = 0; -// value = dht.getTemperature(); -// if (String(value) != "nan") { -// //eventGen2(dhtT_value_name, ""); -// //jsonWriteStr(configLiveJson, dhtT_value_name, String(value)); -// // publishStatus(dhtT_value_name, String(value)); -// //SerialPrint("I", "Sensor", "'" + dhtT_value_name + "' data: " + String(value)); -// } -// } -//} -// -////dhtH h 2 dht11 Влажность#DHT,#t°C Датчики any-data 1 -//void dhtH() { -// String value_name = sCmd.next(); -// String pin = sCmd.next(); -// String sensor_type = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String type = sCmd.next(); -// String page_number = sCmd.next(); -// //dhtH_value_name = value_name; -// if (sensor_type == "dht11") { -// dht.setup(pin.toInt(), DHTesp::DHT11); -// } -// if (sensor_type == "dht22") { -// dht.setup(pin.toInt(), DHTesp::DHT22); -// } -// createWidgetByType(widget_name, page_name, page_number, type, value_name); -// //sensors_reading_map[5] = 1; -//} -// -//void dhtH_reading() { -// float value = 0; -// static int counter; -// if (dht.getStatus() != 0 && counter < 5) { -// // publishStatus(dhtH_value_name, String(dht.getStatusString())); -// counter++; -// } else { -// counter = 0; -// value = dht.getHumidity(); -// if (String(value) != "nan") { -// //eventGen2(dhtH_value_name, ""); -// //jsonWriteStr(configLiveJson, dhtH_value_name, String(value)); -// // publishStatus(dhtH_value_name, String(value)); -// //SerialPrint("I", "Sensor", "'" + dhtH_value_name + "' data: " + String(value)); -// } -// } -//} -// -////dhtPerception Восприятие: Датчики 4 -//void dhtP() { -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String page_number = sCmd.next(); -// createWidgetByType(widget_name, page_name, page_number, "any-data", "dhtPerception"); -// //sensors_reading_map[6] = 1; -//} -// -//void dhtP_reading() { -// byte value; -// if (dht.getStatus() != 0) { -// publishStatus("dhtPerception", String(dht.getStatusString())); -// } else { -// //value = dht.computePerception(jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false); -// String final_line = perceptionStr(value); -// jsonWriteStr(configLiveJson, "dhtPerception", final_line); -// eventGen2("dhtPerception", ""); -// publishStatus("dhtPerception", final_line); -// if (mqtt.connected()) { -// SerialPrint("I", "Sensor", "'dhtPerception' data: " + final_line); -// } -// } -//} -// -////dhtComfort Степень#комфорта: Датчики 3 -//void dhtC() { -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String page_number = sCmd.next(); -// createWidgetByType(widget_name, page_name, page_number, "anydata", "dhtComfort"); -// //sensors_reading_map[7] = 1; -//} -// -//void dhtC_reading() { -// ComfortState cf; -// if (dht.getStatus() != 0) { -// publishStatus("dhtComfort", String(dht.getStatusString())); -// } else { -// //dht.getComfortRatio(cf, jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false); -// String final_line = comfortStr(cf); -// jsonWriteStr(configLiveJson, "dhtComfort", final_line); -// eventGen2("dhtComfort", ""); -// publishStatus("dhtComfort", final_line); -// SerialPrint("I", "Sensor", "'dhtComfort' send date " + final_line); -// } -//} -// -//const String perceptionStr(byte value) { -// String res; -// switch (value) { -// case 0: -// res = F("Сухой воздух"); -// break; -// case 1: -// res = F("Комфортно"); -// break; -// case 2: -// res = F("Уютно"); -// break; -// case 3: -// res = F("Хорошо"); -// break; -// case 4: -// res = F("Неудобно"); -// break; -// case 5: -// res = F("Довольно неудобно"); -// break; -// case 6: -// res = F("Очень неудобно"); -// break; -// case 7: -// res = F("Невыносимо"); -// default: -// res = F("Unknown"); -// break; -// } -// return res; -//} -// -//const String comfortStr(ComfortState value) { -// String res; -// switch (value) { -// case Comfort_OK: -// res = F("Отлично"); -// break; -// case Comfort_TooHot: -// res = F("Очень жарко"); -// break; -// case Comfort_TooCold: -// res = F("Очень холодно"); -// break; -// case Comfort_TooDry: -// res = F("Очень сухо"); -// break; -// case Comfort_TooHumid: -// res = F("Очень влажно"); -// break; -// case Comfort_HotAndHumid: -// res = F("Жарко и влажно"); -// break; -// case Comfort_HotAndDry: -// res = F("Жарко и сухо"); -// break; -// case Comfort_ColdAndHumid: -// res = F("Холодно и влажно"); -// break; -// case Comfort_ColdAndDry: -// res = F("Холодно и сухо"); -// break; -// default: -// res = F("Неизвестно"); -// break; -// }; -// return res; -//} -// -////dhtDewpoint Точка#росы: Датчики 5 -//void dhtD() { -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String page_number = sCmd.next(); -// createWidgetByType(widget_name, page_name, page_number, "anydata", "dhtDewpoint"); -// //sensors_reading_map[8] = 1; -//} -// -//void dhtD_reading() { -// float value; -// if (dht.getStatus() != 0) { -// publishStatus("dhtDewpoint", String(dht.getStatusString())); -// } else { -// //value = dht.computeDewPoint(jsonReadStr(configLiveJson, dhtT_value_name).toFloat(), jsonReadStr(configLiveJson, dhtH_value_name).toFloat(), false); -// jsonWriteInt(configLiveJson, "dhtDewpoint", value); -// eventGen2("dhtDewpoint", ""); -// publishStatus("dhtDewpoint", String(value)); -// SerialPrint("I", "Sensor", "'dhtDewpoint' data: " + String(value)); -// } -//} -//#endif -//=========================================i2c bus esp8266 scl-4 sda-5 ==================================================================== -//========================================================================================================================================= -//=========================================Модуль сенсоров bmp280========================================================================== - -////bmp280T temp1 0x76 Температура#bmp280 Датчики any-data 1 -//void bmp280T() { -// String value_name = sCmd.next(); -// String address = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String type = sCmd.next(); -// String page_number = sCmd.next(); -// //bmp280T_value_name = value_name; -// createWidgetByType(widget_name, page_name, page_number, type, value_name); -// bmp.begin(hexStringToUint8(address)); -// bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ -// Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ -// Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ -// Adafruit_BMP280::FILTER_X16, /* Filtering. */ -// Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ -// //bmp_temp->printSensorDetails(); -// //sensors_reading_map[9] = 1; -//} -// -//void bmp280T_reading() { -// float value = 0; -// sensors_event_t temp_event; -// bmp_temp->getEvent(&temp_event); -// value = temp_event.temperature; -// //jsonWriteStr(configLiveJson, bmp280T_value_name, String(value)); -// //eventGen2(bmp280T_value_name, ""); -// // publishStatus(bmp280T_value_name, String(value)); -// //SerialPrint("I", "Sensor", "'" + bmp280T_value_name + "' data: " + String(value)); -//} -// -////bmp280P press1 0x76 Давление#bmp280 Датчики any-data 2 -//void bmp280P() { -// String value_name = sCmd.next(); -// String address = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String type = sCmd.next(); -// String page_number = sCmd.next(); -// //bmp280P_value_name = value_name; -// createWidgetByType(widget_name, page_name, page_number, type, value_name); -// bmp.begin(hexStringToUint8(address)); -// bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ -// Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ -// Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ -// Adafruit_BMP280::FILTER_X16, /* Filtering. */ -// Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ -// //bmp_temp->printSensorDetails(); -// //sensors_reading_map[10] = 1; -//} -// -//void bmp280P_reading() { -// float value = 0; -// sensors_event_t pressure_event; -// bmp_pressure->getEvent(&pressure_event); -// value = pressure_event.pressure; -// value = value / 1.333224; -// //jsonWriteStr(configLiveJson, bmp280P_value_name, String(value)); -// //eventGen2(bmp280P_value_name, ""); -// // publishStatus(bmp280P_value_name, String(value)); -// //SerialPrint("I", "Sensor", "'" + bmp280P_value_name + "' data: " + String(value)); -//} -// -////========================================================================================================================================= -////=============================================Модуль сенсоров bme280====================================================================== -////bme280T temp1 0x76 Температура#bmp280 Датчики any-data 1 -//void bme280T() { -// String value_name = sCmd.next(); -// String address = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String type = sCmd.next(); -// String page_number = sCmd.next(); -// //bme280T_value_name = value_name; -// //createWidgetByType(widget_name, page_name, page_number, type, value_name); -// //bme.begin(hexStringToUint8(address)); -// //sensors_reading_map[11] = 1; -//} -// -//void bme280T_reading() { -// float value = 0; -// value = bme.readTemperature(); -// //jsonWriteStr(configLiveJson, bme280T_value_name, String(value)); -// //eventGen2(bme280T_value_name, ""); -// // publishStatus(bme280T_value_name, String(value)); -// //SerialPrint("I", "Sensor", "'" + bme280T_value_name + "' data: " + String(value)); -//} -// -////bme280P pres1 0x76 Давление#bmp280 Датчики any-data 1 -//void bme280P() { -// String value_name = sCmd.next(); -// String address = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String type = sCmd.next(); -// String page_number = sCmd.next(); -// //bme280P_value_name = value_name; -// //createWidgetByType(widget_name, page_name, page_number, type, value_name); -// //bme.begin(hexStringToUint8(address)); -// //sensors_reading_map[12] = 1; -//} -// -//void bme280P_reading() { -// float value = 0; -// value = bme.readPressure(); -// value = value / 1.333224 / 100; -// //jsonWriteStr(configLiveJson, bme280P_value_name, String(value)); -// //eventGen2(bme280P_value_name, ""); -// // publishStatus(bme280P_value_name, String(value)); -// //SerialPrint("I", "Sensor", "'" + bme280P_value_name + "' data: " + String(value)); -//} -// -////bme280H hum1 0x76 Влажность#bmp280 Датчики any-data 1 -//void bme280H() { -// String value_name = sCmd.next(); -// String address = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String type = sCmd.next(); -// String page_number = sCmd.next(); -// //bme280H_value_name = value_name; -// createWidgetByType(widget_name, page_name, page_number, type, value_name); -// bme.begin(hexStringToUint8(address)); -// //sensors_reading_map[13] = 1; -//} -// -//void bme280H_reading() { -// float value = 0; -// value = bme.readHumidity(); -// //jsonWriteStr(configLiveJson, bme280H_value_name, String(value)); -// //eventGen2(bme280H_value_name, ""); -// // publishStatus(bme280H_value_name, String(value)); -// //SerialPrint("I", "Sensor", "'" + bme280H_value_name + "' data: " + String(value)); -//} -// -////bme280A altit1 0x76 Высота#bmp280 Датчики any-data 1 -//void bme280A() { -// String value_name = sCmd.next(); -// String address = sCmd.next(); -// String widget_name = sCmd.next(); -// String page_name = sCmd.next(); -// String type = sCmd.next(); -// String page_number = sCmd.next(); -// //bme280A_value_name = value_name; -// createWidgetByType(widget_name, page_name, page_number, type, value_name); -// bme.begin(hexStringToUint8(address)); -// //sensors_reading_map[14] = 1; -//} -// -//void bme280A_reading() { -// float value = bme.readAltitude(1013.25); -// //jsonWriteStr(configLiveJson, bme280A_value_name, String(value, 2)); -// -// //eventGen2(bme280A_value_name, ""); -// -// // publishStatus(bme280A_value_name, String(value)); -// -// //SerialPrint("I", "Sensor", "'" + bme280A_value_name + "' data: " + String(value)); -//} diff --git a/src/Servo/Servs.cpp b/src/Servo/Servs.cpp deleted file mode 100644 index 96ebba91..00000000 --- a/src/Servo/Servs.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Servo/Servos.h" - -Servos myServo; - -Servos::Servos(){}; - -Servo *Servos::create(uint8_t num, uint8_t pin) { - // Ищем среди ранее созданных - for (size_t i = 0; i < _items.size(); i++) { - auto item = _items.at(i); - if (item.num == num) { - if (item.pin != pin) { - item.obj->attach(pin); - item.pin = pin; - }; - return item.obj; - } - } - // Добавляем новый - Servo_t newItem{num, pin}; - newItem.obj = new Servo(); - newItem.obj->attach(pin); - _items.push_back(newItem); - return newItem.obj; -} - -Servo *Servos::get(uint8_t num) { - // Ищем среди ранее созданных - for (size_t i = 0; i < _items.size(); i++) { - auto item = _items.at(i); - if (item.num == num) { - return item.obj; - } - } - return nullptr; -} - -size_t Servos::count() { - return _items.size(); -} diff --git a/src/Telegram.cpp b/src/Telegram.cpp deleted file mode 100644 index 89425e5a..00000000 --- a/src/Telegram.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "Telegram.h" - - -CTBot* myBot{ nullptr }; - -void telegramInit() { - if (isTelegramEnabled()) { - telegramInitBeen = true; - sCmd.addCommand("telegram", sendTelegramMsg); - String token = jsonReadStr(configSetupJson, "telegramApi"); - if (!myBot) { - myBot = new CTBot(); - } - myBot->setTelegramToken(token); - myBot->enableUTF8Encoding(true); - if (myBot->testConnection()) { - SerialPrint("I", "Telegram", "Connected"); - } - else { - SerialPrint("E", "Telegram", "Not connected"); - } - } -} - -void handleTelegram() { - if (telegramInitBeen) { - if (isTelegramEnabled()) { - TBMessage msg; - static unsigned long prevMillis; - unsigned long currentMillis = millis(); - unsigned long difference = currentMillis - prevMillis; - if (difference >= 5000) { - prevMillis = millis(); - if (myBot->getNewMessage(msg)) { - SerialPrint("->", "Telegram", "chat ID: " + String(msg.sender.id) + ", msg: " + String(msg.text)); - jsonWriteInt(configSetupJson, "chatId", msg.sender.id); - saveConfig(); - telegramMsgParse(String(msg.text)); - } - } - } - } -} - -void telegramMsgParse(String msg) { - if (msg.indexOf("set") != -1) { - msg = deleteBeforeDelimiter(msg, "_"); - msg.replace("_", " "); - orderBuf += String(msg) + ","; - myBot->sendMessage(jsonReadInt(configSetupJson, "chatId"), "order done"); - SerialPrint("<-", "Telegram", "chat ID: " + String(jsonReadInt(configSetupJson, "chatId")) + ", msg: " + String(msg)); - } - else if (msg.indexOf("get") != -1) { - msg = deleteBeforeDelimiter(msg, "_"); - myBot->sendMessage(jsonReadInt(configSetupJson, "chatId"), jsonReadStr(configLiveJson, msg)); - SerialPrint("<-", "Telegram", "chat ID: " + String(jsonReadInt(configSetupJson, "chatId")) + ", msg: " + String(msg)); - } - else if (msg.indexOf("all") != -1) { - String list = returnListOfParams(); - myBot->sendMessage(jsonReadInt(configSetupJson, "chatId"), list); - SerialPrint("<-", "Telegram", "chat ID: " + String(jsonReadInt(configSetupJson, "chatId")) + "\n" + list); - } - else { - myBot->sendMessage(jsonReadInt(configSetupJson, "chatId"), "Wrong order, use /all to get all values, /get_id to get value, or /set_id_value to set value"); - } -} - -void sendTelegramMsg() { - String msg = sCmd.next(); - String type = sCmd.next(); - msg.replace("#", " "); - if (type == "1") { - static String prevMsg; - if (prevMsg != msg) { - prevMsg = msg; - myBot->sendMessage(jsonReadInt(configSetupJson, "chatId"), msg); - SerialPrint("<-", "Telegram", "chat ID: " + String(jsonReadInt(configSetupJson, "chatId")) + ", msg: " + msg); - } - } else if (type == "2") { - myBot->sendMessage(jsonReadInt(configSetupJson, "chatId"), msg); - SerialPrint("<-", "Telegram", "chat ID: " + String(jsonReadInt(configSetupJson, "chatId")) + ", msg: " + msg); - } -} - -bool isTelegramEnabled() { - return jsonReadBool(configSetupJson, "telegonof"); -} - - -String returnListOfParams() { - String cmdStr = readFile(DEVICE_CONFIG_FILE, 4096); - cmdStr += "\r\n"; - cmdStr.replace("\r\n", "\n"); - cmdStr.replace("\r", "\n"); - int count = 0; - String out; - while (cmdStr.length()) { - String buf = selectToMarker(cmdStr, "\n"); - count++; - if (count > 1) { - String id = selectFromMarkerToMarker(buf, ";", 2); - String value = jsonReadStr(configLiveJson, id); - String page = selectFromMarkerToMarker(buf, ";", 4); - page.replace("#", " "); - String name = selectFromMarkerToMarker(buf, ";", 5); - name.replace("#", " "); - out += page + " " + " " + name + " " + value + "\n"; - } - cmdStr = deleteBeforeDelimiter(cmdStr, "\n"); - } - return out; -} \ No newline at end of file diff --git a/src/Timers.cpp b/src/Timers.cpp deleted file mode 100644 index b45ab7b6..00000000 --- a/src/Timers.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "Global.h" - -//================================================================================================================ -//=========================================Таймеры================================================================= -void Timer_countdown_init() { - ts.add( - TIMER_COUNTDOWN, 1000, [&](void*) { - String old_line = jsonReadStr(configOptionJson, "timers"); - if (old_line != "") { - //Serial.println(old_line); - int i = 0; - do { - String timer = selectFromMarkerToMarker(old_line, ",", i); - //Serial.print("timer no " + String(i) + ": "); - //Serial.println(timer); - if (timer == "not found" || timer == "") return; - int number = selectToMarker(timer, ":").toInt(); - int time = readTimer(number); - if (time == 0) { - delTimer(String(number)); - jsonWriteStr(configLiveJson, "timer" + String(number), "0"); - eventGen2("timer", String(number)); - } else { - time--; - addTimer(String(number), String(time)); - } - i++; - } while (i <= 9); - } - }, - nullptr, true); -} - -void timerStart_() { - String number = sCmd.next(); - String period_of_time = sCmd.next(); - String type = sCmd.next(); - if (period_of_time.indexOf("digit") != -1) { - //period_of_time = add_set(period_of_time); - period_of_time = jsonReadStr(configLiveJson, period_of_time); - } - if (type == "sec") period_of_time = period_of_time; - if (type == "min") period_of_time = String(period_of_time.toInt() * 60); - if (type == "hours") period_of_time = String(period_of_time.toInt() * 60 * 60); - addTimer(number, period_of_time); - jsonWriteStr(configLiveJson, "timer" + number, "1"); -} -void addTimer(String number, String time) { - String tmp = jsonReadStr(configOptionJson, "timers"); //1:60,2:120, - String new_timer = number + ":" + time; - int psn1 = tmp.indexOf(number + ":"); //0 ищем позицию таймера который надо заменить - if (psn1 != -1) { //если он есть - int psn2 = tmp.indexOf(",", psn1); //4 от этой позиции находим позицию запятой - String timer = tmp.substring(psn1, psn2); //1:60 выделяем таймер который надо заменить - ///tmp.replace(timer, new_timer); //заменяем таймер на новый (во всей стороке) - tmp.replace(timer + ",", ""); - tmp += new_timer + ","; - } else { //если его нет - tmp += new_timer + ","; - } - jsonWriteStr(configOptionJson, "timers", tmp); - //Serial.println("ura"); -} - -void timerStop_() { - String number = sCmd.next(); - delTimer(number); -} - -void delTimer(String number) { - String tmp = jsonReadStr(configOptionJson, "timers"); //1:60,2:120, - int psn1 = tmp.indexOf(number + ":"); //0 ищем позицию таймера который надо удалить - if (psn1 != -1) { //если он есть - int psn2 = tmp.indexOf(",", psn1); //4 от этой позиции находим позицию запятой - String timer = tmp.substring(psn1, psn2) + ","; //1:60, выделяем таймер который надо удалить - tmp.replace(timer, ""); //удаляем таймер - jsonWriteStr(configOptionJson, "timers", tmp); - } -} - -int readTimer(int number) { - String tmp = jsonReadStr(configOptionJson, "timers"); //1:60,2:120, - int psn1 = tmp.indexOf(String(number) + ":"); //0 ищем позицию таймера который надо прочитать - String timer; - if (psn1 != -1) { //если он есть - int psn2 = tmp.indexOf(",", psn1); //4 от этой позиции находим позицию запятой - timer = tmp.substring(psn1, psn2); //1:60 выделяем таймер который надо прочитать - timer = deleteBeforeDelimiter(timer, ":"); - } - return timer.toInt(); -} \ No newline at end of file diff --git a/src/UpgradeFirm.cpp b/src/UpgradeFirm.cpp deleted file mode 100644 index f5670d23..00000000 --- a/src/UpgradeFirm.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "Upgrade.h" - -#include "Class/NotAsync.h" -#ifdef ESP8266 -#include "ESP8266.h" -#else -#include -#endif - -#include "Global.h" - -void upgradeInit() { - myNotAsyncActions->add( - do_UPGRADE, [&](void*) { - upgrade_firmware(3); - }, - nullptr); - - myNotAsyncActions->add( - do_GETLASTVERSION, [&](void*) { - getLastVersion(); - }, - nullptr); - - if (isNetworkActive()) { - getLastVersion(); - if (lastVersion > 0) { - SerialPrint("I", "Update", "available version: " + String(lastVersion)); - } - }; -} - -void getLastVersion() { - if ((WiFi.status() == WL_CONNECTED)) { - #ifdef ESP8266 - String tmp = getURL( serverIP + F("/projects/iotmanager/esp8266/esp8266ver/esp8266ver.txt")); - #else - String tmp = getURL( serverIP + F("/projects/iotmanager/esp32/esp32ver/esp32ver.txt")); - #endif - if (tmp == "error") { - lastVersion = -1; - } else { - lastVersion = tmp.toInt(); - } - } else { - lastVersion = -2; - } - jsonWriteInt(configSetupJson, "last_version", lastVersion); -} - -void upgrade_firmware(int type) { - String scenario_ForUpdate; - String devconfig_ForUpdate; - String configSetup_ForUpdate; - - scenario_ForUpdate = readFile(String(DEVICE_SCENARIO_FILE), 4000); - devconfig_ForUpdate = readFile(String(DEVICE_CONFIG_FILE), 4000); - configSetup_ForUpdate = configSetupJson; - - if (type == 1) { //only build - if (upgradeBuild()) restartEsp(); - } - - else if (type == 2) { //only spiffs - if (upgradeFS()) { - writeFile(String(DEVICE_SCENARIO_FILE), scenario_ForUpdate); - writeFile(String(DEVICE_CONFIG_FILE), devconfig_ForUpdate); - writeFile("config.json", configSetup_ForUpdate); - restartEsp(); - } - } - - else if (type == 3) { //spiffs and build - if (upgradeFS()) { - writeFile(String(DEVICE_SCENARIO_FILE), scenario_ForUpdate); - writeFile(String(DEVICE_CONFIG_FILE), devconfig_ForUpdate); - writeFile("config.json", configSetup_ForUpdate); - saveConfig(); - if (upgradeBuild()) { - restartEsp(); - } - } - } -} - -bool upgradeFS() { - WiFiClient wifiClient; - bool ret = false; - Serial.println("Start upgrade LittleFS, please wait..."); -#ifdef ESP8266 - ESPhttpUpdate.rebootOnUpdate(false); - t_httpUpdate_return retFS = ESPhttpUpdate.updateSpiffs(wifiClient, serverIP + F("/projects/iotmanager/esp8266/littlefs/littlefs.bin")); -#else - httpUpdate.rebootOnUpdate(false); - HTTPUpdateResult retFS = httpUpdate.updateSpiffs(wifiClient, serverIP + F("/projects/iotmanager/esp32/littlefs/spiffs.bin")); -#endif - if (retFS == HTTP_UPDATE_OK) { //если FS обновилась успешно - SerialPrint("I", "Update", "LittleFS upgrade done!"); - ret = true; - } - return ret; -} - -bool upgradeBuild() { - WiFiClient wifiClient; - bool ret = false; - Serial.println("Start upgrade BUILD, please wait..."); - -#ifdef ESP8266 - ESPhttpUpdate.rebootOnUpdate(false); - t_httpUpdate_return retBuild = ESPhttpUpdate.update(wifiClient, serverIP + F("/projects/iotmanager/esp8266/firmware/firmware.bin")); -#else - httpUpdate.rebootOnUpdate(false); - HTTPUpdateResult retBuild = httpUpdate.update(wifiClient, serverIP + F("/projects/iotmanager/esp32/firmware/firmware.bin")); -#endif - - if (retBuild == HTTP_UPDATE_OK) { //если BUILD обновился успешно - SerialPrint("I", "Update", "BUILD upgrade done!"); - ret = true; - } - return ret; -} - -void restartEsp() { - Serial.println("Restart ESP...."); - delay(1000); - ESP.restart(); -} \ No newline at end of file diff --git a/src/Utils/FileUtils.cpp b/src/Utils/FileUtils.cpp deleted file mode 100644 index f5163d39..00000000 --- a/src/Utils/FileUtils.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "Utils/FileUtils.h" -#include "Utils/SerialPrint.h" -#include "Utils/StringUtils.h" - - - -const String filepath(const String& filename) { - return filename.startsWith("/") ? filename : "/" + filename; -} - -bool fileSystemInit() { - if (!LittleFS.begin()) { - SerialPrint("[E]","Files","init"); - return false; - } - return true; -} - -void removeFile(const String& filename) { - String path = filepath(filename); - if (LittleFS.exists(path)) { - if (!LittleFS.remove(path)) { - SerialPrint("I","Files","remove " + path); - } - } else { - SerialPrint("E","Files","not exist" + path); - } -} - -File seekFile(const String& filename, size_t position) { - String path = filepath(filename); - auto file = LittleFS.open(path, "r"); - if (!file) { - SerialPrint("[E]","Files","open " + path); - } - // поставим курсор в начало файла - file.seek(position, SeekSet); - return file; -} - -const String readFileString(const String& filename, const String& to_find) { - String path = filepath(filename); - String res = "failed"; - auto file = LittleFS.open(path, "r"); - if (!file) { - return "failed"; - } - if (file.find(to_find.c_str())) { - res = file.readStringUntil('\n'); - } - file.close(); - return res; -} - -const String addFileLn(const String& filename, const String& str) { - String path = filepath(filename); - auto file = LittleFS.open(path, "a"); - if (!file) { - return "failed"; - } - file.println(str); - file.close(); - return "sucсess"; -} - -const String addFile(const String& filename, const String& str) { - String path = filepath(filename); - auto file = LittleFS.open(path, "a"); - if (!file) { - return "failed"; - } - file.print(str); - file.close(); - return "sucсess"; -} - -bool copyFile(const String& src, const String& dst, bool overwrite) { - String srcPath = filepath(src); - String dstPath = filepath(dst); - SerialPrint("I","Files","copy " + srcPath + " to " + dstPath); - if (!LittleFS.exists(srcPath)) { - SerialPrint("[E]","Files","not exist: " + srcPath); - return false; - } - if (LittleFS.exists(dstPath)) { - if (!overwrite) { - SerialPrint("[E]","Files","already exist: " + dstPath); - return false; - } - LittleFS.remove(dstPath); - } - auto srcFile = LittleFS.open(srcPath, "r"); - auto dstFile = LittleFS.open(dstPath, "w"); - - uint8_t buf[512]; - while (srcFile.available()) { - size_t len = srcFile.read(buf, 512); - dstFile.write(buf, len); - } - srcFile.close(); - dstFile.close(); - return true; -} - -const String writeFile(const String& filename, const String& str) { - String path = filepath(filename); - auto file = LittleFS.open(path, "w"); - if (!file) { - return "failed"; - } - file.print(str); - file.close(); - return "sucсess"; -} - -const String readFile(const String& filename, size_t max_size) { - String path = filepath(filename); - auto file = LittleFS.open(path, "r"); - if (!file) { - return "failed"; - } - size_t size = file.size(); - if (size > max_size) { - file.close(); - return "large"; - } - String temp = file.readString(); - file.close(); - return temp; -} - -const String getFileSize(const String filename) { - String filepath(filename); - auto file = LittleFS.open(filepath, "r"); - if (!file) { - return "failed"; - } - size_t size = file.size(); - file.close(); - return String(size); -} - -const String getFSSizeInfo() { - String res; -#ifdef ESP8266 - FSInfo info; - if (LittleFS.info(info)) { - res = prettyBytes(info.usedBytes) + " of " + prettyBytes(info.totalBytes); - } else { - res = "error"; - } -#else - res = prettyBytes(LittleFS.usedBytes()) + " of " + prettyBytes(LittleFS.totalBytes()); -#endif - return res; -} - -const String getConfigFile(uint8_t preset, ConfigType_t type) { - char buf[64]; - sprintf(buf, "/conf/%s%03d.txt", (type == CT_CONFIG) ? "c" : "s", preset); - return String(buf); -} \ No newline at end of file diff --git a/src/Utils/JsonUtils.cpp b/src/Utils/JsonUtils.cpp deleted file mode 100644 index 2389773c..00000000 --- a/src/Utils/JsonUtils.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "Utils/JsonUtils.h" -#include "Utils/FileUtils.h" -#include "Global.h" - -String jsonReadStr(String& json, String name) { - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(json); - return root[name].as(); -} - -boolean jsonReadBool(String& json, String name) { - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(json); - return root[name].as(); -} - -int jsonReadInt(String& json, String name) { - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(json); - return root[name]; -} - -String jsonWriteStr(String& json, String name, String value) { - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(json); - root[name] = value; - json = ""; - root.printTo(json); - return json; -} - -String jsonWriteBool(String& json, String name, boolean value) { - return jsonWriteStr(json, name, value ? "1" : "0"); -} - -String jsonWriteInt(String& json, String name, int value) { - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(json); - root[name] = value; - json = ""; - root.printTo(json); - return json; -} - -String jsonWriteFloat(String& json, String name, float value) { - DynamicJsonBuffer jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(json); - root[name] = value; - json = ""; - root.printTo(json); - return json; -} - -void saveConfig() { - writeFile(String("config.json"), configSetupJson); -} \ No newline at end of file diff --git a/src/Utils/SerialPrint.cpp b/src/Utils/SerialPrint.cpp deleted file mode 100644 index 7438a0b3..00000000 --- a/src/Utils/SerialPrint.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "Utils/SerialPrint.h" - -#include "Global.h" - -void SerialPrint(String errorLevel, String module, String msg) { - //if (module == "Stat") { - Serial.println(prettyMillis(millis()) + " [" + errorLevel + "] [" + module + "] " + msg); - //} -} \ No newline at end of file diff --git a/src/Utils/StringUtils.cpp b/src/Utils/StringUtils.cpp deleted file mode 100644 index a158fa94..00000000 --- a/src/Utils/StringUtils.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "Utils/StringUtils.h" -#include "Consts.h" - -String selectToMarkerLast(String str, String found) { - int p = str.lastIndexOf(found); - return str.substring(p + found.length()); -} - -String selectToMarker(String str, String found) { - int p = str.indexOf(found); - return str.substring(0, p); -} - -String extractInner(String str) { - int p1 = str.indexOf("["); - int p2 = str.indexOf("]"); - return str.substring(p1 + 1, p2); -} - -String deleteAfterDelimiter(String str, String found) { - int p = str.indexOf(found); - return str.substring(0, p); -} - -String deleteBeforeDelimiter(String str, String found) { - int p = str.indexOf(found) + found.length(); - return str.substring(p); -} - -String deleteBeforeDelimiterTo(String str, String found) { - int p = str.indexOf(found); - return str.substring(p); -} - -String deleteToMarkerLast(String str, String found) { - int p = str.lastIndexOf(found); - return str.substring(0, p); -} - -String selectToMarkerPlus(String str, String found, int plus) { - int p = str.indexOf(found); - return str.substring(0, p + plus); -} - -String selectFromMarkerToMarker(String str, String tofind, int number) { - if (str.indexOf(tofind) == -1) { - return "not found"; - } - str += tofind; // добавим для корректного поиска - uint8_t i = 0; // Индекс перебора - do { - if (i == number) { - // если индекс совпал с позицией - return selectToMarker(str, tofind); - } - // отбросим проверенный блок до разделителя - str = deleteBeforeDelimiter(str, tofind); - i++; - } while (str.length() != 0); - - return "not found"; -} - -uint8_t hexStringToUint8(String hex) { - uint8_t tmp = strtol(hex.c_str(), NULL, 0); - if (tmp >= 0x00 && tmp <= 0xFF) { - return tmp; - } -} - -uint16_t hexStringToUint16(String hex) { - uint16_t tmp = strtol(hex.c_str(), NULL, 0); - if (tmp >= 0x0000 && tmp <= 0xFFFF) { - return tmp; - } -} - -size_t itemsCount(String str, const String& separator) { - // если строки поиск нет сразу выход - if (str.indexOf(separator) == -1) { - return 0; - } - // добавим для корректного поиска - str += separator; - size_t cnt = 0; - while (str.length()) { - // отбросим проверенный блок до разделителя - str = deleteBeforeDelimiter(str, separator); - cnt++; - } - return cnt; -} - -boolean isDigitStr(const String& str) { - for (size_t i = 0; i < str.length(); i++) { - if (!isDigit(str.charAt(i))) { - return false; - } - } - return str.length(); -} - -String prettyBytes(size_t size) { - if (size < 1024) - return String(size) + "b"; - else if (size < (1024 * 1024)) - return String(size / 1024.0) + "kB"; - else if (size < (1024 * 1024 * 1024)) - return String(size / 1024.0 / 1024.0) + "MB"; - else - return String(size / 1024.0 / 1024.0 / 1024.0) + "GB"; -} - - - diff --git a/src/Utils/SysUtils.cpp b/src/Utils/SysUtils.cpp deleted file mode 100644 index a9f507a1..00000000 --- a/src/Utils/SysUtils.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "Utils/SysUtils.h" - -#include "Global.h" - - -const String getUniqueId(const char* name) { - return String(name) + getMacAddress(); -} - -uint32_t ESP_getChipId(void) { -#ifdef ESP32 - uint32_t id = 0; - for (uint32_t i = 0; i < 17; i = i + 8) { - id |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; - } - return id; -#else - return ESP.getChipId(); -#endif -} - -uint32_t ESP_getFlashChipId(void) { -#ifdef ESP32 - // Нет аналогичной (без доп.кода) функций в 32 - // надо использовать другой id - варианты есть - return ESP_getChipId(); -#else - return ESP.getFlashChipId(); -#endif -} - -const String getChipId() { - return String(ESP_getChipId()) + "-" + String(ESP_getFlashChipId()); -} - -void setChipId() { - chipId = getChipId(); - SerialPrint("I", "System", "id: " + chipId); -} - -#ifdef ESP8266 -static uint32_t total_memory = 52864; -#else -static uint32_t total_memory = ESP.getHeapSize(); -#endif - -const String printMemoryStatus() { - uint32_t free = ESP.getFreeHeap(); - uint32_t used = total_memory - free; - uint32_t memory_load = (used * 100) / total_memory; - char buf[64]; - sprintf(buf, "used: %d%% free: %s", memory_load, getHeapStats().c_str()); - return String(buf); -} - -#ifdef ESP8266 -const String getHeapStats() { - uint32_t free; - uint16_t max; - uint8_t frag; - ESP.getHeapStats(&free, &max, &frag); - String buf; - buf += prettyBytes(free); - buf += " frag: "; - buf += frag; - buf += '%'; - return buf; -} -#else -const String getHeapStats() { - String buf; - buf = prettyBytes(ESP.getFreeHeap()); - return buf; -} -#endif - -const String getMacAddress() { - uint8_t mac[6]; - char buf[13] = {0}; -#if defined(ESP8266) - WiFi.macAddress(mac); - sprintf(buf, MACSTR, MAC2STR(mac)); -#else - esp_read_mac(mac, ESP_MAC_WIFI_STA); - sprintf(buf, MACSTR, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -#endif - return String(buf); -} - -#ifdef ESP8266 -void setLedStatus(LedStatus_t status) { - if (jsonReadBool(configSetupJson, "blink") == 1) { - pinMode(LED_PIN, OUTPUT); - switch (status) { - case LED_OFF: - noTone(LED_PIN); - digitalWrite(LED_PIN, HIGH); - break; - case LED_ON: - noTone(LED_PIN); - digitalWrite(LED_PIN, LOW); - break; - case LED_SLOW: - tone(LED_PIN, 1); - break; - case LED_FAST: - tone(LED_PIN, 20); - break; - default: - break; - } - } -} -#else -void setLedStatus(LedStatus_t status) { - if (jsonReadBool(configSetupJson, "blink") == 1) { - pinMode(LED_PIN, OUTPUT); - switch (status) { - case LED_OFF: - digitalWrite(LED_PIN, HIGH); - break; - case LED_ON: - digitalWrite(LED_PIN, LOW); - break; - case LED_SLOW: - break; - case LED_FAST: - break; - default: - break; - } - } -} -#endif -//=================================================================== -/* - void web_print (String text) { - if (WiFi.status() == WL_CONNECTED) { - jsonWriteStr(json, "test1", jsonReadStr(json, "test2")); - jsonWriteStr(json, "test2", jsonReadStr(json, "test3")); - jsonWriteStr(json, "test3", jsonReadStr(json, "test4")); - jsonWriteStr(json, "test4", jsonReadStr(json, "test5")); - jsonWriteStr(json, "test5", jsonReadStr(json, "test6")); - - jsonWriteStr(json, "test6", GetTime() + " " + text); - - ws.textAll(json); - } - } -*/ -//=================================================================== -/* - "socket": [ - "ws://{{ip}}/ws" - ], -*/ -//=================================================================== -/* - { - "type": "h4", - "title": "('{{build2}}'=='{{firmware_version}}'?'NEW':'OLD')" - }, -*/ -//=================================================================== -/* - { - "type": "button", - "title": "Конфигурация устройства", - "socket": "test2", - "class": "btn btn-block btn-primary" - }, - { - "type": "hr" - }, - { - "type": "h6", - "title": "{{test1}}" - }, - { - "type": "h6", - "title": "{{test2}}" - }, - { - "type": "h6", - "title": "{{test3}}" - }, - { - "type": "h6", - "title": "{{test4}}" - }, - { - "type": "h6", - "title": "{{test5}}" - }, - { - "type": "h6", - "title": "{{test6}}" - }, - { - "type": "hr" - }, -*/ -//=================================================================== - -/* - String getResetReason(uint8_t core) { - int reason = rtc_get_reset_reason(core); - switch (reason) { - case 1 : return "Power on"; break; //Vbat power on reset - case 3 : return "Software reset digital core"; break; //Software reset digital core - case 4 : return "Legacy watch dog reset digital core"; break; //Legacy watch dog reset digital core - case 5 : return "Deep Sleep reset digital core"; break; //Deep Sleep reset digital core - case 6 : return "Reset by SLC module, reset digital core"; break; //Reset by SLC module, reset digital core - case 7 : return "Timer Group0 Watch dog reset digital core"; break; //Timer Group0 Watch dog reset digital core - case 8 : return "Timer Group1 Watch dog reset digital core"; break; //Timer Group1 Watch dog reset digital core - case 9 : return "RTC Watch dog Reset digital core"; break; // - case 10 : return "Instrusion tested to reset CPU"; break; - case 11 : return "Time Group reset CPU"; break; - case 12 : return "Software reset CPU"; break; - case 13 : return "RTC Watch dog Reset CPU"; break; - case 14 : return "for APP CPU, reseted by PRO CPU"; break; - case 15 : return "Reset when the vdd voltage is not stable"; break; - case 16 : return "RTC Watch dog reset digital core and rtc module"; break; - default : return "NO_MEAN"; - } - } - - - String EspClass::getResetReason(void) { - char buff[32]; - if (resetInfo.reason == REASON_DEFAULT_RST) { // normal startup by power on - strcpy_P(buff, PSTR("Power on")); - } else if (resetInfo.reason == REASON_WDT_RST) { // hardware watch dog reset - strcpy_P(buff, PSTR("Hardware Watchdog")); - } else if (resetInfo.reason == REASON_EXCEPTION_RST) { // exception reset, GPIO status won’t change - strcpy_P(buff, PSTR("Exception")); - } else if (resetInfo.reason == REASON_SOFT_WDT_RST) { // software watch dog reset, GPIO status won’t change - strcpy_P(buff, PSTR("Software Watchdog")); - } else if (resetInfo.reason == REASON_SOFT_RESTART) { // software restart ,system_restart , GPIO status won’t change - strcpy_P(buff, PSTR("Software/System restart")); - } else if (resetInfo.reason == REASON_DEEP_SLEEP_AWAKE) { // wake up from deep-sleep - strcpy_P(buff, PSTR("Deep-Sleep Wake")); - } else if (resetInfo.reason == REASON_EXT_SYS_RST) { // external system reset - strcpy_P(buff, PSTR("External System")); - } else { - strcpy_P(buff, PSTR("Unknown")); - } - return String(buff); - } -*/ diff --git a/src/Utils/TimeUtils.cpp b/src/Utils/TimeUtils.cpp deleted file mode 100644 index 2b313e69..00000000 --- a/src/Utils/TimeUtils.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "Utils/TimeUtils.h" - -#include "Utils/StringUtils.h" - -static const uint8_t days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -static const char* week_days[7] = {"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat"}; - -// String getTimeUnix() { -// time_t t; -// struct tm* tm; - -// t = time(NULL); -// tm = localtime(&t); -// Serial.printf("%04d/%02d/%02d(%s) %02d:%02d:%02d\n", -// tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, week_days[tm->tm_wday], -// tm->tm_hour, tm->tm_min, tm->tm_sec); -// delay(1000); -// time_t now = time(nullptr); -// if (now < 30000) { -// return "failed"; -// } -// return String(now); -// } - -// String getTime() { -// time_t now = time(nullptr); -// int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt(); -// now = now + zone; -// String Time = ""; // Строка для результатов времени -// Time += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017 -// int i = Time.indexOf(":"); //Ишем позицию первого символа : -// Time = Time.substring(i - 2, i + 6); // Выделяем из строки 2 символа перед символом : и 6 символов после -// return Time; // Возврашаем полученное время -// } - -// String getTimeWOsec() { -// time_t now = time(nullptr); -// int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt(); -// now = now + zone; -// String Time = ""; // Строка для результатов времени -// Time += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017 -// int i = Time.indexOf(":"); //Ишем позицию первого символа : -// Time = Time.substring(i - 2, i + 3); // Выделяем из строки 2 символа перед символом : и 6 символов после -// return Time; // Возврашаем полученное время -// } - -// String getDate() { -// time_t now = time(nullptr); -// int zone = 3600 * jsonReadStr(configSetupJson, "timezone").toInt(); -// now = now + zone; -// String Data = ""; // Строка для результатов времени -// Data += ctime(&now); // Преобразуем время в строку формата Thu Jan 19 00:55:35 2017 -// Data.replace("\n", ""); -// uint8_t i = Data.lastIndexOf(" "); //Ишем позицию последнего символа пробел -// String Time = Data.substring(i - 8, i + 1); // Выделяем время и пробел -// Data.replace(Time, ""); // Удаляем из строки 8 символов времени и пробел -// return Data; // Возврашаем полученную дату -// } - -// String getDateDigitalFormated() { -// String date = getDate(); - -// date = deleteBeforeDelimiter(date, " "); - -// date.replace("Jan", "01"); -// date.replace("Feb", "02"); -// date.replace("Mar", "03"); -// date.replace("Apr", "04"); -// date.replace("May", "05"); -// date.replace("Jun", "06"); -// date.replace("Jul", "07"); -// date.replace("Aug", "08"); -// date.replace("Sep", "09"); -// date.replace("Oct", "10"); -// date.replace("Nov", "11"); -// date.replace("Dec", "12"); - -// String month = date.substring(0, 2); -// String day = date.substring(3, 5); -// String year = date.substring(8, 10); - -// String out = day; -// out += "."; -// out += month; -// out += "."; -// out += year; - -// return out; -// } - -// int timeToMin(String Time) { -// //"00:00:00" время в секунды -// long min = selectToMarker(Time, ":").toInt() * 60; //общее количество секунд в полных часах -// Time = deleteBeforeDelimiter(Time, ":"); // Теперь здесь минуты секунды -// min += selectToMarker(Time, ":").toInt(); // Добавим секунды из полных минут -// return min; -// } - -static const char* TIME_FORMAT PROGMEM = "%02d:%02d:%02d"; -static const char* TIME_FORMAT_WITH_DAYS PROGMEM = "%dd %02d:%02d"; - -const String prettySeconds(unsigned long time_s) { - unsigned long tmp = time_s; - unsigned long seconds; - unsigned long minutes; - unsigned long hours; - unsigned long days; - seconds = tmp % 60; - tmp = tmp / 60; - - minutes = tmp % 60; - tmp = tmp / 60; - - hours = tmp % 24; - days = tmp / 24; - - char buf[32]; - - if (days) { - sprintf_P(buf, TIME_FORMAT_WITH_DAYS, days, hours, minutes, seconds); - } else { - sprintf_P(buf, TIME_FORMAT, hours, minutes, seconds); - } - return String(buf); -} - -const String prettyMillis(unsigned long time_ms) { - return prettySeconds(time_ms / 1000); -} - -unsigned long millis_since(unsigned long sinse) { - return millis_passed(sinse, millis()); -} - -unsigned long millis_passed(unsigned long start, unsigned long finish) { - unsigned long result = 0; - if (start <= finish) { - unsigned long passed = finish - start; - if (passed <= __LONG_MAX__) { - result = static_cast(passed); - } else { - result = static_cast((__LONG_MAX__ - finish) + start + 1u); - } - } else { - unsigned long passed = start - finish; - if (passed <= __LONG_MAX__) { - result = static_cast(passed); - result = -1 * result; - } else { - result = static_cast((__LONG_MAX__ - start) + finish + 1u); - result = -1 * result; - } - } - return result; -} - -int getOffsetInSeconds(int timezone) { - return getOffsetInMinutes(timezone) * ONE_MINUTE_s; -} - -int getOffsetInMinutes(int timezone) { - return timezone * ONE_HOUR_m; -} - -void breakEpochToTime(unsigned long epoch, Time_t& tm) { - // break the given time_input into time components - // this is a more compact version of the C library localtime function - - unsigned long time = epoch; - tm.second = time % 60; - time /= 60; // now it is minutes - tm.minute = time % 60; - time /= 60; // now it is hours - tm.hour = time % 24; - time /= 24; // now it is days - tm.days = time; - tm.day_of_week = ((time + 4) % 7) + 1; // Sunday is day 1 - - uint8_t year = 0; - unsigned long days = 0; - - while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { - year++; - } - tm.year = year - 30; - - days -= LEAP_YEAR(year) ? 366 : 365; - time -= days; // now it is days in this year, starting at 0 - tm.day_of_year = time; - - uint8_t month; - uint8_t month_length; - for (month = 0; month < 12; month++) { - if (1 == month) { // february - if (LEAP_YEAR(year)) { - month_length = 29; - } else { - month_length = 28; - } - } else { - month_length = days_in_month[month]; - } - - if (time >= month_length) { - time -= month_length; - } else { - break; - } - } - tm.month = month + 1; // jan is month 1 - tm.day_of_month = time + 1; // day of month - tm.valid = (epoch > MIN_DATETIME); -} diff --git a/src/Utils/WebUtils.cpp b/src/Utils/WebUtils.cpp deleted file mode 100644 index 8c766b0e..00000000 --- a/src/Utils/WebUtils.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "Utils/WebUtils.h" -#include "ESPAsyncWebServer.h" - -String getURL(const String& urls) { - String res = ""; - HTTPClient http; - http.begin(urls); - int httpCode = http.GET(); - if (httpCode == HTTP_CODE_OK) { - res = http.getString(); - } else { - res = "error"; - } - http.end(); - return res; -} - - - -const String getMethodName(AsyncWebServerRequest* request) { - String res = F("UNKNOWN"); - if (request->method() == HTTP_GET) - res = F("GET"); - else if (request->method() == HTTP_POST) - res = F("POST"); - else if (request->method() == HTTP_DELETE) - res = F("DELETE"); - else if (request->method() == HTTP_PUT) - res = F("PUT"); - else if (request->method() == HTTP_PATCH) - res = F("PATCH"); - else if (request->method() == HTTP_HEAD) - res = F("HEAD"); - else if (request->method() == HTTP_OPTIONS) - res = F("OPTIONS"); - return res; -} - -const String getRequestInfo(AsyncWebServerRequest* request) { - String res = getMethodName(request); - res += ' '; - res += "http://"; - res += request->host(); - res += request->url(); - res += '\n'; - if (request->contentLength()) { - res += "content-type: "; - res += request->contentType(); - res += " content-lenght: "; - res += prettyBytes(request->contentLength()); - res += '\n'; - } - - if (request->headers()) { - res += "headers:\n"; - for (size_t i = 0; i < request->headers(); i++) { - AsyncWebHeader* h = request->getHeader(i); - res += h->name(); - res += '='; - res += h->value(); - res += '\n'; - } - } - - if (request->params()) { - res += "params:\n"; - for (size_t i = 0; i < request->params(); i++) { - AsyncWebParameter* p = request->getParam(i); - if (p->isFile()) { - res += "FILE"; - } else if (p->isPost()) { - res += "POST"; - } else { - res += "GET"; - } - res += ' '; - res += p->name(); - res += ':'; - res += p->value(); - if (p->isFile()) { - res += " size:"; - res += p->size(); - } - res += '\n'; - } - } - return res; -} diff --git a/src/Utils/WiFiUtils.cpp b/src/Utils/WiFiUtils.cpp deleted file mode 100644 index f0c66eae..00000000 --- a/src/Utils/WiFiUtils.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "Utils/WiFiUtils.h" - -void routerConnect() { - setLedStatus(LED_SLOW); - WiFi.mode(WIFI_STA); - byte tries = 20; - - String _ssid = jsonReadStr(configSetupJson, "routerssid"); - String _password = jsonReadStr(configSetupJson, "routerpass"); - //WiFi.persistent(false); - - if (_ssid == "" && _password == "") { - WiFi.begin(); - } else { - WiFi.begin(_ssid.c_str(), _password.c_str()); - SerialPrint("I", "WIFI", "ssid: " + _ssid); - } - - while (--tries && WiFi.status() != WL_CONNECTED) { - if (WiFi.status() == WL_CONNECT_FAILED) { - SerialPrint("E", "WIFI", "password is not correct"); - tries = 1; - jsonWriteInt(configOptionJson, "pass_status", 1); - } - Serial.print("."); - delay(1000); - } - - if (WiFi.status() != WL_CONNECTED) { - Serial.println(""); - startAPMode(); - } else { - Serial.println(""); - SerialPrint("I", "WIFI", "http://" + WiFi.localIP().toString()); - jsonWriteStr(configSetupJson, "ip", WiFi.localIP().toString()); - setLedStatus(LED_OFF); - mqttInit(); - } -} - -bool startAPMode() { - setLedStatus(LED_ON); - SerialPrint("I", "WIFI", "AP Mode"); - - WiFi.disconnect(); - WiFi.mode(WIFI_AP); - - String _ssidAP = jsonReadStr(configSetupJson, "apssid"); - String _passwordAP = jsonReadStr(configSetupJson, "appass"); - - WiFi.softAP(_ssidAP.c_str(), _passwordAP.c_str()); - IPAddress myIP = WiFi.softAPIP(); - - SerialPrint("I", "WIFI", "AP IP: " + myIP.toString()); - jsonWriteStr(configSetupJson, "ip", myIP.toString()); - - //if (jsonReadInt(configOptionJson, "pass_status") != 1) { - ts.add( - WIFI_SCAN, 10 * 1000, [&](void*) { - String sta_ssid = jsonReadStr(configSetupJson, "routerssid"); - - SerialPrint("I", "WIFI", "scanning for " + sta_ssid); - - if (RouterFind(sta_ssid)) { - ts.remove(WIFI_SCAN); - WiFi.scanDelete(); - routerConnect(); - } - }, - nullptr, true); - //} - return true; -} - - -boolean RouterFind(String ssid) { - bool res = false; - int n = WiFi.scanComplete(); - SerialPrint("I", "WIFI", "scan result: " + String(n, DEC)); - - if (n == -2) { //Сканирование не было запущено, запускаем - SerialPrint("I", "WIFI", "start scanning"); - WiFi.scanNetworks(true, false); //async, show_hidden - } - - else if (n == -1) { //Сканирование все еще выполняется - SerialPrint("I", "WIFI", "scanning in progress"); - } - - else if (n == 0) { //ни одна сеть не найдена - SerialPrint("I", "WIFI", "no networks found"); - WiFi.scanNetworks(true, false); - } - - else if (n > 0) { - for (int8_t i = 0; i < n; i++) { - if (WiFi.SSID(i) == ssid) { - res = true; - } - SerialPrint("I", "WIFI", (res ? "*" : "") + String(i, DEC) + ") " + WiFi.SSID(i)); - } - } - WiFi.scanDelete(); - return res; -} - -boolean isNetworkActive() { - return WiFi.status() == WL_CONNECTED; -} diff --git a/src/Utils/statUtils.cpp b/src/Utils/statUtils.cpp deleted file mode 100644 index 0145e5f2..00000000 --- a/src/Utils/statUtils.cpp +++ /dev/null @@ -1,309 +0,0 @@ -#include "Utils/StatUtils.h" - -#include -#include - -#include "Global.h" -#include "ItemsList.h" - -#ifdef ESP32 -#include -#endif - -String ESP_getResetReason(void); - -void initSt() { - addNewDevice(); - decide(); - if (TELEMETRY_UPDATE_INTERVAL_MIN) { - ts.add( - STATISTICS, TELEMETRY_UPDATE_INTERVAL_MIN * 60000, [&](void*) { - static bool secondTime = false; - if (secondTime) getNextNumber("totalhrs.txt"); - secondTime = true; - updateDeviceStatus(); - }, - nullptr, true); - } -} - -void decide() { - if ((WiFi.status() == WL_CONNECTED)) { - uint8_t cnt = getNextNumber("stat.txt"); - SerialPrint("I", "Stat", "Total resets number: " + String(cnt)); - if (cnt <= 3) { - Serial.println("(get)"); - getPsn(); - } else { - if (cnt % 5) { - Serial.println("(skip)"); - } else { - Serial.println("(get)"); - getPsn(); - } - } - } -} - -void getPsn() { - String res = getURL(F("http://ipinfo.io/?token=c60f88583ad1a4")); - if (res != "") { - String line = jsonReadStr(res, "loc"); - String lat = selectToMarker(line, ","); - String lon = deleteBeforeDelimiter(line, ","); - //String city = jsonReadStr(res, "city"); - //String country = jsonReadStr(res, "country"); - //String region = jsonReadStr(res, "region"); - updateDevicePsn(lat, lon, "0"); - } -} - -String addNewDevice() { - String ret; - if ((WiFi.status() == WL_CONNECTED)) { - WiFiClient client; - HTTPClient http; - String json = "{}"; - String mac = WiFi.macAddress().c_str(); - //============================================== - jsonWriteStr(json, "uniqueId", mac); - jsonWriteStr(json, "name", FIRMWARE_NAME); - jsonWriteStr(json, "model", getChipId()); - //============================================== - http.begin(client, serverIP + F(":8082/api/devices/")); - http.setAuthorization("admin", "admin"); - http.addHeader("Content-Type", "application/json"); - int httpCode = http.POST(json); - if (httpCode > 0) { - ret = httpCode; - if (httpCode == HTTP_CODE_OK) { - String payload = http.getString(); - ret += " " + payload; - //saveId("statid.txt", jsonReadInt(payload, "id")); - } - } else { - ret = http.errorToString(httpCode).c_str(); - } - http.end(); - } - SerialPrint("I", "Stat", "New device registaration: " + ret); - return ret; -} - -String updateDevicePsn(String lat, String lon, String accur) { - String ret; - if ((WiFi.status() == WL_CONNECTED)) { - float latfl = lat.toFloat(); - float lonfl = lon.toFloat(); - randomSeed(micros()); - float latc = random(1, 9)/100; - randomSeed(micros()); - float lonc = random(1, 9)/100; - latfl = latfl + latc; - lonfl = lonfl + lonc; - WiFiClient client; - HTTPClient http; - http.begin(client, serverIP + F(":5055/")); - http.setAuthorization("admin", "admin"); - http.addHeader("Content-Type", "application/json"); - String mac = WiFi.macAddress().c_str(); - int httpCode = http.POST("?id=" + mac + - "&resetReason=" + ESP_getResetReason() + - "&lat=" + String(latfl) + - "&lon=" + String(lonfl) + - "&accuracy=" + accur + ""); - if (httpCode > 0) { - ret = httpCode; - if (httpCode == HTTP_CODE_OK) { - String payload = http.getString(); - ret += " " + payload; - } - } else { - ret = http.errorToString(httpCode).c_str(); - } - http.end(); - } - SerialPrint("I", "Stat", "Update device psn: " + ret); - return ret; -} - -String updateDeviceStatus() { - String ret; - if ((WiFi.status() == WL_CONNECTED)) { - WiFiClient client; - HTTPClient http; - http.begin(client, serverIP + F(":5055/")); - http.setAuthorization("admin", "admin"); - http.addHeader("Content-Type", "application/json"); - String mac = WiFi.macAddress().c_str(); - int httpCode = http.POST("?id=" + mac + - "&resetReason=" + ESP_getResetReason() + - "&uptime=" + timeNow->getUptime() + - "&uptimeTotal=" + getUptimeTotal() + - "&version=" + FIRMWARE_VERSION + - "&resetsTotal=" + String(getCurrentNumber("stat.txt")) + - "&heap=" + String(ESP.getFreeHeap()) + ""); - if (httpCode > 0) { - ret = httpCode; - if (httpCode == HTTP_CODE_OK) { - String payload = http.getString(); - ret += " " + payload; - } - } else { - ret = http.errorToString(httpCode).c_str(); - } - http.end(); - } - SerialPrint("I", "Stat", "Update device data: " + ret); - return ret; -} - -String getUptimeTotal() { - uint8_t hrs = getCurrentNumber("totalhrs.txt"); - String hrsStr = prettySeconds(hrs * 60 * 60); - SerialPrint("I", "Stat", "Total running time: " + hrsStr); - return hrsStr; -} - -uint8_t getNextNumber(String file) { - uint8_t number = readFile(file, 100).toInt(); - number++; - removeFile(file); - addFile(file, String(number)); - return number; -} - -uint8_t getCurrentNumber(String file) { - uint8_t number = readFile(file, 100).toInt(); - return number; -} - -#ifdef ESP8266 -String ESP_getResetReason(void) { - return ESP.getResetReason(); -} -#else -String ESP32GetResetReason(uint32_t cpu_no) { - // tools\sdk\include\esp32\rom\rtc.h - switch (rtc_get_reset_reason((RESET_REASON)cpu_no)) { - case POWERON_RESET: - return F("Vbat power on reset"); // 1 - case SW_RESET: - return F("Software reset digital core"); // 3 - case OWDT_RESET: - return F("Legacy watch dog reset digital core"); // 4 - case DEEPSLEEP_RESET: - return F("Deep Sleep reset digital core"); // 5 - case SDIO_RESET: - return F("Reset by SLC module, reset digital core"); // 6 - case TG0WDT_SYS_RESET: - return F("Timer Group0 Watch dog reset digital core"); // 7 - case TG1WDT_SYS_RESET: - return F("Timer Group1 Watch dog reset digital core"); // 8 - case RTCWDT_SYS_RESET: - return F("RTC Watch dog Reset digital core"); // 9 - case INTRUSION_RESET: - return F("Instrusion tested to reset CPU"); // 10 - case TGWDT_CPU_RESET: - return F("Time Group reset CPU"); // 11 - case SW_CPU_RESET: - return F("Software reset CPU"); // 12 - case RTCWDT_CPU_RESET: - return F("RTC Watch dog Reset CPU"); // 13 - case EXT_CPU_RESET: - return F("or APP CPU, reseted by PRO CPU"); // 14 - case RTCWDT_BROWN_OUT_RESET: - return F("Reset when the vdd voltage is not stable"); // 15 - case RTCWDT_RTC_RESET: - return F("RTC Watch dog reset digital core and rtc module"); // 16 - default: - return F("NO_MEAN"); // 0 - } -} - -String ESP_getResetReason(void) { - return ESP32GetResetReason(0); // CPU 0 -} -#endif -//String getUptimeTotal() { -// static int hrs; -// EEPROM.begin(512); -// hrs = eeGetInt(0); -// SerialPrint("I","Stat","Total running hrs: " + String(hrs)); -// String hrsStr = prettySeconds(hrs * 60 * 60); -// SerialPrint("I","Stat","Total running hrs (f): " + hrsStr); -// return hrsStr; -//} -//int plusOneHour() { -// static int hrs; -// EEPROM.begin(512); -// hrs = eeGetInt(0); -// hrs++; -// eeWriteInt(0, hrs); -// return hrs; -//} -// -//void eeWriteInt(int pos, int val) { -// byte* p = (byte*)&val; -// EEPROM.write(pos, *p); -// EEPROM.write(pos + 1, *(p + 1)); -// EEPROM.write(pos + 2, *(p + 2)); -// EEPROM.write(pos + 3, *(p + 3)); -// EEPROM.commit(); -//} -// -//int eeGetInt(int pos) { -// int val; -// byte* p = (byte*)&val; -// *p = EEPROM.read(pos); -// *(p + 1) = EEPROM.read(pos + 1); -// *(p + 2) = EEPROM.read(pos + 2); -// *(p + 3) = EEPROM.read(pos + 3); -// if (val < 0) { -// return 0; -// } else { -// return val; -// } -//} -//========for updating list of device================= -/* -void updateDeviceList() { - if ((WiFi.status() == WL_CONNECTED)) { - WiFiClient client; - HTTPClient http; - String json = "{}"; - String mac = WiFi.macAddress().c_str(); - //=============================================== - jsonWriteStr(json, "uniqueId", mac); - jsonWriteStr(json, "name", FIRMWARE_NAME); - jsonWriteStr(json, "model", FIRMWARE_VERSION); - jsonWriteInt(json, "id", getId("statid.txt")); - //=============================================== - http.begin(client, "http://") + serverIP + F(":8082/api/devices/" + mac + "/"); - http.setAuthorization("admin", "admin"); - http.addHeader("Content-Type", "application/json"); - int httpCode = http.PUT(json); - if (httpCode > 0) { - Serial.printf("update Device List... code: %d\n", httpCode); - if (httpCode == HTTP_CODE_OK) { - const String& payload = http.getString(); - Serial.println("received payload:\n<<"); - Serial.println(payload); - Serial.println(">>"); - } - } else { - Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str()); - } - http.end(); - } -} - -void saveId(String file, int id) { - removeFile(file); - addFile(file, String(id)); -} - -int getId(String file) { - return readFile(file, 100).toInt(); -} -*/ \ No newline at end of file diff --git a/src/Web.cpp b/src/Web.cpp deleted file mode 100644 index d2f53825..00000000 --- a/src/Web.cpp +++ /dev/null @@ -1,290 +0,0 @@ -#include "Web.h" -#include "Class/NotAsync.h" -#include "Global.h" -#include "Init.h" -#include "ItemsList.h" -#include "items/LoggingClass.h" -#include "Telegram.h" - -bool parseRequestForPreset(AsyncWebServerRequest* request, uint8_t& preset) { - if (request->hasArg("preset")) { - preset = request->getParam("preset")->value().toInt(); - return true; - } - return false; -} - -void web_init() { - server.on("/set", HTTP_GET, [](AsyncWebServerRequest* request) { - //==============================set.device.json==================================================================================================== - if (request->hasArg("addItem")) { - String name = request->getParam("addItem")->value(); - addItem(name); - request->redirect("/?set.device"); - } - - if (request->hasArg("addPreset")) { - String name = request->getParam("addPreset")->value(); - addPreset(name); - request->redirect("/?set.device"); - } - - if (request->hasArg("delChoosingItems")) { - myNotAsyncActions->make(do_delChoosingItems); - request->send(200); - } - - if (request->hasArg("delAllItems")) { - delAllItems(); - request->redirect("/?set.device"); - } - - if (request->hasArg("saveItems")) { - myNotAsyncActions->make(do_deviceInit); - request->send(200); - } - - if (request->hasArg("scen")) { - bool value = request->getParam("scen")->value().toInt(); - jsonWriteBool(configSetupJson, "scen", value); - saveConfig(); - loadScenario(); - request->send(200); - } - - if (request->hasArg("sceninit")) { - loadScenario(); - request->send(200); - } - -#ifdef LOGGING_ENABLED - if (request->hasArg("cleanlog")) { - clean_log_date(); - request->send(200); - } -#endif - - //==============================wifi settings============================================= - if (request->hasArg("devname")) { - jsonWriteStr(configSetupJson, "name", request->getParam("devname")->value()); - saveConfig(); - request->send(200); - } - - if (request->hasArg("routerssid")) { - jsonWriteStr(configSetupJson, "routerssid", request->getParam("routerssid")->value()); - saveConfig(); - request->send(200); - } - - if (request->hasArg("routerpass")) { - jsonWriteStr(configSetupJson, "routerpass", request->getParam("routerpass")->value()); - saveConfig(); - request->send(200); - } - - if (request->hasArg("apssid")) { - jsonWriteStr(configSetupJson, "apssid", request->getParam("apssid")->value()); - saveConfig(); - request->send(200, "text/text", "OK"); - } - - if (request->hasArg("appass")) { - jsonWriteStr(configSetupJson, "appass", request->getParam("appass")->value()); - saveConfig(); - request->send(200); - } - - if (request->hasArg("weblogin")) { - jsonWriteStr(configSetupJson, "weblogin", request->getParam("weblogin")->value()); - saveConfig(); - request->send(200); - } - - if (request->hasArg("webpass")) { - jsonWriteStr(configSetupJson, "webpass", request->getParam("webpass")->value()); - saveConfig(); - request->send(200); - } - - if (request->hasArg("timezone")) { - String timezoneStr = request->getParam("timezone")->value(); - jsonWriteStr(configSetupJson, "timezone", timezoneStr); - saveConfig(); - timeNow->setTimezone(timezoneStr.toInt()); - request->send(200); - } - - if (request->hasArg("ntp")) { - String ntpStr = request->getParam("ntp")->value(); - jsonWriteStr(configSetupJson, "ntp", ntpStr); - saveConfig(); - timeNow->setNtpPool(ntpStr); - request->send(200); - } - - if (request->hasArg("blink")) { - bool value = request->getParam("blink")->value().toInt(); - jsonWriteBool(configSetupJson, "blink", value); - saveConfig(); - request->send(200); - } - - if (request->hasArg("device")) { - if (request->getParam("device")->value() == "ok") { - ESP.restart(); - } - request->send(200); - } - - if (request->hasArg("test")) { - if (request->getParam("test")->value() == "ok") { - Serial.println("test pass"); - } - request->send(200); - } - - //==============================mqtt settings============================================= - - if (request->hasArg("mqttServer")) { - jsonWriteStr(configSetupJson, "mqttServer", request->getParam("mqttServer")->value()); - saveConfig(); - myNotAsyncActions->make(do_MQTTPARAMSCHANGED); - request->send(200); - } - if (request->hasArg("mqttPort")) { - int port = (request->getParam("mqttPort")->value()).toInt(); - jsonWriteInt(configSetupJson, "mqttPort", port); - saveConfig(); - myNotAsyncActions->make(do_MQTTPARAMSCHANGED); - request->send(200); - } - if (request->hasArg("mqttPrefix")) { - jsonWriteStr(configSetupJson, "mqttPrefix", request->getParam("mqttPrefix")->value()); - saveConfig(); - myNotAsyncActions->make(do_MQTTPARAMSCHANGED); - request->send(200); - } - if (request->hasArg("mqttUser")) { - jsonWriteStr(configSetupJson, "mqttUser", request->getParam("mqttUser")->value()); - saveConfig(); - myNotAsyncActions->make(do_MQTTPARAMSCHANGED); - request->send(200); - } - if (request->hasArg("mqttPass")) { - jsonWriteStr(configSetupJson, "mqttPass", request->getParam("mqttPass")->value()); - saveConfig(); - myNotAsyncActions->make(do_MQTTPARAMSCHANGED); - request->send(200); - } - - if (request->hasArg("mqttsend")) { - myNotAsyncActions->make(do_MQTTUDP); - request->send(200); - } - - if (request->hasArg("mqttcheck")) { - String buf = "" + getStateStr(); - - String payload = "{}"; - jsonWriteStr(payload, "title", buf); - jsonWriteStr(payload, "class", "pop-up"); - - request->send(200, "text/html", payload); - } - - //==============================push settings============================================= - if (request->hasArg("telegramApi")) { - jsonWriteStr(configSetupJson, "telegramApi", request->getParam("telegramApi")->value()); - //telegramInit(); - saveConfig(); - request->send(200); - } - if (request->hasArg("telegonof")) { - bool value = request->getParam("telegonof")->value().toInt(); - jsonWriteBool(configSetupJson, "telegonof", value); - //telegramInit(); - saveConfig(); - request->send(200); - } - - //==============================utilities settings============================================= - if (request->hasArg("i2c")) { - myNotAsyncActions->make(do_BUSSCAN); - request->redirect("/?set.utilities"); - } - - //==============================developer settings============================================= - if (request->hasArg("serverip")) { - jsonWriteStr(configSetupJson, "serverip", request->getParam("serverip")->value()); - saveConfig(); - serverIP = jsonReadStr(configSetupJson, "serverip"); - request->send(200); - } - }); - - //==============================list of items===================================================== - //server.on("/del", HTTP_GET, [](AsyncWebServerRequest* request) { - // if (request->hasArg("file")) { - // itemsFile = request->getParam("file")->value(); - // } - // if (request->hasArg("line")) { - // itemsLine = request->getParam("line")->value(); - // } - // delElementFlag = true; - // Device_init(); - // request->redirect("/?setn.device"); - //}); - - /* - * Check - */ - server.on("/check", HTTP_GET, [](AsyncWebServerRequest* request) { - myNotAsyncActions->make(do_GETLASTVERSION); - SerialPrint("I", "Update", "firmware version: " + String(lastVersion)); - - String msg = ""; - if (lastVersion == FIRMWARE_VERSION) { - msg = F("Актуальная версия прошивки уже установлена."); - } - else if (lastVersion > FIRMWARE_VERSION) { - msg = F("Новая версия прошивкиИдет обновление прошивки, после обновления страница перезагрузится автоматически...')\">Установить"); - } - else if (lastVersion == -1) { - msg = F("Cервер не найден. Попробуйте повторить позже..."); - } - else if (lastVersion == -2) { - msg = F("Устройство не подключено к роутеру!"); - } - else if (lastVersion < FIRMWARE_VERSION) { - msg = F("Ошибка версии. Попробуйте повторить позже..."); - } - - // else if (lastVersion == "") { - //msg = F("Нажмите на кнопку \"обновить прошивку\" повторно..."); - //} else if (lastVersion == "less") { - //msg = F("Обновление \"по воздуху\" не поддерживается!"); - //} else if (lastVersion == "notsupported") { - // msg = F("Обновление возможно только через usb!"); - //} - - String tmp = "{}"; - jsonWriteStr(tmp, "title", "" + msg); - jsonWriteStr(tmp, "class", "pop-up"); - request->send(200, "text/html", tmp); - }); - - /* - * Upgrade - */ - server.on("/upgrade", HTTP_GET, [](AsyncWebServerRequest* request) { - myNotAsyncActions->make(do_UPGRADE); - request->send(200, "text/html"); - }); -} - -void setConfigParam(const char* param, const String& value) { - SerialPrint("I", "Web", "set " + String(param) + ": " + value); - jsonWriteStr(configSetupJson, param, value); - saveConfig(); -} \ No newline at end of file diff --git a/src/WebServer.cpp b/src/WebServer.cpp deleted file mode 100644 index 810a1add..00000000 --- a/src/WebServer.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "HttpServer.h" -#include "BufferExecute.h" -#include "Utils/FileUtils.h" -#include "Utils/WebUtils.h" -#include "FSEditor.h" - -namespace HttpServer { - - -/* Forward declaration */ -void initOta(); -void initMDNS(); -void initWS(); - -void init() { - String login = jsonReadStr(configSetupJson, "weblogin"); - String pass = jsonReadStr(configSetupJson, "webpass"); -#ifdef ESP32 - server.addHandler(new FSEditor(LittleFS, login, pass)); -#else - server.addHandler(new FSEditor(login, pass)); -#endif - - server.serveStatic("/css/", LittleFS, "/css/").setCacheControl("max-age=600"); - server.serveStatic("/js/", LittleFS, "/js/").setCacheControl("max-age=600"); - server.serveStatic("/favicon.ico", LittleFS, "/favicon.ico").setCacheControl("max-age=600"); - server.serveStatic("/icon.jpeg", LittleFS, "/icon.jpeg").setCacheControl("max-age=600"); - - server.serveStatic("/", LittleFS, "/").setDefaultFile("index.htm").setAuthentication(login.c_str(), pass.c_str()); - - server.onNotFound([](AsyncWebServerRequest *request) { - SerialPrint("[E]","WebServer","not found:\n" + getRequestInfo(request)); - request->send(404); - }); - - server.onFileUpload([](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) { - // TODO - if (!index) { - SerialPrint("I","WebServer","start upload " + filename); - } - if (final) { - SerialPrint("I","WebServer","finish upload: " + prettyBytes(index + len)); - } - }); - - // динамические данные - server.on("/config.live.json", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "application/json", configLiveJson); - }); - - // данные не являющиеся событиями - server.on("/config.option.json", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "application/json", configOptionJson); - }); - - // для хранения постоянных данных - server.on("/config.setup.json", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "application/json", configSetupJson); - }); - - server.on("/cmd", HTTP_GET, [](AsyncWebServerRequest *request) { - String cmdStr = request->getParam("command")->value(); - SerialPrint("I","WebServer","do: " + cmdStr); - loopCmdAdd(cmdStr); - request->send(200, "text/html", "OK"); - }); - - server.begin(); - - initOta(); - initMDNS(); - initWS(); -} - -void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { -#ifdef WS_enable - if (type == WS_EVT_CONNECT) { - Serial.printf("ws[%s][%u] connect\n", server->url(), client->id()); - client->printf(json.c_str(), client->id()); - //client->ping(); - } else if (type == WS_EVT_DISCONNECT) { - Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id()); - } else if (type == WS_EVT_ERROR) { - Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data); - } else if (type == WS_EVT_PONG) { - Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char *)data : ""); - } else if (type == WS_EVT_DATA) { - AwsFrameInfo *info = (AwsFrameInfo *)arg; - String msg = ""; - if (info->final && info->index == 0 && info->len == len) { - //the whole message is in a single frame and we got all of it's data - Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT) ? "text" : "binary", info->len); - - if (info->opcode == WS_TEXT) { - for (size_t i = 0; i < info->len; i++) { - msg += (char)data[i]; - } - } else { - char buff[3]; - for (size_t i = 0; i < info->len; i++) { - sprintf(buff, "%02x ", (uint8_t)data[i]); - msg += buff; - } - } - Serial.printf("%s\n", msg.c_str()); - - if (info->opcode == WS_TEXT) - client->text("{}"); - else - client->binary("{}"); - } else { - //message is comprised of multiple frames or the frame is split into multiple packets - if (info->index == 0) { - if (info->num == 0) - Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT) ? "text" : "binary"); - Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len); - } - - Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT) ? "text" : "binary", info->index, info->index + len); - - if (info->opcode == WS_TEXT) { - for (size_t i = 0; i < len; i++) { - msg += (char)data[i]; - } - } else { - char buff[3]; - for (size_t i = 0; i < len; i++) { - sprintf(buff, "%02x ", (uint8_t)data[i]); - msg += buff; - } - } - Serial.printf("%s\n", msg.c_str()); - - if ((info->index + len) == info->len) { - Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); - if (info->final) { - Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT) ? "text" : "binary"); - if (info->message_opcode == WS_TEXT) - client->text("I got your text message"); - else - client->binary("I got your binary message"); - } - } - } - } -#endif - ; -} - -void initMDNS() { -#ifdef MDNS_ENABLED - MDNS.addService("http", "tcp", 80); - // TODO Add Adduino OTA -#endif - ; -} - -void initOta() { -#ifdef OTA_UPDATES_ENABLED - ArduinoOTA.onStart([]() { - events.send("Update Start", "ota"); - }); - ArduinoOTA.onEnd([]() { - events.send("Update End", "ota"); - }); - ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { - char p[32]; - sprintf(p, "Progress: %u%%\n", (progress / (total / 100))); - events.send(p, "ota"); - }); - ArduinoOTA.onError([](ota_error_t error) { - if (error == OTA_AUTH_ERROR) - events.send("Auth Failed", "ota"); - else if (error == OTA_BEGIN_ERROR) - events.send("Begin Failed", "ota"); - else if (error == OTA_CONNECT_ERROR) - events.send("Connect Failed", "ota"); - else if (error == OTA_RECEIVE_ERROR) - events.send("Recieve Failed", "ota"); - else if (error == OTA_END_ERROR) - events.send("End Failed", "ota"); - }); - ArduinoOTA.setHostname(hostName); - ArduinoOTA.begin(); -#endif - ; -} - -void initWS() { -#ifdef WS_enable - ws.onEvent(onWsEvent); - server.addHandler(&ws); - events.onConnect([](AsyncEventSourceClient *client) { - client->send("", NULL, millis(), 1000); - }); - server.addHandler(&events); -#endif - ; -} - -} // namespace HttpServer \ No newline at end of file diff --git a/src/Widgets.cpp b/src/Widgets.cpp deleted file mode 100644 index 13c58db1..00000000 --- a/src/Widgets.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "Global.h" - - -const String getWidgetFile(const String& name); - -bool loadWidget(const String& filename, String& buf) { - buf = readFile(getWidgetFile(filename), 2048); - bool res = !(buf == "Failed" || buf == "Large"); - if (!res) { - SerialPrint("[E]","Widgets","on load" + filename); - } - return res; -} - -void createWidget(String descr, String page, String order, String filename, String topic) { - String buf = "{}"; - if (!loadWidget(filename, buf)) { - return; - } - descr.replace("#", " "); - page.replace("#", " "); - - jsonWriteStr(buf, "page", page); - jsonWriteStr(buf, "order", order); - jsonWriteStr(buf, "descr", descr); - jsonWriteStr(buf, "topic", prex + "/" + topic); - -#ifdef LAYOUT_IN_RAM - all_widgets += widget + "\r\n"; -#else - addFileLn("layout.txt", buf); -#endif -} - -//TODO Вот эта процедура, и несколько оберток -void createWidgetParam(String widget, String page, String pageNumber, String filename, String topic, - String name1, String param1, String name2, String param2, String name3, String param3) { - String buf = ""; - if (!loadWidget(filename, buf)) { - return; - } - - widget.replace("#", " "); - page.replace("#", " "); - - jsonWriteStr(buf, "page", page); - jsonWriteStr(buf, "order", pageNumber); - jsonWriteStr(buf, "descr", widget); - jsonWriteStr(buf, "topic", prex + "/" + topic); - - if (name1) jsonWriteStr(buf, name1, param1); - if (name2) jsonWriteStr(buf, name2, param2); - if (name3) jsonWriteStr(buf, name3, param3); - -#ifdef LAYOUT_IN_RAM - all_widgets += widget + "\r\n"; -#else - addFileLn("layout.txt", buf); -#endif -} - -void createChart(String widget, String page, String pageNumber, String filename, String topic, - String maxCount) { - String buf = ""; - if (!loadWidget(filename, buf)) { - return; - } - - widget.replace("#", " "); - page.replace("#", " "); - - jsonWriteStr(buf, "page", page); - jsonWriteStr(buf, "order", pageNumber); - //jsonWriteStr(widget, "descr", widget_name); - jsonWriteStr(buf, "series", widget); - jsonWriteStr(buf, "maxCount", maxCount); - jsonWriteStr(buf, "topic", prex + "/" + topic); - -#ifdef LAYOUT_IN_RAM - all_widgets += widget + "\r\n"; -#else - addFileLn("layout.txt", buf); -#endif -} - -void createWidgetByType(String widget, String page, String pageNumber, String type, String topic) { - createWidget(widget, page, pageNumber, getWidgetFile(type), topic); -} - -const String getWidgetFile(const String& name) { - return "/widgets/" + name + ".json"; -} diff --git a/src/items/ButtonInClass.cpp b/src/items/ButtonInClass.cpp deleted file mode 100644 index 23a944f2..00000000 --- a/src/items/ButtonInClass.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "BufferExecute.h" -#include "items/ButtonInClass.h" -//==========================================Модуль физических кнопок======================================== -//button-in switch1 toggle Кнопки Свет 1 pin[2] db[20] -//========================================================================================================== - -boolean but[NUM_BUTTONS]; -Bounce *buttons = new Bounce[NUM_BUTTONS]; - -ButtonInClass myButtonIn; -void buttonIn() { - myButtonIn.update(); - String key = myButtonIn.gkey(); - String pin = myButtonIn.gpin(); - sCmd.addCommand(key.c_str(), buttonInSet); - myButtonIn.init(); - myButtonIn.switchStateSetDefault(); - myButtonIn.clear(); -} - -void buttonInSet() { - String key = sCmd.order(); - String state = sCmd.next(); - myButtonIn.switchChangeVirtual(key, state); -} \ No newline at end of file diff --git a/src/items/ButtonOutClass.cpp b/src/items/ButtonOutClass.cpp deleted file mode 100644 index ba674e0d..00000000 --- a/src/items/ButtonOutClass.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "items/ButtonOutClass.h" - -#include "BufferExecute.h" -//==========================================Модуль кнопок=================================================== -//button-out light toggle Кнопки Свет 1 pin[12] inv[1] st[1] -//========================================================================================================== -ButtonOutClass myButtonOut; -void buttonOut() { - myButtonOut.update(); - String key = myButtonOut.gkey(); - String pin = myButtonOut.gpin(); - String inv = myButtonOut.ginv(); - sCmd.addCommand(key.c_str(), buttonOutSet); - myButtonOut.init(); - myButtonOut.pinStateSetDefault(); - myButtonOut.clear(); -} - -void buttonOutSet() { - String key = sCmd.order(); - String state = sCmd.next(); - myButtonOut.pinChange(key, state); -} diff --git a/src/items/ImpulsOutClass.cpp b/src/items/ImpulsOutClass.cpp deleted file mode 100644 index 4cab6494..00000000 --- a/src/items/ImpulsOutClass.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "items/ImpulsOutClass.h" - -#include -#include "BufferExecute.h" -#include "Class/LineParsing.h" -#include "Global.h" -#include "BufferExecute.h" - -ImpulsOutClass::ImpulsOutClass(unsigned int impulsPin) { - _impulsPin = impulsPin; - pinMode(impulsPin, OUTPUT); -} - -ImpulsOutClass::~ImpulsOutClass() {} - -void ImpulsOutClass::execute(unsigned long impulsPeriod, unsigned int impulsCount) { - _impulsPeriod = impulsPeriod; - _impulsCount = impulsCount * 2; - _impulsCountBuf = _impulsCount; -} - -void ImpulsOutClass::loop() { - currentMillis = millis(); - unsigned long difference = currentMillis - prevMillis; - if (_impulsCountBuf > 0) { - if (difference > _impulsPeriod) { - _impulsCountBuf--; - prevMillis = millis(); - yield(); - digitalWrite(_impulsPin, !digitalRead(_impulsPin)); - yield(); - } - } - if (_impulsCountBuf <= 0) { - digitalWrite(_impulsPin, LOW); - } -} - -MyImpulsOutVector* myImpulsOut = nullptr; - -void impuls() { - myLineParsing.update(); - String key = myLineParsing.gkey(); - String pin = myLineParsing.gpin(); - myLineParsing.clear(); - - impulsEnterCounter++; - addKey(key, impulsKeyList, impulsEnterCounter); - - static bool firstTime = true; - if (firstTime) myImpulsOut = new MyImpulsOutVector(); - firstTime = false; - myImpulsOut->push_back(ImpulsOutClass(pin.toInt())); - - sCmd.addCommand(key.c_str(), impulsExecute); -} - -void impulsExecute() { - String key = sCmd.order(); - String impulsPeriod = sCmd.next(); - String impulsCount = sCmd.next(); - - int number = getKeyNum(key, impulsKeyList); - - if (myImpulsOut != nullptr) { - if (number != -1) { - myImpulsOut->at(number).execute(impulsPeriod.toInt(), impulsCount.toInt()); - } - } -} diff --git a/src/items/InputDigitClass.cpp b/src/items/InputDigitClass.cpp deleted file mode 100644 index 1a2e3b38..00000000 --- a/src/items/InputDigitClass.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "BufferExecute.h" -#include "items/InputClass.h" -//==========================================Модуль ввода цифровых значений================================== -//input-digit digit1 inputDigit Ввод Введите.цифру 4 st[60] -//========================================================================================================== -InputClass myInputDigit; -void inputDigit() { - myInputDigit.update(); - String key = myInputDigit.gkey(); - sCmd.addCommand(key.c_str(), inputDigitSet); - myInputDigit.inputSetDefaultFloat(); - myInputDigit.clear(); -} - -void inputDigitSet() { - String key = sCmd.order(); - String state = sCmd.next(); - myInputDigit.inputSetFloat(key, state); -} \ No newline at end of file diff --git a/src/items/InputTimeClass.cpp b/src/items/InputTimeClass.cpp deleted file mode 100644 index 9dc16dd4..00000000 --- a/src/items/InputTimeClass.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "BufferExecute.h" -#include "items/InputClass.h" -//==========================================Модуль ввода времени============================================ -//========================================================================================================== -InputClass myInputTime; -void inputTime() { - myInputTime.update(); - String key = myInputTime.gkey(); - sCmd.addCommand(key.c_str(), inputTimeSet); - myInputTime.inputSetDefaultStr(); - myInputTime.clear(); -} - -void inputTimeSet() { - String key = sCmd.order(); - String state = sCmd.next(); - myInputTime.inputSetStr(key, state); -} - -void handle_time_init() { - ts.add( - TIME, 1000, [&](void*) { - String timenow = timeNow->getTimeWOsec(); - static String prevTime; - if (prevTime != timenow) { - prevTime = timenow; - jsonWriteStr(configLiveJson, "timenow", timenow); - eventGen2("timenow", timenow); - } - }, - nullptr, true); -} \ No newline at end of file diff --git a/src/items/LoggingClass.cpp b/src/items/LoggingClass.cpp deleted file mode 100644 index e01e01f5..00000000 --- a/src/items/LoggingClass.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "items/LoggingClass.h" - -#include - -#include "Class/LineParsing.h" -#include "Global.h" -#include "BufferExecute.h" - -LoggingClass::LoggingClass(unsigned long period, unsigned int maxPoints, String loggingValueKey, String key) { - _period = period * 1000; - _maxPoints = maxPoints; - _loggingValueKey = loggingValueKey; - _key = key; -} - -LoggingClass::~LoggingClass() {} - -void LoggingClass::loop() { - currentMillis = millis(); - unsigned long difference = currentMillis - prevMillis; - if (difference >= _period) { - prevMillis = millis(); - addNewDelOldData("logs/" + _key + ".txt", _maxPoints, jsonReadStr(configLiveJson, _loggingValueKey)); - } -} - -void LoggingClass::addNewDelOldData(const String filename, size_t maxPoints, String payload) { - String logData = readFile(filename, 5120); - size_t lines_cnt = itemsCount(logData, "\r\n"); - - SerialPrint("I", "Logging", "http://" + WiFi.localIP().toString() + "/" + filename + " (" + String(lines_cnt, DEC) + ")"); - - if ((lines_cnt > maxPoints + 1) || !lines_cnt) { - removeFile(filename); - lines_cnt = 0; - } - - if (payload != "") { - if (lines_cnt > maxPoints) { - logData = deleteBeforeDelimiter(logData, "\r\n"); - if (timeNow->hasTimeSynced()) { - logData += timeNow->getTimeUnix() + " " + payload + "\r\n"; - writeFile(filename, logData); - } - } - else { - if (timeNow->hasTimeSynced()) { - addFileLn(filename, timeNow->getTimeUnix() + " " + payload); - } - } - } -} - -MyLoggingVector* myLogging = nullptr; - -void logging() { - myLineParsing.update(); - String loggingValueKey = myLineParsing.gval(); - String key = myLineParsing.gkey(); - String interv = myLineParsing.gint(); - String maxcnt = myLineParsing.gcnt(); - myLineParsing.clear(); - - loggingKeyList += key + ","; - - static bool firstTime = true; - if (firstTime) myLogging = new MyLoggingVector(); - firstTime = false; - myLogging->push_back(LoggingClass(interv.toInt(), maxcnt.toInt(), loggingValueKey, key)); -} - -void choose_log_date_and_send() { - String all_line = loggingKeyList; - while (all_line.length() != 0) { - String tmp = selectToMarker(all_line, ","); - sendLogData("logs/" + tmp + ".txt", tmp); - all_line = deleteBeforeDelimiter(all_line, ","); - } -} - -void sendLogData(String file, String topic) { - String log_date = readFile(file, 5120); - if (log_date != "failed") { - log_date.replace("\r\n", "\n"); - log_date.replace("\r", "\n"); - String buf = "{}"; - String json_array; - String unix_time; - String value; - while (log_date.length()) { - String tmp = selectToMarker(log_date, "\n"); - log_date = deleteBeforeDelimiter(log_date, "\n"); - unix_time = selectToMarker(tmp, " "); - jsonWriteInt(buf, "x", unix_time.toInt()); - value = deleteBeforeDelimiter(tmp, " "); - jsonWriteFloat(buf, "y1", value.toFloat()); - if (log_date.length() < 3) { - json_array += buf; - } - else { - json_array += buf + ","; - } - buf = "{}"; - } - unix_time = ""; - value = ""; - log_date = ""; - json_array = "{\"status\":[" + json_array + "]}"; - //SerialPrint("I", "module", json_array); - - publishChart(topic, json_array); - } -} - -void clean_log_date() { -#ifdef ESP8266 - auto dir = LittleFS.openDir("logs"); - while (dir.next()) { - String fname = dir.fileName(); - SerialPrint("I", "System", fname); - removeFile("logs/" + fname); - } -#endif -} diff --git a/src/items/OutputTextClass.cpp b/src/items/OutputTextClass.cpp deleted file mode 100644 index f86de77d..00000000 --- a/src/items/OutputTextClass.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "BufferExecute.h" -#include "items/OutputTextClass.h" -//===============================================Модуль вывода текста============================================ -//output-text;id;anydata;Вывод;Сигнализация;order;st[Обнаружено.движение] -//=============================================================================================================== -OutputTextClass myOutputText; -void textOut() { - myOutputText.update(); - String key = myOutputText.gkey(); - sCmd.addCommand(key.c_str(), textOutSet); - myOutputText.OutputModuleStateSetDefault(); - myOutputText.clear(); -} - -void textOutSet() { - String key = sCmd.order(); - String state = sCmd.next(); - myOutputText.OutputModuleChange(key, state); -} \ No newline at end of file diff --git a/src/items/PwmOutClass.cpp b/src/items/PwmOutClass.cpp deleted file mode 100644 index 44ece25c..00000000 --- a/src/items/PwmOutClass.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "BufferExecute.h" -#include "items/PwmOutClass.h" -//==========================================Модуль управления ШИМ=================================================== -//pwm-out volume range Кнопки Свет 1 pin[12] st[500] -//================================================================================================================== -PwmOutClass myPwmOut; -void pwmOut() { - myPwmOut.update(); - String key = myPwmOut.gkey(); - String pin = myPwmOut.gpin(); - String inv = myPwmOut.ginv(); - sCmd.addCommand(key.c_str(), pwmOutSet); - jsonWriteStr(configOptionJson, key + "_pin", pin); - myPwmOut.pwmModeSet(); - myPwmOut.pwmStateSetDefault(); - myPwmOut.clear(); -} - -void pwmOutSet() { - String key = sCmd.order(); - String state = sCmd.next(); - String pin = jsonReadStr(configOptionJson, key + "_pin"); - myPwmOut.pwmChange(key, pin, state); -} \ No newline at end of file diff --git a/src/items/SensorAnalogClass.cpp b/src/items/SensorAnalogClass.cpp deleted file mode 100644 index 470d31c6..00000000 --- a/src/items/SensorAnalogClass.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "BufferExecute.h" -#include "items/SensorAnalogClass.h" -#ifdef ANALOG_ENABLED -//==============================================Модуль аналогового сенсора=========================================================================================== -//=================================================================================================================================================================== -SensorAnalogClass mySensorAnalog; -void analogAdc() { - mySensorAnalog.update(); - String key = mySensorAnalog.gkey(); - sCmd.addCommand(key.c_str(), analogReading); - sensorReadingMap10sec += key + ","; - mySensorAnalog.SensorAnalogInit(); - mySensorAnalog.clear(); -} - -void analogReading() { - String key = sCmd.order(); - String pin = jsonReadStr(configOptionJson, key + "_pin"); - mySensorAnalog.SensorAnalogRead(key, pin); -} -#endif \ No newline at end of file diff --git a/src/items/SensorBme280Class.cpp b/src/items/SensorBme280Class.cpp deleted file mode 100644 index 21a2f476..00000000 --- a/src/items/SensorBme280Class.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "items/SensorBme280Class.h" - -#include "BufferExecute.h" -//#ifdef SensorBme280Enabled -//=========================================Модуль ультрозвукового дальномера================================================================== -//bme280-temp;id;anydata;Сенсоры;Температура;order;c[1] -//bme280-hum;id;anydata;Сенсоры;Температура;order;c[1] -//bme280-press;id;anydata;Сенсоры;Температура;order;c[1] -//========================================================================================================================================= -SensorBme280Class mySensorBme280; - -void bme280Temp() { - mySensorBme280.update(); - String key = mySensorBme280.gkey(); - sCmd.addCommand(key.c_str(), bme280ReadingTemp); - mySensorBme280.SensorBme280Init(); - mySensorBme280.clear(); -} -void bme280ReadingTemp() { - String key = sCmd.order(); - mySensorBme280.SensorBme280ReadTmp(key); -} - -void bme280Hum() { - mySensorBme280.update(); - String key = mySensorBme280.gkey(); - sCmd.addCommand(key.c_str(), bme280ReadingHum); - mySensorBme280.SensorBme280Init(); - mySensorBme280.clear(); -} -void bme280ReadingHum() { - String key = sCmd.order(); - mySensorBme280.SensorBme280ReadHum(key); -} - -void bme280Press() { - mySensorBme280.update(); - String key = mySensorBme280.gkey(); - sCmd.addCommand(key.c_str(), bme280ReadingPress); - mySensorBme280.SensorBme280Init(); - mySensorBme280.clear(); -} -void bme280ReadingPress() { - String key = sCmd.order(); - mySensorBme280.SensorBme280ReadPress(key); -} -//#endif \ No newline at end of file diff --git a/src/items/SensorBmp280Class.cpp b/src/items/SensorBmp280Class.cpp deleted file mode 100644 index e6a2e7ed..00000000 --- a/src/items/SensorBmp280Class.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "items/SensorBmp280Class.h" - -#include "BufferExecute.h" -//#ifdef SensorBmp280Enabled -//=========================================Модуль ультрозвукового дальномера================================================================== -//bmp280-temp;id;anydata;Сенсоры;Температура;order;c[1] -//bmp280-hum;id;anydata;Сенсоры;Температура;order;c[1] -//bmp280-press;id;anydata;Сенсоры;Температура;order;c[1] -//========================================================================================================================================= -SensorBmp280Class mySensorBmp280; - -void bmp280Temp() { - mySensorBmp280.update(); - String key = mySensorBmp280.gkey(); - sCmd.addCommand(key.c_str(), bmp280ReadingTemp); - mySensorBmp280.SensorBmp280Init(); - mySensorBmp280.clear(); -} -void bmp280ReadingTemp() { - String key = sCmd.order(); - mySensorBmp280.SensorBmp280ReadTmp(key); -} - -void bmp280Press() { - mySensorBmp280.update(); - String key = mySensorBmp280.gkey(); - sCmd.addCommand(key.c_str(), bmp280ReadingPress); - mySensorBmp280.SensorBmp280Init(); - mySensorBmp280.clear(); -} -void bmp280ReadingPress() { - String key = sCmd.order(); - mySensorBmp280.SensorBmp280ReadPress(key); -} -//#endif \ No newline at end of file diff --git a/src/items/SensorDallas.cpp b/src/items/SensorDallas.cpp deleted file mode 100644 index 1abadc25..00000000 --- a/src/items/SensorDallas.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "items/SensorDallas.h" -#include "Class/LineParsing.h" -#include "Global.h" -#include "BufferExecute.h" -#include - -SensorDallas::SensorDallas(unsigned long interval, unsigned int pin, unsigned int index, String key) { - _interval = interval * 1000; - _key = key; - _pin = pin; - _index = index; - - oneWire = new OneWire((uint8_t)_pin); - sensors.setOneWire(oneWire); - sensors.begin(); - sensors.setResolution(12); -} - -SensorDallas::~SensorDallas() {} - -void SensorDallas::loop() { - currentMillis = millis(); - unsigned long difference = currentMillis - prevMillis; - if (difference >= _interval) { - prevMillis = millis(); - readDallas(); - } -} - -void SensorDallas::readDallas() { - sensors.requestTemperaturesByIndex(_index); - float value = sensors.getTempCByIndex(_index); - eventGen2(_key, String(value)); - jsonWriteStr(configLiveJson, _key, String(value)); - publishStatus(_key, String(value)); - SerialPrint("I", "Sensor", "'" + _key + "' data: " + String(value)); -} - -MySensorDallasVector* mySensorDallas2 = nullptr; - -void dallas() { - myLineParsing.update(); - String interval = myLineParsing.gint(); - String pin = myLineParsing.gpin(); - String index = myLineParsing.gindex(); - String key = myLineParsing.gkey(); - myLineParsing.clear(); - - static bool firstTime = true; - if (firstTime) mySensorDallas2 = new MySensorDallasVector(); - firstTime = false; - mySensorDallas2->push_back(SensorDallas(interval.toInt(), pin.toInt(), index.toInt(), key)); -} - diff --git a/src/items/SensorDhtClass.cpp b/src/items/SensorDhtClass.cpp deleted file mode 100644 index 035a4eb2..00000000 --- a/src/items/SensorDhtClass.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "items/SensorDhtClass.h" - -#include "BufferExecute.h" -//#ifdef SensorDhtEnabled -//=========================================DHT Sensor================================================================== -//dht-temp;id;anydata;Сенсоры;Температура;order;pin;type[dht11];c[1] -//dht-hum;id;anydata;Сенсоры;Влажность;order;pin;type[dht11];c[1] -//========================================================================================================================================= -SensorDhtClass mySensorDht; -void dhtTemp() { - mySensorDht.update(); - String key = mySensorDht.gkey(); - sCmd.addCommand(key.c_str(), dhtReadingTemp); - mySensorDht.SensorDhtInit(); - mySensorDht.clear(); -} -void dhtReadingTemp() { - String key = sCmd.order(); - mySensorDht.SensorDhtReadTemp(key); -} - - - -void dhtHum() { - mySensorDht.update(); - String key = mySensorDht.gkey(); - sCmd.addCommand(key.c_str(), dhtReadingHum); - mySensorDht.SensorDhtInit(); - mySensorDht.clear(); -} -void dhtReadingHum() { - String key = sCmd.order(); - mySensorDht.SensorDhtReadHum(key); -} -//#endif \ No newline at end of file diff --git a/src/items/SensorModbusClass.cpp b/src/items/SensorModbusClass.cpp deleted file mode 100644 index 368fe916..00000000 --- a/src/items/SensorModbusClass.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//#include "items/SensorModbusClass.h" -// -//#include "BufferExecute.h" -////#ifdef SensorModbusEnabled -////=========================================Модуль modbus=================================================================================== -////modbus;id;anydata;Сенсоры;Температура;order;addr[1];regaddr[0];c[1] -////========================================================================================================================================= -//SensorModbusClass mySensorModbus; -// -//void modbus() { -// mySensorModbus.update(); -// String key = mySensorModbus.gkey(); -// sCmd.addCommand(key.c_str(), modbusReading); -// mySensorModbus.SensorModbusInit(); -// mySensorModbus.clear(); -//} -//void modbusReading() { -// String key = sCmd.order(); -// String addr = sCmd.next(); -// String regaddr = sCmd.next(); -// mySensorModbus.SensorModbusRead(key, addr.toInt(), regaddr.toInt()); -//} -////#endif \ No newline at end of file diff --git a/src/items/SensorUltrasonicClass.cpp b/src/items/SensorUltrasonicClass.cpp deleted file mode 100644 index cd72a470..00000000 --- a/src/items/SensorUltrasonicClass.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "BufferExecute.h" -#include "items/SensorUltrasonicClass.h" -//#ifdef SensorUltrasonicEnabled -//=========================================Модуль ультрозвукового дальномера================================================================== -//ultrasonic-cm;id;anydata;Сенсоры;Расстояние;order;pin[12,13];map[1,100,1,100];c[1] -//========================================================================================================================================= -SensorUltrasonic mySensorUltrasonic; -void ultrasonicCm() { - mySensorUltrasonic.update(); - String key = mySensorUltrasonic.gkey(); - sCmd.addCommand(key.c_str(), ultrasonicReading); - mySensorUltrasonic.init(); - mySensorUltrasonic.clear(); -} - -void ultrasonicReading() { - String key = sCmd.order(); - mySensorUltrasonic.SensorUltrasonicRead(key); -} -//#endif \ No newline at end of file diff --git a/src/items/sysUptime.cpp b/src/items/sysUptime.cpp deleted file mode 100644 index 910bb871..00000000 --- a/src/items/sysUptime.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "Class/LineParsing.h" -#include "BufferExecute.h" -#include "Global.h" -#include - -void sysUptime() { - myLineParsing.update(); - String key = myLineParsing.gkey(); - sCmd.addCommand(key.c_str(), uptimeReading); - sensorReadingMap30sec += key + ","; - myLineParsing.clear(); -} - -void uptimeReading() { - String key = sCmd.order(); - String uptime = timeNow->getUptime(); - jsonWriteStr(configLiveJson, key, uptime); - publishStatus(key, uptime); - SerialPrint("I", "Sensor", "'" + key + "' data: " + uptime); -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 08c03929..00000000 --- a/src/main.cpp +++ /dev/null @@ -1,150 +0,0 @@ - -#include - -#include "BufferExecute.h" -#include "Bus.h" -#include "Class/CallBackTest.h" -#include "Class/NotAsync.h" -#include "Class/ScenarioClass3.h" -#include "Cmd.h" -#include "Global.h" -#include "Init.h" -#include "ItemsList.h" -#include "RemoteOrdersUdp.h" -#include "Utils/StatUtils.h" -#include "Utils/Timings.h" -#include "Utils/WebUtils.h" -#include "items/ButtonInClass.h" -#include "items/LoggingClass.h" -#include "items/ImpulsOutClass.h" -#include "items/SensorDallas.h" -#include "Telegram.h" - -void not_async_actions(); - -Timings metric; -boolean initialized = false; - -void setup() { - WiFi.setAutoConnect(false); - WiFi.persistent(false); - - Serial.begin(115200); - Serial.flush(); - Serial.println(); - Serial.println("--------------started----------------"); - - setChipId(); - - myNotAsyncActions = new NotAsync(do_LAST); - myScenario = new Scenario(); - - fileSystemInit(); - SerialPrint("I", "FS", "FS Init"); - - loadConfig(); - SerialPrint("I", "Conf", "Config Init"); - - clock_init(); - SerialPrint("I", "Time", "Clock Init"); - - handle_time_init(); - SerialPrint("I", "Time", "Handle time init("); - - sensorsInit(); - SerialPrint("I", "Sensors", "Sensors Init"); - - itemsListInit(); - SerialPrint("I", "Items", "Items Init"); - - all_init(); - SerialPrint("I", "Init", "Init Init"); - - routerConnect(); - SerialPrint("I", "WIFI", "Network Init"); - - telegramInit(); - SerialPrint("I", "Telegram", "Telegram Init"); - - uptime_init(); - SerialPrint("I", "Uptime", "Uptime Init"); - - upgradeInit(); - SerialPrint("I", "Update", "Updater Init"); - - HttpServer::init(); - SerialPrint("I", "HTTP", "HttpServer Init"); - - web_init(); - SerialPrint("I", "Web", "WebAdmin Init"); - - initSt(); - SerialPrint("I", "Stat", "Stat Init"); - -#ifdef UDP_ENABLED - SerialPrint("I", "UDP", "Udp Init"); - asyncUdpInit(); -#endif - - SerialPrint("I", "Bus", "Bus Init"); - busInit(); - -#ifdef SSDP_ENABLED - SerialPrint("I", "SSDP", "Ssdp Init"); - SsdpInit(); -#endif - - - - //esp_log_level_set("esp_littlefs", ESP_LOG_NONE); - - ts.add( - TEST, 1000 * 60, [&](void*) { - SerialPrint("I", "System", printMemoryStatus()); - }, - nullptr, true); - - just_load = false; - initialized = true; -} - -void loop() { - if (!initialized) { - return; - } -#ifdef OTA_UPDATES_ENABLED - ArduinoOTA.handle(); -#endif -#ifdef WS_enable - ws.cleanupClients(); -#endif - timeNow->loop(); - mqttLoop(); - myButtonIn.loop(); - myScenario->loop(); - loopCmdExecute(); - //loopSerial(); - - myNotAsyncActions->loop(); - ts.update(); - - handleTelegram(); - - if (myLogging != nullptr) { - for (unsigned int i = 0; i < myLogging->size(); i++) { - myLogging->at(i).loop(); - } - } - - if (myImpulsOut != nullptr) { - for (unsigned int i = 0; i < myImpulsOut->size(); i++) { - myImpulsOut->at(i).loop(); - } - } - - if (mySensorDallas2 != nullptr) { - for (unsigned int i = 0; i < mySensorDallas2->size(); i++) { - mySensorDallas2->at(i).loop(); - } - } -} \ No newline at end of file diff --git a/tools/gzip-firmware.py b/tools/gzip-firmware.py deleted file mode 100644 index 7df522e7..00000000 --- a/tools/gzip-firmware.py +++ /dev/null @@ -1,28 +0,0 @@ -Import('env') -import os -import shutil -import gzip - -OUTPUT_DIR = "build_output{}".format(os.path.sep) - -def bin_gzip(source, target, env): - variant = str(target[0]).split(os.path.sep)[2] - - # create string with location and file names based on variant - bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant) - gzip_file = "{}firmware{}{}.bin.gz".format(OUTPUT_DIR, os.path.sep, variant) - - # check if new target files exist and remove if necessary - if os.path.isfile(gzip_file): os.remove(gzip_file) - - # write gzip firmware file - with open(bin_file,"rb") as fp: - with gzip.open(gzip_file, "wb", compresslevel = 9) as f: - shutil.copyfileobj(fp, f) - - ORG_FIRMWARE_SIZE = os.stat(bin_file).st_size - GZ_FIRMWARE_SIZE = os.stat(gzip_file).st_size - - print("Compressed to {:.0f}% ({} bytes)".format((GZ_FIRMWARE_SIZE / ORG_FIRMWARE_SIZE) * 100, ORG_FIRMWARE_SIZE, GZ_FIRMWARE_SIZE)) - -env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_gzip]) \ No newline at end of file diff --git a/tools/littlefsbuilder.py b/tools/littlefsbuilder.py deleted file mode 100644 index df1fb52d..00000000 --- a/tools/littlefsbuilder.py +++ /dev/null @@ -1,2 +0,0 @@ -Import("env") -env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/tools/mklittlefs.exe' ) diff --git a/tools/mklittlefs.exe b/tools/mklittlefs.exe deleted file mode 100644 index 7de93ff2..00000000 Binary files a/tools/mklittlefs.exe and /dev/null differ diff --git a/tools/name-firmware.py b/tools/name-firmware.py deleted file mode 100644 index a82b5579..00000000 --- a/tools/name-firmware.py +++ /dev/null @@ -1,34 +0,0 @@ -Import('env') -import os -import shutil - -OUTPUT_DIR = "build_output{}".format(os.path.sep) - -def bin_map_copy(source, target, env): - variant = str(target[0]).split(os.path.sep)[2] - - # check if output directories exist and create if necessary - if not os.path.isdir(OUTPUT_DIR): - os.mkdir(OUTPUT_DIR) - - for d in ['firmware', 'map']: - if not os.path.isdir("{}{}".format(OUTPUT_DIR, d)): - os.mkdir("{}{}".format(OUTPUT_DIR, d)) - - # create string with location and file names based on variant - map_file = "{}map{}{}.map".format(OUTPUT_DIR, os.path.sep, variant) - bin_file = "{}firmware{}{}.bin".format(OUTPUT_DIR, os.path.sep, variant) - - # check if new target files exist and remove if necessary - for f in [map_file, bin_file]: - if os.path.isfile(f): - os.remove(f) - - # copy firmware.bin to firmware/.bin - shutil.copy(str(target[0]), bin_file) - - # copy firmware.map to map/.map - if os.path.isfile("firmware.map"): - shutil.move("firmware.map", map_file) - -env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", [bin_map_copy]) \ No newline at end of file