/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad * Copyright (C) 2013-2015 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ /** * @file MyTransport.h * * @defgroup MyTransportgrp MyTransport * @ingroup internals * @{ * * Transport-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE * - [!] Exclamation mark is prepended in case of error * - SYSTEM: * - TSM: messages emitted by the transport state machine * - TSF: messages emitted by transport support functions * - SUB SYSTEMS: * - Transport state machine (TSM) * - TSM:INIT from stInit Initialize transport and radio * - TSM:FPAR from stParent Find parent * - TSM:ID from stID Check/request node ID, if dynamic node ID set * - TSM:UPL from stUplink Verify uplink connection by pinging GW * - TSM:READY from stReady Transport is ready and fully operational * - TSM:FAILURE from stFailure Failure in transport link or transport HW * - Transport support function (TSF) * - TSF:CHKUPL from @ref transportCheckUplink(..), checks connection to GW * - TSF:ASID from @ref transportAssignNodeID(..), assigns node ID * - TSF:PING from @ref transportPingNode(..), pings a node * - TSF:CRT from @ref transportClearRoutingTable(..), clears routing table stored in EEPROM * - TSF:MSG from @ref transportProcessMessage(..), processes incoming message * - TSF:SANCHK from @ref transportInvokeSanityCheck(..), calls transport-specific sanity check * - TSF:ROUTE from @ref transportRouteMessage(..), sends message * - TSF:SEND from @ref transportSendRoute(..), sends message if transport is ready (exposed) * * TSM state stInit log status / errors * - TSM:INIT Transition to stInit state * - TSM:INIT:STATID,ID=x Node ID x is static * - TSM:INIT:TSP OK Transport device configured and fully operational * - TSM:INIT:GW MODE Node is set up as GW, thus omitting ID and findParent states * - !TSM:INIT:TSP FAIL Transport device initialization failed * * TSM state stParent log status / errors * - TSM:FPAR Transition to stParent state * - TSM:FPAR:STATP=x Static parent x set, skip finding parent * - TSM:FPAR:OK Parent node identified * - !TSM:FPAR:NO REPLY No potential parents replied to find parent request, retry * - !TSM:FPAR:FAIL Finding parent failed, go to failure state * * TSM state stID log status / errors * - TSM:ID Transition to stID state * - TSM:ID:OK,ID=x Node ID x is valid * - TSM:ID:REQ Request node ID from controller * - !TSM:ID:FAIL,ID=x ID verification failed, ID x invalid * * TSM state stUplink log status / errors * - TSM:UPL Transition to stUplink state * - TSM:UPL:OK Uplink OK, GW returned ping * - !TSM:UPL:FAIL Uplink check failed, i.e. GW could not be pinged * * TSM state stReady log status / errors * - TSM:READY Transition to stReady, i.e. transport is ready and fully operational * - !TSM:READY:UPL FAIL,SNP Too many failed uplink transmissions, search new parent * - !TSM:READY:UPL FAIL,STATP Too many failed uplink transmissions, no SNP, static parent enforced * * TSM state stFailure information / status * - TSM:FAILURE Transition to stFailure state * - TSM:FAILURE:PDT Power-down transport * - TSM:FAILURE:RE-INIT Attempt to re-initialize transport * * TSF information / status * - TSF:CHKUPL:OK Uplink OK * - TSF:CHKUPL:OK,FCTRL Uplink OK, flood control prevents pinging GW in too short intervals * - TSF:CHKUPL:DGWC,O=x,N=y Checking uplink revealed a changed network topology, old distance x, new distance y * - TSF:CHKUPL:FAIL No reply received when checking uplink * - TSF:ASID:OK,ID=x Node ID x assigned * - TSF:PING:SEND,TO=x Send ping to destination x * - TSF:MSG:ACK REQ ACK message requested * - TSF:MSG:ACK ACK message, do not proceed but forward to callback * - TSF:MSG:FPAR RES,ID=x,D=y Response to find parent received from node x with distance y to GW * - TSF:MSG:FPAR PREF FOUND Preferred parent found * - TSF:MSG:FPAR OK,ID=x,D=y Find parent reponse from node x is valid, distance y to GW * - TSF:MSG:FPAR INACTIVE Find parent response received, but no find parent request active, skip response * - TSF:MSG:FPAR REQ,ID=x Find parent request from node x * - TSF:MSG:PINGED,ID=x,HP=y Node pinged by node x with y hops * - TSF:MSG:PONG RECV,HP=x Pinged node replied with x hops * - TSF:MSG:BC Broadcast message received * - TSF:MSG:GWL OK Link to GW ok * - TSF:MSG:FWD BC MSG Controlled broadcast message forwarding * - TSF:MSG:REL MSG Relay message * - TSF:MSG:REL PxNG,HP=x Relay PING/PONG message, increment hop counter x * - TSF:SANCHK:OK Sanity check passed. This ensures radio functionality and automatically attempts to re-initialize in case of failure * - TSF:CRT:OK Clearing routing table successful * * Incoming / outgoing messages * * See here for more detail on the format and definitons. * * Receiving a message * - TSF:MSG:READ,sender-last-destination,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s * Sending a message * - [!]TSF:MSG:SEND,sender-last-next-destination,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,ft=%d,st=%s:%s * * - Message fields: * - s=sensor ID * - c=command * - t=msg type * - pt=payload type * - l=length * - ft=failed uplink transmission counter * - sg=signing flag * * TSF errors * - !TSF:ASID:FAIL,ID=x Assigned ID x is invalid, e.g. 0 (GATEWAY) * - !TSF:ROUTE:FPAR ACTIVE Finding parent active, message not sent * - !TSF:ROUTE:DST x UNKNOWN Routing for destination x unkown, send message to parent * - !TSF:SEND:TNR Transport not ready, message cannot be sent * - !TSF:MSG:PVER,x!=y Message protocol version mismatch * - !TSF:MSG:SIGN VERIFY FAIL Signing verficiation failed * - !TSF:MSG:REL MSG,NORP Node received a message for relaying, but node is not a repeater, message skipped * - !TSF:MSG:SIGN FAIL Signing message failed * - !TSF:MSG:GWL FAIL GW uplink failed * - !TSF:SANCHK:FAIL Sanity check failed, attempt to re-intialize radio * * @brief API declaration for MyTransport * */ #ifndef MyTransport_h #define MyTransport_h #include "MySensorsCore.h" #if defined(MY_REPEATER_FEATURE) #define TRANSMISSION_FAILURES 10 //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes #else #define TRANSMISSION_FAILURES 5 //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes #endif #define TIMEOUT_FAILURE_STATE 10000 //!< duration failure state #define STATE_TIMEOUT 2000 //!< general state timeout #define STATE_RETRIES 3 //!< retries before switching to FAILURE #define AUTO 255 //!< ID 255 is reserved for auto initialization of nodeId. #define BROADCAST_ADDRESS ((uint8_t)255) //!< broadcasts are addressed to ID 255 #define DISTANCE_INVALID ((uint8_t)255) //!< invalid distance when searching for parent #define MAX_HOPS ((uint8_t)254) //!< maximal mumber of hops for ping/pong #define INVALID_HOPS ((uint8_t)255) //!< invalid hops #define MAX_SUBSEQ_MSGS 5 //!< Maximum number of subsequentially processed messages in FIFO (to prevent transport deadlock if HW issue) #define CHKUPL_INTERVAL ((uint32_t)10000) //!< Minimum time interval to re-check uplink #define _autoFindParent (bool)(MY_PARENT_NODE_ID == AUTO) //!< returns true if static parent id is undefined #define isValidDistance(distance) (bool)(distance!=DISTANCE_INVALID) //!< returns true if distance is valid #define isValidParent(parent) (bool)(parent != AUTO) //!< returns true if parent is valid /** * @brief SM state * * This structure stores SM state definitions */ struct transportState { void(*Transition)(); //!< state transition function void(*Update)(); //!< state update function }; /** * @brief Status variables and SM state * * This structure stores transport status and SM variables */ typedef struct { transportState* currentState; //!< pointer to current fsm state uint32_t stateEnter; //!< state enter timepoint uint32_t lastUplinkCheck; //!< last uplink check, required to prevent GW flooding uint32_t lastSanityCheck; //!< last sanity check // 8 bits bool findingParentNode : 1; //!< flag finding parent node is active bool preferredParentFound : 1; //!< flag preferred parent found bool uplinkOk : 1; //!< flag uplink ok bool pingActive : 1; //!< flag ping active bool transportActive : 1; //!< flag transport active uint8_t reserved : 3; //!< reserved // 8 bits uint8_t retries : 4; //!< retries / state re-enter uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions // 8 bits uint8_t pingResponse; //!< stores hops received in I_PONG } __attribute__((packed)) transportSM; // PRIVATE functions /** * @brief Initialize SM variables and transport HW */ void stInitTransition(); /** * @brief Find parent */ void stParentTransition(); /** * @brief Verify find parent responses */ void stParentUpdate(); /** * @brief Send ID request */ void stIDTransition(); /** * @brief Verify ID response and GW link */ void stIDUpdate(); /** * @brief Send uplink ping request */ void stUplinkTransition(); /** * @brief Set transport OK */ void stReadyTransition(); /** * @brief Monitor transport link */ void stReadyUpdate(); /** * @brief Transport failure and power down radio */ void stFailureTransition(); /** * @brief Re-initialize transport after timeout */ void stFailureUpdate(); /** * @brief Switch SM state * @param newState New state to switch SM to */ void transportSwitchSM(transportState& newState); /** * @brief Update SM state */ void transportUpdateSM(); /** * @brief Request time in current SM state * @return ms in current state */ uint32_t transportTimeInState(); /** * @brief Call transport driver sanity check */ void transportInvokeSanityCheck(); /** * @brief Process all pending messages in RX FIFO */ void transportProcessFIFO(); /** * @brief Receive message from RX FIFO and process */ void transportProcessMessage(); /** * @brief Assign node ID * @param newNodeId New node ID * @return true if node ID valid and successfully assigned */ bool transportAssignNodeID(uint8_t newNodeId); /** * @brief Wait and process messages for a defined amount of time until specified message received * @param ms Time to wait and process incoming messages in ms * @param cmd Specific command * @param msgtype Specific message type * @return true if specified command received within waiting time */ bool transportWait(uint32_t ms, uint8_t cmd, uint8_t msgtype); /** * @brief Ping node * @param targetId Node to be pinged * @return hops from pinged node or 255 if no answer received within 2000ms */ uint8_t transportPingNode(uint8_t targetId); /** * @brief Send and route message according to destination * * This function is used in MyTransport and omits the transport state check, i.e. message can be sent even if transport is not ready * * @param message * @return true if message sent successfully */ bool transportRouteMessage(MyMessage &message); /** * @brief Send and route message according to destination with transport state check * @param message * @return true if message sent successfully and false if sending error or transport !OK */ bool transportSendRoute(MyMessage &message); /** * @brief Send message to recipient * @param to Recipient of message * @param message * @return true if message sent successfully */ bool transportSendWrite(uint8_t to, MyMessage &message); /** * @brief Check uplink to GW, includes flooding control * @param force to override flood control timer * @return true if uplink ok */ bool transportCheckUplink(bool force); // PUBLIC functions /** * @brief Initialize transport and SM */ void transportInitialize(); /** * @brief Process FIFO msg and update SM */ void transportProcess(); /** * @brief Flag transport ready * @return true if transport is initialize and ready */ bool isTransportReady(); /** * @brief Flag searching parent ongoing * @return true if transport is searching for parent */ bool isTransportSearchingParent(); /** * @brief Clear routing table */ void transportClearRoutingTable(); /** * @brief Return heart beat, i.e. ms in current state */ uint32_t transportGetHeartbeat(); // interface functions for radio driver /** * @brief Initialize transport HW * @return true if initalization successful */ bool transportInit(); /** * @brief Set node address */ void transportSetAddress(uint8_t address); /** * @brief Retrieve node address */ uint8_t transportGetAddress(); /** * @brief Send message * @param to recipient * @param data message to be sent * @param len length of message (header + payload) * @return true if message sent successfully */ bool transportSend(uint8_t to, const void* data, uint8_t len); /** * @brief Verify if RX FIFO has pending messages * @return true if message available in RX FIFO */ bool transportAvailable(); /** * @brief Sanity check for transport: is transport still responsive? * @return true transport ok */ bool transportSanityCheck(); /** * @brief Receive message from FIFO * @return length of recevied message (header + payload) */ uint8_t transportReceive(void* data); /** * @brief Power down transport HW */ void transportPowerDown(); #endif // MyTransport_h /** @}*/