Random
This commit is contained in:
329
src/pages/display.c
Normal file
329
src/pages/display.c
Normal file
@ -0,0 +1,329 @@
|
||||
#include "drivers/display.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <pigpio.h>
|
||||
|
||||
|
||||
|
||||
struct display_t
|
||||
{
|
||||
int handle;
|
||||
bool backlight, display, cursor, blink;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//Bit mask for display pins
|
||||
#define PIN_E 0b00000100
|
||||
#define PIN_RW 0b00000010
|
||||
#define PIN_RS 0b00000001
|
||||
#define PIN_BL 0b00001000
|
||||
#define PIN_D4 0b00010000
|
||||
#define PIN_D5 0b00100000
|
||||
#define PIN_D6 0b01000000
|
||||
#define PIN_D7 0b10000000
|
||||
|
||||
//Periods for signal hold
|
||||
#define PERIOD_PULSE 500
|
||||
#define PERIOD_CMD 4100
|
||||
|
||||
//Display commands
|
||||
#define CMD_CLEAR 0x01
|
||||
#define CMD_HOME 0x02
|
||||
#define CMD_ENTRY 0x04
|
||||
#define CMD_DISP 0x08
|
||||
#define CMD_CODS 0x10
|
||||
#define CMD_FUNC 0x20
|
||||
#define CMD_CGADR 0x40
|
||||
#define CMD_DRADR 0x80
|
||||
|
||||
//Flags for entry mode
|
||||
#define ENTRY_NORM 0x02
|
||||
#define ENTRY_SHIFT 0x01
|
||||
|
||||
//Flags for display
|
||||
#define DISP_PWR 0x04
|
||||
#define DISP_OFF 0x00
|
||||
#define DISP_CURS 0x02
|
||||
#define DISP_BLNK 0x01
|
||||
|
||||
//Flags for CODS
|
||||
#define CODS_CURL 0x00
|
||||
#define CODS_CURR 0x04
|
||||
#define CODS_SCRL 0x08
|
||||
#define CODS_SCRR 0x0C
|
||||
|
||||
//Flags for function
|
||||
#define FUNC_4BIT 0x00
|
||||
#define FUNC_8BIT 0x10
|
||||
#define FUNC_1LIN 0x00
|
||||
#define FUNC_2LIN 0x08
|
||||
#define FUNC_5x8D 0x00
|
||||
#define FUNC_5x11D 0x04
|
||||
|
||||
|
||||
|
||||
static void write_cmd(int handle, unsigned int cmd, bool backlight)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
byte = (cmd & 0xF0) | (backlight ? PIN_BL : 0);
|
||||
i2cWriteByte(handle, byte & 0xFF);
|
||||
gpioDelay(PERIOD_PULSE);
|
||||
i2cWriteByte(handle, (byte | PIN_E) & 0xFF);
|
||||
gpioDelay(PERIOD_PULSE);
|
||||
i2cWriteByte(handle, (byte | ~PIN_E) & 0xFF);
|
||||
gpioDelay(PERIOD_CMD);
|
||||
|
||||
byte = ((cmd << 4) & 0xF0) | (backlight ? PIN_BL : 0);
|
||||
i2cWriteByte(handle, byte & 0xFF);
|
||||
gpioDelay(PERIOD_PULSE);
|
||||
i2cWriteByte(handle, (byte | PIN_E) & 0xFF);
|
||||
gpioDelay(PERIOD_PULSE);
|
||||
i2cWriteByte(handle, (byte | ~PIN_E) & 0xFF);
|
||||
gpioDelay(PERIOD_CMD);
|
||||
}
|
||||
|
||||
static void write_char(int handle, char ch, bool backlight)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
byte = (ch & 0xF0) | PIN_RS | (backlight ? PIN_BL : 0);
|
||||
i2cWriteByte(handle, byte & 0xFF);
|
||||
gpioDelay(PERIOD_PULSE);
|
||||
i2cWriteByte(handle, (byte | PIN_E) & 0xFF);
|
||||
gpioDelay(PERIOD_PULSE);
|
||||
i2cWriteByte(handle, (byte | ~PIN_E) & 0xFF);
|
||||
gpioDelay(PERIOD_CMD);
|
||||
|
||||
byte = ((ch << 4) & 0xF0) | PIN_RS | (backlight ? PIN_BL : 0);
|
||||
i2cWriteByte(handle, byte & 0xFF);
|
||||
gpioDelay(PERIOD_PULSE);
|
||||
i2cWriteByte(handle, (byte | PIN_E) & 0xFF);
|
||||
gpioDelay(PERIOD_PULSE);
|
||||
i2cWriteByte(handle, (byte | ~PIN_E) & 0xFF);
|
||||
gpioDelay(PERIOD_CMD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
display_t *display_init(int bus, uint8_t addr)
|
||||
{
|
||||
if (bus != DISP_I2C0 && bus != DISP_I2C1)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_init received an invalid bus: %d.\n", bus);
|
||||
return NULL;
|
||||
}
|
||||
if (addr >= 0x80)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_init received an invalid address: %d.\n", addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
display_t * ret = malloc(sizeof(display_t));
|
||||
if (!ret)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_init failed to allocate memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->backlight = true;
|
||||
ret->handle = i2cOpen(bus, addr, 0);
|
||||
if (ret->handle < 0)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_init could not open the required I2C%d bus for address %d: %d\n", bus, addr, ret->handle);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Literal magic, idk why it's needed, idk what the values are
|
||||
//All I know is it no workey without this
|
||||
//Average programming moment
|
||||
write_cmd(ret->handle, 0x03, false);
|
||||
write_cmd(ret->handle, 0x03, false);
|
||||
write_cmd(ret->handle, 0x03, false);
|
||||
write_cmd(ret->handle, 0x02, false);
|
||||
|
||||
write_cmd(ret->handle, CMD_FUNC | FUNC_4BIT | FUNC_2LIN | FUNC_5x8D, ret->backlight);
|
||||
write_cmd(ret->handle, CMD_DISP | DISP_PWR, ret->backlight);
|
||||
write_cmd(ret->handle, CMD_CLEAR, ret->backlight);
|
||||
write_cmd(ret->handle, CMD_ENTRY | ENTRY_NORM, ret->backlight);
|
||||
gpioDelay(200000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void display_destroy(display_t *display)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_destroy received a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
i2cClose(display->handle);
|
||||
free(display);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void display_clear(display_t *display)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_clear was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
write_cmd(display->handle, CMD_CLEAR, display->backlight);
|
||||
}
|
||||
|
||||
void display_set_backlight(display_t *display, bool backlight)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_set_backlight was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
display->backlight = backlight;
|
||||
i2cWriteByte(display->handle, backlight ? PIN_BL : 0);
|
||||
}
|
||||
|
||||
void display_set_cursor(display_t *display, int lin, int col)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_set_cursor was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = col % 20;
|
||||
switch (lin % 4)
|
||||
{
|
||||
case 1:
|
||||
pos += 0x40;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
pos += 0x14;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
pos += 0x54;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
write_cmd(display->handle, CMD_DRADR | (pos & 0x7F), display->backlight);
|
||||
}
|
||||
|
||||
void display_write_ch(display_t *display, char ch)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_write_ch was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
write_char(display->handle, ch, display->backlight);
|
||||
}
|
||||
|
||||
void display_write_str(display_t *display, char *str)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_write_str was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
if (!str)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_write_str was given a NULL str.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; str[i]; i++)
|
||||
write_char(display->handle, str[i], display->backlight);
|
||||
}
|
||||
|
||||
void display_write_str_at(display_t *display, char *str, int lin, int col)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_write_str_at was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
if (!str)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_write_str_at was given a NULL str.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
display_set_cursor(display, lin, col);
|
||||
display_write_str(display, str);
|
||||
}
|
||||
|
||||
void display_set_display_on(display_t *display, bool on)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_set_display_on was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
display->display = on;
|
||||
char cmd = CMD_DISP | (display->display ? 0x4 : 0x0) | (display->cursor ? 0x2 : 0x0) | (display->blink ? 0x1 : 0x0);
|
||||
write_cmd(display->handle, cmd, display->backlight);
|
||||
}
|
||||
|
||||
void display_set_cursor_show(display_t *display, bool show)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_set_cursor_show was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
display->cursor = show;
|
||||
char cmd = CMD_DISP | (display->display ? 0x4 : 0x0) | (display->cursor ? 0x2 : 0x0) | (display->blink ? 0x1 : 0x0);
|
||||
write_cmd(display->handle, cmd, display->backlight);
|
||||
}
|
||||
|
||||
void display_set_cursor_blink(display_t *display, bool blink)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_set_cursor_blink was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
display->blink = blink;
|
||||
char cmd = CMD_DISP | (display->display ? 0x4 : 0x0) | (display->cursor ? 0x2 : 0x0) | (display->blink ? 0x1 : 0x0);
|
||||
write_cmd(display->handle, cmd, display->backlight);
|
||||
}
|
||||
|
||||
void display_set_custom_char(display_t *display, uint8_t char_idx, uint64_t data)
|
||||
{
|
||||
if (!display)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_set_custom_char was given a NULL display.\n");
|
||||
return;
|
||||
}
|
||||
if (char_idx >= 8)
|
||||
{
|
||||
fprintf(stderr, "WARN: display_set_custom_char was given an invalid char_idx: %d.\n", char_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
write_cmd(display->handle, CMD_CGADR | (char_idx << 3), display->backlight);
|
||||
|
||||
for (int i = 7; i >= 0; i--)
|
||||
write_char(display->handle, (data >> (i * 8)) & 0xFF, display->backlight);
|
||||
}
|
||||
Reference in New Issue
Block a user