#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/adc.h"
#include "pico/i2c_slave.h"

#define I2C_SDA 8
#define I2C_SCL 9
#define I2C_SLAVE_ADDR  0x41

#define CMD_NONE        0
#define CMD_GET_VOLT    1
#define CMD_GET_FACTOR  2
#define CMD_GET_RAW     3
#define CMD_UNKNOWN     4

#define ADC_INPUT_PIN   26
#define ADC_CH          0
#define ADC_FACTOR      10000
#define ADC_REF         33000

bool i2c_slave_request(i2c_inst_t *i2c, int cmd)
{
    bool rval = false;

    switch(cmd){
      case CMD_NONE:
        // 適当に0を返しておく
        uint8_t data[2] = {0, 0};
        i2c_write_raw_blocking(i2c, data, 2);
        rval = true;
        break;
    
      case CMD_GET_VOLT:
      case CMD_GET_RAW:
        uint16_t value;
        uint32_t volt;
        adc_select_input(ADC_CH);
        value = adc_read();

        if(cmd == CMD_GET_VOLT) {
            // 3.3V ref, 12-bit ADC(0-4095)
            value = (uint32_t)value * ADC_REF / 4095;
        }
        // RP2040はリトルエンディアンのため、LSBから送信される
        i2c_write_raw_blocking(i2c, (uint8_t *)&value, sizeof(uint16_t));
        rval = true;
        break;
    
      case CMD_GET_FACTOR:
        uint16_t fact = ADC_FACTOR;
        i2c_write_raw_blocking(i2c, (uint8_t *)&fact, sizeof(uint16_t));
        rval = true;
        break;
        
      default:
        rval = false;
    }
    return rval;
}

static void i2c_slave_callback(i2c_inst_t *i2c, i2c_slave_event_t event)
{
    static int slave_cmd = CMD_NONE;

    switch(event) {
      // マスターからのデータ受信
      case I2C_SLAVE_RECEIVE:
        // マスターからの1バイトを取り出す
        uint8_t rdata = i2c_read_byte_raw(i2c);
        if(rdata < CMD_UNKNOWN) {
            slave_cmd = rdata;  // コマンド更新
        }
        break;
      
      // マスターからデータ要求
      case I2C_SLAVE_REQUEST:
        bool r = i2c_slave_request(i2c, slave_cmd);
        if(r)
            slave_cmd = CMD_NONE;
        break;
      
      // ストップまたはRepeated Start Condition
      case I2C_SLAVE_FINISH:
        break;
    }
}

int main()
{
    stdio_init_all();

    // I2C Initialisation. Using it at 100Khz.
    i2c_init(i2c0, 100*1000);
    
    gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
    gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
    gpio_disable_pulls(I2C_SDA);
    gpio_disable_pulls(I2C_SCL);

    adc_init();
    adc_gpio_init(ADC_INPUT_PIN);

    i2c_slave_init(i2c0, I2C_SLAVE_ADDR, i2c_slave_callback);

    while (true) {
        tight_loop_contents();
    }
}

