// Message delivered through _msg void _processInternalMessages() { bool isMetric; uint8_t type = _msg.type; #if !defined(MY_DISABLE_REMOTE_RESET) if (type == I_REBOOT) { // Requires MySensors or other bootloader with watchdogs enabled hwReboot(); } else #endif if (type == I_CONFIG) { // Pick up configuration from controller (currently only metric/imperial) // and store it in eeprom if changed if (_msg.getString() == NULL) { isMetric = true; } else { isMetric = _msg.getString()[0] == 'M'; } _cc.isMetric = isMetric; hwWriteConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); } else if (type == I_PRESENTATION) { if (!mGetAck(_msg)) { // Re-send node presentation to controller #if defined(MY_RADIO_FEATURE) transportPresentNode(); #endif if (presentation) presentation(); } } else if (type == I_HEARTBEAT) { sendHeartbeat(); } else if (type == I_TIME) { // Deliver time to callback if (receiveTime) receiveTime(_msg.getULong()); } #if defined(MY_REPEATER_FEATURE) if (type == I_CHILDREN) { if (_msg.getString()[0] == 'C') { // Clears child relay data for this node debug(PSTR("clear routing table\n")); uint8_t i = 255; do { hwWriteConfig(EEPROM_ROUTES_ADDRESS+i, BROADCAST_ADDRESS); } while (i--); // Clear parent node id & distance to gw hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, AUTO); hwWriteConfig(EEPROM_DISTANCE_ADDRESS, DISTANCE_INVALID); // Find parent node transportFindParentNode(); _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("")); } } #endif }
void transportSetRoute(const uint8_t node, const uint8_t route) { #if defined(MY_RAM_ROUTING_TABLE_ENABLED) _transportRoutingTable.route[node] = route; #else hwWriteConfig(EEPROM_ROUTES_ADDRESS + node, route); #endif }
void nodeLock(const char* str) { // Make sure EEPROM is updated to locked status hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, 0); while (1) { debug(PSTR("Node is locked. Ground pin %d and reset to unlock.\n"), MY_NODE_UNLOCK_PIN); #if defined(MY_GATEWAY_ESP8266) yield(); #endif _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_LOCKED, false).set(str)); #if defined(MY_RADIO_FEATURE) transportPowerDown(); #endif (void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message } }
bool transportAssignNodeID(const uint8_t newNodeId) { // verify if ID valid if (newNodeId != GATEWAY_ADDRESS && newNodeId != AUTO) { _transportConfig.nodeId = newNodeId; transportSetAddress(newNodeId); // Write ID to EEPROM hwWriteConfig(EEPROM_NODE_ID_ADDRESS, newNodeId); TRANSPORT_DEBUG(PSTR("TSF:SID:OK,ID=%d\n"),newNodeId); // Node ID assigned return true; } else { TRANSPORT_DEBUG(PSTR("!TSF:SID:FAIL,ID=%d\n"),newNodeId); // ID is invalid, cannot assign ID setIndication(INDICATION_ERR_NET_FULL); _transportConfig.nodeId = AUTO; return false; } }
// stParent: find parent void stParentTransition(void) { TRANSPORT_DEBUG(PSTR("TSM:FPAR\n")); // find parent setIndication(INDICATION_FIND_PARENT); _transportSM.uplinkOk = false; _transportSM.preferredParentFound = false; #if defined(MY_PARENT_NODE_IS_STATIC) TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"), (uint8_t)MY_PARENT_NODE_ID); // static parent _transportSM.findingParentNode = false; _transportConfig.distanceGW = 1u; // assumption, CHKUPL:GWDC will update this variable _transportConfig.parentNodeId = (uint8_t)MY_PARENT_NODE_ID; // save parent ID to eeprom (for bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, (uint8_t)MY_PARENT_NODE_ID); #else _transportSM.findingParentNode = true; _transportConfig.distanceGW = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID _transportConfig.parentNodeId = AUTO; // Broadcast find parent request (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_REQUEST).set("")); #endif }
void stInitUpdate(void) { // initialise radio if (!transportInit()) { TRANSPORT_DEBUG(PSTR("!TSM:INIT:TSP FAIL\n")); setIndication(INDICATION_ERR_INIT_TRANSPORT); transportSwitchSM(stFailure); } else { TRANSPORT_DEBUG(PSTR("TSM:INIT:TSP OK\n")); _transportSM.transportActive = true; #if defined(MY_GATEWAY_FEATURE) // Set configuration for gateway TRANSPORT_DEBUG(PSTR("TSM:INIT:GW MODE\n")); _transportConfig.parentNodeId = GATEWAY_ADDRESS; _transportConfig.distanceGW = 0u; _transportConfig.nodeId = GATEWAY_ADDRESS; transportSetAddress(GATEWAY_ADDRESS); // GW mode: skip FPAR,ID,UPL states transportSwitchSM(stReady); #else if (MY_NODE_ID != AUTO) { TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%d\n"),(uint8_t)MY_NODE_ID); // Set static ID _transportConfig.nodeId = (uint8_t)MY_NODE_ID; // Save static ID to eeprom (for bootloader) hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID); } // assign ID if set if (_transportConfig.nodeId == AUTO || transportAssignNodeID(_transportConfig.nodeId)) { // if node ID valid (>0 and <255), proceed to next state transportSwitchSM(stParent); } else { // ID invalid (0 or 255) transportSwitchSM(stFailure); } #endif } }
void _begin() { #if !defined(MY_DISABLED_SERIAL) hwInit(); #endif // Call before() in sketch (if it exists) if (before) before(); debug(PSTR("Starting " MY_NODE_TYPE " (" MY_CAPABILITIES ", " LIBRARY_VERSION ")\n")); signerInit(); #if defined(MY_RADIO_FEATURE) _failedTransmissions = 0; // Setup radio if (!transportInit()) { debug(PSTR("Radio init failed. Check wiring.\n")); // Nothing more we can do _infiniteLoop(); } else { debug(PSTR("Radio init successful.\n")); } #endif #if defined(MY_GATEWAY_FEATURE) #if defined(MY_INCLUSION_BUTTON_FEATURE) inclusionInit(); #endif // initialize the transport driver if (!gatewayTransportInit()) { debug(PSTR("Transport driver init fail\n")); // Nothing more we can do _infiniteLoop(); } #endif #if defined(MY_LEDS_BLINKING_FEATURE) ledsInit(); #endif // Read latest received controller configuration from EEPROM hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); if (_cc.isMetric == 0xff) { // Eeprom empty, set default to metric _cc.isMetric = 0x01; } #if defined(MY_GATEWAY_FEATURE) // Set configuration for gateway _nc.parentNodeId = GATEWAY_ADDRESS; _nc.distance = 0; _nc.nodeId = GATEWAY_ADDRESS; #elif defined(MY_RADIO_FEATURE) // Read settings from eeprom hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); #ifdef MY_OTA_FIRMWARE_FEATURE // Read firmware config from EEPROM, i.e. type, version, CRC, blocks hwReadConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); #endif _autoFindParent = MY_PARENT_NODE_ID == AUTO; if (!_autoFindParent) { _nc.parentNodeId = MY_PARENT_NODE_ID; // Save static parent id in eeprom (used by bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); // We don't actually know the distance to gw here. Let's pretend it is 1. // If the current node is also repeater, be aware of this. _nc.distance = 1; } else if (!isValidParent(_nc.parentNodeId)) { // Auto find parent, but parent in eeprom is invalid. Try find one. transportFindParentNode(); } if (MY_NODE_ID != AUTO) { // Set static id _nc.nodeId = MY_NODE_ID; // Save static id in eeprom hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID); } else if (_nc.nodeId == AUTO && isValidParent(_nc.parentNodeId)) { // Try to fetch node-id from gateway transportRequestNodeId(); } #endif #ifdef MY_NODE_LOCK_FEATURE // Check if node has been locked down if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0) { // Node is locked, check if unlock pin is asserted, else hang the node pinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP); // Make a short delay so we are sure any large external nets are fully pulled unsigned long enter = hwMillis(); while (hwMillis() - enter < 2); if (digitalRead(MY_NODE_UNLOCK_PIN) == 0) { // Pin is grounded, reset lock counter hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); // Disable pullup pinMode(MY_NODE_UNLOCK_PIN, INPUT); debug(PSTR("Node is unlocked.\n")); } else { // Disable pullup pinMode(MY_NODE_UNLOCK_PIN, INPUT); nodeLock("LDB"); //Locked during boot } } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) { // Reset walue hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); } #endif // Call sketch setup if (setup) setup(); #if defined(MY_RADIO_FEATURE) transportPresentNode(); #endif if (presentation) presentation(); debug(PSTR("Init complete, id=%d, parent=%d, distance=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance); }
void saveState(uint8_t pos, uint8_t value) { hwWriteConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value); }