Kamil Cukrowski / Mbed 2 deprecated STM32_Button_Interrupt_dla_taty

Dependencies:   mbed DS18B20 TextLCD

main.cpp

Committer:
KamilCuk
Date:
2020-02-13
Revision:
0:55c37ea095b0
Child:
1:f8a4796e766e

File content as of revision 0:55c37ea095b0:

#include "mbed.h"
#include "TextLCD.h"
#include <atomic_flag.h>
#include <string>
#include <cstdio>
#include <cassert>
#include <cstdarg>
#include <DS1820.h>
#include <DebounceIn.h>
#include <limits>
#include <flash.h>
#include <cassert>

static DigitalOut led_on_board(PC_13);

/* str --------------------------------------------- */

void str_remove(char *str, const char *reject) {
    while (1) {
        const size_t s = strcspn(str, reject);
        str += s;
        if (str[0] == '\0') {
            break;
        }
        memmove(str, str + 1, strlen(str + 1) + 1);
    }
}

void str_pad_suffix(char *str, size_t len, char c) {
    if (strlen(str) < len) {
        memset(str + strlen(str), c, len - strlen(str));
    }
    str[len] = '\0';
}

char *str_filename(const char *file) {
    return (char*)(strrchr(file, '/') ? strrchr(file, '/') + 1 : file);
}

/* lcd ------------------------------------------------- */

static TextLCD& lcd() {
    static TextLCD lcd(PB_15, PA_10, PB_3, PB_4, PB_5, PB_6, TextLCD::LCD16x2); // rs, e, d4-d7
    // static TextLCD lcd(PA_0, PA_1, PA_2, PA_3, PA_4, PA_5, TextLCD::LCD16x2); // rs, e, d4-d7
    return lcd;
}

void lcd_cls() {
    lcd().cls();
}

void lcd_vprintln(const char *fmt, va_list va) {
    char buf[20] = {0};
    const size_t len = vsnprintf(buf, sizeof(buf), fmt, va);
    str_remove(buf, "\r\n");
    str_pad_suffix(buf, 16, ' ');
    lcd().printf(buf);
}

__attribute__((__format__(__printf__, 1, 2)))
void lcd_println(const char *fmt, ...) {
    va_list va;
    va_start(va, fmt);
    lcd_vprintln(fmt, va);
    va_end(va);
}

extern "C" {
    void d(const char *fmt, ...) {
        va_list va;
        va_start(va, fmt);
        lcd_vprintln(fmt, va);
        va_end(va);
        wait(1);
    }
}
    
/* system --------------------------------------------- */

extern "C" void abort() {
    for (int i = 0; i < 20 * 5; ++i) {
        led_on_board = !led_on_board;
        wait(0.05);
    }
    NVIC_SystemReset();
}

extern "C" void __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
  lcd_println("ASSERT %d", line);
  lcd_println("%s", str_filename(file));
  abort();
}


/* ds18b20 --------------------------------------------- */

/**
 * @return
 *              0 - no errors ('temp' contains the temperature measured)
 *              1 - sensor not present ('temp' is not updated)
 *              2 - CRC error ('temp' is not updated)
 */
static int ds18b20_temp(float& temperature_f_C) {
    static DS1820 probe('B', PB_1);
    static Timer t;
    static bool running = false;
    
    // start the conversion if not running
    if (running == false) {
        running = true;
        probe.startConversion();
        t.start();
    }
    
    // wait for conversion end
    const unsigned ms = t.read_ms();
    const unsigned conversion_time_ms = 800;
    if (ms < conversion_time_ms) {
        wait((conversion_time_ms - ms) / 1000.0);
    }
    
    // read temperature from buffer
    temperature_f_C = -1000;
    const uint8_t err = probe.read(temperature_f_C);
    
    // restart new conversion
    probe.startConversion();
    t.reset();
    
    return err;
}

/* output -------------------------------------------- */

static DigitalOut output(PC_14);

/* state --------------------------------------------- */

struct state {
    volatile int high;  // in Celcius
    volatile int low;   // in Celcius
    volatile bool inverted;
    
    state() : high(30), low(20) {}
    
    struct data {
        static const int data_version = 0x11;
        int version;
        int high;
        int low;
        bool inverted : 1;
        bool current : 1;
        data() : version(data_version) {}
        data(const state& s, const DigitalOut& o) : 
            version(data_version),
            high(s.high), 
            low(s.low), 
            inverted(s.inverted), 
            current(output) 
            {}
        void put(state& s, DigitalOut& o) {
            s.high = high;
            s.low = low;
            s.inverted = inverted;
            o = current;
        }
    };
    
