Subversion Repositories tpanel

Rev

Rev 446 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2018 to 2024 by Andreas Theofilu <andreas@theosys.at>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

#ifndef __TAMXNET_H__
#define __TAMXNET_H__

//#include "asio.hpp"

#include <vector>
#include <map>
#include <functional>
#include <cstring>
#include <cstdio>
#include <atomic>
#include <thread>

#include "tsocket.h"
#include "tvector.h"

#if defined(__ANDROID__) || defined(__MACH__)
typedef unsigned long int ulong;
#endif

extern std::atomic<bool> killed;
extern bool prg_stopped;

namespace amx
{
#define MAX_CHUNK   0x07d0  // Maximum size a part of a file can have. The file will be splitted into this size of chunks.
#define BUF_SIZE    0x1000  // 4096 bytes

#define NSTATE_OFFLINE      0
#define NSTATE_OFFLINE1     1
#define NSTATE_ONLINE       6
#define NSTATE_ONLINE1      5
#define NSTATE_CONNECTING   9

#define WAIT_RESET          3   // Number of seconds to wait in case of connecting to another controller
#define WAIT_RECONNECT      15  // Number of seconds to wait in case of reconnecting to the same controller

#define DTSZ_STRING         0x01    // ASCII string (8 bit)
#define DTSZ_WSTRING        0x02    // Wide string (16 bit)
#define DTSZ_BYTE           0x10    // Byte (8 bit unsigned)
#define DTSZ_CHAR           0x11    // Byte (8 bit signed)
#define DTSZ_UINT           0x20    // Word (16 bit unsigned)
#define DTSZ_INT            0x21    // Word (16 bit signed)
#define DTSZ_LUINT          0x40    // DWORD (32 bit unsigned)
#define DTSZ_LINTT          0x41    // DWORD (32 bit signed)
#define DTSZ_FLOAT          0x4f    // FLOAT (32 bit)
#define DTSZ_DOUBLE         0x8f    // DOUBLE (32/64 bit)

    typedef struct ANET_SEND
    {
        uint16_t device{0};     // Device ID of panel
        uint16_t MC{0};         // message command number
        uint16_t port{0};       // port number
        uint16_t level{0};      // level number (if any)
        uint16_t channel{0};    // channel status
        uint16_t value{0};      // level value
        // this is for custom events
        uint16_t ID{0};         // ID of button
        uint16_t type{0};       // Type of event
        uint16_t flag{0};       // Flag
        uint32_t value1{0};     // Value 1
        uint32_t value2{0};     // Value 2
        uint32_t value3{0};     // Value 3
        unsigned char dtype{0}; // Type of data
        std::string msg;        // message string
    } ANET_SEND;

    typedef union
    {
        unsigned char byte; // type = 0x10
        char ch;            // type = 0x11
        uint16_t integer;   // type = 0x20 (also wide char)
        int16_t sinteger;   // type = 0x21
        uint32_t dword;     // type = 0x40
        int32_t sdword;     // type = 0x41
        float fvalue;       // type = 0x4f
        double dvalue;      // type = 0x8f
    } ANET_CONTENT;

    typedef struct ANET_MSG
    {
        uint16_t device;        // device number
        uint16_t port;          // port number
        uint16_t system;        // system number
        uint16_t value;         // value of command
        unsigned char type;     // defines how to interpret the content of cmd
        ANET_CONTENT content;
    } ANET_MSG;

    typedef struct ANET_MSG_STRING
    {
        uint16_t device;        // device number
        uint16_t port;          // port number
        uint16_t system;        // system number
        unsigned char type;     // Definnes the type of content (0x01 = 8 bit chars, 0x02 = 16 bit chars --> wide chars)
        uint16_t length;        // length of following content
        unsigned char content[1500];// content string
    } ANET_MSG_STRING;

    typedef struct ANET_ASIZE
    {
        uint16_t device;        // device number
        uint16_t port;          // port number
        uint16_t system;        // system number
        unsigned char type;     // Defines the type of content (0x01 = 8 bit chars, 0x02 = 16 bit chars --> wide chars)
        uint16_t length;        // length of following content
    } ANET_ASIZE;

    typedef struct ANET_LEVSUPPORT
    {
        uint16_t device;        // device number
        uint16_t port;          // port number
        uint16_t system;        // system number
        uint16_t level;         // level number
        unsigned char num;      // number of supported types
        unsigned char types[6]; // Type codes
    } ANET_LEVSUPPORT;

