#define SCPI_GPIB_CORE_C
#include "app/scpi/scpi_gpib_core.h"
#include "my_assert.h"

// Reference:
// [1] SCPI Specification, revision 1999.0
//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
// [2], Gpib Programming Tutorial, Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
// [3] USBTMC-USB488 Standard, rev. 1.0, 14/04/2003
//     "Universal Serial Bus Test and Measurement Class, Subclass USB488 Specification (USBTMC-USB488)
// [4] IEEE 488.2 Standard, revision IEEE Std 488.2-1987 (1992)
//     "IEEE Standard Codes, Formats, Protocols, and Common Commands for Use With IEEE Std 488.1-1987, IEEE

static void gpib_get_event_status_register( xGPIBRegisters_t * _gpibr, uint8_t * pesr );
static void gpib_set_event_status_register_power_on_state( xGPIBRegisters_t * _gpibr, bool pon );
static void gpib_set_event_status_register_user_request_state( xGPIBRegisters_t * _gpibr, bool urq );
static void gpib_set_event_status_register_command_error_state( xGPIBRegisters_t * _gpibr, bool cme );
static void gpib_set_event_status_register_execution_error_state( xGPIBRegisters_t * _gpibr, bool e );
static void gpib_set_event_status_register_device_specific_error_state( xGPIBRegisters_t * _gpibr, bool dde );
static void gpib_set_event_status_register_query_error_state( xGPIBRegisters_t * _gpibr, bool qye );
static void gpib_set_event_status_register_request_control_state( xGPIBRegisters_t * _gpibr, bool rqc );
static void gpib_set_event_status_register_operation_complete_state( xGPIBRegisters_t * _gpibr, bool opc );
static void gpib_get_event_status_enable_register( xGPIBRegisters_t * _gpibr, uint8_t * pese );
static void gpib_set_event_status_enable_register( xGPIBRegisters_t * _gpibr, uint8_t ese );
static void gpib_get_event_summary_bit( xGPIBRegisters_t * _gpibr, uint8_t * pesb );
static void gpib_set_event_summary_enable_state( xGPIBRegisters_t * _gpibr, bool esb );
static void gpib_set_message_available_bit( xGPIBRegisters_t * _gpibr, bool mav );
static void gpib_set_message_available_enable_state( xGPIBRegisters_t * _gpibr, bool mav );
static void gpib_get_message_available_bit( xGPIBRegisters_t * _gpibr, uint8_t * pmav );
static void gpib_set_error_available_bit( xGPIBRegisters_t * _gpibr, bool eav );
static void gpib_set_error_available_enable_state( xGPIBRegisters_t * _gpibr, bool eav );
static void gpib_get_error_available_bit( xGPIBRegisters_t * _gpibr, uint8_t * peav );
static void gpib_get_status_byte_serial_poll( xGPIBRegisters_t * _gpibr, uint8_t * pstb );
static void gpib_get_status_byte_normal_poll( xGPIBRegisters_t * _gpibr, uint8_t * pstb );
static void gpib_clr_status_byte( xGPIBRegisters_t * _gpibr );
static void gpib_get_service_request_enable_register( xGPIBRegisters_t * _gpibr, uint8_t * psre );
static void gpib_set_service_request_enable_register( xGPIBRegisters_t * _gpibr, uint8_t sre );
static void gpib_get_service_request_status( xGPIBRegisters_t * _gpibr, bool * psrq );
static void gpib_set_service_request_status( xGPIBRegisters_t * _gpibr, bool srq );

