MAX4147X RF Receiver Mbed Driver

Fork of MAX4147X by Sinan Divarci

Max4147x.cpp

Committer:
Sinan Divarci
Date:
2021-08-02
Revision:
0:dc5ded118d7c

File content as of revision 0:dc5ded118d7c:

/*******************************************************************************
 * Copyright(C) Maxim Integrated Products, Inc., All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files(the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Maxim Integrated
 * Products, Inc.shall not be used except as stated in the Maxim Integrated
 * Products, Inc.Branding Policy.
 *
 * The mere transfer of this software does not imply any licenses
 * of trade secrets, proprietary technology, copyrights, patents,
 * trademarks, maskwork rights, or any other form of intellectual
 * property whatsoever. Maxim Integrated Products, Inc.retains all
 * ownership rights.
 *******************************************************************************
 */

#include "Max4147x.h"
#include <iostream>

using namespace std;

const uint8_t default_register_value_0[Q_CONF_LEN] = {0x46,0x26,0x08,0x24,0xA7,0x09,0x0A,0x1F,0x00,0x13,0xAC,0xCD,0x0F,0x00,0x00};
const uint8_t default_register_value_1[Q_CONF_LEN] = {0x44,0x26,0x18,0x24,0x00,0x00,0x00,0x1E,0x00,0x13,0xAC,0xCD,0x0F,0x00,0x00};

float bit_rate_min_max[10][2] = {{0.25, 103}, {0.125, 51.5}, {0.0625, 25.75}, {0.03125, 12.875}, {0.015625, 6.4375},
                                 {0.125, 51.5}, {0.0625, 25.75}, {0.3125, 12.875}, {0.015625, 6.4375}, {0.0078125, 3.21875}};

const int  mu1_conf[10]    = {-81, -93, -102, -110, -118, -90, -102, -110, -118, -125};
const char ath_tc_conf[8]  = {0x14, 0x12, 0x10, 0x0D, 0x09, 0x07, 0x05, 0x04};
const char ath_gc_conf[10] = {0x0B, 0x09, 0x08, 0x07, 0x06, 0x0A, 0x07, 0x06, 0x05, 0x04};

const char nominal_fsk_conf[14] = {80, 57, 44, 40, 29, 22, 20, 14, 11, 10, 7, 5, 3, 2};
const char chf_sel_demod_fsk_conf[14][2] = {{0, 0}, {0, 1}, {0, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 3},
                                            {2, 4}, {2, 5}, {3, 4}, {3, 5}, {4, 4}, {4, 5}, {4, 6}};

template <class REG>
MAX4147X<REG>::MAX4147X(REG *reg, SPI *spi, DigitalOut *cs, DigitalOut *powerPin, DigitalIn *dataPin)
{
    operation_mode = UNINITIALIZED;

    if (reg == NULL || spi == NULL || cs == NULL || powerPin == NULL || dataPin == NULL)
        return;

    reg_map     = reg;
    spi_handler = spi;
    ssel        = cs;
    power_pin   = powerPin;
    data_read   = dataPin;
    i2c_handler = NULL;
    preset_mode = 0;

    encoding            = Manchester;
    crystal_frequency   = 16.0f;
    center_frequency    = 315.0f;
    baud_rate           = 2.0f;
    baud_rate_ratio     = 1.0f;

    if (initial_programming() < 0)
        return;
    operation_mode = INITIALIZED;
}

template <class REG>
MAX4147X<REG>::MAX4147X(REG *reg, SPI *spi, DigitalOut *powerPin, DigitalIn *dataPin)
{
    operation_mode = UNINITIALIZED;

    if (reg == NULL || spi == NULL || powerPin == NULL || dataPin == NULL)
        return;

    reg_map     = reg;
    spi_handler = spi;
    ssel        = NULL;
    power_pin   = powerPin;
    data_read   = dataPin;
    i2c_handler = NULL;
    preset_mode = 0;

    encoding            = Manchester;
    crystal_frequency   = 16.0f;
    center_frequency    = 315.0f;
    baud_rate           = 2.0f;
    baud_rate_ratio     = 1.0f;

    if (initial_programming() < 0)
        return;

    operation_mode = INITIALIZED;
}

template <class REG>
MAX4147X<REG>::MAX4147X(REG *reg, I2C *i2c, DigitalOut *powerPin, DigitalIn *dataPin)
{
    operation_mode = UNINITIALIZED;

    if (reg == NULL || i2c == NULL || powerPin == NULL || dataPin == NULL)
        return;

    reg_map     = reg;
    spi_handler = NULL;
    ssel        = NULL;
    power_pin   = powerPin;
    data_read   = dataPin;
    i2c_handler = i2c;
    preset_mode = 0;

    encoding            = Manchester;
    crystal_frequency   = 16.0f;
    center_frequency    = 315.0f;
    baud_rate           = 2.0f;
    baud_rate_ratio     = 1.0f;

    if (initial_programming() < 0)
        return;

    operation_mode = INITIALIZED;
}

template <>
int MAX4147X<max41470_reg_map_t>::read_register(uint8_t reg, uint8_t *value, uint8_t len)
{

    int rtn_val = 0;
    uint8_t readed_byte_cnt = 0;
//Since 3-wire spi is not supported by mbed, the read_register function must be implemented by the user.
//Here you can find an implemented read_register function for the max32630fthr.
#if defined(TARGET_MAX32630FTHR)
    if (value == NULL) {
        return -1;
    }

    if (this->reg_map == NULL) {
        return -1;
    }

    spi_handler->format(8,0);
    spi_handler->frequency(400000);

    if (ssel != NULL) {
        *ssel = 0;
    }
    spi_handler->write((uint8_t)0x80 | reg); // Set R/W bit 1 for reading
    spi_handler->write(0x00);     // dummy write command for waiting data read

    MAX4147X_SPI->mstr_cfg |= MXC_F_SPIM_MSTR_CFG_THREE_WIRE_MODE;

    // Disable SPI for General Control Configuration
    MAX4147X_SPI->gen_ctrl = 0;
    MAX4147X_SPI->gen_ctrl |= (MXC_F_SPIM_GEN_CTRL_TX_FIFO_EN | MXC_F_SPIM_GEN_CTRL_RX_FIFO_EN | MXC_F_SPIM_GEN_CTRL_ENABLE_SCK_FB_MODE | (1 << MXC_F_SPIM_GEN_CTRL_SIMPLE_MODE_POS)); // simple header

    MAX4147X_SPI->simple_headers &= 0x0000FFFF;
    MAX4147X_SPI->simple_headers |= 0x2016<<16;
    MAX4147X_SPI->gen_ctrl |=MXC_F_SPIM_GEN_CTRL_START_RX_ONLY;

    // Enable the SPI
    MAX4147X_SPI->gen_ctrl |= MXC_F_SPIM_GEN_CTRL_SPI_MSTR_EN;

    volatile mxc_spim_fifo_regs_t *fifo;

    fifo = MXC_SPIM_GET_SPIM_FIFO(MXC_SPIM_GET_IDX(MAX4147X_SPI));

    int avail = ((MAX4147X_SPI->fifo_ctrl & MXC_F_SPIM_FIFO_CTRL_RX_FIFO_USED) >> MXC_F_SPIM_FIFO_CTRL_RX_FIFO_USED_POS);

    Timer *t = NULL;
    t = new Timer();

    while(readed_byte_cnt < len)
    {
        t->start();

        while (avail < 1) {
            if (t->read_ms() > 1000) {
                rtn_val = -1;
                break;
            } else {
                avail = ((MAX4147X_SPI->fifo_ctrl & MXC_F_SPIM_FIFO_CTRL_RX_FIFO_USED) >> MXC_F_SPIM_FIFO_CTRL_RX_FIFO_USED_POS);
            }
        }

        t->stop();

        for (int i = 0; i < avail; i++) {
            *(value++) = fifo->rslts_8[i];
            readed_byte_cnt++;
        }

        while (MAX4147X_SPI->fifo_ctrl & MXC_F_SPIM_FIFO_CTRL_RX_FIFO_USED) {
            fifo->rslts_8[0];
        }
    }

    MAX4147X_SPI->gen_ctrl = 0;
    MAX4147X_SPI->gen_ctrl |= (MXC_F_SPIM_GEN_CTRL_TX_FIFO_EN | MXC_F_SPIM_GEN_CTRL_RX_FIFO_EN | MXC_F_SPIM_GEN_CTRL_ENABLE_SCK_FB_MODE | (0 << MXC_F_SPIM_GEN_CTRL_SIMPLE_MODE_POS)); // simple header

    MAX4147X_SPI->gen_ctrl |= MXC_F_SPIM_GEN_CTRL_SPI_MSTR_EN;

    if (ssel != NULL) {
        *ssel = 1;
    }

    t->~Timer();
    delete t;
#else
    if (value == NULL) {
        return -1;
    }

    if (this->reg_map == NULL) {
        return -2;
    }

    spi_handler->format(8,0);
    spi_handler->frequency(400000);

    if (ssel != NULL) {
        *ssel = 0;
    }
    spi_handler->write((uint8_t)0x80 | reg);

    spi_handler->write(0x00);     // dummy write command for waiting data read

    for (uint8_t i = 0; i < len; i++) {
        *(value++) = spi_handler->write(0x00);     // read back  data bytes
    }
    if (ssel != NULL) {
        *ssel = 1;
    }
#endif
    return rtn_val;
}

