/***************************************************************************
 *   Copyright (C) 2021 - 2023 by Federico Amedeo Izzo IU2NUO,             *
 *                                Niccolò Izzo IU2KIN                      *
 *                                Frederik Saraci IU2NRO                   *
 *                                Silvano Seva IU2KWO                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, see <http://www.gnu.org/licenses/>   *
 **************************************************************************/

#include <interfaces/delays.h>
#include "AT1846S.h"
#include "SA8x8.h"

void AT1846S::init()
{
    i2c_writeReg16(0x30, 0x0001);   // Soft reset
    delayMs(50);

    i2c_writeReg16(0x30, 0x0004);   // Chip enable
    i2c_writeReg16(0x04, 0x0FD0);   // 26MHz crystal frequency
    i2c_writeReg16(0x1F, 0x1000);   // Gpio6 squelch output
    i2c_writeReg16(0x09, 0x03AC);
    i2c_writeReg16(0x24, 0x0001);
    i2c_writeReg16(0x31, 0x0031);
    i2c_writeReg16(0x33, 0x45F5);   // AGC number
    i2c_writeReg16(0x34, 0x2B89);   // RX digital gain
    i2c_writeReg16(0x3F, 0x3263);   // RSSI 3 threshold
    i2c_writeReg16(0x41, 0x470F);   // Tx digital gain
    i2c_writeReg16(0x42, 0x1036);
    i2c_writeReg16(0x43, 0x00BB);
    i2c_writeReg16(0x44, 0x06FF);   // Tx digital gain
    i2c_writeReg16(0x47, 0x7F2F);   // Soft mute
    i2c_writeReg16(0x4E, 0x0082);
    i2c_writeReg16(0x4F, 0x2C62);
    i2c_writeReg16(0x53, 0x0094);
    i2c_writeReg16(0x54, 0x2A3C);
    i2c_writeReg16(0x55, 0x0081);
    i2c_writeReg16(0x56, 0x0B02);
    i2c_writeReg16(0x57, 0x1C00);   // Bypass RSSI low-pass
    i2c_writeReg16(0x5A, 0x4935);   // SQ detection time
    i2c_writeReg16(0x58, 0xBCCD);
    i2c_writeReg16(0x62, 0x3263);   // Modulation detect tresh
    i2c_writeReg16(0x4E, 0x2082);
    i2c_writeReg16(0x63, 0x16AD);
    i2c_writeReg16(0x30, 0x40A4);
    delayMs(50);

    i2c_writeReg16(0x30, 0x40A6);   // Start calibration
    delayMs(100);
    i2c_writeReg16(0x30, 0x4006);   // Stop calibration

    delayMs(100);

    i2c_writeReg16(0x58, 0xBCED);
    i2c_writeReg16(0x0A, 0x7BA0);   // PGA gain
    i2c_writeReg16(0x41, 0x4731);   // Tx digital gain
    i2c_writeReg16(0x44, 0x05FF);   // Tx digital gain
    i2c_writeReg16(0x59, 0x09D2);   // Mixer gain
    i2c_writeReg16(0x44, 0x05CF);   // Tx digital gain
    i2c_writeReg16(0x44, 0x05CC);   // Tx digital gain
    i2c_writeReg16(0x48, 0x1A32);   // Noise 1 threshold
    i2c_writeReg16(0x60, 0x1A32);   // Noise 2 threshold
    i2c_writeReg16(0x3F, 0x29D1);   // RSSI 3 threshold
    i2c_writeReg16(0x0A, 0x7BA0);   // PGA gain
    i2c_writeReg16(0x49, 0x0C96);   // RSSI SQL thresholds
    i2c_writeReg16(0x33, 0x45F5);   // AGC number
    i2c_writeReg16(0x41, 0x470F);   // Tx digital gain
    i2c_writeReg16(0x42, 0x1036);
    i2c_writeReg16(0x43, 0x00BB);
}

