Initial working
Signed-off-by: Lukas Bachschwell <lukas@lbsfilm.at>
This commit is contained in:
parent
6017cafad1
commit
3356acdf78
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
HCPBridge/.vscode
|
HCPBridge/.vscode
|
||||||
|
HCPBridgeESP32/src/credentials.h
|
||||||
Investigation/bussniffer/tools/opendooralert/opendooralert.py.bak
|
Investigation/bussniffer/tools/opendooralert/opendooralert.py.bak
|
||||||
tools/opendooralert/opendooralert.py.bak
|
tools/opendooralert/opendooralert.py.bak
|
||||||
|
@ -1,43 +1,56 @@
|
|||||||
#include "hciemulator.h"
|
#include "hciemulator.h"
|
||||||
#define CHECKCHANGEDSET(Target,Value,Flag) if((Target)!=(Value)){Target=Value;Flag=true;}
|
#define CHECKCHANGEDSET(Target, Value, Flag) \
|
||||||
|
if ((Target) != (Value)) \
|
||||||
|
{ \
|
||||||
|
Target = Value; \
|
||||||
|
Flag = true; \
|
||||||
|
}
|
||||||
int hciloglevel = DEFAULTLOGLEVEL;
|
int hciloglevel = DEFAULTLOGLEVEL;
|
||||||
|
|
||||||
|
#define SOFTSERIAL 1
|
||||||
|
|
||||||
#ifdef SOFTSERIAL
|
#ifdef SOFTSERIAL
|
||||||
#define Log(Level,Message) LogCore(Level,Message)
|
#define Log(Level, Message) LogCore(Level, Message)
|
||||||
#define Log3(Level,Message,Buffer, Len) LogCore(Level,Message,Buffer,Len)
|
#define Log3(Level, Message, Buffer, Len) LogCore(Level, Message, Buffer, Len)
|
||||||
//LOGLEVEL
|
// LOGLEVEL
|
||||||
void LogCore(int Level, const char* msg, const unsigned char * data=NULL, size_t datalen=0){
|
void LogCore(int Level, const char *msg, const unsigned char *data = NULL, size_t datalen = 0)
|
||||||
if(Level>hciloglevel){
|
{
|
||||||
|
if (Level > hciloglevel)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(data!=NULL && datalen>0){
|
if (data != NULL && datalen > 0)
|
||||||
|
{
|
||||||
String newmsg(msg);
|
String newmsg(msg);
|
||||||
char str[4];
|
char str[4];
|
||||||
for (size_t i = 0; i < datalen; i++){
|
for (size_t i = 0; i < datalen; i++)
|
||||||
snprintf(str,sizeof(str),"%02x ", data[i]);
|
{
|
||||||
newmsg+=str;
|
snprintf(str, sizeof(str), "%02x ", data[i]);
|
||||||
|
newmsg += str;
|
||||||
}
|
}
|
||||||
Serial.println(newmsg);
|
Serial.println(newmsg);
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Serial.println(msg);
|
Serial.println(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define Log(Level,Message)
|
#define Log(Level, Message)
|
||||||
#define Log3(Level,Message,Buffer, Len)
|
#define Log3(Level, Message, Buffer, Len)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int HCIEmulator::getLogLevel()
|
||||||
int HCIEmulator::getLogLevel(){
|
{
|
||||||
return hciloglevel;
|
return hciloglevel;
|
||||||
|
|
||||||
}
|
}
|
||||||
void HCIEmulator::setLogLevel(int level){
|
void HCIEmulator::setLogLevel(int level)
|
||||||
hciloglevel=level;
|
{
|
||||||
|
hciloglevel = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
//modbus crc calculation borrowed from:
|
// modbus crc calculation borrowed from:
|
||||||
//https://github.com/yaacov/ArduinoModbusSlave
|
// https://github.com/yaacov/ArduinoModbusSlave
|
||||||
#define MODBUS_CRC_LENGTH 2
|
#define MODBUS_CRC_LENGTH 2
|
||||||
#define readCRC(arr, length) word(arr[(length - MODBUS_CRC_LENGTH) + 1], arr[length - MODBUS_CRC_LENGTH])
|
#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])
|
#define readUInt16(arr, index) word(arr[index], arr[index + 1])
|
||||||
@ -48,13 +61,13 @@ void HCIEmulator::setLogLevel(int level){
|
|||||||
* @param length The length of the byte array.
|
* @param length The length of the byte array.
|
||||||
*
|
*
|
||||||
* @return The calculated CRC as an unsigned 16 bit integer.
|
* @return The calculated CRC as an unsigned 16 bit integer.
|
||||||
*
|
*
|
||||||
* Calculate and add the CRC.
|
* Calculate and add the CRC.
|
||||||
* uint16_t crc = Modbus::calculateCRC(_responseBuffer, _responseBufferLength - MODBUS_CRC_LENGTH);
|
* uint16_t crc = Modbus::calculateCRC(_responseBuffer, _responseBufferLength - MODBUS_CRC_LENGTH);
|
||||||
* _responseBuffer[_responseBufferLength - MODBUS_CRC_LENGTH] = crc & 0xFF;
|
* _responseBuffer[_responseBufferLength - MODBUS_CRC_LENGTH] = crc & 0xFF;
|
||||||
* _responseBuffer[(_responseBufferLength - MODBUS_CRC_LENGTH) + 1] = crc >> 8;
|
* _responseBuffer[(_responseBufferLength - MODBUS_CRC_LENGTH) + 1] = crc >> 8;
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* #define MODBUS_FRAME_SIZE 4
|
* #define MODBUS_FRAME_SIZE 4
|
||||||
* #define MODBUS_CRC_LENGTH 2
|
* #define MODBUS_CRC_LENGTH 2
|
||||||
* uint16_t crc = readCRC(_requestBuffer, _requestBufferLength);
|
* uint16_t crc = readCRC(_requestBuffer, _requestBufferLength);
|
||||||
@ -84,342 +97,396 @@ uint16_t calculateCRC(uint8_t *buffer, int length)
|
|||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
HCIEmulator::HCIEmulator(Stream * port) {
|
HCIEmulator::HCIEmulator(Stream *port)
|
||||||
m_state.valid = false;
|
{
|
||||||
m_statemachine=WAITING;
|
m_state.valid = false;
|
||||||
|
m_statemachine = WAITING;
|
||||||
m_rxlen = m_txlen = 0;
|
m_rxlen = m_txlen = 0;
|
||||||
m_recvTime=m_lastStateTime=0;
|
m_recvTime = m_lastStateTime = 0;
|
||||||
m_skipFrame=false;
|
m_skipFrame = false;
|
||||||
m_port = port;
|
m_port = port;
|
||||||
m_statusCallback = NULL;
|
m_statusCallback = NULL;
|
||||||
setLogLevel(DEFAULTLOGLEVEL);
|
setLogLevel(DEFAULTLOGLEVEL);
|
||||||
};
|
};
|
||||||
|
|
||||||
void HCIEmulator::poll(){
|
#define TX_ON 25
|
||||||
|
|
||||||
if(m_port==NULL) return;
|
void HCIEmulator::poll()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (m_port == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
// receive Data
|
// receive Data
|
||||||
if(m_port->available() >0)
|
if (m_port->available() > 0)
|
||||||
{
|
{
|
||||||
m_rxlen+= m_port->readBytes((char*)(m_rxbuffer+m_rxlen), _min((int)(255-m_rxlen),m_port->available()));
|
// Serial.println("got data");
|
||||||
if(m_rxlen > 254)
|
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");
|
Log(LL_ERROR, "RX Bufferoverflow, skip next Frame");
|
||||||
Log3(LL_DEBUG,"Buffer Data: ", m_rxbuffer, m_rxlen);
|
Log3(LL_DEBUG, "Buffer Data: ", m_rxbuffer, m_rxlen);
|
||||||
m_rxlen=0;
|
m_rxlen = 0;
|
||||||
m_skipFrame = true;
|
m_skipFrame = true;
|
||||||
}
|
}
|
||||||
m_recvTime = micros();
|
m_recvTime = micros();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// check frame, process frame
|
// Serial.printf("Data % x\n", m_txbuffer);
|
||||||
if(m_rxlen>0 && (micros()-m_recvTime > T3_5))
|
// check frame, process frame
|
||||||
|
if (m_rxlen > 0 && (micros() - m_recvTime > T3_5))
|
||||||
{
|
{
|
||||||
// check last action timeout -> reset > then 2sec
|
// Serial.printf("Act on it % x\n", m_txbuffer);
|
||||||
if(m_statemachine!= WAITING && m_lastStateTime+2000<millis()){
|
// check last action timeout -> reset > then 2sec
|
||||||
|
if (m_statemachine != WAITING && m_lastStateTime + 2000 < millis())
|
||||||
|
{
|
||||||
m_statemachine = WAITING;
|
m_statemachine = WAITING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!m_skipFrame){
|
if (!m_skipFrame)
|
||||||
|
{
|
||||||
|
|
||||||
processFrame();
|
processFrame();
|
||||||
|
|
||||||
// send response
|
// send response
|
||||||
if(m_txlen > 0){
|
if (m_txlen > 0)
|
||||||
|
{
|
||||||
// fix crc
|
// fix crc
|
||||||
uint16_t crc = calculateCRC(m_txbuffer, m_txlen - MODBUS_CRC_LENGTH);
|
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] = crc & 0xFF;
|
||||||
m_txbuffer[(m_txlen - MODBUS_CRC_LENGTH) + 1] = crc >> 8;
|
m_txbuffer[(m_txlen - MODBUS_CRC_LENGTH) + 1] = crc >> 8;
|
||||||
|
|
||||||
// send data
|
// send data
|
||||||
m_lastSendTime = micros()-m_recvTime;
|
m_lastSendTime = micros() - m_recvTime;
|
||||||
|
|
||||||
//Log(LL_DEBUG, ("ST:"+String(m_lastSendTime)).c_str());
|
// Log(LL_DEBUG, ("ST:"+String(m_lastSendTime)).c_str());
|
||||||
|
|
||||||
|
digitalWrite(TX_ON, HIGH);
|
||||||
|
delayMicroseconds(10);
|
||||||
|
Serial.println("write data");
|
||||||
m_port->write(m_txbuffer, m_txlen);
|
m_port->write(m_txbuffer, m_txlen);
|
||||||
Log3(LL_DEBUG,"Response: ", m_txbuffer, m_txlen);
|
Log3(LL_DEBUG, "Response: ", m_txbuffer, m_txlen);
|
||||||
|
// delayMicroseconds(50);
|
||||||
|
digitalWrite(TX_ON, LOW);
|
||||||
m_txlen = 0;
|
m_txlen = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("skipped frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_skipFrame = false;
|
m_skipFrame = false;
|
||||||
m_rxlen=0;
|
m_rxlen = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HCIEmulator::processFrame(){
|
void HCIEmulator::processFrame()
|
||||||
m_txlen = 0; // clear send buffer
|
{
|
||||||
|
m_txlen = 0; // clear send buffer
|
||||||
|
|
||||||
if(m_rxlen<5) {
|
if (m_rxlen < 5)
|
||||||
Log(LL_ERROR,"Frame skipped, invalid frame len");
|
{
|
||||||
Log3(LL_ERROR,"Data:", m_rxbuffer,m_rxlen);
|
Log(LL_ERROR, "Frame skipped, invalid frame len");
|
||||||
|
Log3(LL_ERROR, "Data:", m_rxbuffer, m_rxlen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check device id, pass only device id 2 and 0 (broadcast)
|
// check device id, pass only device id 2 and 0 (broadcast)
|
||||||
if(m_rxbuffer[0] != BROADCASTID && m_rxbuffer[0] != DEVICEID){
|
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);
|
Log(LL_DEBUG, "Frame skipped, unsupported device id");
|
||||||
|
Log3(LL_DEBUG, "Data:", m_rxbuffer, m_rxlen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check crc
|
// check crc
|
||||||
uint16_t crc = readCRC(m_rxbuffer, m_rxlen);
|
uint16_t crc = readCRC(m_rxbuffer, m_rxlen);
|
||||||
if(crc != calculateCRC(m_rxbuffer,m_rxlen-MODBUS_CRC_LENGTH)){
|
if (crc != calculateCRC(m_rxbuffer, m_rxlen - MODBUS_CRC_LENGTH))
|
||||||
Log3(LL_ERROR,"Frame skipped, wrong crc", m_rxbuffer,m_rxlen);
|
{
|
||||||
|
Log3(LL_ERROR, "Frame skipped, wrong crc", m_rxbuffer, m_rxlen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log3(LL_DEBUG,"Incomming Data: ", m_rxbuffer, m_rxlen);
|
Log3(LL_DEBUG, "Incomming Data: ", m_rxbuffer, m_rxlen);
|
||||||
|
|
||||||
// dispatch modbus function
|
// dispatch modbus function
|
||||||
switch(m_rxbuffer[1]){
|
switch (m_rxbuffer[1])
|
||||||
case 0x10:{ // Write Multiple registers
|
{
|
||||||
if(m_rxlen == 0x1b && m_rxbuffer[0] == BROADCASTID)
|
case 0x10:
|
||||||
{
|
{ // Write Multiple registers
|
||||||
processBroadcastStatusFrame();
|
if (m_rxlen == 0x1b && m_rxbuffer[0] == BROADCASTID)
|
||||||
return;
|
{
|
||||||
}
|
processBroadcastStatusFrame();
|
||||||
break;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
case 0x17:{ // Read/Write Multiple registers
|
|
||||||
if(m_rxbuffer[0] == DEVICEID){
|
|
||||||
switch(m_rxlen){
|
|
||||||
case 0x11:{
|
|
||||||
processDeviceStatusFrame();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x13:
|
|
||||||
processDeviceBusScanFrame();
|
|
||||||
return;;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Log3(LL_ERROR,"Frame skipped, unexpected data: ", m_rxbuffer, m_rxlen);
|
|
||||||
|
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_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};
|
const unsigned char ResponseTemplate_Fcn17_Cmd04_L02[] = {0x02, 0x17, 0x04, 0x0F, 0x00, 0x04, 0xFD, 0x0A, 0x72};
|
||||||
void HCIEmulator::processDeviceStatusFrame(){
|
void HCIEmulator::processDeviceStatusFrame()
|
||||||
if(m_rxlen==0x11){
|
{
|
||||||
|
if (m_rxlen == 0x11)
|
||||||
|
{
|
||||||
unsigned char counter = m_rxbuffer[11];
|
unsigned char counter = m_rxbuffer[11];
|
||||||
unsigned char cmd = m_rxbuffer[12];
|
unsigned char cmd = m_rxbuffer[12];
|
||||||
if(m_rxbuffer[5] == 0x08){
|
if (m_rxbuffer[5] == 0x08)
|
||||||
// expose internal state
|
{
|
||||||
|
// expose internal state
|
||||||
// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
|
// 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
|
// 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
|
// res=> 02 17 10 3E 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 74 1B
|
||||||
memcpy(m_txbuffer, ResponseTemplate_Fcn17_Cmd03_L08, sizeof(ResponseTemplate_Fcn17_Cmd03_L08));
|
memcpy(m_txbuffer, ResponseTemplate_Fcn17_Cmd03_L08, sizeof(ResponseTemplate_Fcn17_Cmd03_L08));
|
||||||
m_txbuffer[0] = m_rxbuffer[0];
|
m_txbuffer[0] = m_rxbuffer[0];
|
||||||
m_txbuffer[3] = counter;
|
m_txbuffer[3] = counter;
|
||||||
m_txbuffer[5] = cmd;
|
m_txbuffer[5] = cmd;
|
||||||
m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd03_L08);
|
m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd03_L08);
|
||||||
|
|
||||||
|
switch (m_statemachine)
|
||||||
switch(m_statemachine)
|
|
||||||
{
|
{
|
||||||
// open Door
|
// open Door
|
||||||
case STARTOPENDOOR:
|
case STARTOPENDOOR:
|
||||||
m_txbuffer[7]= 0x02;
|
m_txbuffer[7] = 0x02;
|
||||||
m_txbuffer[8]= 0x10;
|
m_txbuffer[8] = 0x10;
|
||||||
m_statemachine = STARTOPENDOOR_RELEASE;
|
m_statemachine = STARTOPENDOOR_RELEASE;
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
break;
|
break;
|
||||||
case STARTOPENDOOR_RELEASE:
|
case STARTOPENDOOR_RELEASE:
|
||||||
if(m_lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||||
m_txbuffer[7]= 0x01;
|
{
|
||||||
m_txbuffer[8]= 0x10;
|
m_txbuffer[7] = 0x01;
|
||||||
m_statemachine = WAITING;
|
m_txbuffer[8] = 0x10;
|
||||||
}
|
m_statemachine = WAITING;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// close Door
|
// close Door
|
||||||
case STARTCLOSEDOOR:
|
case STARTCLOSEDOOR:
|
||||||
m_txbuffer[7]= 0x02;
|
m_txbuffer[7] = 0x02;
|
||||||
m_txbuffer[8]= 0x20;
|
m_txbuffer[8] = 0x20;
|
||||||
m_statemachine = STARTCLOSEDOOR_RELEASE;
|
m_statemachine = STARTCLOSEDOOR_RELEASE;
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
break;
|
break;
|
||||||
case STARTCLOSEDOOR_RELEASE:
|
case STARTCLOSEDOOR_RELEASE:
|
||||||
if(m_lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||||
m_txbuffer[7]= 0x01;
|
{
|
||||||
m_txbuffer[8]= 0x20;
|
m_txbuffer[7] = 0x01;
|
||||||
m_statemachine = WAITING;
|
m_txbuffer[8] = 0x20;
|
||||||
}
|
m_statemachine = WAITING;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// stop Door
|
// stop Door
|
||||||
case STARTSTOPDOOR:
|
case STARTSTOPDOOR:
|
||||||
m_txbuffer[7]= 0x02;
|
m_txbuffer[7] = 0x02;
|
||||||
m_txbuffer[8]= 0x40;
|
m_txbuffer[8] = 0x40;
|
||||||
m_statemachine = STARTSTOPDOOR_RELEASE;
|
m_statemachine = STARTSTOPDOOR_RELEASE;
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
break;
|
break;
|
||||||
case STARTSTOPDOOR_RELEASE:
|
case STARTSTOPDOOR_RELEASE:
|
||||||
if(m_lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||||
m_txbuffer[7]= 0x01;
|
{
|
||||||
m_txbuffer[8]= 0x40;
|
m_txbuffer[7] = 0x01;
|
||||||
m_statemachine = WAITING;
|
m_txbuffer[8] = 0x40;
|
||||||
}
|
m_statemachine = WAITING;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// Ventilation
|
// Ventilation
|
||||||
case STARTVENTPOSITION:
|
case STARTVENTPOSITION:
|
||||||
m_txbuffer[7]= 0x02;
|
m_txbuffer[7] = 0x02;
|
||||||
m_txbuffer[9]= 0x40;
|
m_txbuffer[9] = 0x40;
|
||||||
m_statemachine = STARTVENTPOSITION_RELEASE;
|
m_statemachine = STARTVENTPOSITION_RELEASE;
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
break;
|
break;
|
||||||
case STARTVENTPOSITION_RELEASE:
|
case STARTVENTPOSITION_RELEASE:
|
||||||
if(m_lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||||
m_txbuffer[7]= 0x01;
|
{
|
||||||
m_txbuffer[9]= 0x40;
|
m_txbuffer[7] = 0x01;
|
||||||
m_statemachine = WAITING;
|
m_txbuffer[9] = 0x40;
|
||||||
}
|
m_statemachine = WAITING;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Half Position
|
||||||
|
case STARTOPENDOORHALF:
|
||||||
|
m_txbuffer[7] = 0x02;
|
||||||
|
m_txbuffer[9] = 0x04;
|
||||||
|
m_statemachine = STARTOPENDOORHALF_RELEASE;
|
||||||
|
m_lastStateTime = millis();
|
||||||
|
break;
|
||||||
|
|
||||||
// Half Position
|
case STARTOPENDOORHALF_RELEASE:
|
||||||
case STARTOPENDOORHALF:
|
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||||
m_txbuffer[7]= 0x02;
|
{
|
||||||
m_txbuffer[9]= 0x04;
|
m_txbuffer[7] = 0x01;
|
||||||
m_statemachine = STARTOPENDOORHALF_RELEASE;
|
m_txbuffer[9] = 0x04;
|
||||||
m_lastStateTime = millis();
|
m_statemachine = WAITING;
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case STARTOPENDOORHALF_RELEASE:
|
// Toggle Lamp
|
||||||
if(m_lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
case STARTTOGGLELAMP:
|
||||||
m_txbuffer[7]= 0x01;
|
m_txbuffer[7] = 0x10;
|
||||||
m_txbuffer[9]= 0x04;
|
m_txbuffer[9] = 0x02;
|
||||||
m_statemachine = WAITING;
|
m_statemachine = STARTTOGGLELAMP_RELEASE;
|
||||||
}
|
m_lastStateTime = millis();
|
||||||
break;
|
break;
|
||||||
|
case STARTTOGGLELAMP_RELEASE:
|
||||||
|
if (m_lastStateTime + SIMULATEKEYPRESSDELAYMS < millis())
|
||||||
|
{
|
||||||
|
m_txbuffer[7] = 0x08;
|
||||||
|
m_txbuffer[9] = 0x02;
|
||||||
|
m_statemachine = WAITING;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// Toggle Lamp
|
case WAITING:
|
||||||
case STARTTOGGLELAMP:
|
break;
|
||||||
m_txbuffer[7]= 0x10;
|
}
|
||||||
m_txbuffer[9]= 0x02;
|
return;
|
||||||
m_statemachine = STARTTOGGLELAMP_RELEASE;
|
|
||||||
m_lastStateTime = millis();
|
|
||||||
break;
|
|
||||||
case STARTTOGGLELAMP_RELEASE:
|
|
||||||
if(m_lastStateTime+SIMULATEKEYPRESSDELAYMS<millis()){
|
|
||||||
m_txbuffer[7]= 0x08;
|
|
||||||
m_txbuffer[9]= 0x02;
|
|
||||||
m_statemachine = WAITING;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WAITING:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else if(m_rxbuffer[5] == 0x02){
|
else if (m_rxbuffer[5] == 0x02)
|
||||||
|
{
|
||||||
// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
|
// 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
|
// 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
|
// res=> 02 17 04 0F 00 04 FD 0A 72
|
||||||
memcpy(m_txbuffer, ResponseTemplate_Fcn17_Cmd04_L02, sizeof(ResponseTemplate_Fcn17_Cmd04_L02));
|
memcpy(m_txbuffer, ResponseTemplate_Fcn17_Cmd04_L02, sizeof(ResponseTemplate_Fcn17_Cmd04_L02));
|
||||||
m_txbuffer[0] = m_rxbuffer[0];
|
m_txbuffer[0] = m_rxbuffer[0];
|
||||||
m_txbuffer[3] = counter;
|
m_txbuffer[3] = counter;
|
||||||
m_txbuffer[5] = cmd;
|
m_txbuffer[5] = cmd;
|
||||||
m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd04_L02);
|
m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd04_L02);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log3(LL_ERROR,"Frame skipped, unexpected data: ", m_rxbuffer, m_rxlen);
|
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};
|
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(){
|
void HCIEmulator::processDeviceBusScanFrame()
|
||||||
|
{
|
||||||
// 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
|
// 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
|
// 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
|
// res=> 02 17 0a 00 00 02 05 04 30 10 ff a8 45 0e df
|
||||||
unsigned char counter = m_rxbuffer[11];
|
unsigned char counter = m_rxbuffer[11];
|
||||||
unsigned char cmd = m_rxbuffer[12];
|
unsigned char cmd = m_rxbuffer[12];
|
||||||
memcpy(m_txbuffer, ResponseTemplate_Fcn17_Cmd02_L05, sizeof(ResponseTemplate_Fcn17_Cmd02_L05));
|
memcpy(m_txbuffer, ResponseTemplate_Fcn17_Cmd02_L05, sizeof(ResponseTemplate_Fcn17_Cmd02_L05));
|
||||||
m_txbuffer[0] = m_rxbuffer[0];
|
m_txbuffer[0] = m_rxbuffer[0];
|
||||||
m_txbuffer[3] = counter;
|
m_txbuffer[3] = counter;
|
||||||
m_txbuffer[5] = cmd;
|
m_txbuffer[5] = cmd;
|
||||||
m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd02_L05);
|
m_txlen = sizeof(ResponseTemplate_Fcn17_Cmd02_L05);
|
||||||
|
|
||||||
Log(LL_INFO,"Busscan received");
|
Log(LL_INFO, "Busscan received");
|
||||||
}
|
}
|
||||||
|
|
||||||
void HCIEmulator::processBroadcastStatusFrame(){
|
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
|
{
|
||||||
|
// 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;
|
bool hasChanged = false;
|
||||||
CHECKCHANGEDSET(m_state.lampOn,m_rxbuffer[20] == 0x14,hasChanged);
|
CHECKCHANGEDSET(m_state.lampOn, m_rxbuffer[20] == 0x14, hasChanged);
|
||||||
CHECKCHANGEDSET(m_state.doorCurrentPosition,m_rxbuffer[10],hasChanged);
|
CHECKCHANGEDSET(m_state.doorCurrentPosition, m_rxbuffer[10], hasChanged);
|
||||||
CHECKCHANGEDSET(m_state.doorTargetPosition, m_rxbuffer[9],hasChanged);
|
CHECKCHANGEDSET(m_state.doorTargetPosition, m_rxbuffer[9], hasChanged);
|
||||||
CHECKCHANGEDSET(m_state.doorState, m_rxbuffer[11],hasChanged);
|
CHECKCHANGEDSET(m_state.doorState, m_rxbuffer[11], hasChanged);
|
||||||
CHECKCHANGEDSET(m_state.reserved, m_rxbuffer[17],hasChanged);
|
CHECKCHANGEDSET(m_state.reserved, m_rxbuffer[17], hasChanged);
|
||||||
CHECKCHANGEDSET(m_state.valid, true,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 (hasChanged)
|
||||||
if(m_statemachine != WAITING){
|
{
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
m_statemachine = STARTOPENDOOR;
|
m_statemachine = STARTOPENDOOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HCIEmulator::openDoorHalf(){
|
void HCIEmulator::openDoorHalf()
|
||||||
if(m_statemachine != WAITING){
|
{
|
||||||
|
if (m_statemachine != WAITING)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
m_statemachine = STARTOPENDOORHALF;
|
m_statemachine = STARTOPENDOORHALF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HCIEmulator::closeDoor(){
|
void HCIEmulator::closeDoor()
|
||||||
if(m_statemachine != WAITING){
|
{
|
||||||
|
if (m_statemachine != WAITING)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
m_statemachine = STARTCLOSEDOOR;
|
m_statemachine = STARTCLOSEDOOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HCIEmulator::stopDoor(){
|
void HCIEmulator::stopDoor()
|
||||||
if(m_statemachine != WAITING){
|
{
|
||||||
|
if (m_statemachine != WAITING)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
m_statemachine = STARTSTOPDOOR;
|
m_statemachine = STARTSTOPDOOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HCIEmulator::toggleLamp(){
|
void HCIEmulator::toggleLamp()
|
||||||
if(m_statemachine != WAITING){
|
{
|
||||||
|
if (m_statemachine != WAITING)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
m_statemachine = STARTTOGGLELAMP;
|
m_statemachine = STARTTOGGLELAMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HCIEmulator::ventilationPosition(){
|
void HCIEmulator::ventilationPosition()
|
||||||
if(m_statemachine != WAITING){
|
{
|
||||||
|
if (m_statemachine != WAITING)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_lastStateTime = millis();
|
m_lastStateTime = millis();
|
||||||
m_statemachine = STARTVENTPOSITION;
|
m_statemachine = STARTVENTPOSITION;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HCIEmulator::onStatusChanged(callback_function_t handler) {
|
void HCIEmulator::onStatusChanged(callback_function_t handler)
|
||||||
|
{
|
||||||
m_statusCallback = handler;
|
m_statusCallback = handler;
|
||||||
}
|
}
|
||||||
|
@ -11,35 +11,34 @@
|
|||||||
#define LL_INFO 3
|
#define LL_INFO 3
|
||||||
#define LL_DEBUG 4
|
#define LL_DEBUG 4
|
||||||
|
|
||||||
#define DEFAULTLOGLEVEL LL_WARN
|
#define DEFAULTLOGLEVEL LL_DEBUG
|
||||||
|
|
||||||
#define DEVICEID 0x02
|
#define DEVICEID 0x02
|
||||||
#define BROADCASTID 0x00
|
#define BROADCASTID 0x00
|
||||||
#define SIMULATEKEYPRESSDELAYMS 100
|
#define SIMULATEKEYPRESSDELAYMS 100
|
||||||
|
|
||||||
|
// Modbus states that a baud rate higher than 19200 must use a fixed 750 us
|
||||||
// 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 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.
|
// 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
|
// 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
|
// In milliseconds this will be 960characters per 1000ms. So for 1 character
|
||||||
// 1000ms/960characters is 1.04167ms per character and finaly modbus states an
|
// 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
|
// 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.
|
// 1.5T = 1.04167ms * 1.5 = 1.5625ms. A frame delay is 3.5T.
|
||||||
#define T1_5 750
|
#define T1_5 750
|
||||||
#define T3_5 4800 //1750
|
#define T3_5 4800 // 1750
|
||||||
|
|
||||||
|
enum DoorState : uint8_t
|
||||||
enum DoorState : uint8_t {
|
{
|
||||||
DOOR_OPEN_POSITION = 0x20,
|
DOOR_OPEN_POSITION = 0x20,
|
||||||
DOOR_CLOSE_POSITION = 0x40,
|
DOOR_CLOSE_POSITION = 0x40,
|
||||||
DOOR_HALF_POSITION = 0x80,
|
DOOR_HALF_POSITION = 0x80,
|
||||||
DOOR_MOVE_CLOSEPOSITION = 0x02,
|
DOOR_MOVE_CLOSEPOSITION = 0x02,
|
||||||
DOOR_MOVE_OPENPOSITION = 0x01,
|
DOOR_MOVE_OPENPOSITION = 0x01,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SHCIState{
|
struct SHCIState
|
||||||
|
{
|
||||||
bool valid;
|
bool valid;
|
||||||
bool lampOn;
|
bool lampOn;
|
||||||
uint8_t doorState; // see DoorState
|
uint8_t doorState; // see DoorState
|
||||||
@ -48,7 +47,8 @@ struct SHCIState{
|
|||||||
uint8_t reserved;
|
uint8_t reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum StateMachine: uint8_t{
|
enum StateMachine : uint8_t
|
||||||
|
{
|
||||||
WAITING,
|
WAITING,
|
||||||
|
|
||||||
STARTOPENDOOR,
|
STARTOPENDOOR,
|
||||||
@ -70,11 +70,12 @@ enum StateMachine: uint8_t{
|
|||||||
STARTVENTPOSITION_RELEASE
|
STARTVENTPOSITION_RELEASE
|
||||||
};
|
};
|
||||||
|
|
||||||
class HCIEmulator {
|
class HCIEmulator
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::function<void(const SHCIState&)> callback_function_t;
|
typedef std::function<void(const SHCIState &)> callback_function_t;
|
||||||
|
|
||||||
HCIEmulator(Stream * port);
|
HCIEmulator(Stream *port);
|
||||||
|
|
||||||
void poll();
|
void poll();
|
||||||
|
|
||||||
@ -85,16 +86,19 @@ public:
|
|||||||
void toggleLamp();
|
void toggleLamp();
|
||||||
void ventilationPosition();
|
void ventilationPosition();
|
||||||
|
|
||||||
const SHCIState& getState() {
|
const SHCIState &getState()
|
||||||
if(micros()-m_recvTime > 2000000){
|
{
|
||||||
// 2 sec without statusmessage
|
if (micros() - m_recvTime > 2000000)
|
||||||
|
{
|
||||||
|
// 2 sec without statusmessage
|
||||||
m_state.valid = false;
|
m_state.valid = false;
|
||||||
}
|
}
|
||||||
return m_state;
|
return m_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned long getMessageAge(){
|
unsigned long getMessageAge()
|
||||||
return micros()-m_recvTime;
|
{
|
||||||
|
return micros() - m_recvTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLogLevel();
|
int getLogLevel();
|
||||||
@ -109,7 +113,7 @@ protected:
|
|||||||
void processBroadcastStatusFrame();
|
void processBroadcastStatusFrame();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
callback_function_t m_statusCallback;
|
callback_function_t m_statusCallback;
|
||||||
Stream *m_port;
|
Stream *m_port;
|
||||||
SHCIState m_state;
|
SHCIState m_state;
|
||||||
StateMachine m_statemachine;
|
StateMachine m_statemachine;
|
||||||
@ -121,11 +125,14 @@ private:
|
|||||||
size_t m_rxlen;
|
size_t m_rxlen;
|
||||||
size_t m_txlen;
|
size_t m_txlen;
|
||||||
|
|
||||||
unsigned char m_rxbuffer[255];
|
unsigned char m_rxbuffer[255] = {
|
||||||
unsigned char m_txbuffer[255];
|
0,
|
||||||
|
};
|
||||||
|
unsigned char m_txbuffer[255] = {
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
bool m_skipFrame;
|
bool m_skipFrame;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif
|
|
||||||
|
1
HCPBridgeESP32/src/index_html.h
Normal file
1
HCPBridgeESP32/src/index_html.h
Normal file
File diff suppressed because one or more lines are too long
@ -4,31 +4,27 @@
|
|||||||
#include "AsyncJson.h"
|
#include "AsyncJson.h"
|
||||||
#include "ArduinoJson.h"
|
#include "ArduinoJson.h"
|
||||||
#include "hciemulator.h"
|
#include "hciemulator.h"
|
||||||
#include "index_html.h"
|
// #include "index_html.h"
|
||||||
#include "../../WebUI/index_html.h"
|
#include "../../WebUI/index_html.h"
|
||||||
|
|
||||||
/* create this file and add your wlan credentials
|
/* create this file and add your wlan credentials
|
||||||
const char* ssid = "MyWLANSID";
|
const char* ssid = "MyWLANSID";
|
||||||
const char* password = "MYPASSWORD";
|
const char* password = "MYPASSWORD";
|
||||||
*/
|
*/
|
||||||
#include "../../../private/credentials.h"
|
#include "credentials.h"
|
||||||
|
|
||||||
|
|
||||||
// switch relay sync to the lamp
|
// switch relay sync to the lamp
|
||||||
// e.g. the Wifi Relay Board U4648
|
// e.g. the Wifi Relay Board U4648
|
||||||
#define USERELAY
|
// #define USERELAY
|
||||||
|
|
||||||
// use alternative uart pins
|
#define RS485 Serial2
|
||||||
//#define SWAPUART
|
#define TX_ON 25
|
||||||
|
|
||||||
#define RS485 Serial
|
|
||||||
|
|
||||||
// Relay Board parameters
|
// Relay Board parameters
|
||||||
#define ESP8266_GPIO2 2 // Blue LED.
|
#define ESP8266_GPIO2 2 // Blue LED.
|
||||||
#define ESP8266_GPIO4 4 // Relay control.
|
#define ESP8266_GPIO4 4 // Relay control.
|
||||||
#define ESP8266_GPIO5 5 // Optocoupler input.
|
#define ESP8266_GPIO5 5 // Optocoupler input.
|
||||||
#define LED_PIN ESP8266_GPIO2
|
#define LED_PIN ESP8266_GPIO2
|
||||||
|
|
||||||
|
|
||||||
// Hörmann HCP2 based on modbus rtu @57.6kB 8E1
|
// Hörmann HCP2 based on modbus rtu @57.6kB 8E1
|
||||||
HCIEmulator emulator(&RS485);
|
HCIEmulator emulator(&RS485);
|
||||||
@ -37,87 +33,104 @@ HCIEmulator emulator(&RS485);
|
|||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
// called by ESPAsyncTCP-esphome:SyncClient.cpp (see patch) instead of delay to avoid connection breaks
|
// called by ESPAsyncTCP-esphome:SyncClient.cpp (see patch) instead of delay to avoid connection breaks
|
||||||
void DelayHandler(void){
|
void DelayHandler(void)
|
||||||
emulator.poll();
|
{
|
||||||
|
emulator.poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch GPIO4 und GPIO2 sync to the lamp
|
// switch GPIO4 und GPIO2 sync to the lamp
|
||||||
void onStatusChanged(const SHCIState& state){
|
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
|
// see https://ucexperiment.wordpress.com/2016/12/18/yunshan-esp8266-250v-15a-acdc-network-wifi-relay-module/
|
||||||
if(state.valid){
|
// Setting GPIO4 high, causes the relay to close the NO contact with
|
||||||
digitalWrite( ESP8266_GPIO4, state.lampOn );
|
if (state.valid)
|
||||||
digitalWrite(LED_PIN, state.lampOn);
|
|
||||||
}else
|
|
||||||
{
|
{
|
||||||
digitalWrite( ESP8266_GPIO4, false );
|
digitalWrite(ESP8266_GPIO4, state.lampOn);
|
||||||
digitalWrite(LED_PIN, false);
|
digitalWrite(LED_PIN, state.lampOn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
digitalWrite(ESP8266_GPIO4, false);
|
||||||
|
digitalWrite(LED_PIN, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle lamp to expected state
|
// toggle lamp to expected state
|
||||||
void switchLamp(bool on){
|
void switchLamp(bool on)
|
||||||
|
{
|
||||||
bool toggle = (on && !emulator.getState().lampOn) || (!on && emulator.getState().lampOn);
|
bool toggle = (on && !emulator.getState().lampOn) || (!on && emulator.getState().lampOn);
|
||||||
if(toggle){
|
if (toggle)
|
||||||
|
{
|
||||||
emulator.toggleLamp();
|
emulator.toggleLamp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
volatile unsigned long lastCall = 0;
|
volatile unsigned long lastCall = 0;
|
||||||
volatile unsigned long maxPeriod = 0;
|
volatile unsigned long maxPeriod = 0;
|
||||||
|
|
||||||
void modBusPolling( void * parameter) {
|
void modBusPolling(void *parameter)
|
||||||
while(true){
|
{
|
||||||
if(lastCall>0){
|
while (true)
|
||||||
maxPeriod = _max(micros()-lastCall,maxPeriod);
|
{
|
||||||
}
|
if (lastCall > 0)
|
||||||
lastCall=micros();
|
{
|
||||||
emulator.poll();
|
maxPeriod = _max(micros() - lastCall, maxPeriod);
|
||||||
vTaskDelay(1);
|
}
|
||||||
|
lastCall = micros();
|
||||||
|
emulator.poll();
|
||||||
|
vTaskDelay(1);
|
||||||
}
|
}
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TaskHandle_t modBusTask;
|
TaskHandle_t modBusTask;
|
||||||
|
|
||||||
// setup mcu
|
// setup mcu
|
||||||
void setup(){
|
void setup()
|
||||||
|
{
|
||||||
//setup modbus
|
Serial.begin(115200);
|
||||||
RS485.begin(57600,SERIAL_8E1);
|
Serial.println("Starting door control");
|
||||||
#ifdef SWAPUART
|
// setup modbus
|
||||||
RS485.swap();
|
RS485.begin(57600, SERIAL_8E1, 16, 17);
|
||||||
#endif
|
|
||||||
|
|
||||||
|
pinMode(TX_ON, OUTPUT);
|
||||||
|
digitalWrite(TX_ON, LOW);
|
||||||
|
|
||||||
|
// digitalWrite(TX_ON, HIGH);
|
||||||
|
// for (;;)
|
||||||
|
//{
|
||||||
|
// RS485.write("hello there");
|
||||||
|
// delay(100);
|
||||||
|
// }
|
||||||
|
|
||||||
xTaskCreatePinnedToCore(
|
xTaskCreatePinnedToCore(
|
||||||
modBusPolling, /* Function to implement the task */
|
modBusPolling, /* Function to implement the task */
|
||||||
"ModBusTask", /* Name of the task */
|
"ModBusTask", /* Name of the task */
|
||||||
10000, /* Stack size in words */
|
10000, /* Stack size in words */
|
||||||
NULL, /* Task input parameter */
|
NULL, /* Task input parameter */
|
||||||
//1, /* Priority of the task */
|
// 1, /* Priority of the task */
|
||||||
configMAX_PRIORITIES -1,
|
configMAX_PRIORITIES - 1,
|
||||||
&modBusTask, /* Task handle. */
|
&modBusTask, /* Task handle. */
|
||||||
1); /* Core where the task should run */
|
1); /* Core where the task should run */
|
||||||
|
|
||||||
|
// setup wifi
|
||||||
//setup wifi
|
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin(ssid, password);
|
WiFi.begin(ssid, password);
|
||||||
WiFi.setAutoReconnect(true);
|
WiFi.setAutoReconnect(true);
|
||||||
while (WiFi.status() != WL_CONNECTED) {
|
while (WiFi.status() != WL_CONNECTED)
|
||||||
|
{
|
||||||
delay(100);
|
delay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup http server
|
// setup http server
|
||||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
AsyncWebServerResponse *response = request->beginResponse_P( 200, "text/html", index_html,sizeof(index_html));
|
AsyncWebServerResponse *response = request->beginResponse_P( 200, "text/html", index_html,sizeof(index_html));
|
||||||
response->addHeader("Content-Encoding","deflate");
|
response->addHeader("Content-Encoding","deflate");
|
||||||
request->send(response);
|
request->send(response); });
|
||||||
});
|
|
||||||
|
|
||||||
server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
const SHCIState& doorstate = emulator.getState();
|
const SHCIState& doorstate = emulator.getState();
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(1024);
|
||||||
@ -133,10 +146,10 @@ void setup(){
|
|||||||
lastCall = maxPeriod = 0;
|
lastCall = maxPeriod = 0;
|
||||||
|
|
||||||
serializeJson(root,*response);
|
serializeJson(root,*response);
|
||||||
request->send(response);
|
request->send(response); });
|
||||||
});
|
|
||||||
|
|
||||||
server.on("/command", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
server.on("/command", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
if (request->hasParam("action")) {
|
if (request->hasParam("action")) {
|
||||||
int actionid = request->getParam("action")->value().toInt();
|
int actionid = request->getParam("action")->value().toInt();
|
||||||
switch (actionid){
|
switch (actionid){
|
||||||
@ -162,10 +175,10 @@ void setup(){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
request->send(200, "text/plain", "OK");
|
request->send(200, "text/plain", "OK"); });
|
||||||
});
|
|
||||||
|
|
||||||
server.on("/sysinfo", HTTP_GET, [] (AsyncWebServerRequest *request) {
|
server.on("/sysinfo", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(1024);
|
||||||
@ -177,26 +190,25 @@ void setup(){
|
|||||||
root["resetreason"] =esp_reset_reason();
|
root["resetreason"] =esp_reset_reason();
|
||||||
serializeJson(root,*response);
|
serializeJson(root,*response);
|
||||||
|
|
||||||
request->send(response);
|
request->send(response); });
|
||||||
});
|
|
||||||
|
|
||||||
AsyncElegantOTA.begin(&server);
|
AsyncElegantOTA.begin(&server);
|
||||||
|
|
||||||
server.begin();
|
server.begin();
|
||||||
|
|
||||||
//setup relay board
|
// setup relay board
|
||||||
#ifdef USERELAY
|
#ifdef USERELAY
|
||||||
pinMode( ESP8266_GPIO4, OUTPUT ); // Relay control pin.
|
pinMode(ESP8266_GPIO4, OUTPUT); // Relay control pin.
|
||||||
pinMode( ESP8266_GPIO5, INPUT_PULLUP ); // Input pin.
|
pinMode(ESP8266_GPIO5, INPUT_PULLUP); // Input pin.
|
||||||
pinMode( LED_PIN, OUTPUT ); // ESP8266 module blue L
|
pinMode(LED_PIN, OUTPUT); // ESP8266 module blue L
|
||||||
digitalWrite( ESP8266_GPIO4, 0 );
|
digitalWrite(ESP8266_GPIO4, 0);
|
||||||
digitalWrite(LED_PIN,0);
|
digitalWrite(LED_PIN, 0);
|
||||||
emulator.onStatusChanged(onStatusChanged);
|
emulator.onStatusChanged(onStatusChanged);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mainloop
|
// mainloop
|
||||||
void loop(){
|
void loop()
|
||||||
|
{
|
||||||
AsyncElegantOTA.loop();
|
AsyncElegantOTA.loop();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user