/*
Damon Hart-Davis licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2016
*/

static const char *Id = "$Id: ssmppt15l-modbus.cpp 15764 2016-10-30 22:50:03Z dhd $";

/*
Stand-alone code to interrogate SS-MPPT-15L solar controller over MODBUS.
*/

#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include "mbaccess.h"


int main (const int argc, char *const argv [])
    {
    int c;
    while((c = getopt(argc,argv,"hvkcE")) >= 0)
        {
        switch(c)
            {
            case 'h':
            case '?':
            default:
                {
                fprintf(stderr, "Version %s, libmodbus " LIBMODBUS_VERSION_STRING "\n", Id);
                fprintf(stderr, "%s [options]\n", argv[0]);
                fprintf(stderr, " -h this help\n");
                fprintf(stderr, " -v verbose\n");
                fprintf(stderr, " -c mAh net charge today*\n");
                fprintf(stderr, " -k kWh cumulative charge*\n");
                fprintf(stderr, " -E noisy numbers with entropy*\n");
                fprintf(stderr, "*takes dev/log lock.\n");
                exit(1);
                }

            case 'k':
                {
                // Print on stdout cumulative kWh charge figure from controller.
                // Format as XXX.XXX ie with 3sf.
                int exitCode = 0;
                // ACQUIRE MUTEX
                lockAcquire();
                uint16_t kWhc;
                if(getMODBUSReg(SS_REG_kWhc, kWhc))
                    { fprintf(stdout, "%3.3f\n", kWhc/10.0f); }
                else { fprintf(stderr, "Failed\n"); exitCode = 1; }
                // RELEASE MUTEX
                lockRelease();
                exit(exitCode);
                }

            case 'c':
                {
                // Print on stdout net mAh charge today.
                int exitCode = 0;
                // ACQUIRE MUTEX
                lockAcquire();
                uint16_t Ahc_daily, Ahl_daily;
                if(getMODBUSReg(SS_REG_Ahc_daily, Ahc_daily) &&
                   getMODBUSReg(SS_REG_Ahl_daily, Ahl_daily))
                    { fprintf(stdout, "%ld\n", (long) fMODBUSTmAh32(Ahc_daily) - (long) fMODBUSTmAh32(Ahl_daily)); }
                else { fprintf(stderr, "Failed\n"); exitCode = 1; }
                // RELEASE MUTEX
                lockRelease();
                exit(exitCode);
                }

            case 'E':
                {
                // Print on stdout some noisy numbers with entropy.
                // Good for feeding entropy pools.
                // Includes nothing knowingly entropy-free, eg uptime.
                int exitCode = 0;
                // ACQUIRE MUTEX
                lockAcquire();
                // Note: no checking of fetch success or not, for fun.
                // Fetch and print typically-highest-entropy first.
                uint16_t Adc_va_f;
                getMODBUSReg(SS_REG_Adc_va_f, Adc_va_f);
                uint16_t Adc_il_f;
                getMODBUSReg(SS_REG_Adc_il_f, Adc_il_f);
                uint16_t Adc_vl_f;
                getMODBUSReg(SS_REG_Adc_vl_f, Adc_vl_f);
                uint16_t Adc_ic_f;
                getMODBUSReg(SS_REG_Adc_ic_f, Adc_ic_f);
                fprintf(stdout, "%x %x %x %x\n",
                        Adc_va_f, Adc_il_f, Adc_vl_f, Adc_ic_f);
                // RELEASE MUTEX
                lockRelease();
                exit(exitCode);
                }
            }
        }

    // Time since boot.
    struct sysinfo sinfo;
    if(0 == sysinfo(&sinfo))
        { fprintf(stdout, "Time since boot (s): %ld\n", sinfo.uptime); }

    // Get (smoothed/slow) battery voltage.
    uint16_t Vb_f_raw;
    if(getMODBUSReg(SS_REG_Vb_f, Vb_f_raw))
        {
        //fprintf(stdout, "Vb_f (V): %f\n", Vb_f_raw*100.0f/32768.0f);
        fprintf(stdout, "Vb_f battery voltage slow (mV): %u\n", fMODBUSTmV(Vb_f_raw));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    // Get load voltage.
    uint16_t Adc_vl_f;
    if(getMODBUSReg(SS_REG_Adc_vl_f, Adc_vl_f))
        {
        fprintf(stdout, "Adc_vl_f load voltage (mV): %u\n", fMODBUSTmV(Adc_vl_f));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Adc_ic_f;
    if(getMODBUSReg(SS_REG_Adc_ic_f, Adc_ic_f))
        {
        fprintf(stdout, "Adc_ic_f battery charge current (mA): %u\n", fMODBUSTmA(Adc_ic_f));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Adc_il_f;
    if(getMODBUSReg(SS_REG_Adc_il_f, Adc_il_f))
        {
        fprintf(stdout, "Adc_il_f load current (mA): %u\n", fMODBUSTmA(Adc_il_f));
        fprintf(stdout, "Load power (mW): %lu\n", (unsigned long)(999ul + fMODBUSTmV(Vb_f_raw) * (uint32_t)fMODBUSTmA(Adc_il_f)) / 1000ul);
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Adc_va_f;
    if(getMODBUSReg(SS_REG_Adc_va_f, Adc_va_f))
        {
        fprintf(stdout, "Adc_va_f array voltage (mV): %u\n", fMODBUSTmV(Adc_va_f));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Sweep_Vmp;
    if(getMODBUSReg(SS_REG_Sweep_Vmp, Sweep_Vmp))
        {
        fprintf(stdout, "Sweep_Vmp (mV): %u\n", fMODBUSTmV(Sweep_Vmp));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Sweep_Voc;
    if(getMODBUSReg(SS_REG_Sweep_Voc, Sweep_Voc))
        {
        fprintf(stdout, "Sweep_Voc (mV): %u\n", fMODBUSTmV(Sweep_Voc));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Sweep_Pmax;
    if(getMODBUSReg(SS_REG_Sweep_Pmax, Sweep_Pmax))
        {
        fprintf(stdout, "Sweep_Pmax (mW): %lu\n", (unsigned long)fMODBUSTmW32(Sweep_Pmax));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Power_out;
    if(getMODBUSReg(SS_REG_Power_out, Power_out))
        {
        fprintf(stdout, "Power_out (mW): %lu\n", (unsigned long)fMODBUSTmW32(Power_out));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t kWhc;
    if(getMODBUSReg(SS_REG_kWhc, kWhc))
        {
        fprintf(stdout, "kWhc (kWh*10): %u\n", kWhc);
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t charge_state;
    if(getMODBUSReg(SS_REG_charge_state, charge_state))
        {
        fprintf(stdout, "charge_state: %u\n", charge_state);
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Ahc_daily;
    if(getMODBUSReg(SS_REG_Ahc_daily, Ahc_daily))
        {
        fprintf(stdout, "Ahc_daily (mAh): %lu\n", (unsigned long) fMODBUSTmAh32(Ahc_daily));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t Ahl_daily;
    if(getMODBUSReg(SS_REG_Ahl_daily, Ahl_daily))
        {
        fprintf(stdout, "Ahl_daily (mAh): %lu\n", (unsigned long) fMODBUSTmAh32(Ahl_daily));
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    uint16_t T_batt;
    if(getMODBUSReg(SS_REG_T_batt, T_batt))
        {
        fprintf(stdout, "T_batt (C): %d\n", (int) T_batt);
        }
    else { fprintf(stderr, "Failed\n"); exit(1); }

    return(0);
    }


/* Sample output 20160814T1856Z

Vb_f battery voltage slow (mV): 12922
Adc_ic_f battery charge current (mA): 32
Adc_il_f load current (mA): 1283
Load power (mW): 16579
Adc_va_f array voltage (mV): 20209
Sweep_Vmp (mV): 20200
Sweep_Voc (mV): 26929
Sweep_Pmax (W): 3.835037
kWhc (kWh*10): 2025
charge_state: 5

*/


/* Sample output 20160815T1147Z

Vb_f battery voltage slow (mV): 14084
Adc_ic_f battery charge current (mA): 6844
Adc_il_f load current (mA): 2453
Load power (mW): 34549
Adc_va_f array voltage (mV): 31833
Sweep_Vmp (mV): 25721
Sweep_Voc (mV): 34290
Sweep_Pmax (mW): 158264
Power_out (mW): 94457
kWhc (kWh*10): 2027
charge_state: 6

*/

/* Sample output 20160911T0820Z

Time simce boot (s): 62934
Vb_f battery voltage slow (mV): 12522
Adc_vl_f load voltage (mV): 12421
Adc_ic_f battery charge current (mA): 510
Adc_il_f load current (mA): 3141
Load power (mW): 39332
Adc_va_f array voltage (mV): 28855
Sweep_Vmp (mV): 28882
Sweep_Voc (mV): 31800
Sweep_Pmax (mW): 6644
Power_out (mW): 6342
kWhc (kWh*10): 2131
charge_state: 5
Ahc_daily (mAh): 200
Ahl_daily (mAh): 14500

*/
