--- /dev/null
+# Makefile for apps
+
+MODULE = $(shell basename $(shell cd .. && pwd && cd -))
+NAME = $(shell basename $(CURDIR))
+
+# Add this to your ~/.vimrc in order to get proper function of :make in vim :
+# let $COMPILE_FROM_IDE = 1
+ifeq ($(strip $(COMPILE_FROM_IDE)),)
+ PRINT_DIRECTORY = --no-print-directory
+else
+ PRINT_DIRECTORY =
+ LANG = C
+endif
+
+.PHONY: $(NAME).bin
+$(NAME).bin:
+ @make -C ../../.. ${PRINT_DIRECTORY} NAME=$(NAME) MODULE=$(MODULE) apps/$(MODULE)/$(NAME)/$@
+
+clean mrproper:
+ @make -C ../../.. ${PRINT_DIRECTORY} $@
+
--- /dev/null
+/****************************************************************************
+ * apps/scialys/v05/config.c
+ *
+ * Copyright 2018 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include "core/system.h"
+#include "core/systick.h"
+#include "core/pio.h"
+
+#include "drivers/serial.h"
+#include "drivers/gpio.h"
+#include "drivers/i2c.h"
+#include "drivers/adc.h"
+#include "drivers/ssp.h"
+#include "drivers/timers.h"
+
+
+#include "extdrv/status_led.h"
+#include "extdrv/max31855_thermocouple.h"
+
+#include "lib/stdio.h"
+
+#include "config.h"
+#include "interface.h"
+#include "time.h"
+#include "uSD.h"
+
+#define SELECTED_FREQ FREQ_SEL_48MHz
+
+
+uint8_t config_got_interface = 1;
+
+/***************************************************************************** */
+/* Pins configuration */
+/* pins blocks are passed to set_pins() for pins configuration.
+ * Unused pin blocks can be removed safely with the corresponding set_pins() call
+ * All pins blocks may be safelly merged in a single block for single set_pins() call..
+ */
+const struct pio_config common_pins[] = {
+ /* UART 0 */
+ { LPC_UART0_RX_PIO_0_1, LPC_IO_DIGITAL },
+ { LPC_UART0_TX_PIO_0_2, LPC_IO_DIGITAL },
+ /* UART 1 */
+ { LPC_UART1_RX_PIO_0_8, LPC_IO_DIGITAL },
+ { LPC_UART1_TX_PIO_0_9, LPC_IO_DIGITAL },
+ /* I2C 0 */
+ { LPC_I2C0_SCL_PIO_0_10, (LPC_IO_DIGITAL | LPC_IO_OPEN_DRAIN_ENABLE) },
+ { LPC_I2C0_SDA_PIO_0_11, (LPC_IO_DIGITAL | LPC_IO_OPEN_DRAIN_ENABLE) },
+ /* SPI */
+ { LPC_SSP0_SCLK_PIO_0_14, LPC_IO_DIGITAL },
+ { LPC_SSP0_MOSI_PIO_0_17, LPC_IO_DIGITAL },
+ { LPC_SSP0_MISO_PIO_0_16, LPC_IO_DIGITAL },
+ /* ADC */
+ { LPC_ADC_AD0_PIO_0_30, LPC_IO_ANALOG }, /* Home */
+ { LPC_ADC_AD1_PIO_0_31, LPC_IO_ANALOG }, /* Production */
+ { LPC_ADC_AD2_PIO_1_0, LPC_IO_ANALOG }, /* Load */
+ { LPC_ADC_AD7_PIO_1_5, LPC_IO_ANALOG }, /* Display potentiometer */
+ /* GPIO */
+ { LPC_GPIO_0_0, LPC_IO_DIGITAL }, /* Clkout / interrupt from RTC */
+ { LPC_GPIO_0_3, LPC_IO_DIGITAL }, /* External switch input */
+ { LPC_GPIO_0_4, LPC_IO_DIGITAL }, /* Zero crossing detection input */
+ { LPC_GPIO_0_6, LPC_IO_DIGITAL }, /* Mosfet control */
+ { LPC_GPIO_0_7, LPC_IO_DIGITAL }, /* Fan control */
+ { LPC_GPIO_0_12, LPC_IO_DIGITAL }, /* ISP / User button OK */
+ { LPC_GPIO_0_15, LPC_IO_DIGITAL }, /* Thermocouple chip select */
+ { LPC_GPIO_0_21, LPC_IO_DIGITAL }, /* WS2812B RGB Leds control */
+ { LPC_GPIO_0_28, LPC_IO_DIGITAL }, /* Charge State */
+ { LPC_GPIO_1_1, LPC_IO_DIGITAL }, /* Uext Chip select / Module eeprom select */
+ { LPC_GPIO_1_6, LPC_IO_DIGITAL }, /* uSD Card SPI Chip Select */
+ ARRAY_LAST_PIO,
+};
+
+/* Internal status leds */
+const struct pio status_light_green = LPC_GPIO_0_26;
+const struct pio status_light_red = LPC_GPIO_0_27;
+
+/* Inputs */
+/* External signals */
+const struct pio zero_cross_in_pin = LPC_GPIO_0_4;
+const struct pio rtc_in_pin = LPC_GPIO_0_0;
+const struct pio ext_disable_in_pin = LPC_GPIO_0_3;
+const struct pio charge_status_in_pin = LPC_GPIO_0_28;
+
+/* Outputs */
+/* AC output control (Mosfet) */
+const struct pio ac_ctrl = LPC_GPIO_0_6;
+const struct pio fan_ctrl = LPC_GPIO_0_7;
+/* Chip selects */
+const struct pio uSD_cs = LPC_GPIO_1_6; /* uSD card */
+const struct pio th_cs = LPC_GPIO_0_15; /* Thermocouple */
+const struct pio uext_cs = LPC_GPIO_1_1; /* UEXT module (optionnal) */
+
+
+
+/***************************************************************************** */
+/* Basic system init and configuration */
+static volatile int got_wdt_int = 0;
+void wdt_callback(void)
+{
+ got_wdt_int = 1;
+}
+
+const struct wdt_config wdconf = {
+ .clk_sel = WDT_CLK_IRC,
+ .intr_mode_only = 0,
+ .callback = wdt_callback,
+ .locks = 0,
+ .nb_clk = 0x03FFFFFF, /* 0x3FF to 0x03FFFFFF */
+ .wdt_window = 0,
+ .wdt_warn = 0x3FF,
+};
+
+void system_init()
+{
+ /* Configure the Watchdog */
+ watchdog_config(&wdconf);
+ system_set_default_power_state();
+ clock_config(SELECTED_FREQ);
+ set_pins(common_pins);
+ gpio_on();
+ status_led_config(&status_light_green, &status_light_red);
+ /* System tick timer MUST be configured and running in order to use the sleeping
+ * functions */
+ systick_timer_on(1); /* 1ms */
+ systick_start();
+}
+
+/* Define our fault handler. This one is not mandatory, the dummy fault handler
+ * will be used when it's not overridden here.
+ * Note : The default one does a simple infinite loop. If the watchdog is deactivated
+ * the system will hang.
+ */
+void fault_info(const char* name, uint32_t len)
+{
+ uprintf(UART0, name);
+ while (1);
+}
+
+
+/***************************************************************************** */
+/* Internal modules */
+const struct lpc_tc_config ac_timer_conf = {
+ .mode = LPC_TIMER_MODE_TIMER | LPC_TIMER_MODE_MATCH,
+ .match_control = { 0, LPC_TIMER_INT_RESET_AND_STOP_ON_MATCH, 0, 0, },
+ .match = { 0, 10, 0, 0, },
+ .ext_match_config = { 0, LPC_TIMER_SET_ON_MATCH, 0, 0, },
+};
+
+extern void config_rx(uint8_t c);
+extern void comm_rx(uint8_t c);
+extern void ac_switch_on(uint32_t flags);
+
+void modules_config(void)
+{
+ uart_on(UART0, 115200, config_rx);
+ uart_on(UART1, 115200, comm_rx);
+ i2c_on(I2C0, I2C_CLK_100KHz, I2C_MASTER);
+ ssp_master_on(SSP_BUS_0, LPC_SSP_FRAME_SPI, 8, 4*1000*1000);
+ adc_on(NULL);
+ adc_start_burst_conversion(ADC_MCH(0) | ADC_MCH(1) | ADC_MCH(2) | ADC_MCH(7), LPC_ADC_SEQ(0));
+ timer_on(LPC_TIMER_32B1, 0, ac_switch_on);
+ timer_counter_config(LPC_TIMER_32B1, &ac_timer_conf);
+}
+
+
+/***************************************************************************** */
+extern void zero_cross(uint32_t gpio);
+void board_io_config(void)
+{
+ /* Immediatly turn off Mosfet / Triac */
+ config_gpio(&ac_ctrl, 0, GPIO_DIR_OUT, 0);
+ /* Start with FAN ON */
+ config_gpio(&fan_ctrl, 0, GPIO_DIR_OUT, 1);
+
+ /* Configure Input GPIO */
+ config_gpio(&ext_disable_in_pin, 0, GPIO_DIR_IN, 0);
+ config_gpio(&rtc_in_pin, 0, GPIO_DIR_IN, 0);
+ config_gpio(&charge_status_in_pin, 0, GPIO_DIR_IN, 1);
+
+ /* Zero-crossing detection */
+ set_gpio_callback(zero_cross, &zero_cross_in_pin, EDGE_FALLING);
+}
+
+
+
+/***************************************************************************** */
+/* Configure external components */
+
+/* Thermocouple reading */
+const struct max31855_sensor_config thermocouple = {
+ .ssp_bus_num = 0,
+ .chip_select = LPC_GPIO_0_15,
+};
+
+/* RTC and time */
+#define RTC_ADDR 0xA2
+
+
+int external_config(uint32_t uart)
+{
+ int ret = 0;
+
+ /* Configure GPIO for specific board usage */
+ board_io_config();
+
+ /* uSD card */
+ uSD_config((struct pio *)&uSD_cs, SSP_BUS_0);
+ uSD_detect(uart);
+
+ /* RTC */
+ time_config(I2C0, RTC_ADDR);
+ time_init_check(uart);
+
+ /* Thermocouple configuration */
+ max31855_sensor_config(&thermocouple);
+
+ /* Configure interface board */
+ ret = interface_config(uart);
+ if (ret != 0) {
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+/****************************************************************************
+ * apps/blyes/inter_lights/config.h
+ *
+ * Copyright 2018 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include "core/system.h"
+#include "core/systick.h"
+#include "core/pio.h"
+
+#include "drivers/serial.h"
+#include "drivers/gpio.h"
+#include "drivers/i2c.h"
+#include "drivers/adc.h"
+#include "drivers/ssp.h"
+#include "drivers/timers.h"
+
+#include "extdrv/status_led.h"
+#include "extdrv/max31855_thermocouple.h"
+#include "extdrv/ws2812.h"
+
+#include "lib/stdio.h"
+
+
+#define SELECTED_FREQ FREQ_SEL_48MHz
+
+/***************************************************************************** */
+/* Pins configuration */
+extern const struct pio status_led_green;
+extern const struct pio status_led_red;
+
+/* Inputs */
+/* External signals */
+extern const struct pio zero_cross_in_pin;
+extern const struct pio rtc_in_pin;
+extern const struct pio ext_disable_in_pin;
+extern const struct pio charge_status_in_pin;
+
+/* Outputs */
+/* AC output control (Mosfet) */
+extern const struct pio ac_ctrl;
+extern const struct pio fan_ctrl;
+/* Chip selects */
+extern const struct pio uSD_cs; /* uSD card */
+extern const struct pio th_cs; /* Thermocouple */
+extern const struct pio uext_cs; /* UEXT module (optionnal) */
+
+
+
+/***************************************************************************** */
+extern const struct max31855_sensor_config thermocouple;
+
+
+/***************************************************************************** */
+/* Configuration */
+
+/* Configure the watchdog, clocks, systick, power and common pins */
+void system_init();
+
+/* Define our fault handler. This one is not mandatory, the dummy fault handler
+ * will be used when it's not overridden here.
+ * Note : The default one does a simple infinite loop. If the watchdog is deactivated
+ * the system will hang.
+ */
+void fault_info(const char* name, uint32_t len);
+
+
+/* Configure modules and main functions */
+void modules_config(void);
+
+/* Configure GPIO for specific board usage */
+void board_io_config(void);
+
+/* Configure external components */
+int external_config(uint32_t uart);
+
+
+#endif /* CONFIG_H */
+
--- /dev/null
+/****************************************************************************
+ * apps/scialys/v05/interface.c
+ *
+ * Copyright 2018 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include "core/system.h"
+#include "core/systick.h"
+#include "core/pio.h"
+
+#include "drivers/serial.h"
+#include "drivers/gpio.h"
+#include "drivers/i2c.h"
+#include "drivers/adc.h"
+
+#include "extdrv/status_led.h"
+#include "extdrv/ws2812.h"
+#include "extdrv/tmp101_temp_sensor.h"
+#include "extdrv/ssd130x_oled_driver.h"
+#include "extdrv/ssd130x_oled_buffer.h"
+
+#include "lib/stdio.h"
+#include "lib/font.h"
+#include "lib/time.h"
+
+#include "interface.h"
+#include "time.h"
+
+/***************************************************************************** */
+/* Buttons inputs on front panel */
+const struct pio button_up = LPC_GPIO_0_25;
+#define GPIO_BUTTON_UP 25
+const struct pio button_right = LPC_GPIO_0_24;
+#define GPIO_BUTTON_RIGHT 24
+const struct pio button_left = LPC_GPIO_0_23;
+#define GPIO_BUTTON_LEFT 23
+const struct pio button_down = LPC_GPIO_0_22;
+#define GPIO_BUTTON_DOWN 22
+/* ISP /User button OK */
+const struct pio button_ok = LPC_GPIO_0_12;
+#define GPIO_BUTTON_OK 12
+/* Led control data pin */
+const struct pio ws2812_data_out_pin = LPC_GPIO_0_21;
+
+
+static uint8_t interface_board_present = 0;
+
+/***************************************************************************** */
+/* TMP101 onboard I2C temperature sensor */
+#define TMP101_ADDR 0x94 /* Pin Addr0 (pin5 of tmp101) connected to VCC */
+struct tmp101_sensor_config tmp101_sensor = {
+ .bus_num = I2C0,
+ .addr = TMP101_ADDR,
+ .resolution = TMP_RES_ELEVEN_BITS,
+};
+
+/***************************************************************************** */
+/* Oled Display */
+static uint8_t gddram[ 4 + GDDRAM_SIZE ];
+
+#define DISPLAY_ADDR 0x78
+struct oled_display display = {
+ .bus_type = SSD130x_BUS_I2C,
+ .address = DISPLAY_ADDR,
+ .bus_num = I2C0,
+ .charge_pump = SSD130x_EXT_VCC,
+ .video_mode = SSD130x_DISP_NORMAL,
+ .contrast = 128,
+ .scan_dir = SSD130x_SCAN_BOTTOM_TOP,
+ .read_dir = SSD130x_RIGHT_TO_LEFT,
+ .display_offset_dir = SSD130x_MOVE_TOP,
+ .display_offset = 4,
+ .gddram = gddram,
+};
+
+#define ROW(x) VERTICAL_REV(x)
+DECLARE_FONT(font);
+
+void display_char(uint8_t line, uint8_t col, uint8_t c)
+{
+ uint8_t tile = (c > FIRST_FONT_CHAR) ? (c - FIRST_FONT_CHAR) : 0;
+ uint8_t* tile_data = (uint8_t*)(&font[tile]);
+ ssd130x_buffer_set_tile(gddram, col, line, tile_data);
+}
+int display_line(uint8_t line, uint8_t col, char* text)
+{
+ int len = strlen((char*)text);
+ int i = 0;
+
+ if (interface_board_present == 0) {
+ return -1;
+ }
+
+ for (i = 0; i < len; i++) {
+ uint8_t tile = (text[i] > FIRST_FONT_CHAR) ? (text[i] - FIRST_FONT_CHAR) : 0;
+ uint8_t* tile_data = (uint8_t*)(&font[tile]);
+ ssd130x_buffer_set_tile(gddram, col++, line, tile_data);
+ if (col >= (OLED_LINE_CHAR_LENGTH)) {
+ col = 0;
+ line++;
+ if (line >= SSD130x_NB_PAGES) {
+ len = i;
+ break;
+ }
+ }
+ }
+ return len;
+}
+
+int erase_line(uint8_t line)
+{
+ uint8_t* tile_data = (uint8_t*)(&font[0]);
+ uint8_t col = 0;
+ int i = 0;
+
+ if (interface_board_present == 0) {
+ return -1;
+ }
+
+ for (i = 0; i < OLED_LINE_CHAR_LENGTH; i++) {
+ ssd130x_buffer_set_tile(gddram, col++, line, tile_data);
+ }
+ /* Update Oled display */
+ return ssd130x_display_full_screen(&display);
+}
+
+void erase_screen_content(void)
+{
+ /* Erase screen data ram */
+ ssd130x_buffer_set(gddram, 0x00);
+}
+
+
+int temp_read(uint32_t uart, int* deci_degrees)
+{
+ int ret = 0;
+
+ if (interface_board_present == 0) {
+ return -1;
+ }
+
+ ret = tmp101_sensor_read(&tmp101_sensor, NULL, deci_degrees);
+ if (ret != 0) {
+ uprintf(uart, "TMP101 read error : %d\n", ret);
+ return -1;
+ }
+ return 0;
+}
+
+
+/***************************************************************************** */
+volatile uint8_t button_pressed = 0;
+void button_callback(uint32_t gpio)
+{
+ switch (gpio) {
+ case GPIO_BUTTON_OK:
+ button_pressed |= BUTTON_OK;
+ break;
+ case GPIO_BUTTON_UP:
+ button_pressed |= BUTTON_UP;
+ break;
+ case GPIO_BUTTON_DOWN:
+ button_pressed |= BUTTON_DOWN;
+ break;
+ case GPIO_BUTTON_LEFT:
+ button_pressed |= BUTTON_LEFT;
+ break;
+ case GPIO_BUTTON_RIGHT:
+ button_pressed |= BUTTON_RIGHT;
+ break;
+ }
+}
+
+int interface_config(uint32_t uart)
+{
+ int ret = 0;
+
+ /* TMP101 sensor config */
+ ret = tmp101_sensor_config(&tmp101_sensor);
+ if (ret != 0) {
+ uprintf(uart, "Temp config error: %d\n", ret);
+ interface_board_present = 0;
+ return -1;
+ }
+ ret = tmp101_sensor_set_continuous_conversion(&tmp101_sensor);
+ if (ret != 0) {
+ uprintf(uart, "Temp config error: %d\n", ret);
+ interface_board_present = 0;
+ return -2;
+ }
+ interface_board_present = 1;
+
+ /* Buttons inputs on front panel */
+ /* Activate on Rising edge (button release) */
+ set_gpio_callback(button_callback, &button_up, EDGE_RISING);
+ set_gpio_callback(button_callback, &button_left, EDGE_RISING);
+ set_gpio_callback(button_callback, &button_right, EDGE_RISING);
+ set_gpio_callback(button_callback, &button_down, EDGE_RISING);
+ set_gpio_callback(button_callback, &button_ok, EDGE_RISING);
+
+ /* WS2812B Leds on display board */
+ ws2812_config(&ws2812_data_out_pin);
+
+ /* Configure and start display */
+ ssd130x_display_on(&display);
+ erase_screen_content();
+ ssd130x_display_full_screen(&display);
+
+ ws2812_set_pixel(0, 0x05, 0x15, 0x08);
+ ws2812_send_frame(0);
+
+ uprintf(uart, "Config OK\n");
+
+ return 0;
+}
+
+
+enum interface_modes {
+ MODE_RUN = 0,
+ MODE_CONFIG,
+ MODE_DISPLAY,
+};
+
+extern int water_centi_degrees;
+extern uint32_t moyenne_solar;
+extern uint32_t moyenne_home;
+extern volatile uint8_t command_val;
+
+static int current_mode = MODE_RUN;
+volatile int manual_activation_request = 0;
+void interface_update(char heat_mode)
+{
+ int abs_centi = water_centi_degrees;
+ uint16_t user_potar = 0;
+
+ if (water_centi_degrees < 0) {
+ abs_centi = -water_centi_degrees;
+ }
+
+ /* Get potentiometer value */
+ adc_get_value(&user_potar, LPC_ADC(7));
+
+ if (current_mode == MODE_RUN) {
+ if (button_pressed & BUTTON_OK) {
+ manual_activation_request = -1;
+ }
+ if (interface_board_present != 0) {
+ char line[DISPLAY_LINE_LENGTH];
+
+ /* Start with a blank screen */
+ erase_screen_content();
+
+ /* Update time and time display on internal memory */
+ rtc_pcf85363_time_read(&rtc_conf, &now);
+ snprintf(line, DISPLAY_LINE_LENGTH, "%02xh%02x:%02x", now.hour, now.min, now.sec);
+ display_line(0, 0, line);
+
+ /* Display info */
+ snprintf(line, DISPLAY_LINE_LENGTH, "Water:% 2d.%03d %cC", (water_centi_degrees / 100), (abs_centi % 100), 0x1F);
+ display_line(2, 0, line);
+ snprintf(line, DISPLAY_LINE_LENGTH, "Prod :% 2d,%03dA", (moyenne_solar / 1000), ((moyenne_solar % 1000) / 10));
+ display_line(3, 0, line);
+ snprintf(line, DISPLAY_LINE_LENGTH, "Conso:% 2d,%03dA", (moyenne_home / 1000), ((moyenne_home % 1000) / 10));
+ display_line(4, 0, line);
+ snprintf(line, DISPLAY_LINE_LENGTH, "Command: %d%%", command_val);
+ display_line(5, 0, line);
+ snprintf(line, DISPLAY_LINE_LENGTH, "Mode: %c", heat_mode);
+ display_line(6, 0, line);
+ /* Update Oled display */
+ ssd130x_display_full_screen(&display);
+ }
+
+ /* Update RGB leds */
+ ws2812_set_pixel(0, (moyenne_home / 2000), (moyenne_solar / 2000), 0);
+ ws2812_set_pixel(1, 0, 0, (user_potar >> 2));
+ ws2812_send_frame(0);
+ }
+
+ if (button_pressed != 0) {
+ uprintf(UART0, "Button : 0x%02x\n", button_pressed);
+ button_pressed = 0;
+ }
+
+}
--- /dev/null
+/****************************************************************************
+ * apps/blyes/relay_lights/interface.h
+ *
+ * Copyright 2018 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include "core/system.h"
+#include "core/pio.h"
+
+#include "extdrv/ssd130x_oled_driver.h"
+
+#define OLED_LINE_CHAR_LENGTH (SSD130x_NB_COL / 8)
+#define DISPLAY_LINE_LENGTH (OLED_LINE_CHAR_LENGTH + 1)
+
+
+/***************************************************************************** */
+/* Pins configuration */
+/* Buttons inputs on front panel */
+extern const struct pio button_up;
+extern const struct pio button_left;
+extern const struct pio button_right;
+extern const struct pio button_down;
+extern const struct pio button_ok;
+
+extern volatile int manual_activation_request;
+
+/* Exported vars */
+extern volatile uint8_t button_pressed;
+#define BUTTON_OK (0x01 << 0)
+#define BUTTON_UP (0x01 << 1)
+#define BUTTON_DOWN (0x01 << 2)
+#define BUTTON_RIGHT (0x01 << 3)
+#define BUTTON_LEFT (0x01 << 4)
+
+/***************************************************************************** */
+/* Configuration */
+/* Configure interface board */
+int interface_config(uint32_t uart);
+
+
+/* Internal Temperature sensor */
+int temp_read(uint32_t uart, int* deci_degrees);
+
+/* Interface content update */
+void interface_update(char mode);
+
+#endif /* INTERFACE_H */
+
--- /dev/null
+/****************************************************************************
+ * apps/scialys/v05/main.c
+ *
+ * Scialys system for solar-panel power generation tracking and fair use.
+ *
+ * Copyright 2016 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+#include "config.h"
+#include "interface.h"
+#include "time.h"
+#include "uSD.h"
+
+
+#define MODULE_VERSION 0x05
+#define MODULE_NAME "Scialys uC"
+
+
+
+/***************************************************************************** */
+/* System configuration */
+
+/* Period (in ms) of the decrementer handler from the systick interrupt */
+#define DEC_PERIOD 100
+/* Period (in ms) of the handler for the command value update */
+#define CMD_UPD_PERIOD 500
+
+/* Max water temperature. Internal protection which cannot be overriden by configuration */
+#define MAX_WATER_TEMP 90
+/* Internal system max temperature : turn off heating when reached */
+#define MAX_INTERNAL_TEMP 80 /* FIXME */
+
+/* Most of the defines in here should go to configuration setting in user flash */
+/* If temperature falls bellow FORCE_HEATER_TEMP value, we enter forced heater mode, until
+ * TARGET_FORCED_HEATER_TEMP is reached.
+ * When in forced heater mode, the heater is controlled to heat at FORCED_MODE_VALUE which
+ * is between 0 and 100.
+ */
+#define FORCE_HEATER_TEMP 30
+#define TARGET_FORCED_HEATER_TEMP 50
+#define FORCED_MODE_VALUE 75 /* A fraction of 100 */
+/* mA prod value above which the system will not enter forced mode, waiting for home
+ * to stop using power to start automatic heating */
+#define SUNNY_DAYS_PROD_VALUE 3000
+
+/* Delay before automatic forced heating */
+#define FORCED_HEATER_DELAY (2 * 3600 * 1000 / DEC_PERIOD)
+/* Duration of automatic forced heating */
+#define FORCED_HEATER_DURATION (3 * 3600 * 1000 / DEC_PERIOD)
+
+/* Duration of manual forced heating */
+#define MANUAL_ACTIVATION_DURATION (3 * 3600 * 1000 / DEC_PERIOD) /* Three hours */
+
+
+uint32_t forced_heater_mode = 0;
+uint32_t forced_heater_delay = 0;
+uint32_t forced_heater_time = 0;
+
+uint8_t error_shutdown = 0;
+
+uint8_t never_force = 0;
+uint32_t sunny_days_prod_value_config = 0;
+
+#define EXTERNAL_DISABLE_FORCE 0 /* Input is pulled low when external disable is ON */
+int external_disable = 0;
+
+enum modes {
+ heat = 'C',
+ ext_disable = 'E',
+ delayed_heat_prod = 'P',
+ forced = 'F',
+ temp_OK = 'T',
+ manual = 'M',
+ idle_heat = 'L',
+ full_heat = 'F',
+};
+
+/* Water and internaltemperature */
+int water_centi_degrees = 0;
+int tmp101_deci_degrees = 0;
+
+/* RTC and time */
+struct rtc_time now;
+
+
+/***************************************************************************** */
+/* Rx interrupt handler for system configuration over USB */
+void config_rx(uint8_t c)
+{
+ /* FAN control */
+ if (c == 'f') {
+ gpio_set(fan_ctrl);
+ } else {
+ gpio_clear(fan_ctrl);
+ }
+}
+
+
+/* Communication with slave modules */
+void comm_rx(uint8_t c)
+{
+}
+
+
+
+/***************************************************************************** */
+/* System communication over UART1 */
+void cmd_rx(uint8_t c)
+{
+}
+
+
+/***************************************************************************** */
+/* Decrementer for heating timers */
+void handle_dec_request(uint32_t curent_tick) {
+ if (manual_activation_request > 0) {
+ manual_activation_request--;
+ }
+ if (forced_heater_mode == 1) {
+ if (forced_heater_delay > 0) {
+ forced_heater_delay--;
+ }
+ if (forced_heater_time > 0) {
+ forced_heater_time--;
+ }
+ }
+}
+
+
+/***************************************************************************** */
+/* Track power production and usage */
+
+/* Average value computed on last 10 ADC values */
+uint32_t moyenne_solar = 0;
+uint32_t moyenne_home = 0;
+/* Last ADC values (snapshot) */
+static uint16_t snapval_solar = 0;
+static uint16_t snapval_home = 0;
+
+#define NB_VAL 20
+static void track_isnail_values(void)
+{
+ static uint16_t isnail_solar_values[NB_VAL];
+ static uint16_t isnail_home_values[NB_VAL];
+ static uint8_t idx = 0;
+
+ /* Get new values */
+ adc_get_value(&snapval_solar, LPC_ADC(1));
+ adc_get_value(&snapval_home, LPC_ADC(0));
+
+ /* Convert to mA value.
+ * ADC range is 0 to 1024 - approx 3.2mV / ADC step
+ * Coil convertion is 1000mA -> 50mV : multily mV value by 20 to get mA value
+ * x * 3.2 * 20 == x * 32 * 2 == x << 6
+ * Increment is 64mA / ADC step */
+ snapval_solar = snapval_solar << 6;
+ snapval_home = snapval_home << 6;
+
+ /* Store value */
+ isnail_solar_values[idx] = snapval_solar;
+ isnail_home_values[idx++] = snapval_home;
+ if (idx == NB_VAL) {
+ idx = 0;
+ }
+
+ /* Compute average once we sampled enough values */
+ if ((idx == 0) || (idx == (NB_VAL / 2))) {
+ int i = 0;
+ moyenne_solar = 0;
+ moyenne_home = 0;
+ for (i = 0; i < NB_VAL; i++) {
+ moyenne_solar += isnail_solar_values[i];
+ moyenne_home += isnail_home_values[i];
+ }
+ moyenne_solar = moyenne_solar / NB_VAL;
+ moyenne_home = moyenne_home / NB_VAL;
+ }
+}
+
+/***************************************************************************** */
+/* AC control */
+
+volatile uint8_t command_val = 0;
+volatile int act_cmd = 0;
+static int fan_on = 0;
+
+void set_ctrl_duty_cycle(uint8_t value)
+{
+ act_cmd = value;
+ /* Below 3% and above 97% there are triggering problems which
+ * lead to 50% instead of desired command */
+ if (act_cmd >= 97) {
+ act_cmd = 97;
+ } else if (act_cmd <= 2) {
+ act_cmd = 0;
+ }
+}
+
+void ac_switch_on(uint32_t flags)
+{
+ gpio_set(ac_ctrl);
+}
+
+static uint32_t clk_cycles_ac_zc = 0;
+volatile uint32_t zc_cnt = 0;
+void zero_cross(uint32_t gpio)
+{
+ uint32_t delay = 0;
+
+ gpio_clear(ac_ctrl);
+ zc_cnt++;
+ if (act_cmd == 0) {
+ return;
+ }
+ /* Set timer to trigger ac out ON at given delay */
+ delay = clk_cycles_ac_zc * (100 - act_cmd);
+ timer_set_match(LPC_TIMER_32B1, CHAN1, delay);
+ timer_restart(LPC_TIMER_32B1);
+}
+
+
+/* Handle the power command */
+#define CMD_UP_DELAY_RESET_VALUE 5
+void handle_cmd_update(uint32_t curent_tick)
+{
+ static uint8_t cmd = 0;
+ static uint8_t cmd_up_delay = CMD_UP_DELAY_RESET_VALUE;
+
+ /* Unable to read internal temperature : turn off heating */
+ if (error_shutdown == 1) {
+ cmd = 0;
+ goto cmd_update_end;
+ }
+
+ /* Water max temperature protection */
+ if (water_centi_degrees > (MAX_WATER_TEMP * 100)) {
+ cmd = 0;
+ goto cmd_update_end;
+ }
+
+ /* Which is the current mode ? */
+ if (forced_heater_mode == 1) {
+ /* Forced heating mode */
+ if ((forced_heater_delay == 0) && (forced_heater_time > 0)) {
+ cmd = FORCED_MODE_VALUE;
+ }
+ /* Entering forced heating mode from temperature getting below threshold,
+ * wait some delay before effective forced heating */
+ if (forced_heater_time == 0) {
+ forced_heater_delay = FORCED_HEATER_DELAY;
+ forced_heater_time = FORCED_HEATER_DELAY + FORCED_HEATER_DURATION;
+ }
+ } else if (moyenne_solar < (moyenne_home - 64)) {
+ /* Low production mode */
+ if (cmd > 0) {
+ cmd--;
+ }
+ } else if (moyenne_solar > (moyenne_home + 1280)) {
+ if (cmd < 100) {
+ cmd++;
+ }
+ } else if (moyenne_solar > (moyenne_home + 192)) {
+ /* High production mode */
+ if (cmd_up_delay > 0) {
+ cmd_up_delay--;
+ } else {
+ cmd_up_delay = CMD_UP_DELAY_RESET_VALUE;
+ if (cmd < 100) {
+ cmd++;
+ }
+ }
+ }
+
+cmd_update_end:
+ command_val = cmd;
+ /* Set Control Output duty cycle */
+ set_ctrl_duty_cycle(100 - cmd);
+}
+
+
+/***************************************************************************** */
+void scialys_config(void)
+{
+ /* We want 100 Hz (50 Hz but two zero crossings) with 1% granularity */
+ clk_cycles_ac_zc = get_main_clock() / (100 * 100);
+
+ /* Read parameters from memory */
+ if (1) {
+ never_force = 0;
+ sunny_days_prod_value_config = SUNNY_DAYS_PROD_VALUE;
+ }
+
+ /* Add a systick callback to handle command value update */
+ add_systick_callback(handle_cmd_update, CMD_UPD_PERIOD);
+
+ /* Add a systick callback to handle time counting */
+ add_systick_callback(handle_dec_request, DEC_PERIOD);
+}
+
+
+/***************************************************************************** */
+int main(void)
+{
+ uint32_t loop = 0;
+ char mode = heat; /* Debug info */
+
+ system_init();
+ board_io_config();
+ modules_config();
+
+ external_config(UART0);
+ scialys_config();
+
+ msleep(1500);
+ status_led(green_only);
+
+ while (1) {
+ uint16_t snapval_load = 0;
+
+ /* Default mode : try to heat the water tank */
+ mode = heat;
+
+ /* Always track power consumption and production */
+ track_isnail_values();
+
+ /* Get load power usage */
+ adc_get_value(&snapval_load, LPC_ADC(2));
+
+ /* Feed the dog */
+ if ((moyenne_solar != 0) && (moyenne_home != 0)) {
+ watchdog_feed();
+ }
+
+ /* Get internal temperature */
+ if (temp_read(UART0, &tmp101_deci_degrees) != 0) {
+ tmp101_deci_degrees = 1500;
+ }
+
+ /* Internal temperature protection */
+ if (tmp101_deci_degrees > (MAX_INTERNAL_TEMP * 10)) {
+ error_shutdown = 1;
+ } else if (tmp101_deci_degrees < ((MAX_INTERNAL_TEMP * 10) / 2)) {
+ error_shutdown = 0;
+ }
+ /* If internal temperature is above 32°C, then turn on fan. Turn off when back to under 28°C */
+ if (tmp101_deci_degrees > 320) {
+ fan_on = 1;
+ gpio_set(fan_ctrl);
+ } else if (tmp101_deci_degrees < 280) {
+ fan_on = 0;
+ gpio_clear(fan_ctrl);
+ }
+
+ /* Get thermocouple value */
+ if (1) {
+ int ret = 0, old_water_temp = 0;
+ old_water_temp = water_centi_degrees;
+ ret = max31855_sensor_read(&thermocouple, NULL, &water_centi_degrees);
+ if (ret != 0) {
+ uprintf(UART0, "Water Temp read error : %d\n", ret);
+ /* Do not act upon iinvalid temp value */
+ water_centi_degrees = old_water_temp;
+ }
+ }
+
+ /* Need to enter Forced heating mode ? */
+ if (water_centi_degrees < (FORCE_HEATER_TEMP * 100)) {
+ if (forced_heater_mode == 0) {
+ uprintf(UART0, "Water temp low, entering forced mode\n");
+ forced_heater_mode = 1;
+ }
+ status_led(red_on);
+ mode = forced;
+ } else if ((water_centi_degrees > (TARGET_FORCED_HEATER_TEMP * 100)) && (forced_heater_mode == 1)) {
+ status_led(red_off);
+ uprintf(UART0, "Water temp OK, forced mode exit\n");
+ forced_heater_mode = 0;
+ mode = temp_OK;
+ }
+
+ /* Do not force if there is a lot of sun, it may be enough to heat again soon */
+ if (moyenne_solar > sunny_days_prod_value_config) {
+ mode = delayed_heat_prod;
+ forced_heater_mode = 0;
+ }
+
+ /* Do not force heating if disabled by external command */
+ external_disable = gpio_read(ext_disable_in_pin);
+ if ((external_disable == EXTERNAL_DISABLE_FORCE) && (forced_heater_mode != 0)) {
+ forced_heater_mode = 0;
+ mode = ext_disable;
+ }
+
+ if (never_force == 1) {
+ forced_heater_mode = 0;
+ }
+
+ /* Did the user request a forced heating ? */
+ if (manual_activation_request != 0) {
+ forced_heater_mode = 1;
+ mode = manual;
+ if (manual_activation_request == -1) {
+ uprintf(UART0, "Entering manual forced mode for %d ticks\n", manual_activation_request);
+ manual_activation_request = MANUAL_ACTIVATION_DURATION;
+ forced_heater_time = FORCED_HEATER_DURATION;
+ }
+ if (manual_activation_request < 10) {
+ uprintf(UART0, "Leaving manual forced mode\n");
+ manual_activation_request = 0;
+ }
+ }
+
+ /* Wait approx 10ms between each loop */
+ msleep(10);
+
+ /* Display */
+ interface_update(mode);
+
+ /* Debug */
+ if (1) {
+ uprintf(UART0, "%c:%d - Is: %d,%04d - Ih: %d,%04d\n", mode, loop++,
+ (moyenne_solar / 1000), (moyenne_solar % 1000),
+ (moyenne_home / 1000), (moyenne_home % 1000));
+ uprintf(UART0, "Water Temp : %d\n", water_centi_degrees);
+ uprintf(UART0, "Internal Temp : %d\n", tmp101_deci_degrees);
+ uprintf(UART0, "ADC: Sol: %dmA, Home: %dmA, Load: %d\n",
+ snapval_solar, snapval_home, snapval_load);
+ uprintf(UART0, "Zc: %d\n", zc_cnt);
+ uprintf(UART0, "CMD: %d/%d, Fan: %d\n\n", command_val, act_cmd, fan_on);
+ }
+
+ }
+ return 0;
+}
+
+
+
--- /dev/null
+/****************************************************************************
+ * apps/blyes/inter_lights/time.c
+ *
+ * Copyright 2018 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include "core/system.h"
+
+#include "drivers/serial.h"
+#include "drivers/i2c.h"
+
+#include "lib/stdio.h"
+#include "lib/errno.h"
+
+#include "time.h"
+
+
+/***************************************************************************** */
+/* RTC */
+struct rtc_pcf85363a_config rtc_conf = {
+ .mode = PCF85363A_MODE_RTC,
+ .config_marker = PCF85363A_CONFIGURED_1,
+ .batt_ctrl = PCF85363A_CONF_BATT_TH_2_8V,
+};
+/* Oldest acceptable time in RTC. BCD coded. */
+const struct rtc_time oldest = {
+ .year = 0x18,
+ .month = 0x08,
+ .day = 0x09,
+ .hour = 0x13,
+ .min = 0x37,
+};
+int time_valid = 0;
+int rtc_conf_ok = 0;
+
+int time_init_check(uint32_t uart)
+{
+ int ret = 0;
+ ret = rtc_pcf85363a_config(&rtc_conf);
+ if (ret < 0) {
+ uprintf(uart, "RTC config error: %d\n", ret);
+ return -1;
+ }
+ rtc_conf_ok = 1;
+
+ ret = rtc_pcf85363a_is_up(&rtc_conf, &oldest);
+ if (ret == 1) {
+ /* Time is valid (newer than source code time) */
+ char buff[30];
+ rtc_pcf85363_time_read(&rtc_conf, &now);
+ rtc_pcf85363_time_to_str(&now, buff, 30);
+ /* Debug */
+ uprintf(uart, "Using time from RTC: %s\n", buff);
+ time_valid = 1;
+ } else if (ret == -EFAULT) {
+ /* Time is older than source code time */
+ time_valid = 0;
+ uprintf(uart, "RTC time too old, provide valid time.\n");
+ /* FIXME: remove this, time should come from control master */
+ memcpy(&now, &oldest, sizeof(struct rtc_time));
+ rtc_pcf85363_time_write(&rtc_conf, &now);
+ } else {
+ /* RTC config error */
+ rtc_conf_ok = 0;
+ }
+ return ret;
+}
+
+
+/***************************************************************************** */
+/* RTC init */
+void time_config(uint32_t i2c_bus_num, uint8_t rtc_addr)
+{
+ rtc_conf.bus_num = i2c_bus_num;
+ rtc_conf.addr = rtc_addr;
+}
+
--- /dev/null
+/****************************************************************************
+ * apps/blyes/inter_lights/time.h
+ *
+ * Copyright 2018 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef RTC_TIME_H
+#define RTC_TIME_H
+
+#include "extdrv/rtc_pcf85363a.h"
+
+extern struct rtc_pcf85363a_config rtc_conf;
+extern struct rtc_time now;
+
+int time_init_check(uint32_t uart);
+void time_config(uint32_t i2c_bus_num, uint8_t rtc_addr);
+
+#endif /* RTC_TIME_H */
+
--- /dev/null
+/****************************************************************************
+ * apps/blyes/inter_lights/uSD.c
+ *
+ * Copyright 2018 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include "core/system.h"
+
+#include "drivers/serial.h"
+#include "drivers/ssp.h"
+
+#include "lib/stdio.h"
+
+#include "uSD.h"
+
+
+/***************************************************************************** */
+/* SD/MMC Card */
+struct sdmmc_card micro_sd = {
+ .card_type = MMC_CARDTYPE_UNKNOWN,
+ .block_size = 64,
+};
+
+static uint8_t got_uSD = 0;
+
+/* Buffer to read / write uSD card */
+uint8_t mmc_data[MMC_BUF_SIZE];
+
+/* Read up to 4 blocks of 16 bytes each */
+int uSD_read(uint32_t offset, uint8_t nb_blocks)
+{
+ int i = 0, ret = 0;
+ if (got_uSD == 0) {
+ return -1;
+ }
+ if (nb_blocks > 4) {
+ return -2;
+ }
+ memset(mmc_data, 0, MMC_BUF_SIZE);
+ for (i = 0; i < nb_blocks; i++) {
+ ret = sdmmc_read_block(µ_sd, (offset + i), (mmc_data + (i * 16)));
+ /* FIXME : check return value */
+ }
+ return 0;
+}
+
+
+/* Write up to 4 blocks of 16 bytes each */
+int uSD_write(uint32_t offset, uint8_t nb_blocks)
+{
+ int i = 0, ret = 0;
+ if (got_uSD == 0) {
+ return -1;
+ }
+ if (nb_blocks > 4) {
+ return -1;
+ }
+ for (i = 0; i < nb_blocks; i++) {
+ ret = sdmmc_write_block(µ_sd, (offset + i), (mmc_data + (i * 16)));
+ /* FIXME : check return value */
+ }
+ return 0;
+}
+
+/* microSD card init */
+int uSD_detect(int uart)
+{
+ int i = 0, ret = 0, step = 0;
+ do {
+ step = 0;
+ ret = sdmmc_init(µ_sd);
+ if (ret == 0) {
+ step = 1;
+ msleep(10);
+ ret = sdmmc_init_wait_card_ready(µ_sd);
+ if (ret <= 1) {
+ step = 2;
+ ret = sdmmc_init_end(µ_sd);
+ }
+ }
+ uprintf(uart, "uSD init(%d): step:%d, ret: %d, type: %d, bs: %d\n",
+ i, step, ret, micro_sd.card_type, micro_sd.block_size);
+ i++;
+ } while (((ret != 0) || (micro_sd.card_type == MMC_CARDTYPE_UNKNOWN)) && (i < 10));
+
+ /* Got uSD ? */
+ if (i >= 10) {
+ uprintf(uart, "uSD init failed, no uSD card present.\n");
+ got_uSD = 0;
+ return -1;
+ }
+
+ /* uSD card detected */
+ got_uSD = 1;
+ /* got_uSD MUST be set to 1 from here on ! */
+ uSD_read(0, 4); /* Read 4 blocks at start of card */
+ /* FIXME : check that the card magic is present */
+ uprintf(uart, "uSD read: %s\n", mmc_data);
+
+ return 0;
+}
+
+
+int uSD_logs_init(int uart)
+{
+ /* FIXME : read 4 blocks at offset FIXME to get the last block used info */
+ return 0;
+}
+
+/***************************************************************************** */
+/* microSD card init */
+void uSD_config(struct pio* uSD_cs, uint32_t ssp_bus_num)
+{
+ memcpy(&(micro_sd.chip_select), uSD_cs, sizeof(struct pio));
+ micro_sd.ssp_bus_num = ssp_bus_num;
+}
+
--- /dev/null
+/****************************************************************************
+ * apps/blyes/inter_lights/usSD.h
+ *
+ * Copyright 2018 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef USD_H
+#define USD_H
+
+#include "extdrv/sdmmc.h"
+
+#define MMC_BUF_SIZE 64
+
+extern struct sdmmc_card micro_sd;
+extern uint8_t mmc_data[MMC_BUF_SIZE];
+
+int uSD_read(uint32_t offset, uint8_t nb_blocks);
+int uSD_write(uint32_t offset, uint8_t nb_blocks);
+
+/***************************************************************************** */
+/* microSD card init */
+int uSD_detect(int uart);
+void uSD_config(struct pio* uSD_cs, uint32_t ssp_bus_num);
+
+
+#endif /* USD_H */
+