diff --git a/src/06-mini-project/daemon/application/app.c b/src/06-mini-project/daemon/application/app.c new file mode 100644 index 0000000..8db9765 --- /dev/null +++ b/src/06-mini-project/daemon/application/app.c @@ -0,0 +1,138 @@ +#include "app.h" +#include "sysfs.h" + +#include +#include +#include + +static led_t* led; + +/* Threads objects */ +static pthread_t anim_thread_id; +static pthread_mutex_t anim_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t anim_condition = PTHREAD_COND_INITIALIZER; // SHARED RESOURCES + +/* The counter of pending animations */ +static int pending_animations = 0; // SHARED RESOURCES +static int keep_running = 1; + +void btn_set_led(led_t* l) { + if (l != NULL) { + led = l; + } +} + +void set_period(uint32_t period_ms){ + sysfs_set_period(period_ms); +} + +uint32_t get_period() { + return sysfs_get_period(); +} + +void increase_period() { + uint32_t current_period = sysfs_get_period(); + set_period(current_period + GAP_PERIOD_MS); +} + +void decrease_period() { + uint32_t current_period = sysfs_get_period(); + set_period(current_period - GAP_PERIOD_MS); +} + +int get_mode() { + return sysfs_get_mode(); +} + +void set_mode(int mode) { + sysfs_set_mode(mode); +} + +void mode_toggle() { + int current_mode = sysfs_get_mode(); + set_mode(current_mode ^ 1); +} + +float get_temperature() { + return sysfs_get_temperature(); +} + + +/** + * animation_worker() - The single thread that processes the queue + */ +static void* animation_worker(void* arg) { + while (keep_running) { + // ENTER CRITICAL SECTION + pthread_mutex_lock(&anim_lock); + + /* + * As long as there are no animations to do, the thread sleeps here. + * It consumes 0% CPU while waiting. + */ + while (pending_animations == 0 && keep_running) { + /* + * Wait signal to make animation. + * The function unlocks the mutex to allow another process to add an animation. + * The function forces the thread to sleep until a signal is received. + */ + pthread_cond_wait(&anim_condition, &anim_lock); + } + + if (!keep_running) { + pthread_mutex_unlock(&anim_lock); + break; + } + + /* We take one animation from the queue */ + pending_animations--; + + pthread_mutex_unlock(&anim_lock); + // LEAVE CRITICAL SECTION + + /* Perform the visual task */ + if (led != NULL) { + led_on(led); + usleep(150000); + led_off(led); + usleep(100000); /* Small delay between consecutive pulses */ + } + } + return NULL; +} + + +/** + * init_animations() - To be called once during daemon startup + */ +void init_animations(void) { + pthread_create(&anim_thread_id, NULL, animation_worker, NULL); + +} + +/** + * trigger_pulse() - Increments the counter and wakes up the thread + */ +static void trigger_pulse(void) { + + // ENTER CRITICAL SECTION + pthread_mutex_lock(&anim_lock); + + pending_animations++; + + /* Signal the thread that there is work to do */ + pthread_cond_signal(&anim_condition); + + pthread_mutex_unlock(&anim_lock); + // LEAVE CRITICAL SECTION +} + +void btn_increase_period() { + trigger_pulse(); + increase_period(); +} + +void btn_decrease_period() { + trigger_pulse(); + decrease_period(); +} diff --git a/src/06-mini-project/daemon/application/app.h b/src/06-mini-project/daemon/application/app.h new file mode 100644 index 0000000..37f6669 --- /dev/null +++ b/src/06-mini-project/daemon/application/app.h @@ -0,0 +1,37 @@ +#ifndef APP_H +#define APP_H + +#include + +#include "../gpio/led.h" + +#define DEFAULT_PERIOD_MS 1000 + +#define GAP_PERIOD_MS 50 + +/* --- Period functions --- */ +void increase_period(); +void decrease_period(); +void set_period(uint32_t period_ms); +uint32_t get_period(); + + +/* --- Mode functions --- */ +void mode_toggle(); +void set_mode(int mode); +int get_mode(); + + +/* --- Temperature functions --- */ +float get_temperature(); + + +/* --- Button specific function --- */ + +void btn_set_led(led_t* l); +void init_animations(void); + +void btn_increase_period(); +void btn_decrease_period(); + +#endif /* APP_H */ diff --git a/src/06-mini-project/daemon/logic/sysfs.c b/src/06-mini-project/daemon/application/sysfs.c similarity index 86% rename from src/06-mini-project/daemon/logic/sysfs.c rename to src/06-mini-project/daemon/application/sysfs.c index d591b85..90346ae 100644 --- a/src/06-mini-project/daemon/logic/sysfs.c +++ b/src/06-mini-project/daemon/application/sysfs.c @@ -5,7 +5,7 @@ -float get_temperature() { +float sysfs_get_temperature() { FILE *f = fopen(PATH_TEMPERATURE, "r"); if (f == NULL) { return 0.0f; /* Return 0.0 if the kernel module is not loaded */ @@ -26,7 +26,7 @@ float get_temperature() { return 0.0f; } -uint32_t get_mode() { +uint32_t sysfs_get_mode() { FILE *f = fopen(PATH_MODE, "r"); if (f == NULL) return 0; @@ -37,7 +37,7 @@ uint32_t get_mode() { return mode; } -void set_mode(uint32_t mode) { +void sysfs_set_mode(uint32_t mode) { FILE *f = fopen(PATH_MODE, "w"); if (f == NULL) return; @@ -46,7 +46,7 @@ void set_mode(uint32_t mode) { fclose(f); } -uint32_t get_period() { +uint32_t sysfs_get_period() { FILE *f = fopen(PATH_PERIOD_ST, "r"); if (f == NULL) return 0; @@ -57,7 +57,7 @@ uint32_t get_period() { return period; } -void set_period(uint32_t period) { +void sysfs_set_period(uint32_t period) { FILE *f = fopen(PATH_PERIOD_SET, "w"); if (f == NULL) return; diff --git a/src/06-mini-project/daemon/logic/sysfs.h b/src/06-mini-project/daemon/application/sysfs.h similarity index 72% rename from src/06-mini-project/daemon/logic/sysfs.h rename to src/06-mini-project/daemon/application/sysfs.h index 7de8b32..40c0505 100644 --- a/src/06-mini-project/daemon/logic/sysfs.h +++ b/src/06-mini-project/daemon/application/sysfs.h @@ -10,11 +10,11 @@ #define PATH_PERIOD_ST SYSFS_BASE_PATH "/period_status" #define PATH_PERIOD_SET SYSFS_BASE_PATH "/period_set" -float get_temperature(); -uint32_t get_mode(); -void set_mode(uint32_t mode); -uint32_t get_period(); -void set_period(uint32_t period); +float sysfs_get_temperature(); +uint32_t sysfs_get_mode(); +void sysfs_set_mode(uint32_t mode); +uint32_t sysfs_get_period(); +void sysfs_set_period(uint32_t period); #endif /* SYSFS_H */ diff --git a/src/06-mini-project/daemon/logic/app.c b/src/06-mini-project/daemon/logic/app.c deleted file mode 100644 index 8384780..0000000 --- a/src/06-mini-project/daemon/logic/app.c +++ /dev/null @@ -1 +0,0 @@ -#include "app.h" diff --git a/src/06-mini-project/daemon/logic/app.h b/src/06-mini-project/daemon/logic/app.h deleted file mode 100644 index df277c3..0000000 --- a/src/06-mini-project/daemon/logic/app.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef APP_H -#define APP_H - -#include "../gpio/led.h" - -#define DEFAULT_PERIOD_MS 1000 - -void set_led( - -void increase_period(); -void decrease_period(); -void set_period(int period_ms); - -void mode_toggle(); -void set_mode(int mode); - -float get_temperature(); - - -/* Button specific function */ - -void btn_increase_period(); -void btn_decrease_period(); - -#endif /* APP_H */ diff --git a/src/06-mini-project/daemon/main.c b/src/06-mini-project/daemon/main.c index 98c632b..e03ff0d 100644 --- a/src/06-mini-project/daemon/main.c +++ b/src/06-mini-project/daemon/main.c @@ -14,38 +14,12 @@ #include "gpio/led.h" #include "gpio/button.h" #include "ipc/ipc_server.h" +#include "oled/oled.h" +#include "application/app.h" #define DEFAULT_TIME_MS 1000 #define DUTY_CYCLE_PERCENT 2 -void set_mode(int mode) { - printf("set_mode: %d\n", mode); -} - -void set_period(int period) { - printf("set_period: %d\n", period); -} - -uint32_t get_period() { - printf("get_period\n"); - return 200; -} - -void period_inc() { - printf("period_inc\n"); -} - -void period_dec() { - printf("period_dec\n"); -} - -void period_reset() { - printf("period_reset\n"); -} - -void get_temp() { - printf("get_temp\n"); -} int main(void) { @@ -56,23 +30,34 @@ int main(void) { led_t* led_power = led_init(LED_POWER); - btn_set_callback(btn_inc, period_inc); - btn_set_callback(btn_dec, period_dec); - btn_set_callback(btn_mode, period_reset); + btn_set_callback(btn_inc, btn_decrease_period); + btn_set_callback(btn_dec, btn_decrease_period); + btn_set_callback(btn_mode, set_mode); struct ipc_callbacks_t ipc_cbs = { - .on_dec_frequency = period_dec, - .on_inc_frequency = period_inc, - .on_set_frequency = set_period, + .on_dec_frequency = decrease_period, + .on_inc_frequency = increase_period, + // .on_set_frequency = set_period, .on_set_mode = set_mode, }; + struct oled_callbacks_t oled_cbs = { + .get_mode = get_mode, + .get_period = get_period, + .get_temperature = get_temperature, + }; + int ret = start_ipc_server(&ipc_cbs); if (ret < 0) { fprintf(stderr, "Failed to start IPC server: %d\n", ret); return 1; } + init_oled(&oled_cbs); + + btn_set_led(led_power); + init_animations(); + while (1) { sleep(1); } diff --git a/src/06-mini-project/daemon/oled/oled.c b/src/06-mini-project/daemon/oled/oled.c index f4be528..d92aae5 100644 --- a/src/06-mini-project/daemon/oled/oled.c +++ b/src/06-mini-project/daemon/oled/oled.c @@ -26,26 +26,26 @@ static void display(int mode, float temp, uint32_t period_ms) { /* Static header rows */ ssd1306_set_position(0, 0); ssd1306_puts("CSEL1a - SP.07"); - ssd1306_set_position(0, 1); - ssd1306_puts(" WATCHDOG CPU "); - ssd1306_set_position(0, 2); - ssd1306_puts("--------------"); + // ssd1306_set_position(0, 1); + // ssd1306_puts(" WATCHDOG CPU "); + // ssd1306_set_position(0, 2); + // ssd1306_puts("--------------"); - /* Mode display: switches between AUTO and MANU strings */ - ssd1306_set_position(0, 3); - snprintf(buffer, sizeof(buffer), "Mode: %s", mode ? "AUTO" : "MANU"); - ssd1306_puts(buffer); + // /* Mode display: switches between AUTO and MANU strings */ + // ssd1306_set_position(0, 3); + // snprintf(buffer, sizeof(buffer), "Mode: %s", mode ? "AUTO" : "MANU"); + // ssd1306_puts(buffer); - /* Temperature display: formatted with one decimal precision */ - ssd1306_set_position(0, 4); - snprintf(buffer, sizeof(buffer), "Temp: %.1f'C", temp); - ssd1306_puts(buffer); + // /* Temperature display: formatted with one decimal precision */ + // ssd1306_set_position(0, 4); + // snprintf(buffer, sizeof(buffer), "Temp: %.1f'C", temp); + // ssd1306_puts(buffer); - /* Period/Frequency display: shows the value in milliseconds */ - ssd1306_set_position(0, 5); - float freq = 1.0f / (period_ms / 1000.0f); - snprintf(buffer, sizeof(buffer), "Freq: %.1fHz", freq); - ssd1306_puts(buffer); + // /* Period/Frequency display: shows the value in milliseconds */ + // ssd1306_set_position(0, 5); + // float freq = 1.0f / (period_ms / 1000.0f); + // snprintf(buffer, sizeof(buffer), "Freq: %.1fHz", freq); + // ssd1306_puts(buffer); } /** @@ -65,7 +65,7 @@ static void *update_oled_thread(void* arg) { ); } /* Sleep to control refresh rate and save CPU cycles */ - usleep(250000); + usleep(1000000); } return NULL; } diff --git a/src/06-mini-project/daemon/oled/ssd1306.c b/src/06-mini-project/daemon/oled/ssd1306.c index a8e7195..a111f49 100644 --- a/src/06-mini-project/daemon/oled/ssd1306.c +++ b/src/06-mini-project/daemon/oled/ssd1306.c @@ -14,11 +14,11 @@ #define ARRAY_OF(x) (sizeof(x)/sizeof(x[0])) -#define I2C_BUS "/dev/i2c-0" -#define OLED_ADDR 0x3c +#define I2C_BUS "/dev/i2c-1" +#define OLED_ADDR 0x3c #define OLED_COMMAND_MODE 0x00 -#define OLED_DATA_MODE 0x40 -#define OLED_DISPLAY_OFF_CMD 0xae +#define OLED_DATA_MODE 0x40 +#define OLED_DISPLAY_OFF_CMD 0xae #define OLED_DISPLAY_ON_CMD 0xaf static const uint8_t font[][8] = { @@ -163,7 +163,7 @@ static void send_command(uint8_t cmd) } } -void send_data(uint8_t byte) +void send_data(uint8_t byte) { uint8_t buf[2] = { [0] = OLED_DATA_MODE, @@ -181,7 +181,7 @@ void ssd1306_set_position (uint32_t column, uint32_t row) send_command(0x10 + ((8*column>>4)&0x0f)); //set column higher address } -void ssd1306_putc(char c) +void ssd1306_putc(char c) { if ((c<32) || (c>127)) // Ignore non-printable ASCII characters c=' '; @@ -193,7 +193,7 @@ void ssd1306_putc(char c) } } -void ssd1306_puts(const char* str) +void ssd1306_puts(const char* str) { while (*str != 0) ssd1306_putc(*str++); @@ -203,7 +203,7 @@ void ssd1306_clear_display() { send_command(OLED_DISPLAY_OFF_CMD);// display off for (int j=0; j<8; j++) { - ssd1306_set_position(0,j); + ssd1306_set_position(0,j); for (int i=0; i<16; i++) //clear all columns ssd1306_putc(' '); } @@ -218,7 +218,7 @@ int ssd1306_init() printf("ERROR: unable to open i2c bus interface (%s)\n", I2C_BUS); return -1; } - if (ioctl(fd, I2C_SLAVE, OLED_ADDR) < 0) { + if (ioctl(fd, I2C_SLAVE, OLED_ADDR) < 0) { printf("ERROR: unable to access OLED as slave\n"); return -1; } @@ -231,6 +231,3 @@ int ssd1306_init() return 0; } - - -