Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/embedded'
Browse files Browse the repository at this point in the history
  • Loading branch information
giuliocorradini committed Mar 21, 2021
2 parents 1393d7e + c412236 commit 63acce6
Show file tree
Hide file tree
Showing 15 changed files with 498 additions and 72 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
tools/venv/*

.idea
Empty file removed examples/.keep
Empty file.
35 changes: 35 additions & 0 deletions examples/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "edstream.h"
#include "edstream_hal.h"

#include <ssd1306.h>

#define LOG_LOCAL_LEVEL ESP_LOG_ERROR
#include "esp_log.h"

void receiver(void *pvParameters)
{
struct eds_hal_config eds_hal_conf = eds_hal_default();
eds_hal_init(&eds_hal_conf);

ssd1306_128x64_i2c_init();

ssd1306_clearScreen();

uint8_t cmd[512];
int read;

while(true) {
vTaskDelay(1);
read = eds_hal_recv(cmd, 512);
if (read <= 0) continue;
ESP_LOGD("RX", "Read bytes: %d", read);
eds_decode_message(cmd, read);
}

vTaskDelete(NULL);
}

void app_main()
{
xTaskCreate(receiver, "receiver", 8192, NULL, 0, NULL); // Yep, this is a huge amount of memory
}
30 changes: 19 additions & 11 deletions include/edstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,37 @@
*/

// Receiver should save this frame (as part of animation)
#define PROTOCOL_SAVE_FRAME (0x01 << 0)
#define PROTOCOL_SAVE_FRAME (0x01 << 0)
// Sent frame is zipped
#define PROTOCOL_ZIPPED_FRAME (0x01 << 1)
#define PROTOCOL_ZIPPED_FRAME (0x01 << 1)

// This msg. sets the refresh rate of the animation. Expected payload
// is 1 byte with refresh rate in milliseconds (as uint8_t)
#define PROTOCOL_SET_FREQ (0x01 << 2)
#define PROTOCOL_SET_FREQ (0x01 << 2)

// XOR function. If set starts/stops the animation. No payload is
// expected
#define PROTOCOL_TOGGLE_ANIMATION (0x01 << 3)

// Clear animation buffer
#define PROTOCOL_CLEAR_BUF (0x01 << 4)
#define PROTOCOL_CLEAR_BUF (0x01 << 4)

#define PROTOCOL_QUERY (0x01 << 7)
#define PROTOCOL_QUERY (0x01 << 7)

#define QUERY_IS_ANIMATION_RUNNING 0x01
#define QUERY_SUPPORTED_FX 0x02
#define QUERY_BUFFER_SIZE 0x03
#define QUERY_IS_ANIMATION_RUNNING (0x01)
#define QUERY_SUPPORTED_FX (0x02)
#define QUERY_BUFFER_SIZE (0x03)

#define RESPONSE_ACK (0xff)

#define FRAME_SIZE (1024)
#define MAX_FRAME_NUMBER (14)

/*
* Controller functions
*/

int eds_send_frame(uint8_t *frame, bool save, bool zip);
int eds_send_frame(const uint8_t *frame, bool save, bool zip);
int eds_start_animation();
int eds_stop_animation();

Expand All @@ -43,13 +48,16 @@ bool eds_query_animation_status();
typedef void(*eds_zip_function_t)(uint8_t *src, uint8_t *dst, int *pl_size);
void eds_zip_function_set(eds_zip_function_t f);
void eds_zip_deflate(uint8_t *src, uint8_t *dst, int *pl_size);
eds_zip_function_t eds_zip_function = eds_zip_deflate;

/*
* Device functions
*/

// Callback function to decode messages
int eds_decode_message(uint8_t *payload, int i);
int eds_decode_message(const uint8_t *payload, int i);

int eds_send_ack(void);
void eds_toggle_animation(void);
void eds_clear_framebuffer(void);

#endif //__EDSTREAM_H
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ platform = espressif32
board = esp32doit-devkit-v1
framework = espidf
monitor_speed = 115200
monitor_filter = direct
monitor_filters = direct
135 changes: 113 additions & 22 deletions src/edstream.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
#include <string.h>

#include "edstream.h"
#include "edstream_hal.h"

#define LOG_LOCAL_LEVEL ESP_LOG_NONE
#include "esp_log.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include <string.h>

static bool is_animation_running = false;
static int refresh_rate = 33; // ms
static eds_zip_function_t eds_zip_function = eds_zip_deflate;

static uint8_t framebuffer[FRAME_SIZE * MAX_FRAME_NUMBER];
static int framebuffer_size = 0;

