#include #include #include #include #include #include #include #include #include #include #include #include typedef enum { MBCS_IDLE, MBCS_SEND, MBCS_SEND_CONT, MBCS_SENDING_DONE, MBCS_ENABLE_FRONTEND, MBCS_START1, MBCS_LENGTH1, MBCS_LENGTH2, MBCS_START2, MBCS_C_FIELD, MBCS_A_FIELD, MBCS_CI_FIELD, MBCS_USERDATA, MBCS_CHKSUM, MBCS_STOP, MBCS_DONE, MBCS_TIMEOUT, MBCS_DISABLE_FRONTEND, MBCS_ERROR } 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_mbusCommResult result; t_longframe frame; } t_mbusCommHandle; static t_mbusCommHandle mbusCommHandle = { .state = MBCS_IDLE, .retryCnt = 0, .cmd = 0, .addr = 0, .receiveCnt = 0, .receivedOctet = 0, .receiving = false }; static void printFrame(t_longframe *frame) { logMsg("frame: %02x %02x %02x %02x", frame->start1, frame->length1, frame->length2, frame->start2); logMsg("frame: C:%02x A:%02x CI:%02x", frame->c, frame->a, frame->ci); logMsg("frame: userdata ..."); logMsg("frame: CHKSUM:%02x", frame->chksum); logMsg("frame: %02x", frame->stop); } static void handleRequestEngine(void *handle); static void timeoutHandler(void *handle) { logMsg("mbc timeout"); t_mbusCommHandle *localMbusCommHandle = (t_mbusCommHandle*) handle; localMbusCommHandle->state = MBCS_TIMEOUT; 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; static uint8_t userdataIdx = 0; static uint8_t calculatedChksum = 0; switch (localMbusCommHandle->state) { case MBCS_IDLE: logMsg("hre state IDLE"); break; case MBCS_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 = MBCS_SEND_CONT; // no break !! case MBCS_SEND_CONT: logMsg("hre state SEND_CONT"); show(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 = MBCS_SENDING_DONE; } break; case MBCS_SENDING_DONE: logMsg("hre state SENDING_DONE"); localMbusCommHandle->state = MBCS_ENABLE_FRONTEND; schAdd(handleRequestEngine, handle, 3, 0); break; case MBCS_ENABLE_FRONTEND: logMsg("hre state ENABLE_FRONTEND"); frontendEnable(); schAdd(timeoutHandler, handle, 2500, 0); calculatedChksum = 0; userdataIdx = 0; localMbusCommHandle->state = MBCS_START1; receiveNext(localMbusCommHandle); break; case MBCS_START1: //logMsg("hre state START1"); if (localMbusCommHandle->receivedOctet == 0x68) { localMbusCommHandle->frame.start1 = localMbusCommHandle->receivedOctet; localMbusCommHandle->state = MBCS_LENGTH1; } else { logMsg("hre err: invalid start1 symbol %02x", localMbusCommHandle->receivedOctet); localMbusCommHandle->result = MBCR_ERROR_STATE_ENGINE__START1; localMbusCommHandle->state = MBCS_ERROR; } receiveNext(localMbusCommHandle); break; case MBCS_LENGTH1: //logMsg("hre state LENGTH1"); if (localMbusCommHandle->receivedOctet <= 3) { logMsg("hre err: length to small %02x", localMbusCommHandle->receivedOctet); localMbusCommHandle->result = MBCR_ERROR_STATE_ENGINE__LENGTH1; localMbusCommHandle->state = MBCS_ERROR; } else { localMbusCommHandle->frame.length1 = localMbusCommHandle->receivedOctet; localMbusCommHandle->frame.userdata = (uint8_t*) malloc(localMbusCommHandle->frame.length1 - 3); if (! localMbusCommHandle->frame.userdata) { logMsg("hre err: unable to allocate memory for userdata"); localMbusCommHandle->result = MBCR_ERROR_OUT_OF_MEMORY__USERDATA; localMbusCommHandle->state = MBCS_ERROR; } else { localMbusCommHandle->state = MBCS_LENGTH2; } } receiveNext(localMbusCommHandle); break; case MBCS_LENGTH2: //logMsg("hre state LENGTH2"); if (localMbusCommHandle->frame.length1 != localMbusCommHandle->receivedOctet) { logMsg("hre err: invalid length2 %02x vs. %02x", localMbusCommHandle->frame.length1, localMbusCommHandle->receivedOctet); localMbusCommHandle->result = MBCR_ERROR_STATE_ENGINE__LENGTH2; localMbusCommHandle->state = MBCS_ERROR; } else { localMbusCommHandle->frame.length2 = localMbusCommHandle->receivedOctet; localMbusCommHandle->state = MBCS_START2; } receiveNext(localMbusCommHandle); break; case MBCS_START2: //logMsg("hre state START2"); if (localMbusCommHandle->receivedOctet == 0x68) { localMbusCommHandle->frame.start2 = localMbusCommHandle->receivedOctet; localMbusCommHandle->state = MBCS_C_FIELD; } else { logMsg("hre err: invalid start2 symbol %02x", localMbusCommHandle->receivedOctet); localMbusCommHandle->result = MBCR_ERROR_STATE_ENGINE__START2; localMbusCommHandle->state = MBCS_ERROR; } receiveNext(localMbusCommHandle); break; case MBCS_C_FIELD: //logMsg("hre state C_FIELD"); localMbusCommHandle->frame.c = localMbusCommHandle->receivedOctet; calculatedChksum += localMbusCommHandle->receivedOctet; localMbusCommHandle->state = MBCS_A_FIELD; receiveNext(localMbusCommHandle); break; case MBCS_A_FIELD: //logMsg("hre state A_FIELD"); localMbusCommHandle->frame.a = localMbusCommHandle->receivedOctet; calculatedChksum += localMbusCommHandle->receivedOctet; localMbusCommHandle->state = MBCS_CI_FIELD; receiveNext(localMbusCommHandle); break; case MBCS_CI_FIELD: //logMsg("hre state CI_FIELD"); localMbusCommHandle->frame.ci = localMbusCommHandle->receivedOctet; calculatedChksum += localMbusCommHandle->receivedOctet; localMbusCommHandle->state = MBCS_USERDATA; receiveNext(localMbusCommHandle); break; case MBCS_USERDATA: //logMsg("hre state USERDATA"); localMbusCommHandle->frame.userdata[userdataIdx] = localMbusCommHandle->receivedOctet; calculatedChksum += localMbusCommHandle->receivedOctet; userdataIdx++; if (userdataIdx == (localMbusCommHandle->frame.length1 - 3)) { localMbusCommHandle->state = MBCS_CHKSUM; } receiveNext(localMbusCommHandle); break; case MBCS_CHKSUM: //logMsg("hre state CHKSUM"); if (localMbusCommHandle->receivedOctet != calculatedChksum) { logMsg("hre err: invalid checksum %02x vs %02x", calculatedChksum, localMbusCommHandle->receivedOctet); localMbusCommHandle->result = MBCR_ERROR_STATE_ENGINE__INVALID_CHKSUM; localMbusCommHandle->state = MBCS_ERROR; } else { localMbusCommHandle->frame.chksum = localMbusCommHandle->receivedOctet; localMbusCommHandle->state = MBCS_STOP; } receiveNext(localMbusCommHandle); break; case MBCS_STOP: //logMsg("hre state STOP"); if (localMbusCommHandle->receivedOctet == 0x16) { localMbusCommHandle->frame.stop = localMbusCommHandle->receivedOctet; localMbusCommHandle->state = MBCS_DONE; schAdd(handleRequestEngine, handle, 0, 0); } else { logMsg("hre err: invalid stop symbol %02x", localMbusCommHandle->receivedOctet); localMbusCommHandle->result = MBCR_ERROR_STATE_ENGINE__STOP; localMbusCommHandle->state = MBCS_ERROR; receiveNext(localMbusCommHandle); } break; case MBCS_DONE: logMsg("hre state DONE"); printFrame(&(localMbusCommHandle->frame)); if (localMbusCommHandle->frame.userdata != NULL) { free(localMbusCommHandle->frame.userdata); localMbusCommHandle->frame.userdata = NULL; } localMbusCommHandle->result = MBCR_SUCCESS; localMbusCommHandle->state = MBCS_DISABLE_FRONTEND; schDel(timeoutHandler, handle); schAdd(handleRequestEngine, handle, 0, 0); break; case MBCS_ERROR: logMsg("hre state ERROR"); show(LED_RED, ON); logMsg("hre err: already error, read the rest (now: %02x) until timeout", localMbusCommHandle->receivedOctet); receiveNext(localMbusCommHandle); break; case MBCS_TIMEOUT: logMsg("hre state TIMEOUT"); localMbusCommHandle->receiving = false; if (localMbusCommHandle->frame.userdata != NULL) { free(localMbusCommHandle->frame.userdata); localMbusCommHandle->frame.userdata = NULL; } HAL_UART_AbortReceive(&mbusUart); uint8_t kitchenSink[16]; memset(kitchenSink, 0, 16); HAL_StatusTypeDef r = HAL_UART_Receive(&mbusUart, kitchenSink, 16, 100); logMsg("hre abort, last receive result: %02x", r); // no break case MBCS_DISABLE_FRONTEND: logMsg("hre state DISABLE_FRONTEND"); frontendDisable(); localMbusCommHandle->state = MBCS_IDLE; break; default: localMbusCommHandle->state = MBCS_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 == MBCS_IDLE) { mbusCommHandle.state = MBCS_SEND; mbusCommHandle.retryCnt = 0; mbusCommHandle.cmd = cmd; mbusCommHandle.addr = addr; schAdd(handleRequestEngine, (void*) &mbusCommHandle, 0, 0); } else { // busy } }