    static bool _low_high_valid(int high, int low) {
        return -99 < high && high < 99 &&
                -99 < low && low < 99 &&
                low < high &&
                low != high;
    }
    
    void save() {
        const struct data d(*this, output);
        flash::write(d);
    }
    
    void restore() {
        struct data d;
        const int e = flash::read(d);
        if (e) {
            lcd_println("New flash %d", e);
            wait(1);
            return;
        }
        if (!_low_high_valid(d.high, d.low)) {
            lcd_println("Invalid flash vals");
            lcd_println("%d %d", d.high, d.low);
            wait(1);
            return;
        }
        lcd_println("Flash load %d %d", d.high, d.low);
        wait(1);
        d.put(*this, output);
    }
    
    void high_inc() { _inc_it(high, low); }
    void high_dec() { _dec_it(high, low); }
    void low_inc() { _inc_it(low, high); }
    void low_dec() { _dec_it(low, high); }    
    void invert_invert() {
        inverted = !inverted;
        save();
    }
    
private:
    void _inc_it(volatile int &val, volatile int &other) {
        if (val + 1 == other) return;
        if (val >= 99) return;
        val++;
        save();
    }
    void _dec_it(volatile int &val, volatile int &other) {
        if (val - 1 == other) return;
        if (val <= -99) return;
        val--;
        save();
    }
};

static state state;


/* buttons -------------------------------------------- */

static DebounceIn button_h_inc(PA_6, PullDown);
static DebounceIn button_h_dec(PA_5, PullDown);
static DebounceIn button_l_inc(PA_4, PullDown);
static DebounceIn button_l_dec(PA_3, PullDown);
static DebounceIn button_inv(PA_2, PullDown);
static DebounceIn button_refresh(PA_1, PullDown);

static void button_h_inc_pressed() { state.high_inc(); }
static void button_h_dec_pressed() { state.high_dec(); }
static void button_l_inc_pressed() { state.low_inc(); }
static void button_l_dec_pressed() { state.low_dec(); }
static void button_inv_pressed() {
    output = !output;
    state.invert_invert();
}

static void button_init() {
    const unsigned debounce_timeout_us = 200 * 1000;
    button_h_inc.fall(button_h_inc_pressed, debounce_timeout_us);
    button_h_dec.fall(button_h_dec_pressed, debounce_timeout_us);
    button_l_inc.fall(button_l_inc_pressed, debounce_timeout_us);
    button_l_dec.fall(button_l_dec_pressed, debounce_timeout_us);
    button_inv.fall(button_inv_pressed, debounce_timeout_us * 2);
}
    

static void button_check() {
    while(1) {
        DebounceIn *arr[6] = {
            &button_h_inc,
            &button_h_dec,
            &button_l_inc,
            &button_l_dec,
            &button_inv,
            &button_refresh
        };
        lcd_println("%d %d %d %d %d %d\n",
            arr[0]->read(),
            arr[1]->read(),
            arr[2]->read(),
            arr[3]->read(),
            arr[4]->read(),
            arr[5]->read());
        lcd_println("");
    }
}

/* main --------------------------- */

static void setup() {    
    // wait for voltage stability
    wait(1);
    // some info
    lcd_cls();
    lcd_println("Hello!");
    lcd_println("clock=%ld", SystemCoreClock);
    wait(1);
    lcd_cls();
    state.restore();
    button_init();
}

static void loop() {
    static bool alive;
    alive = !alive;
    
    float temperature_f_C = 0;
    const int ds18b20_err = ds18b20_temp(temperature_f_C);
    
    lcd_cls();
    
    char temperature_s[8] = "ERROR";
    if (ds18b20_err == 0) {
        const int temperature_dC = temperature_f_C * 10;
        const int temperature_C = temperature_f_C;
        
        if (temperature_C < -100 || temperature_C > 100) {
            snprintf(temperature_s, sizeof(temperature_s), "INVAL");
        } else {
                        
            if (!output ^ state.inverted) {
                if (temperature_C > state.high) {
                    output = 1 ^ state.inverted;
                }
            } else {
                if (temperature_C < state.low) {
                    output = 0 ^ state.inverted;
                }
            }
            
            snprintf(temperature_s, sizeof(temperature_s), "%3d.%d'C", temperature_C, temperature_dC % 10);
        }
    }
    
    led_on_board = output;

    lcd_println("%-7s %3s  %3s",
            temperature_s,
            state.inverted ? "INV" : "NOR",
            output ? "ON" : "OFF"
    );
    lcd_println("H=%2d'C L=%2d'C %c%c", 
            state.high,
            state.low, 
            !alive ? '\xff' : ' ',
            alive ? '\xff' : ' '
    );
}

int main() {
    setup();
    while (1) {
        loop();
    }
    return 0;
}