/********************************  espmsg.h  *******************************
 * $Source: /home/cvs/ESP/gen2/software/msp430/dwarves/espmsg.h,v $
 *  Copyright (C) 2003 MBARI
 *
 *  MBARI Proprietary Information. All rights reserved.
 * $Id: espmsg.h,v 1.24 2006/03/25 00:39:33 brent Exp $
 *
 * ESP "dwarf" node command message formats
 *
 *  These messages are defined in terms of structs without pad
 *  bytes and where all multibyte quantities are assumed to be
 *  stored in "network" byte order e.g. most significant bytes first
 *  On the MSP430, this means that, in practice, these struts 
 *  cannot be used directly.  But, sizeof(struct msg) will be correct, if...
 *
 *  Multi-byte scalar values (like int, msg16 or in32) must
 *  not appear in messages because the compiler may insert pad byte
 *  around them to insure they align on machine word boundaries.
 *  Enumerations (enums) are generally OK in messages, as
 *  must compilers will represent enumerations where all values
 *  are between 0 and 255 as single bytes
 *
 *****************************************************************************/

#ifndef ESPMSG_H
#define ESPMSG_H

#include "types.h"    //standard types
#include "servobits.h" //constants for servo and shaft control and msgs
#include "heater.h"

typedef byte msg24[3];          //24-bit signed integer
typedef byte umsg24[3];         //24-bit signed integer
typedef byte msg32[4];          //32-bit signed integer
typedef byte umsg32[4];         //32-bit signed integer


enum ESPmsgCmd {  //message types -- first byte of each ESP dwarf command

  ESPmsgNOP,          //do nothing
  ESPmsgEchoCmd,      //echo received request to back source node
  ESPmsgDupAdr,       //broadcast to host to warn it of duplicate I2C addresses
  
  solenoidConfigCmd,    //configure solenoid control
  solenoidStatusCmd,    //solenoid status query/reply
  solenoidPulseCmd,     //pulse solenoids
  solenoidHoldCmd,      //hold solenoids
  
  shaftConfigCmd,       //configure shaft control
  shaftStatusCmd,       //shaft status query/reply
  shaftRotateCmd,       //move shaft
  
  thermalConfigCmd,     //configure thermal control
  thermalStatusCmd,     //query/reply
  thermalProgramCmd,    //used to be define/query thermal program
  thermalRunCmd,        //run thermal program

  servoConfigCmd,       //configure servo channel
  servoStatusCmd,       //servo status query/reply
  servoAbsMoveCmd,      //move servo to absolute position
  servoRelMoveCmd,      //move servo relative to current position
  servoOnCmd,           //hold current position
  servoGoalCmd,         //query/reply current servo goal
  servoGripCmd,		//close gripper
  servoReleaseCmd,	//open gripper
  servoGPIOCmd,		//read/write general purpose bits
  servoOffCmd,		//turn off PWM
 
  serialInfoCmd,      //get general information about available serial ports
  serialConfigureCmd, //configure serial port
  serialGetConfigCmd, //get serial port configuration
  serialWriteCmd,     //write a string to a serial port
  serialFlushCmd,     //flush serial port's queues
  serialReadCmd,      //read serial data
  serialReadErrCmd,   //read serial data received with errors
  
  ESPmsgCmds 
};


/**********  Solenoid Control Messages  ********************/

struct ESPdupMsg  { //duplicate address message
  enum ESPmsgCmd cmd;        //ESPmsgDupAdr
  byte  dupAdr;         //source address to which two or more nodes respond
};

struct solenoidConfigMsg  { //each solenoid tic = 1/64 seconds
  enum ESPmsgCmd cmd;         //solenoidConfigCmd
  byte  pulseDuration;  // in tics
};

struct solenoidConfigRequest {
  byte dst;
  enum ESPmsgCmd cmd;         //solenoidConfigCmd
};

struct solenoidConfigReply { 
  enum ESPmsgCmd cmd;      //solenoidConfigCmd
  byte pulseDuration;      // in tics
  byte quanity;            //# of solenoids available
};

struct solenoidStatusRequest {
  byte dst;
  enum ESPmsgCmd cmd;         //solenoidStatusCmd
};

struct solenoidStatusReply { 
  enum ESPmsgCmd cmd;             //solenoidStatusCmd
  byte pulseWidthRemaining; //# of ticks before the end of the current pulse
  byte state[1];            //4 solenoid states per byte (variable length array)
};

