#ifndef LOCONET_INCLUDED
#define LOCONET_INCLUDED

/*****************************************************************************
 *                                                                           *
 *      Copyright (C) 2001 Ron W. Auld                                       *
 *      Copyright (C) 2004 Alex Shepherd                                                                      *
 *                                                                           *
 *      Portions Copyright (C) Digitrax Inc.                                 * 
 *                                                                           *
 *                                                                           *
 *  This library is free software; you can redistribute it and/or            *
 *  modify it under the terms of the GNU Lesser General Public               *
 *  License as published by the Free Software Foundation; either             *
 *  version 2.1 of the License, or (at your option) any later version.       *
 *                                                                           *
 *  This library 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        *
 *  Lesser General Public License for more details.                          *
 *                                                                           *
 *  You should have received a copy of the GNU Lesser General Public         *
 *  License along with this library; if not, write to the Free Software      *
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*
 *                                                                           *
 *****************************************************************************
 *
 *  IMPORTANT:
 *
 *  Some of the message formats used in this code are Copyright Digitrax, Inc.
 *  and are used with permission as part of the EmbeddedLocoNet project. That
 *  permission does not extend to uses in other software products. If you wish
 *  to use this code, algorithm or these message formats outside of
 *  EmbeddedLocoNet, please contact Digitrax Inc, for specific permission.
 *
 *  Note: The sale any LocoNet device hardware (including bare PCB's) that
 *  uses this or any other LocoNet software, requires testing and certification
 *  by Digitrax Inc. and will be subject to a licensing agreement.
 *
 *  Please contact Digitrax Inc. for details.
 *
 *****************************************************************************
 *  NOTE                                                                     *
 *                                                                           *
 *  This file was first released under the GPL license but Ron Auld has      *
 *  given his permission for this file to be included in the EmbeddedLoconet *
 *  project under the LGPL license                                           *
 *                                                                           *
 *****************************************************************************
 *                                                                           *
 *  Some of this code is based on work done by John Kabat and I thank him    *
 *  for the use of that code and his contributions to the understanding      *
 *  and use of the Digitrax LocoNet.                                         *
 *                                                                           *
 *****************************************************************************
 *
 * File Name:     loconet.h
 * Module:        Generic Loconet (r) message definitions.
 * Language:
 * Contributors:  Ron W. Auld (RwA), John Kabat
 * Remarks:
 *
 *    This file contains the definitions and structures pertinant to the
 *    Loconet (r) message protocol.
 *
 * Version Control:
 * $Log: loconet.h,v $
 * Revision 1.13  2007/02/21 21:08:06  sbormann71
 * added Uhlenbrock basic packet format to lnMsg union
 *
 * Revision 1.12  2006/11/05 12:03:29  tkurz
 * OPC_SE added
 *
 * Revision 1.11  2006/06/22 23:02:32  sbormann71
 * fixed OPC_BUSY
 *
 * Revision 1.10  2006/06/21 22:27:53  sbormann71
 * added GTRK_POWER
 *
 * Revision 1.9  2004/03/08 09:15:34  kiwi64ajs
 * minor bug fixes found in testing in the Emulator Test App
 *
 * Revision 1.8  2004/02/19 04:04:16  kiwi64ajs
 * moved sv message definition from sv.h to loconet.h
 * added special Digitrax copyright notice to loconet.h
 * added message union to loconet.h
 *
 * Revision 1.7  2003/11/03 20:27:19  kiwi64ajs
 * added #ifndef for multiple inclusion
 *
 * Revision 1.6  2003/01/02 12:05:48  kiwi64ajs
 * moved byte definition out to common_defs.h
 *
 * Revision 1.5  2002/12/28 11:08:07  kiwi64ajs
 * change #ifndef test for byte and word being already defined
 *
 * Revision 1.4  2002/12/14 21:08:05  kiwi64ajs
 * minor changes to be compatible with BORLANDC
 * changed all char array index vars to byte and modified code to handle invalid case ox 0xFF not 0x00
 *
 * Revision 1.3  2002/12/03 10:49:23  kiwi64ajs
 * Added locoDataMsg and pragma pack
 *
 * Revision 1.2  2002/09/23 09:49:01  kiwi64ajs
 * Added comment about license change from GPL to LGPL
 *
 * Revision 1.1  2002/09/23 09:22:19  kiwi64ajs
 * Added generic loconet directory for non-avr specific loconet files
 * Added Ron Auld's comprehensive loconet structures definition
 *
 * Revision 1.2  2001/05/31 17:40:05  rauld
 * Added options and code needed for llnmon to use a Locobuffer interface instead
 * of an MS-100.
 *
 * Revision 1.1.1.1  2001/01/16 12:55:59  rauld
 * Initial import into CVS
 *
 *
 */