    typedef struct ANET_ASTATCODE
    {
        uint16_t device;        // device number
        uint16_t port;          // port number
        uint16_t system;        // system number
        uint16_t status;        // status code
        unsigned char type;     // defines how to interpret the content of cmd
        uint16_t length;        // length of following string
        unsigned char str[512];
    } ANET_ASTATCODE;

    typedef struct ANET_LEVEL
    {
        uint16_t device;        // device number
        uint16_t port;          // port number
        uint16_t system;        // system number
        uint16_t level;         // level number
    } ANET_LEVEL;

    typedef struct ANET_CHANNEL
    {
        uint16_t device;        // device number
        uint16_t port;          // port number
        uint16_t system;        // system number
        uint16_t channel;       // level number
    } ANET_CHANNEL;

    typedef struct ANET_RPCOUNT
    {
        uint16_t device;        // device number
        uint16_t system;        // system number
    } ANET_RPCOUNT;

    typedef struct ANET_APCOUNT // Answer to request for port count
    {
        uint16_t device;        // device number
        uint16_t system;        // system number
        uint16_t pcount;        // number of supported ports
    } ANET_APCOUNT;

    typedef struct ANET_ROUTCHAN    // Request for port count
    {
        uint16_t device;        // device number
        uint16_t port;          // system number
        uint16_t system;        // number of supported ports
    } ANET_ROUTCHAN;

    typedef struct ANET_AOUTCHAN    // Answer to request for port count
    {
        uint16_t device;        // device number
        uint16_t port;          // system number
        uint16_t system;        // number of supported ports
        uint16_t count;         // number of supported channels
    } ANET_AOUTCHAN;

    typedef struct ANET_ADEVINFO // Answer to "request device info"
    {
        uint16_t device;        // device number
        uint16_t system;        // system number
        uint16_t flag;          // Bit 8 - If set, this message was generated in response to a key press, during the identification mode is active.
        unsigned char objectID; // object ID
        unsigned char parentID; // parent ID
        uint16_t herstID;       // herst ID
        uint16_t deviceID;      // device ID
        unsigned char serial[16]; // serial number
        uint16_t fwid;          // firmware ID
        unsigned char info[512];// several NULL terminated informations
        int len;                // length of field info
    } ANET_ADEVINFO;

    typedef struct ANET_ASTATUS // Answer to "master status"
    {
        uint16_t system;        // number of system
        uint16_t status;        // Bit field
        unsigned char str[512]; // Null terminated status string
    } ANET_ASTATUS;

    typedef struct ANET_CUSTOM  // Custom event
    {
        uint16_t device;        // Device number
        uint16_t port;          // Port number
        uint16_t system;        // System number
        uint16_t ID;            // ID of event (button ID)
        uint16_t type;          // Type of event
        uint16_t flag;          // Flag
        uint32_t value1;        // Value 1
        uint32_t value2;        // Value 2
        uint32_t value3;        // Value 3
        unsigned char dtype;    // type of following data
        uint16_t length;        // length of following string
        unsigned char data[255];// Custom data
    } ANET_CUSTOM;

    typedef struct ANET_BLINK       // Blink message (contains date and time)
    {
        unsigned char heartBeat;    // Time between heart beats in 10th of seconds
        unsigned char LED;          // Bit 0: Bus-LED: 0 off, 1 on; Bits 1-6 reserved; Bit 7: 1 = force reset device
        unsigned char month;        // Month 1 - 12
        unsigned char day;          // Day 1 - 31
        uint16_t year;              // Year
        unsigned char hour;         // Hours 0 - 23
        unsigned char minute;       // Minutes 0 - 59
        unsigned char second;       // Seconds 0 - 59
        unsigned char weekday;      // 0 = Monday, 1 = Thuesday, ...
        uint16_t extTemp;           // External temperature, if available (0x8000 invalid value)
        unsigned char dateTime[64]; // Rest is a string containing the date and time.

        void clear()
        {
            heartBeat = 0;
            LED = 0;
            month = 0;
            day = 0;
            year = 0;
            hour = 0;
            minute = 0;
            second = 0;
            weekday = 0;
            extTemp = 0;
            dateTime[0] = 0;
        }
    } ANET_BLINK;

    typedef struct ANET_NETWORK     // Setting the IP address, subnet mask and gateway of the Ethernet interface of the unit.
    {
        unsigned char bf;
        char data[1024];
        size_t len;
    }ANET_NETWORK;

