// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright (c) 2026 Ashwin Whitchurch, Protocentral Electronics

/*
 * 06_LiquidLevel - Non-contact liquid-level sensing on two channels
 *
 * Copyright (c) 2026 Ashwin Whitchurch, Protocentral Electronics
 * Email: info@protocentral.com
 *
 * Differential setup on the ProtoCentral FDC2214:
 *   CH0 = REFERENCE electrode, mounted above the maximum fill line. Its
 *         capacitance does not change with fluid level. Used to cancel
 *         temperature / humidity / dielectric drift.
 *   CH1 = LEVEL electrode, a vertical strip running down the side of the
 *         tank.
 *
 * On startup, both channels are measured "empty" to obtain baselines. Level
 * is then estimated as:
 *
 *     level% = clamp( (delta_level - delta_ref) / span * 100, 0, 100 )
 *
 * Calibrate SPAN by filling the tank fully once, reading the printed
 * "delta_level - delta_ref" value, and setting LEVEL_SPAN below.
 *
 * This software is licensed under the MIT License.
 */

//////////////////////////////////////////////////////////////////////////////////////////
//
//    Hardware Setup:
//      CH0 -> reference electrode (above max fill line)
//      CH1 -> level electrode (vertical strip on side of tank)
//        3.3V -> VCC
//        GND  -> GND
//        SDA  -> SDA (A4 on Uno)
//        SCL  -> SCL (A5 on Uno)
//
/////////////////////////////////////////////////////////////////////////////////////////

#include <Wire.h>
#include <Protocentral_FDC2214.h>

FDC2214 fdc;

// Calibrate empirically: fill the tank, read the printed differential,
// and set this constant to that value.
const long LEVEL_SPAN = 250000;

const uint16_t BASELINE_SAMPLES = 200;

float baseline_ref   = 0.0f;
float baseline_level = 0.0f;

static float averageChannel(fdc2214_channel_t ch, uint16_t n) {
    double sum = 0.0;
    for (uint16_t i = 0; i < n; i++) {
        while (!fdc.isDataReady(ch)) { /* wait */ }
        sum += (double)fdc.readRawChannel(ch);
    }
    return (float)(sum / n);
}

void setup() {
    Serial.begin(115200);
    while (!Serial && millis() < 3000);

    Wire.begin();

    if (!fdc.begin()) {
        Serial.println(F("FDC2214 not found"));
        while (1) delay(1000);
    }

    fdc.configureDefaults();
    fdc.setAutoscan(true, FDC2214_RR_SEQ_CH0_CH1);
    fdc.start();

    Serial.println(F("Calibrating empty-tank baselines..."));
    baseline_ref   = averageChannel(FDC2214_CH0, BASELINE_SAMPLES);
    baseline_level = averageChannel(FDC2214_CH1, BASELINE_SAMPLES);

    Serial.print(F("Baseline ref:   ")); Serial.println(baseline_ref,   0);
    Serial.print(F("Baseline level: ")); Serial.println(baseline_level, 0);
    Serial.println(F("delta_ref\tdelta_level\tdiff\tlevel%"));
}

void loop() {
    uint32_t raw_ref   = fdc.readRawChannel(FDC2214_CH0);
    uint32_t raw_level = fdc.readRawChannel(FDC2214_CH1);

    long d_ref   = (long)raw_ref   - (long)baseline_ref;
    long d_level = (long)raw_level - (long)baseline_level;
    long diff    = d_level - d_ref;

    long pct = (diff * 100L) / LEVEL_SPAN;
    if (pct < 0)   pct = 0;
    if (pct > 100) pct = 100;

    Serial.print(d_ref);   Serial.print('\t');
    Serial.print(d_level); Serial.print('\t');
    Serial.print(diff);    Serial.print('\t');
    Serial.println(pct);

    delay(200);
}
