#pragma once #include "Observer.h" #include "mesh-pb-constants.h" #include // Make sure that we never let our packets grow too large for one BLE packet #define MAX_TO_FROM_RADIO_SIZE 512 /** * Provides our protobuf based API which phone/PC clients can use to talk to our device * over UDP, bluetooth or serial. * * Subclass to customize behavior for particular type of transport (BLE, UDP, TCP, serial) * * Eventually there should be once instance of this class for each live connection (because it has a bit of state * for that connection) */ class PhoneAPI : public Observer // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member { enum State { STATE_UNUSED, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config // (disconnected) STATE_SEND_MY_INFO, // send our my info record // STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet // STATE_SEND_OWNER, no need to send Owner specially, it is just part of the nodedb STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client STATE_SEND_COMPLETE_ID, STATE_SEND_PACKETS // send packets or debug strings }; State state = STATE_SEND_NOTHING; /** * Each packet sent to the phone has an incrementing count */ uint32_t fromRadioNum = 0; /// We temporarily keep the packet here between the call to available and getFromRadio. We will free it after the phone /// downloads it MeshPacket *packetForPhone = NULL; /// We temporarily keep the nodeInfo here between the call to available and getFromRadio const NodeInfo *nodeInfoForPhone = NULL; ToRadio toRadioScratch; // this is a static scratch object, any data must be copied elsewhere before returning /// Use to ensure that clients don't get confused about old messages from the radio uint32_t config_nonce = 0; public: PhoneAPI(); /// Destructor - calls close() virtual ~PhoneAPI(); // Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING // Unregisters our observer. A closed connection **can** be reopened by calling init again. virtual void close(); /** * Handle a ToRadio protobuf * @return true true if a packet was queued for sending (so that caller can yield) */ virtual bool handleToRadio(const uint8_t *buf, size_t len); /** * Get the next packet we want to send to the phone * * We assume buf is at least FromRadio_size bytes long. * Returns number of bytes in the FromRadio packet (or 0 if no packet available) */ size_t getFromRadio(uint8_t *buf); /** * Return true if we have data available to send to the phone */ bool available(); bool isConnected() { return state != STATE_SEND_NOTHING; } /// emit a debugging log character, FIXME - implement void debugOut(char c) { } protected: /// Our fromradio packet while it is being assembled FromRadio fromRadioScratch; /** the last msec we heard from the client on the other side of this link */ uint32_t lastContactMsec = 0; /// Hookable to find out when connection changes virtual void onConnectionChanged(bool connected) {} /// If we haven't heard from the other side in a while then say not connected void checkConnectionTimeout(); /// Check the current underlying physical link to see if the client is currently connected virtual bool checkIsConnected() = 0; /** * Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies) */ virtual void onNowHasData(uint32_t fromRadioNum) {} /** * Subclasses can use this to find out when a client drops the link */ virtual void handleDisconnect(); private: void releasePhonePacket(); /// begin a new connection void handleStartConfig(); /** * Handle a packet that the phone wants us to send. We can write to it but can not keep a reference to it * @return true true if a packet was queued for sending */ bool handleToRadioPacket(MeshPacket &p); /// If the mesh service tells us fromNum has changed, tell the phone virtual int onNotify(uint32_t newValue); };