#include #include #include #include #include #include #include #include typedef enum { IDLE, SEND, SEND_CONT, SENDING_DONE, ENABLE_FRONTEND, RECEIVING, DISABLE_FRONTEND } e_mbusCommState; typedef struct { e_mbusCommState state; uint8_t retryCnt; uint8_t cmd; uint8_t addr; uint8_t sendBuf[5]; uint8_t receiveCnt; uint8_t receivedOctet; bool receiving; } t_mbusCommHandle; static t_mbusCommHandle mbusCommHandle = { .state = IDLE, .retryCnt = 0, .cmd = 0, .addr = 0, .receiveCnt = 0, .receivedOctet = 0, .receiving = false }; static void handleRequestEngine(void *handle); static void timeoutHandler(void *handle) { logMsg("mbc timeout"); t_mbusCommHandle *localMbusCommHandle = (t_mbusCommHandle*) handle; localMbusCommHandle->state = DISABLE_FRONTEND; localMbusCommHandle->receiving = false; handleRequestEngine(handle); } static void receiveNext(t_mbusCommHandle *localMbusCommHandle) { localMbusCommHandle->receiving = true; HAL_UART_Receive_IT(&mbusUart, &(localMbusCommHandle->receivedOctet), 1); } static void handleRequestEngine(void *handle) { t_mbusCommHandle *localMbusCommHandle = (t_mbusCommHandle*) handle; switch (localMbusCommHandle->state) { case IDLE: logMsg("hre state IDLE"); break; case SEND: logMsg("hre state SEND"); localMbusCommHandle->sendBuf[0] = 0x10; localMbusCommHandle->sendBuf[1] = localMbusCommHandle->cmd; localMbusCommHandle->sendBuf[2] = localMbusCommHandle->addr; localMbusCommHandle->sendBuf[3] = localMbusCommHandle->cmd + localMbusCommHandle->addr; // checksum localMbusCommHandle->sendBuf[4] = 0x16; localMbusCommHandle->state = SEND_CONT; // no break !! case SEND_CONT: logMsg("hre state SEND_CONT"); signal(LED_RED, OFF); if (! loopActive) { logMsg("hre enabling loop, try %d", localMbusCommHandle->retryCnt); localMbusCommHandle->retryCnt++; loopEnable(); schAdd(handleRequestEngine, handle, 10, 0); // give 10ms to settled the loop } else { localMbusCommHandle->retryCnt = 0; HAL_UART_Transmit_IT(&mbusUart, localMbusCommHandle->sendBuf, 5); // transition from here to SENDING_DONE is initiate by mbusCommTxCpltCallback // interrupt callback localMbusCommHandle->state = SENDING_DONE; } break; case SENDING_DONE: logMsg("hre state SENDING_DONE"); localMbusCommHandle->state = ENABLE_FRONTEND; schAdd(handleRequestEngine, handle, 3, 0); break; case ENABLE_FRONTEND: logMsg("hre state ENABLE_FRONTEND"); frontendEnable(); schAdd(timeoutHandler, handle, 250, 0); localMbusCommHandle->state = RECEIVING; localMbusCommHandle->receiveCnt = 0; receiveNext(localMbusCommHandle); break; case RECEIVING: // logMsg("hre state RECEIVING"); logMsg("hre received octet: 0x%02x: 0x%02x", localMbusCommHandle->receiveCnt, localMbusCommHandle->receivedOctet); localMbusCommHandle->receiveCnt += 1; receiveNext(localMbusCommHandle); break; case DISABLE_FRONTEND: logMsg("hre state DISABLE_FRONTEND"); localMbusCommHandle->receiving = false; HAL_UART_AbortReceive(&mbusUart); uint8_t kitchenSink[16]; memset(kitchensink, 0, 16); HAL_StatusTypeDef r = HAL_UART_Receive(&mbusUart, kitchenSink, 16, 1000); if (r == HAL_OK) { logMsg("hre abort, still got some: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", kitchenSink[0], kitchenSink[1], kitchenSink[2], kitchenSink[3], kitchenSink[4], kitchenSink[5], kitchenSink[6], kitchenSink[7], kitchenSink[8], kitchenSink[9], kitchenSink[10], kitchenSink[11], kitchenSink[12], kitchenSink[13], kitchenSink[14], kitchenSink[15]); } else if (r == HAL_TIMEOUT) { logMsg("hre abort, run into timeout"); } else { logMsg("hre abort, some other result: %02x", r); } frontendDisable(); localMbusCommHandle->state = IDLE; break; default: localMbusCommHandle->state = IDLE; break; } } void mbusCommTxCpltCallback(UART_HandleTypeDef *huart) { schAdd(handleRequestEngine, (void*) &mbusCommHandle, 0, 0); } void mbusCommRxCpltCallback(UART_HandleTypeDef *huart) { if (mbusCommHandle.receiving) { schAdd(handleRequestEngine, (void*) &mbusCommHandle, 0, 0); mbusCommHandle.receiving = false; } else { logMsg("mcrx: received 0x%02x but not expected", mbusCommHandle.receivedOctet); } } void mbusCommRequest(uint8_t cmd, uint8_t addr) { if (mbusCommHandle.state == IDLE) { mbusCommHandle.state = SEND; mbusCommHandle.retryCnt = 0; mbusCommHandle.cmd = cmd; mbusCommHandle.addr = addr; schAdd(handleRequestEngine, (void*) &mbusCommHandle, 0, 0); } else { // busy } }