/*** INCLUDES ***/

#include "common_defs.h"

/*** CONSTANTS ****/

/*** TYPES ***/

/* various bit masks */
#define DIRF_DIR          0x20                                                 /* direction bit */
#define DIRF_F0           0x10                                                 /* Function 0 bit */
#define DIRF_F4           0x08                                                 /* Function 1 bit */
#define DIRF_F3           0x04                                                 /* Function 2 bit */
#define DIRF_F2           0x02                                                 /* Function 3 bit */
#define DIRF_F1           0x01                                                 /* Function 4 bit */
#define SND_F8            0x08                                                 /* Sound 4/Function 8 bit */
#define SND_F7            0x04                                                 /* Sound 3/Function 7 bit */
#define SND_F6            0x02                                                 /* Sound 2/Function 6 bit */
#define SND_F5            0x01                                                 /* Sound 1/Function 5 bit */

#define OPC_SW_ACK_CLOSED 0x20                                                 /* command switch closed/open bit */
#define OPC_SW_ACK_OUTPUT 0x10                                                 /* command switch output on/off bit */

#define OPC_INPUT_REP_CB  0x40                                                 /* control bit, reserved otherwise */
#define OPC_INPUT_REP_SW  0x20                                                 /* input is switch input, aux otherwise */
#define OPC_INPUT_REP_HI  0x10                                                 /* input is HI, LO 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_REP_INPUTS 0x40                                                 /* sensor inputs, outputs otherwise */

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

#define OPC_LOCO_SPD_ESTOP 0x01                                                /* emergency stop command */
#define OPC_SE     				0xE4                                             /* Opcode Security Element */

/* Slot Status byte definitions and macros */

/***********************************************************************************
*   D7-SL_SPURGE    ; 1=SLOT purge en,                                             *
*                   ; ALSO adrSEL (INTERNAL use only) (not seen on NET!)           *
*                                                                                  *
*   D6-SL_CONUP     ; CONDN/CONUP: bit encoding-Control double linked Consist List *
*                   ;    11=LOGICAL MID CONSIST , Linked up AND down               *
*                   ;    10=LOGICAL CONSIST TOP, Only linked downwards             *
*                   ;    01=LOGICAL CONSIST SUB-MEMBER, Only linked upwards        *
*                   ;    00=FREE locomotive, no CONSIST indirection/linking        *
*                   ; ALLOWS "CONSISTS of CONSISTS". Uplinked means that           *
*                   ; Slot SPD number is now SLOT adr of SPD/DIR and STATUS        *
*                   ; of consist. i.e. is ;an Indirect pointer. This Slot          *
*                   ; has same BUSY/ACTIVE bits as TOP of Consist. TOP is          *
*                   ; loco with SPD/DIR for whole consist. (top of list).          *
*                   ; BUSY/ACTIVE: bit encoding for SLOT activity                  *
*                                                                                  *
*   D5-SL_BUSY      ; 11=IN_USE loco adr in SLOT -REFRESHED                        *
*                                                                                  *
*   D4-SL_ACTIVE    ; 10=IDLE loco adr in SLOT -NOT refreshed                      *
*                   ; 01=COMMON loco adr IN SLOT -refreshed                        *
*                   ; 00=FREE SLOT, no valid DATA -not refreshed                   *
*                                                                                  *
*   D3-SL_CONDN     ; shows other SLOT Consist linked INTO this slot, see SL_CONUP *
*                                                                                  *
*   D2-SL_SPDEX     ; 3 BITS for Decoder TYPE encoding for this SLOT               *
*                                                                                  *
*   D1-SL_SPD14     ; 011=send 128 speed mode packets                              *
*                                                                                  *
*   D0-SL_SPD28     ; 010=14 step MODE                                             *
*                   ; 001=28 step. Generate Trinary packets for this               *
*                   ;              Mobile ADR                                      *
*                   ; 000=28 step. 3 BYTE PKT regular mode                         *
*                   ; 111=128 Step decoder, Allow Advanced DCC consisting          *
*                   ; 100=28 Step decoder ,Allow Advanced DCC consisting           *
***********************************************************************************/