//adjacent pairs of bits in each state byte:
//(lowest numbered channel corresponds to the least significant bit pair)
enum {
  solenoidStateOFF,
  solenoidStateUP,
  solenoidStateDOWN,
  solenoidStateReserved
};  


struct solenoidPulseMsg {
  enum ESPmsgCmd cmd;       //solenoidPulseCmd
  byte direction[1];        //4 pulse commands per byte (variable length array)
};

struct solenoidHoldMsg {
  enum ESPmsgCmd cmd;       //solenoidPulseCmd
  byte direction[1];        //4 pulse commands per byte (variable length array)
};

//adjacent pairs of bits in each direction byte:
//(lowest numbered channel corresponds to the least significant bit pair)
enum {
  solenoidDirectionNOP,
  solenoidDirectionUP,
  solenoidDirectionDOWN,
  solenoidDirectionSTOP
};  



/**********  Shaft Rotation Control Messages  ********************/

struct shaftConfig {  //core configuration parameters (not a message in itself!)
  byte    brakeTics;   //# of 1/64 second tics to allow for braking to a stop
  byte    maxCurrent;  //maximum motor current (hundreths of amps)
  umsg16  maxError;    //max acceptable positioning error
  umsg16  revCounts;   //# of encoder counts per revolution (i.e. resolution)
  umsg16  lash;        //amount of expected backlash in counts
  umsg16  near;        //how closely to approach goal before slowing down
  byte    slow;        //slow rate as a percentage of full PWM 
  byte    stuckTics;   //# of tics stuck before applying full power
};

struct shaftConfigMsg  {
  enum ESPmsgCmd cmd;    //shaftConfigCmd
  byte     shaftNumber;  //zero is the 1st shaft
  struct shaftConfig  config;
};

struct shaftConfigRequest {
  enum ESPmsgCmd cmd;    //shaftConfigCmd
  byte     shaftNumber;  //shaft on which configuration data is requested
};

struct shaftConfigReply  {
  enum ESPmsgCmd cmd;    //shaftConfigCmd
  struct shaftConfig  config;
};

struct shaftStatusRequest { 
  enum ESPmsgCmd cmd;   //shaftStatusCmd
  byte     shaftNumber; //shaft on which status is requested
  umsg16   repeatRate;  //optional repeat rate (tics/report)
};

struct shaftStatusReply { 
  enum ESPmsgCmd cmd;   //shaftStatusCmd
  umsg16   angle;       //current angle [0..65535]
  //remaining fields sent only if shaft is moving
  umsg16   goal;        //goal angle [0..65535]
  int8     current;     //current shaft motor current
};

struct shaftRotateRequest {
  enum ESPmsgCmd cmd;   //shaftRotateCmd
  byte     shaftNumber;
  umsg16   goal;        //angle in counts (2^16 == 360 degrees)
  int8     direction;   //+1 = CW, -1 = CCW, 0 = fastest way
};

  
struct shaftRotateReply {
  enum ESPmsgCmd cmd;      //shaftRotateCmd
  umsg16   angle;          //actual angle in counts (2^16 == 360 degrees)
  enum shaftReason reason; //optional error code byte (non-zero implies error)
};


/**********  Servo Control Messages  ********************/

struct servoConfig {  //core configuration parameters (not a message in itself!)
  enum servoOption optionMask; //configuration options
  servoPosition thresholdOffset; //at threshold goal := position + this
  servoPosition maxPositionErr;  //max acceptable position error in counts
  msg16PID  gain;         //PID gains
  umsg16    accel;        //(counts/tic**2)
  umsg16    maxSpeed;     //max allowable speed  (counts/tic)
  umsg16    minSpeed;     //min permissible progress in count/tic)
  umsg16    maxSettling;  //max settling time upon arrival at new goal (tics)
  uint16    maxCurrent;     //max motor drive current
  uint8     maxInPress;     //max inlet pressure
  uint8     maxOutPress;    //max outlet pressure
  uint8     minInPress;     //min inlet pressure
  uint8     minOutPress;    //min outlet pressure
  int8      maxDeltaPress;  //max difference between inlet and outlet press.
  int8      minDeltaPress;  //min difference between inlet and outlet press.
};

struct servoConfigMsg {   //one servo tic == 1/32 seconds
  enum ESPmsgCmd  cmd;    //servoConfigCmd
  byte      channel;      //servo channel 0 or 1
  struct servoConfig item;  //configuration block
};

struct servoOffMsg {  //request channel shut off its servo loop
  enum ESPmsgCmd  cmd;     //servoOffCmd
  byte      channel;       //servo channel 0 or 1
  int8      PWMpercent;    //PWM percentage (signed)
};

