#pragma once

#include <cstdint>
#include <I2C_Interface.hpp>

// clang-format off

// Datasheet:
// https://www.analog.com/media/en/technical-documentation/data-sheets/2493fe.pdf

// 7-bit address table, see Table 5 in above
/**
+-------+-------+---------+-------------+
|  CA1  |  CA0  | ADDRESS | HEX_ADDRESS |
+-------+-------+---------+-------------+
| LOW   | LOW   | 0010100 | 0x14        |
| LOW   | HIGH  | 0010110 | 0x16        |
| LOW   | Float | 0010101 | 0x15        |
| HIGH  | LOW   | 0100110 | 0x26        |
| HIGH  | HIGH  | 0110100 | 0x34        |
| HIGH  | Float | 0100111 | 0x27        |
| Float | LOW   | 0010111 | 0x17        |
| Float | HIGH  | 0100101 | 0x25        |
| Float | Float | 0100100 | 0x24        |
+-------+-------+---------+-------------+
*/

#define LTC2493_ADDRESS_HIGH_HIGH (0x34)
#define LTC2493_ADDRESS_DEFAULT LTC2493_ADDRESS_HIGH_HIGH

// Set bit (SB) macro
#ifndef _SB
#define _SB(x) (1<<(x))
#endif

// The LTC2493 consumes a 13-bit configuration, broken into two 8-bit words.

// Word 1 Description
/** Table 3 from datasheet
+-------------------------------+-----------------------------+
|          MUX ADDRESSES        |      CHANNEL SELECTION      |
+-----+----------+----+----+----+-----+-----+-----+-----+-----+
| SGL | ODD/SIGN | A2 | A1 | A0 |  0  |  1  |  2  |  3  | COM |
+-----+----------+----+----+----+-----+-----+-----+-----+-----+
| *0  |        0 |  0 |  0 |  0 | IN+ | IN– |     |     |     |
| 0   |        0 |  0 |  0 |  1 |     |     | IN+ | IN– |     |
| 0   |        1 |  0 |  0 |  0 | IN– | IN+ |     |     |     |
| 0   |        1 |  0 |  0 |  1 |     |     | IN– | IN+ |     |
+-----+----------+----+----+----+-----+-----+-----+-----+-----+
| 1   |        0 |  0 |  0 |  0 | IN+ |     |     |     | IN– |
| 1   |        0 |  0 |  0 |  1 |     |     | IN+ |     | IN– |
| 1   |        1 |  0 |  0 |  0 |     | IN+ |     |     | IN– |
| 1   |        1 |  0 |  0 |  1 |     |     |     | IN+ | IN– |
+-----+----------+----+----+----+-----+-----+-----+-----+-----+
*Denote power-up default
*/

/// First configuration word (Channel selection)
//		bit 7 unused (should be 1 according to datasheet)
//		bit 6 unused (should be 0 according to datasheet)
#define CONFIG1_EN	5
#define CONFIG1_SGL	4
#define CONFIG1_ODD	3
#define CONFIG1_A2	2
#define CONFIG1_A1	1
#define CONFIG1_A0	0

// Differential configs, corresponding to rows above
#define CHANNEL_DIFF_0P_1N (0)
#define CHANNEL_DIFF_2P_3N ( _SB(CONFIG1_A0) )
#define CHANNEL_DIFF_0N_1P ( _SB(CONFIG1_ODD) )
#define CHANNEL_DIFF_2N_3P ( _SB(CONFIG1_ODD) | _SB(CONFIG1_A0) )

// Single ended configs, corresponding to rows above
#define CHANNEL_SINGLE_0P ( _SB(CONFIG1_SGL) )
#define CHANNEL_SINGLE_2P ( _SB(CONFIG1_SGL) | _SB(CONFIG1_A0) )
#define CHANNEL_SINGLE_1P ( _SB(CONFIG1_SGL) | _SB(CONFIG1_ODD) )
#define CHANNEL_SINGLE_3P ( _SB(CONFIG1_SGL) | _SB(CONFIG1_ODD) | _SB(CONFIG1_A0) )


