/*********************************************************************************
 *
 *  lora_aprs_node_pico is a LoRa APRS KISS modem with additional PE1RXF telemetry
 *  capabilities. It runs on a Raspberry Pi Pico.
 *
 * (C)2023 M.T. Konstapel https://meezenest.nl/mees
 *
 * This file is part of lora_aprs_node_pico.
 *
 *    lora_aprs_node_pico 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.
 *
 *    lora_aprs_node_pico 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 lora_aprs_node_pico. If not, see <https://www.gnu.org/licenses/>.
 *
 **********************************************************************************/
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"

#include "i2c_sensor.h"


/*******************************************************************************
 * Function Definitions
 */

// Write 1 byte to the specified register
int reg_write(  i2c_inst_t *i2c,
                const uint addr,
                const uint8_t reg,
                uint8_t *buf,
                const uint8_t nbytes) {

    int num_bytes_read = 0;
    uint8_t msg[nbytes + 1];

    // Check to make sure caller is sending 1 or more bytes
    if (nbytes < 1) {
        return 0;
    }

    // Append register address to front of data packet
    msg[0] = reg;
    for (int i = 0; i < nbytes; i++) {
        msg[i + 1] = buf[i];
    }

    // Write data to register(s) over I2C
    i2c_write_timeout_us(i2c, addr, msg, (nbytes + 1), false, 1000000);

    return num_bytes_read;
}

// Read byte(s) from specified register. If nbytes > 1, read from consecutive
// registers.
int reg_read(  i2c_inst_t *i2c,
                const uint addr,
                const uint8_t reg,
                uint8_t *buf,
                const uint8_t nbytes) {

    int num_bytes_read = 0;

    // Check to make sure caller is asking for 1 or more bytes
    if (nbytes < 1) {
        return 0;
    }

    // Read data from register(s) over I2C
    i2c_write_timeout_us(i2c, addr, &reg, 1, true, 1000000);
    num_bytes_read = i2c_read_timeout_us(i2c, addr, buf, nbytes, false, 1000000);

    return num_bytes_read;
}

/*******************************************************************************
 * Initialize
 */
int initAM2315(void) {

    int16_t humidity;
    int16_t temperature;

    // Ports
    i2c_inst_t *i2c = i2c1;

    // Buffer to store raw reads
    uint8_t data[6];

    //Initialize I2C port at 100 kHz
    i2c_init(i2c, 100 * 1000);

    // Initialize I2C pins
    gpio_set_function(PIN_SDA, GPIO_FUNC_I2C);
    gpio_set_function(PIN_SCL, GPIO_FUNC_I2C);
    gpio_pull_up(PIN_SDA);
    gpio_pull_up(PIN_SCL);


    // Wake up AM2315
    reg_write(i2c, AM2315_I2CADDR, AM2315_READREG, data, 1);

    sleep_ms(10);

    // Request read registers from AM2315
    data[0]=0x00;// start at address 0x0
    data[1]=4;// request 4 bytes data
    reg_write(i2c, AM2315_I2CADDR, AM2315_READREG, data, 3);

    // Actual read registers
    reg_read(i2c, AM2315_I2CADDR, AM2315_READREG, data, 8);
    if (data[0] != AM2315_READREG) {
        return 1;
    }
  return 0;
}

int ReadAM2315(int16_t* humidity, int16_t* temperature){

    // Ports
    i2c_inst_t *i2c = i2c1;

    // Buffer to store raw reads
    uint8_t data[6];

    // Wake up AM2315
    reg_write(i2c, AM2315_I2CADDR, AM2315_READREG, data, 1);

    sleep_ms(10);

    // Request read registers from AM2315
    data[0]=0x00;// start at address 0x0
    data[1]=4;// request 4 bytes data
    reg_write(i2c, AM2315_I2CADDR, AM2315_READREG, data, 3);

    // Actual read registers
    reg_read(i2c, AM2315_I2CADDR, AM2315_READREG, data, 8);

    // Convert 2 bytes (little-endian) into 16-bit integer (signed)
    *humidity = (int16_t)((data[2] << 8) | data[3]);
    *temperature = (int16_t)((data[4] << 8) | data[5]);

}
