/****************************************************************************/
/* Copyright (c) 2015 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  : Power Buoy Data Logger CANBus instrument reader class         */
/* Filename : CanBus.hpp                                                    */
/* Author   : Henthorn                                                      */
/* Project  : Power Buoy                                                    */
/* Version  : 1.0                                                           */
/* Created  : 04/20/2015                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
/*                                                                          */
/* This class is the data source reader for the CANBus instruments on the   */
/* Power Buoy. It is derived from the generic FileSource class.             */
/*                                                                          */
/****************************************************************************/

#ifndef _CANBUS_
#define _CANBUS_

#include <linux/can.h>
#include <linux/can/raw.h>

#include "FileSource.hpp"

class CSVWriter;

class CanBus : public FileSource
{

public:

   // The data contained in a Power Controller CanBUS frame
   //
   struct PC_Record {
      //float  can_time;
      short  seq_num;
      float  rpm;
      float  sd_rpm;
      float  voltage;
      float  power;
      float  bcurrent;
      float  lcurrent;
      float  torque;
      float  diff_press;
      float  bridgedc;
      float  loaddc;
      float  scale;
      float  retract;
      float  target_v;
      unsigned short  status;
      float  sd_rpm_target;
   };

   // The data contained in a Battery Controller CanBUS frame
   //
   struct BC_Record {
      //float  can_time;
      short  seq_num;
      float  voltage;
      float  ips;
      float  vbalance;
      float  vstopcharge;
      float  gfault;
      float  hydrogen;
      unsigned short  status;
   };

#if 0
Packet 0:  (unchanged)
LoadCell  :  Rangefinder : UpperSpringPressure : Lower Spring Pressure

Scaling as before:

Packet 1:  (entirely changed)
epoch most sig. word:  epoch least sig word :  salinity most sig. word :  salinity least significant word

When re-assembled, the epoch seconds is a long that is seconds since 1970 UTC and can just be logged as that.
When re-assembled, the salinity is an unsigned long that is salinity in S/m multiplied by 1000000.  i.e. micro Siemens/m

Packet 2: (only first integer is changed)
temperature  :  Status  :  0  :   0

Here, temperature is an integer representing milli-degrees C.  i.e.  Divide by 1000 to get degrees C.

#endif

   // The data contained in a Spring Controller CanBUS frame
   //
   struct SC_Record {
      //float  can_time;
      short  seq_num;
      short  load;
      float  range;
      float  upsi;
      float  lpsi;
      unsigned long epoch;
      float  salinity;
      float  temperature;
      short  status;
   };

   // The data contained in a Rudder Controller CanBUS frame
   //
   struct RC_Record {
      //float          can_time;
      short          seq_num;
      float          x_vel;       // m/s
      float          y_vel;
      float          z_vel;
      float          pressure;    // psi
      char           b_amp1;      //counts
      char           b_amp2;
      char           b_amp3;
      char           b_cor1;      // percentage
      char           b_cor2;
      char           b_cor3;
      float          target;      // heading data (-180 to +180)
      float          measured;
      float          filtered;
      short          rudder;      // counts
      float          ram;         // inches
      float          qtn[4];
      float          mag[3];      // gauss
      unsigned short status;      // bit field
      float          ang_rate[3]; // rad/sec
      unsigned short vpe_status;  // bit field
      float          accel[3];    // m/sec^2
      short          position;    // Rudder position
      float          p_gain;
      float          i_gain;
      float          d_gain;
      float          period;      // update period
      unsigned short ftc;         // Filter time constant
   };



   // Open a connection to the data source.
   // If the pointer to the writer object is NULL
   // no data is written.
   // 
   CanBus(const char* cansock, CSVWriter* w);

   ~CanBus();

   // Return 0 on error
   // Return the (0 - SourceID) if a full record was read from that source
   // Otherwise, return the number of bytes still needed for
   // a full record.
   // 
   // int v = read_data(0);
   // if (v > 0)
   //   still some reading to do
   // else if (v < 0)
   //   complete record from source (0 - v)
   // else
   //   v == 0, error
   //
   int read_data(char verbose);

   // Return the latest complete record
   // Return 1 if successful, else 0
   // 
   char get_record(PC_Record *pc);
   char get_record(BC_Record *bc);
   char get_record(SC_Record *sc);
   char get_record(RC_Record *rc);

protected:

   unsigned create_mask(unsigned a, unsigned b);
   void make_masks() {
      _seq_mask  = create_mask(0,8);
      _data_mask = create_mask(9,13);
      _src_mask  = create_mask(14,17);
   }



   // Handle Power Controller frame
   //
   int handle_power_msg(struct can_frame);

   // Handle Pneumatic Spring Controller frame
   //
   int handle_spring_msg(struct can_frame);

   // Handle Battery Controller frame
   //
   int handle_battery_msg(struct can_frame);

   // Handle Battery Controller frame
   //
   int handle_rudder_msg(struct can_frame);

   char* _cansock;   // e.g., "can0", "can1"

   unsigned _seq_mask, _data_mask, _src_mask;

   // Double-buffered data record.
   // Use _p to point to the published record buffer
   // _pc_record[_p] is the current stable record
   // _pc_record[1-_p] is the record that is in flux
   // 
   struct CanBus::PC_Record  _pc_record[2];
   struct CanBus::BC_Record  _bc_record[2];
   struct CanBus::SC_Record  _sc_record[2];
   struct CanBus::RC_Record  _rc_record[2];
   char   _p, _b, _s, _r;    // Value will always be either 0 or 1

   CSVWriter* _logger;

   char _verbose;
};

#endif