    typedef struct ANET_FILETRANSFER    // File transfer
    {
        uint16_t ftype;         // 0 = not used, 1=IR, 2=Firmware, 3=TP file, 4=Axcess2
        uint16_t function;      // The function to be performed, or length of data block
        uint16_t info1;
        uint16_t info2;
        uint32_t unk;           // ?
        uint32_t unk1;          // ?
        uint32_t unk2;          // ?
        uint32_t unk3;          // ?
        unsigned char data[2048];// Function specific data
    } ANET_FILETRANSFER;

    typedef union
    {
        ANET_CHANNEL chan_state;
        ANET_MSG message_value;
        ANET_MSG_STRING message_string;
        ANET_LEVEL level;
        ANET_CHANNEL channel;
        ANET_RPCOUNT reqPortCount;
        ANET_APCOUNT sendPortNumber;
        ANET_ROUTCHAN reqOutpChannels;
        ANET_AOUTCHAN sendOutpChannels;
        ANET_ASTATCODE sendStatusCode;
        ANET_ASIZE sendSize;
        ANET_LEVEL reqLevels;
        ANET_LEVSUPPORT sendLevSupport;
        ANET_ADEVINFO srDeviceInfo;     // send/receive device info
        ANET_CUSTOM customEvent;
        ANET_BLINK blinkMessage;
        ANET_NETWORK network;
        ANET_FILETRANSFER filetransfer;
    } ANET_DATA;

    typedef struct ANET_COMMAND // Structure of type command (type = 0x00, status = 0x000c)
    {
        char ID{2};             // 0x00:        Always 0x02
        uint16_t hlen{0};       // 0x01 - 0x02: Header length (length + 3 for total length!)
        char sep1{2};           // 0x03:        Seperator always 0x02
        char type{0};           // 0x04:        Type of header
        uint16_t unk1{1};       // 0x05 - 0x06: always 0x0001
        uint16_t device1{0};    // 0x07 - 0x08: receive: device, send: 0x000
        uint16_t port1{0};      // 0x09 - 0x0a: receive: port,   send: 0x001
        uint16_t system{0};     // 0x0b - 0x0c: receive: system, send: 0x001
        uint16_t device2{0};    // 0x0d - 0x0e: send: device,    receive: 0x0000
        uint16_t port2{0};      // 0x0f - 0x10: send: port,      receive: 0x0001
        char unk6{0x0f};        // 0x11:        Always 0x0f
        uint16_t count{0};      // 0x12 - 0x13: Counter
        uint16_t MC{0};         // 0x14 - 0x15: Message command identifier
        ANET_DATA data;         // 0x16 - n     Data block
        unsigned char checksum{0};  // last byte:   Checksum
        bool intern{false};     // Internal command

        void clear()
        {
            ID = 0x02;
            hlen = 0;
            sep1 = 0x02;
            type = 0;
            unk1 = 1;
            device1 = 0;
            port1 = 0;
            system = 0;
            device2 = 0;
            port2 = 0;
            unk6 = 0x0f;
            count = 0;
            MC = 0;
            checksum = 0;
            intern = false;
        }
    } ANET_COMMAND;

    typedef struct
    {
        unsigned char objectID;     // Unique 8-bit identifier that identifies this structure of information
        unsigned char parentID;     // Refers to an existing object ID. If 0, has this object to any parent object (parent).
        uint16_t manufacturerID;    // Value that uniquely identifies the manufacture of the device.
        uint16_t deviceID;          // Value that uniquely identifies the device type.
        char serialNum[16];         // Fixed length of 16 bytes.
        uint16_t firmwareID;        // Value that uniquely identifies the object code that the device requires.
        // NULL terminated text field
        char versionInfo[16];       // A closed with NULL text string that specifies the version of the reprogrammable component.
        char deviceInfo[32];        // A closed with NULL text string that specifies the name or model number of the device.
        char manufacturerInfo[32];  // A closed with NULL text string that specifies the name of the device manufacturer.
        unsigned char format;       // Value that indicates the type of device specific addressing information following.
        unsigned char len;          // Value that indicates the length of the following device-specific addressing information.
        unsigned char addr[8];      // Extended address as indicated by the type and length of the extended address.
    } DEVICE_INFO;

    typedef struct FTRANSFER
    {
        int percent{0};             // Status indicating the percent done
        int maxFiles{0};            // Total available files
        int lengthFile{0};          // Total length of currently transfered file
        int actFileNum{0};          // Number of currently transfered file.
        int actDelFile{0};          // Number of currently deleted file.
    } FTRANSFER;

    typedef struct FUNC_NETWORK_t
    {
        ulong handle{0};
        std::function<void(int)> func{nullptr};
    }FUNC_NETWORK_t;

    typedef struct FUNC_TIMER_t
    {
        ulong handle{0};
        std::function<void(const ANET_BLINK&)> func{nullptr};
    }FUNC_TIMER_t;