/// Second configuration word (Configuration)
/** Table 4 from datasheet
+---+---+----+-----+-----+----+----+----+-----+----+----+----+-----+---------------------------------+
| 1 | 0 | EN | SGL | ODD | A2 | A1 | A0 | EN2 | IM | FA | FB | SPD |     CONVERTER_CONFIGURATION     |
+---+---+----+-----+-----+----+----+----+-----+----+----+----+-----+---------------------------------+
| 1 | 0 |  0 | X   | X   | X  | X  | X  | X   | X  | X  | X  | X   | Keep_Previous                   |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 0   | X  | X  | X  | X   | Keep_Previous                   |
| 0 | 0 |  1 | X   | X   | X  | X  | X  | X   | X  | X  | X  | X   | Keep_Previous                   |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 0  | 0  | 0  | 0   | ExtInput_50Hz/60Hz-Rejection_1x |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 0  | 0  | 1  | 0   | ExtInput_50Hz-Rejection_1x      |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 0  | 1  | 0  | 0   | ExtInput_60Hz-Rejection_1x      |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 0  | 0  | 0  | 1   | ExtInput_50Hz/60Hz-Rejection_2x |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 0  | 0  | 1  | 1   | ExtInput_50Hz-Rejection_2x      |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 0  | 1  | 0  | 1   | ExtInput_60Hz-Rejection_2x      |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 1  | 0  | 0  | X   | MeasTemp_50Hz/60Hz-Rejection_1x |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 1  | 0  | 1  | X   | MeasTemp_50Hz-Rejection_1x      |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | 1  | 1  | 0  | X   | MeasTemp_60Hz-Rejection_1x      |
| 1 | 0 |  1 | X   | X   | X  | X  | X  | 1   | X  | 1  | 1  | X   | Reserved_Do_Not_Use             |
+---+---+----+-----+-----+----+----+----+-----+----+----+----+-----+---------------------------------+

The second set of configuration data can be loaded into
the device by setting EN2 = 1 (see Table 4). 

The first bit (IM) is used to select the internal temperature sensor. If
IM = 1, the following conversion will be performed on
the internal temperature sensor rather than the selected
input channel. 

The next two bits (FA and FB) are used to set the rejection frequency. 

The final bit (SPD) is used to select either the 1x output rate if 
SPD = 0 (auto-calibration is enabled and the offset is continuously 
calibrated and removed from the final conversion result) or the 2x output
rate if SPD = 1 (offset calibration disabled, multiplexing
output rates up to 15Hz with no latency). 

When IM = 1 (temperature measurement) SPD will be ignored and the
device will operate in 1x mode.

The configuration remains valid until a new input word with
EN = 1 (the first three bits are 101 for the first word) and EN2
= 1 (for the second write byte) is shifted into the device.

Rejection Mode (FA, FB)
The LTC2493 includes a high accuracy on-chip oscillator
with no required external components. Coupled with an
integrated fourth order digital lowpass filter, the LTC2493
rejects line frequency noise. In the default mode, the
LTC2493 simultaneously rejects 50Hz and 60Hz by at least
87dB. If more rejection is required, the LTC2493 can be
configured to reject 50Hz or 60Hz to better than 110dB.

Speed Mode (SPD)
Every conversion cycle, two conversions are combined
to remove the offset (default mode). This result is free
from offset and drift. In applications where the offset is
not critical, the auto-calibration feature can be disabled
with the benefit of twice the output rate.

While operating in the 2× mode (SPD = 1), the linearity
and full-scale errors are unchanged from the 2× mode
performance. In both the 2× and 2× mode there is no
latency. This enables input steps or multiplexer changes
to settle in a single conversion cycle, easing system over-
head and increasing the effective conversion rate. During
temperature measurements, the 1× mode is always used
independent of the value of SPD.

 */

#define CONFIG2_EN2     7
#define CONFIG2_IM		6
#define CONFIG2_FA      5
#define CONFIG2_FB		4
#define CONFIG2_SPD		3

#define CONFIG2_ENABLE				(_SB(CONFIG2_EN2))
#define CONFIG2_50HZ_REJECTION		( _SB(CONFIG2_FB) )
#define CONFIG2_60HZ_REJECTION		( _SB(CONFIG2_FA) )
#define CONFIG2_60_50HZ_REJECTION	(0)
#define CONFIG2_SPEED_2X			(_SB(CONFIG2_SPD))
#define CONFIG2_SPEED_1X			(0)

// clang-format on