const sGPIBMachineRoutines_t GPIBMachine = 
{
     .fGPIB_get_event_status_register                              = gpib_get_event_status_register,
     .fGPIB_set_event_status_register_power_on_state               = gpib_set_event_status_register_power_on_state,             
     .fGPIB_set_event_status_register_user_request_state           = gpib_set_event_status_register_user_request_state,         
     .fGPIB_set_event_status_register_command_error_state          = gpib_set_event_status_register_command_error_state,        
     .fGPIB_set_event_status_register_execution_error_state        = gpib_set_event_status_register_execution_error_state,      
     .fGPIB_set_event_status_register_device_specific_error_state  = gpib_set_event_status_register_device_specific_error_state,
     .fGPIB_set_event_status_register_query_error_state            = gpib_set_event_status_register_query_error_state,          
     .fGPIB_set_event_status_register_request_control_state        = gpib_set_event_status_register_request_control_state,      
     .fGPIB_set_event_status_register_operation_complete_state     = gpib_set_event_status_register_operation_complete_state,  
     .fGPIB_get_event_status_enable_register                       = gpib_get_event_status_enable_register,
     .fGPIB_set_event_status_enable_register                       = gpib_set_event_status_enable_register,
     .fGPIB_get_event_summary_bit                                  = gpib_get_event_summary_bit,
     .fGPIB_set_event_summary_enable_state                         = gpib_set_event_summary_enable_state,
     .fGPIB_set_message_available_bit                              = gpib_set_message_available_bit,
     .fGPIB_set_message_available_enable_state                     = gpib_set_message_available_enable_state,
     .fGPIB_get_message_available_bit                              = gpib_get_message_available_bit,
     .fGPIB_set_error_available_bit                                = gpib_set_error_available_bit,
     .fGPIB_set_error_available_enable_state                       = gpib_set_error_available_enable_state,
     .fGPIB_get_error_available_bit                                = gpib_get_error_available_bit,
     .fGPIB_get_status_byte_serial_poll                            = gpib_get_status_byte_serial_poll,
     .fGPIB_get_status_byte_normal_poll                            = gpib_get_status_byte_normal_poll,
     .fGPIB_clr_status_byte                                        = gpib_clr_status_byte,
     .fGPIB_get_service_request_enable_register                    = gpib_get_service_request_enable_register,
     .fGPIB_set_service_request_enable_register                    = gpib_set_service_request_enable_register,
     .fGPIB_get_service_request_status                             = gpib_get_service_request_status,
     .fGPIB_set_service_request_status                             = gpib_set_service_request_status,
};

// Reference:
// [1] SCPI Specification, revision 1999.0
//     "Standard Commands for Programmable Instruments (SCPI), VERSION 1999.0, May 1999"
// [2], Gpib Programming Tutorial, Electronics Group (http://www.few.vu.nl/~elec), 11 January 2000 Electronics Group, (http://g2pc1.bu.edu/~qzpeng/gpib/manual/GpibProgTut.pdf)
// [3] USBTMC-USB488 Standard, rev. 1.0, 14/04/2003
//     "Universal Serial Bus Test and Measurement Class, Subclass USB488 Specification (USBTMC-USB488)
// --------------------------------------------------------------------------------------------------------

#pragma pack(push,1)
  typedef struct
  {
     uint8_t  operationComplete  :  1;
     uint8_t  requestControl     :  1;
     uint8_t  queryError         :  1;
     uint8_t  deviceError        :  1;
     uint8_t  executionError     :  1;
     uint8_t  commandError       :  1;
     uint8_t  userRequest        :  1;
     uint8_t  powerOn            :  1;
  }
  sGPIBEventStatusRegisterBits_t;   // "4 Instrument status", [2]

  typedef struct
  {
     uint8_t  bit_0              :  1;
     uint8_t  bit_1              :  1;
     uint8_t  EAV                :  1;  // Error AVailable bit
     uint8_t  bit_3              :  1;
     uint8_t  MAV                :  1;  // Message AVailable bit
     uint8_t  ESB                :  1;  // Event Summary Bit
     uint8_t  RQS_MSS            :  1;  // ReQuested Service / Master Summary Status
     uint8_t  bit_7              :  1;
  }
  sGPIBStatusByteRegisterBits_t;   // "4 Instrument status", [2]; "4.3.1 READ_STATUS_BYTE", [3]

  typedef struct
  {
     union
     {
        sGPIBEventStatusRegisterBits_t bits;
        uint8_t                        byte;
     }
     ESR; // "ESR", "Event Status Register"

     union
     {
        sGPIBEventStatusRegisterBits_t bits;
        uint8_t                        byte;
     }
     ESE; // "ESE", "Event Status Enable Register"
  }
  sGPIBEventStatus_t;   // "4 Instrument status", [2]

  typedef union
  {
     sGPIBStatusByteRegisterBits_t  bits;
     uint8_t                        byte;
  }
  sGPIB_STB_t; // "STB", "Status Byte Register"

  typedef union
  {
     sGPIBStatusByteRegisterBits_t  bits;
     uint8_t                        byte;
  }
  sGPIB_SRE_t; // "SRE", "Service Request Enable Register"

  typedef struct
  {
     sGPIB_STB_t STB; 
     sGPIB_SRE_t SRE;
     union
     {
     bool requestService;
     uint32_t reserved;
     };
  }
  sGPIBStatusByte_t;   // "4 Instrument status", [2]

  typedef struct
  {
     sGPIBEventStatus_t EventStatus;
     sGPIBStatusByte_t  Status;
  }
  sGPIBRegisters_t;