#define STAT1_SL_SPURGE   0x80                                                 /* internal use only, not seen on net */
#define STAT1_SL_CONUP    0x40                                                 /* consist status */
#define STAT1_SL_BUSY     0x20                                                 /* used with STAT1_SL_ACTIVE, */
#define STAT1_SL_ACTIVE   0x10                                                 /* */
#define STAT1_SL_CONDN    0x08                                                 /* */
#define STAT1_SL_SPDEX    0x04                                                 /* */
#define STAT1_SL_SPD14    0x02                                                 /* */
#define STAT1_SL_SPD28    0x01                                                 /* */
#define STAT2_SL_SUPPRESS 0x01                                                 /* 1 = Adv. Consisting supressed */
#define STAT2_SL_NOT_ID   0x04                                                 /* 1 = ID1/ID2 is not ID usage */
#define STAT2_SL_NOTENCOD 0x08                                                 /* 1 = ID1/ID2 is not encoded alias */
#define STAT2_ALIAS_MASK  (STAT2_SL_NOTENCOD | STAT2_SL_NOT_ID)
#define STAT2_ID_IS_ALIAS STAT2_SL_NOT_ID

/* mask and values for consist determination */
#define CONSIST_MASK      (STAT1_SL_CONDN | STAT1_SL_CONUP)
#define CONSIST_MID       (STAT1_SL_CONDN | STAT1_SL_CONUP)
#define CONSIST_TOP       (STAT1_SL_CONDN)
#define CONSIST_SUB       (STAT1_SL_CONUP)
#define CONSIST_NO        (0)
#define CONSIST_STAT(s) (  ((s & CONSIST_MASK) == CONSIST_MID) ? "Mid-Consisted" : \
                         ( ((s & CONSIST_MASK) == CONSIST_TOP) ? "Consist TOP" : \
                          (((s & CONSIST_MASK) == CONSIST_SUB) ? "Sub-Consisted" : \
                           "Not Consisted")))

#define CONSISTED(s) (((s & CONSIST_MASK) == CONSIST_MID) || ((s & CONSIST_MASK) == CONSIST_SUB))

/* mask and values for locomotive use determination */
#define LOCOSTAT_MASK     (STAT1_SL_BUSY  | STAT1_SL_ACTIVE)
#define LOCO_IN_USE       (STAT1_SL_BUSY  | STAT1_SL_ACTIVE)
#define LOCO_IDLE         (STAT1_SL_BUSY)
#define LOCO_COMMON       (STAT1_SL_ACTIVE)
#define LOCO_FREE         (0)
#define LOCO_STAT(s)    (  ((s & LOCOSTAT_MASK) == LOCO_IN_USE) ? "In-Use" : \
                         ( ((s & LOCOSTAT_MASK) == LOCO_IDLE)   ? "Idle" : \
                          (((s & LOCOSTAT_MASK) == LOCO_COMMON) ? "Common" : \
                           "Free")))

/* mask and values for decoder type encoding for this slot */
#define DEC_MODE_MASK     (STAT1_SL_SPDEX | STAT1_SL_SPD14 | STAT1_SL_SPD28)

/* Advanced consisting allowed for the next two */
#define DEC_MODE_128A     (STAT1_SL_SPDEX | STAT1_SL_SPD14 | STAT1_SL_SPD28)
#define DEC_MODE_28A      (STAT1_SL_SPDEX                                  )

