#ifndef GPIB_DEFS_H
#define GPIB_DEFS_H

#include "ch32fun.h"

// Control Lines (Active LOW)
#define PIN_EOI PB3
#define PIN_REN PB11
#define PIN_ATN PA8
#define PIN_SRQ PA9
#define PIN_IFC PA10
#define PIN_NDAC PA11  // Handshake: Not Data Accepted
#define PIN_NRFD PA12  // Handshake: Not Ready For Data
#define PIN_DAV PA15   // Handshake: Data Valid

// GPIB Commands

// enum cmd_byte {
//   GTL = 0x1, /* go to local            */
//   SDC = 0x4, /* selected device clear  */
//   PP_CONFIG = 0x5,
//   GET = 0x8,  /* group execute trigger  */
//   TCT = 0x9,  /* take control           */
//   LLO = 0x11, /* local lockout          */
//   DCL = 0x14, /* device clear           */
//   PPU = 0x15, /* parallel poll unconfigure */
//   SPE = 0x18, /* serial poll enable     */
//   SPD = 0x19, /* serial poll disable    */
//   CFE = 0x1f, /* configure enable       */
//   LAD = 0x20, /* value to be 'ored' in to obtain listen address */
//   UNL = 0x3F, /* unlisten               */
//   TAD = 0x40, /* value to be 'ored' in to obtain talk address   */
//   UNT = 0x5F, /* untalk                 */
//   SAD = 0x60, /* my secondary address (base) */
//   PPE = 0x60, /* parallel poll enable (base) */
//   PPD = 0x70  /* parallel poll disable  */
// };

#define GPIB_CMD_GTL 0x01       /* go to local */
#define GPIB_CMD_SDC 0x04       /* selected device clear */
#define GPIB_CMD_PP_CONFIG 0x05 /* parallel poll configure */
#define GPIB_CMD_GET 0x08       /* group execute trigger */
#define GPIB_CMD_TCT 0x09       /* take control */
#define GPIB_CMD_LLO 0x11       /* local lockout */
#define GPIB_CMD_DCL 0x14       /* device clear */
#define GPIB_CMD_PPU 0x15       /* parallel poll unconfigure */
#define GPIB_CMD_SPE 0x18       /* serial poll enable */
#define GPIB_CMD_SPD 0x19       /* serial poll disable */
#define GPIB_CMD_CFE 0x1F       /* configure enable */
#define GPIB_CMD_LAD 0x20       /* listen address (OR with addr) */
#define GPIB_CMD_UNL 0x3F       /* unlisten */
#define GPIB_CMD_TAD 0x40       /* talk address (OR with addr) */
#define GPIB_CMD_UNT 0x5F       /* untalk */
#define GPIB_CMD_SAD 0x60       /* secondary address base */
#define GPIB_CMD_PPE 0x60       /* parallel poll enable */
#define GPIB_CMD_PPD 0x70       /* parallel poll disable */

// Address Groups
#define GPIB_LAG_BASE 0x20  // Listen Address Group base
#define GPIB_TAG_BASE 0x40  // Talk Address Group base
#define GPIB_SCG_BASE 0x60  // Secondary Command Group base

/* HP3478A */
// Measurement Function (F)
#define HP3478A_FUNC_DC_VOLTS "F1"
#define HP3478A_FUNC_AC_VOLTS "F2"
#define HP3478A_FUNC_OHMS_2WIRE "F3"
#define HP3478A_FUNC_OHMS_4WIRE "F4"
#define HP3478A_FUNC_DC_CURRENT "F5"
#define HP3478A_FUNC_AC_CURRENT "F6"
#define HP3478A_FUNC_OHMS_EXT "F7"

// Range (R)
#define HP3478A_RANGE_NEG_2 "R-2" /* 30mV DC */
#define HP3478A_RANGE_NEG_1 "R-1" /* 300mV (AC/DC) or 300mA (AC/DC) */
#define HP3478A_RANGE_0 "R0"      /* 3V (AC/DC) or 3A (AC/DC) */
#define HP3478A_RANGE_1 "R1"      /* 30V (AC/DC) or 30 Ohm */
#define HP3478A_RANGE_2 "R2"      /* 300V (AC/DC) or 300 Ohm */
#define HP3478A_RANGE_3 "R3"      /* 3K Ohm */
#define HP3478A_RANGE_4 "R4"      /* 30K Ohm */
#define HP3478A_RANGE_5 "R5"      /* 300K Ohm */
#define HP3478A_RANGE_6 "R6"      /* 3M Ohm */
#define HP3478A_RANGE_7 "R7"      /* 30M Ohm */
#define HP3478A_RANGE_AUTO "RA"   /* Autorange */

// Display / Integration Time (N)
#define HP3478A_DIGITS_3_5 "N3" /* 3 1/2 digit (Fastest) */
#define HP3478A_DIGITS_4_5 "N4" /* 4 1/2 digit (1 PLC integration) */
#define HP3478A_DIGITS_5_5 "N5" /* 5 1/2 digit (Best noise rejection) */

// Trigger (T)
#define HP3478A_TRIG_INTERNAL "T1" /* Internal trigger */
#define HP3478A_TRIG_EXTERNAL "T2" /* External trigger pulse */
#define HP3478A_TRIG_SINGLE "T3"   /* Single trigger (Software/GET) */
#define HP3478A_TRIG_HOLD "T4"     /* Trigger Hold (Idle) */
#define HP3478A_TRIG_FAST "T5"     /* Fast Trigger (No settling delay) */