#pragma pack(pop)
// --------------------------------------------------------------------------------------------------------
STATIC_ASSERT( sizeof(xGPIBRegisters_t) == sizeof(sGPIBRegisters_t), "Invalid xGPIBRegisters_t/sGPIBRegisters_t size" );
// --------------------------------------------------------------------------------------------------------
static void gpib_RQS_set( xGPIBRegisters_t * _gpibr )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;
   gpibr->Status.requestService = true;
}
static void gpib_RQS_reset( xGPIBRegisters_t * _gpibr )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;
   gpibr->Status.requestService = false;
}
// --------------------------------------------------------------------------------------------------------
static void gpib_STB_update( xGPIBRegisters_t * _gpibr )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;
   sGPIB_STB_t MASK = { .byte = 0xff }; MASK.bits.RQS_MSS = 0;
   gpibr->Status.STB.bits.RQS_MSS = (gpibr->Status.SRE.byte & gpibr->Status.STB.byte & MASK.byte)?1:0;
}
// --------------------------------------------------------------------------------------------------------
// @gpib_get_event_status_register
// Returns GPIB event status register
// Reference:
//  "4 Instrument status", [2]
//  "10.12 *ESR?, Standard Event Status Register Query", [4]
//  "11.5.1.2 Standard Event Status Register Operation", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @pesr - pointer to the variable to store the value of ESR (event status register) to.
// Returns: none
static void gpib_get_event_status_register( xGPIBRegisters_t * _gpibr, uint8_t * pesr )
{
   my_assert( _gpibr );
   my_assert( pesr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   *pesr = gpibr->EventStatus.ESR.byte;

   //  "10.12 *ESR?, Standard Event Status Register Query", [4]
   //  "11.5.1.2 Standard Event Status Register Operation", [4]
   // "<...> Reading the Standard Event Status Register clears it <...>", [4]
   gpibr->EventStatus.ESR.byte = 0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_register_power_on_state
// Sets GPIB event status register status: power on
// Reference:
//  "4 Instrument status", [2]
//  "11.5.1.1 Standard Event Status Register Bit Definitions", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @pon - value of Power On bit (PON) in ESR (event status register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_register_power_on_state( xGPIBRegisters_t * _gpibr, bool pon )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESR.bits.powerOn = (pon)?1:0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_register_user_request_state
// Sets GPIB event status register status: user request
// Reference:
//  "4 Instrument status", [2]
//  "11.5.1.1 Standard Event Status Register Bit Definitions", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @urq - value of User Request bit (URQ) in ESR (event status register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_register_user_request_state( xGPIBRegisters_t * _gpibr, bool urq )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESR.bits.userRequest = (urq)?1:0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_register_command_error_state
// Sets GPIB event status register status: command error
// Reference:
//  "4 Instrument status", [2]
//  "11.5.1.1 Standard Event Status Register Bit Definitions", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @cme - value of Command Error bit (CME) in ESR (event status register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_register_command_error_state( xGPIBRegisters_t * _gpibr, bool cme )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESR.bits.commandError = (cme)?1:0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_register_execution_error_state
// Sets GPIB event status register status: execution error
// Reference:
//  "4 Instrument status", [2]
//  "11.5.1.1 Standard Event Status Register Bit Definitions", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @e - value of Execution Error bit (E) in ESR (event status register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_register_execution_error_state( xGPIBRegisters_t * _gpibr, bool e )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESR.bits.executionError = (e)?1:0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_register_device_specific_error_state
// Sets GPIB event status register status: device specific error
// Reference:
//  "4 Instrument status", [2]
//  "11.5.1.1 Standard Event Status Register Bit Definitions", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @dde - value of Device Specific Error bit (DDE) in ESR (event status register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_register_device_specific_error_state( xGPIBRegisters_t * _gpibr, bool dde )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESR.bits.deviceError = (dde)?1:0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_register_query_error_state
// Sets GPIB event status register status: query error
// Reference:
//  "4 Instrument status", [2]
//  "11.5.1.1 Standard Event Status Register Bit Definitions", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @qye - value of Device Specific Error bit (QYE) in ESR (event status register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_register_query_error_state( xGPIBRegisters_t * _gpibr, bool qye )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESR.bits.queryError = (qye)?1:0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_register_request_control_state
// Sets GPIB event status register status: request control
// Reference:
//  "4 Instrument status", [2]
//  "11.5.1.1 Standard Event Status Register Bit Definitions", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @rqc - value of Request Control bit (RQC) in ESR (event status register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_register_request_control_state( xGPIBRegisters_t * _gpibr, bool rqc )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESR.bits.requestControl = (rqc)?1:0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_register_operation_complete_state
// Sets GPIB event status register status: operation complete
// Reference:
//  "4 Instrument status", [2]
//  "11.5.1.1 Standard Event Status Register Bit Definitions", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @opc - value of Operation Complete bit (RQC) in ESR (event status register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_register_operation_complete_state( xGPIBRegisters_t * _gpibr, bool opc )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESR.bits.operationComplete = (opc)?1:0;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_get_event_status_enable_register
// Returns GPIB event status enable register
// Reference:
//  "4 Instrument status", [2]
// Parameters:
// @_gpibr - GPIB Register structure;
// @pesr - pointer to the variable to store the value of ESE (event status enable register) to.
// Returns: none
static void gpib_get_event_status_enable_register( xGPIBRegisters_t * _gpibr, uint8_t * pese )
{
   my_assert( _gpibr );
   my_assert( pese );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   *pese = gpibr->EventStatus.ESE.byte;
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_status_enable_register
// Sets GPIB event status enable register
// Reference:
//  "4 Instrument status", [2]
// Parameters:
// @_gpibr - GPIB Register structure;
// @ese - value of ESE (event status enable register) to write to GPIB Register structure.
// Returns: none
static void gpib_set_event_status_enable_register( xGPIBRegisters_t * _gpibr, uint8_t ese )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->EventStatus.ESE.byte = ese;

   gpibr->Status.STB.bits.ESB = ((gpibr->EventStatus.ESR.byte & gpibr->EventStatus.ESE.byte)?1:0);

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_get_event_summary_bit
// Return GPIB event summary bit
// Reference:
//   "4.1 Status Byte registers (STB and SRE)", "Event Summary Bit", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @pesb - pointer to the variable to store the value of ESB (event summary bit) to.
// Note: the value of the bit will be set to the corresponding bit position, all the rest bits are reset to zero.
// Returns: none 
static void gpib_get_event_summary_bit( xGPIBRegisters_t * _gpibr, uint8_t * pesb )
{
   my_assert( _gpibr );
   my_assert( pesb );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   sGPIB_STB_t MASK = { .byte = 0 }; MASK.bits.ESB = 1;

   *pesb = gpibr->Status.STB.byte & MASK.byte;
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_event_summary_enable_state
// Set GPIB event summary enable bit in Service Request Enable Register (SRE) 
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
// Parameters:
// @_gpibr - GPIB Register structure;
// @esb - the event summary indictor enable to set to GPIB Register structure.     
// Returns: none
static void gpib_set_event_summary_enable_state( xGPIBRegisters_t * _gpibr, bool esb )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->Status.SRE.bits.ESB = (esb)?1:0;

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_message_available_bit
// Return GPIB message available bit
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @mav - the message available indictor to set to GPIB Register structure.
// Returns: none 
static void gpib_set_message_available_bit( xGPIBRegisters_t * _gpibr, bool mav )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->Status.STB.bits.MAV = (mav)?1:0;

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_message_available_enable_state
// Set GPIB message available enable bit in Service Request Enable Register (SRE) 
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
// Parameters:
// @_gpibr - GPIB Register structure;
// @mav - the message available indictor enable to set to GPIB Register structure.     
// Returns: none
static void gpib_set_message_available_enable_state( xGPIBRegisters_t * _gpibr, bool mav )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->Status.SRE.bits.MAV = (mav)?1:0;

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_get_message_available_bit
// Set GPIB message available bit
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @pmav - pointer to the variable to store the value of MAV (message available bit) to.
// Note: the value of the bit will be set to the corresponding bit position, all the rest bits are reset to zero.
// Returns: none 
static void gpib_get_message_available_bit( xGPIBRegisters_t * _gpibr, uint8_t * pmav )
{
   my_assert( _gpibr );
   my_assert( pmav );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   sGPIB_STB_t MASK = { .byte = 0 }; MASK.bits.MAV = 1;

   *pmav = gpibr->Status.STB.byte & MASK.byte;
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_error_available_bit
// Set GPIB error available bit
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @eav - the error available indictor to set to GPIB Register structure.
// Returns: none 
static void gpib_set_error_available_bit( xGPIBRegisters_t * _gpibr, bool eav )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->Status.STB.bits.EAV = (eav)?1:0;

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_error_available_enable_state
// Set GPIB error available enable bit in Service Request Enable Register (SRE)
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
// Parameters:
// @_gpibr - GPIB Register structure;
// @eav - the error available indictor enable to set to GPIB Register structure.
// Returns: none 
static void gpib_set_error_available_enable_state( xGPIBRegisters_t * _gpibr, bool eav )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->Status.SRE.bits.EAV = (eav)?1:0;

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_get_error_available_bit
// Return GPIB error available bit
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @peav - pointer to the variable to store the value of EAV (error available bit) to.
// Note: the value of the bit will be set to the corresponding bit position, all the rest bits are reset to zero.
// Returns: none 
static void gpib_get_error_available_bit( xGPIBRegisters_t * _gpibr, uint8_t * peav )
{
   my_assert( _gpibr );
   my_assert( peav );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   sGPIB_STB_t MASK = { .byte = 0 }; MASK.bits.EAV = 1;

   *peav = gpibr->Status.STB.byte & MASK.byte;
}

// --------------------------------------------------------------------------------------------------------
// @gpib_get_status_byte_serial_poll
// Return GPIB Status Byte during Serial Poll procedure.
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "3.4.1 Interrupt-IN DATA sent due to an SRQ condition", [3]
//   "3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request", [3]
//   "11.2.2 Reading the Status Byte Register", [4]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @pstb - pointer to the variable to store the value of STB (status byte) to.
// Returns: none 
static void gpib_get_status_byte_serial_poll( xGPIBRegisters_t * _gpibr, uint8_t * pstb )
{
   my_assert( _gpibr );
   my_assert( pstb );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   sGPIB_STB_t MASK = { .byte = 0x00 }; MASK.bits.RQS_MSS = (gpibr->Status.requestService)?1:0;

   *pstb = gpibr->Status.STB.byte | MASK.byte;
   
   gpib_RQS_reset(_gpibr); // "11.2.2.1 Reading with a Serial Poll", [4]
}

// --------------------------------------------------------------------------------------------------------
// @gpib_get_status_byte_normal_poll
// Return GPIB Status Byte during *STB? procedure.
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "3.4.1 Interrupt-IN DATA sent due to an SRQ condition", [3]
//   "3.4.2 Interrupt-IN DATA sent due to READ_STATUS_BYTE request", [3]
//   "11.2.2 Reading the Status Byte Register", [4]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @pstb - pointer to the variable to store the value of STB (status byte) to.
// Returns: none 
static void gpib_get_status_byte_normal_poll( xGPIBRegisters_t * _gpibr, uint8_t * pstb )
{
   my_assert( _gpibr );
   my_assert( pstb );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   sGPIB_STB_t MASK = { .byte = 0x00 }; MASK.bits.RQS_MSS = (gpibr->Status.requestService)?1:0;

   *pstb = gpibr->Status.STB.byte | MASK.byte;
}

// --------------------------------------------------------------------------------------------------------
// @gpib_clr_status_byte
// Clears GPIB Status Byte
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.4 Clearing the Status Byte Register"
// Parameters:
// @_gpibr - GPIB Register structure;     
// Returns: none 
void gpib_clr_status_byte( xGPIBRegisters_t * _gpibr )
{
   my_assert( _gpibr );   
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   gpibr->Status.STB.bits.bit_0 = 0;
   gpibr->Status.STB.bits.bit_1 = 0;
   gpibr->Status.STB.bits.bit_3 = 0;
   gpibr->Status.STB.bits.bit_7 = 0;
   gpibr->Status.STB.bits.EAV = 0;
   gpibr->Status.STB.bits.ESB = 0;

   sGPIB_STB_t MASK = { .byte = 0xff }; MASK.bits.RQS_MSS = 0;
   gpibr->Status.STB.bits.RQS_MSS = (gpibr->Status.SRE.byte & gpibr->Status.STB.byte & MASK.byte)?1:0;
}

// --------------------------------------------------------------------------------------------------------
// @gpib_get_service_request_enable_register
// Return GPIB Service Request Enable Register
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @psre - pointer to the variable to store the value of SRE (Service Request Enable Register) to.
// Returns: none 
static void gpib_get_service_request_enable_register( xGPIBRegisters_t * _gpibr, uint8_t * psre )
{
   my_assert( _gpibr );
   my_assert( psre );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   sGPIB_SRE_t MASK = { .byte = 0xff }; MASK.bits.RQS_MSS = 0;

   *psre = (gpibr->Status.SRE.byte) & (MASK.byte);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_service_request_enable_register
// Set GPIB Service Request Enable Register
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @sre - value of SRE (Service Request Enable Register) to write to GPIB Register structure.
// Returns: none 
static void gpib_set_service_request_enable_register( xGPIBRegisters_t * _gpibr, uint8_t sre )
{
   my_assert( _gpibr );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;
   {
   sGPIB_SRE_t MASK = { .byte = 0 }; MASK.bits.RQS_MSS = 0;
   gpibr->Status.SRE.byte = (sre) & (MASK.byte);
   }

   gpib_STB_update(_gpibr);
}

// --------------------------------------------------------------------------------------------------------
// @gpib_get_service_request_status
// Return GPIB Service Request indicator (Service Request Generation, SRQ)
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @psrq - pointer to the variable to store the state of SRQ indicator (Service ReQuest) to.
// Returns: none 
static void gpib_get_service_request_status( xGPIBRegisters_t * _gpibr, bool * psrq )
{
   my_assert( _gpibr );
   my_assert( psrq );
   sGPIBRegisters_t * gpibr = (sGPIBRegisters_t*)_gpibr;

   *psrq = gpibr->Status.requestService;
}

// --------------------------------------------------------------------------------------------------------
// @gpib_set_service_request_status
// Writes GPIB Service Request indicator (Service Request Generation, SRQ)
// Reference:
//   "4 Instrument status", [2]
//   "4.1 Status Byte registers (STB and SRE)", [2]
//   "11.2.2.3 Master Summary Status", [4]
//   "11.3.2.4 Clearing the Service Request Enable Register", [4]
// Parameters:
// @_gpibr - GPIB Register structure;
// @srq - SRQ indicator value (Service ReQuest) to write
// Returns: none 
static void gpib_set_service_request_status( xGPIBRegisters_t * _gpibr, bool srq )
{
   my_assert( _gpibr );
   if( srq )
   gpib_RQS_set( _gpibr );
   else
   gpib_RQS_reset( _gpibr );
}