/* normal modes */
#define DEC_MODE_128      (STAT1_SL_SPD14 | STAT1_SL_SPD28)
#define DEC_MODE_14       (STAT1_SL_SPD14)
#define DEC_MODE_28TRI    (STAT1_SL_SPD28)
#define DEC_MODE_28       (0)
#define DEC_MODE(s)    (    ((s & DEC_MODE_MASK) == DEC_MODE_128A)  ? "128 (Allow Adv. consisting)" : \
                        (   ((s & DEC_MODE_MASK) == DEC_MODE_28A)   ? "28 (Allow Adv. consisting)" : \
                         (  ((s & DEC_MODE_MASK) == DEC_MODE_128)   ? "128" : \
                          ( ((s & DEC_MODE_MASK) == DEC_MODE_14)    ? "14" : \
                           (((s & DEC_MODE_MASK) == DEC_MODE_28TRI) ? "28 (Motorola)" : "28")))))

/* values for track status encoding for this slot */
#define GTRK_PROG_BUSY    0x08                                                 /* 1 = programming track in this master
                                                                                * is Busy */
#define GTRK_MLOK1        0x04                                                 /* 0 = Master is DT200, 1=Master
                                                                                * implements LocoNet 1.1 */
#define GTRK_IDLE         0x02                                                 /* 0 = Track paused, B'cast EMERG STOP,
                                                                                * 1 = Power On */
#define GTRK_POWER        0x01

#define FC_SLOT           0x7b                                                 /* Fast clock is in this slot */
#define PRG_SLOT          0x7c                                                 /* This slot communicates with the
                                                                                * programming track */

/* values and macros to decode programming messages */
#define PCMD_RW           0x40                                                 /* 1 = write, 0 = read */
#define PCMD_BYTE_MODE    0x20                                                 /* 1 = byte operation, 0 = bit operation 
                                                                                * (if possible) */
#define PCMD_TY1          0x10                                                 /* TY1 Programming type select bit */
#define PCMD_TY0          0x08                                                 /* TY0 Programming type select bit */
#define PCMD_OPS_MODE     0x04                                                 /* 1 = Ops mode, 0 = Service Mode */
#define PCMD_RSVRD1       0x02                                                 /* reserved */
#define PCMD_RSVRD0       0x01                                                 /* reserved */

/* programming mode mask */
#define PCMD_MODE_MASK      (PCMD_BYTE_MODE | PCMD_OPS_MODE | PCMD_TY1 | PCMD_TY0)

/*
 *  programming modes
 */

/* Paged mode  byte R/W on Service Track */
#define PAGED_ON_SRVC_TRK       (PCMD_BYTE_MODE)

/* Direct mode byte R/W on Service Track */
#define DIR_BYTE_ON_SRVC_TRK    (PCMD_BYTE_MODE | PCMD_TY0)

/* Direct mode bit  R/W on Service Track */
#define DIR_BIT_ON_SRVC_TRK     (PCMD_TY0)

/* Physical Register byte R/W on Service Track */
#define REG_BYTE_RW_ON_SRVC_TRK (PCMD_TY1)

/* Service Track Reserved function */
#define SRVC_TRK_RESERVED       (PCMD_TY1 | PCMD_TY0)

/* Ops mode byte program - no feedback */
#define OPS_BYTE_NO_FEEDBACK    (PCMD_BYTE_MODE | PCMD_OPS_MODE)

/* Ops mode byte program - feedback */
#define OPS_BYTE_FEEDBACK       (OPS_BYTE_NO_FEEDBACK | PCMD_TY0)

/* Ops mode bit program - no feedback */
#define OPS_BIT_NO_FEEDBACK     (PCMD_OPS_MODE)

/* Ops mode bit program - feedback */
#define OPS_BIT_FEEDBACK        (OPS_BIT_NO_FEEDBACK | PCMD_TY0)

/* Programmer Status error flags */
#define PSTAT_USER_ABORTED  0x08                                               /* User aborted this command */
#define PSTAT_READ_FAIL     0x04                                               /* Failed to detect Read Compare
                                                                                * Acknowledge from decoder */
#define PSTAT_WRITE_FAIL    0x02                                               /* No Write acknowledge from decoder */
#define PSTAT_NO_DECODER    0x01                                               /* Service mode programming track empty */

