static int TestTelegram(TBusTelegram *pTxMsg, uint8_t msgSize) { TBusTelegram *pRxMsg = BusMsgBufGet(); int timeout; uint8_t zerobuf[sizeof(TBusTelegram)]; memset(zerobuf, 0, sizeof(zerobuf)); memset(pRxMsg, 0, sizeof(*pRxMsg)); if (BusSend(pTxMsg) != BUS_SEND_OK) { return -1; } for (timeout = 0; (timeout < RX_TIMEOUT) && (BusCheck() != BUS_MSG_OK); timeout++) { usleep(1000); } if (timeout < RX_TIMEOUT) { if (memcmp(pTxMsg, pRxMsg, msgSize) != 0) { return -1; } if (memcmp((uint8_t *)pRxMsg + msgSize, zerobuf, sizeof(TBusTelegram) - msgSize) != 0) { return -1; } } else { return -1; } return 0; }
/*----------------------------------------------------------------------------- * send the startup msg. Delay depends on module address */ static void SendStartupMsg(void) { uint16_t startCnt; uint16_t cntMs; uint16_t diff; /* send startup message */ /* delay depends on module address (address * 100 ms) */ GET_TIME_MS16(startCnt); do { GET_TIME_MS16(cntMs); diff = cntMs - startCnt; } while (diff < ((uint16_t)MY_ADDR * 100)); sTxBusMsg.type = eBusDevStartup; sTxBusMsg.senderAddr = MY_ADDR; BusSend(&sTxBusMsg); }
/*----------------------------------------------------------------------------- * program start */ int main(int argc, char *argv[]) { int i; int j; char comPort[SIZE_COMPORT] = ""; uint8_t myAddr; bool myAddrValid = false; TBusTelegram txBusMsg; uint8_t busRet; TBusTelegram *pRxBusMsg; uint8_t mask; int flags; int sioHandle; int sioFd; fd_set rfds; int ret; uint8_t val8; char buffer[SIZE_CMD_BUF]; char *p; signal(SIGPIPE, sighandler); flags = fcntl(fileno(stdout), F_GETFL); fcntl(fileno(stdout), F_SETFL, flags | O_NONBLOCK); /* get com interface */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-c") == 0) { if (argc > i) { strncpy(comPort, argv[i + 1], sizeof(comPort) - 1); comPort[sizeof(comPort) - 1] = '\0'; } break; } } /* our bus address */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-a") == 0) { if (argc > i) { myAddr = atoi(argv[i + 1]); myAddrValid = true; } break; } } if ((strlen(comPort) == 0) || !myAddrValid) { PrintUsage(); return 0; } sioHandle = InitBus(comPort); if (sioHandle == -1) { printf("cannot open %s\r\n", comPort); return -1; } sioFd = SioGetFd(sioHandle); for (;;) { FD_ZERO(&rfds); FD_SET(sioFd, &rfds); FD_SET(STDIN_FILENO, &rfds); ret = select(sioFd + 1, &rfds, 0, 0, 0); if ((ret > 0) && FD_ISSET(sioFd, &rfds)) { busRet = BusCheck(); if (busRet == BUS_MSG_OK) { pRxBusMsg = BusMsgBufGet(); if ((pRxBusMsg->type == eBusDevReqActualValueEvent) && ((pRxBusMsg->msg.devBus.receiverAddr == myAddr))) { Print("event address %d device type ", pRxBusMsg->senderAddr); switch (pRxBusMsg->msg.devBus.x.devReq.actualValueEvent.devType) { case eBusDevTypeDo31: Print("DO31\n"); for (i = 0; i < BUS_DO31_DIGOUT_SIZE_ACTUAL_VALUE; i++) { for (j = 0, mask = 1; j < 8; j++, mask <<= 1) { if ((i == 3) && (j == 7)) { // DO31 has 31 outputs, dont display the last bit break; } if (pRxBusMsg->msg.devBus.x.devReq.actualValueEvent.actualValue.do31.digOut[i] & mask) { Print("1"); } else { Print("0"); } } } Print("\n"); for (i = 0; i < BUS_DO31_SHADER_SIZE_ACTUAL_VALUE; i++) { Print("%02x", pRxBusMsg->msg.devBus.x.devReq.actualValueEvent.actualValue.do31.shader[i]); if (i < (BUS_DO31_SHADER_SIZE_ACTUAL_VALUE - 1)) { Print(" "); } } memcpy(txBusMsg.msg.devBus.x.devResp.actualValueEvent.actualValue.do31.digOut, pRxBusMsg->msg.devBus.x.devReq.actualValueEvent.actualValue.do31.digOut, BUS_DO31_DIGOUT_SIZE_ACTUAL_VALUE); memcpy(txBusMsg.msg.devBus.x.devResp.actualValueEvent.actualValue.do31.shader, pRxBusMsg->msg.devBus.x.devReq.actualValueEvent.actualValue.do31.shader, BUS_DO31_SHADER_SIZE_ACTUAL_VALUE); txBusMsg.msg.devBus.x.devResp.actualValueEvent.devType = eBusDevTypeDo31; break; case eBusDevTypeSw8: Print("SW8\n"); val8 = pRxBusMsg->msg.devBus.x.devReq.actualValueEvent.actualValue.sw8.state; for (i = 0, mask = 1; i < 8; i++, mask <<= 1) { if (val8 & mask) { Print("1"); } else { Print("0"); } } txBusMsg.msg.devBus.x.devResp.actualValueEvent.actualValue.sw8.state = val8; txBusMsg.msg.devBus.x.devResp.actualValueEvent.devType = eBusDevTypeSw8; break; default: break; } Print("\n"); fflush(stdout); txBusMsg.type = eBusDevRespActualValueEvent; txBusMsg.senderAddr = pRxBusMsg->msg.devBus.receiverAddr; txBusMsg.msg.devBus.receiverAddr = pRxBusMsg->senderAddr; BusSend(&txBusMsg); } } else if (busRet == BUS_IF_ERROR) { Print("bus interface access error - exiting\n"); break; } } if ((ret > 0) && FD_ISSET(STDIN_FILENO, &rfds)) { p = fgets(buffer, sizeof(buffer), stdin); if (p == 0) { printf("error/EOF on reading from stdin. exiting\n"); ret = -1; break; } if (strcmp("-exit\n", p) == 0) { Print("OK\n"); break; } } } SioClose(sioHandle); return ret; }
/*----------------------------------------------------------------------------- * process bus telegrams */ static void ProcessBus(uint8_t ret) { TBusMsgType msgType; uint8_t i; bool msgForMe = false; uint8_t state; uint8_t mask8; uint8_t action; TBusDevRespInfo *pInfo; TBusDevRespActualValue *pActVal; TClient *pClient; static TBusTelegram sTxMsg; static bool sTxRetry = false; bool flag; uint8_t val8; if (sTxRetry) { sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; return; } if (ret == BUS_MSG_OK) { msgType = spBusMsg->type; switch (msgType) { case eBusDevReqReboot: case eBusDevReqInfo: case eBusDevReqActualValue: case eBusDevReqSetValue: case eBusDevReqSwitchState: case eBusDevReqSetAddr: case eBusDevReqEepromRead: case eBusDevReqEepromWrite: case eBusDevReqSetClientAddr: case eBusDevReqGetClientAddr: case eBusDevRespActualValueEvent: if (spBusMsg->msg.devBus.receiverAddr == MY_ADDR) { msgForMe = true; } break; case eBusButtonPressed1: case eBusButtonPressed2: case eBusButtonPressed1_2: msgForMe = true; break; default: break; } } else if (ret == BUS_MSG_ERROR) { ButtonTimeStampRefresh(); } if (msgForMe == false) { return; } switch (msgType) { case eBusDevReqReboot: /* use watchdog to reboot */ /* set the watchdog timeout as short as possible (14 ms) */ cli(); wdt_enable(WDTO_15MS); /* wait for reset */ while (1); break; case eBusButtonPressed1: ButtonEvent(spBusMsg->senderAddr, 1); break; case eBusButtonPressed2: ButtonEvent(spBusMsg->senderAddr, 2); break; case eBusButtonPressed1_2: ButtonEvent(spBusMsg->senderAddr, 1); ButtonEvent(spBusMsg->senderAddr, 2); break; case eBusDevReqInfo: /* response packet */ pInfo = &sTxMsg.msg.devBus.x.devResp.info; sTxMsg.type = eBusDevRespInfo; sTxMsg.senderAddr = MY_ADDR; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; pInfo->devType = eBusDevTypePwm4; strncpy((char *)(pInfo->version), ApplicationVersion(), sizeof(pInfo->version)); pInfo->version[sizeof(pInfo->version) - 1] = '\0'; sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; break; case eBusDevReqActualValue: /* response packet */ pActVal = &sTxMsg.msg.devBus.x.devResp.actualValue; sTxMsg.type = eBusDevRespActualValue; sTxMsg.senderAddr = MY_ADDR; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; pActVal->devType = eBusDevTypePwm4; PwmGetAll(pActVal->actualValue.pwm4.pwm, sizeof(pActVal->actualValue.pwm4.pwm)); val8 = 0; for (i = 0; i < NUM_PWM_CHANNEL; i++) { PwmIsOn(i, &flag); val8 |= flag ? 1 << i: 0; } pActVal->actualValue.pwm4.state = val8; sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; break; case eBusDevReqSetValue: if (spBusMsg->msg.devBus.x.devReq.setValue.devType != eBusDevTypePwm4) { break; } mask8 = spBusMsg->msg.devBus.x.devReq.setValue.setValue.pwm4.set; for (i = 0; i < NUM_PWM_CHANNEL; i++) { action = (0x3 << (i * 2) & mask8) >> (i * 2); switch (action) { case 0x00: /* no action, ignore pwm[] from telegram */ break; case 0x01: /* set current pwm, ignore pwm[] from telegram */ PwmOn(i, true); break; case 0x02: /* set to pwm[] from telegram */ PwmSet(i, spBusMsg->msg.devBus.x.devReq.setValue.setValue.pwm4.pwm[i]); PwmOn(i, true); break; case 0x03: /* off, ignore pwm[] from telegram */ PwmOn(i, false); break; default: break; } } /* response packet */ sTxMsg.type = eBusDevRespSetValue; sTxMsg.senderAddr = MY_ADDR; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; break; case eBusDevReqSwitchState: state = spBusMsg->msg.devBus.x.devReq.switchState.switchState; if ((state & 0x01) != 0) { SwitchEvent(spBusMsg->senderAddr, 1, true); } else { SwitchEvent(spBusMsg->senderAddr, 1, false); } if ((state & 0x02) != 0) { SwitchEvent(spBusMsg->senderAddr, 2, true); } else { SwitchEvent(spBusMsg->senderAddr, 2, false); } /* response packet */ sTxMsg.type = eBusDevRespSwitchState; sTxMsg.senderAddr = MY_ADDR; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; sTxMsg.msg.devBus.x.devResp.switchState.switchState = state; sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; break; case eBusDevReqSetAddr: sTxMsg.senderAddr = MY_ADDR; sTxMsg.type = eBusDevRespSetAddr; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; eeprom_write_byte((uint8_t *)MODUL_ADDRESS, spBusMsg->msg.devBus.x.devReq.setAddr.addr); sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; break; case eBusDevReqEepromRead: sTxMsg.senderAddr = MY_ADDR; sTxMsg.type = eBusDevRespEepromRead; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; sTxMsg.msg.devBus.x.devResp.readEeprom.data = eeprom_read_byte((const uint8_t *)spBusMsg->msg.devBus.x.devReq.readEeprom.addr); sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; break; case eBusDevReqEepromWrite: sTxMsg.senderAddr = MY_ADDR; sTxMsg.type = eBusDevRespEepromWrite; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; eeprom_write_byte((uint8_t *)spBusMsg->msg.devBus.x.devReq.readEeprom.addr, spBusMsg->msg.devBus.x.devReq.writeEeprom.data); sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; break; case eBusDevRespActualValueEvent: pClient = sClient; for (i = 0; i < sNumClients; i++) { if ((pClient->address == spBusMsg->senderAddr) && (pClient->state == eEventWaitForConfirmation)) { TBusDevActualValuePwm4 *p; uint16_t buf[NUM_PWM_CHANNEL]; PwmGetAll(buf, sizeof(buf)); val8 = 0; for (i = 0; i < NUM_PWM_CHANNEL; i++) { PwmIsOn(i, &flag); val8 |= flag ? 1 << i: 0; } p = &spBusMsg->msg.devBus.x.devResp.actualValueEvent.actualValue.pwm4; if ((memcmp(p->pwm, buf, sizeof(buf)) == 0) && (p->state == val8)) { pClient->state = eEventConfirmationOK; } break; } pClient++; } break; case eBusDevReqSetClientAddr: sTxMsg.senderAddr = MY_ADDR; sTxMsg.type = eBusDevRespSetClientAddr; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; for (i = 0; i < BUS_MAX_CLIENT_NUM; i++) { uint8_t *p = &spBusMsg->msg.devBus.x.devReq.setClientAddr.clientAddr[i]; eeprom_write_byte((uint8_t *)(CLIENT_ADDRESS_BASE + i), *p); } sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; GetClientListFromEeprom(); break; case eBusDevReqGetClientAddr: sTxMsg.senderAddr = MY_ADDR; sTxMsg.type = eBusDevRespGetClientAddr; sTxMsg.msg.devBus.receiverAddr = spBusMsg->senderAddr; for (i = 0; i < BUS_MAX_CLIENT_NUM; i++) { uint8_t *p = &sTxMsg.msg.devBus.x.devResp.getClientAddr.clientAddr[i]; *p = eeprom_read_byte((const uint8_t *)(CLIENT_ADDRESS_BASE + i)); } sTxRetry = BusSend(&sTxMsg) != BUS_SEND_OK; break; default: break; } }
/*----------------------------------------------------------------------------- * post state changes to registered bus clients */ static void CheckEvent(void) { static uint8_t sActualClient = 0xff; /* actual client's index being processed */ static uint16_t sChangeTestTimeStamp; TClient *pClient; uint16_t actualTime16; bool actValChanged; static bool sNewClientCycleDelay = false; static uint16_t sNewClientCycleTimeStamp; TBusDevReqActualValueEvent *pActVal; bool getNextClient; uint8_t nextClient; static uint16_t sCurPwmActVal[NUM_PWM_CHANNEL]; static bool sCurPwmState[NUM_PWM_CHANNEL]; uint8_t i; uint8_t val8; if (sNumClients == 0) { return; } /* do the change detection not in each cycle */ GET_TIME_MS16(actualTime16); if (((uint16_t)(actualTime16 - sChangeTestTimeStamp)) >= CHANGE_DETECT_CYCLE_TIME_MS) { PwmGetAll(sCurPwmActVal, sizeof(sCurPwmActVal)); for (i = 0; i < NUM_PWM_CHANNEL; i++) { PwmIsOn(i, &sCurPwmState[i]); } if ((memcmp(sCurPwmActVal, sOldPwmActVal, sizeof(sCurPwmActVal)) == 0) && (memcmp(sCurPwmState, sOldPwmState, sizeof(sCurPwmActVal)) == 0)) { actValChanged = false; } else { actValChanged = true; } if (actValChanged) { memcpy(sOldPwmActVal, sCurPwmActVal, sizeof(sOldPwmActVal)); memcpy(sOldPwmState, sCurPwmState, sizeof(sOldPwmState)); sActualClient = 0; sNewClientCycleDelay = false; InitClientState(); } sChangeTestTimeStamp = actualTime16; } if (sActualClient == 0xff) { return; } if (sNewClientCycleDelay) { if (((uint16_t)(actualTime16 - sNewClientCycleTimeStamp)) < RETRY_CYCLE_TIME_MS) { return; } else { sNewClientCycleDelay = false; } } pClient = &sClient[sActualClient]; getNextClient = true; switch (pClient->state) { case eEventInit: pActVal = &sTxBusMsg.msg.devBus.x.devReq.actualValueEvent; sTxBusMsg.type = eBusDevReqActualValueEvent; sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.msg.devBus.receiverAddr = pClient->address; pActVal->devType = eBusDevTypePwm4; memcpy(pActVal->actualValue.pwm4.pwm, sCurPwmActVal, sizeof(pActVal->actualValue.pwm4.pwm)); val8 = 0; for (i = 0; i < NUM_PWM_CHANNEL; i++) { val8 |= sCurPwmState[i] ? 1 << i : 0; } pActVal->actualValue.pwm4.state = val8; if (BusSend(&sTxBusMsg) == BUS_SEND_OK) { pClient->state = eEventWaitForConfirmation; pClient->requestTimeStamp = actualTime16; } else { getNextClient = false; } break; case eEventWaitForConfirmation: if ((((uint16_t)(actualTime16 - pClient->requestTimeStamp)) >= RESPONSE_TIMEOUT_MS) && (pClient->state != eEventMaxRetry)) { if (pClient->curRetry < pClient->maxRetry) { /* try again */ pClient->curRetry++; getNextClient = false; pClient->state = eEventInit; } else { pClient->state = eEventMaxRetry; } } break; case eEventConfirmationOK: break; default: break; } if (getNextClient) { nextClient = GetUnconfirmedClient(sActualClient); if (nextClient <= sActualClient) { sNewClientCycleDelay = true; sNewClientCycleTimeStamp = actualTime16; } sActualClient = nextClient; } }
/*----------------------------------------------------------------------------- * program start */ int main(void) { UINT8 ret; UINT16 flashWordAddr; UINT16 sum; cli(); MCUSR = 0; wdt_disable(); /* get oscillator correction value from EEPROM */ EEAR = OSCCAL_CORR; /* Start eeprom read by writing EERE */ EECR |= (1 << EERE); /* read data */ OSCCAL += EEDR; /* get modul adress from EEPROM */ EEAR = MODUL_ADDRESS; /* Start eeprom read by writing EERE */ EECR |= (1 << EERE); /* read data */ sMyAddr = EEDR; /* configure pins to input with pull up */ PORTB = 0b11111111; DDRB = 0b00000000; PORTC = 0b11111111; DDRC = 0b00000000; PORTD = 0b11111111; DDRD = 0b00100010; /* configure Timer 0 */ /* prescaler clk/64 -> Interrupt period 256/1000000 * 64 = 16.384 ms */ TCCR0B = 3 << CS00; TIMSK0 = 1 << TOIE0; SioInit(); spRxBusMsg = BusMsgBufGet(); /* Enable change of Interrupt Vectors */ MCUCR = (1 << IVCE); /* Move interrupts to Boot Flash section */ MCUCR = (1 << IVSEL); /* Prüfsumme der Applikation berechnen */ sum = 0; for (flashWordAddr = 0; flashWordAddr < (MAX_FIRMWARE_SIZE / 2); flashWordAddr += CHECKSUM_BLOCK_SIZE) { sum += FlashSum(flashWordAddr, (UINT8)CHECKSUM_BLOCK_SIZE); } if (sum != FLASH_CHECKSUM) { /* Fehler */ sFwuState = WAIT_FOR_UPD_ENTER; } sei(); /* Startup-Msg senden */ sTxBusMsg.type = eBusDevStartup; sTxBusMsg.senderAddr = MY_ADDR; BusSend(&sTxBusMsg); SioReadFlush(); /* Hauptschleife */ while (1) { ret = BusCheck(); ProcessBus(ret); /* Mit timeout auf Request zum Firmwareupdate warten */ if (sFwuState == WAIT_FOR_UPD_ENTER_TIMEOUT) { if (gTimeS8 >= 4) { /* Application starten */ break; } } } cli(); /* Enable change of Interrupt Vectors */ MCUCR = (1 << IVCE); /* Move interrupts to application section */ MCUCR = (0 << IVSEL); /* jump to application */ ApplicationEntry(); /* never reach this */ return 0; }
/*----------------------------------------------------------------------------- * Verarbeitung der Bustelegramme */ static void ProcessBus(UINT8 ret) { TBusMsgType msgType; UINT16 *pData; UINT16 wordAddr; BOOL rc; BOOL msgForMe = FALSE; if (ret == BUS_MSG_OK) { msgType = spRxBusMsg->type; switch (msgType) { case eBusDevReqReboot: case eBusDevReqUpdEnter: case eBusDevReqUpdData: case eBusDevReqUpdTerm: if (spRxBusMsg->msg.devBus.receiverAddr == MY_ADDR) { msgForMe = TRUE; } default: break; } if (msgForMe == FALSE) { return; } if (msgType == eBusDevReqReboot) { /* Über Watchdog Reset auslösen */ /* Watchdogtimeout auf kurzeste Zeit (14 ms) stellen */ cli(); wdt_enable(WDTO_15MS); /* warten auf Reset */ while (1); } else { switch (sFwuState) { case WAIT_FOR_UPD_ENTER_TIMEOUT: case WAIT_FOR_UPD_ENTER: if (msgType == eBusDevReqUpdEnter) { /* Applicationbereich des Flash löschen */ FlashErase(); /* Antwort senden */ SetMsg(eBusDevRespUpdEnter, spRxBusMsg->senderAddr); BusSend(&sTxBusMsg); sFwuState = WAIT_FOR_UPD_DATA; } break; case WAIT_FOR_UPD_DATA: if (msgType == eBusDevReqUpdData) { wordAddr = spRxBusMsg->msg.devBus.x.devReq.updData.wordAddr; pData = spRxBusMsg->msg.devBus.x.devReq.updData.data; /* Flash programmieren */ rc = FlashProgram(wordAddr, pData, sizeof(spRxBusMsg->msg.devBus.x.devReq.updData.data) / 2); /* Antwort senden */ SetMsg(eBusDevRespUpdData, spRxBusMsg->senderAddr); if (rc == TRUE) { /* Falls Programmierung des Block OK: empfangene wordAddr zurücksenden */ sTxBusMsg.msg.devBus.x.devResp.updData.wordAddr = wordAddr; } else { /* Problem bei Programmierung: -1 als wordAddr zurücksenden */ sTxBusMsg.msg.devBus.x.devResp.updData.wordAddr = -1; } BusSend(&sTxBusMsg); } else if (msgType == eBusDevReqUpdTerm) { /* programmiervorgang im Flash abschließen (falls erforderlich) */ rc = FlashProgramTerminate(); /* Antwort senden */ SetMsg(eBusDevRespUpdTerm, spRxBusMsg->senderAddr); if (rc == TRUE) { /* Falls Programmierung OK: success auf 1 setzen */ sTxBusMsg.msg.devBus.x.devResp.updTerm.success = 1; } else { /* Problem bei Programmierung: -1 als wordAddr zurücksenden */ sTxBusMsg.msg.devBus.x.devResp.updTerm.success = 0; } BusSend(&sTxBusMsg); } break; default: break; } } } }
/*----------------------------------------------------------------------------- * process received bus telegrams */ static void ProcessBus(void) { uint8_t ret; TClient *pClient; TBusMsgType msgType; uint8_t i; uint8_t *p; bool msgForMe = false; ret = BusCheck(); if (ret == BUS_MSG_OK) { msgType = spRxBusMsg->type; switch (msgType) { case eBusDevReqReboot: case eBusDevRespSwitchState: case eBusDevReqActualValue: case eBusDevReqSetClientAddr: case eBusDevReqGetClientAddr: case eBusDevReqInfo: case eBusDevReqSetAddr: case eBusDevReqEepromRead: case eBusDevReqEepromWrite: if (spRxBusMsg->msg.devBus.receiverAddr == MY_ADDR) { msgForMe = true; } break; default: break; } if (msgForMe == false) { return; } switch (msgType) { case eBusDevReqReboot: /* reset controller with watchdog */ /* set watchdog timeout to shortest value (14 ms) */ cli(); wdt_enable(WDTO_15MS); /* wait for reset */ while (1); break; case eBusDevRespSwitchState: pClient = &sClient[0]; for (i = 0; i < BUS_MAX_CLIENT_NUM; i++) { if (pClient->state == eSkip) { pClient++; continue; } else if ((pClient->address == spRxBusMsg->senderAddr) && (spRxBusMsg->msg.devBus.x.devResp.switchState.switchState == sSwitchStateActual) && ((pClient->state == eWaitForConfirmation1) || (pClient->state == eWaitForConfirmation2))) { pClient->state = eConfirmationOK; break; } pClient++; } break; case eBusDevReqActualValue: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespActualValue; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; sTxBusMsg.msg.devBus.x.devResp.actualValue.devType = eBusDevTypeSw8; sTxBusMsg.msg.devBus.x.devResp.actualValue.actualValue.sw8.state = sSwitchStateActual; BusSend(&sTxBusMsg); break; case eBusDevReqSetClientAddr: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespSetClientAddr; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; for (i = 0; i < BUS_MAX_CLIENT_NUM; i++) { p = &(spRxBusMsg->msg.devBus.x.devReq.setClientAddr.clientAddr[i]); eeprom_write_byte((uint8_t *)(CLIENT_ADDRESS_BASE + i), *p); } BusSend(&sTxBusMsg); break; case eBusDevReqGetClientAddr: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespGetClientAddr; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; for (i = 0; i < BUS_MAX_CLIENT_NUM; i++) { p = &(sTxBusMsg.msg.devBus.x.devResp.getClientAddr.clientAddr[i]); *p = eeprom_read_byte((const uint8_t *)(CLIENT_ADDRESS_BASE + i)); } BusSend(&sTxBusMsg); break; case eBusDevReqInfo: sTxBusMsg.type = eBusDevRespInfo; sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; sTxBusMsg.msg.devBus.x.devResp.info.devType = eBusDevTypeSw8; strncpy((char *)(sTxBusMsg.msg.devBus.x.devResp.info.version), version, BUS_DEV_INFO_VERSION_LEN); sTxBusMsg.msg.devBus.x.devResp.info.version[BUS_DEV_INFO_VERSION_LEN - 1] = '\0'; BusSend(&sTxBusMsg); break; case eBusDevReqSetAddr: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespSetAddr; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; p = &(spRxBusMsg->msg.devBus.x.devReq.setAddr.addr); eeprom_write_byte((uint8_t *)MODUL_ADDRESS, *p); BusSend(&sTxBusMsg); break; case eBusDevReqEepromRead: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespEepromRead; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; sTxBusMsg.msg.devBus.x.devResp.readEeprom.data = eeprom_read_byte((const uint8_t *)spRxBusMsg->msg.devBus.x.devReq.readEeprom.addr); BusSend(&sTxBusMsg); break; case eBusDevReqEepromWrite: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespEepromWrite; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; p = &(spRxBusMsg->msg.devBus.x.devReq.writeEeprom.data); eeprom_write_byte((uint8_t *)spRxBusMsg->msg.devBus.x.devReq.readEeprom.addr, *p); BusSend(&sTxBusMsg); break; default: break; } } }
/*----------------------------------------------------------------------------- * send button pressed telegram * telegram is repeated every 48 ms for max 8 secs */ static void ProcessButton(uint8_t buttonState) { static uint8_t sSequenceState = BUTTON_TX_OFF; static uint16_t sStartTimeS; static uint8_t sTimeStampMs; bool pressed; uint16_t actualTimeS; uint8_t actualTimeMs; /* buttons pull down pins to ground when pressed */ switch (buttonState) { case 0: sTxBusMsg.type = eBusButtonPressed1_2; pressed = true; break; case 1: sTxBusMsg.type = eBusButtonPressed2; pressed = true; break; case 2: sTxBusMsg.type = eBusButtonPressed1; pressed = true; break; default: pressed = false; break; } switch (sSequenceState) { case BUTTON_TX_OFF: if (pressed) { /* begin transmission of eBusButtonPressed* telegram */ GET_TIME_S(sStartTimeS); sTimeStampMs = GET_TIME_MS; sTxBusMsg.senderAddr = MY_ADDR; BusSend(&sTxBusMsg); sSequenceState = BUTTON_TX_ON; } break; case BUTTON_TX_ON: if (pressed) { GET_TIME_S(actualTimeS); if ((uint16_t)(actualTimeS - sStartTimeS) < BUTTON_TELEGRAM_REPEAT_TIMEOUT) { actualTimeMs = GET_TIME_MS; if ((uint8_t)(actualTimeMs - sTimeStampMs) >= BUTTON_TELEGRAM_REPEAT_DIFF) { sTimeStampMs = GET_TIME_MS; sTxBusMsg.senderAddr = MY_ADDR; BusSend(&sTxBusMsg); } } else { sSequenceState = BUTTON_TX_TIMEOUT; } } else { sSequenceState = BUTTON_TX_OFF; } break; case BUTTON_TX_TIMEOUT: if (!pressed) { sSequenceState = BUTTON_TX_OFF; } break; default: sSequenceState = BUTTON_TX_OFF; break; } }
/*----------------------------------------------------------------------------- * send switch state change to clients * - client address list is read from eeprom * - if there is no confirmation from client within RESPONSE_TIMEOUT2 * the next client in list is processed * - telegrams to clients without response are repeated again and again * til telegrams to all clients in list are confirmed * - if switchStateChanged occurs while client confirmations are missing * actual client process is canceled and the new state telegram is sent * to clients */ static void ProcessSwitch(uint8_t switchState) { static uint8_t sActualClient = 0xff; /* actual client's index being processed */ static uint16_t sChangeTimeStamp; TClient *pClient; uint8_t i; uint16_t actualTime16; uint8_t actualTime8; bool switchStateChanged; bool startProcess; if ((switchState ^ sSwitchStateOld) != 0) { switchStateChanged = true; } else { switchStateChanged = false; } if (switchStateChanged) { if (sActualClient < BUS_MAX_CLIENT_NUM) { pClient = &sClient[sActualClient]; if (pClient->state == eWaitForConfirmation1) { startProcess = false; } else { startProcess = true; sSwitchStateOld = switchState; } } else { startProcess = true; sSwitchStateOld = switchState; } if (startProcess == true) { sSwitchStateActual = switchState; GET_TIME_MS16(sChangeTimeStamp); /* set up client descriptor array */ sActualClient = 0; pClient = &sClient[0]; for (i = 0; i < BUS_MAX_CLIENT_NUM; i++) { pClient->address = eeprom_read_byte((const uint8_t *)(CLIENT_ADDRESS_BASE + i)); if (pClient->address != BUS_CLIENT_ADDRESS_INVALID) { pClient->state = eInit; } else { pClient->state = eSkip; } pClient++; } } } if (sActualClient < BUS_MAX_CLIENT_NUM) { GET_TIME_MS16(actualTime16); if (((uint16_t)(actualTime16 - sChangeTimeStamp)) < RETRY_TIMEOUT2_MS) { pClient = &sClient[sActualClient]; if (pClient->state == eConfirmationOK) { /* get next client */ sActualClient = GetUnconfirmedClient(sActualClient); if (sActualClient < BUS_MAX_CLIENT_NUM) { pClient = &sClient[sActualClient]; } else { /* we are ready */ } } switch (pClient->state) { case eInit: sTxBusMsg.type = eBusDevReqSwitchState; sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.msg.devBus.receiverAddr = pClient->address; sTxBusMsg.msg.devBus.x.devReq.switchState.switchState = sSwitchStateActual; BusSend(&sTxBusMsg); pClient->state = eWaitForConfirmation1; GET_TIME_MS16(pClient->requestTimeStamp); break; case eWaitForConfirmation1: actualTime8 = GET_TIME_MS; if (((uint8_t)(actualTime8 - pClient->requestTimeStamp)) >= RESPONSE_TIMEOUT1_MS) { pClient->state = eWaitForConfirmation2; GET_TIME_MS16(pClient->requestTimeStamp); } break; case eWaitForConfirmation2: GET_TIME_MS16(actualTime16); if (((uint16_t)(actualTime16 - pClient->requestTimeStamp)) >= RESPONSE_TIMEOUT2_MS) { /* set client for next try after the other clients */ pClient->state = eInit; /* try next client */ sActualClient = GetUnconfirmedClient(sActualClient); } break; default: break; } } else { sActualClient = 0xff; } } }
/*----------------------------------------------------------------------------- * post state changes to registered bus clients */ static void ProcessSwitch(void) { static uint8_t sActualClient = 0xff; /* actual client's index being processed */ static uint16_t sChangeTimeStamp; TClient *pClient; uint16_t actualTime16; static bool sNewClientCycleDelay = false; static uint16_t sNewClientCycleTimeStamp; uint8_t rc; bool getNextClient; uint8_t nextClient; bool switchStateChanged; if (sNumClients == 0) { return; } if ((sWindSwitch ^ sWindSwitchOld) != 0) { switchStateChanged = true; } else { switchStateChanged = false; } /* do the change detection not in each cycle */ GET_TIME_MS16(actualTime16); if (switchStateChanged) { sChangeTimeStamp = actualTime16; sActualClient = 0; sNewClientCycleDelay = false; InitClientState(); sWindSwitchOld = sWindSwitch; } if (sActualClient == 0xff) { return; } if (sNewClientCycleDelay) { if (((uint16_t)(actualTime16 - sNewClientCycleTimeStamp)) < RETRY_CYCLE_TIME_MS) { return; } else { sNewClientCycleDelay = false; } } pClient = &sClient[sActualClient]; getNextClient = true; switch (pClient->state) { case eInit: sTxBusMsg.type = eBusDevReqSwitchState; sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.msg.devBus.receiverAddr = pClient->address; sTxBusMsg.msg.devBus.x.devReq.switchState.switchState = sWindSwitch; rc = BusSend(&sTxBusMsg); if (rc == BUS_SEND_OK) { pClient->state = eWaitForConfirmation; pClient->requestTimeStamp = actualTime16; } else { getNextClient = false; } break; case eWaitForConfirmation: if (((uint16_t)(actualTime16 - pClient->requestTimeStamp)) >= RESPONSE_TIMEOUT_MS) { /* try once more */ pClient->state = eInit; getNextClient = false; } break; case eConfirmationOK: break; default: break; } if (getNextClient) { nextClient = GetUnconfirmedClient(sActualClient); if (nextClient <= sActualClient) { sNewClientCycleDelay = true; sNewClientCycleTimeStamp = actualTime16; } sActualClient = nextClient; } if (((uint16_t)(actualTime16 - sChangeTimeStamp)) > RETRY_TIMEOUT_MS) { sActualClient = 0xff; // stop } }
/*----------------------------------------------------------------------------- * Programstart */ int main(void) { UINT8 ret; UINT16 flashWordAddr; UINT16 sum; /* get oscillator correction value from EEPROM */ EEAR = OSCCAL_CORR; /* Start eeprom read by writing EERE */ EECR |= (1 << EERE); /* read data */ OSCCAL += EEDR; /* get modul adress from EEPROM */ EEAR = MODUL_ADDRESS; /* Start eeprom read by writing EERE */ EECR |= (1 << EERE); /* read data */ sMyAddr = EEDR; /* Portpins für Schaltereingänge mit Pullup konfigurieren */ /* nicht benutzte Pin aus Ausgang Low*/ PORTC = 0x03; DDRC = 0x3C; PORTB = 0x38; DDRB = 0xC7; PORTD = 0x01; DDRD = 0xFE; /* configure Timer 0 */ /* prescaler clk/64 -> Interrupt period 256/1000000 * 64 = 16.384 ms */ TCCR0 = 3 << CS00; TIMSK = 1 << TOIE0; SioInit(); spRxBusMsg = BusMsgBufGet(); /* Umschaltung der Interruptvektor-Tabelle */ GICR = (1 << IVCE); /* In Bootbereich verschieben */ GICR = (1 << IVSEL); /* Prüfsumme der Applikation berechnen */ sum = 0; for (flashWordAddr = 0; flashWordAddr < (MAX_FIRMWARE_SIZE / 2); flashWordAddr += CHECKSUM_BLOCK_SIZE) { sum += FlashSum(flashWordAddr, (UINT8)CHECKSUM_BLOCK_SIZE); } if (sum != FLASH_CHECKSUM) { /* Fehler */ sFwuState = WAIT_FOR_UPD_ENTER; } sei(); /* Startup-Msg senden */ sTxBusMsg.type = eBusDevStartup; sTxBusMsg.senderAddr = MY_ADDR; BusSend(&sTxBusMsg); SioReadFlush(); /* Hauptschleife */ while (1) { ret = BusCheck(); ProcessBus(ret); /* Mit timeout auf Request zum Firmwareupdate warten */ if (sFwuState == WAIT_FOR_UPD_ENTER_TIMEOUT) { if (gTimeS8 >= 4) { /* Application starten */ break; } } } cli(); /* Umschaltung der Interruptvektor-Tabelle */ GICR = (1 << IVCE); /* In Applikationsbereich verschieben */ GICR = (0 << IVSEL); /* zur Applikation springen */ ApplicationEntry(); /* hier kommen wir nicht her!!*/ return 0; }
/*----------------------------------------------------------------------------- * process received bus telegrams */ static void ProcessBus(void) { uint8_t ret; TBusMsgType msgType; uint8_t i; uint8_t *p; bool msgForMe = false; uint8_t flags; uint8_t old_osccal; static uint8_t sOsccal = 0; uint16_t startCnt; uint16_t stopCnt; uint16_t clocks; uint16_t diff; uint16_t seqLen; static int sCount = 0; static uint16_t sMinDiff = 0xffff; static uint8_t sMinOsccal = 0; uint8_t osccal_corr; ret = BusCheck(); if (ret == BUS_MSG_OK) { msgType = spRxBusMsg->type; switch (msgType) { case eBusDevReqReboot: case eBusDevReqInfo: case eBusDevReqSetAddr: case eBusDevReqEepromRead: case eBusDevReqEepromWrite: case eBusDevReqDoClockCalib: if (spRxBusMsg->msg.devBus.receiverAddr == MY_ADDR) { msgForMe = true; } break; default: break; } if (msgForMe == false) { return; } switch (msgType) { case eBusDevReqReboot: /* reset controller with watchdog */ /* set watchdog timeout to shortest value (14 ms) */ cli(); wdt_enable(WDTO_15MS); /* wait for reset */ while (1); break; case eBusDevReqInfo: sTxBusMsg.type = eBusDevRespInfo; sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; sTxBusMsg.msg.devBus.x.devResp.info.devType = eBusDevTypeSw8Cal; strncpy((char *)(sTxBusMsg.msg.devBus.x.devResp.info.version), version, BUS_DEV_INFO_VERSION_LEN); sTxBusMsg.msg.devBus.x.devResp.info.version[BUS_DEV_INFO_VERSION_LEN - 1] = '\0'; BusSend(&sTxBusMsg); break; case eBusDevReqSetAddr: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespSetAddr; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; p = &(spRxBusMsg->msg.devBus.x.devReq.setAddr.addr); eeprom_write_byte((uint8_t *)MODUL_ADDRESS, *p); BusSend(&sTxBusMsg); break; case eBusDevReqEepromRead: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespEepromRead; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; sTxBusMsg.msg.devBus.x.devResp.readEeprom.data = eeprom_read_byte((const uint8_t *)spRxBusMsg->msg.devBus.x.devReq.readEeprom.addr); BusSend(&sTxBusMsg); break; case eBusDevReqEepromWrite: sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespEepromWrite; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; p = &(spRxBusMsg->msg.devBus.x.devReq.writeEeprom.data); eeprom_write_byte((uint8_t *)spRxBusMsg->msg.devBus.x.devReq.readEeprom.addr, *p); BusSend(&sTxBusMsg); break; case eBusDevReqDoClockCalib: if (spRxBusMsg->msg.devBus.x.devReq.doClockCalib.command == eBusDoClockCalibInit) { sCount = 0; sOsccal = 0; sMinDiff = 0xffff; } else if (sCount > MAX_CAL_TEL) { sTxBusMsg.msg.devBus.x.devResp.doClockCalib.state = eBusDoClockCalibStateError; sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespDoClockCalib; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; BusSend(&sTxBusMsg); break; } flags = DISABLE_INT; BUS_TRANSCEIVER_POWER_UP; PORTB = 0; /* 8 bytes 0x00: 8 * (1 start bit + 8 data bits) + 7 stop bits */ seqLen = 8 * 1000000 * 9 / 9600 + 7 * 1000000 * 1 / 9600; /* = 8229 us */ old_osccal = OSCCAL; ExitComm(); InitTimer1(); TCCR1B = (1 << ICES1) | TIMER1_PRESCALER; OSCCAL = sOsccal; NOP_10; for (i = 0; i < 8; i++) { startCnt = Synchronize(); stopCnt = ClkMeasure(); clocks = stopCnt - startCnt; if (clocks > seqLen) { diff = clocks - seqLen; } else { diff = seqLen - clocks; } if (diff < sMinDiff) { sMinDiff = diff; sMinOsccal = OSCCAL; } OSCCAL++; NOP_4; } BUS_TRANSCEIVER_POWER_DOWN; InitTimer1(); InitComm(); sOsccal = OSCCAL; OSCCAL = old_osccal; RESTORE_INT(flags); if (sCount < MAX_CAL_TEL) { sTxBusMsg.msg.devBus.x.devResp.doClockCalib.state = eBusDoClockCalibStateContiune; sCount++; } else { sTxBusMsg.msg.devBus.x.devResp.doClockCalib.state = eBusDoClockCalibStateSuccess; /* save the osccal correction value to eeprom */ osccal_corr = eeprom_read_byte((const uint8_t *)OSCCAL_CORR); osccal_corr += sMinOsccal - old_osccal; eeprom_write_byte((uint8_t *)OSCCAL_CORR, osccal_corr); OSCCAL = sMinOsccal; NOP_10; } sTxBusMsg.senderAddr = MY_ADDR; sTxBusMsg.type = eBusDevRespDoClockCalib; sTxBusMsg.msg.devBus.receiverAddr = spRxBusMsg->senderAddr; BusSend(&sTxBusMsg); break; default: break; } } }