/*    Paco Mouse -- F. Cañada 2022-2025 --  https://usuaris.tinet.cat/fmco/

      This software and associated files are a DIY project that is not intended for commercial use.
      This software uses libraries with different licenses, follow all their different terms included.

      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.

      Sources are only provided for building and uploading to the device.
      You are not allowed to modify the source code or fork/publish this project.
      Commercial use is forbidden.
*/

// OPCODES
#define OPC_GPOFF         0x82              // GLOBAL power OFF request 
#define OPC_GPON          0x83              // GLOBAL power ON request

#define OPC_LOCO_SPD      0xA0              // SET SLOT speed
#define OPC_LOCO_DIRF     0xA1              // SET SLOT dir,F0-4 state
#define OPC_LOCO_SND      0xA2              // SET SLOT sound functions 
#define OPC_LOCO_F9F12    0xA3              // Uhlenbrock 

#define OPC_SW_REQ        0xB0              // REQ SWITCH function
#define OPC_SW_REP        0xB1              // Turnout  SENSOR state REPORT
#define OPC_INPUT_REP     0xB2              // General SENSOR Input codes

#define OPC_LONG_ACK      0xB4              // Long acknowledge 
#define OPC_SLOT_STAT1    0xB5              // WRITE slot stat1

#define OPC_MOVE_SLOTS    0xBA              // MOVE slot SRC to DEST
#define OPC_RQ_SL_DATA    0xBB              // Request SLOT DATA/status block
#define OPC_SW_STATE      0xBC              // REQ state of SWITCH
#define OPC_LOCO_ADR      0xBF              // REQ  loco ADR

#define OPC_UHLI_FUN      0xD4              // Uhlenbrock

#define OPC_PEER_XFER     0xE5              // move 8 bytes PEER to PEER, SRC->DST
#define OPC_SL_RD_DATA    0xE7              // SLOT DATA return, 10 bytes
#define OPC_IMM_PACKET    0xED              // SEND n-byte packet immediate
#define OPC_WR_SL_DATA    0xEF              // WRITE SLOT DATA, 10 bytes


// BIT MASK
#define OPC_SW_REP_INPUTS 0x40              // sensor inputs, outputs otherwise  
#define OPC_SW_REP_SW     0x20              // switch input, aux input otherwise 
#define OPC_SW_REP_HI     0x10              // input is HI, LO otherwise
#define OPC_SW_REP_CLOSED 0x20              // 'Closed' line is ON, OFF otherwise  
#define OPC_SW_REP_THROWN 0x10              // 'Thrown' line is ON, OFF otherwise  

#define OPC_SW_REQ_DIR    0x20              // switch direction - closed/thrown
#define OPC_SW_REQ_OUT    0x10              // output On/Off                        

#define OPC_INPUT_REP_SW  0x20              // input is switch input, aux otherwise 
#define OPC_INPUT_REP_HI  0x10              // input is HI, LO otherwise   

#define STAT1_SL_BUSY     0x20              // BUSY/ACTIVE: bit encoding for SLOT activity
#define STAT1_SL_ACTIVE   0x10


// Message structure to determine the size of a message
typedef struct {
  uint8_t command;   /* LocoNet Op Code */
  uint8_t mesg_size; /* size of the message in bytes */
} szMsg;

/* Turnout sensor state report */
typedef struct swrep_t {
  uint8_t command;
  uint8_t sn1;           /* first  byte of report                                */
  uint8_t sn2;           /* second byte of report                                */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} swRepMsg;

/* Request Switch function */
typedef struct swreq_t {
  uint8_t command;
  uint8_t sw1;           /* first  byte of request                               */
  uint8_t sw2;           /* second byte of request                               */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} swReqMsg;

/* Sensor input report */
typedef struct inputrep_t {
  uint8_t command;
  uint8_t in1;           /* first  byte of report                                */
  uint8_t in2;           /* second byte of report                                */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} inputRepMsg;

/* Slot data request */
typedef struct slotreq_t {
  uint8_t command;
  uint8_t slot;          /* slot number for this request                         */
  uint8_t pad;           /* should be zero                                       */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} slotReqMsg;

/* Read/Write Slot data messages */
typedef struct rwslotdata_t {
  uint8_t command;
  uint8_t mesg_size;     /* ummmmm, size of the message in bytes?                */
  uint8_t slot;          /* slot number for this request                         */
  uint8_t stat;          /* slot status                                          */
  uint8_t adr;           /* loco address                                         */
  uint8_t spd;           /* command speed                                        */
  uint8_t dirf;          /* direction and F0-F4 bits                             */
  uint8_t trk;           /* track status                                         */
  uint8_t ss2;           /* slot status 2 (tells how to use ID1/ID2 & ADV Consist*/
  uint8_t adr2;          /* loco address high                                    */
  uint8_t snd;           /* Sound 1-4 / F5-F8                                    */
  uint8_t id1;           /* ls 7 bits of ID code                                 */
  uint8_t id2;           /* ms 7 bits of ID code                                 */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} rwSlotDataMsg;