template <class REG>
int MAX4147X<REG>::read_register(uint8_t reg, uint8_t *value, uint8_t len)
{
    int rtn_val;

    if (value == NULL) {
        return -1;
    }

    if (this->reg_map == NULL) {
        return -2;
    }

    rtn_val = i2c_handler->write(MAX4147X_I2C_ADDRESS, (const char *)&reg, 1, true);
    if (rtn_val != 0) {
        return -3;
    }

    rtn_val = i2c_handler->read(MAX4147X_I2C_ADDRESS, (char *) value, len, false);
    if (rtn_val < 0) {
        return -4;
    }

    return 0;
}

template <>
int MAX4147X<max41470_reg_map_t>::write_register(uint8_t reg, const uint8_t *value, uint8_t len)
{
    int rtn_val = -1;
    uint8_t local_data[1 + len];

    if (value == NULL) {
        return -1;
    }

    memcpy(&local_data[0], value, len);

    if (ssel != NULL) {
        *ssel = 0;
    }

    rtn_val = spi_handler->write(0x7F & reg); // write mode and adress send
    for (int i = 0; i < len; i++) {
        rtn_val = spi_handler->write(local_data[i]); // write adress
    }

    if (ssel != NULL) {
        *ssel = 1;
    }

    if (rtn_val != 0) {
        return rtn_val;
    }

    return 0;
}

template <class REG>
int MAX4147X<REG>::write_register(uint8_t reg, const uint8_t *value, uint8_t len)
{
    int rtn_val;
    uint8_t local_data[1 + len];

    if (value == NULL) {
        return -1;
    }

    local_data[0] = reg;

    memcpy(&local_data[1], value, len);

    rtn_val = i2c_handler->write(MAX4147X_I2C_ADDRESS, (const char *)local_data, sizeof(local_data));
    if (rtn_val != 0) {
        return -1;
    }

    return 0;
}

#define SET_BIT_FIELD(address, reg_name, bit_field_name, value)                         \
            int ret;                                                                    \
            ret = read_register(address, (uint8_t *)&(reg_name), 1);                    \
            if (ret) {                                                                  \
                return ret;                                                             \
            }                                                                           \
            bit_field_name = value;                                                     \
            ret = write_register(address, (uint8_t *)&(reg_name), 1);                   \
            if (ret) {                                                                  \
                return ret;                                                             \
            }

