562 lines
22 KiB
C

#include "ssd1306.h"
#include "ssd1306_const.h"
uint8_t ssd1306_logo[8][64] = {
{0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0xEF, 0xEF, 0xEF, 0xEF, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x9F, 0x5F, 0x6F, 0xE7, 0xF3, 0xF9, 0xF9, 0xFB,
0xF7, 0xE7, 0xCF, 0x9F, 0xBF, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0x3F, 0x9F, 0xDF,
0xCF, 0xE7, 0xF3, 0xF9, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF9, 0xF3, 0xF7, 0x67, 0x0F, 0x1F, 0x3F, 0x7F,
0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0x7F, 0x3F, 0x80, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFE, 0x3F, 0x1F, 0x1F,
0x0F, 0x07, 0x07, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x03, 0x03, 0x07, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFB, 0xF9, 0xFC, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF,
0xFE, 0xFC, 0xF9, 0xF3, 0xF7, 0xEF, 0xCF, 0x9F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0x00, 0xFE, 0x7F, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0x7F, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F,
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFC, 0xFC, 0xFE, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFC, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xF0, 0xE0,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xFC, 0x9E, 0x1F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFE, 0xFC, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0x78, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF,
0xDF, 0xDF, 0xDF, 0xDF, 0xD0, 0xC0, 0xC0, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC0, 0xC0,
0xD0, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF,
0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
};
static i2c_ssd1306_handle_t i2c_ssd1306;
static i2c_master_bus_handle_t i2c_master_bus;
/* I2C Master */
static const i2c_master_bus_config_t i2c_master_bus_config = {
.i2c_port = I2C_NUM_0,
.scl_io_num = GPIO_NUM_22,
.sda_io_num = GPIO_NUM_21,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true};
/* SSD1306 */
static const i2c_ssd1306_config_t i2c_ssd1306_config = {
.i2c_device_address = 0x3C,
.i2c_scl_speed_hz = 400000,
.width = 128,
.height = 64,
.wise = SSD1306_BOTTOM_TO_TOP};
void init_ssd1306(void)
{
i2c_new_master_bus(&i2c_master_bus_config, &i2c_master_bus);
i2c_ssd1306_init(i2c_master_bus, i2c_ssd1306_config, &i2c_ssd1306);
i2c_ssd1306_buffer_image(&i2c_ssd1306, 32, 0, (const uint8_t *)ssd1306_logo, 64, 64, false);
i2c_ssd1306_buffer_to_ram(&i2c_ssd1306);
vTaskDelay(1000 / portTICK_PERIOD_MS);
i2c_ssd1306_buffer_clear(&i2c_ssd1306);
}
esp_err_t ssd1306_print_str(uint8_t x, uint8_t y, const char *text, bool invert)
{
return (i2c_ssd1306_buffer_text(&i2c_ssd1306, x, y, text, invert));
}
esp_err_t ssd1306_display(void)
{
return (i2c_ssd1306_buffer_to_ram(&i2c_ssd1306));
}
esp_err_t ssd1306_clear_screen(void)
{
return (i2c_ssd1306_buffer_clear(&i2c_ssd1306));
}
esp_err_t i2c_ssd1306_init(i2c_master_bus_handle_t i2c_master_bus, i2c_ssd1306_config_t i2c_ssd1306_config, i2c_ssd1306_handle_t *i2c_ssd1306)
{
if (i2c_ssd1306_config.i2c_scl_speed_hz > 400000 || i2c_ssd1306_config.width > 128 || i2c_ssd1306_config.height % 8 != 0 || i2c_ssd1306_config.height < 16 || i2c_ssd1306_config.height > 64)
{
ESP_LOGE(SSD1306_TAG, "Invalid SSD1306 configuration, 'i2c_scl_speed_hz' must be less than or equal to 400000, 'width' must be less than or equal to 128, 'height' must be between 16 and 64 and multiple of 8");
return ESP_ERR_INVALID_ARG;
}
ESP_LOGI(SSD1306_TAG, "Initializing I2C SSD1306...");
esp_err_t ret = i2c_master_probe(i2c_master_bus, i2c_ssd1306_config.i2c_device_address, I2C_SSD1306_TIMEOUT_MS / portTICK_PERIOD_MS);
if (ret != ESP_OK)
{
switch (ret)
{
case ESP_ERR_NOT_FOUND:
ESP_LOGE(SSD1306_TAG, "I2C SSD1306 device not found in address 0x%02X", i2c_ssd1306_config.i2c_device_address);
break;
case ESP_ERR_TIMEOUT:
ESP_LOGE(SSD1306_TAG, "I2C SSD1306 device timeout in address 0x%02X", i2c_ssd1306_config.i2c_device_address);
break;
default:
ESP_LOGE(SSD1306_TAG, "I2C SSD1306 device error in address 0x%02X", i2c_ssd1306_config.i2c_device_address);
break;
}
return ret;
}
i2c_device_config_t i2c_device_config = {
.dev_addr_length = I2C_ADDR_BIT_7,
.device_address = i2c_ssd1306_config.i2c_device_address,
.scl_speed_hz = i2c_ssd1306_config.i2c_scl_speed_hz};
ret = i2c_master_bus_add_device(i2c_master_bus, &i2c_device_config, &i2c_ssd1306->i2c_master_dev);
if (ret != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to add I2C SSD1306 device");
return ret;
}
uint8_t ssd1306_init_cmd[] = {
OLED_CONTROL_BYTE_CMD,
OLED_CMD_DISPLAY_OFF,
OLED_CMD_SET_MUX_RATIO, (i2c_ssd1306_config.height - 1),
OLED_CMD_SET_VERT_DISPLAY_OFFSET, 0x00,
OLED_MASK_DISPLAY_START_LINE | 0x00,
OLED_CMD_COM_SCAN_DIRECTION_NORMAL,
OLED_CMD_SEGMENT_REMAP_LEFT_TO_RIGHT,
OLED_CMD_SET_COM_PIN_HARDWARE_MAP, 0x12,
OLED_CMD_SET_MEMORY_ADDR_MODE, 0x02,
OLED_CMD_SET_CONTRAST_CONTROL, 0xFF,
OLED_CMD_SET_DISPLAY_CLK_DIVIDE, 0x80,
OLED_CMD_ENABLE_DISPLAY_RAM,
OLED_CMD_NORMAL_DISPLAY,
OLED_CMD_SET_CHARGE_PUMP, 0x14,
OLED_CMD_DISPLAY_ON};
if (i2c_ssd1306_config.wise == SSD1306_BOTTOM_TO_TOP)
{
ssd1306_init_cmd[7] = OLED_CMD_COM_SCAN_DIRECTION_REMAP;
ssd1306_init_cmd[8] = OLED_CMD_SEGMENT_REMAP_RIGHT_TO_LEFT;
}
ret = i2c_master_transmit(i2c_ssd1306->i2c_master_dev, ssd1306_init_cmd, sizeof(ssd1306_init_cmd), I2C_SSD1306_TIMEOUT_MS / portTICK_PERIOD_MS);
if (ret != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to initialize I2C SSD1306 device");
return ret;
}
i2c_ssd1306->width = i2c_ssd1306_config.width;
i2c_ssd1306->height = i2c_ssd1306_config.height;
i2c_ssd1306->total_pages = i2c_ssd1306_config.height / 8;
i2c_ssd1306->page = (ssd1306_page_t *)calloc(i2c_ssd1306->total_pages, sizeof(ssd1306_page_t));
if (i2c_ssd1306->page == NULL)
{
ESP_LOGE(SSD1306_TAG, "Failed to allocate memory for I2C SSD1306 device");
return ESP_ERR_NO_MEM;
}
for (uint8_t i = 0; i < i2c_ssd1306->total_pages; i++)
{
i2c_ssd1306->page[i].segment = (uint8_t *)calloc(i2c_ssd1306->width, sizeof(uint8_t));
if (i2c_ssd1306->page[i].segment == NULL)
return ESP_ERR_NO_MEM;
}
ESP_LOGI(SSD1306_TAG, "I2C SSD1306 initialized successfully");
return ret;
}
esp_err_t i2c_ssd1306_deinit(i2c_ssd1306_handle_t *i2c_ssd1306)
{
ESP_LOGI(SSD1306_TAG, "Deinitializing I2C SSD1306...");
for (uint8_t i = 0; i < i2c_ssd1306->total_pages; i++)
{
free(i2c_ssd1306->page[i].segment);
}
free(i2c_ssd1306->page);
esp_err_t ret = i2c_master_bus_rm_device(i2c_ssd1306->i2c_master_dev);
if (ret != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to remove I2C SSD1306 device");
return ret;
}
ESP_LOGI(SSD1306_TAG, "I2C SSD1306 deinitialized successfully");
return ret;
}
esp_err_t i2c_ssd1306_buffer_check(i2c_ssd1306_handle_t *i2c_ssd1306)
{
for (uint8_t i = 0; i < i2c_ssd1306->total_pages; i++)
{
for (uint8_t j = 0; j < i2c_ssd1306->width; j++)
{
printf("%02X ", i2c_ssd1306->page[i].segment[j]);
}
printf("\n");
}
return ESP_OK;
}
esp_err_t i2c_ssd1306_buffer_clear(i2c_ssd1306_handle_t *i2c_ssd1306)
{
for (uint8_t i = 0; i < i2c_ssd1306->total_pages; i++)
{
memset(i2c_ssd1306->page[i].segment, 0x00, i2c_ssd1306->width);
}
return ESP_OK;
}
esp_err_t i2c_ssd1306_buffer_fill(i2c_ssd1306_handle_t *i2c_ssd1306)
{
for (uint8_t i = 0; i < i2c_ssd1306->total_pages; i++)
{
memset(i2c_ssd1306->page[i].segment, 0xFF, i2c_ssd1306->width);
}
return ESP_OK;
}
esp_err_t i2c_ssd1306_buffer_fill_pixel(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t x, uint8_t y, bool fill)
{
if (x >= i2c_ssd1306->width || y >= i2c_ssd1306->height)
{
ESP_LOGE(SSD1306_TAG, "Invalid pixel coordinates, 'x' must be between 0 and %d, 'y' must be between 0 and %d", i2c_ssd1306->width - 1, i2c_ssd1306->height - 1);
return ESP_ERR_INVALID_ARG;
}
uint8_t page = y / 8;
uint8_t bit = 1 << (y % 8);
if (fill)
{
i2c_ssd1306->page[page].segment[x] |= bit;
}
else
{
i2c_ssd1306->page[page].segment[x] &= ~bit;
}
return ESP_OK;
}
esp_err_t i2c_ssd1306_buffer_fill_space(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t x1, uint8_t x2, uint8_t y1, uint8_t y2, bool fill)
{
if (x1 >= i2c_ssd1306->width || x2 >= i2c_ssd1306->width || y1 >= i2c_ssd1306->height || y2 >= i2c_ssd1306->height || x1 > x2 || y1 > y2)
{
ESP_LOGE(SSD1306_TAG, "Invalid space coordinates, 'x1' and 'x2' must be between 0 and %d, 'y1' and 'y2' must be between 0 and %d, 'x1' must be less than 'x2', 'y1' must be less than 'y2'", i2c_ssd1306->width - 1, i2c_ssd1306->height - 1);
return ESP_ERR_INVALID_ARG;
}
uint8_t start_page = y1 / 8;
uint8_t end_page = y2 / 8;
uint8_t mask;
uint8_t offset_start = y1 % 8;
uint8_t offset_end = y2 % 8;
for (uint8_t page = start_page; page <= end_page; page++)
{
if (start_page == end_page)
{
mask = (0xFF << offset_start) & (0xFF >> (7 - offset_end));
}
else if (page == start_page)
{
mask = 0xFF << offset_start;
}
else if (page == end_page)
{
mask = 0xFF >> (7 - offset_end);
}
else
{
mask = 0xFF;
}
for (uint8_t j = x1; j <= x2; j++)
{
if (fill)
i2c_ssd1306->page[page].segment[j] |= mask;
else
i2c_ssd1306->page[page].segment[j] &= ~mask;
}
}
return ESP_OK;
}
esp_err_t i2c_ssd1306_buffer_text(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t x, uint8_t y, const char *text, bool invert)
{
if (x >= i2c_ssd1306->width || y >= i2c_ssd1306->height || !text || strlen(text) == 0)
{
ESP_LOGE(SSD1306_TAG, "Invalid text or coordinates: x=%d (max %d), y=%d (max %d)", x, i2c_ssd1306->width - 1, y, i2c_ssd1306->height - 1);
return ESP_ERR_INVALID_ARG;
}
uint8_t len = strlen(text);
uint8_t page = y / 8;
uint8_t offset = y % 8;
bool has_next_page = (page + 1) < i2c_ssd1306->total_pages;
uint8_t max_chars = (i2c_ssd1306->width - x) / 8;
if (len > max_chars)
{
ESP_LOGW(SSD1306_TAG, "Text truncated: text columns exceed display width, lost %d columns", x + (len * 8) - i2c_ssd1306->width);
}
if (offset != 0 && !has_next_page)
{
ESP_LOGW(SSD1306_TAG, "Vertical truncation: text exceeds display height, lost %d rows", offset);
}
for (uint8_t i = 0; i < len && x < i2c_ssd1306->width; i++)
{
const uint8_t *char_data = font8x8[(uint8_t)text[i]];
uint8_t available_columns = i2c_ssd1306->width - x;
uint8_t columns_to_draw = (available_columns < 8) ? available_columns : 8;
for (uint8_t j = 0; j < columns_to_draw; j++)
{
uint8_t char_col = char_data[j];
if (invert)
{
char_col = ~char_col;
}
if (offset == 0)
{
i2c_ssd1306->page[page].segment[x + j] |= char_col;
}
else
{
uint8_t lower_part = char_col << offset;
uint8_t upper_part = char_col >> (8 - offset);
i2c_ssd1306->page[page].segment[x + j] |= lower_part;
if (has_next_page)
{
i2c_ssd1306->page[page + 1].segment[x + j] |= upper_part;
}
}
}
x += 8;
}
return ESP_OK;
}
esp_err_t i2c_ssd1306_buffer_int(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t x, uint8_t y, int value, bool invert)
{
char text[16];
sprintf(text, "%d", value);
return i2c_ssd1306_buffer_text(i2c_ssd1306, x, y, text, invert);
}
esp_err_t i2c_ssd1306_buffer_float(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t x, uint8_t y, float value, uint8_t decimals, bool invert)
{
char text[16];
sprintf(text, "%.*f", decimals, value);
return i2c_ssd1306_buffer_text(i2c_ssd1306, x, y, text, invert);
}
esp_err_t i2c_ssd1306_buffer_image(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t x, uint8_t y, const uint8_t *image, uint8_t img_width, uint8_t img_height, bool invert)
{
if (image == NULL || img_width == 0 || img_height == 0 || x >= i2c_ssd1306->width || y >= i2c_ssd1306->height)
{
ESP_LOGE(SSD1306_TAG, "Invalid image or coordinates: x=%d (max %d), y=%d (max %d)", x, i2c_ssd1306->width - 1, y, i2c_ssd1306->height - 1);
return ESP_ERR_INVALID_ARG;
}
uint8_t draw_width = (img_width < (i2c_ssd1306->width - x)) ? img_width : (i2c_ssd1306->width - x);
uint8_t draw_height = (img_height < (i2c_ssd1306->height - y)) ? img_height : (i2c_ssd1306->height - y);
uint8_t start_page = y / 8;
uint8_t vertical_offset = y % 8;
uint8_t num_pages = i2c_ssd1306->total_pages;
uint8_t draw_pages = (((draw_height + 7) / 8) < (num_pages - start_page)) ? ((draw_height + 7) / 8) : (num_pages - start_page);
if (img_height > draw_height)
{
ESP_LOGW(SSD1306_TAG, "Vertical truncation: Lost %d rows", img_height - draw_height);
}
if (draw_width < img_width)
{
ESP_LOGW(SSD1306_TAG, "Horizontal truncation: Lost %d columns", img_width - draw_width);
}
for (uint8_t col = 0; col < draw_width; col++)
{
for (uint8_t page = 0; page < draw_pages; page++)
{
uint8_t target_page = start_page + page;
if (target_page >= num_pages)
break;
uint8_t img_byte = image[page * img_width + col];
if (invert)
img_byte = ~img_byte;
if (vertical_offset == 0)
{
i2c_ssd1306->page[target_page].segment[x + col] |= img_byte;
}
else
{
uint8_t lower = img_byte << vertical_offset;
uint8_t upper = img_byte >> (8 - vertical_offset);
i2c_ssd1306->page[target_page].segment[x + col] |= lower;
if (target_page + 1 < num_pages)
{
i2c_ssd1306->page[target_page + 1].segment[x + col] |= upper;
}
}
}
}
return ESP_OK;
}
esp_err_t i2c_ssd1306_segment_to_ram(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t page, uint8_t segment)
{
if (page >= i2c_ssd1306->total_pages || segment >= i2c_ssd1306->width)
{
ESP_LOGE(SSD1306_TAG, "Invalid page or segment number, 'page' must be between 0 and %d, 'segment' must be between 0 and %d", i2c_ssd1306->total_pages - 1, i2c_ssd1306->width - 1);
return ESP_ERR_INVALID_ARG;
}
uint8_t ram_addr_cmd[] = {
OLED_CONTROL_BYTE_CMD,
OLED_MASK_PAGE_ADDR | page,
OLED_MASK_LSB_NIBBLE_SEG_ADDR | (segment & 0x0F),
OLED_MASK_HSB_NIBBLE_SEG_ADDR | (segment >> 4 & 0x0F)};
esp_err_t err = i2c_master_transmit(i2c_ssd1306->i2c_master_dev, ram_addr_cmd, sizeof(ram_addr_cmd), I2C_SSD1306_TIMEOUT_MS / portTICK_PERIOD_MS);
if (err != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to address the segment to the RAM of the SSD1306 device");
return err;
}
uint8_t ram_data_cmd[] = {
OLED_CONTROL_BYTE_DATA,
i2c_ssd1306->page[page].segment[segment]};
err = i2c_master_transmit(i2c_ssd1306->i2c_master_dev, ram_data_cmd, sizeof(ram_data_cmd), I2C_SSD1306_TIMEOUT_MS / portTICK_PERIOD_MS);
if (err != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to transfer the segment to the RAM of the SSD1306 device");
return err;
}
return err;
}
esp_err_t i2c_ssd1306_segments_to_ram(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t page, uint8_t initial_segment, uint8_t final_segment)
{
if (page >= i2c_ssd1306->total_pages || initial_segment >= i2c_ssd1306->width || final_segment >= i2c_ssd1306->width || initial_segment > final_segment)
{
ESP_LOGE(SSD1306_TAG, "Invalid page or segment range, 'page' must be between 0 and %d, 'initial_segment' and 'final_segment' must be between 0 and %d, 'initial_segment' must be less than or equal to 'final_segment'", i2c_ssd1306->total_pages - 1, i2c_ssd1306->width - 1);
return ESP_ERR_INVALID_ARG;
}
uint8_t ram_addr_cmd[] = {
OLED_CONTROL_BYTE_CMD,
OLED_MASK_PAGE_ADDR | page,
OLED_MASK_LSB_NIBBLE_SEG_ADDR | (initial_segment & 0x0F),
OLED_MASK_HSB_NIBBLE_SEG_ADDR | (initial_segment >> 4 & 0x0F)};
esp_err_t err = i2c_master_transmit(i2c_ssd1306->i2c_master_dev, ram_addr_cmd, sizeof(ram_addr_cmd), I2C_SSD1306_TIMEOUT_MS / portTICK_PERIOD_MS);
if (err != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to address the initial segment to the RAM of the SSD1306 device");
return err;
}
uint8_t ram_data_cmd[final_segment - initial_segment + 2];
ram_data_cmd[0] = OLED_CONTROL_BYTE_DATA;
for (uint8_t i = 0; i < final_segment - initial_segment + 1; i++)
{
ram_data_cmd[i + 1] = i2c_ssd1306->page[page].segment[initial_segment + i];
}
err = i2c_master_transmit(i2c_ssd1306->i2c_master_dev, ram_data_cmd, sizeof(ram_data_cmd), I2C_SSD1306_TIMEOUT_MS / portTICK_PERIOD_MS);
if (err != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to transfer the segments to the RAM of the SSD1306 device");
return err;
}
return err;
}
esp_err_t i2c_ssd1306_page_to_ram(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t page)
{
if (page >= i2c_ssd1306->total_pages)
{
ESP_LOGE(SSD1306_TAG, "Invalid page number, must be between 0 and %d", i2c_ssd1306->total_pages - 1);
return ESP_ERR_INVALID_ARG;
}
uint8_t ram_addr_cmd[] = {
OLED_CONTROL_BYTE_CMD,
OLED_MASK_PAGE_ADDR | page,
OLED_MASK_LSB_NIBBLE_SEG_ADDR | (0x00 & 0x0F),
OLED_MASK_HSB_NIBBLE_SEG_ADDR | (0x00 >> 4 & 0x0F)};
esp_err_t err = i2c_master_transmit(i2c_ssd1306->i2c_master_dev, ram_addr_cmd, sizeof(ram_addr_cmd), I2C_SSD1306_TIMEOUT_MS / portTICK_PERIOD_MS);
if (err != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to address the page to the RAM of the SSD1306 device");
return err;
}
uint8_t ram_data_cmd[i2c_ssd1306->width + 1];
ram_data_cmd[0] = OLED_CONTROL_BYTE_DATA;
for (uint8_t i = 0; i < i2c_ssd1306->width; i++)
{
ram_data_cmd[i + 1] = i2c_ssd1306->page[page].segment[i];
}
err = i2c_master_transmit(i2c_ssd1306->i2c_master_dev, ram_data_cmd, sizeof(ram_data_cmd), I2C_SSD1306_TIMEOUT_MS / portTICK_PERIOD_MS);
if (err != ESP_OK)
{
ESP_LOGE(SSD1306_TAG, "Failed to transfer the page to the RAM of the SSD1306 device");
return err;
}
return err;
}
esp_err_t i2c_ssd1306_pages_to_ram(i2c_ssd1306_handle_t *i2c_ssd1306, uint8_t initial_page, uint8_t final_page)
{
if (initial_page >= i2c_ssd1306->total_pages || final_page >= i2c_ssd1306->total_pages || initial_page > final_page)
{
ESP_LOGE(SSD1306_TAG, "Invalid page range, 'initial_page' and 'final_page' must be between 0 and %d, 'initial_page' must be less than or equal to 'final_page'", i2c_ssd1306->total_pages - 1);
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = ESP_OK;
for (uint8_t i = initial_page; i <= final_page; i++)
{
esp_err_t err = i2c_ssd1306_page_to_ram(i2c_ssd1306, i);
if (err != ESP_OK)
return err;
}
return err;
}
esp_err_t i2c_ssd1306_buffer_to_ram(i2c_ssd1306_handle_t *i2c_ssd1306)
{
esp_err_t err = ESP_OK;
for (uint8_t i = 0; i < i2c_ssd1306->total_pages; i++)
{
err = i2c_ssd1306_page_to_ram(i2c_ssd1306, i);
if (err != ESP_OK)
return err;
}
return err;
}