struct servoConfigRequest {
  enum ESPmsgCmd  cmd;       //servoConfigCmd
  byte        channel;       //servo channel 0 or 1
};

struct servoConfigReply {   //one servo tic == 1/32 seconds
  enum ESPmsgCmd  cmd;      //servoConfigCmd
  struct servoConfig item;  //configuration block
};
  
struct servoStatusRequest {  //request channel's current status
  enum ESPmsgCmd  cmd;       //servoStatusCmd
  byte      channel;      //servo channel 0 or 1
  umsg16    repeatRate;   //optional repeat rate in tics/report
};

struct servoStatusReply {  //channel's current status
  enum ESPmsgCmd   cmd;       //servoStatusCmd
  struct servoStatus state;   //core servoStatus
};

struct servoMoveRequest {  //absolute or relative move
  enum ESPmsgCmd  cmd;        //servoAbsMoveCmd or servoRelMoveCmd
  byte      channel;
  servoPosition goal;     //target position or relative offest
};

struct servoMoveReply {    //when move is complete...
  enum ESPmsgCmd   cmd;       //servoAbsMoveCmd or servoRelMoveCmd
// subsequent fields are present only if an error occurred
  enum servoReason    reason;       //why the command aborted
  struct servoStatus  stateAtAbort; //detailed status of servo at that instant
};

struct servoOnRequest {  //request channel hold its current position
  enum ESPmsgCmd  cmd;     //servoHoldCmd
  byte      channel;       //servo channel 0 or 1
};

struct servoOnReply {    //when servo hold fails...
  enum ESPmsgCmd   cmd;       //servoAbsMoveCmd or servoRelMoveCmd
// subsequent fields are present only if an error occurred
  enum servoReason    reason;       //why the command aborted
  struct servoStatus  stateAtAbort; //detailed status of servo at that instant
};

struct servoGoalRequest {  //query current servo goal
  enum ESPmsgCmd   cmd;       //servoGoalCmd
  byte             channel;   //servo channel 0 or 1
};

struct servoGoalReply {
  enum ESPmsgCmd   cmd;       //servoGoalCmd
  enum ESPmsgCmd   servoMode; //Hold, AbsMove, RelMove, or ESPmsgNOP if off
  servoPosition    goal;      //omitted if servoMode == ESPmsgNOP
};

struct servoGPIORequest{
  enum ESPmsgCmd   cmd;       //servoGPIOCmd
  byte channel;
};
struct servoGPIOReply{
  enum ESPmsgCmd   cmd;       //servoGPIOCmd
  byte bitMask;		//LSB is the only bit used
};
struct servoGPIOMsg{
  enum ESPmsgCmd   cmd;       //servoGPIOCmd
  byte channel;
  byte bitMask;		//LSB is the only bit used
};
struct servoGripRequest{
  enum ESPmsgCmd   cmd;       //servoGrip or Release
  byte channel;  
};
struct servoGripReply{
  enum ESPmsgCmd   cmd;       //servoGrip or Release
  enum servoReason reason;	//error code see docs  
};

/**********  Thermal Control Messages  ********************/


struct thermalConfigMsg  { 
  enum ESPmsgCmd cmd;   //thermalConfigCmd
  msg16PID  heating, cooling;  //PID gains for heating and cooling 
};

struct thermalConfigRequest {  //response is a struct ThermalConfigMsg
  enum ESPmsgCmd cmd;   //thermalConfigCmd
};
struct thermalConfigReply {   //one servo tic == 1/32 seconds
  enum ESPmsgCmd  cmd;      //servoConfigCmd
  msg16PID  heating, cooling;  //PID gains for heating and cooling
};
  

struct thermalStatusRequest {
  enum ESPmsgCmd cmd;   //thermalStatusCmd
  umsg16   repeatRate;  //optional repeat rate (tics/report) 
};

struct thermalStatusReply {
  enum ESPmsgCmd cmd;   //thermalStatusCmd
  msg16    currentTemperature;   //hundredths of degrees Celsius
  //subsequent fields only appear if a thermal program is running
  umsg16   elapsedTics;          //tics since start of the current program
  byte     heaterPwr, coolerPwr; //current heater and cooler power levels
            //0 == off, 0xff == full power
};

struct thermalRunRequest {
  enum ESPmsgCmd  cmd;        //thermalRunCmd
  thermalStep step[1];  //variable length array
};

