/* * 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