Neue Version via Interrupt und für ESP32 zur Vermeidung von Timing-Problemen
HCPBridgeISR für ESP8266 HCPBridgeESP32 für ESP32 HCPBridge nicht mehr nutzen!
This commit is contained in:
5
HCPBridgeISR/.gitignore
vendored
Normal file
5
HCPBridgeISR/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
7
HCPBridgeISR/.vscode/extensions.json
vendored
Normal file
7
HCPBridgeISR/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
13
HCPBridgeISR/.vscode/settings.json
vendored
Normal file
13
HCPBridgeISR/.vscode/settings.json
vendored
Normal file
@ -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"
|
||||
}
|
||||
}
|
39
HCPBridgeISR/include/README
Normal file
39
HCPBridgeISR/include/README
Normal file
@ -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
|
46
HCPBridgeISR/lib/README
Normal file
46
HCPBridgeISR/lib/README
Normal file
@ -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 <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
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
|
17
HCPBridgeISR/platformio.ini
Normal file
17
HCPBridgeISR/platformio.ini
Normal file
@ -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
|
18
HCPBridgeISR/simulator/hcisim.py
Normal file
18
HCPBridgeISR/simulator/hcisim.py
Normal file
@ -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))
|
21
HCPBridgeISR/src/LICENSE
Normal file
21
HCPBridgeISR/src/LICENSE
Normal file
@ -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.
|
10
HCPBridgeISR/src/README.md
Normal file
10
HCPBridgeISR/src/README.md
Normal file
@ -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.
|
44
HCPBridgeISR/src/crc.c
Normal file
44
HCPBridgeISR/src/crc.c
Normal file
@ -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;
|
||||
}
|
22
HCPBridgeISR/src/crc.h
Normal file
22
HCPBridgeISR/src/crc.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __crc_h
|
||||
#define __crc_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
//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
|
511
HCPBridgeISR/src/hciemulator.c
Normal file
511
HCPBridgeISR/src/hciemulator.c
Normal file
@ -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<millis()){
|
||||
txbuffer[7]= 0x01;
|
||||
txbuffer[8]= 0x10;
|
||||
statemachine = WAITING;
|
||||
}
|
||||
break;
|
||||
|
||||
// close Door
|
||||
case STARTCLOSEDOOR:
|
||||
txbuffer[7]= 0x02;
|
||||
txbuffer[8]= 0x20;
|
||||
statemachine = STARTCLOSEDOOR_RELEASE;
|
||||
lastStateTime = millis();
|
||||
break;
|
||||
case STARTCLOSEDOOR_RELEASE:
|
||||
if(lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
||||
txbuffer[7]= 0x01;
|
||||
txbuffer[8]= 0x20;
|
||||
statemachine = WAITING;
|
||||
}
|
||||
break;
|
||||
|
||||
// stop Door
|
||||
case STARTSTOPDOOR:
|
||||
txbuffer[7]= 0x02;
|
||||
txbuffer[8]= 0x40;
|
||||
statemachine = STARTSTOPDOOR_RELEASE;
|
||||
lastStateTime = millis();
|
||||
break;
|
||||
case STARTSTOPDOOR_RELEASE:
|
||||
if(lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
||||
txbuffer[7]= 0x01;
|
||||
txbuffer[8]= 0x40;
|
||||
statemachine = WAITING;
|
||||
}
|
||||
break;
|
||||
|
||||
// Ventilation
|
||||
case STARTVENTPOSITION:
|
||||
txbuffer[7]= 0x02;
|
||||
txbuffer[9]= 0x40;
|
||||
statemachine = STARTVENTPOSITION_RELEASE;
|
||||
lastStateTime = millis();
|
||||
break;
|
||||
case STARTVENTPOSITION_RELEASE:
|
||||
if(lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
||||
txbuffer[7]= 0x01;
|
||||
txbuffer[9]= 0x40;
|
||||
statemachine = WAITING;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// Half Position
|
||||
case STARTOPENDOORHALF:
|
||||
txbuffer[7]= 0x02;
|
||||
txbuffer[9]= 0x04;
|
||||
statemachine = STARTOPENDOORHALF_RELEASE;
|
||||
lastStateTime = millis();
|
||||
break;
|
||||
|
||||
case STARTOPENDOORHALF_RELEASE:
|
||||
if(lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
||||
txbuffer[7]= 0x01;
|
||||
txbuffer[9]= 0x04;
|
||||
statemachine = WAITING;
|
||||
}
|
||||
break;
|
||||
|
||||
// Toggle Lamp
|
||||
case STARTTOGGLELAMP:
|
||||
txbuffer[7]= 0x10;
|
||||
txbuffer[9]= 0x02;
|
||||
statemachine = STARTTOGGLELAMP_RELEASE;
|
||||
lastStateTime = millis();
|
||||
break;
|
||||
case STARTTOGGLELAMP_RELEASE:
|
||||
if(lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
||||
txbuffer[7]= 0x08;
|
||||
txbuffer[9]= 0x02;
|
||||
statemachine = WAITING;
|
||||
}
|
||||
break;
|
||||
|
||||
case WAITING:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if(rxbuffer[5] == 0x02){
|
||||
// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
|
||||
//0011: 02 17 9C B9 00 02 9C 41 00 02 04 0F 04 17 00 7B 21
|
||||
//res=> 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<millis()){
|
||||
statemachine = WAITING;
|
||||
}
|
||||
|
||||
if(!processFrame()){
|
||||
return;
|
||||
}
|
||||
|
||||
rxlen = 0;
|
||||
|
||||
// prepare response fix crc
|
||||
if(txlen > 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; i<uart0_rxfifo_len; i++) {
|
||||
if (rxlen < sizeof(rxbuffer)) {
|
||||
rxbuffer[rxlen++] = UART_RXFIFO_GET(UART0);
|
||||
}else{
|
||||
// buffer overflow!!!
|
||||
skipFrame = true;
|
||||
UART_RXFIFO_GET(UART0);
|
||||
}
|
||||
recvTime = micros();
|
||||
}
|
||||
|
||||
if(!skipFrame && rxlen>0){
|
||||
processMessage();
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static uint16
|
||||
uart0_send()
|
||||
{
|
||||
uint16 i;
|
||||
for (i=UART_TXFIFO_LEN(UART0); i<UART_TXFIFO_SIZE; i++) {
|
||||
if (txpos==txlen) {
|
||||
txpos=txlen=0;
|
||||
CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
|
||||
break;
|
||||
}
|
||||
UART_TXFIFO_PUT(UART0, txbuffer[txpos++]);
|
||||
lastSendTime = micros()-recvTime;
|
||||
}
|
||||
return i-1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
uart0_intr_handler(void *arg)
|
||||
{
|
||||
uint32 uart0_status;
|
||||
uart0_status = READ_PERI_REG(UART_INT_ST(UART0));
|
||||
if (uart0_status & UART_RXFIFO_TOUT_INT_ST) {
|
||||
// No character received for some time, read to ringbuf
|
||||
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_ST);
|
||||
uart0_receive();
|
||||
|
||||
} else if (uart0_status & UART_RXFIFO_FULL_INT_ST) {
|
||||
// RX buffer becoming full,
|
||||
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_ST);
|
||||
uart0_receive();
|
||||
|
||||
} else if (uart0_status & UART_TXFIFO_EMPTY_INT_ST) {
|
||||
// TX buffer empty, check if ringbuf has space or disable int
|
||||
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_TXFIFO_EMPTY_INT_ST);
|
||||
uart0_send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
uart0_open(uint32 baud_rate, uint32 flags)
|
||||
{
|
||||
uint32 clkdiv;
|
||||
|
||||
ETS_UART_INTR_DISABLE();
|
||||
|
||||
// Set both RX and TX pins to correct mode
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
|
||||
|
||||
// Disable pullup on TX pin, enable on RX pin
|
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
|
||||
PIN_PULLUP_EN(PERIPHS_IO_MUX_U0RXD_U);
|
||||
|
||||
// Configure baud rate for the port
|
||||
clkdiv = (UART_CLK_FREQ / baud_rate) & UART_CLKDIV_CNT;
|
||||
WRITE_PERI_REG(UART_CLKDIV(UART0), clkdiv);
|
||||
|
||||
// Configure parameters for the port
|
||||
WRITE_PERI_REG(UART_CONF0(UART0), flags);
|
||||
|
||||
// Reset UART0
|
||||
uart0_reset(baud_rate, flags);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
uart0_reset()
|
||||
{
|
||||
// Disable interrupts while resetting UART0
|
||||
ETS_UART_INTR_DISABLE();
|
||||
|
||||
// Clear all RX and TX buffers and flags
|
||||
SET_PERI_REG_MASK(UART_CONF0(UART0), UART_RXFIFO_RST | UART_TXFIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(UART_CONF0(UART0), UART_RXFIFO_RST | UART_TXFIFO_RST);
|
||||
|
||||
// Set RX and TX interrupt thresholds
|
||||
WRITE_PERI_REG(UART_CONF1(UART0),
|
||||
UART_RX_TOUT_EN |
|
||||
((UART_RXTOUT_TH & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S) |
|
||||
((UART_RXFIFO_TH & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
|
||||
((UART_TXFIFO_TH & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S));
|
||||
|
||||
// Disable all existing interrupts and enable ours
|
||||
WRITE_PERI_REG(UART_INT_CLR(UART0), 0xffff);
|
||||
SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_RXFIFO_TOUT_INT_ENA);
|
||||
SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_RXFIFO_FULL_INT_ENA);
|
||||
|
||||
// Restart the interrupt handler for UART0
|
||||
ETS_UART_INTR_ATTACH(uart0_intr_handler, NULL);
|
||||
ETS_UART_INTR_ENABLE();
|
||||
|
||||
|
||||
state.valid = false;
|
||||
}
|
113
HCPBridgeISR/src/hciemulator.h
Normal file
113
HCPBridgeISR/src/hciemulator.h
Normal file
@ -0,0 +1,113 @@
|
||||
/* 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.
|
||||
*/
|
||||
#ifndef ESP_UART_H
|
||||
#define ESP_UART_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <c_types.h>
|
||||
|
||||
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
|
1
HCPBridgeISR/src/index_html.h
Normal file
1
HCPBridgeISR/src/index_html.h
Normal file
File diff suppressed because one or more lines are too long
169
HCPBridgeISR/src/main.cpp
Normal file
169
HCPBridgeISR/src/main.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
#include <Arduino.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#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;
|
||||
}
|
||||
}
|
128
HCPBridgeISR/src/uart_register.h
Normal file
128
HCPBridgeISR/src/uart_register.h
Normal file
@ -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
|
1
HCPBridgeISR/src/webpage/buildindex.cmd
Normal file
1
HCPBridgeISR/src/webpage/buildindex.cmd
Normal file
@ -0,0 +1 @@
|
||||
python compress.py
|
0
HCPBridgeISR/src/webpage/command
Normal file
0
HCPBridgeISR/src/webpage/command
Normal file
35
HCPBridgeISR/src/webpage/compress.py
Normal file
35
HCPBridgeISR/src/webpage/compress.py
Normal file
@ -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"<script>(.+?)<\/script>"
|
||||
content = re.sub(regex, lambda x: "<script>"+jsmin(x.group(1))+"</script>" ,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("};");
|
159
HCPBridgeISR/src/webpage/index.html
Normal file
159
HCPBridgeISR/src/webpage/index.html
Normal file
@ -0,0 +1,159 @@
|
||||
<!DOCTYPE HTML><html>
|
||||
<head>
|
||||
<title>Garagentor Steuerung</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="data:,">
|
||||
<style>
|
||||
html {font-family: Arial; display: inline-block; text-align: center;}
|
||||
h2 {font-size: 3.0rem;}
|
||||
p {font-size: 3.0rem;}
|
||||
body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
|
||||
.switch {position: relative; display: inline-block; width: 80px; height: 48px}
|
||||
.switch input {display: none}
|
||||
.slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 6px}
|
||||
.slider:before {position: absolute; content: ""; height: 32px; width: 32px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 3px}
|
||||
input:checked+.slider {background-color: #b30000}
|
||||
input:checked+.slider:before {-webkit-transform: translateX(32px); -ms-transform: translateX(32px); transform: translateX(32px)}
|
||||
|
||||
.button {
|
||||
border: 4px;
|
||||
border-style: solid;
|
||||
color: black;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
text-align: center;
|
||||
display: inline;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
margin: 4px 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 50px;
|
||||
}
|
||||
.buttonred {border-color: #ED5961;}
|
||||
.buttonyellow {border-color: #fcca00;}
|
||||
.buttongreen {border-color: #48bd81;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Garagentor</h2>
|
||||
<canvas width="250px" height="250px" id="dc"></canvas>
|
||||
<h3 id="status">warte auf Verbindung.</h3>
|
||||
|
||||
<hr/>
|
||||
<button class="button buttonred" onclick="doCommand(1)">Auf</button> <button class="button buttonyellow" onclick="doCommand(2)">Stop</button> <button class="button buttongreen" onclick="doCommand(0)">Zu</button>
|
||||
<hr/>
|
||||
<h4>Licht</h4><label class="switch"><input type="checkbox" onchange="doCommand(5)" id="light"><span class="slider"></span></label>
|
||||
<hr/>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
doorpos = 10;
|
||||
dir = -1;
|
||||
isconnected = false;
|
||||
var animation;
|
||||
function startDoorAnimation() {
|
||||
if(!animation){
|
||||
animation = setInterval(Draw, 200);
|
||||
}
|
||||
|
||||
}
|
||||
function stopDoorAnimation() {
|
||||
if(animation){
|
||||
clearInterval(animation);
|
||||
}
|
||||
animation = null;
|
||||
}
|
||||
|
||||
function Draw(){
|
||||
var svg =document.getElementById("svg");
|
||||
var dc = document.getElementById("dc");
|
||||
var ctx = dc.getContext("2d");
|
||||
width = dc.width;
|
||||
height = dc.height;
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
xa= [18,18,10,3,174,347,340,332,332,297,297,52,52,18];
|
||||
ya= [327,114,117,100,22,100,117,114,327,327,112,112,327,327];
|
||||
|
||||
ctx.fillStyle = "black";
|
||||
ctx.beginPath();
|
||||
for (i =0;i<xa.length;i++){
|
||||
if(i==0){
|
||||
ctx.moveTo((xa[i]/350) * width , (ya[i]/350)*width);
|
||||
}else{
|
||||
ctx.lineTo((xa[i]/350) * width, (ya[i]/350)*width);
|
||||
}
|
||||
}
|
||||
ctx.fill();
|
||||
|
||||
for(i=0;i<doorpos;i++){
|
||||
ctx.fillRect((62/350) * width, ((120+21*i)/350) * width, (225/350) * width, (18/350) * width);
|
||||
}
|
||||
doorpos+=dir;
|
||||
|
||||
if(dir<0 && doorpos<=0){
|
||||
dir=dir*-1;
|
||||
}
|
||||
if(dir>0 &&doorpos>=10){
|
||||
dir=dir*-1;
|
||||
}
|
||||
}
|
||||
|
||||
function doCommand(action) {
|
||||
if(!isconnected){return;}
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/command?action="+action, true);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function setDoorState(state){
|
||||
stopDoorAnimation();
|
||||
if(state == 0) {doorpos = 10;dir = -1};
|
||||
if(state == 1) {doorpos = 0; dir = 1};
|
||||
if(state == 2) {doorpos = 5; dir = 1};
|
||||
Draw();
|
||||
if(state == 3) startDoorAnimation();
|
||||
}
|
||||
|
||||
function getStatusText(id){
|
||||
result = "Das Tor "
|
||||
switch(id)
|
||||
{
|
||||
case 0x20: setDoorState(1); return result+"ist geöffnet.";
|
||||
case 0x40: setDoorState(0); return result+"ist geschlossen.";
|
||||
case 0x80: setDoorState(2); return result+"ist teilgeöffnet.";
|
||||
case 0x00: setDoorState(2); return result+"ist teilgeöffnet.";
|
||||
case 0x02: setDoorState(3); return result+"schließt.";
|
||||
case 0x01: setDoorState(3); return result+"öffnet.";
|
||||
case -1: setDoorState(0); return "keine Verbindung zum Tor.";
|
||||
default: return "unbekanter Status: " + id;
|
||||
}
|
||||
}
|
||||
|
||||
function updateData(){
|
||||
var xmlhttp = new XMLHttpRequest();
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
var status = JSON.parse(this.responseText);
|
||||
isconnected = status.valid;
|
||||
document.getElementById("status").innerHTML = getStatusText(status.valid?status.doorstate:-1);
|
||||
document.getElementById("light").checked = status.lamp & status.valid;
|
||||
return;
|
||||
}
|
||||
isconnected= false;
|
||||
};
|
||||
xmlhttp.open("GET", "/status", true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
Draw();
|
||||
updateData();
|
||||
setInterval(updateData, 3000);
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
1
HCPBridgeISR/src/webpage/runtestserver.cmd
Normal file
1
HCPBridgeISR/src/webpage/runtestserver.cmd
Normal file
@ -0,0 +1 @@
|
||||
python -m http.server
|
9
HCPBridgeISR/src/webpage/status
Normal file
9
HCPBridgeISR/src/webpage/status
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"valid" : true,
|
||||
"doorstate" : 1,
|
||||
"doorposition" : 0,
|
||||
"doortarget" : 0,
|
||||
"lamp" : true,
|
||||
"debug" : 0,
|
||||
"lastresponse" : 0
|
||||
}
|
11
HCPBridgeISR/test/README
Normal file
11
HCPBridgeISR/test/README
Normal file
@ -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
|
Reference in New Issue
Block a user