/* bit masks for CVH */
#define CVH_CV8_CV9         0x30                                               /* mask for CV# bits 8 and 9 */
#define CVH_CV7             0x01                                               /* mask for CV# bit 7 */
#define CVH_D7              0x02                                               /* MSbit for data value */

/* build data byte from programmer message */
#define PROG_DATA(ptr)      (((ptr->cvh & CVH_D7) << 6) | (ptr->data7 & 0x7f))

/* build CV # from programmer message */
#define PROG_CV_NUM(ptr)    (((((ptr->cvh & CVH_CV8_CV9) >> 3) | (ptr->cvh & CVH_CV7)) * 128)   \
                            + (ptr->cvl & 0x7f))

#ifdef __BORLANDC__
#pragma pack( push, 1 )
#endif

/* Locomotive Address Message */
typedef struct locoadr_t
{
   byte                                    command;
   byte                                    adr_hi;                             /* ms seven bits of loco address (D6-D0) 
                                                                                */
   byte                                    adr_lo;                             /* ls seven bits of loco address (D6-D0) 
                                                                                */
   byte                                    chksum;                             /* exclusive-or checksum for the message 
                                                                                */
} locoAdrMsg;

/* Switch with/without Acknowledge */
typedef struct switchack_t
{
   byte                                    command;
   byte                                    sw1;                                /* ls seven bits of switch address
                                                                                * (D6-D0) */
   byte                                    sw2;                                /* ms four bits of switch address
                                                                                * (D3-D0) */
   /* and control bits */
   byte                                    chksum;                             /* exclusive-or checksum for the message 
                                                                                */
} switchAckMsg                         , switchReqMsg;

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

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

/* Consist Function Message */
typedef struct consistfunc_t
{
   byte                                    command;
   byte                                    slot;                               /* slot number for this request */
   byte                                    dirf;                               /* direction and light function bits */
   byte                                    chksum;                             /* exclusive-or checksum for the message 
                                                                                */
} consistFuncMsg;

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

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

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

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

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

/* Set slot sound functions */
typedef struct locodata_t
{
   byte                                    command;
   byte                                    slot;                               /* slot number for this request */
   byte                                    data;                               /* data for request */
   byte                                    chksum;                             /* exclusive-or checksum for the message 
                                                                                */
} locoDataMsg;

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

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

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

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

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

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

/* peer-peer transfer message */
typedef struct peerxfer_t
{
   byte                                    command;
   byte                                    mesg_size;                          /* ummmmm, size of the message in bytes? 
                                                                                */
   byte                                    src;                                /* source of transfer */
   byte                                    dst_l;                              /* ls 7 bits of destination */
   byte                                    dst_h;                              /* ms 7 bits of destination */
   byte                                    pxct1;
   byte                                    d1;                                 /* data byte 1 */
   byte                                    d2;                                 /* data byte 2 */
   byte                                    d3;                                 /* data byte 3 */
   byte                                    d4;                                 /* data byte 4 */
   byte                                    pxct2;
   byte                                    d5;                                 /* data byte 5 */
   byte                                    d6;                                 /* data byte 6 */
   byte                                    d7;                                 /* data byte 7 */
   byte                                    d8;                                 /* data byte 8 */
   byte                                    chksum;                             /* exclusive-or checksum for the message 
                                                                                */
} peerXferMsg;

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

/* sv message */
typedef struct sv_t
{
   byte                                    command;                            /* LocoNet Op Code */
   byte                                    mesg_size;                          /* size of the message in bytes */
   byte                                    src;                                /* 8 bit source address */
   byte                                    sv_cmd;                             /* SV Command */
   byte                                    sv_type;                            /* SV Type = 0x02 for this format */
   byte                                    svx1;                               /* <0,0,0,1,D3,D2,D1,D0 of next 4 bytes */
   byte                                    dst_lo;                             /* low 8 bits of 16 bit destination
                                                                                * address */
   byte                                    dst_hi;                             /* high 8 bits of 16 bit destination
                                                                                * address */
   byte                                    sv_addl;                            /* low 8 bits of 16 bit SV Offset */
   byte                                    sv_addh;                            /* low 8 bits of 16 bit SV Offset */
   byte                                    svx2;                               /* <0,0,0,1,D3,D2,D1,D0 of next 4 bytes */
   byte                                    d1;                                 /* SV data byte 1 */
   byte                                    d2;                                 /* SV data byte 2 */
   byte                                    d3;                                 /* SV data byte 3 */
   byte                                    d4;                                 /* SV data byte 4 */
   byte                                    chksum;                             /* exclusive-or checksum for the message 
                                                                                */
} svMsg;

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