// Autozero (Z)
#define HP3478A_AUTOZERO_OFF "Z0"
#define HP3478A_AUTOZERO_ON "Z1"

// Write to Display (D)
#define HP3478A_DISP_NORMAL "D1" /* Return to normal measurement display */
#define HP3478A_DISP_TEXT "D2"   /* Prefix: Follow with up to 12 chars */
#define HP3478A_DISP_TEXT_FAST \
  "D3" /* Like D2, but stops updating (faster read rate) */

// Preset Commands (H)
#define HP3478A_PRESET_HOME "H0"
#define HP3478A_MEAS_DC_VOLTS "H1"
#define HP3478A_MEAS_AC_VOLTS "H2"
#define HP3478A_MEAS_OHMS_2WIRE "H3"
#define HP3478A_MEAS_OHMS_4WIRE "H4"
#define HP3478A_MEAS_DC_CURRENT "H5"
#define HP3478A_MEAS_AC_CURRENT "H6"
#define HP3478A_MEAS_OHMS_EXT "H7"

#define HP3478A_CMD_STATUS_BYTE "B"

// Serial Poll Register (K)
#define HP3478A_CMD_SRQ_CLEAR "K"

// Error Register (E)
#define HP3478A_CMD_ERR_READ "E"

// Front/Rear Switch (S)
#define HP3478A_CMD_SWITCH_READ "S"

// SRQ Mask (M)
#define HP3478A_CMD_SRQ_MASK_PFX "M"

#define HP3478A_MASK_DATA_READY 0x01   /* Bit 0: Reading available to bus */
#define HP3478A_MASK_UNUSED_B1 0x02    /* Bit 1: Not used */
#define HP3478A_MASK_SYNTAX_ERR 0x04   /* Bit 2: Syntax error */
#define HP3478A_MASK_HARDWARE_ERR 0x08 /* Bit 3: Hardware error */
#define HP3478A_MASK_KEYBOARD_SRQ \
  0x10                             /* Bit 4: Front panel 'SRQ' key pressed */
#define HP3478A_MASK_CAL_FAIL 0x20 /* Bit 5: Calibration procedure failed */
#define HP3478A_MASK_ZERO_B6 0x40  /* Bit 6: Always zero */
#define HP3478A_MASK_POWER_ON 0x80 /* Bit 7: PON Switched/Device Clear */

// "M20" -> SRQ on Button Only
#define HP3478A_CMD_MASK_BTN_ONLY "M20"
// "M21" -> SRQ on Button OR Data Ready
#define HP3478A_CMD_MASK_BTN_DATA "M21"
// "M00" -> Clear Mask (Disable SRQ)
#define HP3478A_CMD_MASK_CLEAR "M00"
#define HP3478A_CMD_MASK_BTN_SYNERR "M24"

#define GPIB_ASSERT(pin) funDigitalWrite(pin, 0)
#define GPIB_RELEASE(pin) funDigitalWrite(pin, 1)
#define GPIB_READ(pin) funDigitalRead(pin)

// Data Lines (DIO1-DIO8)
#define PIN_DIO1 PB9
#define PIN_DIO2 PB8
#define PIN_DIO3 PB5
#define PIN_DIO4 PB4
#define PIN_DIO5 PB15
#define PIN_DIO6 PB14
#define PIN_DIO7 PB13
#define PIN_DIO8 PB12

// Physical Pin mappings on PORT B
#define PIN_POS_D1 9   // PB9
#define PIN_POS_D2 8   // PB8
#define PIN_POS_D3 5   // PB5
#define PIN_POS_D4 4   // PB4
#define PIN_POS_D5 15  // PB15
#define PIN_POS_D6 14  // PB14
#define PIN_POS_D7 13  // PB13
#define PIN_POS_D8 12  // PB12

#define SHIFT_GRP_9 9  // D1 (PB9->0) & D6 (PB14->5)
#define SHIFT_GRP_7 7  // D2 (PB8->1) & D7 (PB13->6)
#define SHIFT_D3 3     // D3 (PB5->2)
#define SHIFT_D4 1     // D4 (PB4->3)
#define SHIFT_D5 11    // D5 (PB15->4)
#define SHIFT_D8 5     // D8 (PB12->7)

// pins that share the same shift amount
// Group A: shift right 9 (PB9->Bit0, PB14->Bit5)
#define MASK_GRP_9 ((1 << 0) | (1 << 5))
// Group B: shift right 7 (PB8->Bit1, PB13->Bit6)
#define MASK_GRP_7 ((1 << 1) | (1 << 6))

#define CALC_PIN_BSHR(val, bit_idx, pin_num) \
  ((val & (1 << bit_idx)) ? (1U << (pin_num + 16)) : (1U << pin_num))

#define MASK_DIO1 (1U << 9)
#define MASK_DIO2 (1U << 8)
#define MASK_DIO3 (1U << 5)
#define MASK_DIO4 (1U << 4)
#define MASK_DIO5 (1U << 15)
#define MASK_DIO6 (1U << 14)
#define MASK_DIO7 (1U << 13)
#define MASK_DIO8 (1U << 12)

#endif
