lcd-clock - initial commit
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
bin/
 | 
			
		||||
obj/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										144
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,144 @@
 | 
			
		||||
CROSS_COMPILE ?=
 | 
			
		||||
 | 
			
		||||
TARGET_FILE ?= test_c
 | 
			
		||||
 | 
			
		||||
CC = $(CROSS_COMPILE)gcc
 | 
			
		||||
CPP = $(CROSS_COMPILE)cpp
 | 
			
		||||
CHECK = cppcheck
 | 
			
		||||
LCOV = lcov
 | 
			
		||||
GENHTML = genhtml
 | 
			
		||||
 | 
			
		||||
SRC_DIR = src
 | 
			
		||||
OBJ_DIR = obj
 | 
			
		||||
BIN_DIR = bin
 | 
			
		||||
COVERAGE_DIR = coverage
 | 
			
		||||
UNIT_TEST_SRC_DIR = test/unit
 | 
			
		||||
UNIT_TEST_OBJ_DIR = $(OBJ_DIR)/$(UNIT_TEST_SRC_DIR)
 | 
			
		||||
 | 
			
		||||
PREFIX ?= /usr
 | 
			
		||||
BIN_INSTALL_DIR = $(PREFIX)/bin
 | 
			
		||||
 | 
			
		||||
INCLUDES := interface/
 | 
			
		||||
INCLUDES += include/
 | 
			
		||||
INCLUDES += include/$(ARCH)/
 | 
			
		||||
INCLUDES += $(PREFIX)/include/
 | 
			
		||||
INCLUDES += $(EXTRA_INC)
 | 
			
		||||
 | 
			
		||||
LIBS =
 | 
			
		||||
 | 
			
		||||
LD_FLAGS += $(addprefix -L,$(EXTRA_LIB_DIR))
 | 
			
		||||
 | 
			
		||||
ifneq "$(findstring $(MAKECMDGOALS), build_unit_test exec_unit_test coverage)" ""
 | 
			
		||||
INCLUDES += test/inc
 | 
			
		||||
C_FLAGS += --coverage
 | 
			
		||||
LD_FLAGS += --coverage
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
C_FLAGS += -fpic
 | 
			
		||||
 | 
			
		||||
C_FLAGS += -O0 -g -Wall
 | 
			
		||||
CPP_FLAGS += $(addprefix -I, $(INCLUDES))
 | 
			
		||||
 | 
			
		||||
CHECK_FLAGS = $(addprefix -I,$(filter-out $(PREFIX)/include/,$(INCLUDES)))
 | 
			
		||||
CHECK_FLAGS += --enable=all --template=gcc --error-exitcode=1 --suppress=missingIncludeSystem --inline-suppr --force
 | 
			
		||||
 | 
			
		||||
