/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


//
// Commands for one-wire Dallas temperature sensor
//
static constexpr eCxx::uint8_t DS_START_CONVERSION = 0x44;
static constexpr eCxx::uint8_t DS_READ_SCRATCHPAD  = 0xBE;


//
// List of one-wire slave devices
//
static eCxx::OWIMaster::OneWireDevice owDevices[4];
static eCxx::uint8_t                  numSlavesFound;
static eCxx::uint8_t                  selSlaveIndex;


//
// Helper functions
//
static void initOWIMasterWithDallasTemperatureSensor()
{
    // For convenience
    auto& uart = App::uart();
    auto& owi  = App::owiMaster();

    // Initialize OWIMaster
    uart.write('\n');
    uart.writeString   ( PGM_STR("Initializing OWIMaster at GPIO #") );
    uart.writeDecString( OWI                                         );
    uart.writeString   ( PGM_STR(" ... ")                            );

    if( owi.begin(OWI) ) {
        uart.writeStringln( PGM_STR("SUCCESS\n") );
    }
    else {
        uart.writeStringln( PGM_STR("FAILED\nHalting here!\n" ) );
        App::halt();
    }

    // Search for slave device(s)
    uart.writeString( PGM_STR("Searching for slave device(s) ... ") );
    numSlavesFound = owi.searchBus(owDevices);

    if(numSlavesFound == eCxx::OWIMaster::Invalid) {
        uart.writeStringln( PGM_STR("FAILED\nHalting here!\n" ) );
        App::halt();
    }

    uart.writeString   ( PGM_STR("found "      ) );
    uart.writeDecString(numSlavesFound           );
    uart.writeStringln ( PGM_STR(" device(s)\n") );

    // Find any Dallas temperature sensor device
    selSlaveIndex = owi.findFamily( owDevices, eCxx::makeArray<eCxx::uint8_t, 0x10, 0x22, 0x28, 0x3B, 0x42>() );

    if(selSlaveIndex == eCxx::OWIMaster::Invalid) {
        uart.writeStringln( PGM_STR("No one-wire Dallas temperature sensor device found\nHalting here!\n") );
        App::halt();
    }

    uart.writeString   ( PGM_STR("Selecting the first one-wire Dallas temperature sensor found at slave device #") );
    uart.writeDecString( selSlaveIndex                                                                             );
    uart.writeString   ( PGM_STR(" with ID "                                                                     ) );
    for(eCxx::uint8_t i = 0; i < 8; ++i) {
        uart.writeHexString(
            owDevices[selSlaveIndex].id[i],
            eCxx::Convert::NumSign::None_Minus,
            2,
            eCxx::Convert::NumPad::Zero,
            eCxx::Convert::NumFormat::Uppercase
        );
        if(i != 7) uart.write(':');
    }
    uart.write('\n');
    uart.write('\n');
}


static void readDallasTemperatureSensor()
{
    // For convenience
    auto& uart = App::uart();
    auto& owi  = App::owiMaster();

    // Start conversion
    uart.writeString( PGM_STR("Initiating a single temperature conversion process ... ") );
    owi.reset();
    owi.matchROM(owDevices[selSlaveIndex].id);
    owi.write(DS_START_CONVERSION);

    // Wait until the process is completed
    while( !owi.read() );
    uart.writeStringln( PGM_STR("DONE") );

    // Read the result
    uart.writeStringln( PGM_STR("Reading scratchpad register ...") );
    owi.reset();
    owi.matchROM(owDevices[selSlaveIndex].id);
    owi.write(DS_READ_SCRATCHPAD);

    eCxx::int16_t temperature = owi.read() | (owi.read() << 8);

    // Write the temperature to UART
    eCxx::uint16_t fraction    = 625 * (temperature & 0x000F);
                   temperature = temperature >> 4;

    uart.writeString   ( PGM_STR("Current temperature is ") );
    uart.writeDecString( temperature                        );
    uart.write         ( '.'                                );
    uart.writeDecString( fraction                           );
    uart.writeStringln ( PGM_STR("°C\n"                   ) );
}