typedef struct se_t
{
   byte                                    command;
   byte                                    mesg_size;                          /* ummmmm, size of the message in bytes? 
                                                                                */
   byte                                    addr_h;                             /* ms 7 bits of destination */
   byte                                    addr_l;                             /* ls 7 bits of destination */
   byte                                    cmd;                                /* command */
   byte                                    se1;                                /* data Byte 1 */
   byte                                    se2;                                /* data byte 2 */
   byte                                    se3;                                /* data byte 3 */
   byte                                    chksum;                             /* exclusive-or checksum for the message 
                                                                                */
} seMsg;

typedef struct
{
   byte                                    command;                            // OPC_PEER_XFER for replies,
   // OPC_IMM_PACKET for commands
   byte                                    mesg_size;                          // 15 bytes
   byte                                    SRC;                                // source
   byte                                    DSTL;                               // destination, low byte
   byte                                    DSTH;                               // destination, high byte
   byte                                    ReqId;                              // Request ID, distinguishes commands
   byte                                    PXCT1;                              // MSBs of following data
   byte                                    D[7];
} UhlenbrockMsg;

typedef union
{
   locoAdrMsg                              la;
   switchAckMsg                            sa;
   slotReqMsg                              sr;
   slotMoveMsg                             sm;
   consistFuncMsg                          cf;
   slotStatusMsg                           ss;
   longAckMsg                              lack;
   inputRepMsg                             ir;
   swRepMsg                                srp;
   swReqMsg                                srq;
   locoDataMsg                             ld;
   locoSndMsg                              ls;
   locoDirfMsg                             ldf;
   locoSpdMsg                              lsp;
   rwSlotDataMsg                           sd;
   fastClockMsg                            fc;
   progTaskMsg                             pt;
   peerXferMsg                             px;
   sendPktMsg                              sp;
   svMsg                                   sv;
   szMsg                                   sz;
   seMsg                                   se;
   UhlenbrockMsg                           ub;
   byte                                    data[16];
} lnMsg;

#ifdef __BORLANDC__
#pragma pack( pop )
#endif

/* loconet opcodes */
#define OPC_BUSY          0x81
#define OPC_GPOFF         0x82
#define OPC_GPON          0x83
#define OPC_IDLE          0x85
#define OPC_LOCO_SPD      0xa0
#define OPC_LOCO_DIRF     0xa1
#define OPC_LOCO_SND      0xa2
#define OPC_SW_REQ        0xb0
#define OPC_SW_REP        0xb1
#define OPC_INPUT_REP     0xb2
#define OPC_UNKNOWN       0xb3
#define OPC_LONG_ACK      0xb4
#define OPC_SLOT_STAT1    0xb5
#define OPC_CONSIST_FUNC  0xb6
#define OPC_UNLINK_SLOTS  0xb8
#define OPC_LINK_SLOTS    0xb9
#define OPC_MOVE_SLOTS    0xba
#define OPC_RQ_SL_DATA    0xbb
#define OPC_SW_STATE      0xbc
#define OPC_SW_ACK        0xbd
#define OPC_LOCO_ADR      0xbf
#define OPC_PEER_XFER     0xe5
#define OPC_SL_RD_DATA    0xe7
#define OPC_IMM_PACKET    0xed
#define OPC_IMM_PACKET_2  0xee
#define OPC_WR_SL_DATA    0xef
#define OPC_MASK          0x7f                                                 /* mask for acknowledge opcodes */

/*** STATIC DATA ***/

/*** PROTOTYPES ***/

/*** FUNCTIONS ***/

/*** END OF FILE ***/

#endif
