From e13f6e5274f13e74df9b510c82f585b9ed064800 Mon Sep 17 00:00:00 2001 From: Maik Hofmann Date: Wed, 24 Feb 2021 19:08:31 +0100 Subject: [PATCH] =?UTF-8?q?Neue=20Version=20via=20Interrupt=20und=20f?= =?UTF-8?q?=C3=BCr=20ESP32=20zur=20Vermeidung=20von=20Timing-Problemen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HCPBridgeISR für ESP8266 HCPBridgeESP32 für ESP32 HCPBridge nicht mehr nutzen! --- HCPBridge/extra_script.py | 3 - .../ESPAsyncTCP-esphome/src/SyncClient.cpp | 423 --------------- HCPBridge/platformio.ini | 1 - HCPBridge/src/main.cpp | 7 +- HCPBridgeESP32/.gitignore | 5 + HCPBridgeESP32/.vscode/extensions.json | 7 + HCPBridgeESP32/.vscode/settings.json | 12 + HCPBridgeESP32/include/README | 39 ++ HCPBridgeESP32/lib/README | 46 ++ HCPBridgeESP32/platformio.ini | 18 + HCPBridgeESP32/src/hciemulator.cpp | 425 +++++++++++++++ HCPBridgeESP32/src/hciemulator.h | 131 +++++ HCPBridgeESP32/src/index_html.h | 1 + HCPBridgeESP32/src/main.cpp | 200 +++++++ HCPBridgeESP32/src/webpage/buildindex.cmd | 1 + HCPBridgeESP32/src/webpage/command | 0 HCPBridgeESP32/src/webpage/compress.py | 35 ++ HCPBridgeESP32/src/webpage/index.html | 159 ++++++ HCPBridgeESP32/src/webpage/runtestserver.cmd | 1 + HCPBridgeESP32/src/webpage/status | 9 + HCPBridgeESP32/test/README | 11 + HCPBridgeISR/.gitignore | 5 + HCPBridgeISR/.vscode/extensions.json | 7 + HCPBridgeISR/.vscode/settings.json | 13 + HCPBridgeISR/include/README | 39 ++ HCPBridgeISR/lib/README | 46 ++ HCPBridgeISR/platformio.ini | 17 + HCPBridgeISR/simulator/hcisim.py | 18 + HCPBridgeISR/src/LICENSE | 21 + HCPBridgeISR/src/README.md | 10 + HCPBridgeISR/src/crc.c | 44 ++ HCPBridgeISR/src/crc.h | 22 + HCPBridgeISR/src/hciemulator.c | 511 ++++++++++++++++++ HCPBridgeISR/src/hciemulator.h | 113 ++++ HCPBridgeISR/src/index_html.h | 1 + HCPBridgeISR/src/main.cpp | 169 ++++++ HCPBridgeISR/src/uart_register.h | 128 +++++ HCPBridgeISR/src/webpage/buildindex.cmd | 1 + HCPBridgeISR/src/webpage/command | 0 HCPBridgeISR/src/webpage/compress.py | 35 ++ HCPBridgeISR/src/webpage/index.html | 159 ++++++ HCPBridgeISR/src/webpage/runtestserver.cmd | 1 + HCPBridgeISR/src/webpage/status | 9 + HCPBridgeISR/test/README | 11 + README.md | 2 +- 45 files changed, 2486 insertions(+), 430 deletions(-) delete mode 100644 HCPBridge/extra_script.py delete mode 100644 HCPBridge/patch/.pio/libdeps/esp12e/ESPAsyncTCP-esphome/src/SyncClient.cpp create mode 100644 HCPBridgeESP32/.gitignore create mode 100644 HCPBridgeESP32/.vscode/extensions.json create mode 100644 HCPBridgeESP32/.vscode/settings.json create mode 100644 HCPBridgeESP32/include/README create mode 100644 HCPBridgeESP32/lib/README create mode 100644 HCPBridgeESP32/platformio.ini create mode 100644 HCPBridgeESP32/src/hciemulator.cpp create mode 100644 HCPBridgeESP32/src/hciemulator.h create mode 100644 HCPBridgeESP32/src/index_html.h create mode 100644 HCPBridgeESP32/src/main.cpp create mode 100644 HCPBridgeESP32/src/webpage/buildindex.cmd create mode 100644 HCPBridgeESP32/src/webpage/command create mode 100644 HCPBridgeESP32/src/webpage/compress.py create mode 100644 HCPBridgeESP32/src/webpage/index.html create mode 100644 HCPBridgeESP32/src/webpage/runtestserver.cmd create mode 100644 HCPBridgeESP32/src/webpage/status create mode 100644 HCPBridgeESP32/test/README create mode 100644 HCPBridgeISR/.gitignore create mode 100644 HCPBridgeISR/.vscode/extensions.json create mode 100644 HCPBridgeISR/.vscode/settings.json create mode 100644 HCPBridgeISR/include/README create mode 100644 HCPBridgeISR/lib/README create mode 100644 HCPBridgeISR/platformio.ini create mode 100644 HCPBridgeISR/simulator/hcisim.py create mode 100644 HCPBridgeISR/src/LICENSE create mode 100644 HCPBridgeISR/src/README.md create mode 100644 HCPBridgeISR/src/crc.c create mode 100644 HCPBridgeISR/src/crc.h create mode 100644 HCPBridgeISR/src/hciemulator.c create mode 100644 HCPBridgeISR/src/hciemulator.h create mode 100644 HCPBridgeISR/src/index_html.h create mode 100644 HCPBridgeISR/src/main.cpp create mode 100644 HCPBridgeISR/src/uart_register.h create mode 100644 HCPBridgeISR/src/webpage/buildindex.cmd create mode 100644 HCPBridgeISR/src/webpage/command create mode 100644 HCPBridgeISR/src/webpage/compress.py create mode 100644 HCPBridgeISR/src/webpage/index.html create mode 100644 HCPBridgeISR/src/webpage/runtestserver.cmd create mode 100644 HCPBridgeISR/src/webpage/status create mode 100644 HCPBridgeISR/test/README diff --git a/HCPBridge/extra_script.py b/HCPBridge/extra_script.py deleted file mode 100644 index eda61ce..0000000 --- a/HCPBridge/extra_script.py +++ /dev/null @@ -1,3 +0,0 @@ -from distutils import dir_util -Import("env") -dir_util.copy_tree("patch",".") diff --git a/HCPBridge/patch/.pio/libdeps/esp12e/ESPAsyncTCP-esphome/src/SyncClient.cpp b/HCPBridge/patch/.pio/libdeps/esp12e/ESPAsyncTCP-esphome/src/SyncClient.cpp deleted file mode 100644 index 8010a7a..0000000 --- a/HCPBridge/patch/.pio/libdeps/esp12e/ESPAsyncTCP-esphome/src/SyncClient.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* - Asynchronous TCP 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 "SyncClient.h" -#include "ESPAsyncTCP.h" -#include "cbuf.h" -#include - -#define DEBUG_ESP_SYNC_CLIENT -#if defined(DEBUG_ESP_SYNC_CLIENT) && !defined(SYNC_CLIENT_DEBUG) -#define SYNC_CLIENT_DEBUG( format, ...) DEBUG_GENERIC_P("[SYNC_CLIENT]", format, ##__VA_ARGS__) -#endif -#ifndef SYNC_CLIENT_DEBUG -#define SYNC_CLIENT_DEBUG(...) do { (void)0;} while(false) -#endif - -/* - Without LWIP_NETIF_TX_SINGLE_PBUF, all tcp_writes default to "no copy". - Referenced data must be preserved and free-ed from the specified tcp_sent() - callback. Alternative, tcp_writes need to use the TCP_WRITE_FLAG_COPY - attribute. -*/ -static_assert(LWIP_NETIF_TX_SINGLE_PBUF, "Required, tcp_write() must always copy."); - - -void DelayHandler(void); -void customDelay(long ms){ - unsigned long startTime = millis(); - do{ - DelayHandler(); - }while(startTime+ms>millis()); -} - -SyncClient::SyncClient(size_t txBufLen) - : _client(NULL) - , _tx_buffer(NULL) - , _tx_buffer_size(txBufLen) - , _rx_buffer(NULL) - , _ref(NULL) -{ - ref(); -} - -SyncClient::SyncClient(AsyncClient *client, size_t txBufLen) - : _client(client) - , _tx_buffer(new (std::nothrow) cbuf(txBufLen)) - , _tx_buffer_size(txBufLen) - , _rx_buffer(NULL) - , _ref(NULL) -{ - if(ref() > 0 && _client != NULL) - _attachCallbacks(); -} - -SyncClient::~SyncClient(){ - if (0 == unref()) - _release(); -} - -void SyncClient::_release(){ - if(_client != NULL){ - _client->onData(NULL, NULL); - _client->onAck(NULL, NULL); - _client->onPoll(NULL, NULL); - _client->abort(); - _client = NULL; - } - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - while(_rx_buffer != NULL){ - cbuf *b = _rx_buffer; - _rx_buffer = _rx_buffer->next; - delete b; - } -} - -int SyncClient::ref(){ - if(_ref == NULL){ - _ref = new (std::nothrow) int; - if(_ref != NULL) - *_ref = 0; - else - return -1; - } - return (++*_ref); -} - -int SyncClient::unref(){ - int count = -1; - if (_ref != NULL) { - count = --*_ref; - if (0 == count) { - delete _ref; - _ref = NULL; - } - } - return count; -} - -#if ASYNC_TCP_SSL_ENABLED -int SyncClient::_connect(const IPAddress& ip, uint16_t port, bool secure){ -#else -int SyncClient::_connect(const IPAddress& ip, uint16_t port){ -#endif - if(connected()) - return 0; - if(_client != NULL) - delete _client; - - _client = new (std::nothrow) AsyncClient(); - if (_client == NULL) - return 0; - - _client->onConnect([](void *obj, AsyncClient *c){ ((SyncClient*)(obj))->_onConnect(c); }, this); - _attachCallbacks_Disconnect(); -#if ASYNC_TCP_SSL_ENABLED - if(_client->connect(ip, port, secure)){ -#else - if(_client->connect(ip, port)){ -#endif - while(_client != NULL && !_client->connected() && !_client->disconnecting()) - customDelay(1); - return connected(); - } - return 0; -} - -#if ASYNC_TCP_SSL_ENABLED -int SyncClient::connect(const char *host, uint16_t port, bool secure){ -#else -int SyncClient::connect(const char *host, uint16_t port){ -#endif - if(connected()) - return 0; - if(_client != NULL) - delete _client; - - _client = new (std::nothrow) AsyncClient(); - if (_client == NULL) - return 0; - - _client->onConnect([](void *obj, AsyncClient *c){ ((SyncClient*)(obj))->_onConnect(c); }, this); - _attachCallbacks_Disconnect(); -#if ASYNC_TCP_SSL_ENABLED - if(_client->connect(host, port, secure)){ -#else - if(_client->connect(host, port)){ -#endif - while(_client != NULL && !_client->connected() && !_client->disconnecting()) - customDelay(1); - return connected(); - } - return 0; -} -//#define SYNCCLIENT_NEW_OPERATOR_EQUAL -#ifdef SYNCCLIENT_NEW_OPERATOR_EQUAL -/* - New behavior for operator= - - Allow for the object to be placed on a queue and transfered to a new container - with buffers still in tact. Avoiding receive data drops. Transfers rx and tx - buffers. Supports return by value. - - Note, this is optional, the old behavior is the default. - -*/ -SyncClient & SyncClient::operator=(const SyncClient &other){ - int *rhsref = other._ref; - ++*rhsref; // Just in case the left and right side are the same object with different containers - if (0 == unref()) - _release(); - _ref = other._ref; - ref(); - --*rhsref; - // Why do I not test _tx_buffer for != NULL and free? - // I allow for the lh target container, to be a copy of an active - // connection. Thus we are just reusing the container. - // The above unref() handles releaseing the previous client of the container. - _tx_buffer_size = other._tx_buffer_size; - _tx_buffer = other._tx_buffer; - _client = other._client; - if (_client != NULL && _tx_buffer == NULL) - _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); - - _rx_buffer = other._rx_buffer; - if(_client) - _attachCallbacks(); - return *this; -} -#else // ! SYNCCLIENT_NEW_OPERATOR_EQUAL -// This is the origianl logic with null checks -SyncClient & SyncClient::operator=(const SyncClient &other){ - if(_client != NULL){ - _client->abort(); - _client->free(); - _client = NULL; - } - _tx_buffer_size = other._tx_buffer_size; - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - while(_rx_buffer != NULL){ - cbuf *b = _rx_buffer; - _rx_buffer = b->next; - delete b; - } - if(other._client != NULL) - _tx_buffer = new (std::nothrow) cbuf(other._tx_buffer_size); - - _client = other._client; - if(_client) - _attachCallbacks(); - - return *this; -} -#endif - -void SyncClient::setTimeout(uint32_t seconds){ - if(_client != NULL) - _client->setRxTimeout(seconds); -} - -uint8_t SyncClient::status(){ - if(_client == NULL) - return 0; - return _client->state(); -} - -uint8_t SyncClient::connected(){ - return (_client != NULL && _client->connected()); -} - -bool SyncClient::stop(unsigned int maxWaitMs){ - (void)maxWaitMs; - if(_client != NULL) - _client->close(true); - return true; -} - -size_t SyncClient::_sendBuffer(){ - if(_client == NULL || _tx_buffer == NULL) - return 0; - size_t available = _tx_buffer->available(); - if(!connected() || !_client->canSend() || available == 0) - return 0; - size_t sendable = _client->space(); - if(sendable < available) - available= sendable; - char *out = new (std::nothrow) char[available]; - if(out == NULL) - return 0; - - _tx_buffer->read(out, available); - size_t sent = _client->write(out, available); - delete[] out; - return sent; -} - -void SyncClient::_onData(void *data, size_t len){ - _client->ackLater(); - cbuf *b = new (std::nothrow) cbuf(len+1); - if(b != NULL){ - b->write((const char *)data, len); - if(_rx_buffer == NULL) - _rx_buffer = b; - else { - cbuf *p = _rx_buffer; - while(p->next != NULL) - p = p->next; - p->next = b; - } - } else { - // We ran out of memory. This fail causes lost receive data. - // The connection should be closed in a manner that conveys something - // bad/abnormal has happened to the connection. Hence, we abort the - // connection to avoid possible data corruption. - // Note, callbacks maybe called. - _client->abort(); - } -} - -void SyncClient::_onDisconnect(){ - if(_client != NULL){ - _client = NULL; - } - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } -} - -void SyncClient::_onConnect(AsyncClient *c){ - _client = c; - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); - _attachCallbacks_AfterConnected(); -} - -void SyncClient::_attachCallbacks(){ - _attachCallbacks_Disconnect(); - _attachCallbacks_AfterConnected(); -} - -void SyncClient::_attachCallbacks_AfterConnected(){ - _client->onAck([](void *obj, AsyncClient* c, size_t len, uint32_t time){ (void)c; (void)len; (void)time; ((SyncClient*)(obj))->_sendBuffer(); }, this); - _client->onData([](void *obj, AsyncClient* c, void *data, size_t len){ (void)c; ((SyncClient*)(obj))->_onData(data, len); }, this); - _client->onTimeout([](void *obj, AsyncClient* c, uint32_t time){ (void)obj; (void)time; c->close(); }, this); -} - -void SyncClient::_attachCallbacks_Disconnect(){ - _client->onDisconnect([](void *obj, AsyncClient* c){ ((SyncClient*)(obj))->_onDisconnect(); delete c; }, this); -} - -size_t SyncClient::write(uint8_t data){ - return write(&data, 1); -} - -size_t SyncClient::write(const uint8_t *data, size_t len){ - if(_tx_buffer == NULL || !connected()){ - return 0; - } - size_t toWrite = 0; - size_t toSend = len; - while(_tx_buffer->room() < toSend){ - toWrite = _tx_buffer->room(); - _tx_buffer->write((const char*)data, toWrite); - while(connected() && !_client->canSend()) - customDelay(0); - if(!connected()) - return 0; - _sendBuffer(); - toSend -= toWrite; - } - _tx_buffer->write((const char*)(data+(len - toSend)), toSend); - if(connected() && _client->canSend()) - _sendBuffer(); - return len; -} - -int SyncClient::available(){ - if(_rx_buffer == NULL) return 0; - size_t a = 0; - cbuf *b = _rx_buffer; - while(b != NULL){ - a += b->available(); - b = b->next; - } - return a; -} - -int SyncClient::peek(){ - if(_rx_buffer == NULL) return -1; - return _rx_buffer->peek(); -} - -int SyncClient::read(uint8_t *data, size_t len){ - if(_rx_buffer == NULL) return -1; - - size_t readSoFar = 0; - while(_rx_buffer != NULL && (len - readSoFar) >= _rx_buffer->available()){ - cbuf *b = _rx_buffer; - _rx_buffer = _rx_buffer->next; - size_t toRead = b->available(); - readSoFar += b->read((char*)(data+readSoFar), toRead); - if(connected()){ - _client->ack(b->size() - 1); - } - delete b; - } - if(_rx_buffer != NULL && readSoFar < len){ - readSoFar += _rx_buffer->read((char*)(data+readSoFar), (len - readSoFar)); - } - return readSoFar; -} - -int SyncClient::read(){ - uint8_t res = 0; - if(read(&res, 1) != 1) - return -1; - return res; -} - -bool SyncClient::flush(unsigned int maxWaitMs){ - (void)maxWaitMs; - if(_tx_buffer == NULL || !connected()) - return false; - if(_tx_buffer->available()){ - while(connected() && !_client->canSend()) - customDelay(0); - if(_client == NULL || _tx_buffer == NULL) - return false; - _sendBuffer(); - } - return true; -} diff --git a/HCPBridge/platformio.ini b/HCPBridge/platformio.ini index b04a0a5..e4d26de 100644 --- a/HCPBridge/platformio.ini +++ b/HCPBridge/platformio.ini @@ -15,4 +15,3 @@ framework = arduino lib_deps = ottowinter/ESPAsyncWebServer-esphome@^1.2.7 bblanchon/ArduinoJson@^6.17.2 -extra_scripts = pre:extra_script.py diff --git a/HCPBridge/src/main.cpp b/HCPBridge/src/main.cpp index fcfc4ba..0bf13b6 100644 --- a/HCPBridge/src/main.cpp +++ b/HCPBridge/src/main.cpp @@ -5,6 +5,10 @@ #include "hciemulator.h" #include "index_html.h" +!!! DONT USE THIS, BECAUSE OF TIMING PROBLEMS !!! +!!! USE THE ISR VERSION OR SWITCH TO ESP32 !!! + + /* create this file and add your wlan credentials const char* ssid = "MyWLANSID"; const char* password = "MYPASSWORD"; @@ -61,8 +65,6 @@ void switchLamp(bool on){ } } - - // setup mcu void setup(){ @@ -71,6 +73,7 @@ void setup(){ #ifdef SWAPUART RS485.swap(); #endif + //setup wifi WiFi.mode(WIFI_STA); diff --git a/HCPBridgeESP32/.gitignore b/HCPBridgeESP32/.gitignore new file mode 100644 index 0000000..d3e0c0c --- /dev/null +++ b/HCPBridgeESP32/.gitignore @@ -0,0 +1,5 @@ +/.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/HCPBridgeESP32/.vscode/extensions.json b/HCPBridgeESP32/.vscode/extensions.json new file mode 100644 index 0000000..e80666b --- /dev/null +++ b/HCPBridgeESP32/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} diff --git a/HCPBridgeESP32/.vscode/settings.json b/HCPBridgeESP32/.vscode/settings.json new file mode 100644 index 0000000..d67a7f8 --- /dev/null +++ b/HCPBridgeESP32/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "files.associations": { + "array": "cpp", + "deque": "cpp", + "list": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "initializer_list": "cpp", + "regex": "cpp" + } +} \ No newline at end of file diff --git a/HCPBridgeESP32/include/README b/HCPBridgeESP32/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/HCPBridgeESP32/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/HCPBridgeESP32/lib/README b/HCPBridgeESP32/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/HCPBridgeESP32/lib/README @@ -0,0 +1,46 @@ + +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/HCPBridgeESP32/platformio.ini b/HCPBridgeESP32/platformio.ini new file mode 100644 index 0000000..7d0e363 --- /dev/null +++ b/HCPBridgeESP32/platformio.ini @@ -0,0 +1,18 @@ +; 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 + +[env:esp12e] +platform = espressif32 +board = nodemcu-32s +framework = arduino +lib_deps = + ottowinter/ESPAsyncWebServer-esphome@^1.2.7 + bblanchon/ArduinoJson@^6.17.2 + plerup/EspSoftwareSerial@^6.11.6 diff --git a/HCPBridgeESP32/src/hciemulator.cpp b/HCPBridgeESP32/src/hciemulator.cpp new file mode 100644 index 0000000..eb015d9 --- /dev/null +++ b/HCPBridgeESP32/src/hciemulator.cpp @@ -0,0 +1,425 @@ +#include "hciemulator.h" +#define CHECKCHANGEDSET(Target,Value,Flag) if((Target)!=(Value)){Target=Value;Flag=true;} +int hciloglevel = DEFAULTLOGLEVEL; + +#ifdef SOFTSERIAL +#define Log(Level,Message) LogCore(Level,Message) +#define Log3(Level,Message,Buffer, Len) LogCore(Level,Message,Buffer,Len) +//LOGLEVEL +void LogCore(int Level, const char* msg, const unsigned char * data=NULL, size_t datalen=0){ + if(Level>hciloglevel){ + return; + } + if(data!=NULL && datalen>0){ + String newmsg(msg); + char str[4]; + for (size_t i = 0; i < datalen; i++){ + snprintf(str,sizeof(str),"%02x ", data[i]); + newmsg+=str; + } + Serial.println(newmsg); + }else{ + Serial.println(msg); + } +} +#else + #define Log(Level,Message) + #define Log3(Level,Message,Buffer, Len) +#endif + + +int HCIEmulator::getLogLevel(){ + return hciloglevel; + +} +void HCIEmulator::setLogLevel(int level){ + hciloglevel=level; +} + +//modbus crc calculation borrowed from: +//https://github.com/yaacov/ArduinoModbusSlave +#define MODBUS_CRC_LENGTH 2 +#define readCRC(arr, length) word(arr[(length - MODBUS_CRC_LENGTH) + 1], arr[length - MODBUS_CRC_LENGTH]) +#define readUInt16(arr, index) word(arr[index], arr[index + 1]) +/** + * Calculate the CRC of the passed byte array from zero up to the passed length. + * + * @param buffer The byte array containing the data. + * @param length The length of the byte array. + * + * @return The calculated CRC as an unsigned 16 bit integer. + * + * Calculate and add the CRC. + * uint16_t crc = Modbus::calculateCRC(_responseBuffer, _responseBufferLength - MODBUS_CRC_LENGTH); + * _responseBuffer[_responseBufferLength - MODBUS_CRC_LENGTH] = crc & 0xFF; + * _responseBuffer[(_responseBufferLength - MODBUS_CRC_LENGTH) + 1] = crc >> 8; + * + * + * #define MODBUS_FRAME_SIZE 4 + * #define MODBUS_CRC_LENGTH 2 + * uint16_t crc = readCRC(_requestBuffer, _requestBufferLength); + * #define readUInt16(arr, index) word(arr[index], arr[index + 1]) + * #define readCRC(arr, length) word(arr[(length - MODBUS_CRC_LENGTH) + 1], arr[length - MODBUS_CRC_LENGTH]) + */ +uint16_t calculateCRC(uint8_t *buffer, int length) +{ + int i, j; + uint16_t crc = 0xFFFF; + uint16_t tmp; + + // Calculate the CRC. + for (i = 0; i < length; i++) + { + crc = crc ^ buffer[i]; + for (j = 0; j < 8; j++) + { + tmp = crc & 0x0001; + crc = crc >> 1; + if (tmp) + { + crc = crc ^ 0xA001; + } + } + } + return crc; +} + +HCIEmulator::HCIEmulator(Stream * port) { + m_state.valid = false; + m_statemachine=WAITING; + m_rxlen = m_txlen = 0; + m_recvTime=m_lastStateTime=0; + m_skipFrame=false; + m_port = port; + m_statusCallback = NULL; + setLogLevel(DEFAULTLOGLEVEL); +}; + +void HCIEmulator::poll(){ + + if(m_port==NULL) return; + + // receive Data + if(m_port->available() >0) + { + m_rxlen+= m_port->readBytes((char*)(m_rxbuffer+m_rxlen), _min((int)(255-m_rxlen),m_port->available())); + if(m_rxlen > 254) + { + Log(LL_ERROR,"RX Bufferoverflow, skip next Frame"); + Log3(LL_DEBUG,"Buffer Data: ", m_rxbuffer, m_rxlen); + m_rxlen=0; + m_skipFrame = true; + } + m_recvTime = micros(); + } + + + // check frame, process frame + if(m_rxlen>0 && (micros()-m_recvTime > T3_5)) + { + // check last action timeout -> reset > then 2sec + if(m_statemachine!= WAITING && m_lastStateTime+2000 0){ + + // fix crc + uint16_t crc = calculateCRC(m_txbuffer, m_txlen - MODBUS_CRC_LENGTH); + m_txbuffer[m_txlen - MODBUS_CRC_LENGTH] = crc & 0xFF; + m_txbuffer[(m_txlen - MODBUS_CRC_LENGTH) + 1] = crc >> 8; + + // send data + m_lastSendTime = micros()-m_recvTime; + + //Log(LL_DEBUG, ("ST:"+String(m_lastSendTime)).c_str()); + + m_port->write(m_txbuffer, m_txlen); + Log3(LL_DEBUG,"Response: ", m_txbuffer, m_txlen); + m_txlen = 0; + } + } + + m_skipFrame = false; + m_rxlen=0; + } +} + +void HCIEmulator::processFrame(){ + m_txlen = 0; // clear send buffer + + if(m_rxlen<5) { + Log(LL_ERROR,"Frame skipped, invalid frame len"); + Log3(LL_ERROR,"Data:", m_rxbuffer,m_rxlen); + return; + } + + // check device id, pass only device id 2 and 0 (broadcast) + if(m_rxbuffer[0] != BROADCASTID && m_rxbuffer[0] != DEVICEID){ + Log(LL_DEBUG,"Frame skipped, unsupported device id"); + Log3(LL_DEBUG,"Data:", m_rxbuffer,m_rxlen); + return; + } + + // check crc + uint16_t crc = readCRC(m_rxbuffer, m_rxlen); + if(crc != calculateCRC(m_rxbuffer,m_rxlen-MODBUS_CRC_LENGTH)){ + Log3(LL_ERROR,"Frame skipped, wrong crc", m_rxbuffer,m_rxlen); + return; + } + + Log3(LL_DEBUG,"Incomming Data: ", m_rxbuffer, m_rxlen); + + // dispatch modbus function + switch(m_rxbuffer[1]){ + case 0x10:{ // Write Multiple registers + if(m_rxlen == 0x1b && m_rxbuffer[0] == BROADCASTID) + { + processBroadcastStatusFrame(); + return; + } + break; + } + + case 0x17:{ // Read/Write Multiple registers + if(m_rxbuffer[0] == DEVICEID){ + switch(m_rxlen){ + case 0x11:{ + processDeviceStatusFrame(); + return; + } + + case 0x13: + processDeviceBusScanFrame(); + return;; + } + } + break; + } + } + Log3(LL_ERROR,"Frame skipped, unexpected data: ", m_rxbuffer, m_rxlen); +} + +const unsigned char ResponseTemplate_Fcn17_Cmd03_L08 []= {0x02,0x17,0x10,0x3E,0x00,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x1B}; +const unsigned char ResponseTemplate_Fcn17_Cmd04_L02 []= {0x02,0x17,0x04,0x0F,0x00,0x04,0xFD,0x0A,0x72}; +void HCIEmulator::processDeviceStatusFrame(){ + if(m_rxlen==0x11){ + unsigned char counter = m_rxbuffer[11]; + unsigned char cmd = m_rxbuffer[12]; + if(m_rxbuffer[5] == 0x08){ + // expose internal state + // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 + //0011: 02 17 9C B9 00 08 9C 41 00 02 04 3E 03 00 00 EB CC + //res=> 02 17 10 3E 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 74 1B + memcpy_P(m_txbuffer, ResponseTemplate_Fcn17_Cmd03_L08, sizeof(ResponseTemplate_Fcn17_Cmd03_L08)); + m_txbuffer[0] = m_rxbuffer[0]; + m_txbuffer[3] = counter; + m_txbuffer[5] = cmd; + m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd03_L08); + + + switch(m_statemachine) + { + // open Door + case STARTOPENDOOR: + m_txbuffer[7]= 0x02; + m_txbuffer[8]= 0x10; + m_statemachine = STARTOPENDOOR_RELEASE; + m_lastStateTime = millis(); + break; + case STARTOPENDOOR_RELEASE: + if(m_lastStateTime+SIMULATEKEYPRESSDELAYMS 02 17 04 0F 00 04 FD 0A 72 + memcpy_P(m_txbuffer, ResponseTemplate_Fcn17_Cmd04_L02, sizeof(ResponseTemplate_Fcn17_Cmd04_L02)); + m_txbuffer[0] = m_rxbuffer[0]; + m_txbuffer[3] = counter; + m_txbuffer[5] = cmd; + m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd04_L02); + return; + } + } + + Log3(LL_ERROR,"Frame skipped, unexpected data: ", m_rxbuffer, m_rxlen); +} + +const unsigned char ResponseTemplate_Fcn17_Cmd02_L05 []= {0x02,0x17,0x0a,0x00,0x00,0x02,0x05,0x04,0x30,0x10,0xff,0xa8,0x45,0x0e,0xdf}; +void HCIEmulator::processDeviceBusScanFrame(){ + // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 + //0013: 02 17 9C B9 00 05 9C 41 00 03 06 00 02 00 00 01 02 f8 35 + //res=> 02 17 0a 00 00 02 05 04 30 10 ff a8 45 0e df + unsigned char counter = m_rxbuffer[11]; + unsigned char cmd = m_rxbuffer[12]; + memcpy_P(m_txbuffer, ResponseTemplate_Fcn17_Cmd02_L05, sizeof(ResponseTemplate_Fcn17_Cmd02_L05)); + m_txbuffer[0] = m_rxbuffer[0]; + m_txbuffer[3] = counter; + m_txbuffer[5] = cmd; + m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd02_L05); + + Log(LL_INFO,"Busscan received"); +} + +void HCIEmulator::processBroadcastStatusFrame(){ + //001B: 00 10 9D 31 00 09 12 64 00 00 00 40 60 00 00 00 00 00 00 00 00 00 01 00 00 CA 22 + bool hasChanged = false; + CHECKCHANGEDSET(m_state.lampOn,m_rxbuffer[20] == 0x14,hasChanged); + CHECKCHANGEDSET(m_state.doorCurrentPosition,m_rxbuffer[10],hasChanged); + CHECKCHANGEDSET(m_state.doorTargetPosition, m_rxbuffer[9],hasChanged); + CHECKCHANGEDSET(m_state.doorState, m_rxbuffer[11],hasChanged); + CHECKCHANGEDSET(m_state.reserved, m_rxbuffer[17],hasChanged); + CHECKCHANGEDSET(m_state.valid, true,hasChanged); + + if(hasChanged){ + Log3(LL_INFO,"New State: ",m_rxbuffer,m_rxlen); + if(m_statusCallback != NULL){ + m_statusCallback(m_state); + } + } +} + +void HCIEmulator::openDoor(){ + if(m_statemachine != WAITING){ + return; + } + m_lastStateTime = millis(); + m_statemachine = STARTOPENDOOR; +} + +void HCIEmulator::openDoorHalf(){ + if(m_statemachine != WAITING){ + return; + } + m_lastStateTime = millis(); + m_statemachine = STARTOPENDOORHALF; +} + +void HCIEmulator::closeDoor(){ + if(m_statemachine != WAITING){ + return; + } + m_lastStateTime = millis(); + m_statemachine = STARTCLOSEDOOR; +} + +void HCIEmulator::stopDoor(){ + if(m_statemachine != WAITING){ + return; + } + m_lastStateTime = millis(); + m_statemachine = STARTSTOPDOOR; +} + +void HCIEmulator::toggleLamp(){ + if(m_statemachine != WAITING){ + return; + } + m_lastStateTime = millis(); + m_statemachine = STARTTOGGLELAMP; +} + +void HCIEmulator::ventilationPosition(){ + if(m_statemachine != WAITING){ + return; + } + m_lastStateTime = millis(); + m_statemachine = STARTVENTPOSITION; +} + +void HCIEmulator::onStatusChanged(callback_function_t handler) { + m_statusCallback = handler; +} \ No newline at end of file diff --git a/HCPBridgeESP32/src/hciemulator.h b/HCPBridgeESP32/src/hciemulator.h new file mode 100644 index 0000000..41cb511 --- /dev/null +++ b/HCPBridgeESP32/src/hciemulator.h @@ -0,0 +1,131 @@ +#ifndef __hciemulator_h +#define __hciemulator_h + +#include +#include +#include + +#define LL_OFF 0 +#define LL_ERROR 1 +#define LL_WARN 2 +#define LL_INFO 3 +#define LL_DEBUG 4 + +#define DEFAULTLOGLEVEL LL_WARN + +#define DEVICEID 0x02 +#define BROADCASTID 0x00 +#define SIMULATEKEYPRESSDELAYMS 100 + + +// Modbus states that a baud rate higher than 19200 must use a fixed 750 us +// for inter character time out and 1.75 ms for a frame delay. +// For baud rates below 19200 the timeing is more critical and has to be calculated. +// E.g. 9600 baud in a 10 bit packet is 960 characters per second +// In milliseconds this will be 960characters per 1000ms. So for 1 character +// 1000ms/960characters is 1.04167ms per character and finaly modbus states an +// intercharacter must be 1.5T or 1.5 times longer than a normal character and thus +// 1.5T = 1.04167ms * 1.5 = 1.5625ms. A frame delay is 3.5T. +#define T1_5 750 +#define T3_5 4800 //1750 + + +enum DoorState : uint8_t { + DOOR_OPEN_POSITION = 0x20, + DOOR_CLOSE_POSITION = 0x40, + DOOR_HALF_POSITION = 0x80, + DOOR_MOVE_CLOSEPOSITION = 0x02, + DOOR_MOVE_OPENPOSITION = 0x01, + +}; + +struct SHCIState{ + bool valid; + bool lampOn; + uint8_t doorState; // see DoorState + uint8_t doorCurrentPosition; + uint8_t doorTargetPosition; + uint8_t reserved; +}; + +enum StateMachine: uint8_t{ + WAITING, + + STARTOPENDOOR, + STARTOPENDOOR_RELEASE, + + STARTOPENDOORHALF, + STARTOPENDOORHALF_RELEASE, + + STARTCLOSEDOOR, + STARTCLOSEDOOR_RELEASE, + + STARTSTOPDOOR, + STARTSTOPDOOR_RELEASE, + + STARTTOGGLELAMP, + STARTTOGGLELAMP_RELEASE, + + STARTVENTPOSITION, + STARTVENTPOSITION_RELEASE +}; + +class HCIEmulator { +public: + typedef std::function callback_function_t; + + HCIEmulator(Stream * port); + + void poll(); + + void openDoor(); + void openDoorHalf(); + void closeDoor(); + void stopDoor(); + void toggleLamp(); + void ventilationPosition(); + + const SHCIState& getState() { + if(micros()-m_recvTime > 2000000){ + // 2 sec without statusmessage + m_state.valid = false; + } + return m_state; + }; + + unsigned long getMessageAge(){ + return micros()-m_recvTime; + } + + int getLogLevel(); + void setLogLevel(int level); + + void onStatusChanged(callback_function_t handler); + +protected: + void processFrame(); + void processDeviceStatusFrame(); + void processDeviceBusScanFrame(); + void processBroadcastStatusFrame(); + +private: + callback_function_t m_statusCallback; + Stream *m_port; + SHCIState m_state; + StateMachine m_statemachine; + + unsigned long m_recvTime; + unsigned long m_lastStateTime; + unsigned long m_lastSendTime; + + size_t m_rxlen; + size_t m_txlen; + + unsigned char m_rxbuffer[255]; + unsigned char m_txbuffer[255]; + + bool m_skipFrame; +}; + + +#endif \ No newline at end of file diff --git a/HCPBridgeESP32/src/index_html.h b/HCPBridgeESP32/src/index_html.h new file mode 100644 index 0000000..bb80e1c --- /dev/null +++ b/HCPBridgeESP32/src/index_html.h @@ -0,0 +1 @@ +const uint8_t index_html[] PROGMEM = {0x78,0xDA,0xA5,0x57,0xFD,0x6E,0xE3,0x36,0x12,0xFF,0x7B,0xFD,0x14,0xAC,0x0E,0x08,0xA4,0x8D,0xED,0x48,0xB2,0xB3,0xEB,0x5A,0x96,0x8B,0xED,0x66,0xAF,0xDB,0x62,0x7B,0x2D,0x9A,0x5C,0xD1,0x5E,0xB1,0x7F,0xD0,0xD4,0xC8,0x26,0x42,0x7D,0x1C,0x45,0xC5,0xF6,0x1A,0x7E,0x96,0xBE,0xC5,0xBD,0x40,0x5F,0xEC,0x86,0xA4,0x64,0xCB,0x89,0xB3,0x2D,0xD0,0xC0,0x8A,0x48,0xCE,0xCC,0x6F,0x3E,0x38,0x33,0xA4,0x66,0x5F,0xDC,0xFC,0xF0,0xF6,0xEE,0xD7,0x1F,0xDF,0x91,0xF7,0x77,0xDF,0x7F,0x98,0xCF,0x56,0x2A,0x13,0xF8,0x1F,0x68,0x32,0x9F,0x29,0xAE,0x04,0xCC,0xBF,0xA1,0x92,0x2E,0x21,0x57,0x85,0x24,0xB7,0x0A,0x6A,0x90,0x75,0xBE,0x9C,0x5D,0x59,0xDA,0x2C,0x03,0x45,0x49,0x4E,0x33,0x88,0x1F,0x38,0xAC,0xCB,0x42,0x2A,0xC2,0x8A,0x5C,0x21,0x7B,0xEC,0xAC,0x79,0xA2,0x56,0x71,0x02,0x0F,0x9C,0xC1,0xC0,0x4C,0xFA,0x84,0xE7,0x5C,0x71,0x2A,0x06,0x15,0xA3,0x02,0xE2,0xC0,0x69,0x10,0xD8,0x8A,0xCA,0x0A,0x54,0xFC,0xEF,0xBB,0x7F,0x0E,0x26,0xF3,0x99,0xE0,0xF9,0x3D,0x91,0x20,0x62,0x8E,0x60,0x64,0x25,0x21,0x8D,0x13,0xAA,0xE8,0xB4,0x3F,0x9F,0x55,0x6A,0x8B,0x7A,0x7B,0x04,0xFF,0xB4,0xA9,0x64,0x97,0xA2,0xBA,0x41,0x4A,0x33,0x2E,0xB6,0x53,0xF2,0x46,0x22,0x78,0x44,0x12,0x5E,0x95,0x82,0xE2,0x9C,0xE7,0x08,0x05,0x83,0x85,0x28,0xD8,0x7D,0x44,0x14,0x6C,0xD4,0x80,0x0A,0xBE,0xCC,0xA7,0x84,0xA1,0x89,0x20,0xA3,0xBD,0x45,0x0A,0x1B,0x9C,0x8A,0x7F,0x82,0x29,0x19,0x0D,0x7D,0x09,0x59,0x43,0x2B,0x9F,0x27,0x2D,0x8A,0x64,0x4B,0x76,0x19,0xDD,0x58,0xEF,0xA6,0xE4,0x95,0xEF,0x97,0x9B,0x88,0x64,0x54,0x2E,0x79,0x3E,0xC5,0x31,0xA1,0xB5,0x2A,0x22,0x52,0xD2,0x24,0xE1,0xF9,0x72,0xB0,0x28,0x94,0x2A,0xB2,0x29,0x09,0xAF,0x91,0xCD,0x62,0x0C,0xAB,0x35,0x57,0x6C,0x45,0x76,0x65,0x51,0x61,0x68,0x0A,0x34,0x0D,0x1D,0xA7,0x8A,0x3F,0xC0,0xB3,0x7E,0x34,0xDA,0x26,0x46,0xD9,0x0A,0xF8,0x72,0xA5,0xA6,0x64,0x3C,0x29,0x37,0x7B,0x72,0x82,0xC9,0xF3,0xB2,0x56,0x64,0x77,0x40,0xC9,0x8B,0x1C,0x5A,0xAD,0x82,0x27,0x20,0xBB,0x5A,0xE9,0xA2,0x2A,0x44,0xAD,0x50,0xAB,0x2A,0xCA,0x29,0xF1,0x23,0x22,0x20,0x55,0x66,0x20,0xAD,0x06,0x1C,0xB5,0x0E,0xE8,0x21,0x65,0xF7,0x4B,0x59,0xD4,0x79,0x32,0x60,0x85,0x28,0xE4,0x94,0xFC,0x83,0x31,0xA6,0x59,0x24,0x22,0x0F,0x24,0x4D,0x78,0x5D,0x61,0x48,0xD0,0xAA,0xAE,0xCA,0xE9,0x02,0xD2,0x42,0xC2,0x79,0xCD,0x4D,0xEA,0x4C,0x89,0xE3,0x1C,0x1D,0x1B,0x85,0xDA,0xCD,0xC6,0x67,0x3B,0xB1,0x96,0x4D,0xF4,0xB0,0xB5,0xC8,0x4E,0x9E,0xDA,0x94,0xA6,0x69,0x44,0x06,0x6B,0x58,0xDC,0x73,0x35,0x50,0x92,0xE6,0xAD,0xD6,0xE1,0xB8,0x42,0x57,0x1F,0x2F,0x3C,0xB2,0x7E,0xD4,0x5A,0x6F,0x42,0x39,0x65,0x2B,0x60,0xF7,0x90,0x5C,0x1E,0xC2,0x77,0x46,0xE1,0x62,0xE4,0xE3,0xDF,0x67,0xA4,0x0E,0x11,0x38,0xB1,0x0A,0x97,0xD0,0x0B,0x33,0xC4,0xDD,0x87,0x5F,0x5C,0xED,0xA9,0x87,0xA6,0x67,0xD5,0xE7,0x19,0x3E,0x43,0xDC,0xF7,0x5E,0xF4,0x5E,0x0C,0x17,0x35,0x46,0x28,0x27,0xBB,0xDE,0x8B,0x17,0xD6,0x3B,0xCC,0x15,0x0C,0xD6,0x61,0x3A,0x30,0x25,0x35,0x25,0xB8,0x09,0x3C,0xD1,0xCB,0x8D,0x27,0x0B,0x81,0xCE,0xE9,0x79,0x13,0xFA,0xC0,0x24,0x37,0xCE,0xDB,0x8D,0x39,0x2C,0x9C,0xA9,0x2B,0x5C,0x7D,0x94,0xBC,0x07,0xC6,0x04,0x58,0x21,0xA9,0x8D,0xB9,0xCE,0xC8,0x33,0xBC,0x4D,0xA2,0x23,0xC1,0x94,0xDE,0xBA,0x51,0xB8,0x28,0x44,0x72,0x58,0xB4,0xF5,0x18,0x36,0x26,0x34,0x25,0xA7,0x3D,0x23,0xA1,0x5D,0x62,0xB5,0xAC,0xB4,0x1F,0x65,0xC1,0x5B,0x93,0x1E,0xED,0xEE,0xB5,0x15,0xDE,0x1F,0x82,0x24,0x21,0xC1,0x3D,0xB5,0x4C,0xED,0x7E,0xBE,0xBB,0xB9,0xFE,0xF2,0x55,0x10,0x1D,0x99,0xB6,0x20,0x44,0xB1,0x7E,0xC2,0x97,0x32,0x46,0x7D,0xBF,0xC3,0xB7,0x94,0x00,0xF9,0x13,0xB6,0xF1,0x64,0x91,0x4C,0x10,0x8E,0xE8,0x52,0x9D,0x5D,0xD9,0x76,0x36,0xBB,0xB2,0x0D,0x57,0x37,0x14,0x6C,0xBE,0x61,0xA7,0xE7,0x22,0x29,0x9C,0xCF,0x18,0xCD,0x1F,0x68,0x65,0x8B,0x20,0x0E,0xB5,0xDD,0x4D,0x79,0x34,0x13,0x9E,0xC4,0x09,0x43,0x18,0xCB,0x87,0x10,0x23,0xBD,0x54,0x29,0xAA,0xEA,0x6A,0xBE,0xA6,0x52,0x01,0x76,0xA2,0x94,0xFC,0x0C,0x72,0xC1,0xF3,0x04,0x1B,0xF8,0x10,0x71,0x47,0xC8,0x27,0x51,0xA9,0xCD,0x0F,0x26,0x68,0x55,0xC5,0x4E,0x33,0x3B,0xC4,0xC3,0x21,0x45,0xCE,0x04,0x67,0xF7,0x71,0x52,0xBC,0x2D,0xB2,0x8C,0xE6,0x89,0x1B,0x78,0xF3,0x37,0x75,0x3A,0xBB,0xB2,0x4C,0x9F,0x45,0xB0,0xC1,0x3A,0x07,0x12,0x7A,0xF3,0x5B,0xEC,0x34,0x7F,0x09,0xC5,0x84,0xF2,0x1C,0x88,0xEF,0xCD,0xFF,0x53,0x1F,0x21,0xB4,0x3B,0xAB,0xF1,0xFC,0x03,0x67,0x2B,0x85,0x0E,0x8E,0xF1,0x24,0xA1,0x0B,0x10,0x0D,0xA6,0xED,0x8A,0xF3,0x99,0x6D,0x8B,0x6A,0x5B,0x42,0x6C,0x4A,0x73,0x51,0x6C,0x34,0xF4,0x8A,0xE6,0x4B,0xE8,0x60,0x5F,0x7B,0x3A,0x86,0x42,0x47,0x19,0x8F,0x9D,0x92,0xB6,0xA6,0xD9,0x2A,0xC6,0x60,0xEB,0x35,0x7C,0x19,0x15,0x56,0x77,0xC5,0x24,0x2F,0xD5,0x3C,0x29,0x0A,0x89,0xED,0x2D,0x0E,0xFC,0x28,0xE1,0x32,0x1E,0x04,0x11,0xAF,0xB0,0xB5,0xE5,0xC0,0x14,0x24,0x71,0x4A,0x45,0x05,0xD1,0x03,0x95,0x84,0xE6,0x3C,0x33,0x85,0x10,0xA5,0x75,0xCE,0xF4,0x80,0xE0,0x96,0x49,0x75,0x83,0xF2,0x6F,0x5A,0x9A,0xEB,0xED,0x78,0xEA,0x7E,0x71,0xE0,0xF5,0x76,0x87,0x61,0x8C,0x47,0xE6,0xB7,0x3A,0xB7,0x1F,0xA8,0x70,0x6F,0x24,0x5D,0xF7,0x43,0xDF,0xF7,0xA2,0xFD,0xBE,0xD7,0xC1,0x2B,0xCA,0x33,0x70,0x1D,0x34,0x26,0x80,0xCA,0x03,0xCA,0x91,0x80,0x99,0x7C,0x54,0x94,0xD7,0x42,0x44,0x1D,0x58,0xAD,0x0C,0x91,0xB4,0x13,0xD5,0xC3,0x12,0x83,0xC6,0xEA,0x0C,0xD3,0x75,0xB8,0x04,0xF5,0x4E,0x80,0x1E,0x7E,0xBD,0xFD,0x36,0x71,0x1D,0x24,0x3A,0x9E,0xF1,0x35,0x61,0xCF,0x73,0x25,0xAC,0x61,0x62,0x6A,0x83,0x79,0xAC,0xE9,0x6F,0xF5,0x49,0xB0,0x51,0xAE,0x13,0x26,0x48,0x6B,0x6E,0x12,0x6C,0x68,0x06,0x51,0x93,0xFA,0x38,0xB7,0xA3,0x08,0xE5,0x86,0xC6,0x8F,0x9F,0x30,0xC4,0xAE,0xDF,0xF7,0xFB,0xF6,0xBA,0x61,0xC9,0x5E,0xB4,0xA1,0xF1,0x6F,0xC1,0xA4,0xAF,0x7F,0x7E,0x7F,0xD4,0x0F,0x5E,0x8F,0xFB,0xA3,0xF1,0x6B,0x7C,0x70,0x36,0x0A,0xCD,0x13,0x7E,0xF9,0xDA,0x3C,0xD7,0xA1,0xFE,0x05,0x93,0x8F,0xD1,0x16,0x85,0x46,0xE1,0xEB,0x7E,0x10,0x8C,0xF1,0xC1,0xB7,0xEF,0xF7,0xC3,0xD0,0xBC,0xCC,0x14,0x97,0x35,0xD9,0xB2,0x84,0xE6,0x69,0xE6,0x1F,0x8D,0x41,0x29,0x17,0xE2,0x56,0x97,0x37,0x26,0xB3,0x6E,0xA5,0x8E,0x59,0x5D,0x00,0xF6,0xA9,0x1F,0xA9,0x5A,0xB9,0x5E,0x84,0x5D,0xDB,0xE5,0xB1,0x1F,0xF1,0xD9,0x86,0x0E,0x05,0xE4,0x4B,0xF4,0x8D,0x5F,0x5E,0x9A,0x1D,0xE2,0x71,0xEC,0xE3,0xE6,0xA0,0x44,0x56,0x3C,0xC0,0x5D,0xE1,0xBA,0x1B,0xFA,0x1B,0xFF,0x78,0x35,0xBA,0xF6,0xBD,0x97,0xD6,0x3B,0x77,0xFB,0x68,0x05,0xF7,0x0C,0x30,0xB7,0x8C,0x94,0x6E,0xA3,0x7F,0x59,0x6A,0xDF,0x6B,0x0D,0x3E,0xB1,0xAA,0xC9,0x63,0x6B,0x53,0xCB,0x61,0x42,0xEC,0xBE,0x0A,0x4F,0x30,0xDD,0x20,0xF4,0x2F,0xC3,0xE0,0x25,0xF7,0x4E,0x96,0xC3,0xF0,0xFA,0x64,0x1E,0x4C,0x4E,0xF5,0xF6,0x1A,0x0D,0x97,0x31,0xD6,0x49,0x84,0x5E,0xE3,0x6B,0xE6,0x5F,0x5C,0x34,0xCB,0x33,0x1D,0x02,0x5D,0x41,0xF8,0xBC,0x1C,0xE8,0x1E,0x6C,0x59,0xE6,0x47,0x96,0x39,0x16,0xD9,0x29,0x4F,0x27,0x4B,0x8F,0xB5,0x4C,0x99,0x4D,0x76,0x5D,0x49,0x9D,0x5A,0xF4,0x76,0x12,0x54,0x2D,0x73,0x44,0xD6,0xE9,0xB7,0x59,0xC9,0x38,0x87,0x35,0xF9,0xE5,0xFB,0x0F,0xEF,0x95,0x2A,0x7F,0x82,0xFF,0xD6,0x50,0x29,0x0C,0x09,0x12,0x86,0x45,0x09,0xB9,0xEB,0x7C,0xF3,0xEE,0xCE,0xE9,0x3B,0x57,0xCC,0xE2,0x7E,0x65,0x71,0x63,0xE7,0xD2,0x0E,0xFA,0x4A,0xD6,0x60,0xD9,0x2B,0x40,0xB5,0x5E,0xB7,0x66,0xB0,0x58,0x75,0x25,0xDE,0x62,0x53,0x06,0x57,0xB7,0x66,0xF0,0x76,0x67,0xCA,0x53,0x87,0xC1,0x50,0x4D,0x02,0x3C,0x69,0x25,0xFB,0x0E,0x3D,0x38,0xD2,0x2D,0xF9,0x84,0x1A,0x1E,0xA9,0xD7,0x2D,0xD5,0xD6,0x6D,0x87,0x69,0xE4,0x9D,0xEB,0x38,0x5D,0xB3,0xB1,0x18,0x6F,0xCD,0x39,0x72,0xA7,0xEB,0x91,0x9B,0x98,0x55,0xB5,0xC0,0xFB,0xFD,0x0D,0x9E,0x48,0x77,0xF8,0x55,0xE0,0xF4,0x6C,0x67,0xD5,0xC4,0xDE,0x8E,0xD1,0x0A,0x88,0xBF,0x09,0xFD,0xE9,0x89,0xC3,0x81,0x17,0xD9,0x58,0x13,0x2B,0x7E,0xE9,0xF0,0x4A,0x21,0xF8,0x1F,0xFF,0x4B,0xD3,0x1C,0xD4,0x10,0xAB,0xC3,0x0A,0x8E,0x1F,0x09,0xFA,0xCF,0x08,0x56,0x6C,0x25,0x8A,0x0A,0xC3,0x7C,0x14,0x9D,0x3C,0x12,0x0D,0xCF,0x8A,0x2A,0xE0,0xE2,0x8C,0x5E,0xFF,0x6F,0x09,0x87,0xA7,0xC2,0xA3,0x27,0xC2,0xDA,0x5C,0x0E,0x7F,0xFC,0xDE,0x15,0x0A,0xFE,0x4C,0xE8,0x54,0xCF,0x20,0x78,0x26,0x32,0xCE,0x3D,0x60,0xB5,0x77,0x4E,0x77,0xF2,0xA9,0xCE,0xF4,0xD6,0xA0,0x60,0x02,0x29,0x45,0xAC,0x69,0xC3,0x59,0xE7,0x0B,0xB8,0xA7,0xBA,0xDB,0x13,0xBB,0xAB,0x78,0xD7,0xBE,0xC4,0x6B,0x5F,0xB7,0x6C,0xEA,0x12,0x3F,0xB6,0xE0,0x06,0x3F,0xB8,0x9A,0x16,0xBF,0xC9,0xC4,0x0A,0xEB,0xE1,0x99,0xDA,0xB0,0xC4,0xA1,0xBE,0x2D,0xD0,0x64,0x6B,0xF2,0xAA,0x39,0x4B,0x5B,0x44,0x7B,0xE6,0xA8,0x15,0xAF,0x86,0x86,0xE7,0xD6,0xE6,0xDE,0xF8,0xE2,0xC2,0xAC,0xD9,0x6B,0x0A,0x26,0x2C,0x1E,0x5E,0xF6,0x48,0xB1,0x0B,0xDF,0xDD,0xFE,0xF0,0xAF,0x61,0xA9,0x3F,0x0C,0x5B,0xD9,0xAA,0x2C,0xF2,0x0A,0x74,0x22,0x7A,0x27,0x47,0xAA,0x15,0x18,0xE2,0x01,0x86,0xAE,0x3C,0x7F,0x18,0x19,0x2E,0xC7,0x1B,0x72,0x94,0x93,0xFA,0x73,0x37,0x3E,0x4D,0xEE,0x2E,0xCC,0x57,0xCD,0x44,0x97,0x90,0xF1,0x69,0x3A,0xC0,0x14,0x7E,0x16,0xDB,0x5C,0x13,0x10,0xBA,0xB9,0xEB,0xB7,0x16,0x09,0x9A,0x95,0x17,0x27,0xD6,0x1D,0x1A,0xCE,0xD3,0x2B,0xC1,0xFE,0x18,0xCB,0x6E,0xAF,0x69,0xCC,0x6E,0x7B,0x4B,0xC3,0x72,0xE8,0x2F,0x4D,0x49,0x77,0x37,0x2D,0xEA,0xDE,0x0B,0x8E,0x84,0xBE,0xFE,0x32,0xF1,0x22,0xBC,0xB8,0xD8,0x6B,0x0A,0xDE,0x9B,0xCC,0x7D,0xF3,0xCA,0x7C,0xF3,0xFF,0x1F,0xA6,0x8A,0x84,0xF0}; \ No newline at end of file diff --git a/HCPBridgeESP32/src/main.cpp b/HCPBridgeESP32/src/main.cpp new file mode 100644 index 0000000..bdd8964 --- /dev/null +++ b/HCPBridgeESP32/src/main.cpp @@ -0,0 +1,200 @@ +#include +#include +#include "AsyncJson.h" +#include "ArduinoJson.h" +#include "hciemulator.h" +#include "index_html.h" + +/* create this file and add your wlan credentials + const char* ssid = "MyWLANSID"; + const char* password = "MYPASSWORD"; +*/ +#include "../../../private/credentials.h" + + +// switch relay sync to the lamp +// e.g. the Wifi Relay Board U4648 +#define USERELAY + +// use alternative uart pins +//#define SWAPUART + +#define RS485 Serial + +// Relay Board parameters +#define ESP8266_GPIO2 2 // Blue LED. +#define ESP8266_GPIO4 4 // Relay control. +#define ESP8266_GPIO5 5 // Optocoupler input. +#define LED_PIN ESP8266_GPIO2 + + +// Hörmann HCP2 based on modbus rtu @57.6kB 8E1 +HCIEmulator emulator(&RS485); + +// webserver on port 80 +AsyncWebServer server(80); + +// called by ESPAsyncTCP-esphome:SyncClient.cpp (see patch) instead of delay to avoid connection breaks +void DelayHandler(void){ + emulator.poll(); +} + +// switch GPIO4 und GPIO2 sync to the lamp +void onStatusChanged(const SHCIState& state){ + //see https://ucexperiment.wordpress.com/2016/12/18/yunshan-esp8266-250v-15a-acdc-network-wifi-relay-module/ + //Setting GPIO4 high, causes the relay to close the NO contact with + if(state.valid){ + digitalWrite( ESP8266_GPIO4, state.lampOn ); + digitalWrite(LED_PIN, state.lampOn); + }else + { + digitalWrite( ESP8266_GPIO4, false ); + digitalWrite(LED_PIN, false); + } +} + +// toggle lamp to expected state +void switchLamp(bool on){ + bool toggle = (on && !emulator.getState().lampOn) || (!on && emulator.getState().lampOn); + if(toggle){ + emulator.toggleLamp(); + } +} + +volatile unsigned long lastCall = 0; +volatile unsigned long maxPeriod = 0; + +void modBusPolling( void * parameter) { + while(true){ + if(lastCall>0){ + maxPeriod = _max(micros()-lastCall,maxPeriod); + } + lastCall=micros(); + emulator.poll(); + vTaskDelay(1); + } + vTaskDelete(NULL); +} + + +TaskHandle_t modBusTask; + +// setup mcu +void setup(){ + + //setup modbus + RS485.begin(57600,SERIAL_8E1); + #ifdef SWAPUART + RS485.swap(); + #endif + + + xTaskCreatePinnedToCore( + modBusPolling, /* Function to implement the task */ + "ModBusTask", /* Name of the task */ + 10000, /* Stack size in words */ + NULL, /* Task input parameter */ + //1, /* Priority of the task */ + configMAX_PRIORITIES -1, + &modBusTask, /* Task handle. */ + 1); /* Core where the task should run */ + + + //setup wifi + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + WiFi.setAutoReconnect(true); + while (WiFi.status() != WL_CONNECTED) { + delay(100); + } + + // setup http server + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ + AsyncWebServerResponse *response = request->beginResponse_P( 200, "text/html", index_html,sizeof(index_html)); + response->addHeader("Content-Encoding","deflate"); + request->send(response); + }); + + server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request){ + const SHCIState& doorstate = emulator.getState(); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + DynamicJsonDocument root(1024); + root["valid"] = doorstate.valid; + root["doorstate"] = doorstate.doorState; + root["doorposition"] = doorstate.doorCurrentPosition; + root["doortarget"] = doorstate.doorTargetPosition; + root["lamp"] = doorstate.lampOn; + root["debug"] = doorstate.reserved; + root["lastresponse"] = emulator.getMessageAge()/1000; + root["looptime"] = maxPeriod; + + lastCall = maxPeriod = 0; + + serializeJson(root,*response); + request->send(response); + }); + + server.on("/command", HTTP_GET, [] (AsyncWebServerRequest *request) { + if (request->hasParam("action")) { + int actionid = request->getParam("action")->value().toInt(); + switch (actionid){ + case 0: + emulator.closeDoor(); + break; + case 1: + emulator.openDoor(); + break; + case 2: + emulator.stopDoor(); + break; + case 3: + emulator.ventilationPosition(); + break; + case 4: + emulator.openDoorHalf(); + break; + case 5: + emulator.toggleLamp(); + break; + default: + break; + } + } + request->send(200, "text/plain", "OK"); + }); + + server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) { + if (request->hasParam("channel") && request->hasParam("state")) { + String channel = request->getParam("channel")->value(); + String state = request->getParam("state")->value(); + if(channel.equals("door")){ + if(state=="1"){ + emulator.openDoor(); + }else{ + emulator.closeDoor(); + } + } + if(channel.equals("light")){ + switchLamp(state=="1"); + } + } + request->send(200, "text/plain", "OK"); + }); + + server.begin(); + + //setup relay board +#ifdef USERELAY + pinMode( ESP8266_GPIO4, OUTPUT ); // Relay control pin. + pinMode( ESP8266_GPIO5, INPUT_PULLUP ); // Input pin. + pinMode( LED_PIN, OUTPUT ); // ESP8266 module blue L + digitalWrite( ESP8266_GPIO4, 0 ); + digitalWrite(LED_PIN,0); + emulator.onStatusChanged(onStatusChanged); +#endif + +} + +// mainloop +void loop(){ +} \ No newline at end of file diff --git a/HCPBridgeESP32/src/webpage/buildindex.cmd b/HCPBridgeESP32/src/webpage/buildindex.cmd new file mode 100644 index 0000000..6ed0ebd --- /dev/null +++ b/HCPBridgeESP32/src/webpage/buildindex.cmd @@ -0,0 +1 @@ +python compress.py diff --git a/HCPBridgeESP32/src/webpage/command b/HCPBridgeESP32/src/webpage/command new file mode 100644 index 0000000..e69de29 diff --git a/HCPBridgeESP32/src/webpage/compress.py b/HCPBridgeESP32/src/webpage/compress.py new file mode 100644 index 0000000..5e9faa8 --- /dev/null +++ b/HCPBridgeESP32/src/webpage/compress.py @@ -0,0 +1,35 @@ +#pip install htmlmin +#or python -m pip install htmlmin +#pip install jsmin +#or python -m pip install jsmin + +import gzip +import zlib +import htmlmin +from jsmin import jsmin + + + +content = "" +with open('index.html','rt',encoding="utf-8") as f: + content=f.read() + + +content = htmlmin.minify(content, remove_comments=True, remove_empty_space=True, remove_all_empty_space=True, reduce_empty_attributes=True, reduce_boolean_attributes=False, remove_optional_attribute_quotes=True, convert_charrefs=True, keep_pre=False) + + +import re +regex = r"" ,content, 0, re.DOTALL) + +result ="" +for c in zlib.compress(content.encode("UTF-8"),9): + result= result + ("0x%02X" %c) + if len(result)> 0: + result=result + "," + + +with open('../index_html.h',"wt") as f: + f.write("const uint8_t index_html[] PROGMEM = {"); + f.write(result.strip(",")) + f.write("};"); \ No newline at end of file diff --git a/HCPBridgeESP32/src/webpage/index.html b/HCPBridgeESP32/src/webpage/index.html new file mode 100644 index 0000000..303cbef --- /dev/null +++ b/HCPBridgeESP32/src/webpage/index.html @@ -0,0 +1,159 @@ + + + Garagentor Steuerung + + + + + + +