struct thermalRunReply {
  enum ESPmsgCmd  cmd;        //thermalRunCmd
  enum thermalReason reason;  //completion code
  umsg16  elapsedTics;  //cmd duration
};

struct thermalProgramRequest {  //return the thermal program
  enum ESPmsgCmd  cmd;        //thermalProgramCmd
};

struct thermalProgramReply {  //same struct as thermalRunRequest
  enum ESPmsgCmd  cmd;       //thermalProgramCmd
  thermalStep step[1];  //variable length array
};


/**********  Serial Port Access Messages  ****************/


enum serialOptions {  //serial options/capabilities
  serialBadBaud     = 0x01, //unsupported baud rate
  serialBadWidth    = 0x02, //unsupported character width
  serialBits        = 0x03, //03=5bits, 02=6bits, 01=7bits, 00=8bits
  serialBits5       = 0x03,
  serialBits6       = 0x02,
  serialBits7       = 0x01,
  serialBits8       = 0x00,
  serialParity      = 0x0C, //00=none, 01=odd, 02=even
  serialParityNone  = 0x00,
  serialParityOdd   = 0x04,
  serialParityEven  = 0x08,
  serialStopBits    = 0x10, //1=2 stop bits, 0=1 stop bit
  serialRTSenable   = 0x20, //RTS handshake input enable
  serialDTRenable   = 0x40, //DTR handshake input enable
  serialDCDenable   = 0x80, //DCD handshake input enable
};

struct serialInfoRequest {  //return information about serial ports
  enum ESPmsgCmd cmd;       //serialInfoCmd
  byte channel;             //channel # (omit for all)
};

struct serialInfoReply {
  enum ESPmsgCmd cmd;       //serialInfoCmd
  struct serialInfoBlock {
    enum serialOptions capabilities;  //bit mask of port's capabilities
    umsg24 maxBaud, minBaud;  //max & min allowed baud rates
  } port[1];                  //variable length
};


struct serialConfigureRequest { //configure a serial port
  enum ESPmsgCmd cmd;     //serialConfigureCmd
  byte  channel;          //port index
  struct serialConfiguration {
    enum serialOptions options;
    umsg24 baudRate;
  } config;
};

struct serialConfigureReply {
  enum ESPmsgCmd cmd;      //serialConfigureCmd
  enum serialOptions errs; //omitted for success
};


struct serialGetConfigRequest {  //return current port configuration(s)
  enum ESPmsgCmd cmd;     //serialGetConfigCmd
  byte  channel;          //port index (all ports if omitted)
};

struct serialGetConfigReply {
  enum ESPmsgCmd cmd;     //serialGetConfigCmd
  struct serialConfiguration config[1]; //variable length
};


struct serialWriteRequest {   //write string of bytes to serial port
  enum ESPmsgCmd cmd;     //serialWriteCmd
  byte  channel;          //serial port index
  byte  string[1];        //max string len allowed is 120 bytes
};

struct serialWriteReply {
  enum ESPmsgCmd cmd;     //serialWriteCmd
  byte  bytesAvailable;   //# of bytes now available in output buffer
  byte  bytesAccepted;    //# of bytes actually enqueued (others must be resent)
};


struct serialFlushMsg {   //flush serial ports I/O buffers and/or send break
  enum ESPmsgCmd cmd;     //serialFlushCmd
  byte  channel;          //serial port index
  enum {
    serialFlushWrite =  0x01,
    serialFlushRead =   0x02,
    serialCancelFlow =  0x10,
    serialAssertBreak = 0x80
  } operation;
};


struct serialReadRequest {  //read received bytes from serial port
  enum ESPmsgCmd cmd; //serialReadCmd
  byte  channel;      //serial port index
  byte  maxBytes;     //max # of bytes in a chunk
  byte  minBytes;     //min # of bytes in a chunk
  umsg16  maxAge;     //reply even if <= minBytes waiting after this many tics
  byte  terminator;   //reply after this byte received (unless omitted)
};

struct serialReadReply {
  enum ESPmsgCmd cmd; //serialReadCmd
  byte  string[1];    //serial bytes received (variable length string)
};

struct serialReadErrReply {  //read data received with errors
  enum ESPmsgCmd cmd; //serialReadErrCmd
  enum {
    serialNoErr      = 0x00,
    serialParityErr  = 0x01,
    serialFramingErr = 0x40,
    serialBreakErr   = 0x80   //break is not an error, strictly speaking, but...
  } serialErr;
  byte  string[1];    //serial bytes received (variable length string)
};


#endif