void AT1846S::setBandwidth(const AT1846S_BW band)
{
    if(band == AT1846S_BW::_25)
    {
        // 25kHz bandwidth
        i2c_writeReg16(0x15, 0x1F00);   // Tuning bit
        i2c_writeReg16(0x32, 0x7564);   // AGC target power
        i2c_writeReg16(0x3A, 0x4003);   // Modulation detect sel
        i2c_writeReg16(0x3F, 0x29D2);   // RSSI 3 threshold
        i2c_writeReg16(0x3C, 0x0E1C);   // Peak detect threshold
        i2c_writeReg16(0x48, 0x1E38);   // Noise 1 threshold
        i2c_writeReg16(0x62, 0x3767);   // Modulation detect tresh
        i2c_writeReg16(0x65, 0x248A);
        i2c_writeReg16(0x66, 0xFF2E);   // RSSI comp and AFC range
        i2c_writeReg16(0x7F, 0x0001);   // Switch to page 1
        i2c_writeReg16(0x06, 0x0024);   // AGC gain table
        i2c_writeReg16(0x07, 0x0214);
        i2c_writeReg16(0x08, 0x0224);
        i2c_writeReg16(0x09, 0x0314);
        i2c_writeReg16(0x0A, 0x0324);
        i2c_writeReg16(0x0B, 0x0344);
        i2c_writeReg16(0x0D, 0x1384);
        i2c_writeReg16(0x0E, 0x1B84);
        i2c_writeReg16(0x0F, 0x3F84);
        i2c_writeReg16(0x12, 0xE0EB);
        i2c_writeReg16(0x7F, 0x0000);   // Back to page 0
        maskSetRegister(0x30, 0x3000, 0x3000);
    }
    else
    {
        // 12.5kHz bandwidth
        i2c_writeReg16(0x15, 0x1100);   // Tuning bit
        i2c_writeReg16(0x32, 0x4495);   // AGC target power
        i2c_writeReg16(0x3A, 0x4003);   // Modulation detect sel
        i2c_writeReg16(0x3F, 0x28D0);   // RSSI 3 threshold
        i2c_writeReg16(0x3C, 0x0F1E);   // Peak detect threshold
        i2c_writeReg16(0x48, 0x1DB6);   // Noise 1 threshold
        i2c_writeReg16(0x62, 0x1425);   // Modulation detect tresh
        i2c_writeReg16(0x65, 0x2494);
        i2c_writeReg16(0x66, 0xEB2E);   // RSSI comp and AFC range
        i2c_writeReg16(0x7F, 0x0001);   // Switch to page 1
        i2c_writeReg16(0x06, 0x0014);   // AGC gain table
        i2c_writeReg16(0x07, 0x020C);
        i2c_writeReg16(0x08, 0x0214);
        i2c_writeReg16(0x09, 0x030C);
        i2c_writeReg16(0x0A, 0x0314);
        i2c_writeReg16(0x0B, 0x0324);
        i2c_writeReg16(0x0C, 0x0344);
        i2c_writeReg16(0x0D, 0x1344);
        i2c_writeReg16(0x0E, 0x1B44);
        i2c_writeReg16(0x0F, 0x3F44);
        i2c_writeReg16(0x12, 0xE0EB);   // Back to page 0
        i2c_writeReg16(0x7F, 0x0000);
        maskSetRegister(0x30, 0x3000, 0x0000);
    }

    reloadConfig();
}

void AT1846S::setOpMode(const AT1846S_OpMode mode)
{
    if(mode == AT1846S_OpMode::DMR)
    {
        // DMR mode
        i2c_writeReg16(0x3A, 0x00C2);
        i2c_writeReg16(0x33, 0x45F5);
        i2c_writeReg16(0x41, 0x4731);
        i2c_writeReg16(0x42, 0x1036);
        i2c_writeReg16(0x43, 0x00BB);
        i2c_writeReg16(0x58, 0xBCFD);   // Bit 0  = 1: CTCSS LPF bandwidth to 250Hz
                                        // Bit 3  = 1: bypass CTCSS HPF
                                        // Bit 4  = 1: bypass CTCSS LPF
                                        // Bit 5  = 1: bypass voice LPF
                                        // Bit 6  = 1: bypass voice HPF
                                        // Bit 7  = 1: bypass pre/de-emphasis
                                        // Bit 11 = 1: bypass VOX HPF
                                        // Bit 12 = 1: bypass VOX LPF
                                        // Bit 13 = 1: bypass RSSI LPF
        i2c_writeReg16(0x44, 0x06CC);
        i2c_writeReg16(0x40, 0x0031);
    }
    else
    {
        // FM mode
        i2c_writeReg16(0x33, 0x44A5);
        i2c_writeReg16(0x41, 0x4431);
        i2c_writeReg16(0x42, 0x10F0);
        i2c_writeReg16(0x43, 0x00A9);
        i2c_writeReg16(0x58, 0xBC05);   // Bit 0  = 1: CTCSS LPF badwidth to 250Hz
                                        // Bit 3  = 0: enable CTCSS HPF
                                        // Bit 4  = 0: enable CTCSS LPF
                                        // Bit 5  = 0: enable voice LPF
                                        // Bit 6  = 0: enable voice HPF
                                        // Bit 7  = 0: enable pre/de-emphasis
                                        // Bit 11 = 1: bypass VOX HPF
                                        // Bit 12 = 1: bypass VOX LPF
                                        // Bit 13 = 1: bypass RSSI LPF
        i2c_writeReg16(0x44, 0x06FF);
        i2c_writeReg16(0x40, 0x0030);

        maskSetRegister(0x57, 0x0001, 0x00);     // Audio feedback off
        maskSetRegister(0x3A, 0x7000, 0x4000);   // Select voice channel
    }

    reloadConfig();
}

/*
 * Implementation of AT1846S I2C interface through SA8x8
 */
void AT1846S::i2c_init()
{
}

void AT1846S::i2c_writeReg16(uint8_t reg, uint16_t value)
{
    sa8x8_writeAT1846Sreg(reg, value);
}

uint16_t AT1846S::i2c_readReg16(uint8_t reg)
{
    return sa8x8_readAT1846Sreg(reg);
}