/*
* @brief Sends a frame to display device (that controls the display)
Expand All @@ -14,7 +25,8 @@ static bool is_animation_running = false;
*
* You can provide a Deflate function with eds_zip_function_set()
*/
int eds_send_frame(uint8_t *frame, bool save, bool zip) {
int eds_send_frame(const uint8_t *frame, bool save, bool zip)
{
uint8_t message[1025];
message[0] =
save ? PROTOCOL_SAVE_FRAME : 0 |
Expand All @@ -30,49 +42,95 @@ int eds_send_frame(uint8_t *frame, bool save, bool zip) {
return 0;
}

bool eds_query_animation_status() {
uint16_t message = PROTOCOL_QUERY << 16 + QUERY_IS_ANIMATION_RUNNING;
bool eds_query_animation_status()
{
uint16_t message = (PROTOCOL_QUERY << 16) + QUERY_IS_ANIMATION_RUNNING;
eds_hal_send(&message, 2);

eds_hal_recv(&is_animation_running, 1);

return is_animation_running;
}

int eds_start_animation() {
void eds_show_animation_task(void* pvParameters)
{
int local_frame_counter = 0;
ESP_LOGD("SHOW", "Entering while loop");
while (is_animation_running) {
eds_hal_display_show(framebuffer + local_frame_counter*FRAME_SIZE);
local_frame_counter++;
local_frame_counter %= framebuffer_size;
vTaskDelay(refresh_rate/portTICK_PERIOD_MS);
}
ESP_LOGD("SHOW", "Exiting while loop of show_animation_task");
vTaskDelete(NULL);
}

int eds_start_animation()
{
if(!is_animation_running) {
eds_hal_send(PROTOCOL_TOGGLE_ANIMATION, 1);
ESP_LOGD("START", "Start automation");
// eds_hal_send(PROTOCOL_TOGGLE_ANIMATION, 1);
is_animation_running = true;
xTaskCreate(eds_show_animation_task, "show_animation_task", 8192, NULL, 5, NULL); // TODO: Guru meditation error
}
return 0;
}
int eds_stop_animation() {

int eds_stop_animation()
{
if(is_animation_running) {
eds_hal_send(PROTOCOL_TOGGLE_ANIMATION, 1);
is_animation_running = false;
// eds_hal_send(PROTOCOL_TOGGLE_ANIMATION, 1);
is_animation_running = false; // show_animation_task exits from loop and destroys himself
}
return 0;
}

int eds_send_ack(void)
{
ESP_LOGD("ACK", "Sending ACK to controller");
return eds_hal_send_byte(RESPONSE_ACK);
}

void eds_toggle_animation(void)
{
ESP_LOGD("TOGGLE", "toggle animation");
if (is_animation_running)
eds_stop_animation();
else
eds_start_animation();
}

void eds_clear_framebuffer(void)
{
framebuffer_size = 0;
}


enum eds_fsm_states {
FSM_WAIT_MESSAGE,
FSM_NEW_MESSAGE,
FSM_QUERY,
FSM_CONTROL,
FSM_RECV_FRAME,
FSM_CLEAR_BUF,
FSM_TOGGLE_ANIMATION,
FSM_SAVE_FRAME,
FSM_MAX_STATES
};

static int eds_fsm_state = FSM_WAIT_MESSAGE;
static uint8_t current_frame[1024];

/*
* @return 0 on no error
*/
int eds_decode_message(uint8_t *payload, int n) {
int eds_decode_message(const uint8_t *payload, int n)
{
int i = 0; //consumed bytes
static int received_frame_bytes = 0;
static int frame_counter = 0;
bool is_zipped = false;

ESP_LOGI("FSM", "Called FSM with %d bytes of payload", n);

while(i < n) {
switch(eds_fsm_state) {
Expand All @@ -81,16 +139,21 @@ int eds_decode_message(uint8_t *payload, int n) {
break;

case FSM_NEW_MESSAGE:
if(payload[i] && PROTOCOL_QUERY) {
if (payload[i] & PROTOCOL_QUERY) {
eds_fsm_state = FSM_QUERY;
i++;
} else if (payload[i] >= PROTOCOL_SET_FREQ) {
} else if (payload[i] & PROTOCOL_CLEAR_BUF) {
eds_fsm_state = FSM_CLEAR_BUF;
} else if (payload[i] & PROTOCOL_TOGGLE_ANIMATION) {
eds_fsm_state = FSM_TOGGLE_ANIMATION;
} else if (payload[i] & PROTOCOL_SET_FREQ) {
eds_fsm_state = FSM_CONTROL;
} else if (payload[i] & PROTOCOL_SAVE_FRAME) {
eds_fsm_state = FSM_SAVE_FRAME;
} else {
eds_fsm_state = FSM_RECV_FRAME;
received_frame_bytes = 0;
i++;
eds_fsm_state = FSM_WAIT_MESSAGE;
}
ESP_LOGD("FSM", "Payload is i-1]: %x [i]: %x and next state will be %d\n", payload[i-1], payload[i], eds_fsm_state);
eds_send_ack();
break;

case FSM_QUERY:
Expand All @@ -101,20 +164,48 @@ int eds_decode_message(uint8_t *payload, int n) {
eds_hal_send_byte(10);

if(payload[i] == QUERY_SUPPORTED_FX)
eds_hal_send_byte(0x00); // still dummy
eds_hal_send_byte(0x00);

i++;
eds_fsm_state = FSM_WAIT_MESSAGE;
break;

case FSM_RECV_FRAME:
current_frame[received_frame_bytes++] = payload[i++];
framebuffer[(received_frame_bytes++) + (FRAME_SIZE*frame_counter)] = payload[i++];
ESP_LOGD("FSM", "Bytes counter: %d", received_frame_bytes);
if(received_frame_bytes == 1024) {
eds_hal_display_show(current_frame);
ESP_LOGI("FSM", "Saved...");
eds_fsm_state = FSM_WAIT_MESSAGE;
framebuffer_size++;
frame_counter++;
eds_send_ack();
}
break;

case FSM_CLEAR_BUF:
ESP_LOGD("FSM", "Clear buffer");
frame_counter = 0;
eds_clear_framebuffer();
eds_fsm_state = FSM_WAIT_MESSAGE;
i++;
break;

case FSM_TOGGLE_ANIMATION:
ESP_LOGD("FSM", "Toggle animation");
eds_toggle_animation();
eds_fsm_state = FSM_WAIT_MESSAGE;
i++;
break;

case FSM_SAVE_FRAME:
ESP_LOGD("FSM", "Save frame");
is_zipped = payload[i] & PROTOCOL_ZIPPED_FRAME;
i++;
received_frame_bytes = 0;
eds_fsm_state = FSM_RECV_FRAME;
ESP_LOGD("FSM", "Exiting from save frame state");
break;

default:
eds_fsm_state = FSM_WAIT_MESSAGE;
}
Expand Down
55 changes: 55 additions & 0 deletions src/edstream_hal.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* EDStream HAL implementation
* (c) 2021 - Project EDStream
*
* ESP32 I2C_0 and UART_0
*/

#include "edstream_hal.h"

#define LOG_LOCAL_LEVEL ESP_LOG_NONE
#include "esp_log.h"
#include "ssd1306.h"
#include "driver/uart.h"

static struct eds_hal_config configuration;

static uint8_t uart_num_mem;
static QueueHandle_t queue_handle;

void eds_hal_init(const struct eds_hal_config *config) {

configuration = *config;

// I2C
ssd1306_platform_i2cConfig_t cfg = {
.sda = config->i2c_pins.sda,
.scl = config->i2c_pins.scl
};
ssd1306_platform_i2cInit(config->i2c_num, 0, &cfg);

// UART
ESP_ERROR_CHECK(uart_param_config(config->uart_num, &(config->uart_conf)));
ESP_ERROR_CHECK(uart_set_pin(config->uart_num, config->uart_pins.tx, config->uart_pins.rx, config->uart_pins.rts, config->uart_pins.cts));
ESP_ERROR_CHECK(uart_driver_install(config->uart_num, config->uart_buf_size, config->uart_buf_size, 10, &queue_handle, 0));
uart_num_mem = config->uart_num;
}

int eds_hal_send_byte(uint8_t x) {
return eds_hal_send(&x, 1);
}

int eds_hal_send(const uint8_t *src, int n) {
size_t res = uart_write_bytes(uart_num_mem, (const char*) src, n);
uart_wait_tx_done(uart_num_mem, 100); // timeout of 100 ticks
return res;
}

int eds_hal_recv(uint8_t *dst, int n) {
return uart_read_bytes(UART_NUM_0, dst, n, 100 / portTICK_RATE_MS);
}

int eds_hal_display_show(const uint8_t *frame) {
ssd1306_drawBuffer(0, 0, OLED_W, OLED_H, frame);
return 0;
}
Loading

0 comments on commit 63acce6

Please # to comment.