/* Fast Clock Message */
typedef struct fastclock_t {
  uint8_t command;
  uint8_t mesg_size;     /* ummmmm, size of the message in bytes?                    */
  uint8_t slot;          /* slot number for this request                             */
  uint8_t clk_rate;      /* 0 = Freeze clock, 1 = normal, 10 = 10:1 etc. Max is 0x7f */
  uint8_t frac_minsl;    /* fractional minutes. not for external use.                */
  uint8_t frac_minsh;
  uint8_t mins_60;       /* 256 - minutes   */
  uint8_t track_stat;    /* track status    */
  uint8_t hours_24;      /* 256 - hours     */
  uint8_t days;          /* clock rollovers */
  uint8_t clk_cntrl;     /* bit 6 = 1; data is valid clock info */
  /*  "  "   0; ignore this reply        */
  uint8_t id1;           /* id1/id2 is device id of last device to set the clock */
  uint8_t id2;           /*  "   "  = zero shows not set has happened            */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} fastClockMsg;

/* Programmer Task Message (used in Start and Final Reply, both )*/
typedef struct progtask_t {
  uint8_t command;
  uint8_t mesg_size;     /* ummmmm, size of the message in bytes?                    */
  uint8_t slot;          /* slot number for this request - slot 124 is programmer    */
  uint8_t pcmd;          /* programmer command                                       */
  uint8_t pstat;         /* programmer status error flags in reply message           */
  uint8_t hopsa;         /* Ops mode - 7 high address bits of loco to program        */
  uint8_t lopsa;         /* Ops mode - 7 low  address bits of loco to program        */
  uint8_t trk;           /* track status. Note: bit 3 shows if prog track is busy    */
  uint8_t cvh;           /* hi 3 bits of CV# and msb of data7                        */
  uint8_t cvl;           /* lo 7 bits of CV#                                         */
  uint8_t data7;         /* 7 bits of data to program, msb is in cvh above           */
  uint8_t pad2;
  uint8_t pad3;
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} progTaskMsg;

/* Set slot sound functions */
typedef struct locosnd_t {
  uint8_t command;
  uint8_t slot;          /* slot number for this request                         */
  uint8_t snd;           /* sound/function request                               */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} locoSndMsg;

/* Set slot direction and F0-F4 functions */
typedef struct locodirf_t {
  uint8_t command;
  uint8_t slot;          /* slot number for this request                         */
  uint8_t dirf;          /* direction & function request                         */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} locoDirfMsg;

/* Set slot speed functions */
typedef struct locospd_t {
  uint8_t command;
  uint8_t slot;          /* slot number for this request                         */
  uint8_t spd;           /* speed request                                        */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} locoSpdMsg;

/* send packet immediate message */
typedef struct sendpkt_t {
  uint8_t command;
  uint8_t mesg_size;     /* ummmmm, size of the message in bytes?                */
  uint8_t val7f;         /* fixed value of 0x7f                                  */
  uint8_t reps;          /* repeat count                                         */
  uint8_t dhi;           /* high bits of data bytes                              */
  uint8_t im1;
  uint8_t im2;
  uint8_t im3;
  uint8_t im4;
  uint8_t im5;
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} sendPktMsg;

/* Long ACK message */
typedef struct longack_t {
  uint8_t command;
  uint8_t opcode;        /* op-code of message getting the response (msb=0)      */
  uint8_t ack1;          /* response code                                        */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} longAckMsg;

/* Write slot status message */
typedef struct slotstat_t {
  uint8_t command;
  uint8_t slot;          /* slot number for this request                         */
  uint8_t stat;          /* status to be written                                 */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} slotStatusMsg;

/* Move/Link Slot Message */
typedef struct slotmove_t {
  uint8_t command;
  uint8_t src;           /* source slot number for the move/link                 */
  uint8_t dest;          /* destination slot for the move/link                   */
  uint8_t chksum;        /* exclusive-or checksum for the message                */
} slotMoveMsg;

typedef struct
{
  uint8_t command;   // OPC_PEER_XFER for replies, OPC_IMM_PACKET for commands
  uint8_t mesg_size; // 15 bytes
  uint8_t SRC;       // source
  uint8_t DSTL;      // destination, low byte
  uint8_t DSTH;      // destination, high byte
  uint8_t ReqId;     // Request ID, distinguishes commands
  uint8_t PXCT1;     // MSBs of following data
  uint8_t D0;        // Data Bytes
  uint8_t D1;
  uint8_t D2;
  uint8_t D3;
  uint8_t D4;
  uint8_t D5;
  uint8_t D6;
} UhlenbrockMsg;


typedef union {
  szMsg           sz ;
  swRepMsg        srp ;
  swReqMsg        srq ;
  inputRepMsg     ir ;
  slotReqMsg      sr ;
  rwSlotDataMsg   sd ;
  fastClockMsg    fc ;
  progTaskMsg     pt ;
  locoSndMsg      ls ;
  locoDirfMsg     ldf ;
  locoSpdMsg      lsp ;
  sendPktMsg      sp ;
  longAckMsg      lack ;
  slotStatusMsg   ss ;
  slotMoveMsg     sm ;
  UhlenbrockMsg   ub;
  uint8_t         data[32] ;
} lnMsg ;

//static lnMsg  *LnPacket ;                                   // Paquete recibido por Loconet