Garagentor

+ +

warte auf Verbindung.

+ +
+ +
+

Licht

+
+ + + + \ No newline at end of file diff --git a/HCPBridgeESP32/src/webpage/runtestserver.cmd b/HCPBridgeESP32/src/webpage/runtestserver.cmd new file mode 100644 index 0000000..092262b --- /dev/null +++ b/HCPBridgeESP32/src/webpage/runtestserver.cmd @@ -0,0 +1 @@ +python -m http.server diff --git a/HCPBridgeESP32/src/webpage/status b/HCPBridgeESP32/src/webpage/status new file mode 100644 index 0000000..c050664 --- /dev/null +++ b/HCPBridgeESP32/src/webpage/status @@ -0,0 +1,9 @@ +{ + "valid" : true, + "doorstate" : 1, + "doorposition" : 0, + "doortarget" : 0, + "lamp" : true, + "debug" : 0, + "lastresponse" : 0 +} \ No newline at end of file diff --git a/HCPBridgeESP32/test/README b/HCPBridgeESP32/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/HCPBridgeESP32/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/HCPBridgeISR/.gitignore b/HCPBridgeISR/.gitignore new file mode 100644 index 0000000..d3e0c0c --- /dev/null +++ b/HCPBridgeISR/.gitignore @@ -0,0 +1,5 @@ +/.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/HCPBridgeISR/.vscode/extensions.json b/HCPBridgeISR/.vscode/extensions.json new file mode 100644 index 0000000..e80666b --- /dev/null +++ b/HCPBridgeISR/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} diff --git a/HCPBridgeISR/.vscode/settings.json b/HCPBridgeISR/.vscode/settings.json new file mode 100644 index 0000000..39b251d --- /dev/null +++ b/HCPBridgeISR/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "files.associations": { + "array": "cpp", + "deque": "cpp", + "list": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "initializer_list": "cpp", + "regex": "cpp", + "functional": "cpp" + } +} \ No newline at end of file diff --git a/HCPBridgeISR/include/README b/HCPBridgeISR/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/HCPBridgeISR/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/HCPBridgeISR/lib/README b/HCPBridgeISR/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/HCPBridgeISR/lib/README @@ -0,0 +1,46 @@ + +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/HCPBridgeISR/platformio.ini b/HCPBridgeISR/platformio.ini new file mode 100644 index 0000000..e4d26de --- /dev/null +++ b/HCPBridgeISR/platformio.ini @@ -0,0 +1,17 @@ +; 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 + +[env:esp12e] +platform = espressif8266 +board = esp12e +framework = arduino +lib_deps = + ottowinter/ESPAsyncWebServer-esphome@^1.2.7 + bblanchon/ArduinoJson@^6.17.2 diff --git a/HCPBridgeISR/simulator/hcisim.py b/HCPBridgeISR/simulator/hcisim.py new file mode 100644 index 0000000..3458014 --- /dev/null +++ b/HCPBridgeISR/simulator/hcisim.py @@ -0,0 +1,18 @@ +import serial +import time + +ser = serial.Serial('COM3', baudrate=57600, bytesize=8,timeout=1, parity=serial.PARITY_EVEN, stopbits=serial.STOPBITS_ONE) # open serial port + + +while True: + busscan = "02 17 9C B9 00 05 9C 41 00 03 06 00 02 00 00 01 02 f8 35" + print(bytearray.fromhex(busscan)) + ser.write(bytearray.fromhex(busscan)) + #time.sleep(2) + print(ser.read(15)) + + status = "02 17 9C B9 00 08 9C 41 00 02 04 3E 03 00 00 EB CC" + print(bytearray.fromhex(status)) + ser.write(bytearray.fromhex(status)) + #time.sleep(2) + print(ser.read(21)) diff --git a/HCPBridgeISR/src/LICENSE b/HCPBridgeISR/src/LICENSE new file mode 100644 index 0000000..a8fc851 --- /dev/null +++ b/HCPBridgeISR/src/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 + +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. diff --git a/HCPBridgeISR/src/README.md b/HCPBridgeISR/src/README.md new file mode 100644 index 0000000..eed7ab6 --- /dev/null +++ b/HCPBridgeISR/src/README.md @@ -0,0 +1,10 @@ +# esp-uart + +Blocking ESP8266 UART driver with interrupt-driven RX and TX buffers. + +I needed an UART driver where I have complete control over the input and output, because I have the UART chip attached to a multiplexer that connects to multiple serial ports. The driver supplied by the manufacturer works by queueing read callback tasks from the interrupts, which was unnecessary complication for my use case. This driver is a bit work in progress, but should be already usable. + +The license of uart_register.h is a little bit unclear, but because it only +defines the hardware memory locations, it should not be copyrightable. In any +case it can only be used on ESP8266 and is necessary to be able to use the UART +functionality, so the manufacturer most likely does not have any issues with using it. diff --git a/HCPBridgeISR/src/crc.c b/HCPBridgeISR/src/crc.c new file mode 100644 index 0000000..0a2a204 --- /dev/null +++ b/HCPBridgeISR/src/crc.c @@ -0,0 +1,44 @@ +#include "crc.h" + +/** + * Calculate the CRC of the passed byte array from zero up to the passed length. + * + * @param buffer The byte array containing the data. + * @param length The length of the byte array. + * + * @return The calculated CRC as an unsigned 16 bit integer. + * + * Calculate and add the CRC. + * uint16_t crc = Modbus::calculateCRC(_responseBuffer, _responseBufferLength - MODBUS_CRC_LENGTH); + * _responseBuffer[_responseBufferLength - MODBUS_CRC_LENGTH] = crc & 0xFF; + * _responseBuffer[(_responseBufferLength - MODBUS_CRC_LENGTH) + 1] = crc >> 8; + * + * + * #define MODBUS_FRAME_SIZE 4 + * #define MODBUS_CRC_LENGTH 2 + * uint16_t crc = readCRC(_requestBuffer, _requestBufferLength); + * #define readUInt16(arr, index) word(arr[index], arr[index + 1]) + * #define readCRC(arr, length) word(arr[(length - MODBUS_CRC_LENGTH) + 1], arr[length - MODBUS_CRC_LENGTH]) + */ +uint16_t calculateCRC(uint8_t *buffer, int length) +{ + int i, j; + uint16_t crc = 0xFFFF; + uint16_t tmp; + + // Calculate the CRC. + for (i = 0; i < length; i++) + { + crc = crc ^ buffer[i]; + for (j = 0; j < 8; j++) + { + tmp = crc & 0x0001; + crc = crc >> 1; + if (tmp) + { + crc = crc ^ 0xA001; + } + } + } + return crc; +} diff --git a/HCPBridgeISR/src/crc.h b/HCPBridgeISR/src/crc.h new file mode 100644 index 0000000..5c5ef10 --- /dev/null +++ b/HCPBridgeISR/src/crc.h @@ -0,0 +1,22 @@ +#ifndef __crc_h +#define __crc_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +//modbus crc calculation borrowed from: +//https://github.com/yaacov/ArduinoModbusSlave +#define MODBUS_CRC_LENGTH 2 +#define readUInt16(arr, index) (arr[index]<<8 | arr[index + 1]) +#define readCRC(arr, length) (arr[(length - MODBUS_CRC_LENGTH) + 1] << 8 | arr[length - MODBUS_CRC_LENGTH]) + +uint16_t calculateCRC(uint8_t *buffer, int length); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/HCPBridgeISR/src/hciemulator.c b/HCPBridgeISR/src/hciemulator.c new file mode 100644 index 0000000..6ccfc21 --- /dev/null +++ b/HCPBridgeISR/src/hciemulator.c @@ -0,0 +1,511 @@ +/* + * modified/reduced to provide HCP Modbus low level functions + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Juho Vähä-Herttua (juhovh@iki.fi) + * + * 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. + */ +#include "hciemulator.h" +#include "crc.h" + +#include "osapi.h" +#include "ets_sys.h" +#include "uart_register.h" + + +#define T3_5 4800 //1750 +#define DEVICEID 0x02 +#define BROADCASTID 0x00 +#define SIMULATEKEYPRESSDELAYMS 100 +#define CHECKCHANGEDSET(Target,Value,Flag) if((Target)!=(Value)){Target=Value;Flag=true;} + +#define UART0 0 + +// Missing defines from SDK +#define FUNC_U0RXD 0 + +// Define FIFO sizes, actually 128 but playing safe +#define UART_RXFIFO_SIZE 126 +#define UART_TXFIFO_SIZE 126 +#define UART_RXTOUT_TH 2 +#define UART_RXFIFO_TH 100 +#define UART_TXFIFO_TH 10 + +// Define some helper macros to handle FIFO functions +#define UART_TXFIFO_LEN(uart_no) \ + ((READ_PERI_REG(UART_STATUS(uart_no)) >> UART_TXFIFO_CNT_S) & UART_RXFIFO_CNT) +#define UART_TXFIFO_PUT(uart_no, byte) \ + WRITE_PERI_REG(UART_FIFO(uart_no), (byte) & 0xff) +#define UART_RXFIFO_LEN(uart_no) \ + ((READ_PERI_REG(UART_STATUS(uart_no)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT) +#define UART_RXFIFO_GET(uart_no) \ + READ_PERI_REG(UART_FIFO(uart_no)) + + + +bool skipFrame = false; + + +int recvTime = 0; +int lastSendTime = 0; +int lastStateTime = 0; +size_t rxlen = 0; +size_t txlen = 0; +size_t txpos = 0; +unsigned char rxbuffer[255]; +unsigned char txbuffer[255]; +EStateMachine statemachine = WAITING; +SHCIState state; +//-------------------------------------------------------------- + +void openDoor(){ + if(statemachine != WAITING){ + return; + } + lastStateTime = millis(); + statemachine = STARTOPENDOOR; +} + +void openDoorHalf(){ + if(statemachine != WAITING){ + return; + } + lastStateTime = millis(); + statemachine = STARTOPENDOORHALF; +} + +void closeDoor(){ + if(statemachine != WAITING){ + return; + } + lastStateTime = millis(); + statemachine = STARTCLOSEDOOR; +} + +void stopDoor(){ + if(statemachine != WAITING){ + return; + } + lastStateTime = millis(); + statemachine = STARTSTOPDOOR; +} + +void toggleLamp(){ + if(statemachine != WAITING){ + return; + } + lastStateTime = millis(); + statemachine = STARTTOGGLELAMP; +} + +void ventilationPosition(){ + if(statemachine != WAITING){ + return; + } + lastStateTime = millis(); + statemachine = STARTVENTPOSITION; +} + +unsigned long getMessageAge(){ + return micros()-recvTime; +} + +SHCIState* getHCIState(){ + return &state; +} + + +//-------------------------------------------------------------- + +const unsigned char ResponseTemplate_Fcn17_Cmd03_L08 []= {0x02,0x17,0x10,0x3E,0x00,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x74,0x1B}; +const unsigned char ResponseTemplate_Fcn17_Cmd04_L02 []= {0x02,0x17,0x04,0x0F,0x00,0x04,0xFD,0x0A,0x72}; +static void processDeviceStatusFrame(){ + if(rxlen==0x11){ + unsigned char counter = rxbuffer[11]; + unsigned char cmd = rxbuffer[12]; + if(rxbuffer[5] == 0x08){ + // expose internal state + // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 + //0011: 02 17 9C B9 00 08 9C 41 00 02 04 3E 03 00 00 EB CC + //res=> 02 17 10 3E 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 74 1B + memcpy_P(txbuffer, ResponseTemplate_Fcn17_Cmd03_L08, sizeof(ResponseTemplate_Fcn17_Cmd03_L08)); + txbuffer[0] = rxbuffer[0]; + txbuffer[3] = counter; + txbuffer[5] = cmd; + txlen = sizeof(ResponseTemplate_Fcn17_Cmd03_L08); + + + switch(statemachine) + { + // open Door + case STARTOPENDOOR: + txbuffer[7]= 0x02; + txbuffer[8]= 0x10; + statemachine = STARTOPENDOOR_RELEASE; + lastStateTime = millis(); + break; + case STARTOPENDOOR_RELEASE: + if(lastStateTime+SIMULATEKEYPRESSDELAYMS 02 17 04 0F 00 04 FD 0A 72 + memcpy_P(txbuffer, ResponseTemplate_Fcn17_Cmd04_L02, sizeof(ResponseTemplate_Fcn17_Cmd04_L02)); + txbuffer[0] = rxbuffer[0]; + txbuffer[3] = counter; + txbuffer[5] = cmd; + txlen = sizeof(ResponseTemplate_Fcn17_Cmd04_L02); + return; + } + } + //Log3(LL_ERROR,"Frame skipped, unexpected data: ", m_rxbuffer, m_rxlen); +} + +const unsigned char ResponseTemplate_Fcn17_Cmd02_L05 []= {0x02,0x17,0x0a,0x00,0x00,0x02,0x05,0x04,0x30,0x10,0xff,0xa8,0x45,0x0e,0xdf}; +static void processDeviceBusScanFrame(){ + // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 + //0013: 02 17 9C B9 00 05 9C 41 00 03 06 00 02 00 00 01 02 f8 35 + //res=> 02 17 0a 00 00 02 05 04 30 10 ff a8 45 0e df + unsigned char counter = rxbuffer[11]; + unsigned char cmd = rxbuffer[12]; + memcpy_P(txbuffer, ResponseTemplate_Fcn17_Cmd02_L05, sizeof(ResponseTemplate_Fcn17_Cmd02_L05)); + txbuffer[0] = rxbuffer[0]; + txbuffer[3] = counter; + txbuffer[5] = cmd; + txlen = sizeof(ResponseTemplate_Fcn17_Cmd02_L05); + + //Log(LL_INFO,"Busscan received"); +} + +static void processBroadcastStatusFrame(){ + //001B: 00 10 9D 31 00 09 12 64 00 00 00 40 60 00 00 00 00 00 00 00 00 00 01 00 00 CA 22 + bool hasStateChanged = false; + CHECKCHANGEDSET(state.lampOn,rxbuffer[20] == 0x14,hasStateChanged); + CHECKCHANGEDSET(state.doorCurrentPosition,rxbuffer[10],hasStateChanged); + CHECKCHANGEDSET(state.doorTargetPosition, rxbuffer[9],hasStateChanged); + CHECKCHANGEDSET(state.doorState, rxbuffer[11],hasStateChanged); + CHECKCHANGEDSET(state.reserved, rxbuffer[17],hasStateChanged); + CHECKCHANGEDSET(state.valid, true,hasStateChanged); +} + +static bool processFrame(){ + + switch (rxlen) + { + case 0x1b: + case 0x11: + case 0x13: + break; + + default: + // unexpected rxlen + return false; + } + + txlen=txpos=0; + + // check device id, pass only device id 2 and 0 (broadcast) + if(rxbuffer[0] != BROADCASTID && rxbuffer[0] != DEVICEID){ + // Frame skipped, unsupported device id + return false; + } + + // check crc + uint16_t crc = readCRC(rxbuffer, rxlen); + if(crc != calculateCRC(rxbuffer,rxlen-MODBUS_CRC_LENGTH)){ + // Frame skipped, wrong crc + return false; + } + + // dispatch modbus function + switch(rxbuffer[1]){ + case 0x10:{ // Write Multiple registers + if(rxlen == 0x1b && rxbuffer[0] == BROADCASTID) + { + processBroadcastStatusFrame(); + return true; + } + break; + } + + case 0x17:{ // Read/Write Multiple registers + if(rxbuffer[0] == DEVICEID){ + switch(rxlen){ + case 0x11:{ + processDeviceStatusFrame(); + return true; + } + + case 0x13: + processDeviceBusScanFrame(); + return true; + } + } + break; + } + } + + // Frame skipped, unexpected data + return false; +} + + + +static void processMessage (){ + // check frame, process frame + if(statemachine!= WAITING && lastStateTime+2000 0){ + uint16_t crc = calculateCRC(txbuffer, txlen - MODBUS_CRC_LENGTH); + txbuffer[txlen - MODBUS_CRC_LENGTH] = crc & 0xFF; + txbuffer[(txlen - MODBUS_CRC_LENGTH) + 1] = crc >> 8; + + // Enable send + SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA); + } + +} + +//-------------------------------------------------------------- + +static uint16 +uart0_receive() +{ + uint16 i; + uint16 uart0_rxfifo_len = UART_RXFIFO_LEN(UART0); + + if(rxlen>0 && (micros()-recvTime > T3_5)){ + // last message timeout, reset buffer + rxlen = 0; + skipFrame = false; + } + + // receive data from uart + for (i=0; i0){ + processMessage(); + } + + return i; +} + +static uint16 +uart0_send() +{ + uint16 i; + for (i=UART_TXFIFO_LEN(UART0); i + +typedef enum { + WAITING, + + STARTOPENDOOR, + STARTOPENDOOR_RELEASE, + + STARTOPENDOORHALF, + STARTOPENDOORHALF_RELEASE, + + STARTCLOSEDOOR, + STARTCLOSEDOOR_RELEASE, + + STARTSTOPDOOR, + STARTSTOPDOOR_RELEASE, + + STARTTOGGLELAMP, + STARTTOGGLELAMP_RELEASE, + + STARTVENTPOSITION, + STARTVENTPOSITION_RELEASE +} EStateMachine; + +typedef struct { + int valid; + int lampOn; + uint8_t doorState; // see DoorState + uint8_t doorCurrentPosition; + uint8_t doorTargetPosition; + uint8_t reserved; +} SHCIState; + +SHCIState* getHCIState(); +unsigned long getMessageAge(); +void openDoor(); +void openDoorHalf(); +void closeDoor(); +void stopDoor(); +void toggleLamp(); +void ventilationPosition(); + + +#define UART_STOP_BITS_ONE 0x10 +#define UART_STOP_BITS_ONE_HALF 0x20 +#define UART_STOP_BITS_TWO 0x30 +#define UART_STOP_BITS_MASK 0x30 + +#define UART_BITS_FIVE 0x00 +#define UART_BITS_SIX 0x04 +#define UART_BITS_SEVEN 0x08 +#define UART_BITS_EIGHT 0x0C +#define UART_BITS_MASK 0x0C + +#define UART_PARITY_NONE 0x00 +#define UART_PARITY_EVEN 0x02 +#define UART_PARITY_ODD 0x03 +#define UART_PARITY_MASK 0x03 + +#define UART_FLAGS_8N1 (UART_BITS_EIGHT | UART_PARITY_NONE | UART_STOP_BITS_ONE) +#define UART_FLAGS_8E1 (UART_BITS_EIGHT | UART_PARITY_EVEN | UART_STOP_BITS_ONE) + +#define UART_STATUS_IDLE 0x00 +#define UART_STATUS_RECEIVING 0x01 +#define UART_STATUS_OVERFLOW 0x02 + +void uart0_open(uint32 baud_rate, uint32 flags); +void uart0_reset(); + +uint16 uart0_available(); +uint16 uart0_read_buf(const void *buf, uint16 nbyte, uint16 timeout); +uint16 uart0_write_buf(const void *buf, uint16 nbyte, uint16 timeout); +void uart0_flush(); + +void uart1_open(uint32 baud_rate, uint32 flags); +void uart1_reset(); +uint8 uart1_write_byte(uint8 byte); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/HCPBridgeISR/src/index_html.h b/HCPBridgeISR/src/index_html.h new file mode 100644 index 0000000..bb80e1c --- /dev/null +++ b/HCPBridgeISR/src/index_html.h @@ -0,0 +1 @@ +const uint8_t index_html[] PROGMEM = {0x78,0xDA,0xA5,0x57,0xFD,0x6E,0xE3,0x36,0x12,0xFF,0x7B,0xFD,0x14,0xAC,0x0E,0x08,0xA4,0x8D,0xED,0x48,0xB2,0xB3,0xEB,0x5A,0x96,0x8B,0xED,0x66,0xAF,0xDB,0x62,0x7B,0x2D,0x9A,0x5C,0xD1,0x5E,0xB1,0x7F,0xD0,0xD4,0xC8,0x26,0x42,0x7D,0x1C,0x45,0xC5,0xF6,0x1A,0x7E,0x96,0xBE,0xC5,0xBD,0x40,0x5F,0xEC,0x86,0xA4,0x64,0xCB,0x89,0xB3,0x2D,0xD0,0xC0,0x8A,0x48,0xCE,0xCC,0x6F,0x3E,0x38,0x33,0xA4,0x66,0x5F,0xDC,0xFC,0xF0,0xF6,0xEE,0xD7,0x1F,0xDF,0x91,0xF7,0x77,0xDF,0x7F,0x98,0xCF,0x56,0x2A,0x13,0xF8,0x1F,0x68,0x32,0x9F,0x29,0xAE,0x04,0xCC,0xBF,0xA1,0x92,0x2E,0x21,0x57,0x85,0x24,0xB7,0x0A,0x6A,0x90,0x75,0xBE,0x9C,0x5D,0x59,0xDA,0x2C,0x03,0x45,0x49,0x4E,0x33,0x88,0x1F,0x38,0xAC,0xCB,0x42,0x2A,0xC2,0x8A,0x5C,0x21,0x7B,0xEC,0xAC,0x79,0xA2,0x56,0x71,0x02,0x0F,0x9C,0xC1,0xC0,0x4C,0xFA,0x84,0xE7,0x5C,0x71,0x2A,0x06,0x15,0xA3,0x02,0xE2,0xC0,0x69,0x10,0xD8,0x8A,0xCA,0x0A,0x54,0xFC,0xEF,0xBB,0x7F,0x0E,0x26,0xF3,0x99,0xE0,0xF9,0x3D,0x91,0x20,0x62,0x8E,0x60,0x64,0x25,0x21,0x8D,0x13,0xAA,0xE8,0xB4,0x3F,0x9F,0x55,0x6A,0x8B,0x7A,0x7B,0x04,0xFF,0xB4,0xA9,0x64,0x97,0xA2,0xBA,0x41,0x4A,0x33,0x2E,0xB6,0x53,0xF2,0x46,0x22,0x78,0x44,0x12,0x5E,0x95,0x82,0xE2,0x9C,0xE7,0x08,0x05,0x83,0x85,0x28,0xD8,0x7D,0x44,0x14,0x6C,0xD4,0x80,0x0A,0xBE,0xCC,0xA7,0x84,0xA1,0x89,0x20,0xA3,0xBD,0x45,0x0A,0x1B,0x9C,0x8A,0x7F,0x82,0x29,0x19,0x0D,0x7D,0x09,0x59,0x43,0x2B,0x9F,0x27,0x2D,0x8A,0x64,0x4B,0x76,0x19,0xDD,0x58,0xEF,0xA6,0xE4,0x95,0xEF,0x97,0x9B,0x88,0x64,0x54,0x2E,0x79,0x3E,0xC5,0x31,0xA1,0xB5,0x2A,0x22,0x52,0xD2,0x24,0xE1,0xF9,0x72,0xB0,0x28,0x94,0x2A,0xB2,0x29,0x09,0xAF,0x91,0xCD,0x62,0x0C,0xAB,0x35,0x57,0x6C,0x45,0x76,0x65,0x51,0x61,0x68,0x0A,0x34,0x0D,0x1D,0xA7,0x8A,0x3F,0xC0,0xB3,0x7E,0x34,0xDA,0x26,0x46,0xD9,0x0A,0xF8,0x72,0xA5,0xA6,0x64,0x3C,0x29,0x37,0x7B,0x72,0x82,0xC9,0xF3,0xB2,0x56,0x64,0x77,0x40,0xC9,0x8B,0x1C,0x5A,0xAD,0x82,0x27,0x20,0xBB,0x5A,0xE9,0xA2,0x2A,0x44,0xAD,0x50,0xAB,0x2A,0xCA,0x29,0xF1,0x23,0x22,0x20,0x55,0x66,0x20,0xAD,0x06,0x1C,0xB5,0x0E,0xE8,0x21,0x65,0xF7,0x4B,0x59,0xD4,0x79,0x32,0x60,0x85,0x28,0xE4,0x94,0xFC,0x83,0x31,0xA6,0x59,0x24,0x22,0x0F,0x24,0x4D,0x78,0x5D,0x61,0x48,0xD0,0xAA,0xAE,0xCA,0xE9,0x02,0xD2,0x42,0xC2,0x79,0xCD,0x4D,0xEA,0x4C,0x89,0xE3,0x1C,0x1D,0x1B,0x85,0xDA,0xCD,0xC6,0x67,0x3B,0xB1,0x96,0x4D,0xF4,0xB0,0xB5,0xC8,0x4E,0x9E,0xDA,0x94,0xA6,0x69,0x44,0x06,0x6B,0x58,0xDC,0x73,0x35,0x50,0x92,0xE6,0xAD,0xD6,0xE1,0xB8,0x42,0x57,0x1F,0x2F,0x3C,0xB2,0x7E,0xD4,0x5A,0x6F,0x42,0x39,0x65,0x2B,0x60,0xF7,0x90,0x5C,0x1E,0xC2,0x77,0x46,0xE1,0x62,0xE4,0xE3,0xDF,0x67,0xA4,0x0E,0x11,0x38,0xB1,0x0A,0x97,0xD0,0x0B,0x33,0xC4,0xDD,0x87,0x5F,0x5C,0xED,0xA9,0x87,0xA6,0x67,0xD5,0xE7,0x19,0x3E,0x43,0xDC,0xF7,0x5E,0xF4,0x5E,0x0C,0x17,0x35,0x46,0x28,0x27,0xBB,0xDE,0x8B,0x17,0xD6,0x3B,0xCC,0x15,0x0C,0xD6,0x61,0x3A,0x30,0x25,0x35,0x25,0xB8,0x09,0x3C,0xD1,0xCB,0x8D,0x27,0x0B,0x81,0xCE,0xE9,0x79,0x13,0xFA,0xC0,0x24,0x37,0xCE,0xDB,0x8D,0x39,0x2C,0x9C,0xA9,0x2B,0x5C,0x7D,0x94,0xBC,0x07,0xC6,0x04,0x58,0x21,0xA9,0x8D,0xB9,0xCE,0xC8,0x33,0xBC,0x4D,0xA2,0x23,0xC1,0x94,0xDE,0xBA,0x51,0xB8,0x28,0x44,0x72,0x58,0xB4,0xF5,0x18,0x36,0x26,0x34,0x25,0xA7,0x3D,0x23,0xA1,0x5D,0x62,0xB5,0xAC,0xB4,0x1F,0x65,0xC1,0x5B,0x93,0x1E,0xED,0xEE,0xB5,0x15,0xDE,0x1F,0x82,0x24,0x21,0xC1,0x3D,0xB5,0x4C,0xED,0x7E,0xBE,0xBB,0xB9,0xFE,0xF2,0x55,0x10,0x1D,0x99,0xB6,0x20,0x44,0xB1,0x7E,0xC2,0x97,0x32,0x46,0x7D,0xBF,0xC3,0xB7,0x94,0x00,0xF9,0x13,0xB6,0xF1,0x64,0x91,0x4C,0x10,0x8E,0xE8,0x52,0x9D,0x5D,0xD9,0x76,0x36,0xBB,0xB2,0x0D,0x57,0x37,0x14,0x6C,0xBE,0x61,0xA7,0xE7,0x22,0x29,0x9C,0xCF,0x18,0xCD,0x1F,0x68,0x65,0x8B,0x20,0x0E,0xB5,0xDD,0x4D,0x79,0x34,0x13,0x9E,0xC4,0x09,0x43,0x18,0xCB,0x87,0x10,0x23,0xBD,0x54,0x29,0xAA,0xEA,0x6A,0xBE,0xA6,0x52,0x01,0x76,0xA2,0x94,0xFC,0x0C,0x72,0xC1,0xF3,0x04,0x1B,0xF8,0x10,0x71,0x47,0xC8,0x27,0x51,0xA9,0xCD,0x0F,0x26,0x68,0x55,0xC5,0x4E,0x33,0x3B,0xC4,0xC3,0x21,0x45,0xCE,0x04,0x67,0xF7,0x71,0x52,0xBC,0x2D,0xB2,0x8C,0xE6,0x89,0x1B,0x78,0xF3,0x37,0x75,0x3A,0xBB,0xB2,0x4C,0x9F,0x45,0xB0,0xC1,0x3A,0x07,0x12,0x7A,0xF3,0x5B,0xEC,0x34,0x7F,0x09,0xC5,0x84,0xF2,0x1C,0x88,0xEF,0xCD,0xFF,0x53,0x1F,0x21,0xB4,0x3B,0xAB,0xF1,0xFC,0x03,0x67,0x2B,0x85,0x0E,0x8E,0xF1,0x24,0xA1,0x0B,0x10,0x0D,0xA6,0xED,0x8A,0xF3,0x99,0x6D,0x8B,0x6A,0x5B,0x42,0x6C,0x4A,0x73,0x51,0x6C,0x34,0xF4,0x8A,0xE6,0x4B,0xE8,0x60,0x5F,0x7B,0x3A,0x86,0x42,0x47,0x19,0x8F,0x9D,0x92,0xB6,0xA6,0xD9,0x2A,0xC6,0x60,0xEB,0x35,0x7C,0x19,0x15,0x56,0x77,0xC5,0x24,0x2F,0xD5,0x3C,0x29,0x0A,0x89,0xED,0x2D,0x0E,0xFC,0x28,0xE1,0x32,0x1E,0x04,0x11,0xAF,0xB0,0xB5,0xE5,0xC0,0x14,0x24,0x71,0x4A,0x45,0x05,0xD1,0x03,0x95,0x84,0xE6,0x3C,0x33,0x85,0x10,0xA5,0x75,0xCE,0xF4,0x80,0xE0,0x96,0x49,0x75,0x83,0xF2,0x6F,0x5A,0x9A,0xEB,0xED,0x78,0xEA,0x7E,0x71,0xE0,0xF5,0x76,0x87,0x61,0x8C,0x47,0xE6,0xB7,0x3A,0xB7,0x1F,0xA8,0x70,0x6F,0x24,0x5D,0xF7,0x43,0xDF,0xF7,0xA2,0xFD,0xBE,0xD7,0xC1,0x2B,0xCA,0x33,0x70,0x1D,0x34,0x26,0x80,0xCA,0x03,0xCA,0x91,0x80,0x99,0x7C,0x54,0x94,0xD7,0x42,0x44,0x1D,0x58,0xAD,0x0C,0x91,0xB4,0x13,0xD5,0xC3,0x12,0x83,0xC6,0xEA,0x0C,0xD3,0x75,0xB8,0x04,0xF5,0x4E,0x80,0x1E,0x7E,0xBD,0xFD,0x36,0x71,0x1D,0x24,0x3A,0x9E,0xF1,0x35,0x61,0xCF,0x73,0x25,0xAC,0x61,0x62,0x6A,0x83,0x79,0xAC,0xE9,0x6F,0xF5,0x49,0xB0,0x51,0xAE,0x13,0x26,0x48,0x6B,0x6E,0x12,0x6C,0x68,0x06,0x51,0x93,0xFA,0x38,0xB7,0xA3,0x08,0xE5,0x86,0xC6,0x8F,0x9F,0x30,0xC4,0xAE,0xDF,0xF7,0xFB,0xF6,0xBA,0x61,0xC9,0x5E,0xB4,0xA1,0xF1,0x6F,0xC1,0xA4,0xAF,0x7F,0x7E,0x7F,0xD4,0x0F,0x5E,0x8F,0xFB,0xA3,0xF1,0x6B,0x7C,0x70,0x36,0x0A,0xCD,0x13,0x7E,0xF9,0xDA,0x3C,0xD7,0xA1,0xFE,0x05,0x93,0x8F,0xD1,0x16,0x85,0x46,0xE1,0xEB,0x7E,0x10,0x8C,0xF1,0xC1,0xB7,0xEF,0xF7,0xC3,0xD0,0xBC,0xCC,0x14,0x97,0x35,0xD9,0xB2,0x84,0xE6,0x69,0xE6,0x1F,0x8D,0x41,0x29,0x17,0xE2,0x56,0x97,0x37,0x26,0xB3,0x6E,0xA5,0x8E,0x59,0x5D,0x00,0xF6,0xA9,0x1F,0xA9,0x5A,0xB9,0x5E,0x84,0x5D,0xDB,0xE5,0xB1,0x1F,0xF1,0xD9,0x86,0x0E,0x05,0xE4,0x4B,0xF4,0x8D,0x5F,0x5E,0x9A,0x1D,0xE2,0x71,0xEC,0xE3,0xE6,0xA0,0x44,0x56,0x3C,0xC0,0x5D,0xE1,0xBA,0x1B,0xFA,0x1B,0xFF,0x78,0x35,0xBA,0xF6,0xBD,0x97,0xD6,0x3B,0x77,0xFB,0x68,0x05,0xF7,0x0C,0x30,0xB7,0x8C,0x94,0x6E,0xA3,0x7F,0x59,0x6A,0xDF,0x6B,0x0D,0x3E,0xB1,0xAA,0xC9,0x63,0x6B,0x53,0xCB,0x61,0x42,0xEC,0xBE,0x0A,0x4F,0x30,0xDD,0x20,0xF4,0x2F,0xC3,0xE0,0x25,0xF7,0x4E,0x96,0xC3,0xF0,0xFA,0x64,0x1E,0x4C,0x4E,0xF5,0xF6,0x1A,0x0D,0x97,0x31,0xD6,0x49,0x84,0x5E,0xE3,0x6B,0xE6,0x5F,0x5C,0x34,0xCB,0x33,0x1D,0x02,0x5D,0x41,0xF8,0xBC,0x1C,0xE8,0x1E,0x6C,0x59,0xE6,0x47,0x96,0x39,0x16,0xD9,0x29,0x4F,0x27,0x4B,0x8F,0xB5,0x4C,0x99,0x4D,0x76,0x5D,0x49,0x9D,0x5A,0xF4,0x76,0x12,0x54,0x2D,0x73,0x44,0xD6,0xE9,0xB7,0x59,0xC9,0x38,0x87,0x35,0xF9,0xE5,0xFB,0x0F,0xEF,0x95,0x2A,0x7F,0x82,0xFF,0xD6,0x50,0x29,0x0C,0x09,0x12,0x86,0x45,0x09,0xB9,0xEB,0x7C,0xF3,0xEE,0xCE,0xE9,0x3B,0x57,0xCC,0xE2,0x7E,0x65,0x71,0x63,0xE7,0xD2,0x0E,0xFA,0x4A,0xD6,0x60,0xD9,0x2B,0x40,0xB5,0x5E,0xB7,0x66,0xB0,0x58,0x75,0x25,0xDE,0x62,0x53,0x06,0x57,0xB7,0x66,0xF0,0x76,0x67,0xCA,0x53,0x87,0xC1,0x50,0x4D,0x02,0x3C,0x69,0x25,0xFB,0x0E,0x3D,0x38,0xD2,0x2D,0xF9,0x84,0x1A,0x1E,0xA9,0xD7,0x2D,0xD5,0xD6,0x6D,0x87,0x69,0xE4,0x9D,0xEB,0x38,0x5D,0xB3,0xB1,0x18,0x6F,0xCD,0x39,0x72,0xA7,0xEB,0x91,0x9B,0x98,0x55,0xB5,0xC0,0xFB,0xFD,0x0D,0x9E,0x48,0x77,0xF8,0x55,0xE0,0xF4,0x6C,0x67,0xD5,0xC4,0xDE,0x8E,0xD1,0x0A,0x88,0xBF,0x09,0xFD,0xE9,0x89,0xC3,0x81,0x17,0xD9,0x58,0x13,0x2B,0x7E,0xE9,0xF0,0x4A,0x21,0xF8,0x1F,0xFF,0x4B,0xD3,0x1C,0xD4,0x10,0xAB,0xC3,0x0A,0x8E,0x1F,0x09,0xFA,0xCF,0x08,0x56,0x6C,0x25,0x8A,0x0A,0xC3,0x7C,0x14,0x9D,0x3C,0x12,0x0D,0xCF,0x8A,0x2A,0xE0,0xE2,0x8C,0x5E,0xFF,0x6F,0x09,0x87,0xA7,0xC2,0xA3,0x27,0xC2,0xDA,0x5C,0x0E,0x7F,0xFC,0xDE,0x15,0x0A,0xFE,0x4C,0xE8,0x54,0xCF,0x20,0x78,0x26,0x32,0xCE,0x3D,0x60,0xB5,0x77,0x4E,0x77,0xF2,0xA9,0xCE,0xF4,0xD6,0xA0,0x60,0x02,0x29,0x45,0xAC,0x69,0xC3,0x59,0xE7,0x0B,0xB8,0xA7,0xBA,0xDB,0x13,0xBB,0xAB,0x78,0xD7,0xBE,0xC4,0x6B,0x5F,0xB7,0x6C,0xEA,0x12,0x3F,0xB6,0xE0,0x06,0x3F,0xB8,0x9A,0x16,0xBF,0xC9,0xC4,0x0A,0xEB,0xE1,0x99,0xDA,0xB0,0xC4,0xA1,0xBE,0x2D,0xD0,0x64,0x6B,0xF2,0xAA,0x39,0x4B,0x5B,0x44,0x7B,0xE6,0xA8,0x15,0xAF,0x86,0x86,0xE7,0xD6,0xE6,0xDE,0xF8,0xE2,0xC2,0xAC,0xD9,0x6B,0x0A,0x26,0x2C,0x1E,0x5E,0xF6,0x48,0xB1,0x0B,0xDF,0xDD,0xFE,0xF0,0xAF,0x61,0xA9,0x3F,0x0C,0x5B,0xD9,0xAA,0x2C,0xF2,0x0A,0x74,0x22,0x7A,0x27,0x47,0xAA,0x15,0x18,0xE2,0x01,0x86,0xAE,0x3C,0x7F,0x18,0x19,0x2E,0xC7,0x1B,0x72,0x94,0x93,0xFA,0x73,0x37,0x3E,0x4D,0xEE,0x2E,0xCC,0x57,0xCD,0x44,0x97,0x90,0xF1,0x69,0x3A,0xC0,0x14,0x7E,0x16,0xDB,0x5C,0x13,0x10,0xBA,0xB9,0xEB,0xB7,0x16,0x09,0x9A,0x95,0x17,0x27,0xD6,0x1D,0x1A,0xCE,0xD3,0x2B,0xC1,0xFE,0x18,0xCB,0x6E,0xAF,0x69,0xCC,0x6E,0x7B,0x4B,0xC3,0x72,0xE8,0x2F,0x4D,0x49,0x77,0x37,0x2D,0xEA,0xDE,0x0B,0x8E,0x84,0xBE,0xFE,0x32,0xF1,0x22,0xBC,0xB8,0xD8,0x6B,0x0A,0xDE,0x9B,0xCC,0x7D,0xF3,0xCA,0x7C,0xF3,0xFF,0x1F,0xA6,0x8A,0x84,0xF0}; \ No newline at end of file diff --git a/HCPBridgeISR/src/main.cpp b/HCPBridgeISR/src/main.cpp new file mode 100644 index 0000000..47a90a7 --- /dev/null +++ b/HCPBridgeISR/src/main.cpp @@ -0,0 +1,169 @@ +#include +#include +#include "AsyncJson.h" +#include "ArduinoJson.h" +#include "hciemulator.h" +#include "index_html.h" + +/* create this file and add your wlan credentials + const char* ssid = "MyWLANSID"; + const char* password = "MYPASSWORD"; +*/ +#include "../../../private/credentials.h" + + +// switch relay sync to the lamp +// e.g. the Wifi Relay Board U4648 +#define USERELAY + +// use alternative uart pins +//#define SWAPUART + +#define RS485 Serial + +// Relay Board parameters +#define ESP8266_GPIO2 2 // Blue LED. +#define ESP8266_GPIO4 4 // Relay control. +#define ESP8266_GPIO5 5 // Optocoupler input. +#define LED_PIN ESP8266_GPIO2 + + +// webserver on port 80 +AsyncWebServer server(80); + +#ifdef USERELAY +// switch GPIO4 und GPIO2 sync to the lamp +void onStatusChanged(SHCIState* state){ + //see https://ucexperiment.wordpress.com/2016/12/18/yunshan-esp8266-250v-15a-acdc-network-wifi-relay-module/ + //Setting GPIO4 high, causes the relay to close the NO contact with + if(state->valid){ + digitalWrite( ESP8266_GPIO4, state->lampOn ); + digitalWrite(LED_PIN, state->lampOn); + }else + { + digitalWrite( ESP8266_GPIO4, false ); + digitalWrite(LED_PIN, false); + } +} +#else +void onStatusChanged(SHCIState* state){ +} +#endif + + + +// toggle lamp to expected state +void switchLamp(bool on){ + int lampon = getHCIState()->lampOn; + bool toggle = (on && !lampon) || (!on && lampon); + if(toggle){ + toggleLamp(); + } +} + +// setup mcu +void setup(){ + + //setup modbus + // Hörmann HCP2 based on modbus rtu @57.6kB 8E1 + uart0_open(57600,UART_FLAGS_8E1); + + //setup wifi + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + WiFi.setAutoReconnect(true); + while (WiFi.status() != WL_CONNECTED) { + delay(100); + } + + // setup http server + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ + AsyncWebServerResponse *response = request->beginResponse_P( 200, "text/html", index_html,sizeof(index_html)); + response->addHeader("Content-Encoding","deflate"); + request->send(response); + }); + + server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request){ + SHCIState *doorstate = getHCIState(); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + DynamicJsonDocument root(1024); + root["valid"] = doorstate->valid; + root["doorstate"] = doorstate->doorState; + root["doorposition"] = doorstate->doorCurrentPosition; + root["doortarget"] = doorstate->doorTargetPosition; + root["lamp"] = doorstate->lampOn; + root["debug"] = doorstate->reserved; + root["lastresponse"] = getMessageAge()/1000; + serializeJson(root,*response); + request->send(response); + }); + + server.on("/command", HTTP_GET, [] (AsyncWebServerRequest *request) { + if (request->hasParam("action")) { + int actionid = request->getParam("action")->value().toInt(); + switch (actionid){ + case 0: + closeDoor(); + break; + case 1: + openDoor(); + break; + case 2: + stopDoor(); + break; + case 3: + ventilationPosition(); + break; + case 4: + openDoorHalf(); + break; + case 5: + toggleLamp(); + break; + default: + break; + } + } + request->send(200, "text/plain", "OK"); + }); + + server.on("/update", HTTP_GET, [] (AsyncWebServerRequest *request) { + if (request->hasParam("channel") && request->hasParam("state")) { + String channel = request->getParam("channel")->value(); + String state = request->getParam("state")->value(); + if(channel.equals("door")){ + if(state=="1"){ + openDoor(); + }else{ + closeDoor(); + } + } + if(channel.equals("light")){ + switchLamp(state=="1"); + } + } + request->send(200, "text/plain", "OK"); + }); + + server.begin(); + + //setup relay board +#ifdef USERELAY + pinMode( ESP8266_GPIO4, OUTPUT ); // Relay control pin. + pinMode( ESP8266_GPIO5, INPUT_PULLUP ); // Input pin. + pinMode( LED_PIN, OUTPUT ); // ESP8266 module blue L + digitalWrite( ESP8266_GPIO4, 0 ); + digitalWrite(LED_PIN,0); +#endif + +} + +// mainloop +bool isLampOn = false; +void loop(){ + bool newisLampOn = getHCIState()->valid && getHCIState()->lampOn; + if(isLampOn!=newisLampOn){ + onStatusChanged(getHCIState()); + isLampOn = newisLampOn; + } +} \ No newline at end of file diff --git a/HCPBridgeISR/src/uart_register.h b/HCPBridgeISR/src/uart_register.h new file mode 100644 index 0000000..6398879 --- /dev/null +++ b/HCPBridgeISR/src/uart_register.h @@ -0,0 +1,128 @@ +//Generated at 2012-07-03 18:44:06 +/* + * Copyright (c) 2010 - 2011 Espressif System + * + */ + +#ifndef UART_REGISTER_H_INCLUDED +#define UART_REGISTER_H_INCLUDED +#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) +//version value:32'h062000 + +#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0) +#define UART_RXFIFO_RD_BYTE 0x000000FF +#define UART_RXFIFO_RD_BYTE_S 0 + +#define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4) +#define UART_RXFIFO_TOUT_INT_RAW (BIT(8)) +#define UART_BRK_DET_INT_RAW (BIT(7)) +#define UART_CTS_CHG_INT_RAW (BIT(6)) +#define UART_DSR_CHG_INT_RAW (BIT(5)) +#define UART_RXFIFO_OVF_INT_RAW (BIT(4)) +#define UART_FRM_ERR_INT_RAW (BIT(3)) +#define UART_PARITY_ERR_INT_RAW (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1)) +#define UART_RXFIFO_FULL_INT_RAW (BIT(0)) + +#define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8) +#define UART_RXFIFO_TOUT_INT_ST (BIT(8)) +#define UART_BRK_DET_INT_ST (BIT(7)) +#define UART_CTS_CHG_INT_ST (BIT(6)) +#define UART_DSR_CHG_INT_ST (BIT(5)) +#define UART_RXFIFO_OVF_INT_ST (BIT(4)) +#define UART_FRM_ERR_INT_ST (BIT(3)) +#define UART_PARITY_ERR_INT_ST (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ST (BIT(1)) +#define UART_RXFIFO_FULL_INT_ST (BIT(0)) + +#define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC) +#define UART_RXFIFO_TOUT_INT_ENA (BIT(8)) +#define UART_BRK_DET_INT_ENA (BIT(7)) +#define UART_CTS_CHG_INT_ENA (BIT(6)) +#define UART_DSR_CHG_INT_ENA (BIT(5)) +#define UART_RXFIFO_OVF_INT_ENA (BIT(4)) +#define UART_FRM_ERR_INT_ENA (BIT(3)) +#define UART_PARITY_ERR_INT_ENA (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1)) +#define UART_RXFIFO_FULL_INT_ENA (BIT(0)) + +#define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10) +#define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) +#define UART_BRK_DET_INT_CLR (BIT(7)) +#define UART_CTS_CHG_INT_CLR (BIT(6)) +#define UART_DSR_CHG_INT_CLR (BIT(5)) +#define UART_RXFIFO_OVF_INT_CLR (BIT(4)) +#define UART_FRM_ERR_INT_CLR (BIT(3)) +#define UART_PARITY_ERR_INT_CLR (BIT(2)) +#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1)) +#define UART_RXFIFO_FULL_INT_CLR (BIT(0)) + +#define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14) +#define UART_CLKDIV_CNT 0x000FFFFF +#define UART_CLKDIV_S 0 + +#define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18) +#define UART_GLITCH_FILT 0x000000FF +#define UART_GLITCH_FILT_S 8 +#define UART_AUTOBAUD_EN (BIT(0)) + +#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) +#define UART_TXD (BIT(31)) +#define UART_RTSN (BIT(30)) +#define UART_DTRN (BIT(29)) +#define UART_TXFIFO_CNT 0x000000FF +#define UART_TXFIFO_CNT_S 16 +#define UART_RXD (BIT(15)) +#define UART_CTSN (BIT(14)) +#define UART_DSRN (BIT(13)) +#define UART_RXFIFO_CNT 0x000000FF +#define UART_RXFIFO_CNT_S 0 + +#define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20) +#define UART_TXFIFO_RST (BIT(18)) +#define UART_RXFIFO_RST (BIT(17)) +#define UART_IRDA_EN (BIT(16)) +#define UART_TX_FLOW_EN (BIT(15)) +#define UART_LOOPBACK (BIT(14)) +#define UART_IRDA_RX_INV (BIT(13)) +#define UART_IRDA_TX_INV (BIT(12)) +#define UART_IRDA_WCTL (BIT(11)) +#define UART_IRDA_TX_EN (BIT(10)) +#define UART_IRDA_DPLX (BIT(9)) +#define UART_TXD_BRK (BIT(8)) +#define UART_SW_DTR (BIT(7)) +#define UART_SW_RTS (BIT(6)) +#define UART_STOP_BIT_NUM 0x00000003 +#define UART_STOP_BIT_NUM_S 4 +#define UART_BIT_NUM 0x00000003 +#define UART_BIT_NUM_S 2 +#define UART_PARITY_EN (BIT(1)) +#define UART_PARITY (BIT(0)) + +#define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24) +#define UART_RX_TOUT_EN (BIT(31)) +#define UART_RX_TOUT_THRHD 0x0000007F +#define UART_RX_TOUT_THRHD_S 24 +#define UART_RX_FLOW_EN (BIT(23)) +#define UART_RX_FLOW_THRHD 0x0000007F +#define UART_RX_FLOW_THRHD_S 16 +#define UART_TXFIFO_EMPTY_THRHD 0x0000007F +#define UART_TXFIFO_EMPTY_THRHD_S 8 +#define UART_RXFIFO_FULL_THRHD 0x0000007F +#define UART_RXFIFO_FULL_THRHD_S 0 + +#define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28) +#define UART_LOWPULSE_MIN_CNT 0x000FFFFF +#define UART_LOWPULSE_MIN_CNT_S 0 + +#define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C) +#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF +#define UART_HIGHPULSE_MIN_CNT_S 0 + +#define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30) +#define UART_PULSE_NUM_CNT 0x0003FF +#define UART_PULSE_NUM_CNT_S 0 + +#define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78) +#define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C) +#endif // UART_REGISTER_H_INCLUDED diff --git a/HCPBridgeISR/src/webpage/buildindex.cmd b/HCPBridgeISR/src/webpage/buildindex.cmd new file mode 100644 index 0000000..6ed0ebd --- /dev/null +++ b/HCPBridgeISR/src/webpage/buildindex.cmd @@ -0,0 +1 @@ +python compress.py diff --git a/HCPBridgeISR/src/webpage/command b/HCPBridgeISR/src/webpage/command new file mode 100644 index 0000000..e69de29 diff --git a/HCPBridgeISR/src/webpage/compress.py b/HCPBridgeISR/src/webpage/compress.py new file mode 100644 index 0000000..5e9faa8 --- /dev/null +++ b/HCPBridgeISR/src/webpage/compress.py @@ -0,0 +1,35 @@ +#pip install htmlmin +#or python -m pip install htmlmin +#pip install jsmin +#or python -m pip install jsmin + +import gzip +import zlib +import htmlmin +from jsmin import jsmin + + + +content = "" +with open('index.html','rt',encoding="utf-8") as f: + content=f.read() + + +content = htmlmin.minify(content, remove_comments=True, remove_empty_space=True, remove_all_empty_space=True, reduce_empty_attributes=True, reduce_boolean_attributes=False, remove_optional_attribute_quotes=True, convert_charrefs=True, keep_pre=False) + + +import re +regex = r"" ,content, 0, re.DOTALL) + +result ="" +for c in zlib.compress(content.encode("UTF-8"),9): + result= result + ("0x%02X" %c) + if len(result)> 0: + result=result + "," + + +with open('../index_html.h',"wt") as f: + f.write("const uint8_t index_html[] PROGMEM = {"); + f.write(result.strip(",")) + f.write("};"); \ No newline at end of file diff --git a/HCPBridgeISR/src/webpage/index.html b/HCPBridgeISR/src/webpage/index.html new file mode 100644 index 0000000..303cbef --- /dev/null +++ b/HCPBridgeISR/src/webpage/index.html @@ -0,0 +1,159 @@ + + + Garagentor Steuerung + + + + + + +