template <class REG>
int MAX4147X<REG>::set_rssi_dt(rssi_dt_t rssi_dt)
{
    SET_BIT_FIELD(DEMOD_ADDR, this->reg_map->reg_demod, this->reg_map->reg_demod.bits.rssi_dt, rssi_dt);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_rssi_dt(rssi_dt_t* rssi_dt)
{
    int ret;

    ret = read_register(DEMOD_ADDR, (uint8_t *) & (this->reg_map->reg_demod), 1);
    if (ret < 0) {
        return ret;
    }

    *rssi_dt = (rssi_dt_t)this->reg_map->reg_demod.bits.rssi_dt;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_demod_fsk(demod_fsk_t demod_fsk)
{
    SET_BIT_FIELD(DEMOD_ADDR, this->reg_map->reg_demod, this->reg_map->reg_demod.bits.demod_fsk, demod_fsk);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_demod_fsk(demod_fsk_t* demod_fsk)
{
    int ret;

    ret = read_register(DEMOD_ADDR, (uint8_t *) & (this->reg_map->reg_demod), 1);
    if (ret < 0) {
        return ret;
    }

    *demod_fsk = (demod_fsk_t)this->reg_map->reg_demod.bits.demod_fsk;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_demod_tctrl(demod_tctrl_t demod_tctrl)
{
    SET_BIT_FIELD(DEMOD_ADDR, this->reg_map->reg_demod, this->reg_map->reg_demod.bits.demod_tctrl, demod_tctrl);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_demod_tctrl(demod_tctrl_t* demod_tctrl)
{
    int ret;

    ret = read_register(DEMOD_ADDR, (uint8_t *) & (this->reg_map->reg_demod), 1);
    if (ret < 0) {
        return ret;
    }

    *demod_tctrl = (demod_tctrl_t)this->reg_map->reg_demod.bits.demod_tctrl;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_agc_threl(uint8_t agc_threl)
{
    SET_BIT_FIELD(AGC_ADDR, this->reg_map->reg_agc, this->reg_map->reg_agc.bits.agc_threl, agc_threl);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_agc_threl(uint8_t* agc_threl)
{
    int ret;

    ret = read_register(AGC_ADDR, (uint8_t *) & (this->reg_map->reg_agc), 1);
    if (ret < 0) {
        return ret;
    }

    *agc_threl = (uint8_t)this->reg_map->reg_agc.bits.agc_threl;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_agc_en_bo(agc_en_bo_t agc_op_mode)
{
    SET_BIT_FIELD(AGC_ADDR, this->reg_map->reg_agc, this->reg_map->reg_agc.bits.agc_en_bo, agc_op_mode);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_agc_en_bo(agc_en_bo_t* agc_op_mode)
{
    int ret;

    ret = read_register(AGC_ADDR, (uint8_t *) & (this->reg_map->reg_agc), 1);
    if (ret < 0) {
        return ret;
    }

    *agc_op_mode = (agc_en_bo_t)this->reg_map->reg_agc.bits.agc_en_bo;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ask_fsk_sel(ask_fsk_sel_t ask_fsk_sel)
{
    SET_BIT_FIELD(IF_CHF_SEL_ADDR, this->reg_map->reg_if_chf_sel, this->reg_map->reg_if_chf_sel.bits.ask_fsk_sel, ask_fsk_sel);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ask_fsk_sel(ask_fsk_sel_t* ask_fsk_sel)
{
    int ret;

    ret = read_register(IF_CHF_SEL_ADDR, (uint8_t *) & (this->reg_map->reg_if_chf_sel), 1);
    if (ret < 0) {
        return ret;
    }

    *ask_fsk_sel = (ask_fsk_sel_t)this->reg_map->reg_if_chf_sel.bits.ask_fsk_sel;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_if_sel(if_sel_t if_sel)
{
    SET_BIT_FIELD(IF_CHF_SEL_ADDR, this->reg_map->reg_if_chf_sel, this->reg_map->reg_if_chf_sel.bits.if_sel, if_sel);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_if_sel(if_sel_t* if_sel)
{
    int ret;

    ret = read_register(IF_CHF_SEL_ADDR, (uint8_t *) & (this->reg_map->reg_if_chf_sel), 1);
    if (ret < 0) {
        return ret;
    }

    *if_sel = (if_sel_t)this->reg_map->reg_if_chf_sel.bits.if_sel;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_chf_sel(chf_sel_t chf_sel)
{
    SET_BIT_FIELD(IF_CHF_SEL_ADDR, this->reg_map->reg_if_chf_sel, this->reg_map->reg_if_chf_sel.bits.chf_sel, chf_sel);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_chf_sel(chf_sel_t* chf_sel)
{
    int ret;

    ret = read_register(IF_CHF_SEL_ADDR, (uint8_t *) & (this->reg_map->reg_if_chf_sel), 1);
    if (ret < 0) {
        return ret;
    }

    *chf_sel = (chf_sel_t)this->reg_map->reg_if_chf_sel.bits.chf_sel;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ld_buf(ld_buf_t ld_buf)
{
    SET_BIT_FIELD(PDF_CFG_ADDR, this->reg_map->reg_pdf_cfg, this->reg_map->reg_pdf_cfg.bits.ld_buf, ld_buf);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ld_buf(ld_buf_t* ld_buf)
{
    int ret;

    ret = read_register(PDF_CFG_ADDR, (uint8_t *) & (this->reg_map->reg_pdf_cfg), 1);
    if (ret < 0) {
        return ret;
    }

    *ld_buf = (ld_buf_t)this->reg_map->reg_pdf_cfg.bits.ld_buf;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ld_bw(ld_bw_t ld_bw)
{
    SET_BIT_FIELD(PDF_CFG_ADDR, this->reg_map->reg_pdf_cfg, this->reg_map->reg_pdf_cfg.bits.ld_bw, ld_bw);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ld_bw(ld_bw_t* ld_bw)
{
    int ret;

    ret = read_register(PDF_CFG_ADDR, (uint8_t *) & (this->reg_map->reg_pdf_cfg), 1);
    if (ret < 0) {
        return ret;
    }

    *ld_bw = (ld_bw_t)this->reg_map->reg_pdf_cfg.bits.ld_bw;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_src_lg(src_lg_t src_lg)
{
    SET_BIT_FIELD(PDF_CFG_ADDR, this->reg_map->reg_pdf_cfg, this->reg_map->reg_pdf_cfg.bits.src_lg, src_lg);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_src_lg(src_lg_t* src_lg)
{
    int ret;

    ret = read_register(PDF_CFG_ADDR, (uint8_t *) & (this->reg_map->reg_pdf_cfg), 1);
    if (ret < 0) {
        return ret;
    }

    *src_lg = (src_lg_t)this->reg_map->reg_pdf_cfg.bits.src_lg;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_src_sm(src_sm_t src_sm)
{
    SET_BIT_FIELD(PDF_CFG_ADDR, this->reg_map->reg_pdf_cfg, this->reg_map->reg_pdf_cfg.bits.src_sm, src_sm);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_src_sm(src_sm_t* src_sm)
{
    int ret;

    ret = read_register(PDF_CFG_ADDR, (uint8_t *) & (this->reg_map->reg_pdf_cfg), 1);
    if (ret < 0) {
        return ret;
    }

    *src_sm = (src_sm_t)this->reg_map->reg_pdf_cfg.bits.src_sm;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ath_lb(uint8_t ath_lb)
{
    SET_BIT_FIELD(ATH_CFG1_ADDR, this->reg_map->reg_ath_cfg1, this->reg_map->reg_ath_cfg1.bits.ath_lb, ath_lb);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ath_lb(uint8_t* ath_lb)
{
    int ret;

    ret = read_register(ATH_CFG1_ADDR, (uint8_t *) & (this->reg_map->reg_ath_cfg1), 1);
    if (ret < 0) {
        return ret;
    }

    *ath_lb = (uint8_t)this->reg_map->reg_ath_cfg1.bits.ath_lb;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ath_dt(ath_dt_t ath_dt)
{
    SET_BIT_FIELD(ATH_CFG2_ADDR, this->reg_map->reg_ath_cfg2, this->reg_map->reg_ath_cfg2.bits.ath_dt, ath_dt);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ath_dt(ath_dt_t* ath_dt)
{
    int ret;

    ret = read_register(ATH_CFG2_ADDR, (uint8_t *) & (this->reg_map->reg_ath_cfg2), 1);
    if (ret < 0) {
        return ret;
    }

    *ath_dt = (ath_dt_t)this->reg_map->reg_ath_cfg2.bits.ath_dt;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ath_tc(uint8_t ath_tc)
{
    SET_BIT_FIELD(ATH_CFG2_ADDR, this->reg_map->reg_ath_cfg2, this->reg_map->reg_ath_cfg2.bits.ath_tc, ath_tc);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ath_tc(uint8_t* ath_tc)
{
    int ret;

    ret = read_register(ATH_CFG2_ADDR, (uint8_t *) & (this->reg_map->reg_ath_cfg2), 1);
    if (ret < 0) {
        return ret;
    }

    *ath_tc = (uint8_t)this->reg_map->reg_ath_cfg2.bits.ath_tc;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ath_type(ath_type_t ath_type)
{
    SET_BIT_FIELD(ATH_CFG3_ADDR, this->reg_map->reg_ath_cfg3, this->reg_map->reg_ath_cfg3.bits.ath_type, ath_type);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ath_type(ath_type_t* ath_type)
{
    int ret;

    ret = read_register(ATH_CFG3_ADDR, (uint8_t *) & (this->reg_map->reg_ath_cfg3), 1);
    if (ret < 0) {
        return ret;
    }

    *ath_type = (ath_type_t)this->reg_map->reg_ath_cfg3.bits.ath_type;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ath_bw(ath_bw_t ath_bw)
{
    SET_BIT_FIELD(ATH_CFG3_ADDR, this->reg_map->reg_ath_cfg3, this->reg_map->reg_ath_cfg3.bits.ath_bw, ath_bw);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ath_bw(ath_bw_t* ath_bw)
{
    int ret;

    ret = read_register(ATH_CFG3_ADDR, (uint8_t *) & (this->reg_map->reg_ath_cfg3), 1);
    if (ret < 0) {
        return ret;
    }

    *ath_bw = (ath_bw_t)this->reg_map->reg_ath_cfg3.bits.ath_bw;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ath_gc(uint8_t ath_gc)
{
    SET_BIT_FIELD(ATH_CFG3_ADDR, this->reg_map->reg_ath_cfg3, this->reg_map->reg_ath_cfg3.bits.ath_gc, ath_gc);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ath_gc(uint8_t* ath_gc)
{
    int ret;

    ret = read_register(ATH_CFG3_ADDR, (uint8_t *) & (this->reg_map->reg_ath_cfg3), 1);
    if (ret < 0) {
        return ret;
    }

    *ath_gc = (uint8_t)this->reg_map->reg_ath_cfg3.bits.ath_gc;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_afc_mo(afc_mo_t afc_mo)
{
    SET_BIT_FIELD(AFC_CFG1_ADDR, this->reg_map->reg_afc_cfg1, this->reg_map->reg_afc_cfg1.bits.afc_mo, afc_mo);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_afc_mo(afc_mo_t* afc_mo)
{
    int ret;

    ret = read_register(AFC_CFG1_ADDR, (uint8_t *) & (this->reg_map->reg_afc_cfg1), 1);
    if (ret < 0) {
        return ret;
    }

    *afc_mo = (afc_mo_t)this->reg_map->reg_afc_cfg1.bits.afc_mo;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_afc_lg(afc_lg_t afc_lg)
{
    SET_BIT_FIELD(AFC_CFG1_ADDR, this->reg_map->reg_afc_cfg1, this->reg_map->reg_afc_cfg1.bits.afc_lg, afc_lg);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_afc_lg(afc_lg_t* afc_lg)
{
    int ret;

    ret = read_register(AFC_CFG1_ADDR, (uint8_t *) & (this->reg_map->reg_afc_cfg1), 1);
    if (ret < 0) {
        return ret;
    }

    *afc_lg = (afc_lg_t)this->reg_map->reg_afc_cfg1.bits.afc_lg;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_pad_freeze_afc(pad_freeze_afc_t pad_freeze_afc)
{
    SET_BIT_FIELD(AFC_CFG2_ADDR, this->reg_map->reg_afc_cfg2, this->reg_map->reg_afc_cfg2.bits.pad_freeze_afc, pad_freeze_afc);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_pad_freeze_afc(pad_freeze_afc_t* pad_freeze_afc)
{
    int ret;

    ret = read_register(AFC_CFG2_ADDR, (uint8_t *) & (this->reg_map->reg_afc_cfg2), 1);
    if (ret < 0) {
        return ret;
    }

    *pad_freeze_afc = (pad_freeze_afc_t)this->reg_map->reg_afc_cfg2.bits.pad_freeze_afc;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_lo_ctr_freq_upper(uint8_t lo_ctr_freq_upper)
{
    SET_BIT_FIELD(LO_CTR_FREQ3_ADDR, this->reg_map->reg_lo_ctr_freq3, this->reg_map->reg_lo_ctr_freq3.bits.lo_ctr_freq_23_to_16, lo_ctr_freq_upper);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_lo_ctr_freq_upper(uint8_t* lo_ctr_freq_upper)
{
    int ret;

    ret = read_register(LO_CTR_FREQ3_ADDR, (uint8_t *) & (this->reg_map->reg_lo_ctr_freq3), 1);
    if (ret < 0) {
        return ret;
    }

    *lo_ctr_freq_upper = (uint8_t)this->reg_map->reg_lo_ctr_freq3.bits.lo_ctr_freq_23_to_16;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_lo_ctr_freq_middle(uint8_t lo_ctr_freq_middle)
{
    SET_BIT_FIELD(LO_CTR_FREQ2_ADDR, this->reg_map->reg_lo_ctr_freq2, this->reg_map->reg_lo_ctr_freq2.bits.lo_ctr_freq_15_to_8, lo_ctr_freq_middle);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_lo_ctr_freq_middle(uint8_t* lo_ctr_freq_middle)
{
    int ret;

    ret = read_register(LO_CTR_FREQ2_ADDR, (uint8_t *) & (this->reg_map->reg_lo_ctr_freq2), 1);
    if (ret < 0) {
        return ret;
    }

    *lo_ctr_freq_middle = (uint8_t)this->reg_map->reg_lo_ctr_freq2.bits.lo_ctr_freq_15_to_8;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_lo_ctr_freq_lower(uint8_t lo_ctr_freq_lower)
{
    SET_BIT_FIELD(LO_CTR_FREQ1_ADDR, this->reg_map->reg_lo_ctr_freq1, this->reg_map->reg_lo_ctr_freq1.bits.lo_ctr_freq_7_to_0, lo_ctr_freq_lower);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_lo_ctr_freq_lower(uint8_t* lo_ctr_freq_lower)
{
    int ret;

    ret = read_register(LO_CTR_FREQ1_ADDR, (uint8_t *) & (this->reg_map->reg_lo_ctr_freq1), 1);
    if (ret < 0) {
        return ret;
    }

    *lo_ctr_freq_lower = (uint8_t)this->reg_map->reg_lo_ctr_freq1.bits.lo_ctr_freq_7_to_0;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_preamb_len(uint8_t preamb_len)
{
    SET_BIT_FIELD(PREAMBLE_CFG1_ADDR, this->reg_map->reg_preamble_cfg1, this->reg_map->reg_preamble_cfg1.bits.preamb_len, preamb_len);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_preamb_len(uint8_t* preamb_len)
{
    int ret;

    ret = read_register(PREAMBLE_CFG1_ADDR, (uint8_t *) & (this->reg_map->reg_preamble_cfg1), 1);
    if (ret < 0) {
        return ret;
    }

    *preamb_len = (uint8_t)this->reg_map->reg_preamble_cfg1.bits.preamb_len;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_preamb_word_lower(uint8_t preamb_word_lower)
{
    SET_BIT_FIELD(PREAMBLE_WORD1_ADDR, this->reg_map->reg_preamble_word1, this->reg_map->reg_preamble_word1.bits.preamb_word_7_to_0, preamb_word_lower);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_preamb_word_lower(uint8_t* preamb_word_lower)
{
    int ret;

    ret = read_register(PREAMBLE_WORD1_ADDR, (uint8_t *) & (this->reg_map->reg_preamble_word1), 1);
    if (ret < 0) {
        return ret;
    }

    *preamb_word_lower = (uint8_t)this->reg_map->reg_preamble_word1.bits.preamb_word_7_to_0;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_preamb_word_upper(uint8_t preamb_word_upper)
{
    SET_BIT_FIELD(PREAMBLE_WORD2_ADDR, this->reg_map->reg_preamble_word2, this->reg_map->reg_preamble_word2.bits.preamb_word_15_to_8, preamb_word_upper);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_preamb_word_upper(uint8_t* preamb_word_upper)
{
    int ret;

    ret = read_register(PREAMBLE_WORD2_ADDR, (uint8_t *) & (this->reg_map->reg_preamble_word2), 1);
    if (ret < 0) {
        return ret;
    }

    *preamb_word_upper = (uint8_t)this->reg_map->reg_preamble_word2.bits.preamb_word_15_to_8;

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_rssi(uint8_t* rssi)
{
    int ret;

    ret = read_register(RSSI_ADDR, (uint8_t *) & (this->reg_map->reg_rssi), 1);
    if (ret < 0) {
        return ret;
    }

    *rssi = (uint8_t)this->reg_map->reg_rssi.bits.rssi;

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_fei(uint8_t* fei)
{
    int ret;

    ret = read_register(FEI_ADDR, (uint8_t *) & (this->reg_map->reg_fei), 1);
    if (ret < 0) {
        return ret;
    }

    *fei = (uint8_t)this->reg_map->reg_fei.bits.fei;

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_pdf_out(uint8_t* pdf_out)
{
    int ret;

    ret = read_register(PDF_OUT_ADDR, (uint8_t *) & (this->reg_map->reg_pdf_out), 1);
    if (ret < 0) {
        return ret;
    }

    *pdf_out = (uint8_t)this->reg_map->reg_pdf_out.bits.pdf_out;

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_preamb_det(preamb_det_t *preamb_det)
{
    int ret;

    ret = read_register(ISR_ADDR, (uint8_t *) & (this->reg_map->reg_isr), 1);
    if (ret < 0) {
        return ret;
    }

    *preamb_det = (preamb_det_t)this->reg_map->reg_isr.bits.preamb_det;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_cdr_mode(cdr_mode_t cdr_mode)
{
    SET_BIT_FIELD(CDR_CFG1_ADDR, this->reg_map->reg_cdr_cfg1, this->reg_map->reg_cdr_cfg1.bits.cdr_mode, cdr_mode);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_cdr_mode(cdr_mode_t* cdr_mode)
{
    int ret;

    ret = read_register(CDR_CFG1_ADDR, (uint8_t *) & (this->reg_map->reg_cdr_cfg1), 1);
    if (ret < 0) {
        return ret;
    }

    *cdr_mode = (cdr_mode_t)this->reg_map->reg_cdr_cfg1.bits.cdr_mode;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_en_xo(en_xo_t en_xo)
{
    SET_BIT_FIELD(STATE_CTRL1_ADDR, this->reg_map->reg_state_ctrl1, this->reg_map->reg_state_ctrl1.bits.en_xo, en_xo);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_en_xo(en_xo_t* en_xo)
{
    int ret;

    ret = read_register(STATE_CTRL1_ADDR, (uint8_t *) & (this->reg_map->reg_state_ctrl1), 1);
    if (ret < 0) {
        return ret;
    }

    *en_xo = (en_xo_t)this->reg_map->reg_state_ctrl1.bits.en_xo;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_wut_en(wut_en_t wut_en)
{
    SET_BIT_FIELD(STATE_CTRL1_ADDR, this->reg_map->reg_state_ctrl1, this->reg_map->reg_state_ctrl1.bits.wut_en, wut_en);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_wut_en(wut_en_t* wut_en)
{
    int ret;

    ret = read_register(STATE_CTRL1_ADDR, (uint8_t *) & (this->reg_map->reg_state_ctrl1), 1);
    if (ret < 0) {
        return ret;
    }

    *wut_en = (wut_en_t)this->reg_map->reg_state_ctrl1.bits.wut_en;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_slave_rx_en(slave_rx_en_t slave_rx_en)
{
    SET_BIT_FIELD(STATE_CTRL1_ADDR, this->reg_map->reg_state_ctrl1, this->reg_map->reg_state_ctrl1.bits.slave_rx_en, slave_rx_en);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_slave_rx_en(slave_rx_en_t* slave_rx_en)
{
    int ret;

    ret = read_register(STATE_CTRL1_ADDR, (uint8_t *) & (this->reg_map->reg_state_ctrl1), 1);
    if (ret < 0) {
        return ret;
    }

    *slave_rx_en = (slave_rx_en_t)this->reg_map->reg_state_ctrl1.bits.slave_rx_en;

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_rx_state(rx_state_t* rx_state)
{
    int ret;

    ret = read_register(STATE_CTRL2_ADDR, (uint8_t *) & (this->reg_map->reg_state_ctrl2), 1);
    if (ret < 0) {
        return ret;
    }

    *rx_state = (rx_state_t)this->reg_map->reg_state_ctrl2.bits.rx_state;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_rx_reset_time(rx_reset_time_t rx_reset_time)
{
    SET_BIT_FIELD(STATE_CTRL3_ADDR, this->reg_map->reg_state_ctrl3, this->reg_map->reg_state_ctrl3.bits.rx_reset_time, rx_reset_time);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_rx_reset_time(rx_reset_time_t* rx_reset_time)
{
    int ret;

    ret = read_register(STATE_CTRL3_ADDR, (uint8_t *) & (this->reg_map->reg_state_ctrl3), 1);
    if (ret < 0) {
        return ret;
    }

    *rx_reset_time = (rx_reset_time_t)this->reg_map->reg_state_ctrl3.bits.rx_reset_time;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_tdet(uint8_t tdet)
{
    SET_BIT_FIELD(WUT1_ADDR, this->reg_map->reg_wut1, this->reg_map->reg_wut1.bits.tdet, tdet);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_tdet(uint8_t* tdet)
{
    int ret;

    ret = read_register(WUT1_ADDR, (uint8_t *) & (this->reg_map->reg_wut1), 1);
    if (ret < 0) {
        return ret;
    }

    *tdet = (uint8_t)this->reg_map->reg_wut1.bits.tdet;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_tsby_tdet_ratio(uint8_t tsby_tdet_ratio)
{
    SET_BIT_FIELD(WUT2_ADDR, this->reg_map->reg_wut2, this->reg_map->reg_wut2.bits.tsby_tdet_ratio, tsby_tdet_ratio);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_tsby_tdet_ratio(uint8_t* tsby_tdet_ratio)
{
    int ret;

    ret = read_register(WUT2_ADDR, (uint8_t *) & (this->reg_map->reg_wut2), 1);
    if (ret < 0) {
        return ret;
    }

    *tsby_tdet_ratio = (uint8_t)this->reg_map->reg_wut2.bits.tsby_tdet_ratio;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_xoclkdelay(xoclkdelay_t xoclkdelay)
{
    SET_BIT_FIELD(AFE_CTL1_ADDR, this->reg_map->reg_afe_ctl1, this->reg_map->reg_afe_ctl1.bits.xoclkdelay, xoclkdelay);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_xoclkdelay(xoclkdelay_t* xoclkdelay)
{
    int ret;

    ret = read_register(AFE_CTL1_ADDR, (uint8_t *) & (this->reg_map->reg_afe_ctl1), 1);
    if (ret < 0) {
        return ret;
    }

    *xoclkdelay = (xoclkdelay_t)this->reg_map->reg_afe_ctl1.bits.xoclkdelay;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_xoclkdiv(xoclkdiv_t xoclkdiv)
{
    SET_BIT_FIELD(AFE_CTL1_ADDR, this->reg_map->reg_afe_ctl1, this->reg_map->reg_afe_ctl1.bits.xoclkdiv, xoclkdiv);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_xoclkdiv(xoclkdiv_t* xoclkdiv)
{
    int ret;

    ret = read_register(AFE_CTL1_ADDR, (uint8_t *) & (this->reg_map->reg_afe_ctl1), 1);
    if (ret < 0) {
        return ret;
    }

    *xoclkdiv = (xoclkdiv_t)this->reg_map->reg_afe_ctl1.bits.xoclkdiv;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_mix_hs_lsbar(mix_hs_lsbar_t mix_hs_lsbar)
{
    SET_BIT_FIELD(AFE_CTL1_ADDR, this->reg_map->reg_afe_ctl1, this->reg_map->reg_afe_ctl1.bits.mix_hs_lsbar, mix_hs_lsbar);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_mix_hs_lsbar(mix_hs_lsbar_t* mix_hs_lsbar)
{
    int ret;

    ret = read_register(AFE_CTL1_ADDR, (uint8_t *) & (this->reg_map->reg_afe_ctl1), 1);
    if (ret < 0) {
        return ret;
    }

    *mix_hs_lsbar = (mix_hs_lsbar_t)this->reg_map->reg_afe_ctl1.bits.mix_hs_lsbar;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_lodiv(lodiv_t lodiv)
{
    SET_BIT_FIELD(AFE_CTL1_ADDR, this->reg_map->reg_afe_ctl1, this->reg_map->reg_afe_ctl1.bits.lodiv, lodiv);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_lodiv(lodiv_t* lodiv)
{
    int ret;

    ret = read_register(AFE_CTL1_ADDR, (uint8_t *) & (this->reg_map->reg_afe_ctl1), 1);
    if (ret < 0) {
        return ret;
    }

    *lodiv = (lodiv_t)this->reg_map->reg_afe_ctl1.bits.lodiv;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_fracmode(fracmode_t fracmode)
{
    SET_BIT_FIELD(AFE_CTL1_ADDR, this->reg_map->reg_afe_ctl1, this->reg_map->reg_afe_ctl1.bits.fracmode, fracmode);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_fracmode(fracmode_t* fracmode)
{
    int ret;

    ret = read_register(AFE_CTL1_ADDR, (uint8_t *) & (this->reg_map->reg_afe_ctl1), 1);
    if (ret < 0) {
        return ret;
    }

    *fracmode = (fracmode_t)this->reg_map->reg_afe_ctl1.bits.fracmode;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_ir_adjust(uint8_t ir_adjust)
{
    SET_BIT_FIELD(IR_ADJUST_ADDR, this->reg_map->reg_ir_adjust, this->reg_map->reg_ir_adjust.bits.ir_adjust, ir_adjust);

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_ir_adjust(uint8_t* ir_adjust)
{
    int ret;

    ret = read_register(IR_ADJUST_ADDR, (uint8_t *) & (this->reg_map->reg_ir_adjust), 1);
    if (ret < 0) {
        return ret;
    }

    *ir_adjust = (uint8_t)this->reg_map->reg_ir_adjust.bits.ir_adjust;

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_part_num(part_num_t* part_num)
{
    int ret;

    ret = read_register(PART_NUM_ADDR, (uint8_t *) & (this->reg_map->reg_part_num), 1);
    if (ret < 0) {
        return ret;
    }

    *part_num = (part_num_t)this->reg_map->reg_part_num.bits.part_num;

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_rev_num(uint8_t* rev_num)
{
    int ret;

    ret = read_register(REV_NUM_ADDR, (uint8_t *) & (this->reg_map->reg_rev_num), 1);
    if (ret < 0) {
        return ret;
    }

    *rev_num = (uint8_t)this->reg_map->reg_rev_num.bits.rev_num;

    return 0;
}

template <class REG>
int MAX4147X<REG>::get_pll_lock(pll_lock_t* pll_lock)
{
    int ret;

    ret = read_register(STATUS_ADDR, (uint8_t *) & (this->reg_map->reg_status), 1);
    if (ret < 0) {
        return ret;
    }

    *pll_lock = (pll_lock_t)this->reg_map->reg_status.bits.pll_lock;

    return 0;
}

template <class REG>
int MAX4147X<REG>::set_crystal_frequency(float freq)
{

    if( ((int)freq == 12))
        this->crystal_frequency = 12.8;
    else if((int)freq == 16)
        this->crystal_frequency = 16.0;
    else if((int)freq == 19)
        this->crystal_frequency = 19.2;
    else
        return -1;

    if(this->adjust_crystal_divider() < 0)
        return -2;
    if(this->set_center_frequency(this->center_frequency) < 0)
        return -3;

    return 0;
}

template <class REG>
float MAX4147X<REG>::get_crystal_frequency()
{
    return this->crystal_frequency;
}

template <class REG>
int MAX4147X<REG>::adjust_baud_rate(float baud_rate)
{
    int return_val = 0;
    uint8_t rate_index, src_lg_conf_idx, src_sm_conf_idx;
    float nearestValue = 400, minDiff = 400;
    float bit_rate_min, bit_rate_max, bit_rate, pre_rate, conf_rate, recommended_bit_rate, dif0, dif1;

    if_sel_t *if_sel = (if_sel_t *)malloc(sizeof(if_sel_t));
    if(if_sel == NULL)
        return -99;

    chf_sel_t *chf_sel = (chf_sel_t *)malloc(sizeof(chf_sel_t));
    if(chf_sel == NULL){
        free(if_sel);
        return -98;
    }

    src_lg_t *src_lg = (src_lg_t *)malloc(sizeof(src_lg_t));
    if(src_lg == NULL){
        free(if_sel); free(chf_sel);
        return -97;
    }

    src_sm_t *src_sm = (src_sm_t *)malloc(sizeof(src_sm_t));
    if(src_sm == NULL){
        free(if_sel); free(chf_sel); free(src_lg);
        return -96;
    }

    if(encoding == Manchester){
        bit_rate = baud_rate * 2;
        recommended_bit_rate = this->baud_rate * 2;
    }else{
        bit_rate = baud_rate;
        recommended_bit_rate = this->baud_rate;
    }

    if (bit_rate > 200.0 || bit_rate < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(this->get_if_sel(if_sel) < 0){
        return_val = -2;
        goto free_and_return;
    }
    if(this->get_chf_sel(chf_sel) < 0){
        return_val = -3;
        goto free_and_return;
    }
    if(this->get_src_lg(src_lg) < 0){
        return_val = -4;
        goto free_and_return;
    }
    if(this->get_src_sm(src_sm) < 0){
        return_val = -5;
        goto free_and_return;
    }

    rate_index = (*if_sel) * 5 + (*chf_sel);

    bit_rate_min = bit_rate_min_max[rate_index][0];
    bit_rate_max = bit_rate_min_max[rate_index][1];

    if(bit_rate < bit_rate_min || bit_rate > bit_rate_max){
        return_val = -6;
        goto free_and_return;
    }

    pre_rate = 1600.0 / (pow(2, (*if_sel + *chf_sel)));

    for (src_sm_conf_idx = 0; src_sm_conf_idx < 8; src_sm_conf_idx++)
    {
        for (src_lg_conf_idx = 0; src_lg_conf_idx < 8; src_lg_conf_idx++)
        {
            conf_rate = (pre_rate / ((8 + src_sm_conf_idx) * pow(2, src_lg_conf_idx)));
            dif0 = fabs(bit_rate - conf_rate);
            dif1 = fabs(bit_rate - floor(conf_rate));

            if (dif1 <= nearestValue && dif0 < minDiff && (0.6 * conf_rate) < bit_rate && bit_rate < (1.03 * conf_rate))
            {
                nearestValue = dif1;
                minDiff = dif0;
                *src_sm = (src_sm_t)src_sm_conf_idx;
                *src_lg = (src_lg_t)src_lg_conf_idx;

                this->baud_rate_ratio = bit_rate / conf_rate;
                recommended_bit_rate = conf_rate;
            }
        }
    }

    this->set_src_lg(*src_lg);
    this->set_src_sm(*src_sm);

    if(encoding == Manchester)
        this->baud_rate = recommended_bit_rate/2;
    else
        this->baud_rate = recommended_bit_rate;

    if(this->update_ath_tc() < 0){
        return_val = -7;
        goto free_and_return;
    }
    if(this->update_ath_dt() < 0){
        return_val = -8;
        goto free_and_return;
    }
    if(this->update_ath_bw() < 0){
        return_val = -9;
        goto free_and_return;
    }
    if(this->update_agc_threl() < 0){
        return_val = -10;
        goto free_and_return;
    }
    if(this->update_demod_tctrl() < 0){
        return_val = -11;
        goto free_and_return;
    }
    if(this->update_ath_lb() < 0){
        return_val = -12;
        goto free_and_return;
    }

    free_and_return:
    free(if_sel);
    free(chf_sel);
    free(src_lg);
    free(src_sm);
    return return_val;
}

template <class REG>
float MAX4147X<REG>::get_baud_rate()
{
    return this->baud_rate;
}

template <class REG>
int MAX4147X<REG>::set_center_frequency(float freq)
{
    int return_val = 0, lo_ctr_freq_reg_val;
    float f_if, crystal_frequency;

    mix_hs_lsbar_t *mix_hs_lsbar = (mix_hs_lsbar_t *)malloc(sizeof(mix_hs_lsbar_t));
    if(mix_hs_lsbar == NULL)
        return -99;

    if_sel_t *if_sel = (if_sel_t *)malloc(sizeof(if_sel_t));
    if(if_sel == NULL){
        free(mix_hs_lsbar);
        return -98;
    }

    if(freq < 290 || freq > 960){
        return_val = -1;
        goto free_and_return;
    }

    if(freq >= 286.0 && freq<= 320.0)
        this->set_lodiv(LODIV_286MHZ_TO_320MHZ);
    else if(freq >= 425.0 && freq<= 480.0)
        this->set_lodiv(LODIV_425MHZ_TO_480MHZ);
    else if(freq >= 860.0 && freq<= 960.0)
        this->set_lodiv(LODIV_860MHZ_TO_960MHZ);
    else{
        return_val = -2;
        goto free_and_return;
    }

    if(this->get_mix_hs_lsbar(mix_hs_lsbar) < 0){
        return_val = -3;
        goto free_and_return;
    }

    if(this->get_if_sel(if_sel) < 0){
        return_val = -4;
        goto free_and_return;
    }

    crystal_frequency = this->get_crystal_frequency();

    if(*if_sel == (IF_SEL_400_KHZ))
        f_if = 0.4; //400kHz
    else
        f_if = 0.2; //200kHz

    if(*mix_hs_lsbar == (MIX_HS_LSBAR_TARGET_HT_LO_FREQ))
        lo_ctr_freq_reg_val = uint32_t( (65536*(freq - f_if)) / crystal_frequency);
    else
        lo_ctr_freq_reg_val = uint32_t( (65536*(freq + f_if)) / crystal_frequency);

    this->set_lo_ctr_freq_upper(uint8_t(lo_ctr_freq_reg_val>>16));
    this->set_lo_ctr_freq_middle(uint8_t(lo_ctr_freq_reg_val>>8));
    this->set_lo_ctr_freq_lower(uint8_t(lo_ctr_freq_reg_val));

    this->center_frequency = freq;

    free_and_return:
    free(mix_hs_lsbar);
    free(if_sel);
    return return_val;
}

template <class REG>
float MAX4147X<REG>::get_center_frequency()
{
    return this->center_frequency;
}

template <class REG>
int MAX4147X<REG>::set_power_on_off(uint8_t power) {
    if (power > 0) {  // Shut down the device

        *this->power_pin = power;

    } else { // Turn on the device

        *this->power_pin = 0;
        wait_us(1500);
        *this->power_pin = 1;
        wait_us(1500);
        *this->power_pin = 0;
    }

    return 0;
}

template <class REG>
int MAX4147X<REG>::initial_programming(void)
{
    uint8_t address;

    this->set_power_on_off(0);

    this->set_en_xo(EN_XO_EN_XO);
    wait_us(500);

    if(this->write_register(0, default_register_value_0, (Q_CONF_LEN-1)) < 0)
        return -1;
    if(this->write_register(0x19, &default_register_value_0[Q_CONF_LEN-1], 1) <0 )
        return -2;

    wait_us(500);

    address = 0x05;
    if(this->write_register(0x14, &address, 1) < 0)     //This will turn on the receiver and place the device into the SlaveRX state.
        return -3;

    return 0;
}

template <class REG>
int MAX4147X<REG>::adjust_crystal_divider(void)
{
    if( (int)this->crystal_frequency == 12)
        return set_xoclkdiv(XOCLKDIV_DIVIDE_BY_4);
    else if((int)this->crystal_frequency == 16)
        return set_xoclkdiv(XOCLKDIV_DIVIDE_BY_5);
    else if((int)this->crystal_frequency == 19)
        return set_xoclkdiv(XOCLKDIV_DIVIDE_BY_6);
    else
        return -1;
}

template <>
int MAX4147X<max41470_reg_map_t>::read_data(uint8_t *data, uint32_t length)
{
    preamb_det_t *preamb_det = (preamb_det_t *)malloc(sizeof(preamb_det_t));

    if(preamb_det == NULL){
        return -99;
    }

    if (this->preset_mode == 0) {
        if(this->get_preamb_det(preamb_det) < 0){       //ISR Register is Read. PREAMB_DET bit and WUT_EN bit automatically cleared. MAX41470 placed into the Standby State.
            free(preamb_det);
            return -1;
        }

        if(*preamb_det != PREAMB_DET_PREAMB_DETECTED){  //Interrupt Status Register is not Set!
            free(preamb_det);
            return -2;
        }

        this->set_slave_rx_en(SLAVE_RX_EN_EN_RECEIVER); //MAX41470 moved from Standby to the SlaveRX state. DATA pin will be stream
    }

    free(preamb_det);
    return this->io_read(data, length);
}

template <class REG>
int MAX4147X<REG>::read_data(uint8_t *data, uint32_t length)
{
    if (this->preset_mode == 0) {
        if (length > 32767) {
            return -100;
        }


    } else {
        this->io_read(data, length);
    }

    return 0;
}


template <class REG>
int MAX4147X<REG>::io_read(uint8_t *data, uint32_t length)
{
    uint32_t byte_idx, bit_idx, bit_val, bit_cnt = 0;
    uint32_t signal_period_us, read_period_us, time;
    float baud_rate;
    Timer *t = NULL;

    t = new Timer();
    t->start();

    baud_rate = this->get_baud_rate();
    signal_period_us = 1000000 / baud_rate;
    read_period_us = signal_period_us/2;

    core_util_critical_section_enter();
    t->reset();
    for(byte_idx=0; byte_idx<length; byte_idx++)
    {
        data[byte_idx] = 0;
        for(bit_idx=0; bit_idx<8; bit_idx++)
        {
            while(1)
            {
                time = t->read_us();
                if(byte_idx == 0 && bit_idx == 0)
                {
                    if(time >= read_period_us/2)
                    {
                        bit_val = uint8_t(data_read->read());
                        data[byte_idx] |= bit_val<<bit_idx;
                        bit_cnt++;
                        t->reset();
                        break;
                    }
                    continue;
                }

                if(time >= (read_period_us * bit_cnt))
                {
                    bit_val = uint8_t(data_read->read());
                    data[byte_idx] |= bit_val<<bit_idx;
                    bit_cnt++;
                    break;
                }
            }
        }
    }
    core_util_critical_section_exit();

    t->~Timer();
    delete t;
    return 0;
}

template <class REG>
int MAX4147X<REG>::adjust_encoding_type(encoding_t encoding_type)
{
    int return_val = 0;

    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        return -99;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto free_and_return;
    }

    encoding = encoding_type;

    if(this->update_ath_type() < 0){
        return_val = -3;
        goto free_and_return;
    }
    if(this->update_ath_bw() < 0){
        return_val = -4;
        goto free_and_return;
    }
    if(this->update_ath_dt() < 0){
        return_val = -5;
        goto free_and_return;
    }
    if(this->update_ath_lb() < 0){
        return_val = -6;
        goto free_and_return;
    }

    free_and_return:
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::get_encoding_type()
{
    return int(encoding);
}

template <class REG>
int MAX4147X<REG>::adjust_demodulation(ask_fsk_sel_t demodulation_type)
{
    int return_val = 0;
    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));

    if(rx_state == NULL){
        return -99;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto free_and_return;
    }

    this->set_ask_fsk_sel(demodulation_type);

    if(this->update_demod_tctrl() < 0){
        return_val = -3;
        goto free_and_return;
    }
    if(this->update_afc_lg() < 0){
        return_val = -4;
        goto free_and_return;
    }
    if(this->update_agc_threl() < 0){
        return_val = -5;
        goto free_and_return;
    }

    /*Update ASK Bit Fields*/
    if(this->update_ath_lb() < 0){
        return_val = -6;
        goto free_and_return;
    }
    if(this->update_afc_mo() < 0){
        return_val = -7;
        goto free_and_return;
    }
    if(this->update_ath_gc() < 0){
        return_val = -8;
        goto free_and_return;
    }
    if(this->update_ath_dt() < 0){
        return_val = -9;
        goto free_and_return;
    }
    if(this->update_ath_bw() < 0){
        return_val = -10;
        goto free_and_return;
    }
    if(this->update_ath_type() < 0){
        return_val = -11;
        goto free_and_return;
    }
    /*End of Update ASK Bit Fields*/

    free_and_return:
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_ath_lb(void)
{
    int return_val = 0;
    float src_ratio = 0;
    uint8_t src_r0 = 0, src_r1= 0, foo = 0;
    uint32_t mu_1= 0, mu_2 = 0;
    char data = 0;

    chf_sel_t *chf_sel = (chf_sel_t *)malloc(sizeof(chf_sel_t));
    if(chf_sel == NULL)
        return -99;

    if_sel_t *if_sel = (if_sel_t *)malloc(sizeof(if_sel_t));
    if(if_sel == NULL){
        free(chf_sel);
        return -98;
    }

    src_lg_t *src_lg = (src_lg_t *)malloc(sizeof(src_lg_t));
    if(src_lg == NULL){
        free(chf_sel); free(if_sel);
        return -97;
    }

    src_sm_t *src_sm = (src_sm_t *)malloc(sizeof(src_sm_t));
    if(src_sm == NULL){
        free(chf_sel); free(if_sel); free(src_lg);
        return -96;
    }

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL){
        free(chf_sel); free(if_sel); free(src_lg); free(src_sm);
        return -95;
    }

    rx_state_t *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(chf_sel); free(if_sel); free(src_lg); free(src_sm); free(ask_fsk_sel);
        return -94;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto free_and_return;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto free_and_return;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(this->set_ath_lb(0) < 0)
            return_val = -4;
        goto free_and_return;
    }

    if(this->get_if_sel(if_sel) < 0){
        return_val = -5;
        goto free_and_return;
    }
    if(this->get_chf_sel(chf_sel) < 0){
        return_val = -6;
        goto free_and_return;
    }
    if(this->get_src_sm(src_sm) < 0){
        return_val = -7;
        goto free_and_return;
    }
    if(this->get_src_lg(src_lg) < 0){
        return_val = -8;
        goto free_and_return;
    }

    src_ratio = *src_lg + log2(*src_sm + 8) - 3;

    if(src_ratio < 1.0){
        src_r0 = 29; src_r1 = 21;
    }
    else if (src_ratio < 2){
        src_r0 = 21; src_r1 = 15;
    }
    else if (src_ratio < 3){
        src_r0 = 15; src_r1 = 11;
    }
    else if (src_ratio < 4){
        src_r0 = 11; src_r1 = 8;
    }
    else if (src_ratio < 5){
        src_r0 = 8; src_r1 = 6;
    }
    else if (src_ratio < 6){
        src_r0 = 6; src_r1 = 4;
    }
    else if (src_ratio < 7){
        src_r0 = 4; src_r1 = 3;
    }
    else if (src_ratio < 8){
        src_r0 = 3; src_r1 = 2;
    }
    else {
        src_r0 = 2; src_r1 = 2;
    }

    mu_1 = mu1_conf[(*if_sel) * 5 + *chf_sel];
    mu_2 = (int)round(src_r0 - ((src_r0 - src_r1) * (src_ratio - floor(src_ratio))));

    data = (char)(mu_1 + mu_2 - 6);
    foo = (uint8_t)(data + 256);

    if(this->set_ath_lb(foo) < 0)
        return_val = -9;


    free_and_return:
    free(chf_sel);
    free(if_sel);
    free(src_lg);
    free(src_sm);
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_ath_type(void)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto free_and_return;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto free_and_return;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(this->set_ath_type(ATH_TYPE_PRELPF_MANCHESTER) < 0){
            return_val = -4;
            goto free_and_return;
        }
    }
    else{
        if(encoding == Manchester){
            if(this->set_ath_type(ATH_TYPE_PRELPF_MANCHESTER) < 0){
                return_val = -5;
                goto free_and_return;
            }
        }else{
            if(this->set_ath_type(ATH_TYPE_APD_NRZ) < 0){
                return_val = -6;
                goto free_and_return;
            }
        }
    }

    if(this->update_demod_tctrl() < 0)
        return_val = -7;

    free_and_return:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_ath_bw(void)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto free_and_return;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto free_and_return;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(this->set_ath_bw(ATH_BW_DEFAULT) < 0)
            return_val = -4;
        goto free_and_return;
    }

    if(encoding == Manchester){
        if(baud_rate_ratio < 0.6){
            if(this->set_ath_bw(ATH_BW_DEFAULT_X2) < 0)
                return_val = -5;
        }else{
            if(this->set_ath_bw(ATH_BW_DEFAULT) < 0)
                return_val = -6;
        }
    }else{
        if(this->set_ath_bw(ATH_BW_DEFAULT) < 0)
            return_val = -7;
    }

    free_and_return:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_ath_dt(void)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto free_and_return;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto free_and_return;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(this->set_ath_dt(ATH_DT_DEFAULT_DISCHARGE_TIME) < 0)
            return_val = -4;
        goto free_and_return;
    }

    if(encoding == Manchester){
        if(baud_rate_ratio < 0.6){
            if(this->set_ath_dt(ATH_DT_DISCHARGE_TIME_X2) < 0)
                return_val = -5;
        }else{
            if(this->set_ath_dt(ATH_DT_DEFAULT_DISCHARGE_TIME) < 0)
                return_val = -6;
        }
    }else{
        if(this->set_ath_dt(ATH_DT_DISCHARGE_TIME_X8) < 0)
            return_val = -7;
    }

    free_and_return:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_ath_tc(void)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    src_lg_t *src_lg = (src_lg_t *)malloc(sizeof(src_lg_t));
    if(src_lg == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel); free(src_lg);
        return -97;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto free_and_return;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto free_and_return;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(this->set_ath_tc(0) < 0)
            return_val = -4;
        goto free_and_return;
    }

    if(this->get_src_lg(src_lg) < 0){
        return_val = -5;
        goto free_and_return;
    }

    if(*src_lg > 7){
        return_val = -6;
        goto free_and_return;
    }

    if(this->set_ath_tc(ath_tc_conf[*src_lg]) < 0){
        return_val = -7;
        goto free_and_return;
    }

    free_and_return:
    free(ask_fsk_sel);
    free(src_lg);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_ath_gc(void)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    chf_sel_t *chf_sel = (chf_sel_t *)malloc(sizeof(chf_sel_t));
    if(chf_sel == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if_sel_t *if_sel = (if_sel_t *)malloc(sizeof(if_sel_t));
    if(if_sel == NULL){
        free(ask_fsk_sel); free(chf_sel);
        return -97;
    }

    rx_state_t *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel); free(chf_sel); free(if_sel);
        return -96;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto free_and_return;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto free_and_return;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto free_and_return;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(this->set_ath_gc(0) < 0)
            return_val = -4;
        goto free_and_return;
    }

    if(this->get_if_sel(if_sel) < 0){
        return_val = -5;
        goto free_and_return;
    }

    if(this->get_chf_sel(chf_sel) < 0){
        return_val = -6;
        goto free_and_return;
    }

    if(this->set_ath_gc(ath_gc_conf[(*if_sel) * 5 + *chf_sel]) < 0){
        return_val = -7;
        goto free_and_return;
    }

    free_and_return:
    free(ask_fsk_sel);
    free(chf_sel);
    free(if_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_afc_mo(void)
{
    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));

    if(rx_state == NULL){
        return -99;
    }

    if(this->get_rx_state(rx_state) < 0){
        free(rx_state);
        return -1;
    }

    if(*rx_state != RX_STATE_STANDBY){
        free(rx_state);
        return -2;
    }

    free(rx_state);

    return (this->set_afc_mo(AFC_MO_CONF_7) < 0) ? -3 : 0;
}

template <class REG>
int MAX4147X<REG>::update_afc_lg(void)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto error;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto error;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel)){
        return_val = -3;
        goto error;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(this->set_afc_lg(AFC_LG_CONF_DEFAULT) < 0){
            return_val = -4;
            goto error;
        }
    }else{
        if(this->set_afc_lg(AFC_LG_CONF_DEFAULT_X2) < 0){
            return_val = -5;
            goto error;
        }
    }

    error:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_agc_threl(void)
{
    int return_val = 0;
    float bit_rate;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t  *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto error;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto error;
    }

    if(encoding == Manchester)
        bit_rate = this->baud_rate * 2;
    else
        bit_rate = this->baud_rate;

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto error;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(bit_rate > 51.5){
            if(this->set_agc_threl(0x0F) < 0){
                return_val = -4;
                goto error;
            }
        }else{
            if(this->set_agc_threl(0x09) < 0){
                return_val = -5;
                goto error;
            }
        }
    }
    else{
        if(bit_rate > 26){
            if(this->set_agc_threl(0x0F) < 0){
                return_val = -6;
                goto error;
            }
        }else{
            if(this->set_agc_threl(0x09) < 0){
                return_val = -7;
                goto error;
            }
        }
    }

    error:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::update_demod_tctrl(void)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    src_lg_t *src_lg = (src_lg_t *)malloc(sizeof(src_lg_t));
    if(src_lg == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    chf_sel_t *chf_sel = (chf_sel_t *)malloc(sizeof(chf_sel_t));
    if(chf_sel == NULL){
        free(ask_fsk_sel); free(src_lg);
        return -97;
    }

    ath_type_t *ath_type = (ath_type_t *)malloc(sizeof(ath_type_t));
    if(ath_type == NULL){
        free(ask_fsk_sel); free(src_lg); free(chf_sel);
        return -96;
    }

    rx_state_t *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel); free(src_lg); free(chf_sel); free(ath_type);
        return -95;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto error;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto error;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto error;
    }

    if(*ask_fsk_sel == ASK_FSK_SEL_FSK){
        if(this->get_chf_sel(chf_sel) < 0){
            return_val = -4;
            goto error;
        }
        set_demod_tctrl(demod_tctrl_t(4 - *chf_sel));
    }
    else{
        if(this->get_ath_type(ath_type) < 0){
            return_val = -5;
            goto error;
        }
        if(this->get_src_lg(src_lg) < 0){
            return_val = -6;
            goto error;
        }
        if(*ath_type == ATH_TYPE_PRELPF_MANCHESTER){
            if(2 + *src_lg < 7)
                set_demod_tctrl(demod_tctrl_t(2 + *src_lg));
            else
                set_demod_tctrl(demod_tctrl_t(7));
        }
        else{
            if(3 + *src_lg < 7)
                set_demod_tctrl(demod_tctrl_t(3 + *src_lg));
            else
                set_demod_tctrl(demod_tctrl_t(7));
        }
    }

    error:
    free(ask_fsk_sel);
    free(src_lg);
    free(chf_sel);
    free(ath_type);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::adjust_receiver_bandwidth(int receiver_bw)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto error;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto error;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto error;
    }

    if(*ask_fsk_sel != ASK_FSK_SEL_ASK){
        return_val = -4;
        goto error;
    }

    if(receiver_bw == 340 || receiver_bw == 170)
        set_chf_sel(CHF_SEL_RXBW_340_170_KHZ);
    else if(receiver_bw == 120 || receiver_bw == 60)
        set_chf_sel(CHF_SEL_RXBW_120_60_KHZ);
    else if(receiver_bw == 52 || receiver_bw == 26)
        set_chf_sel(CHF_SEL_RXBW_52_26_KHZ);
    else if(receiver_bw == 24 || receiver_bw == 12)
            set_chf_sel(CHF_SEL_RXBW_24_12_KHZ);
    else if(receiver_bw == 12 || receiver_bw == 6)
            set_chf_sel(CHF_SEL_RXBW_12_6_KHZ);
    else{
        return_val = -5;
        goto error;
    }

    if(this->adjust_baud_rate(this->baud_rate) < 0){
        return_val = -6;
        goto error;
    }
    if(this->update_ath_gc() < 0){
        return_val = -7;
        goto error;
    }
    if(this->update_ath_lb() < 0){
        return_val = -8;
        goto error;
    }
    if(this->update_demod_tctrl() < 0){
        return_val = -9;
        goto error;
    }

    error:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::adjust_receiver_bandwidth(int receiver_bw, float deviation)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto error;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto error;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto error;
    }

    if(*ask_fsk_sel != ASK_FSK_SEL_FSK){
        return_val = -4;
        goto error;
    }

    if(receiver_bw == 340 || receiver_bw == 170)
        set_chf_sel(CHF_SEL_RXBW_340_170_KHZ);
    else if(receiver_bw == 120 || receiver_bw == 60)
        set_chf_sel(CHF_SEL_RXBW_120_60_KHZ);
    else if(receiver_bw == 52 || receiver_bw == 26)
        set_chf_sel(CHF_SEL_RXBW_52_26_KHZ);
    else if(receiver_bw == 24 || receiver_bw == 12)
            set_chf_sel(CHF_SEL_RXBW_24_12_KHZ);
    else if(receiver_bw == 12 || receiver_bw == 6)
            set_chf_sel(CHF_SEL_RXBW_12_6_KHZ);
    else{
        return_val = -5;
        goto error;
    }

    if(this->adjust_baud_rate(this->baud_rate) < 0){
        return_val = -6;
        goto error;
    }
    if(this->update_ath_gc() < 0){
        return_val = -7;
        goto error;
    }
    if(this->update_ath_lb() < 0){
        return_val = -8;
        goto error;
    }
    if(this->update_demod_tctrl() < 0){
        return_val = -9;
        goto error;
    }
    if(this->adjust_fsk_deviation(deviation) < 0){
        return_val = -10;
        goto error;
    }

    error:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::adjust_if_sel(if_sel_t if_sel)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto error;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto error;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto error;
    }

    if(*ask_fsk_sel != ASK_FSK_SEL_ASK){
        return_val = -4;
        goto error;
    }

    this->set_if_sel(if_sel);

    if(this->adjust_baud_rate(this->baud_rate) < 0){
        return_val = -5;
        goto error;
    }
    if(this->update_ath_gc() < 0){
        return_val = -6;
        goto error;
    }
    if(this->update_demod_tctrl() < 0){
        return_val = -7;
        goto error;
    }
    if(this->update_ath_lb() < 0){
        return_val = -8;
        goto error;
    }
    if(this->set_center_frequency(this->center_frequency) < 0){
        return_val = -9;
        goto error;
    }

    error:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::adjust_if_sel(if_sel_t if_sel, float deviation)
{
    int return_val = 0;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    rx_state_t *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto error;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto error;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto error;
    }

    if(*ask_fsk_sel != ASK_FSK_SEL_FSK){
        return_val = -4;
        goto error;
    }

    this->set_if_sel(if_sel);

    if(this->adjust_baud_rate(this->baud_rate) < 0){
        return_val = -5;
        goto error;
    }
    if(this->update_ath_gc() < 0){
        return_val = -6;
        goto error;
    }
    if(this->update_demod_tctrl() < 0){
        return_val = -7;
        goto error;
    }
    if(this->update_ath_lb() < 0){
        return_val = -8;
        goto error;
    }
    if(this->set_center_frequency(this->center_frequency) < 0){
        return_val = -9;
        goto error;
    }
    if(this->adjust_fsk_deviation(deviation) < 0){
        return_val = -10;
        goto error;
    }

    error:
    free(ask_fsk_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::adjust_fsk_deviation(float deviation)
{
    int return_val = 0;
    uint8_t fsk_dev_conf_idx, conf_chf_sel, conf_demod_fsk;
    float conf_nominal_fsk_df;

    ask_fsk_sel_t *ask_fsk_sel = (ask_fsk_sel_t *)malloc(sizeof(ask_fsk_sel_t));
    if(ask_fsk_sel == NULL)
        return -99;

    chf_sel_t *chf_sel = (chf_sel_t *)malloc(sizeof(chf_sel_t));
    if(chf_sel == NULL){
        free(ask_fsk_sel);
        return -98;
    }

    if_sel_t *if_sel = (if_sel_t *)malloc(sizeof(if_sel_t));
    if(if_sel == NULL){
        free(ask_fsk_sel); free(chf_sel);
        return -97;
    }

    rx_state_t *rx_state = (rx_state_t *)malloc(sizeof(rx_state_t));
    if(rx_state == NULL){
        free(ask_fsk_sel); free(chf_sel); free(if_sel);
        return -96;
    }

    if(this->get_rx_state(rx_state) < 0){
        return_val = -1;
        goto error;
    }

    if(*rx_state != RX_STATE_STANDBY){
        return_val = -2;
        goto error;
    }

    if(this->get_ask_fsk_sel(ask_fsk_sel) < 0){
        return_val = -3;
        goto error;
    }

    if(*ask_fsk_sel != ASK_FSK_SEL_FSK){
        return_val = -4;
        goto error;
    }

    if (this->get_if_sel(if_sel) < 0){
        return_val = -5;
        goto error;
    }
    if(this->get_chf_sel(chf_sel) < 0){
        return_val = -6;
        goto error;
    }

    for(fsk_dev_conf_idx = 0; fsk_dev_conf_idx < 14; fsk_dev_conf_idx++)
    {
        conf_nominal_fsk_df = nominal_fsk_conf[fsk_dev_conf_idx];
        conf_nominal_fsk_df = (conf_nominal_fsk_df*10)/(*if_sel + 1);

        if(int(conf_nominal_fsk_df) == int(deviation*10))
        {
            conf_chf_sel = chf_sel_demod_fsk_conf[fsk_dev_conf_idx][0];
            conf_demod_fsk = chf_sel_demod_fsk_conf[fsk_dev_conf_idx][1];
            if(conf_chf_sel == *chf_sel)
            {
                set_demod_fsk(demod_fsk_t(conf_demod_fsk));
                free(ask_fsk_sel);
                free(chf_sel);
                free(if_sel);
                free(rx_state);
                return conf_demod_fsk;
            }
        }
    }

    error:
    free(ask_fsk_sel);
    free(chf_sel);
    free(if_sel);
    free(rx_state);
    return return_val;
}

template <class REG>
int MAX4147X<REG>::adjust_preamble(int preamble, uint8_t preamb_len)
{
    uint8_t preamb_w1, preamb_w2;
    if(preamble < 0 || preamble > 65535)
        return -1;

    if(preamb_len < 1 || preamb_len > 16)
        return -2;

    if(this->set_preamb_len(preamb_len-1) < 0)
        return -3;

    preamb_w1 = (preamble & 0xFF);
    preamb_w2 = ((preamble >> 8) & 0xFF);

    if(this->set_preamb_word_lower(preamb_w1) < 0)
        return -4;

    if(this->set_preamb_word_upper(preamb_w2) < 0)
        return -5;

    return 0;
}

template class MAX4147X<max41470_reg_map_t>;
template class MAX4147X<max41473_4_reg_map_t>;