#include <SerialDevice.h>

#ifndef LCXMODEM_H
#define LCXMODEM_H

#define SOH    (BYTE)0x01   // start-of-packet character
#define EOT    (BYTE)0x04   // end-of-transmission char
#define ACK    (BYTE)0x06
#define NAK    (BYTE)0x15

#ifdef BOOL
   #undef  BOOL
#endif
#define BOOL int

#ifdef BYTE
   #undef  BYTE
#endif
#define BYTE unsigned char

#ifdef WORD
   #undef  WORD
#endif
#define WORD unsigned short

#ifdef DWORD
   #undef  DWORD
#endif
#define DWORD unsigned long

#ifdef HIBYTE
   #undef HIBYTE
#endif
#define HIBYTE(x)   (BYTE)(((x) >> 8) & 0x00FF)

#ifdef LOBYTE
   #undef LOBYTE
#endif
#define LOBYTE(x)   (BYTE)((x) & 0x00FF)

#define  FALSE  0
#define  TRUE   (!FALSE)

#define ERRORMAX               6
#define RETRYMAX               4
#define PACKET_SIZE         1024
#define LAUNCH_CYCLE_WAIT_MIN  4L  


 struct BuoyStatus    // LC will have an array of these, one for each buoy
{
   BYTE   bBuoyNumber;
   BYTE   bMainBattVolts;
   BYTE   bAuxBattVolts;
   BYTE   bTempDegC;
   time_t lTimeSecBuoy;
   long   lARGOSBytesBuoy;
   long   lArchiveBytesBuoy;
   long   lPicoBytesAvailBuoy;
   long   lDataMemoryBuoy;
};

struct LauncherStatus
{
   BYTE   bLauncherError;
   BYTE   bLastLaunchOK;
   BYTE   bBuoyResponsive;
   BYTE   bNextBuoyReady;
   BYTE   bCurrentBuoyNumber;
   BYTE   bNextBuoyNumber;
   BYTE   bTotalNumBuoys;
   BYTE   bNumBuoysRemain;
   BYTE   bNumBuoysLaunched;
   BYTE   bTT8SupplyVoltsL;
   BYTE   bMotorSupplyVoltsL;
   BYTE   bTempDegCL;
   time_t lTimeSecL;
   long   lARGOSBytesL;
   long   lArchiveBytesL;
   long   lPicoBytesAvailL;
   long   lDataMemoryL;
   // 12 buoys
   // although maybe this should be just for the current buoy
   struct BuoyStatus Buoy;
};

// error codes re comms with Buoy
enum BuoyErrors
{
   BOUY_OK = -100, // start here so we do not get confused with ACK/NAK
   BAD_BUOY,
   BUOYCLOCKNOTSET,
   OVERALLTIMEOUT,
   CHARTIMEOUT,
   BADCOMMAND,
   BADCHECKSUM,
   BADRESPONSE,
   BADXMODEMSEND,
   BADXMODEMRCV,
   BADLAUNCHERDISK,
   LAUNCHERDISKFULL,
   MAXBUOYARCHIVEBYTES,
   DATAFILECORRUPTED,
   BADBUOYDISK,
   BADGPS,
   NODATA,
   ESCAPE_KEY,
   ROT_ONE_TO_DATA,
   ROT_ONE_TO_LAUNCH,
   ROT_FORWARD,
   ROT_REVERSE,
   STOP_ROT,
   LAUNCH_FROM_DATA_POS,
   PUSH_BUOY_OUT,
   ARMS_OUT,
   RETRACT_ARMS,
   STOP_ARMS
};

// error codes re. Launcher status - to return in struct LauncherStatus
// member "bLauncherError"
enum LauncherErrors
{
   LAUNCHER_OK = 0,
   MAX_BUOY_ARCHIVE_BYTES,
   ROT_MOTOR_DID_NOT_TURN,    // timeout waiting for limit switch
   ROT_MOTOR_STALLED,         // max current
   ROT_MOTOR_FAIL,            // 0 current
   CAROUSEL_POS_UNKNOWN,
   NO_BUOY_AT_DATA_POS,       // timeout waiting for limit switch
   NO_BUOY_AT_LAUNCH_POS,     // timeout waiting for limit switch
   BUOY_NOT_PUSHED_OUT,       // timeout waiting for limit switch
   ARMS_MOTOR_DID_NOT_TURN,    // timeout waiting for limit switch
   ARMS_MOTOR_STALLED,         // max current
   ARMS_MOTOR_FAIL,            // 0 current
   ARMS_POSITION_UNKNOWN,
   ARMS_FAILED_DOWN,
   ARMS_NOT_DOWN,             // timeout waiting for down limit switch
   CANNOT_FIND_BUOY,
   CANNOT_FIND_GOOD_BUOY,
   DOOR_NOT_CLOSED            // timeout waiting for limit switch
};

enum  DataXferSWErrors  // errors in data transfer
{
   OKAY = 0,
   BAD_LAUNCHER,
   BUOY_NOT_TALKING,
   BUOY_FULL_OF_DATA,
   OVERALL_TIMEOUT,
   CHAR_TIMEOUT,
   BAD_COMMAND,
   BAD_CHECKSUM,
   BAD_RESPONSE,
   XMODEM_ERROR,
   LAUNCH_ERROR,
   LAUNCHER_DISK_FULL,
   UNKNOWN_ERROR,
};

enum  DataXferHWErrors  // errors in data transfer
{
   BUOY_DISK,
   BUOY_MEM,
   LAUNCHER_DISK,
   LAUNCHER_MEM
};

class LcXmodem {

public:

  LcXmodem(SerialDevice *device) : _device(device) {}

  virtual ~LcXmodem() {}

  int    sendXmodem(BYTE *senddata, long numbytes);
  int    receiveXmodem(BYTE *r, long *p);

protected:

  SerialDevice *_device;

  void SendByte(BYTE);
  void SendChar(char);
  int GetCharTimeout(char *b, time_t timeout_sec);

};

#endif    // on LCXMODEM_H