Garagentor

+ +

warte auf Verbindung.

+ +
+ +
+

Licht

+
+ + + + \ No newline at end of file diff --git a/HCPBridgeISR/src/webpage/runtestserver.cmd b/HCPBridgeISR/src/webpage/runtestserver.cmd new file mode 100644 index 0000000..092262b --- /dev/null +++ b/HCPBridgeISR/src/webpage/runtestserver.cmd @@ -0,0 +1 @@ +python -m http.server diff --git a/HCPBridgeISR/src/webpage/status b/HCPBridgeISR/src/webpage/status new file mode 100644 index 0000000..c050664 --- /dev/null +++ b/HCPBridgeISR/src/webpage/status @@ -0,0 +1,9 @@ +{ + "valid" : true, + "doorstate" : 1, + "doorposition" : 0, + "doortarget" : 0, + "lamp" : true, + "debug" : 0, + "lastresponse" : 0 +} \ No newline at end of file diff --git a/HCPBridgeISR/test/README b/HCPBridgeISR/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/HCPBridgeISR/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/README.md b/README.md index 06ab56b..0f03171 100644 --- a/README.md +++ b/README.md @@ -74,4 +74,4 @@ Zwischen A+ (Red) und B- (Green) ist ein 120 Ohm Widerstand zum terminieren des - Busscan aussführen (blauer Pfeil auf off und wieder zurück auf on). Der Adapter bekommt erst dann Strom über die 25V Leitung und muss während des Busscans antworten, sonst wird der Strom wieder abgeschaltet. Im Falle eines Fehlers oder wenn der Adapter abgezogen werden soll, einfach die Busscan Prozedur (On/Off) wiederholen. ## Changelog -TODO +24.02.2021: Neue Version via Interrupt und für ESP32 zur Vermeidung von Timing-Problemen