    class TAmxNet
    {
        public:
            TAmxNet();
            explicit TAmxNet(const std::string& sn);
            explicit TAmxNet(const std::string& sn, const std::string& nm);
            ~TAmxNet();

            void Run();
            void stop(bool soft=false);
            bool reconnect();

            void setCallback(std::function<void(const ANET_COMMAND&)> func) { callback = func; }
            void registerNetworkState(std::function<void(int)> registerNetwork, ulong handle);
            void registerTimer(std::function<void(const ANET_BLINK&)> registerBlink, ulong handle);
            void deregNetworkState(ulong handle);
            void deregTimer(ulong handle);

            bool sendCommand(const ANET_SEND& s);
            bool isStopped() { return stopped_; }
            bool isConnected() { if (mSocket) return mSocket->isConnected(); return false; }
            bool close() { if (mSocket) return mSocket->close(); return false; }
            bool isNetRun();
            void setPanelID(int id) { panelID = id; }
            void setSerialNum(const std::string& sn);
            bool setupStatus() { return receiveSetup; }
            void setPanName(const std::string& nm) { panName.assign(nm); }

            void setWaitTime(int secs);
            int getWaitTime() { return mWaitTime; }
            int swapWaitTime();

        protected:
            void start();

        private:
            enum R_TOKEN
            {
                RT_NONE,
                RT_ID,
                RT_LEN,
                RT_SEP1,
                RT_TYPE,
                RT_WORD1,
                RT_DEVICE,
                RT_WORD2,
                RT_WORD3,
                RT_WORD4,
                RT_WORD5,
                RT_SEP2,
                RT_COUNT,
                RT_MC,
                RT_DATA
            };

            void init();
            void handle_connect();
            void runWrite();
            void start_read();
            void handle_read(size_t n, R_TOKEN tk);
            void start_write();
            void handleFTransfer(ANET_SEND& s, ANET_FILETRANSFER& ft);
            uint16_t swapWord(uint16_t w);
            uint32_t swapDWord(uint32_t dw);
            unsigned char calcChecksum(const unsigned char *buffer, size_t len);
            uint16_t makeWord(unsigned char b1, unsigned char b2);
            uint32_t makeDWord(unsigned char b1, unsigned char b2, unsigned char b3, unsigned char b4);
            unsigned char *makeBuffer(const ANET_COMMAND& s);
            int msg97fill(ANET_COMMAND *com);
            bool isCommand(const std::string& cmd);
            bool isRunning() { return !(stopped_ || killed || prg_stopped); }
            int countFiles();
            void sendAllFuncNetwork(int state);
            void sendAllFuncTimer(const ANET_BLINK& blink);

            std::function<void(const ANET_COMMAND&)> callback;

            TSocket *mSocket{nullptr};  // Pointer to socket class needed for communication
            FILE *rcvFile{nullptr};
            FILE *sndFile{nullptr};
            size_t posRcv{0};
            size_t lenRcv{0};
            size_t posSnd{0};
            size_t lenSnd{0};
            std::thread mThread;
            std::thread mWriteThread;   // Thread used to write to the Netlinx.
            std::string input_buffer_;
            std::string panName;        // The technical name of the panel
            TVector<ANET_COMMAND> comStack; // commands to answer
            std::vector<DEVICE_INFO> devInfo;
            std::string oldCmd;
            std::string serNum;
            std::string sndFileName;
            std::string rcvFileName;
            ANET_COMMAND comm;          // received command
            ANET_COMMAND mSend;         // answer / request
            int panelID{0};             // Panel ID of currently legalized panel.
            int mWaitTime{3};           // [seconds]: Wait by default for 3 seconds
            int mOldWaitTime{3};        // [seconds]: The previous wait time in case of change
            FTRANSFER ftransfer;
            uint16_t reqDevStatus{0};
            uint16_t sendCounter{0};    // Counter increment on every send
            std::atomic<bool> stopped_{false};
            std::atomic<bool> mSendReady{false};
            bool protError{false};      // true = error on receive --> disconnect
            bool initSend{false};       // TRUE = all init messages are send.
            bool ready{false};          // TRUE = ready for communication
            std::atomic<bool> write_busy{false};
            std::atomic<bool> receiveSetup{false};
            bool isOpenSnd{false};
            bool isOpenRcv{false};
            bool _retry{false};
            char buff_[BUF_SIZE];       // Internal used buffer for network communication
            int mLastOnlineState{NSTATE_OFFLINE};
    };
}

#endif