C_SRCS = $(wildcard $(SRC_DIR)/*.c)
 | 
			
		||||
C_SRCS += $(wildcard $(SRC_DIR)/$(ARCH)/*.c)
 | 
			
		||||
C_OBJS = $(patsubst $(SRC_DIR)%,$(OBJ_DIR)%,$(patsubst %.c,%.o,$(C_SRCS)))
 | 
			
		||||
 | 
			
		||||
UNIT_TEST_SRCS = $(wildcard $(UNIT_TEST_SRC_DIR)/*.c) $(filter-out %main.c,$(CC_SRCS))
 | 
			
		||||
UNIT_TEST_OBJS = $(patsubst $(SRC_DIR)%,$(OBJ_DIR)%,$(patsubst $(UNIT_TEST_SRC_DIR)%,$(UNIT_TEST_OBJ_DIR)%,$(patsubst %.c,%.o,$(UNIT_TEST_SRCS))))
 | 
			
		||||
 | 
			
		||||
OBJS = $(C_OBJS)
 | 
			
		||||
 | 
			
		||||
UNIT_TEST_TARGET = $(BIN_DIR)/$(UNIT_TEST_SRC_DIR)/$(TARGET_FILE)
 | 
			
		||||
TARGET = $(BIN_DIR)/$(TARGET_FILE)
 | 
			
		||||
THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
 | 
			
		||||
 | 
			
		||||
.PHONY: all install uninstall clean distclean debug
 | 
			
		||||
debug:
 | 
			
		||||
	@echo $(C_SRCS)
 | 
			
		||||
	@echo $(C_OBJS)
 | 
			
		||||
	@echo $(ARCH)
 | 
			
		||||
	@echo $(CPP_FLAGS)
 | 
			
		||||
 | 
			
		||||
all: $(TARGET)
 | 
			
		||||
 | 
			
		||||
install: all
 | 
			
		||||
	install -d $(BIN_INSTALL_DIR)
 | 
			
		||||
	install -m 0666 $(TARGET) $(BIN_INSTALL_DIR)
 | 
			
		||||
 | 
			
		||||
uninstall:
 | 
			
		||||
	rm -f $(BIN_INSTALL_DIR)/$(TARGET_FILE)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f $(TARGET)
 | 
			
		||||
	rm -f $(OBJS) $(patsubst %.o,%.d,$(OBJS))
 | 
			
		||||
	rm -f $(UNIT_TEST_OBJS) $(patsubst %.o,%.d,$(UNIT_TEST_OBJS)) $(UNIT_TEST_TARGET)
 | 
			
		||||
	rm -f $(UNIT_TEST_OBJ_DIR)/*.gcda
 | 
			
		||||
	rm -f $(UNIT_TEST_OBJ_DIR)/*.gcno
 | 
			
		||||
	rm -f $(OBJ_DIR)/*.gcda $(OBJ_DIR)/*.gcno
 | 
			
		||||
	rm -fr $(COVERAGE_DIR)
 | 
			
		||||
 | 
			
		||||
distclean:
 | 
			
		||||
	rm -rf $(OBJ_DIR) $(BIN_DIR) $(COVERAGE_DIR)
 | 
			
		||||
 | 
			
		||||
.PHONY: coverage
 | 
			
		||||
coverage: _cov_genhtml
 | 
			
		||||
	$(eval COVERAGE:=$(shell grep 'lines' .coverage.tmp | egrep -o '[0-9]+.[0-9]+%'))
 | 
			
		||||
	@echo
 | 
			
		||||
	@echo Line coverage: $(COVERAGE)
 | 
			
		||||
	@echo
 | 
			
		||||
	@rm -f .coverage.tmp
 | 
			
		||||
 | 
			
		||||
.PHONY: _cov_lcov
 | 
			
		||||
_cov_lcov: exec_unit_test
 | 
			
		||||
	@rm -f $(UNIT_TEST_OBJ_DIR)/*.gcda
 | 
			
		||||
	@rm -f $(UNIT_TEST_OBJ_DIR)/*.gcno
 | 
			
		||||
	@mkdir -p $(COVERAGE_DIR)
 | 
			
		||||
	$(LCOV) -c -d $(OBJ_DIR) -o $(COVERAGE_DIR)/coverage.info
 | 
			
		||||
 | 
			
		||||
.PHONY: _cov_genhtml
 | 
			
		||||
_cov_genhtml: _cov_lcov
 | 
			
		||||
	$(GENHTML) -o $(COVERAGE_DIR)/html $(COVERAGE_DIR)/coverage.info > .coverage.tmp
 | 
			
		||||
 | 
			
		||||
.PHONY: unit_test
 | 
			
		||||
build_unit_test: $(UNIT_TEST_TARGET)
 | 
			
		||||
 | 
			
		||||
.PHONY: unit_test
 | 
			
		||||
exec_unit_test: $(UNIT_TEST_TARGET)
 | 
			
		||||
	$(UNIT_TEST_TARGET)
 | 
			
		||||
 | 
			
		||||
.PHONY: check
 | 
			
		||||
check: $(CC_SRCS)
 | 
			
		||||
	$(CHECK) $(CHECK_FLAGS) $(CC_SRCS)
 | 
			
		||||
 | 
			
		||||
$(UNIT_TEST_TARGET): $(UNIT_TEST_OBJS) $(THIS_MAKEFILE)
 | 
			
		||||
	@mkdir -p $(BIN_DIR)/$(UNIT_TEST_SRC_DIR)
 | 
			
		||||
	$(CC) $(CC_FLAGS) $(LD_FLAGS) $(UNIT_TEST_OBJS) -o $@
 | 
			
		||||
 | 
			
		||||
$(TARGET): $(OBJS) $(THIS_MAKEFILE)
 | 
			
		||||
	@mkdir -p $(BIN_DIR)
 | 
			
		||||
	$(CC) $(CC_FLAGS) $(LD_FLAGS) $(OBJS) $(addprefix -l,$(LIBS)) -o $@
 | 
			
		||||
 | 
			
		||||
.PRECIOUS: $(OBJ_DIR)/%.d
 | 
			
		||||
$(OBJ_DIR)/%.d: $(SRC_DIR)/%.c
 | 
			
		||||
	@mkdir -p $(OBJ_DIR)/$(ARCH)
 | 
			
		||||
	$(CPP) -MM -MF $@ -MP -MT $(patsubst %.d,%.o,$@) $(CPP_FLAGS) $(patsubst $(OBJ_DIR)/%.d,$(SRC_DIR)/%.c,$@)
 | 
			
		||||
 | 
			
		||||
.PRECIOUS: $(UNIT_TEST_OBJ_DIR)/%.d
 | 
			
		||||
$(UNIT_TEST_OBJ_DIR)/%.d: $(UNIT_TEST_SRC_DIR)/%.c
 | 
			
		||||
	@mkdir -p $(UNIT_TEST_OBJ_DIR)
 | 
			
		||||
	$(CPP) -MM -MF $@ -MP -MT $(patsubst %.d,%.o,$@) $(CPP_FLAGS) $(patsubst $(UNIT_TEST_OBJ_DIR)/%.d,$(UNIT_TEST_SRC_DIR)/%.c,$@)
 | 
			
		||||
 | 
			
		||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.d
 | 
			
		||||
	@mkdir -p $(OBJ_DIR)/$(ARCH)
 | 
			
		||||
	$(CC) -c $(CPP_FLAGS) $(C_FLAGS) $< -o $@
 | 
			
		||||
 | 
			
		||||
$(UNIT_TEST_OBJ_DIR)/%.o: $(UNIT_TEST_SRC_DIR)/%.c $(UNIT_TEST_OBJ_DIR)/%.d
 | 
			
		||||
	@mkdir -p $(UNIT_TEST_OBJ_DIR)
 | 
			
		||||
	$(CC) -c $(CPP_FLAGS) $(C_FLAGS) $< -o $@
 | 
			
		||||
 | 
			
		||||
ifneq ($(MAKECMDGOALS),clean)
 | 
			
		||||
-include $(patsubst %.o,%.d,$(OBJS))
 | 
			
		||||
endif
 | 
			
		||||
							
								
								
									
										168
									
								
								include/posix/board.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								include/posix/board.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
#ifndef __BOARD_H__
 | 
			
		||||
#define __BOARD_H__
 | 
			
		||||
 | 
			
		||||
#include "driver.h"
 | 
			
		||||
#include "posix/i2c.h"
 | 
			
		||||
#include "ssd1306.h"
 | 
			
		||||
#include "st7789.h"
 | 
			
		||||
#include "gpio.h"
 | 
			
		||||
#include "spi.h"
 | 
			
		||||
 | 
			
		||||
// Board file for the posix board
 | 
			
		||||
 | 
			
		||||
//// ST7789 LCD
 | 
			
		||||
// spi
 | 
			
		||||
static const char * const spi_dev_name = "/dev/spidev0.0";
 | 
			
		||||
static struct spi spi0 = {
 | 
			
		||||
    .spi_device = spi_dev_name,
 | 
			
		||||
    .mode = SPI_MODE_0,
 | 
			
		||||
    .bits_per_word = 8,
 | 
			
		||||
    .speed = 20000000,
 | 
			
		||||
};
 | 
			
		||||
static const struct driver spi0_drv = {
 | 
			
		||||
    .fp = &spi_fp,
 | 
			
		||||
    .dev = &spi0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// data/command select gpio
 | 
			
		||||
static const struct gpio dc_select = {
 | 
			
		||||
    .pin = 25,
 | 
			
		||||
};
 | 
			
		||||
static const struct driver dc_drv = {
 | 
			
		||||
    .fp = &gpio_fp,
 | 
			
		||||
    .dev = &dc_select,
 | 
			
		||||
};
 | 
			
		||||
// backlight gpio
 | 
			
		||||
static const struct gpio bl_select = {
 | 
			
		||||
    .pin = 24,
 | 
			
		||||
};
 | 
			
		||||
static const struct driver bl_drv = {
 | 
			
		||||
    .fp = &gpio_fp,
 | 
			
		||||
    .dev = &bl_select,
 | 
			
		||||
};
 | 
			
		||||
// reset gpio
 | 
			
		||||
static const struct gpio rst_select = {
 | 
			
		||||
    .pin = 27,
 | 
			
		||||
};
 | 
			
		||||
static const struct driver rst_drv = {
 | 
			
		||||
    .fp = &gpio_fp,
 | 
			
		||||
    .dev = &rst_select,
 | 
			
		||||
};
 | 
			
		||||
// lcd
 | 
			
		||||
static const struct st7789 lcd_dev = {
 | 
			
		||||
    .spi = &spi0_drv,
 | 
			
		||||
    .dc = &dc_drv,
 | 
			
		||||
    .bl = &bl_drv,
 | 
			
		||||
    .rst = &rst_drv,
 | 
			
		||||
    .height = 240,
 | 
			
		||||
    .width = 240,
 | 
			
		||||
};
 | 
			
		||||
static const struct driver lcd_drv = {
 | 
			
		||||
    .fp = &st7789_fp,
 | 
			
		||||
    .dev = &lcd_dev,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
// I2C driver
 | 
			
		||||
static const char * const i2c_dev_name = "/dev/i2c-1";
 | 
			
		||||
 | 
			
		||||
static struct i2c i2c_dev = {
 | 
			
		||||
    .i2c_device = i2c_dev_name,
 | 
			
		||||
    .slave_addr = 0x3c,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char i2c_name[] = "i2c-1";
 | 
			
		||||
static const struct driver i2c_drv = {
 | 
			
		||||
    .name = i2c_name,
 | 
			
		||||
    .fp = &i2c_fp,
 | 
			
		||||
    .dev = &i2c_dev,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// SSD 1306 driver
 | 
			
		||||
static char display_buffer[(SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8) + 1] = {
 | 
			
		||||
    0x40,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
 | 
			
		||||
    0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
 | 
			
		||||
    0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF,
 | 
			
		||||
    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
 | 
			
		||||
    0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8,
 | 
			
		||||
    0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80,
 | 
			
		||||
    0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01,
 | 
			
		||||
    0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF,
 | 
			
		||||
    0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00,
 | 
			
		||||
    0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF,
 | 
			
		||||
    0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF,
 | 
			
		||||
    0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F,
 | 
			
		||||
    0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC,
 | 
			
		||||
    0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03,
 | 
			
		||||
    0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01,
 | 
			
		||||
    0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
 | 
			
		||||
    0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03,
 | 
			
		||||
    0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F,
 | 
			
		||||
    0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF,
 | 
			
		||||
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F,
 | 
			
		||||
    0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00,
 | 
			
		||||
    0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E,
 | 
			
		||||
    0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC,
 | 
			
		||||
    0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06,
 | 
			
		||||
    0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8,
 | 
			
		||||
    0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C,
 | 
			
		||||
    0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F,
 | 
			
		||||
    0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00,
 | 
			
		||||
    0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07,
 | 
			
		||||
    0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct ssd1306 display_dev = {
 | 
			
		||||
    .output_dev = &i2c_drv,
 | 
			
		||||
    .output_buffer = &display_buffer[0],
 | 
			
		||||
    .bitmap = &display_buffer[1],
 | 
			
		||||
    .width = SSD1306_LCDWIDTH,
 | 
			
		||||
    .heigth = SSD1306_LCDHEIGHT,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char ssd1306_name[] = "ssd1306";
 | 
			
		||||
static const struct driver ssd1306_drv = {
 | 
			
		||||
    .name = ssd1306_name,
 | 
			
		||||
    .fp = &ssd1306_fp,
 | 
			
		||||
    .dev = &display_dev,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										29
									
								
								include/posix/gpio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								include/posix/gpio.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
#ifndef __GPIO_H__
 | 
			
		||||
#define __GPIO_H__
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
#include "driver.h"
 | 
			
		||||
 | 
			
		||||
#define IOCTL_CMD_SET_DIRECTION 0
 | 
			
		||||
 | 
			
		||||
int gpio_open(const struct driver *drv);
 | 
			
		||||
int gpio_close(const struct driver *drv);
 | 
			
		||||
 | 
			
		||||
int gpio_read(const struct driver *drv, char *buffer, unsigned int len);
 | 
			
		||||
int gpio_write(const struct driver *drv, const char *buffer, unsigned int len);
 | 
			
		||||
int gpio_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args);
 | 
			
		||||
 | 
			
		||||
struct gpio {
 | 
			
		||||
    int pin;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct driver_fp gpio_fp = {
 | 
			
		||||
    .open = gpio_open,
 | 
			
		||||
    .close = gpio_close,
 | 
			
		||||
    .read = gpio_read,
 | 
			
		||||
    .write = gpio_write,
 | 
			
		||||
    .ioctl = gpio_ioctl
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										25
									
								
								include/posix/i2c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								include/posix/i2c.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
#ifndef __I2C_H__
 | 
			
		||||
#define __I2C_H__
 | 
			
		||||
 | 
			
		||||
#include "driver.h"
 | 
			
		||||
 | 
			
		||||
int i2c_open(const struct driver *drv);
 | 
			
		||||
int i2c_close(const struct driver *drv);
 | 
			
		||||
 | 
			
		||||
int i2c_read(const struct driver *drv, char *buffer, unsigned int len);
 | 
			
		||||
int i2c_write(const struct driver *drv, const char *buffer, unsigned int len);
 | 
			
		||||
 | 
			
		||||
struct i2c {
 | 
			
		||||
    const char * i2c_device;
 | 
			
		||||
    const uint8_t slave_addr;
 | 
			
		||||
    int i2c_file;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct driver_fp i2c_fp = {
 | 
			
		||||
    .open = i2c_open,
 | 
			
		||||
    .close = i2c_close,
 | 
			
		||||
    .read = i2c_read,
 | 
			
		||||
    .write = i2c_write,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										37
									
								
								include/posix/spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								include/posix/spi.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
#ifndef __SPI_H__
 | 
			
		||||
#define __SPI_H__
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <linux/spi/spidev.h>
 | 
			
		||||
 | 
			
		||||
#include "driver.h"
 | 
			
		||||
 | 
			
		||||
int spi_open(const struct driver *drv);
 | 
			
		||||
int spi_close(const struct driver *drv);
 | 
			
		||||
 | 
			
		||||
int spi_read(const struct driver *drv, char *buffer, unsigned int len);
 | 
			
		||||
int spi_write(const struct driver *drv, const char *buffer, unsigned int len);
 | 
			
		||||
int spi_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args);
 | 
			
		||||
 | 
			
		||||
struct spi {
 | 
			
		||||
    const char * spi_device;
 | 
			
		||||
    uint8_t mode;
 | 
			
		||||
    uint8_t bits_per_word;
 | 
			
		||||
    uint32_t speed;
 | 
			
		||||
 | 
			
		||||
    int spi_file;
 | 
			
		||||
    bool is_open;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct driver_fp spi_fp = {
 | 
			
		||||
    .open = spi_open,
 | 
			
		||||
    .close = spi_close,
 | 
			
		||||
    .read = spi_read,
 | 
			
		||||
    .write = spi_write,
 | 
			
		||||
    .ioctl = spi_ioctl,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										37
									
								
								include/ssd1306.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								include/ssd1306.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
#ifndef __SSD1306_H__
 | 
			
		||||
#define __SSD1306_H__
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
#include "driver.h"
 | 
			
		||||
 | 
			
		||||
#define SSD1306_LCDWIDTH                  128
 | 
			
		||||
#define SSD1306_LCDHEIGHT                 64
 | 
			
		||||
 | 
			
		||||
#define IOCTL_CMD_CLS           0
 | 
			
		||||
#define IOCTL_CMD_REFRESH       1
 | 
			
		||||
#define IOCTL_CMD_DRAW_PIXEL    2
 | 
			
		||||
#define IOCTL_CMD_DRAW_LINE     3
 | 
			
		||||
#define IOCTL_CMD_DRAW_CIRCLE   4
 | 
			
		||||
 | 
			
		||||
int ssd1306_open(const struct driver *drv);
 | 
			
		||||
int ssd1306_close(const struct driver *drv);
 | 
			
		||||
int ssd1306_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args);
 | 
			
		||||
 | 
			
		||||
struct ssd1306 {
 | 
			
		||||
    const struct driver *output_dev;
 | 
			
		||||
    char *output_buffer;
 | 
			
		||||
    char *bitmap;
 | 
			
		||||
    uint32_t width;
 | 
			
		||||
    uint32_t heigth;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct driver_fp ssd1306_fp = {
 | 
			
		||||
    .open = ssd1306_open,
 | 
			
		||||
    .close = ssd1306_close,
 | 
			
		||||
    .read = NULL,
 | 
			
		||||
    .write = NULL,
 | 
			
		||||
    .ioctl = ssd1306_ioctl,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										32
									
								
								include/st7789.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								include/st7789.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
#ifndef __ST7789_H__
 | 
			
		||||
#define __ST7789_H__
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
#include "driver.h"
 | 
			
		||||
 | 
			
		||||
#define IOCTL_CMD_DRAW_IMAGE 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int st7789_open(const struct driver *drv);
 | 
			
		||||
int st7789_close(const struct driver *drv);
 | 
			
		||||
int st7789_write(const struct driver *drv, const char *buffer, unsigned int len);
 | 
			
		||||
 | 
			
		||||
struct st7789 {
 | 
			
		||||
    const struct driver *spi;
 | 
			
		||||
    const struct driver *dc;
 | 
			
		||||
    const struct driver *bl;
 | 
			
		||||
    const struct driver *rst;
 | 
			
		||||
    unsigned int height;
 | 
			
		||||
    unsigned int width;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct driver_fp st7789_fp = {
 | 
			
		||||
    .open = st7789_open,
 | 
			
		||||
    .close = st7789_close,
 | 
			
		||||
    .read = NULL,
 | 
			
		||||
    .write = st7789_write,
 | 
			
		||||
    .ioctl = NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										34
									
								
								interface/driver.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								interface/driver.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
#ifndef __DRIVER_H__
 | 
			
		||||
#define __DRIVER_H__
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
struct driver;
 | 
			
		||||
 | 
			
		||||
typedef int (*fp_open_t)(const struct driver *);
 | 
			
		||||
typedef int (*fp_close_t)(const struct driver *);
 | 
			
		||||
typedef int (*fp_read_t)(const struct driver *, char *, unsigned int);
 | 
			
		||||
typedef int (*fp_write_t)(const struct driver *, const char *, unsigned int);
 | 
			
		||||
typedef int (*fp_ioctl_t)(const struct driver *, unsigned int, unsigned int argc, va_list);
 | 
			
		||||
 | 
			
		||||
struct driver_fp {
 | 
			
		||||
    fp_open_t   open;
 | 
			
		||||
    fp_close_t  close;
 | 
			
		||||
    fp_read_t   read;
 | 
			
		||||
    fp_write_t  write;
 | 
			
		||||
    fp_ioctl_t  ioctl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct driver {
 | 
			
		||||
    const char *name;
 | 
			
		||||
    const struct driver_fp *fp;
 | 
			
		||||
    const void *dev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int drv_open(const struct driver *drv);
 | 
			
		||||
int drv_close(const struct driver *drv);
 | 
			
		||||
int drv_read(const struct driver *drv, char *buffer, unsigned int length);
 | 
			
		||||
int drv_write(const struct driver *drv, const char *buffer, unsigned int length);
 | 
			
		||||
int drv_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, ...);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										6
									
								
								src/clock_face.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/clock_face.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										67
									
								
								src/driver.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/driver.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include "driver.h"
 | 
			
		||||
 | 
			
		||||
int drv_open(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    int res = -1;
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    if(drv->fp->open) {
 | 
			
		||||
        res = drv->fp->open(drv);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int drv_close(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    int res = -1;
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    if(drv->fp->close) {
 | 
			
		||||
        res = drv->fp->close(drv);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int drv_read(const struct driver *drv, char *buffer, unsigned int length)
 | 
			
		||||
{
 | 
			
		||||
    int res = -1;
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    if(drv->fp->read) {
 | 
			
		||||
        res =  drv->fp->read(drv, buffer, length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int drv_write(const struct driver *drv, const char *buffer, unsigned int length)
 | 
			
		||||
{
 | 
			
		||||
    int res = -1;
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    if(drv->fp->write) {
 | 
			
		||||
        res =  drv->fp->write(drv, buffer, length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int drv_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, ...)
 | 
			
		||||
{
 | 
			
		||||
    int res = -1;
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    if(drv->fp->ioctl) {
 | 
			
		||||
        va_list args;
 | 
			
		||||
        va_start(args, argc);
 | 
			
		||||
        res = drv->fp->ioctl(drv, cmd, argc, args);
 | 
			
		||||
        va_end(args);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include "board.h"
 | 
			
		||||
#include "driver.h"
 | 
			
		||||
#include "clock_face.h"
 | 
			
		||||
 | 
			
		||||
uint16_t image[240 * 240];
 | 
			
		||||
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
    drv_open(&lcd_drv);
 | 
			
		||||
    for (uint16_t i = 0; i < 240 * 240; i++) {
 | 
			
		||||
        image[i] = 0xffff;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drv_write(&lcd_drv, (const char *)image, 240 * 240);
 | 
			
		||||
    sleep(5);
 | 
			
		||||
    drv_write(&lcd_drv, (const char *)clock_face, 240 * 240);
 | 
			
		||||
    sleep(5);
 | 
			
		||||
    drv_close(&lcd_drv);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										168
									
								
								src/posix/gpio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/posix/gpio.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "gpio.h"
 | 
			
		||||
#define BUF_SIZE	3
 | 
			
		||||
#define DIRECTION_MAX	35
 | 
			
		||||
#define VALUE_MAX	30
 | 
			
		||||
 | 
			
		||||
static int gpio_export(int pin);
 | 
			
		||||
static int gpio_unexport(int pin);
 | 
			
		||||
static int gpio_set_direction(int pin, int dir);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int gpio_open(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    int res;
 | 
			
		||||
 | 
			
		||||
    assert(NULL != drv);
 | 
			
		||||
 | 
			
		||||
    struct gpio *this = (struct gpio *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    res = gpio_unexport(this->pin);
 | 
			
		||||
    res = gpio_export(this->pin);
 | 
			
		||||
    usleep(100000); /* Wait until sysfs is exported. */
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gpio_close(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    int res;
 | 
			
		||||
 | 
			
		||||
    assert(NULL != drv);
 | 
			
		||||
 | 
			
		||||
    struct gpio *this = (struct gpio *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    res = gpio_unexport(this->pin);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gpio_read(const struct driver *drv, char *buffer, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    assert(NULL != drv);
 | 
			
		||||
 | 
			
		||||
    char path[VALUE_MAX];
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    struct gpio *this = (struct gpio *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", this->pin);
 | 
			
		||||
    fd = open(path, O_RDONLY);
 | 
			
		||||
    if(-1 == fd) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(-1 == read(fd, buffer, len)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    close(fd);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gpio_write(const struct driver *drv, const char *buffer, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    assert(NULL != drv);
 | 
			
		||||
 | 
			
		||||
    char path[VALUE_MAX];
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    struct gpio *this = (struct gpio *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", this->pin);
 | 
			
		||||
    fd = open(path, O_WRONLY);
 | 
			
		||||
    if(-1 == fd) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int res;
 | 
			
		||||
    if((res = write(fd, buffer, len)) != 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    close(fd);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int gpio_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != 0);
 | 
			
		||||
 | 
			
		||||
    int res = 0, dir;
 | 
			
		||||
    struct gpio *this = (struct gpio *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    switch(cmd) {
 | 
			
		||||
        case IOCTL_CMD_SET_DIRECTION:
 | 
			
		||||
            if(argc != 1) {
 | 
			
		||||
                res = -1;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            dir = va_arg(args, int);
 | 
			
		||||
            res = gpio_set_direction(this->pin, dir);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gpio_export(int pin)
 | 
			
		||||
{
 | 
			
		||||
    char buffer[BUF_SIZE];
 | 
			
		||||
    ssize_t bytes_written;
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    fd = open("/sys/class/gpio/export", O_WRONLY);
 | 
			
		||||
    if(-1 == fd) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bytes_written = snprintf(buffer, BUF_SIZE, "%d", pin);
 | 
			
		||||
    write(fd, buffer, bytes_written);
 | 
			
		||||
    close(fd);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gpio_unexport(int pin)
 | 
			
		||||
{
 | 
			
		||||
    char buffer[BUF_SIZE];
 | 
			
		||||
    ssize_t bytes_written;
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    fd = open("/sys/class/gpio/unexport", O_WRONLY);
 | 
			
		||||
    if(-1 == fd) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bytes_written = snprintf(buffer, BUF_SIZE, "%d", pin);
 | 
			
		||||
    write(fd, buffer, bytes_written);
 | 
			
		||||
    close(fd);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gpio_set_direction(int pin, int dir)
 | 
			
		||||
{
 | 
			
		||||
    static const char directions_str[]  = "in\0out";
 | 
			
		||||
    char path[DIRECTION_MAX];
 | 
			
		||||
    int fd;
 | 
			
		||||
 | 
			
		||||
    snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);
 | 
			
		||||
    fd = open(path, O_WRONLY);
 | 
			
		||||
    if(-1 == fd) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(-1 == write(fd, &directions_str[0 == dir ? 0 : 3], 0 == dir ? 2 : 3)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    close(fd);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								src/posix/i2c.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/posix/i2c.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <linux/i2c-dev.h>
 | 
			
		||||
 | 
			
		||||
#include "posix/i2c.h"
 | 
			
		||||
 | 
			
		||||
int i2c_open(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct i2c *i2c = (struct i2c *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    if((i2c->i2c_file = open(i2c->i2c_device, O_RDWR)) < 0) {
 | 
			
		||||
        fprintf(stderr, "Failed to open the i2c bus\r\n");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(ioctl(i2c->i2c_file, I2C_SLAVE, i2c->slave_addr) < 0) {
 | 
			
		||||
        fprintf(stderr, "Failed to acquire bus access and/or talk to slave.\r\n");
 | 
			
		||||
        return -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int i2c_close(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct i2c *i2c = (struct i2c *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    close(i2c->i2c_file);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int i2c_read(const struct driver *drv, char *buffer, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct i2c *i2c = (struct i2c *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    if(read(i2c->i2c_file, buffer, len) != len) {
 | 
			
		||||
        fprintf(stderr, "Failed to read from the i2c bus.\r\n");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int i2c_write(const struct driver *drv, const char *buffer, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct i2c *i2c = (struct i2c *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    if(write(i2c->i2c_file, buffer, len) != len) {
 | 
			
		||||
        fprintf(stderr, "Failed to write to the i2c bus.\r\n");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										120
									
								
								src/posix/spi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/posix/spi.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
 | 
			
		||||
#include "spi.h"
 | 
			
		||||
 | 
			
		||||
int spi_open(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    int res;
 | 
			
		||||
    struct spi *this = (struct spi *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    // open spi dev
 | 
			
		||||
    this->spi_file = open(this->spi_device, O_RDWR);
 | 
			
		||||
    if(this->spi_file < 0) {
 | 
			
		||||
        return this->spi_file;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // set spi mode
 | 
			
		||||
    res = ioctl(this->spi_file, SPI_IOC_WR_MODE, &(this->mode));
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        close(this->spi_file);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = ioctl(this->spi_file, SPI_IOC_RD_MODE, &(this->mode));
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        close(this->spi_file);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // set word length
 | 
			
		||||
    res = ioctl(this->spi_file, SPI_IOC_WR_BITS_PER_WORD, &(this->bits_per_word));
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        close(this->spi_file);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = ioctl(this->spi_file, SPI_IOC_RD_BITS_PER_WORD, &(this->bits_per_word));
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        close(this->spi_file);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // set max speed
 | 
			
		||||
    res = ioctl(this->spi_file, SPI_IOC_WR_MAX_SPEED_HZ, &(this->speed));
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        close(this->spi_file);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = ioctl(this->spi_file, SPI_IOC_RD_MAX_SPEED_HZ, &(this->speed));
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        close(this->spi_file);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->is_open = true;
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spi_close(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    int res = -1;
 | 
			
		||||
    struct spi *this = (struct spi *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    if(this->is_open == true) {
 | 
			
		||||
        close(this->spi_file);
 | 
			
		||||
        this->is_open = false;
 | 
			
		||||
        res = 0;
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spi_read(const struct driver *drv, char *buffer, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct spi *this = (struct spi *)(drv->dev);
 | 
			
		||||
    struct spi_ioc_transfer tr = {
 | 
			
		||||
        .tx_buf = (unsigned long)0,
 | 
			
		||||
        .rx_buf = (unsigned long)buffer,
 | 
			
		||||
        .delay_usecs = 0,
 | 
			
		||||
        .speed_hz = this->speed,
 | 
			
		||||
        .bits_per_word = this->bits_per_word,
 | 
			
		||||
        .len = len,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    int res = ioctl(this->spi_file, SPI_IOC_MESSAGE(1), &tr);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spi_write(const struct driver *drv, const char *buffer, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct spi *this = (struct spi *)(drv->dev);
 | 
			
		||||
    struct spi_ioc_transfer tr = {
 | 
			
		||||
        .tx_buf = (unsigned long)buffer,
 | 
			
		||||
        .rx_buf = (unsigned long)0,
 | 
			
		||||
        .len = len,
 | 
			
		||||
        .delay_usecs = 0,
 | 
			
		||||
        .speed_hz = this->speed,
 | 
			
		||||
        .bits_per_word = this->bits_per_word,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    int res = ioctl(this->spi_file, SPI_IOC_MESSAGE(1), &tr);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int spi_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										249
									
								
								src/ssd1306.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								src/ssd1306.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,249 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include "ssd1306.h"
 | 
			
		||||
 | 
			
		||||
static void ssd1306_display(const struct driver *drv);
 | 
			
		||||
static void ssd1306_cls(const struct driver *drv);
 | 
			
		||||
static void ssd1306_dot(const struct driver *drv, uint32_t x, uint32_t y);
 | 
			
		||||
static void ssd1306_line(const struct driver *drv, int16_t x0, int16_t y0, int16_t x1, int16_t y1);
 | 
			
		||||
static void ssd1306_circle(const struct driver *drv, int16_t x0, int16_t y0, int16_t radius);
 | 
			
		||||
 | 
			
		||||
static void ssd1306_on(const struct driver *drv);
 | 
			
		||||
static void ssd1306_off(const struct driver *drv);
 | 
			
		||||
static void ssd1306_cmd(const struct driver *drv, uint8_t c);
 | 
			
		||||
static void ssd1306_reset_cursor(const struct driver *drv);
 | 
			
		||||
 | 
			
		||||
int ssd1306_open(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    drv_open(this->output_dev);
 | 
			
		||||
 | 
			
		||||
    ssd1306_off(drv);
 | 
			
		||||
 | 
			
		||||
    ssd1306_cmd(drv, 0xa8); // Set Multiplex Ratio
 | 
			
		||||
    ssd1306_cmd(drv, 0x3f); // Value
 | 
			
		||||
    ssd1306_cmd(drv, 0xd3); // Set Display offset
 | 
			
		||||
    ssd1306_cmd(drv, 0x00); // no vertical shift
 | 
			
		||||
    ssd1306_cmd(drv, 0x40); // set display start line
 | 
			
		||||
    ssd1306_cmd(drv, 0xa1); // set segment re-map
 | 
			
		||||
    ssd1306_cmd(drv, 0xc8);
 | 
			
		||||
    ssd1306_cmd(drv, 0xda);
 | 
			
		||||
    ssd1306_cmd(drv, 0x12);
 | 
			
		||||
    ssd1306_cmd(drv, 0xa4);
 | 
			
		||||
    ssd1306_cmd(drv, 0xa6);
 | 
			
		||||
    ssd1306_cmd(drv, 0xd5);
 | 
			
		||||
    ssd1306_cmd(drv, 0x80);
 | 
			
		||||
    ssd1306_cmd(drv, 0x8d);
 | 
			
		||||
    ssd1306_cmd(drv, 0x14);
 | 
			
		||||
    ssd1306_cmd(drv, 0x20);
 | 
			
		||||
    ssd1306_cmd(drv, 0x20);
 | 
			
		||||
 | 
			
		||||
    ssd1306_on(drv);
 | 
			
		||||
    ssd1306_reset_cursor(drv);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ssd1306_close(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != 0);
 | 
			
		||||
 | 
			
		||||
    struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    ssd1306_off(drv);
 | 
			
		||||
 | 
			
		||||
    drv_close(this->output_dev);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ssd1306_ioctl(const struct driver *drv, unsigned int cmd, unsigned int argc, va_list args)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != 0);
 | 
			
		||||
 | 
			
		||||
    int res = 0;
 | 
			
		||||
            unsigned int xy[4];
 | 
			
		||||
 | 
			
		||||
    switch(cmd) {
 | 
			
		||||
        case IOCTL_CMD_CLS:
 | 
			
		||||
            ssd1306_cls(drv);
 | 
			
		||||
            break;
 | 
			
		||||
        case IOCTL_CMD_REFRESH:
 | 
			
		||||
            ssd1306_display(drv);
 | 
			
		||||
            break;
 | 
			
		||||
        case IOCTL_CMD_DRAW_PIXEL:
 | 
			
		||||
            if(argc != 2) {
 | 
			
		||||
                res = -1;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            for(unsigned int i = 0; i < argc; i++) {
 | 
			
		||||
                xy[i] = va_arg(args, unsigned int);
 | 
			
		||||
            }
 | 
			
		||||
            ssd1306_dot(drv, xy[0], xy[1]);
 | 
			
		||||
            break;
 | 
			
		||||
        case IOCTL_CMD_DRAW_LINE:
 | 
			
		||||
            if(argc != 4) {
 | 
			
		||||
                res = -1;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            for(unsigned int i = 0; i < argc; i++) {
 | 
			
		||||
                xy[i] = va_arg(args, unsigned int);
 | 
			
		||||
            }
 | 
			
		||||
            ssd1306_line(drv, xy[0], xy[1], xy[2], xy[3]);
 | 
			
		||||
            break;
 | 
			
		||||
        case IOCTL_CMD_DRAW_CIRCLE:
 | 
			
		||||
            if(argc != 3) {
 | 
			
		||||
                res = -1;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            for(unsigned int i = 0; i < argc; i++) {
 | 
			
		||||
                xy[i] = va_arg(args, unsigned int);
 | 
			
		||||
            }
 | 
			
		||||
            ssd1306_circle(drv, xy[0], xy[1], xy[2]);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ssd1306_cmd(const struct driver *drv, uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    char control[] = {0x00, c};   // Co = 0, D/C = 0
 | 
			
		||||
    drv_write(this->output_dev, control, sizeof(control));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ssd1306_off(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    ssd1306_cmd(drv, 0xae); // display off
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ssd1306_on(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    ssd1306_cmd(drv, 0xaf); // display on
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ssd1306_reset_cursor(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    ssd1306_cmd(drv, 0x21); // # set column address
 | 
			
		||||
    ssd1306_cmd(drv, 0x00); // #   set start address
 | 
			
		||||
    ssd1306_cmd(drv, 0x7F); // #   set end address (127 max)
 | 
			
		||||
    ssd1306_cmd(drv, 0x22); // # set page address
 | 
			
		||||
    ssd1306_cmd(drv, 0x00); // #   set start address
 | 
			
		||||
    ssd1306_cmd(drv, 0x07); // #   set end address (7 max)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ssd1306_cls(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    memset(this->bitmap, 0x00, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ssd1306_display(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    drv_write(this->output_dev, this->output_buffer, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8) + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ssd1306_dot(const struct driver *drv, uint32_t x, uint32_t y)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct ssd1306 *this = (struct ssd1306 *)(drv->dev);
 | 
			
		||||
 | 
			
		||||
    this->bitmap[x + (y / 8) * SSD1306_LCDWIDTH] |=  (1 << (y & 7));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef _swap_int16_t
 | 
			
		||||
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void ssd1306_line(const struct driver *drv, int16_t x0, int16_t y0, int16_t x1, int16_t y1)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    int16_t steep = abs(y1 - y0) > abs(x1 - x0);
 | 
			
		||||
    if(steep) {
 | 
			
		||||
        _swap_int16_t(x0, y0);
 | 
			
		||||
        _swap_int16_t(x1, y1);
 | 
			
		||||
    }
 | 
			
		||||
    if(x0 > x1) {
 | 
			
		||||
        _swap_int16_t(x0, x1);
 | 
			
		||||
        _swap_int16_t(y0, y1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int16_t dx, dy;
 | 
			
		||||
    dx = x1 - x0;
 | 
			
		||||
    dy = abs(y1 - y0);
 | 
			
		||||
 | 
			
		||||
    int16_t err = dx / 2;
 | 
			
		||||
    int16_t ystep;
 | 
			
		||||
 | 
			
		||||
    if(y0 < y1) {
 | 
			
		||||
        ystep = 1;
 | 
			
		||||
    } else {
 | 
			
		||||
        ystep = -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for(; x0 <= x1; x0++) {
 | 
			
		||||
        if(steep) {
 | 
			
		||||
            ssd1306_dot(drv, y0, x0);
 | 
			
		||||
        } else {
 | 
			
		||||
            ssd1306_dot(drv, x0, y0);
 | 
			
		||||
        }
 | 
			
		||||
        err -= dy;
 | 
			
		||||
        if (err < 0) {
 | 
			
		||||
            y0 += ystep;
 | 
			
		||||
            err += dx;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ssd1306_circle(const struct driver *drv, int16_t x0, int16_t y0, int16_t radius)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    int16_t x = 0, y = radius;
 | 
			
		||||
    int16_t dp = 1 - radius;
 | 
			
		||||
    do {
 | 
			
		||||
        if (dp < 0) {
 | 
			
		||||
            dp = dp + (x++) * 2 + 3;
 | 
			
		||||
        } else {
 | 
			
		||||
            dp = dp + (x++) * 2 - (y--) * 2 + 5;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ssd1306_dot(drv, x0 + x, y0 + y);     //For the 8 octants
 | 
			
		||||
        ssd1306_dot(drv, x0 - x, y0 + y);
 | 
			
		||||
        ssd1306_dot(drv, x0 + x, y0 - y);
 | 
			
		||||
        ssd1306_dot(drv, x0 - x, y0 - y);
 | 
			
		||||
        ssd1306_dot(drv, x0 + y, y0 + x);
 | 
			
		||||
        ssd1306_dot(drv, x0 - y, y0 + x);
 | 
			
		||||
        ssd1306_dot(drv, x0 + y, y0 - x);
 | 
			
		||||
        ssd1306_dot(drv, x0 - y, y0 - x);
 | 
			
		||||
    } while (x < y);
 | 
			
		||||
 | 
			
		||||
    ssd1306_dot(drv, x0 + radius, y0);
 | 
			
		||||
    ssd1306_dot(drv, x0, y0 + radius);
 | 
			
		||||
    ssd1306_dot(drv, x0 - radius, y0);
 | 
			
		||||
    ssd1306_dot(drv, x0, y0 - radius);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										270
									
								
								src/st7789.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								src/st7789.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,270 @@
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "st7789.h"
 | 
			
		||||
 | 
			
		||||
static void send_cmd(const struct driver *drv, uint8_t cmd);
 | 
			
		||||
static void send_data_8bit(const struct driver *drv, uint8_t data);
 | 
			
		||||
 | 
			
		||||
static void lcd_init(const struct driver *drv);
 | 
			
		||||
static void lcd_set_windows(const struct driver *drv, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end);
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
static void send_data_16bit(const struct driver *drv, uint16_t data);
 | 
			
		||||
static void lcd_clear(const struct driver *drv, uint16_t color);
 | 
			
		||||
static void lcd_display(const struct driver *drv, const uint16_t *image);
 | 
			
		||||
static void lcd_draw_pixel(const struct driver *drv, uint16_t x, uint16_t y, uint16_t color);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int st7789_open(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    struct st7789 *this = (struct st7789*)(drv->dev);
 | 
			
		||||
    int res = drv_open(this->rst);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_ioctl(this->rst, 0, 1, 1);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_write(this->rst, "1", 1);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_open(this->dc);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_ioctl(this->dc, 0, 1, 1);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        drv_close(this->dc);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_write(this->dc, "1", 1);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        drv_close(this->dc);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_open(this->bl);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        drv_close(this->dc);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_ioctl(this->bl, 0, 1, 1);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        drv_close(this->dc);
 | 
			
		||||
        drv_close(this->bl);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_write(this->bl, "1", 1);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        drv_close(this->dc);
 | 
			
		||||
        drv_close(this->bl);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    res = drv_open(this->spi);
 | 
			
		||||
    if(res < 0) {
 | 
			
		||||
        drv_close(this->rst);
 | 
			
		||||
        drv_close(this->dc);
 | 
			
		||||
        drv_close(this->bl);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
    // hard reset
 | 
			
		||||
    res = drv_write(this->rst, "0", 1);
 | 
			
		||||
    usleep(100 * 1000);
 | 
			
		||||
    res = drv_write(this->rst, "1", 1);
 | 
			
		||||
    usleep(100 * 1000);
 | 
			
		||||
 | 
			
		||||
    lcd_init(drv);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int st7789_close(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    struct st7789 *this = (struct st7789*)(drv->dev);
 | 
			
		||||
    drv_close(this->rst);
 | 
			
		||||
    drv_close(this->dc);
 | 
			
		||||
    drv_close(this->bl);
 | 
			
		||||
    drv_close(this->spi);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int st7789_write(const struct driver *drv, const char *buffer, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    struct st7789 *this = (struct st7789*)(drv->dev);
 | 
			
		||||
    uint16_t *image = (uint16_t *)buffer;
 | 
			
		||||
    lcd_set_windows(drv, 0, 0, this->width, this->height);
 | 
			
		||||
    drv_write(this->dc, "1", 1);
 | 
			
		||||
    for (uint16_t i = 0; i < this->height; i++) {
 | 
			
		||||
        drv_write(this->spi, (const char *)&image[i * this->width], this->width * 2);
 | 
			
		||||
    }
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void send_cmd(const struct driver *drv, uint8_t cmd)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    struct st7789 *this = (struct st7789*)(drv->dev);
 | 
			
		||||
    drv_write(this->dc, "0", 1);
 | 
			
		||||
    drv_write(this->spi, (const char* )&cmd, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void send_data_8bit(const struct driver *drv, uint8_t data)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    struct st7789 *this = (struct st7789*)(drv->dev);
 | 
			
		||||
    drv_write(this->dc, "1", 1);
 | 
			
		||||
    drv_write(this->spi, (const char* )&data, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_init(const struct driver *drv)
 | 
			
		||||
{
 | 
			
		||||
    send_cmd(drv, 0x3A);
 | 
			
		||||
    send_data_8bit(drv, 0x05);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0xB2);
 | 
			
		||||
    send_data_8bit(drv, 0x0C);
 | 
			
		||||
    send_data_8bit(drv, 0x0C);
 | 
			
		||||
    send_data_8bit(drv, 0x00);
 | 
			
		||||
    send_data_8bit(drv, 0x33);
 | 
			
		||||
    send_data_8bit(drv, 0x33);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0xB7);  //Gate Control
 | 
			
		||||
    send_data_8bit(drv, 0x35);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0xBB);  //VCOM Setting
 | 
			
		||||
    send_data_8bit(drv, 0x19);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0xC0); //LCM Control
 | 
			
		||||
    send_data_8bit(drv, 0x2C);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0xC2);  //VDV and VRH Command Enable
 | 
			
		||||
    send_data_8bit(drv, 0x01);
 | 
			
		||||
    send_cmd(drv, 0xC3);  //VRH Set
 | 
			
		||||
    send_data_8bit(drv, 0x12);
 | 
			
		||||
    send_cmd(drv, 0xC4);  //VDV Set
 | 
			
		||||
    send_data_8bit(drv, 0x20);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0xC6);  //Frame Rate Control in Normal Mode
 | 
			
		||||
    send_data_8bit(drv, 0x0F);
 | 
			
		||||
    
 | 
			
		||||
    send_cmd(drv, 0xD0);  // Power Control 1
 | 
			
		||||
    send_data_8bit(drv, 0xA4);
 | 
			
		||||
    send_data_8bit(drv, 0xA1);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0xE0);  //Positive Voltage Gamma Control
 | 
			
		||||
    send_data_8bit(drv, 0xD0);
 | 
			
		||||
    send_data_8bit(drv, 0x04);
 | 
			
		||||
    send_data_8bit(drv, 0x0D);
 | 
			
		||||
    send_data_8bit(drv, 0x11);
 | 
			
		||||
    send_data_8bit(drv, 0x13);
 | 
			
		||||
    send_data_8bit(drv, 0x2B);
 | 
			
		||||
    send_data_8bit(drv, 0x3F);
 | 
			
		||||
    send_data_8bit(drv, 0x54);
 | 
			
		||||
    send_data_8bit(drv, 0x4C);
 | 
			
		||||
    send_data_8bit(drv, 0x18);
 | 
			
		||||
    send_data_8bit(drv, 0x0D);
 | 
			
		||||
    send_data_8bit(drv, 0x0B);
 | 
			
		||||
    send_data_8bit(drv, 0x1F);
 | 
			
		||||
    send_data_8bit(drv, 0x23);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0xE1);  //Negative Voltage Gamma Control
 | 
			
		||||
    send_data_8bit(drv, 0xD0);
 | 
			
		||||
    send_data_8bit(drv, 0x04);
 | 
			
		||||
    send_data_8bit(drv, 0x0C);
 | 
			
		||||
    send_data_8bit(drv, 0x11);
 | 
			
		||||
    send_data_8bit(drv, 0x13);
 | 
			
		||||
    send_data_8bit(drv, 0x2C);
 | 
			
		||||
    send_data_8bit(drv, 0x3F);
 | 
			
		||||
    send_data_8bit(drv, 0x44);
 | 
			
		||||
    send_data_8bit(drv, 0x51);
 | 
			
		||||
    send_data_8bit(drv, 0x2F);
 | 
			
		||||
    send_data_8bit(drv, 0x1F);
 | 
			
		||||
    send_data_8bit(drv, 0x1F);
 | 
			
		||||
    send_data_8bit(drv, 0x20);
 | 
			
		||||
    send_data_8bit(drv, 0x23);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0x21);  //Display Inversion On
 | 
			
		||||
    send_cmd(drv, 0x11);  //Sleep Out
 | 
			
		||||
    send_cmd(drv, 0x29);  //Display On
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_set_windows(const struct driver *drv, uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end)
 | 
			
		||||
{
 | 
			
		||||
    //set the X coordinates
 | 
			
		||||
    send_cmd(drv, 0x2A);
 | 
			
		||||
    send_data_8bit(drv, (x_start >> 8) & 0xFF);
 | 
			
		||||
    send_data_8bit(drv, x_start & 0xFF);
 | 
			
		||||
    send_data_8bit(drv, ((x_end  - 1) >> 8) & 0xFF);
 | 
			
		||||
    send_data_8bit(drv, (x_end  - 1) & 0xFF);
 | 
			
		||||
 | 
			
		||||
    //set the Y coordinates
 | 
			
		||||
    send_cmd(drv, 0x2B);
 | 
			
		||||
    send_data_8bit(drv, (y_start >> 8) & 0xFF);
 | 
			
		||||
    send_data_8bit(drv, y_start & 0xFF);
 | 
			
		||||
    send_data_8bit(drv, ((y_end  - 1) >> 8) & 0xFF);
 | 
			
		||||
    send_data_8bit(drv, (y_end  - 1) & 0xFF);
 | 
			
		||||
 | 
			
		||||
    send_cmd(drv, 0X2C);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
static void send_data_16bit(const struct driver *drv, uint16_t data)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct st7789 *this = (struct st7789*)(drv->dev);
 | 
			
		||||
    uint8_t buf[2] = {(data >> 8) & 0xff, data & 0xff};
 | 
			
		||||
    drv_write(this->dc, "1", 1);
 | 
			
		||||
    drv_write(this->spi, (const char* )buf, 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_clear(const struct driver *drv, uint16_t color)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
 | 
			
		||||
    struct st7789 *this = (struct st7789*)(drv->dev);
 | 
			
		||||
    uint16_t image[this->height * this->width];
 | 
			
		||||
 | 
			
		||||
    color = ((color << 8) & 0xff00) | (color >> 8);
 | 
			
		||||
    for (uint16_t i = 0; i < this->height * this->width; i++) {
 | 
			
		||||
        image[i] = color;
 | 
			
		||||
    }
 | 
			
		||||
    lcd_set_windows(drv, 0, 0, this->width, this->height);
 | 
			
		||||
    drv_write(this->dc, "1", 1);
 | 
			
		||||
    for(uint16_t i = 0; i < this->height; i++) {
 | 
			
		||||
        drv_write(this->spi, (const char *)&image[i * this->width], this->width * 2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_display(const struct driver *drv, const uint16_t *image)
 | 
			
		||||
{
 | 
			
		||||
    assert(drv != NULL);
 | 
			
		||||
    struct st7789 *this = (struct st7789*)(drv->dev);
 | 
			
		||||
    lcd_set_windows(drv, 0, 0, this->width, this->height);
 | 
			
		||||
    drv_write(this->dc, "1", 1);
 | 
			
		||||
    for (uint16_t i = 0; i < this->height; i++) {
 | 
			
		||||
        drv_write(this->spi, (const char *)&image[i * this->width], this->width * 2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_draw_pixel(const struct driver *drv, uint16_t x, uint16_t y, uint16_t color)
 | 
			
		||||
{
 | 
			
		||||
    lcd_set_windows(drv, x, y, x + 1, y + 1);
 | 
			
		||||
    send_data_16bit(drv, color);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
		Reference in New Issue
	
	Block a user