10 Commits
49 changed files with 4410 additions and 1418 deletions
+63 -21
View File
@@ -1,60 +1,98 @@
## === CPU settings ===
###################################
# Makefile for MightyPork/avr-lib #
# Revision 3 #
###################################
## ===== CPU settings =====
# CPU type
MCU = atmega328p
# CPU frequency
F_CPU = 16000000
# Fuses
LFUSE = 0xFF
HFUSE = 0xDE
EFUSE = 0x05
OPTIMIZE = s
## ===== Source files =====
## === Source files ===
# Main C file
MAIN = main.c
# Extra C files in this folder
LOCAL_SOURCE =
# Library directory (with C files)
EXTRA_SOURCE_DIR = lib/
# Library directory (with C and H files)
LIB_DIR = lib/
# C files in the library directory
EXTRA_SOURCE_FILES = uart.c
LIB_C_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c
# Extra Files that need config file:
#LIB_C_FILES += lcd.c
#LIB_C_FILES += color.c wsrgb.c
#LIB_C_FILES += debouce.c
LIB_H_FILES = adc.h calc.h dht11.h fat16.h fat16_internal.h iopins.h nsdelay.h onewire.h sd.h sonar.h spi.h stream.h uart.h
LIB_H_FILES += lcd.h color.h wsrgb.h debounce.h
## === Programmer ===
## ===== Programmer =====
PROGRAMMER_TYPE = arduino
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
## === C flags ===
## ===== C flags =====
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(EXTRA_SOURCE_DIR)
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment
CFLAGS += -g2 -Wextra -Wfatal-errors -Wno-unused-but-set-variable
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax
# CFLAGS += -lm ## Math
# CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
# CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
CFLAGS_BUILD = $(CFLAGS) -Os
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(LIB_DIR)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -finline-functions
CFLAGS += -ffunction-sections
CFLAGS += -fdata-sections
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wno-main
CFLAGS += -Wno-comment
CFLAGS += -Wno-unused-but-set-variable
CFLAGS += -Wfatal-errors
CFLAGS += -Wl,--gc-sections
CFLAGS += -Wl,--relax
CFLAGS += -Wl,--relax
#CFLAGS += -lm ## Math
#CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## Floating-point printf
#CFLAGS += -Wl,-u,vfprintf -lprintf_min ## Smaller printf
CFLAGS_BUILD = $(CFLAGS) -O$(OPTIMIZE)
# ---------------------------------------------------------------------------
## Defined programs / locations
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
UART_TERM = gtkterm -p /dev/ttyUSB0
## === File lists ===
TARGET = $(strip $(basename $(MAIN)))
SRC1 = $(TARGET).c
SRC = $(SRC1)
EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES))
EXTRA_SOURCE = $(addprefix $(LIB_DIR), $(LIB_C_FILES))
LIB_H_FILES_FILES = $(addprefix $(LIB_DIR), $(LIB_H_FILES))
SRC += $(EXTRA_SOURCE)
SRC += $(LOCAL_SOURCE)
HEADERS = $(SRC:.c=.h)
OBJ = $(SRC:.c=.o)
@@ -67,7 +105,7 @@ pre: $(TARGET).pre
%.hex: %.elf
$(OBJCOPY) -R .eeprom -O ihex $< $@
%.elf: $(SRC)
%.elf: $(SRC) $(LIB_H_FILES_FILES) Makefile
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
%.pre: $(SRC1)
@@ -122,6 +160,10 @@ flashe: $(TARGET).eeprom
shell:
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
fser: all flash ser
ser:
$(UART_TERM)
# === fuses ===
+14 -13
View File
@@ -1,23 +1,24 @@
# MightyPork's AVR Library
# "porklib", MightyPork's Arduino Library
I program my Arduinos in plain C, compile it with `avr-gcc` and flash with `avrdude` (all on Linux).
This library aims to make development for AVR in C easy and fun.
Whenever I learn how to do something, I make a library file and put it here.
Modules of the library provide facilities for pin numbering and aliasing,
bitwise operations and accessing internal and external peripherals of the AVR.
The code is tested and optimized for **ATmega328P**, which is used in most Arduinos. I use "Pro Mini" and "Nano".
It takes some inspiration from Arduino, but is written in pure C, which makes it faster
and smaller.
# How to use
Pull requests to add new modules are welcome, please go ahead!
Link the `lib/` folder to your project, and make sure you add all lib `.c` files to your `Makefile`, so it builds are the needed code.
## Makefile
Some library files don't have `.c`, but many do.
You can use the provided Makefile to boild your project with this library.
## Useful things
A project typically consists of one `main.c` file, and some `*_config.c` files where the
library headers request it (those define eg. IO pin mapping).
- To easily alias I/O pins, use `lib/pins.h`.
- For Arduino pins, there are presets in `lib/arduino_pins.h`
- Binary/byte manipulation utilities are in `lib/calc.h`
- `lib/meta.h` contains some generally useful things that didn't fit elsewhere
Adjust the Makefile to yoru needs!
Each header file contains a comment block with explanation, which will help you understand them.
## License
The library is provided under MIT license, see the LICENSE file for more info.
+2 -2
View File
@@ -11,14 +11,14 @@ EFUSE = 0x05
## === Source files ===
# Main C file
MAIN = uart_isr.c
MAIN = sonar_to_lcd.c
# Extra C files in this folder
LOCAL_SOURCE =
# Library directory (with C files)
EXTRA_SOURCE_DIR = lib/
# C files in the library directory
EXTRA_SOURCE_FILES = uart.c lcd.c sonar.c uart_ansi.c stream.c
EXTRA_SOURCE_FILES = uart.c lcd.c sonar.c stream.c
## === Programmer ===
+7 -9
View File
@@ -2,12 +2,10 @@
// Pin config file for LCD.
#include "lib/arduino_pins.h"
#define LCD_RS D2
#define LCD_RW D3
#define LCD_E D4
#define LCD_D4 D5
#define LCD_D5 D6
#define LCD_D6 D7
#define LCD_D7 D8
#define LCD_RS 2
#define LCD_RW 3
#define LCD_E 4
#define LCD_D4 5
#define LCD_D5 6
#define LCD_D6 7
#define LCD_D7 8
+1 -1
View File
@@ -8,7 +8,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "lib/arduino_pins.h"
#include "lib/iopins.h"
#include "lib/sonar.h"
#include "lib/stream.h"
#include "lib/lcd.h"
-1
View File
@@ -4,7 +4,6 @@
#include <stdint.h>
#include "lib/uart.h"
#include "lib/uart_ansi.h"
#include "lib/stream.h"
//
+4 -4
View File
@@ -23,11 +23,11 @@ void adc_disable()
/** Sample analog pin with 8-bit precision */
uint8_t adc_read_byte(uint8_t channel)
{
write_low_nibble(ADMUX, channel); // Select channel to sample
set_low_nibble(ADMUX, channel); // Select channel to sample
sbi(ADMUX, ADLAR); // Align result to left
sbi(ADCSRA, ADSC); // Start conversion
while(bit_is_high(ADCSRA, ADSC)); // Wait for it...
while (bit_is_high(ADCSRA, ADSC)); // Wait for it...
return ADCH; // The upper 8 bits of ADC result
}
@@ -36,11 +36,11 @@ uint8_t adc_read_byte(uint8_t channel)
/** Sample analog pin with 10-bit precision */
uint16_t adc_read_word(uint8_t channel)
{
write_low_nibble(ADMUX, channel); // Select channel to sample
set_low_nibble(ADMUX, channel); // Select channel to sample
cbi(ADMUX, ADLAR); // Align result to right
sbi(ADCSRA, ADSC); // Start conversion
while(get_bit(ADCSRA, ADSC)); // Wait for it...
while (get_bit(ADCSRA, ADSC)); // Wait for it...
return ADCW; // The whole ADC word (10 bits)
}
-42
View File
@@ -1,42 +0,0 @@
#pragma once
//
// Pin definitions for Arduino (Pro Mini with ATmega328P)
//
#include "pins.h"
#define D0 D,0
#define D1 D,1
#define D2 D,2
#define D3 D,3
#define D4 D,4
#define D5 D,5
#define D6 D,6
#define D7 D,7
#define D8 B,0
#define D9 B,1
#define D10 B,2
// MOSI MISO SCK - not good for input
#define D11 B,3
#define D12 B,4
#define D13 B,5
#define D14 C,0
#define D15 C,1
#define D16 C,2
#define D17 C,3
#define D18 C,4
#define D19 C,5
#define D20 C,6
#define D21 C,7
#define A0 C,0
#define A1 C,1
#define A2 C,2
#define A3 C,3
#define A4 C,4
#define A5 C,5
#define A6 C,6
#define A7 C,7
+54
View File
@@ -0,0 +1,54 @@
#pragma once
//
// Block device interface, somewhat akin to stream.h
// Used for filesystem implementations.
//
#include <stdint.h>
/** Abstract block device interface
*
* Populate an instance of this with pointers to your I/O functions.
*/
typedef struct
{
/** Sequential read at cursor
* @param dest destination memory structure
* @param len number of bytes to load and store in {dest}
*/
void (*load)(void* dest, const uint16_t len);
/** Sequential write at cursor
* @param src source memory structure
* @param len number of bytes to write
*/
void (*store)(const void* src, const uint16_t len);
/** Write one byte at cursor
* @param b byte to write
*/
void (*write)(const uint8_t b);
/** Read one byte at cursor
* @return the read byte
*/
uint8_t (*read)(void);
/** Absolute seek - set cursor
* @param addr new cursor address
*/
void (*seek)(const uint32_t addr);
/** Relative seek - move cursor
* @param offset cursor address change
*/
void (*rseek)(const int16_t offset);
} BLOCKDEV;
+20 -24
View File
@@ -8,7 +8,7 @@
// --- Increment in range ---
// when overflown, wraps within range. Lower bound < upper bound.
// ..., upper bound excluded
#define inc_wrap(var, min, max) do { if ((var) >= (max - 1)) { (var) = (min); } else { (var)++; } } while(0)
#define inc_wrap(var, min, max) { if ((var) >= (max - 1)) { (var) = (min); } else { (var)++; } }
// ..., upper bound included
#define inc_wrapi(var, min, max) inc_wrap((var), (min), (max) + 1)
@@ -16,7 +16,7 @@
// --- Decrement in range ---
// when underflown, wraps within range. Lower bound < upper bound.
// ..., upper bound excluded
#define dec_wrap(var, min, max) do { if ((var) <= (min)) { (var) = (max) - 1; } else { (var)--; } } while(0)
#define dec_wrap(var, min, max) { if ((var) <= (min)) { (var) = (max) - 1; } else { (var)--; } }
// ..., upper bound included
#define dec_wrapi(var, min, max) dec_wrap((var), (min), (max) + 1)
@@ -24,56 +24,52 @@
// --- Bit manipulation --
// Set bit
#define sbi(reg, bit) do { (reg) |= (1 << (uint8_t)(bit)); } while(0)
#define sbi(reg, bit) { (reg) |= (1 << (uint8_t)(bit)); }
// Clear bit
#define cbi(reg, bit) do { (reg) &= ~(1 << (uint8_t)(bit)); } while(0)
#define cbi(reg, bit) { (reg) &= ~(1 << (uint8_t)(bit)); }
// Get n-th bit
#define read_bit(reg, bit) (((reg) >> (uint8_t)(bit)) & 0x1)
#define get_bit(reg, bit) read_bit(reg, bit)
#define get_bit(reg, bit) (((reg) >> (uint8_t)(bit)) & 0x1)
// Test n-th bit (Can't use bit_is_set, as it's redefined in sfr_def.h)
#define bit_is_high(reg, bit) read_bit(reg, bit)
#define bit_is_low(reg, bit) (!read_bit(reg, bit))
#define bit_is_high(reg, bit) get_bit(reg, bit)
#define bit_is_low(reg, bit) (!get_bit(reg, bit))
// Write value to n-th bit
#define write_bit(reg, bit, value) do { (reg) = ((reg) & ~(1 << (uint8_t)(bit))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); } while(0)
#define set_bit(reg, bit, value) write_bit(reg, bit, value)
#define set_bit(reg, bit, value) { (reg) = ((reg) & ~(1 << (uint8_t)(bit))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); }
// Invert n-th bit
#define toggle_bit(reg, bit) do { (reg) ^= (1 << (uint8_t)(bit)); } while(0)
#define toggle_bit(reg, bit) { (reg) ^= (1 << (uint8_t)(bit)); }
// --- Bit manipulation with pointer to variable ---
// Set n-th bit in pointee
#define sbi_p(reg_p, bit) do { (*(reg_p)) |= (1 << (uint8_t)(bit)); } while(0)
#define sbi_p(reg_p, bit) { (*(reg_p)) |= (1 << (uint8_t)(bit)); }
// Clear n-th bit in pointee
#define cbi_p(reg_p, bit) do { (*(reg_p)) &= ~(1 << (uint8_t)(bit)); } while(0)
#define cbi_p(reg_p, bit) { (*(reg_p)) &= ~(1 << (uint8_t)(bit)); }
// Get n-th bit in pointee
#define read_bit_p(reg_p, bit) ((*(reg_p) >> (uint8_t)(bit)) & 0x1)
#define get_bit_p(reg_p, bit) read_bit_p(reg_p, bit)
#define get_bit_p(reg_p, bit) ((*(reg_p) >> (uint8_t)(bit)) & 0x1)
// Test n-th bit in pointee (Can't use bit_is_set, as it's redefined in sfr_def.h)
#define bit_is_high_p(reg_p, bit) read_bit_p(reg_p, bit)
#define bit_is_low_p(reg_p, bit) (!read_bit_p(reg_p, bit))
#define bit_is_high_p(reg_p, bit) get_bit_p(reg_p, bit)
#define bit_is_low_p(reg_p, bit) (!get_bit_p(reg_p, bit))
// Write value to a bit in pointee
#define write_bit_p(reg_p, bit, value) do { *(reg_p) = (*(reg_p) & ~(1 << ((uint8_t)(bit) & 0x1))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); } while(0)
#define set_bit_p(reg_p, bit, value) write_bit_p(reg_p, bit, value)
#define toggle_bit_p(reg_p, bit) do { *(reg_p) ^= (1 << (uint8_t)(bit)); } while(0)
#define set_bit_p(reg_p, bit, value) { *(reg_p) = (*(reg_p) & ~(1 << ((uint8_t)(bit) & 0x1))) | (((uint8_t)(value) & 0x1) << (uint8_t)(bit)); }
#define toggle_bit_p(reg_p, bit) { *(reg_p) ^= (1 << (uint8_t)(bit)); }
// --- Nibble manipulation ---
// Replace nibble in a byte
#define write_low_nibble(reg, value) do { (reg) = ((reg) & 0xF0) | ((uint8_t)(value) & 0xF); } while(0)
#define write_high_nibble(reg, value) do { (reg) = ((reg) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); } while(0)
#define set_low_nibble(reg, value) { (reg) = ((reg) & 0xF0) | ((uint8_t)(value) & 0xF); }
#define set_high_nibble(reg, value) { (reg) = ((reg) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); }
#define write_low_nibble_p(reg_p, value) do { *(reg_p) = (*(reg_p) & 0xF0) | ((uint8_t)(value) & 0xF); } while(0)
#define write_high_nibble_p(reg_p, value) do { *(reg_p) = (*(reg_p) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); } while(0)
#define set_low_nibble_p(reg_p, value) { *(reg_p) = (*(reg_p) & 0xF0) | ((uint8_t)(value) & 0xF); }
#define set_high_nibble_p(reg_p, value) { *(reg_p) = (*(reg_p) & 0x0F) | (((uint8_t)(value) & 0xF) << 4); }
#define low_nibble(x) ((uint8_t)(x) & 0xF)
#define high_nibble(x) (((uint8_t)(x) & 0xF0) >> 4)
+25 -11
View File
@@ -1,10 +1,17 @@
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include "colors.h"
#include "hsl.h"
#include "iopins.h"
#include "nsdelay.h"
#include "color.h"
// --- HSL ---
#ifdef HSL_LINEAR
const uint8_t FADE_128[] = {
const uint8_t FADE_128[] =
{
0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4,
5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 10, 10, 10, 11, 12, 13, 14,
14, 15, 16, 17, 18, 20, 21, 22, 24, 26, 27, 28, 30, 31, 32, 34, 35, 36,
@@ -13,30 +20,37 @@
103, 106, 109, 112, 116, 119, 122, 125, 129, 134, 138, 142, 147, 151,
153, 156, 160, 163, 165, 170, 175, 180, 185, 190, 195, 200, 207, 214, 218,
221, 225, 228, 232, 234, 241, 248, 254, 255
};
};
#endif
// based on: https://github.com/lewisd32/avr-hsl2rgb
xrgb_t hsl2xrgb(const hsl_t cc)
xrgb_t hsl_xrgb(const hsl_t cc)
{
// 0 .. 256*3
const uint16_t hh = (uint16_t) cc.h * 3;
const uint8_t hue_mod = hh % 256;
uint8_t r_temp, g_temp, b_temp;
if (hh < 256) {
if (hh < 256)
{
r_temp = hue_mod ^ 255;
g_temp = hue_mod;
b_temp = 0;
} else if (hh < 512) {
}
else if (hh < 512)
{
r_temp = 0;
g_temp = hue_mod ^ 255;
b_temp = hue_mod;
} else if (hh < 768) {
}
else if (hh < 768)
{
r_temp = hue_mod;
g_temp = 0;
b_temp = hue_mod ^ 255;
} else {
}
else
{
r_temp = 0;
g_temp = 0;
b_temp = 0;
@@ -50,7 +64,7 @@ xrgb_t hsl2xrgb(const hsl_t cc)
uint16_t t16;
#ifdef HSL_LINEAR
const uint8_t bri = FADE_128[cc.l>>1];
const uint8_t bri = FADE_128[cc.l >> 1];
#else
const uint8_t bri = cc.l;
#endif
+57
View File
@@ -0,0 +1,57 @@
#pragma once
// --- color types ---
//
// The XXXc macros don't use cast, so they can be used in array initializers.
//
// xrgb ... 3-byte true-color RGB (8 bits per component)
// rgb24 ... 24-bit color value, with equal nr of bits per component
//
// XX_r (_g, _b) ... extract component from the color, and convert it to 0..255
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
typedef struct
{
uint8_t r;
uint8_t g;
uint8_t b;
} xrgb_t;
typedef uint32_t rgb24_t;
#define xrgb(rr, gg, bb) ((xrgb_t)xrgbc(rr, gg, bb))
// xrgb for constant array declarations
#define xrgbc(rr, gg, bb) { .r = ((uint8_t)(rr)), .g = ((uint8_t)(gg)), .b = ((uint8_t)(bb)) }
#define xrgb_r(c) ((uint8_t)(c.r))
#define xrgb_g(c) ((uint8_t)(c.g))
#define xrgb_b(c) ((uint8_t)(c.b))
#define xrgb_rgb24(c) ((((rgb24_t)c.r) << 16) | (((rgb24_t)c.g) << 8) | (((rgb24_t)c.b)))
#define xrgb_rgb15(c) (((((rgb15_t)c.r) & 0xF8) << 7) | ((((rgb15_t)c.g) & 0xF8) << 2) | ((((rgb15_t)c.b) & 0xF8) >> 3))
#define xrgb_rgb12(c) (((((rgb12_t)c.r) & 0xF0) << 4) | ((((rgb12_t)c.g) & 0xF0)) | ((((rgb12_t)c.b) & 0xF0) >> 4))
#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6))
#define rgb24c(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
#define rgb24(r,g,b) ((rgb24_t) rgb24(r,g,b))
#define rgb24_r(c) ((((rgb24_t) (c)) >> 16) & 0xFF)
#define rgb24_g(c) ((((rgb24_t) (c)) >> 8) & 0xFF)
#define rgb24_b(c) ((((rgb24_t) (c)) >> 0) & 0xFF)
#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define rgb24_xrgbc(c) xrgbc(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define add_xrgb(x, y) ((xrgb_t) { (((y).r > (255 - (x).r)) ? 255 : ((x).r + (y).r)), (((y).g > (255 - (x).g)) ? 255 : ((x).g + (y).g)), (((y).b > 255 - (x).b) ? 255 : ((x).b + (y).b)) })
// HSL data structure
typedef struct
{
uint8_t h;
uint8_t s;
uint8_t l;
} hsl_t;
/* Convert HSL to XRGB */
xrgb_t hsl_xrgb(const hsl_t color);
-84
View File
@@ -1,84 +0,0 @@
#pragma once
//
// Some useful utilities for RGB color manipulation
//
// The XXXc macros don't use cast, so they can be used in array initializers.
//
// xrgb ... 3-byte true-color RGB (8 bits per component)
// rgbXX ... XX-bit color value, with equal nr of bits per component
//
// XX_r (_g, _b) ... extract component from the color, and convert it to 0..255
//
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
} xrgb_t;
typedef uint32_t rgb24_t;
typedef uint16_t rgb15_t;
typedef uint16_t rgb12_t;
typedef uint8_t rgb6_t;
#define xrgb(rr, gg, bb) ((xrgb_t)xrgbc(rr, gg, bb))
// xrgb for constant array declarations
#define xrgbc(rr, gg, bb) { .r = ((uint8_t)(rr)), .g = ((uint8_t)(gg)), .b = ((uint8_t)(bb)) }
#define xrgb_r(c) ((uint8_t)(c.r))
#define xrgb_g(c) ((uint8_t)(c.g))
#define xrgb_b(c) ((uint8_t)(c.b))
#define xrgb_rgb24(c) ((((rgb24_t)c.r) << 16) | (((rgb24_t)c.g) << 8) | (((rgb24_t)c.b)))
#define xrgb_rgb15(c) (((((rgb15_t)c.r) & 0xF8) << 7) | ((((rgb15_t)c.g) & 0xF8) << 2) | ((((rgb15_t)c.b) & 0xF8) >> 3))
#define xrgb_rgb12(c) (((((rgb12_t)c.r) & 0xF0) << 4) | ((((rgb12_t)c.g) & 0xF0)) | ((((rgb12_t)c.b) & 0xF0) >> 4))
#define xrgb_rgb6(c) (((((rgb6_t)c.r) & 0xC0) >> 2) | ((((rgb6_t)c.g) & 0xC0) >> 4) | ((((rgb6_t)c.b) & 0xC0) >> 6))
#define rgb24c(r,g,b) (((((rgb24_t)r) & 0xFF) << 16) | ((((rgb24_t)g) & 0xFF) << 8) | (((rgb24_t)b) & 0xFF))
#define rgb24(r,g,b) ((rgb24_t) rgb24(r,g,b))
#define rgb24_r(c) ((((rgb24_t) (c)) >> 16) & 0xFF)
#define rgb24_g(c) ((((rgb24_t) (c)) >> 8) & 0xFF)
#define rgb24_b(c) ((((rgb24_t) (c)) >> 0) & 0xFF)
#define rgb24_xrgb(c) xrgb(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define rgb24_xrgbc(c) xrgbc(rgb24_r(c), rgb24_g(c), rgb24_b(c))
#define rgb15(r,g,b) ((rgb15_t) rgb15c(r,g,b))
#define rgb15c(r,g,b) (((r & 0x1F) << 10) | ((g & 0x1F) << 5) | (b & 0x1F))
#define rgb15_r(c) ((((rgb15_t) (c)) & 0x7C00) >> 7)
#define rgb15_g(c) ((((rgb15_t) (c)) & 0x3E0) >> 2)
#define rgb15_b(c) ((((rgb15_t) (c)) & 0x1F) << 3)
#define rgb15_xrgb(c) xrgb(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb15_rgb24(c) rgb24(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb15_rgb24c(c) rgb24c(rgb15_r(c), rgb15_g(c), rgb15_b(c))
#define rgb12(r,g,b) ((rgb12_t) rgb12c(r,g,b))
#define rgb12c(r,g,b) (((r & 0xF) << 8) | ((g & 0xF) << 4) | (b & 0xF))
#define rgb12_r(c) ((((rgb12_t) (c)) & 0xF00) >> 4)
#define rgb12_g(c) (((rgb12_t) (c)) & 0xF0)
#define rgb12_b(c) (((r(rgb12_t) (c)gb) & 0x0F) << 4)
#define rgb12_xrgb(c) xrgb(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_xrgbc(c) xrgbc(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_rgb24(c) rgb24(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb12_rgb24c(c) rgb24c(rgb12_r(c), rgb12_g(c), rgb12_b(c))
#define rgb6(r,g,b) ((rgb6_t) rgb6c(r,g,b))
#define rgb6c(r,g,b) (((r & 3) << 4) | ((g & 3) << 2) | (b & 3))
#define rgb6_r(c) ((((rgb6_t) (c)) & 0x30) << 2)
#define rgb6_g(c) ((((rgb6_t) (c)) & 0xC) << 4)
#define rgb6_b(c) ((((rgb6_t) (c)) & 0x3) << 6)
#define rgb6_xrgb(c) xrgb(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_xrgbc(c) xrgbc(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_rgb24(c) rgb24(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define rgb6_rgb24c(c) rgb24c(rgb6_r(c), rgb6_g(c), rgb6_b(c))
#define add_xrgb(x, y) ((xrgb_t) { (((y).r > (255 - (x).r)) ? 255 : ((x).r + (y).r)), (((y).g > (255 - (x).g)) ? 255 : ((x).g + (y).g)), (((y).b > 255 - (x).b) ? 255 : ((x).b + (y).b)) })
+15 -8
View File
@@ -3,7 +3,7 @@
#include "debounce.h"
#include "calc.h"
#include "pins.h"
#include "iopins.h"
#include "debo_config.h"
/** Debounce data array */
@@ -11,11 +11,11 @@ uint8_t debo_next_slot = 0;
uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert)
{
debo_slots[debo_next_slot] = (debo_slot_t){
debo_slots[debo_next_slot] = (debo_slot_t)({
.reg = reg,
.bit = bit | ((invert & 1) << 7) | (get_bit_p(reg, bit) << 6), // bit 7 = invert, bit 6 = state
.count = 0,
};
});
return debo_next_slot++;
}
@@ -24,21 +24,28 @@ uint8_t debo_register(PORT_P reg, uint8_t bit, bool invert)
/** Check debounced pins, should be called periodically. */
void debo_tick()
{
for (uint8_t i = 0; i < debo_next_slot; i++) {
for (uint8_t i = 0; i < debo_next_slot; i++)
{
// current pin value (right 3 bits, xored with inverse bit)
bool value = get_bit_p(debo_slots[i].reg, debo_slots[i].bit & 0x7);
if (value != get_bit(debo_slots[i].bit, 6)) {
if (value != get_bit(debo_slots[i].bit, 6))
{
// different pin state than last recorded state
if (debo_slots[i].count < DEBO_TICKS) {
if (debo_slots[i].count < DEBO_TICKS)
{
debo_slots[i].count++;
} else {
}
else
{
// overflown -> latch value
set_bit(debo_slots[i].bit, 6, value); // set state bit
debo_slots[i].count = 0;
}
} else {
}
else
{
debo_slots[i].count = 0; // reset the counter
}
}
+15 -14
View File
@@ -7,17 +7,10 @@
//
// You must provide a config file debo_config.h (next to your main.c)
//
// Example:
// #pragma once
// #define DEBO_CHANNELS 2
// #define DDEBO_TICKS 5
//
// ----
//
// A pin is registered like this:
//
// #define BTN1 B,0
// #define BTN2 B,1
// #define BTN1 12 // pin D12
// #define BTN2 13
//
// debo_add(BTN0); // The function returns number assigned to the pin (0, 1, ...)
// debo_add_rev(BTN1); // active low
@@ -38,11 +31,19 @@
#include <stdbool.h>
#include "calc.h"
#include "pins.h"
#include "iopins.h"
// Your config file
#include "debo_config.h"
/*
#define DEBO_CHANNELS 2
#define DDEBO_TICKS 5
*/
/* Internal deboucer entry */
typedef struct {
typedef struct
{
PORT_P reg; // pointer to IO register
uint8_t bit; // bits 6 and 7 of this hold "state" & "invert" flag
uint8_t count; // number of ticks this was in the new state
@@ -50,9 +51,9 @@ typedef struct {
debo_slot_t debo_slots[DEBO_CHANNELS];
/** Add a pin for debouncing */
#define debo_add_rev(io) debo_register(&io2pin(io_pack(io)), io2n(io_pack(io)), 1)
#define debo_add(io) debo_register(&io2pin(io_pack(io)), io2n(io_pack(io)), 0)
/** Add a pin for debouncing (must be used with constant args) */
#define debo_add_rev(pin) debo_register(&_pin(pin), _pn(pin), 1)
#define debo_add(pin) debo_register(&_pin(pin), _pn(pin), 0)
/** Add a pin for debouncing (low level function) */
uint8_t debo_register(PORT_P pin_reg_pointer, uint8_t bit, bool invert);
+88
View File
@@ -0,0 +1,88 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "dht11.h"
/** Read one bit */
bool _dht11_rxbit(const uint8_t pin)
{
// Wait until start of pulse
while (is_low_n(pin));
uint8_t cnt = 0;
while (is_high_n(pin))
{
cnt++;
_delay_us(5);
}
return (cnt > 8);
}
/** Read one byte */
uint8_t _dht11_rxbyte(const uint8_t pin)
{
uint8_t byte = 0;
for (uint8_t i = 0; i < 8; i++)
{
if (_dht11_rxbit(pin))
byte |= (1 << (7 - i));
}
return byte;
}
/** Read tehmperature and humidity from the DHT11, returns false on failure */
bool dht11_read(const uint8_t pin, dht11_result_t* result)
{
// bus down for > 18 ms
as_output_n(pin);
pin_low_n(pin);
_delay_ms(20);
// bus up for 20-40us
pin_high_n(pin);
_delay_us(20);
// release
as_input_pu_n(pin);
// DHT should send 80us LOW & 80us HIGH
_delay_us(40);
if (!is_low_n(pin))
return false; // init error
_delay_us(80);
if (!is_high_n(pin))
return false; // init error
// skip to start of first bit
_delay_us(50);
// Receive 5 data bytes (Rh int, Rh dec, Temp int, Temp dec, Checksum)
// Decimal bytes are zero for DHT11 -> we can ignore them.
uint8_t bytes[5];
uint8_t sum = 0;
for (uint8_t i = 0; i < 5; i++)
{
uint8_t b = _dht11_rxbyte(pin);
bytes[i] = b;
if (i < 4) sum += b;
}
// Verify checksum
if (sum != bytes[4]) return false;
result->rh = bytes[0];
result->temp = bytes[2];
return true;
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
//
// Reading temperature and relative humidity from DHT11
//
#include <stdint.h>
#include <stdbool.h>
typedef struct
{
int8_t temp;
int8_t rh;
} dht11_result_t;
/** Read tehmperature and humidity from the DHT11, returns false on failure */
bool dht11_read(const uint8_t pin, dht11_result_t* result);
+1204
View File
File diff suppressed because it is too large Load Diff
+264
View File
@@ -0,0 +1,264 @@
#pragma once
//
// Simple FAT16 library.
//
// To use it, implement BLOCKDEV functions
// and attach them to it's instance.
//
#include <stdint.h>
#include <stdbool.h>
#include "blockdev.h"
// -------------------------------
/**
* File types (values can be used for debug printing).
* Accessible using file->type
*/
typedef enum
{
FT_NONE = '-',
FT_DELETED = 'x',
FT_SUBDIR = 'D',
FT_PARENT = 'P',
FT_LABEL = 'L',
FT_LFN = '~',
FT_INVALID = '?', // not recognized weird file
FT_SELF = '.',
FT_FILE = 'F'
} FAT16_FT;
/** "File address" for saving and restoring file */
typedef struct
{
uint16_t clu;
uint16_t num;
uint32_t cur_rel;
} FSAVEPOS;
// Include definitions of fully internal structs
#include "fat16_internal.h"
/**
* File handle struct.
*
* File handle contains cursor, file name, type, size etc.
* Everything (files, dirs) is accessed using this.
*/
typedef struct __attribute__((packed))
{
/**
* Raw file name. Starting 0x05 was converted to 0xE5.
* To get PRINTABLE file name, use fat16_dispname()
*/
uint8_t name[11];
/**
* File attributes - bit field composed of FA_* flags
* (internal)
*/
uint8_t attribs;
// 14 bytes skipped (10 reserved, date, time)
/** First cluster of the file. (internal) */
uint16_t clu_start;
/**
* File size in bytes.
* This is the current allocated and readable file size.
*/
uint32_t size;
// --- the following fields are added when reading ---
/** File type. */
FAT16_FT type;
// --- INTERNAL FIELDS ---
// Cursor variables. (internal)
uint32_t cur_abs; // absolute position in device
uint32_t cur_rel; // relative position in file
uint16_t cur_clu; // cluster where the cursor is
uint16_t cur_ofs; // offset within the active cluster
// File position in the directory. (internal)
uint16_t clu; // first cluster of directory
uint16_t num; // file entry number
// Pointer to the FAT16 handle. (internal)
const FAT16* fat;
}
FAT16_FILE;
/**
* Save a file "position" into a struct, for later restoration.
* Cursor is also saved.
*/
FSAVEPOS fat16_savepos(const FAT16_FILE* file);
/**
* Restore a file from a saved position.
*/
void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos);
/**
* Initialize the file system - store into "fat"
*/
bool fat16_init(const BLOCKDEV* dev, FAT16* fat);
/**
* Open the first file of the root directory.
* The file may be invalid (eg. a volume label, deleted etc),
* or blank (type FT_NONE) if the filesystem is empty.
*/
void fat16_root(const FAT16* fat, FAT16_FILE* file);
/**
* Resolve the disk label.
* That can be in the Boot Sector, or in the first root directory entry.
*
* @param fat the FAT handle
* @param label_out string to store the label in. Should have at least 12 bytes.
*/
char* fat16_disk_label(const FAT16* fat, char* label_out);
// ----------- FILE I/O -------------
/**
* Move file cursor to a position relative to file start
* Returns false on I/O error (bad file, out of range...)
*/
bool fat16_seek(FAT16_FILE* file, uint32_t addr);
/**
* Read bytes from file into memory
* Returns number of bytes read, 0 on error.
*/
uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len);
/**
* Write into file at a "seek" position.
* "seek" cursor must be within (0..filesize)
*/
bool fat16_write(FAT16_FILE* file, void* source, uint32_t len);
/**
* Create a new file in given folder
*
* file ... open directory; new file is opened into this handle.
* name ... name of the new file, including extension
*/
bool fat16_mkfile(FAT16_FILE* file, const char* name);
/**
* Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".."
*/
bool fat16_mkdir(FAT16_FILE* file, const char* name);
/**
* Set new file size.
* Allocates / frees needed clusters, does NOT erase them.
*
* Useful mainly for shrinking.
*/
void fat16_resize(FAT16_FILE* file, uint32_t size);
/**
* Delete a *FILE* and free it's clusters.
*/
bool fat16_rmfile(FAT16_FILE* file);
/**
* Delete an empty *DIRECTORY* and free it's clusters.
*/
bool fat16_rmdir(FAT16_FILE* file);
/**
* Delete a file or directory, even FT_LFN and FT_INVALID.
* Directories are deleted recursively (!)
*/
bool fat16_delete(FAT16_FILE* file);
// --------- NAVIGATION ------------
/** Go to previous file in the directory (false = no prev file) */
bool fat16_prev(FAT16_FILE* file);
/** Go to next file in directory (false = no next file) */
bool fat16_next(FAT16_FILE* file);
/**
* Open a subdirectory denoted by the file.
* Provided handle changes to the first entry of the directory.
*/
bool fat16_opendir(FAT16_FILE* dir);
/**
* Open a parent directory. Fails in root.
* Provided handle changes to the first entry of the parent directory.
*/
bool fat16_parent(FAT16_FILE* file);
/** Jump to first file in this directory */
void fat16_first(FAT16_FILE* file);
/**
* Find a file with given "display name" in this directory.
* If file is found, "dir" will contain it's handle.
* If file is NOT found, the handle points to the last entry of the directory.
*/
bool fat16_find(FAT16_FILE* dir, const char* name);
// -------- FILE INSPECTION -----------
/** Check if file is a valid entry, or long-name/label/deleted */
bool fat16_is_regular(const FAT16_FILE* file);
/**
* Resolve a file name, trim spaces and add null terminator.
* Returns the passed char*, or NULL on error.
*/
char* fat16_dispname(const FAT16_FILE* file, char* disp_out);
/**
* Convert filename to zero-padded fixed length one
* Returns the passed char*.
*/
char* fat16_rawname(const char* disp_in, char* raw_out);
+64
View File
@@ -0,0 +1,64 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
// Internal types and stuff that is needed in the header for declarations,
// but is not a part of the public API.
/** Boot Sector structure */
typedef struct __attribute__((packed))
{
// Fields loaded directly from disk:
// 13 bytes skipped
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t num_fats;
uint16_t root_entries;
// 3 bytes skipped
uint16_t fat_size_sectors;
// 8 bytes skipped
uint32_t total_sectors; // if "short size sectors" is used, it's copied here too
// 7 bytes skipped
char volume_label[11]; // space padded, no terminator
// Added fields:
uint32_t bytes_per_cluster;
}
Fat16BootSector;
/** FAT filesystem handle */
typedef struct __attribute__((packed))
{
// Backing block device
const BLOCKDEV* dev;
// Root directory sector start
uint32_t rd_addr;
// Start of first cluster (number "2")
uint32_t data_addr;
// Start of fat table
uint32_t fat_addr;
// Boot sector data struct
Fat16BootSector bs;
}
FAT16;
/**
* File Attributes (bit flags)
* Accessible using file->attribs
*/
#define FA_READONLY 0x01 // read only file
#define FA_HIDDEN 0x02 // hidden file
#define FA_SYSTEM 0x04 // system file
#define FA_LABEL 0x08 // volume label entry, found only in root directory.
#define FA_DIR 0x10 // subdirectory
#define FA_ARCHIVE 0x20 // archive flag
-19
View File
@@ -1,19 +0,0 @@
#pragma once
//
// HSL support (addition to colors.h)
//
#include "colors.h"
// Define HSL_LINEAR to get more linear brightness in hsl->rgb conversion
// HSL data structure
typedef struct {
uint8_t h;
uint8_t s;
uint8_t l;
} hsl_t;
/* Convert HSL to XRGB */
xrgb_t hsl2xrgb(const hsl_t color);
+276
View File
@@ -0,0 +1,276 @@
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>
#include "calc.h"
#include "iopins.h"
void set_dir_n(const uint8_t pin, const uint8_t d)
{
switch(pin) {
case 0: set_dir(0, d); return;
case 1: set_dir(1, d); return;
case 2: set_dir(2, d); return;
case 3: set_dir(3, d); return;
case 4: set_dir(4, d); return;
case 5: set_dir(5, d); return;
case 6: set_dir(6, d); return;
case 7: set_dir(7, d); return;
case 8: set_dir(8, d); return;
case 9: set_dir(9, d); return;
case 10: set_dir(10, d); return;
case 11: set_dir(11, d); return;
case 12: set_dir(12, d); return;
case 13: set_dir(13, d); return;
case 14: set_dir(14, d); return;
case 15: set_dir(15, d); return;
case 16: set_dir(16, d); return;
case 17: set_dir(17, d); return;
case 18: set_dir(18, d); return;
case 19: set_dir(19, d); return;
case 20: set_dir(20, d); return;
case 21: set_dir(21, d); return;
}
}
void as_input_n(const uint8_t pin)
{
switch(pin) {
case 0: as_input(0); return;
case 1: as_input(1); return;
case 2: as_input(2); return;
case 3: as_input(3); return;
case 4: as_input(4); return;
case 5: as_input(5); return;
case 6: as_input(6); return;
case 7: as_input(7); return;
case 8: as_input(8); return;
case 9: as_input(9); return;
case 10: as_input(10); return;
case 11: as_input(11); return;
case 12: as_input(12); return;
case 13: as_input(13); return;
case 14: as_input(14); return;
case 15: as_input(15); return;
case 16: as_input(16); return;
case 17: as_input(17); return;
case 18: as_input(18); return;
case 19: as_input(19); return;
case 20: as_input(20); return;
case 21: as_input(21); return;
}
}
void as_input_pu_n(const uint8_t pin)
{
switch(pin) {
case 0: as_input_pu(0); return;
case 1: as_input_pu(1); return;
case 2: as_input_pu(2); return;
case 3: as_input_pu(3); return;
case 4: as_input_pu(4); return;
case 5: as_input_pu(5); return;
case 6: as_input_pu(6); return;
case 7: as_input_pu(7); return;
case 8: as_input_pu(8); return;
case 9: as_input_pu(9); return;
case 10: as_input_pu(10); return;
case 11: as_input_pu(11); return;
case 12: as_input_pu(12); return;
case 13: as_input_pu(13); return;
case 14: as_input_pu(14); return;
case 15: as_input_pu(15); return;
case 16: as_input_pu(16); return;
case 17: as_input_pu(17); return;
case 18: as_input_pu(18); return;
case 19: as_input_pu(19); return;
case 20: as_input_pu(20); return;
case 21: as_input_pu(21); return;
}
}
void as_output_n(const uint8_t pin)
{
switch(pin) {
case 0: as_output(0); return;
case 1: as_output(1); return;
case 2: as_output(2); return;
case 3: as_output(3); return;
case 4: as_output(4); return;
case 5: as_output(5); return;
case 6: as_output(6); return;
case 7: as_output(7); return;
case 8: as_output(8); return;
case 9: as_output(9); return;
case 10: as_output(10); return;
case 11: as_output(11); return;
case 12: as_output(12); return;
case 13: as_output(13); return;
case 14: as_output(14); return;
case 15: as_output(15); return;
case 16: as_output(16); return;
case 17: as_output(17); return;
case 18: as_output(18); return;
case 19: as_output(19); return;
case 20: as_output(20); return;
case 21: as_output(21); return;
}
}
void set_pin_n(const uint8_t pin, const uint8_t v)
{
switch(pin) {
case 0: set_pin(0, v); return;
case 1: set_pin(1, v); return;
case 2: set_pin(2, v); return;
case 3: set_pin(3, v); return;
case 4: set_pin(4, v); return;
case 5: set_pin(5, v); return;
case 6: set_pin(6, v); return;
case 7: set_pin(7, v); return;
case 8: set_pin(8, v); return;
case 9: set_pin(9, v); return;
case 10: set_pin(10, v); return;
case 11: set_pin(11, v); return;
case 12: set_pin(12, v); return;
case 13: set_pin(13, v); return;
case 14: set_pin(14, v); return;
case 15: set_pin(15, v); return;
case 16: set_pin(16, v); return;
case 17: set_pin(17, v); return;
case 18: set_pin(18, v); return;
case 19: set_pin(19, v); return;
case 20: set_pin(20, v); return;
case 21: set_pin(21, v); return;
}
}
void pin_low_n(const uint8_t pin)
{
switch(pin) {
case 0: pin_low(0); return;
case 1: pin_low(1); return;
case 2: pin_low(2); return;
case 3: pin_low(3); return;
case 4: pin_low(4); return;
case 5: pin_low(5); return;
case 6: pin_low(6); return;
case 7: pin_low(7); return;
case 8: pin_low(8); return;
case 9: pin_low(9); return;
case 10: pin_low(10); return;
case 11: pin_low(11); return;
case 12: pin_low(12); return;
case 13: pin_low(13); return;
case 14: pin_low(14); return;
case 15: pin_low(15); return;
case 16: pin_low(16); return;
case 17: pin_low(17); return;
case 18: pin_low(18); return;
case 19: pin_low(19); return;
case 20: pin_low(20); return;
case 21: pin_low(21); return;
}
}
void pin_high_n(const uint8_t pin)
{
switch(pin) {
case 0: pin_high(0); return;
case 1: pin_high(1); return;
case 2: pin_high(2); return;
case 3: pin_high(3); return;
case 4: pin_high(4); return;
case 5: pin_high(5); return;
case 6: pin_high(6); return;
case 7: pin_high(7); return;
case 8: pin_high(8); return;
case 9: pin_high(9); return;
case 10: pin_high(10); return;
case 11: pin_high(11); return;
case 12: pin_high(12); return;
case 13: pin_high(13); return;
case 14: pin_high(14); return;
case 15: pin_high(15); return;
case 16: pin_high(16); return;
case 17: pin_high(17); return;
case 18: pin_high(18); return;
case 19: pin_high(19); return;
case 20: pin_high(20); return;
case 21: pin_high(21); return;
}
}
void toggle_pin_n(const uint8_t pin)
{
switch(pin) {
case 0: toggle_pin(0); return;
case 1: toggle_pin(1); return;
case 2: toggle_pin(2); return;
case 3: toggle_pin(3); return;
case 4: toggle_pin(4); return;
case 5: toggle_pin(5); return;
case 6: toggle_pin(6); return;
case 7: toggle_pin(7); return;
case 8: toggle_pin(8); return;
case 9: toggle_pin(9); return;
case 10: toggle_pin(10); return;
case 11: toggle_pin(11); return;
case 12: toggle_pin(12); return;
case 13: toggle_pin(13); return;
case 14: toggle_pin(14); return;
case 15: toggle_pin(15); return;
case 16: toggle_pin(16); return;
case 17: toggle_pin(17); return;
case 18: toggle_pin(18); return;
case 19: toggle_pin(19); return;
case 20: toggle_pin(20); return;
case 21: toggle_pin(21); return;
}
}
bool get_pin_n(const uint8_t pin)
{
switch(pin) {
case 0: return get_pin(0);
case 1: return get_pin(1);
case 2: return get_pin(2);
case 3: return get_pin(3);
case 4: return get_pin(4);
case 5: return get_pin(5);
case 6: return get_pin(6);
case 7: return get_pin(7);
case 8: return get_pin(8);
case 9: return get_pin(9);
case 10: return get_pin(10);
case 11: return get_pin(11);
case 12: return get_pin(12);
case 13: return get_pin(13);
case 14: return get_pin(14);
case 15: return get_pin(15);
case 16: return get_pin(16);
case 17: return get_pin(17);
case 18: return get_pin(18);
case 19: return get_pin(19);
case 20: return get_pin(20);
case 21: return get_pin(21);
}
return false;
}
bool is_low_n(const uint8_t pin)
{
return !get_pin_n(pin);
}
bool is_high_n(const uint8_t pin)
{
return get_pin_n(pin);
}
+213
View File
@@ -0,0 +1,213 @@
#pragma once
//
// * Utilities for pin aliasing / numbering. *
//
// Designed for Arduino.
//
// If you know the pin number beforehand, you can use the macros.
//
// If you need to use a variable for pin number, use the `_n` functions.
// They are much slower, so always check if you really need them
// - and they aren't fit for things where precise timing is required.
//
#include <avr/io.h>
#include <stdbool.h>
#include <stdint.h>
#include "calc.h"
// type: pointer to port
typedef volatile uint8_t* PORT_P;
/** Pin numbering reference */
#define D0 0
#define D1 1
#define D2 2
#define D3 3
#define D4 4
#define D5 5
#define D6 6
#define D7 7
#define D8 8
#define D9 9
#define D10 10
#define D11 11
#define D12 12
#define D13 13
#define D14 14
#define D15 15
#define D16 16
#define D17 17
#define D18 18
#define D19 19
#define D20 20
#define D21 21
#define A0 14
#define A1 15
#define A2 16
#define A3 17
#define A4 18
#define A5 19
#define A6 20
#define A7 21
#define _ddr(pin) _DDR_##pin
#define _pin(pin) _PIN_##pin
#define _pn(pin) _PN_##pin
#define _port(pin) _PORT_##pin
/** Set pin direction */
#define set_dir(pin, d) set_bit( _ddr(pin), _pn(pin), d )
void set_dir_n(const uint8_t pin, const uint8_t d);
/** Configure pin as input */
#define as_input(pin) cbi( _ddr(pin), _pn(pin) )
void as_input_n(const uint8_t pin);
/** Configure pin as input, with pull-up enabled */
#define as_input_pu(pin) { as_input(pin); pin_high(pin); }
void as_input_pu_n(const uint8_t pin);
/** Configure pin as output */
#define as_output(pin) sbi( _ddr(pin), _pn(pin) )
void as_output_n(const uint8_t pin);
/** Write value to a pin */
#define set_pin(pin, v) set_bit( _port(pin), _pn(pin), v )
void set_pin_n(const uint8_t pin, const uint8_t v);
/** Write 0 to a pin */
#define pin_low(pin) cbi( _port(pin), _pn(pin) )
void pin_low_n(const uint8_t pin);
/** Write 1 to a pin */
#define pin_high(pin) sbi( _port(pin), _pn(pin) )
void pin_high_n(const uint8_t pin);
/** Toggle a pin state */
#define toggle_pin(pin) sbi( _pin(pin), _pn(pin) )
void toggle_pin_n(const uint8_t pin);
/** Read a pin value */
#define get_pin(pin) get_bit( _pin(pin), _pn(pin) )
bool get_pin_n(const uint8_t pin);
/** CHeck if pin is low */
#define is_low(pin) (get_pin(pin) == 0)
bool is_low_n(const uint8_t pin);
/** CHeck if pin is high */
#define is_high(pin) (get_pin(pin) != 0)
bool is_high_n(const uint8_t pin);
// Helper macros
#define _PORT_0 PORTD
#define _PORT_1 PORTD
#define _PORT_2 PORTD
#define _PORT_3 PORTD
#define _PORT_4 PORTD
#define _PORT_5 PORTD
#define _PORT_6 PORTD
#define _PORT_7 PORTD
#define _PORT_8 PORTB
#define _PORT_9 PORTB
#define _PORT_10 PORTB
#define _PORT_11 PORTB
#define _PORT_12 PORTB
#define _PORT_13 PORTB
#define _PORT_14 PORTC
#define _PORT_15 PORTC
#define _PORT_16 PORTC
#define _PORT_17 PORTC
#define _PORT_18 PORTC
#define _PORT_19 PORTC
#define _PORT_20 PORTC
#define _PORT_21 PORTC
#define _PIN_0 PIND
#define _PIN_1 PIND
#define _PIN_2 PIND
#define _PIN_3 PIND
#define _PIN_4 PIND
#define _PIN_5 PIND
#define _PIN_6 PIND
#define _PIN_7 PIND
#define _PIN_8 PINB
#define _PIN_9 PINB
#define _PIN_10 PINB
#define _PIN_11 PINB
#define _PIN_12 PINB
#define _PIN_13 PINB
#define _PIN_14 PINC
#define _PIN_15 PINC
#define _PIN_16 PINC
#define _PIN_17 PINC
#define _PIN_18 PINC
#define _PIN_19 PINC
#define _PIN_20 PINC
#define _PIN_21 PINC
#define _DDR_0 DDRD
#define _DDR_1 DDRD
#define _DDR_2 DDRD
#define _DDR_3 DDRD
#define _DDR_4 DDRD
#define _DDR_5 DDRD
#define _DDR_6 DDRD
#define _DDR_7 DDRD
#define _DDR_8 DDRB
#define _DDR_9 DDRB
#define _DDR_10 DDRB
#define _DDR_11 DDRB
#define _DDR_12 DDRB
#define _DDR_13 DDRB
#define _DDR_14 DDRC
#define _DDR_15 DDRC
#define _DDR_16 DDRC
#define _DDR_17 DDRC
#define _DDR_18 DDRC
#define _DDR_19 DDRC
#define _DDR_20 DDRC
#define _DDR_21 DDRC
#define _PN_0 0
#define _PN_1 1
#define _PN_2 2
#define _PN_3 3
#define _PN_4 4
#define _PN_5 5
#define _PN_6 6
#define _PN_7 7
#define _PN_8 0
#define _PN_9 1
#define _PN_10 2
#define _PN_11 3
#define _PN_12 4
#define _PN_13 5
#define _PN_14 0
#define _PN_15 1
#define _PN_16 2
#define _PN_17 3
#define _PN_18 4
#define _PN_19 5
#define _PN_20 6
#define _PN_21 7
+30 -23
View File
@@ -5,7 +5,7 @@
#include <util/delay.h>
#include "calc.h"
#include "pins.h"
#include "iopins.h"
#include "nsdelay.h"
#include "lcd.h"
#include "lcd_config.h"
@@ -32,22 +32,24 @@ uint8_t _lcd_read_byte();
#define _lcd_write_low(bb) _lcd_write_nibble((bb) & 0x0F)
#define _lcd_write_high(bb) _lcd_write_nibble(((bb) & 0xF0) >> 4)
#define _lcd_write_nibble(nib) do { \
write_pin(LCD_D7, get_bit((nib), 3)); \
write_pin(LCD_D6, get_bit((nib), 2)); \
write_pin(LCD_D5, get_bit((nib), 1)); \
write_pin(LCD_D4, get_bit((nib), 0)); \
set_pin(LCD_D7, get_bit((nib), 3)); \
set_pin(LCD_D6, get_bit((nib), 2)); \
set_pin(LCD_D5, get_bit((nib), 1)); \
set_pin(LCD_D4, get_bit((nib), 0)); \
} while(0)
// 0 W, 1 R
bool _lcd_mode;
struct {
struct
{
uint8_t x;
uint8_t y;
} _pos;
enum {
enum
{
TEXT = 0,
CG = 1
} _addrtype;
@@ -100,9 +102,9 @@ void lcd_init()
/** Send a pulse on the ENABLE line */
void _lcd_clk()
{
pin_up(LCD_E);
pin_high(LCD_E);
delay_ns(450);
pin_down(LCD_E);
pin_low(LCD_E);
}
@@ -111,7 +113,7 @@ void _lcd_mode_r()
{
if (_lcd_mode == 1) return; // already in R mode
pin_up(LCD_RW);
pin_high(LCD_RW);
as_input_pu(LCD_D7);
as_input_pu(LCD_D6);
@@ -127,7 +129,7 @@ void _lcd_mode_w()
{
if (_lcd_mode == 0) return; // already in W mode
pin_down(LCD_RW);
pin_low(LCD_RW);
as_output(LCD_D7);
as_output(LCD_D6);
@@ -146,10 +148,10 @@ uint8_t _lcd_read_byte()
uint8_t res = 0;
_lcd_clk();
res = (read_pin(LCD_D7) << 7) | (read_pin(LCD_D6) << 6) | (read_pin(LCD_D5) << 5) | (read_pin(LCD_D4) << 4);
res = (get_pin(LCD_D7) << 7) | (get_pin(LCD_D6) << 6) | (get_pin(LCD_D5) << 5) | (get_pin(LCD_D4) << 4);
_lcd_clk();
res |= (read_pin(LCD_D7) << 3) | (read_pin(LCD_D6) << 2) | (read_pin(LCD_D5) << 1) | (read_pin(LCD_D4) << 0);
res |= (get_pin(LCD_D7) << 3) | (get_pin(LCD_D6) << 2) | (get_pin(LCD_D5) << 1) | (get_pin(LCD_D4) << 0);
return res;
}
@@ -159,7 +161,7 @@ uint8_t _lcd_read_byte()
void lcd_command(uint8_t bb)
{
_lcd_wait_bf();
pin_down(LCD_RS); // select instruction register
pin_low(LCD_RS); // select instruction register
_lcd_write_byte(bb); // send instruction byte
}
@@ -167,15 +169,18 @@ void lcd_command(uint8_t bb)
/** Write a data byte */
void lcd_write(uint8_t bb)
{
if (_addrtype == TEXT) {
if (bb == '\r') {
if (_addrtype == TEXT)
{
if (bb == '\r')
{
// CR
_pos.x = 0;
lcd_xy(_pos.x, _pos.y);
return;
}
if (bb == '\n') {
if (bb == '\n')
{
// LF
_pos.y++;
lcd_xy(_pos.x, _pos.y);
@@ -186,7 +191,7 @@ void lcd_write(uint8_t bb)
}
_lcd_wait_bf();
pin_up(LCD_RS); // select data register
pin_high(LCD_RS); // select data register
_lcd_write_byte(bb); // send data byte
}
@@ -194,7 +199,7 @@ void lcd_write(uint8_t bb)
/** Read BF & Address */
uint8_t lcd_read_bf_addr()
{
pin_down(LCD_RS);
pin_low(LCD_RS);
return _lcd_read_byte();
}
@@ -204,7 +209,7 @@ uint8_t lcd_read()
{
if (_addrtype == TEXT) _pos.x++;
pin_up(LCD_RS);
pin_high(LCD_RS);
return _lcd_read_byte();
}
@@ -227,7 +232,7 @@ void _lcd_write_byte(uint8_t bb)
void _lcd_wait_bf()
{
uint8_t d = 0;
while(d++ < 120 && lcd_read_bf_addr() & _BV(7))
while (d++ < 120 && lcd_read_bf_addr() & _BV(7))
_delay_us(1);
}
@@ -318,7 +323,8 @@ void lcd_clear()
void lcd_glyph(const uint8_t index, const uint8_t* array)
{
lcd_addr_cg(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
for (uint8_t i = 0; i < 8; ++i)
{
lcd_write(array[i]);
}
@@ -332,7 +338,8 @@ void lcd_glyph(const uint8_t index, const uint8_t* array)
void lcd_glyph_P(const uint8_t index, const uint8_t* array)
{
lcd_addr_cg(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
for (uint8_t i = 0; i < 8; ++i)
{
lcd_write(pgm_read_byte(&array[i]));
}
+10 -10
View File
@@ -7,15 +7,6 @@
//
// Content can be something like this:
//
// #pragma once
// #include "lib/arduino_pins.h"
// #define LCD_RS D10
// #define LCD_RW D11
// #define LCD_E D12
// #define LCD_D4 D13
// #define LCD_D5 D14
// #define LCD_D6 D15
// #define LCD_D7 D16
//
#include <stdint.h>
@@ -23,8 +14,17 @@
#include "stream.h"
// File with configs
// Your file with configs
#include "lcd_config.h"
/*
#define LCD_RS 10
#define LCD_RW 11
#define LCD_E 12
#define LCD_D4 13
#define LCD_D5 14
#define LCD_D6 15
#define LCD_D7 16
*/
-22
View File
@@ -1,22 +0,0 @@
#pragma once
//
// Custom loops
//
// Repeat code n times (uint8_t counter)
#define repeat(count) repeat_aux(count, _repeat_##__COUNTER__)
#define repeat_aux(count, cntvar) for (uint8_t cntvar = 0; cntvar < (count); cntvar++)
// Repeat code n times (uint16_t counter)
#define repeatx(count) repeatx_aux(count, _repeatx_##__COUNTER__)
#define repeatx_aux(count, cntvar) for (uint16_t cntvar = 0; cntvar < (count); cntvar++)
// Repeat with custom counter name (uint8_t)
#define loop(var, count) repeat_aux(count, var)
// ..., uint16_t
#define loopx(var, count) repeatx_aux(count, var)
// Do until condition is met
#define until(what) while(!(what))
-6
View File
@@ -1,6 +0,0 @@
#pragma once
// Weird constructs for the compiler
// general macros
#define SECTION(pos) __attribute__((naked, used, section(pos)))
+248
View File
@@ -0,0 +1,248 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "onewire.h"
/** Perform bus reset. Returns true if any device is connected */
bool ow_reset(const uint8_t pin)
{
as_output_n(pin);
pin_low_n(pin);
_delay_us(480);
as_input_pu_n(pin);
_delay_us(70);
const bool a = get_pin_n(pin);
_delay_us(410);
return a;
}
/** Send a single bit */
void _ow_tx_bit(const uint8_t pin, const bool bit)
{
as_output_n(pin);
pin_low_n(pin);
if (bit)
{
_delay_us(6);
as_input_pu_n(pin);
_delay_us(64);
}
else
{
_delay_us(60);
as_input_pu_n(pin);
_delay_us(10);
}
}
/** Send a single byte */
void ow_send(const uint8_t pin, const uint8_t byte)
{
for (uint8_t i = 0; i < 8; i++)
{
_ow_tx_bit(pin, (byte >> i) & 0x01);
}
}
/** Read a single bit */
bool _ow_rx_bit(const uint8_t pin)
{
as_output_n(pin);
pin_low_n(pin);
_delay_us(6);
as_input_pu_n(pin);
_delay_us(9);
const bool a = get_pin_n(pin);
_delay_us(55);
return a;
}
/** Read a single byte */
uint8_t ow_read(const uint8_t pin)
{
uint8_t byte = 0;
for (uint8_t i = 0; i < 8; i++)
{
byte = (byte >> 1) | (_ow_rx_bit(pin) << 7);
}
return byte;
}
/** Wait until the device is ready. Returns false on timeout */
bool ow_wait_ready(const uint8_t pin)
{
uint16_t timeout = 700;
as_input_pu_n(pin);
while (--timeout > 0)
{
if (is_high_n(pin)) return true;
_delay_ms(1);
}
return false;
}
/** Read bytes into an array */
void ow_read_arr(const uint8_t pin, uint8_t* array, const uint8_t count)
{
for (uint8_t i = 0; i < count; i++)
{
array[i] = ow_read(pin);
}
}
// ---------- CRC utils ----------
/*
Dallas 1-wire CRC routines for Arduino with examples of usage.
The 16-bit routine is new.
The 8-bit routine is from http://github.com/paeaetech/paeae/tree/master/Libraries/ds2482/
Copyright (C) 2010 Kairama Inc
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Dallas 1-wire 16-bit CRC calculation. Developed from Maxim Application Note 27.
/** Compute a CRC16 checksum */
uint16_t crc16(uint8_t *data, uint8_t len)
{
uint16_t crc = 0;
for (uint8_t i = 0; i < len; i++)
{
uint8_t inbyte = data[i];
for (uint8_t j = 0; j < 8; j++)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc = crc >> 1;
if (mix)
crc = crc ^ 0xA001;
inbyte = inbyte >> 1;
}
}
return crc;
}
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
/** Compute a CRC8 checksum */
uint8_t crc8(uint8_t *addr, uint8_t len)
{
uint8_t crc = 0;
for (uint8_t i = 0; i < len; i++)
{
uint8_t inbyte = addr[i];
for (uint8_t j = 0; j < 8; j++)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix)
crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
// --- utils for DS1820 ---
/** Read temperature in 0.0625°C, or TEMP_ERROR on error */
int16_t ds1820_read_temp(uint8_t pin)
{
ow_send(pin, READ_SCRATCHPAD);
uint8_t bytes[9];
ow_read_arr(pin, bytes, 9);
uint8_t crc = crc8(bytes, 8);
if (crc != bytes[8])
{
return TEMP_ERROR;
}
else
{
int16_t a = ((bytes[1] << 8) | bytes[0]) >> 1;
a = a << 4;
a += (16 - bytes[6]) & 0x0F;
a -= 0x04;
return a;
}
}
/** Read temperature in 0.1°C, or TEMP_ERROR on error */
int16_t ds1820_read_temp_c(uint8_t pin)
{
int32_t temp = ds1820_read_temp(pin);
if (temp == TEMP_ERROR)
return TEMP_ERROR;
temp *= 625;
uint16_t rem = temp % 1000;
temp /= 1000;
if (rem >= 500) temp++;
return (int16_t) temp;
}
bool ds1820_single_measure(uint8_t pin)
{
ow_reset(pin);
ow_send(pin, SKIP_ROM);
ow_send(pin, CONVERT_T);
if (!ow_wait_ready(pin))
{
return false;
}
ow_reset(pin);
ow_send(pin, SKIP_ROM);
return true;
}
+58
View File
@@ -0,0 +1,58 @@
#pragma once
//
// Utils for Dallas OneWire bus (DS1820 etc)
//
#include <stdint.h>
#include <stdbool.h>
#define SKIP_ROM 0xCC
#define CONVERT_T 0x44
#define READ_SCRATCHPAD 0xBE
/** Perform bus reset. Returns true if any device is connected */
bool ow_reset(const uint8_t pin);
/** Send a single byte */
void ow_send(const uint8_t pin, const uint8_t byte);
/** Read a single byte */
uint8_t ow_read(const uint8_t pin);
/** Wait until the device is ready. Returns false on timeout */
bool ow_wait_ready(const uint8_t pin);
/** Read bytes into an array */
void ow_read_arr(const uint8_t pin, uint8_t* array, const uint8_t count);
/** Compute a CRC16 checksum */
uint16_t crc16(uint8_t *data, uint8_t len);
/** Compute a CRC8 checksum */
uint8_t crc8(uint8_t *addr, uint8_t len);
// --- utils for DS1820 ---
#define TEMP_ERROR -32768
/**
* Read temperature in 0.0625°C, or TEMP_ERROR on error
* Use this where you'd normally use READ_SCRATCHPAD
*/
int16_t ds1820_read_temp(uint8_t pin);
/**
* Read temperature in 0.1°C, or TEMP_ERROR on error
* Use this where you'd normally use READ_SCRATCHPAD
*/
int16_t ds1820_read_temp_c(uint8_t pin);
/**
* Perform a temperature measurement with single DS1820 device on the line
* Can be followed by a call to read temperature (READ_SCRATCHPAD).
*
* Returns false on failure (device not connected)
*/
bool ds1820_single_measure(uint8_t pin);
-129
View File
@@ -1,129 +0,0 @@
#pragma once
//
// This file provides macros for pin manipulation.
//
// You can define your application pins like so:
//
// // Led at PORTB, pin 1
// #define LED B,1
//
// // Switch at PORTD, pin 7
// #define SW1 D,7
//
// Now you can use macros from this file to wirh with the pins, eg:
//
// as_output(LED);
// as_input(SW1);
// pullup_on(SW1);
//
// toggle_pin(LED);
// while (pin_is_low(SW1));
//
// - The macros io2XXX() can be used to get literal name of register associated with the pin.
// - io2n() provides pin number.
// - The underscored and _aux macros are internal and should not be used elsewhere.
// - The io_pack() macro is used to pass pin (io) to other macro without expanding it.
//
#include <avr/io.h>
#include "calc.h"
// Helpers
// Get particular register associated with the name X (eg. D -> PORTD)
#define _reg_ddr(X) DDR ## X
#define _reg_port(X) PORT ## X
#define _reg_pin(X) PIN ## X
#define _io2ddr_aux(reg, bit) _reg_ddr(reg)
#define _io2port_aux(reg, bit) _reg_port(reg)
#define _io2pin_aux(reg, bit) _reg_pin(reg)
#define _io2n_aux(reg, bit) bit
// === Convert A,1 to corresponding register and pin number ===
#define io2ddr(io) _io2ddr_aux(io)
#define io2port(io) _io2port_aux(io)
#define io2pin(io) _io2pin_aux(io)
#define io2n(io) _io2n_aux(io)
// === covert "A", "1" to "A,1" for passing on to another macro ===
#define io_pack(port, bit) port, bit
// === Useful types for ports and pins ===
// pointer to port
typedef volatile uint8_t* PORT_P;
// number of bit in port
typedef uint8_t BIT_N;
// === pin manipulation ===
// Helpers
#define _set_pin_aux(port, bit) sbi(_reg_port(port), (bit))
#define _clear_pin_aux(port, bit) cbi(_reg_port(port), (bit))
#define _read_pin_aux(port, bit) get_bit(_reg_pin(port), (bit))
#define _write_pin_aux(port, bit, value) set_bit(_reg_port(port), (bit), (value))
#define _toggle_pin_aux(port, bit) sbi(_reg_pin(port), (bit))
// Set pin to HIGH
#define pin_up(io) _set_pin_aux(io)
#define pin_high(io) _set_pin_aux(io)
// Set pin to LOW
#define pin_down(io) _clear_pin_aux(io)
#define pin_low(io) _clear_pin_aux(io)
// Get input pin value
#define get_pin(io) _read_pin_aux(io)
#define read_pin(io) _read_pin_aux(io)
// Check if pin is low or high
#define pin_is_low(io) !_read_pin_aux(io)
#define pin_is_high(io) _read_pin_aux(io)
// Write a value to pin
#define set_pin(io, value) _write_pin_aux(io, (value))
#define write_pin(io, value) _write_pin_aux(io, (value))
#define toggle_pin(io) _toggle_pin_aux(io)
// === Setting pin direction ===
// Helpers
#define _as_input_aux(port, bit) cbi(_reg_ddr(port), (bit))
#define _as_output_aux(port, bit) sbi(_reg_ddr(port), (bit))
#define _set_dir_aux(port, bit, dir) write_bit(_reg_ddr(port), (bit), (dir))
// Pin as input (_pu ... with pull-up)
#define as_input(io) _as_input_aux(io)
#define as_input_pu(io) do { _as_input_aux(io); _pullup_enable_aux(io); } while(0)
// Pin as output
#define as_output(io) _as_output_aux(io)
// Set direction (1 ... output)
#define set_dir(io, dir) _set_dir_aux(io, (dir))
// === Setting pullup ===
// Helpers
#define _pullup_enable_aux(port, bit) sbi(_reg_port(port), (bit))
#define _pullup_disable_aux(port, bit) cbi(_reg_port(port), (bit))
#define _set_pullup_aux(port, bit, on) write_bit(_reg_port(port), (bit), (on))
// Enable pullup
#define pullup_enable(io) _pullup_enable_aux(io)
#define pullup_on(io) _pullup_enable_aux(io)
// Disable pullup
#define pullup_disable(io) _pullup_disable_aux(io)
#define pullup_off(io) _pullup_disable_aux(io)
// Set pullup to value (1 ... pullup enabled)
#define set_pullup(io, on) _set_pullup_aux(io, on)
+202
View File
@@ -0,0 +1,202 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "spi.h"
#include "sd.h"
#define SD_RESET 0x40 // used to make card enter SPI mode
#define SD_GET_STATUS 0x41 // used to check if card left IDLE - should return 0
#define SD_SET_BLOCKLEN 0x50 // used to check if card left IDLE - should return 0
#define SD_READ_BLOCK 0x51 // read single block
#define SD_WRITE_BLOCK 0x58 // write single block
bool sd_inited = false;
bool sd_init()
{
if (sd_inited) return true;
sd_inited = true;
uint8_t i;
spi_init();
spi_ss_disable(); // needed for init sequence, first command will enable it again
// idle for 10 bytes / 80 clocks
for (i = 0; i < 10; i++)
{
spi_write(0xFF);
}
// Send "Go to SPI mode" command, which should return "1"
for (i = 0; i < 100 && sd_command(SD_RESET, 0) != 1; i++)
_delay_ms(10);
if (i == 100)
return false; // timeout
// CMD1 until card comes out of "idle" mode
for (i = 0; i < 100 && sd_command(SD_GET_STATUS, 0) != 0; i++)
_delay_ms(10);
if (i == 100)
return false; // timeout
// f_cpu/8 speed (-> 2 MHz)
SPSR |= _BV(SPI2X);
SPCR &= 0xFC | _BV(SPR0);
// Set block size to 512 bytes (SD card default)
sd_command(SD_SET_BLOCKLEN, 512);
return true;
}
uint8_t sd_command(const uint8_t cmd, const uint32_t arg)
{
spi_ss_enable();
spi_write(cmd);
spi_write(arg >> 24);
spi_write(arg >> 16);
spi_write(arg >> 8);
spi_write(arg);
spi_write(0x95); // CRC for the "init" command, later is ignored
// Send 8 bytes of 0xFF
// SD card replies with non-0xFF once it's done processing the command
uint8_t i, tmp, ret = 0xFF;
for (i = 0; i < 8; i++)
{
tmp = spi_write(0xFF);
if (tmp != 0xFF)
ret = tmp;
}
spi_ss_disable();
return ret;
}
bool sd_read(const uint32_t sector, const uint16_t read_at, uint8_t * buffer, const uint16_t write_at, const uint16_t len)
{
if (read_at + len > 512) return false;
uint16_t i;
spi_ss_enable();
spi_write(SD_READ_BLOCK);
spi_write(sector >> 15); // sector * 512 >> 24
spi_write(sector >> 7); // sector * 512 >> 16
spi_write(sector << 1); // sector * 512 >> 8
spi_write(0); // sector * 512
spi_write(0xFF);
// wait for 0 (ready)
for (i = 0; i < 100 && spi_write(0xFF) != 0x00; i++);
if (i == 100)
{
spi_ss_disable();
return false; // timeout
}
// wait for 0xFE (data start)
for (i = 0; i < 100 && spi_write(0xFF) != 0xFE; i++);
if (i == 100)
{
spi_ss_disable();
return false; // timeout
}
// skip "offset" bytes
for (i = 0; i < read_at; i++)
spi_write(0xFF);
// read "len" bytes
for (i = write_at; i < write_at + len; i++)
buffer[i] = spi_write(0xFF);
// skip remaining bytes in the sector
for (i = read_at + len; i < 512; i++)
spi_write(0xFF);
// skip checksum
spi_write(0xFF);
spi_write(0xFF);
spi_ss_disable();
return true;
}
bool sd_write(const uint32_t sector, const uint8_t * buffer512)
{
uint16_t i;
spi_ss_enable();
spi_write(SD_WRITE_BLOCK);
spi_write(sector >> 15); // sector * 512 >> 24
spi_write(sector >> 7); // sector * 512 >> 16
spi_write(sector << 1); // sector * 512 >> 8
spi_write(0); // sector * 512
spi_write(0xFF);
// wait for 0 (ready)
for (i = 0; i < 100 && spi_write(0xFF) != 0x00; i++);
if (i == 100)
{
spi_ss_disable();
return false; // timeout
}
// Start of data
spi_write(0xFE);
// Data
for (i = 0; i < 512; i++)
{
spi_write(buffer512[i]);
}
// Fake CRC
spi_write(0xFF);
spi_write(0xFF);
// Should contain flag that data was accepted
uint8_t resp = spi_write(0xFF);
if ((resp & 0x0F) != 0x05)
{
// Data not accepted
spi_ss_disable();
return false;
}
else
{
// Data accepted, wait for write complete
for (i = 0; i < 0xFFFF && spi_write(0xFF) == 0x00; i++);
if (i == 0xFFFF)
{
spi_ss_disable();
return false; // timeout
}
}
spi_write(0xFF); // 8 clocks
spi_ss_disable();
return true;
}
+55
View File
@@ -0,0 +1,55 @@
#pragma once
//
// SD card low-level I/O utilities
//
// Inspired by:
// http://www.avrfreaks.net/forum/tutc-simple-fat-and-sd-tutorial
//
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "spi.h"
#include "uart.h"
#include "stream.h"
/** Init SD card on SPI */
bool sd_init();
/**
* Send a command to the SD card
*
* @param cmd command to send
* @param arg command argument
* @return return value on success, 0xFF if nothing received back.
*/
uint8_t sd_command(uint8_t cmd, uint32_t arg);
/**
* Read from a sector into a buffer memory structure.
*
* @param sector sector to read (512 bytes long each)
* @param read_at offset within the sector
* @param buffer target buffer
* @param write_at target starting address
* @param len number of bytes to read
* @return true on success
*/
bool sd_read(uint32_t sector, uint16_t read_at, uint8_t * buffer, uint16_t write_at, uint16_t len);
/**
* Write bytes from a buffer into a sector.
*
* @param sector sector to write (512 bytes long each)
* @param buffer512 source buffer
* @return true on success
*/
bool sd_write(uint32_t sector, const uint8_t * buffer512);
+172
View File
@@ -0,0 +1,172 @@
#include <stdint.h>
#include <stdbool.h>
#include "sd_blockdev.h"
#include "sd.h"
// helpers
void load_sector(const uint32_t addr);
void store_sector();
void handle_cursor_ov();
// blockdev methods
void dev_load(void* dest, const uint16_t len);
void dev_store(const void* src, const uint16_t len);
uint8_t dev_read();
void dev_write(const uint8_t b);
void dev_seek(const uint32_t addr);
void dev_rseek(const int16_t offset);
/** Sector buffer */
uint8_t buff[512];
/** Address of the buffered sector */
uint32_t buff_addr;
/** Buffer needs to be flushed before next read */
bool buff_dirty = false;
/** Buffer holds a valid sector */
bool buff_valid = false;
/** seek cursor */
uint32_t cursor_sec;
uint16_t cursor_offs;
/** Flush the buffer, if it's dirty */
void sdb_flush()
{
if (buff_dirty)
{
store_sector();
buff_dirty = false;
}
}
void load_sector(const uint32_t addr)
{
// do not load if already loaded
if (buff_valid && buff_addr == addr) {
return;
}
sdb_flush();
// read entire sector
sd_read(addr, 0, buff, 0, 512);
buff_valid = true;
buff_addr = addr;
}
void store_sector()
{
// Do not store if not laoded.
if (!buff_dirty) return;
if (!buff_valid) return;
sd_write(buff_addr, buff);
}
/**
* Handle cursor overflow.
* MUST ABSOLUTELY NOT load/store buffer or change buffer addr!
*/
inline void handle_cursor_ov()
{
if (cursor_offs >= 512)
{
cursor_sec++;
cursor_offs = 0;
}
}
void dev_write(const uint8_t b)
{
load_sector(cursor_sec);
buff[cursor_offs++] = b;
buff_dirty = true;
handle_cursor_ov();
}
uint8_t dev_read()
{
load_sector(cursor_sec);
const uint8_t b = buff[cursor_offs++];
handle_cursor_ov();
return b;
}
void dev_load(void* dest, const uint16_t len)
{
for (uint16_t a = 0; a < len; a++)
{
*((uint8_t*)dest++) = dev_read();
}
}
void dev_store(const void* src, const uint16_t len)
{
for (uint16_t a = 0; a < len; a++)
{
dev_write(*((uint8_t*)src++));
}
}
void dev_seek(const uint32_t addr)
{
// compute sector and offset counters
cursor_sec = addr >> 9;
cursor_offs = addr & 0x1FF;
}
void dev_rseek(const int16_t offset)
{
// add WITHIN the same sector
if (offset > 0 && cursor_offs + offset < 512)
{
cursor_offs += offset;
return;
}
// subtract WITHIN the same sector
if (offset < 0 && ((uint16_t)(-offset) <= cursor_offs))
{
cursor_offs += offset;
return;
}
// abs addr change
dev_seek(((cursor_sec << 9) + cursor_offs) + offset);
}
/** Init SD card block device */
bool sdb_init(BLOCKDEV* dev)
{
if(!sd_init()) return false;
dev->load = &dev_load;
dev->store = &dev_store;
dev->read = &dev_read;
dev->write = &dev_write;
dev->seek = &dev_seek;
dev->rseek = &dev_rseek;
return true;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "blockdev.h"
/**
* Flush the sector buffer if it's dirty.
*
* Should be called after each sequence of writes,
* to avoid data loss.
*/
void sdb_flush();
/** Initialize the SD card block device */
bool sdb_init(BLOCKDEV* dev);
+34
View File
@@ -0,0 +1,34 @@
#include <stdint.h>
#include <stdbool.h>
#include "sd_blockdev.h"
#include "sd_fat.h"
#include "fat16.h"
FAT16 _fat;
BLOCKDEV _dev;
bool sdfat_inited = false;
bool sdfat_init()
{
if (sdfat_inited) return true;
sdfat_inited = true;
if (!sdb_init(&_dev)) return false;
if (!fat16_init(&_dev, &_fat)) return false;
return true;
}
void sdfat_root(FAT16_FILE* file)
{
fat16_root(&_fat, file);
}
void sdfat_disk_label(char* str)
{
fat16_disk_label(&_fat, str);
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
//
// FAT-on-SD helpers
//
#include "fat16.h"
/** Initialize FAT16 filesystem on a SPI-connected SD card */
bool sdfat_init();
/** Get first file of the root folder. */
void sdfat_root(FAT16_FILE* file);
/** Get a disk label. Str should have 12 chars. */
void sdfat_disk_label(char* str);
/** Flush the SD buffer (alis of sdb_flush()) */
#define sdfat_flush() sdb_flush()
+34 -23
View File
@@ -3,11 +3,11 @@
#include <stdint.h>
#include <stdbool.h>
#include "pins.h"
#include "iopins.h"
#include "sonar.h"
// Currently measured sonar
sonar_t* _sonar_active_so;
static sonar_t* _so;
// Flag that measurement is in progress
volatile bool sonar_busy;
@@ -23,14 +23,17 @@ void _sonar_init_do(sonar_t* so, PORT_P port, uint8_t ntx, PORT_P pin, uint8_t n
so->pin = pin;
so->nrx = nrx;
switch((const uint16_t) pin) {
case (const uint16_t)&PINB:
switch ((const uint16_t) pin)
{
case ((const uint16_t) &PINB):
so->bank = 0;
break;
case (const uint16_t)&PINC:
case ((const uint16_t) &PINC):
so->bank = 1;
break;
case (const uint16_t)&PIND:
case ((const uint16_t) &PIND):
so->bank = 2;
break;
}
@@ -47,7 +50,7 @@ bool sonar_start(sonar_t* so)
{
if (sonar_busy) return false;
_sonar_active_so = so;
_so = so;
sonar_busy = true;
@@ -56,37 +59,40 @@ bool sonar_start(sonar_t* so)
// Timer overflow interrupt enable
// We'll stop measuring on overflow
TIMSK1 |= (1 << TOIE1);
sbi(TIMSK1, TOIE1);
// Clear the timer value
TCNT1 = 0;
// Set up pin change interrupt mask for the RX pin
switch(so->bank) {
switch (so->bank)
{
case 0:
PCMSK0 |= (1 << (so->nrx));
sbi(PCMSK0, so->nrx);
break;
case 1:
PCMSK1 |= (1 << (so->nrx));
sbi(PCMSK1, so->nrx);
break;
case 2:
PCMSK2 |= (1 << (so->nrx));
sbi(PCMSK2, so->nrx);
break;
}
// send positive pulse
*(so->port) |= (1 << so->ntx);
sbi_p(so->port, so->ntx);
_delay_us(_SNR_TRIG_TIME);
*(so->port) &= ~(1 << so->ntx);
cbi_p(so->port, so->ntx);
// Wait for start of response
while ( (*(so->pin) & (1 << so->nrx)) == 0 );
while (bit_is_low_p(so->pin, so->nrx));
// Set timer clock source: F_CPU / 8 (0.5 us resolution)
TCCR1B = (0b010 << CS10);
// Enable pin change interrupt
PCICR |= (1 << (so->bank));
sbi(PCICR, so->bank);
return true;
}
@@ -99,20 +105,23 @@ void _sonar_stop()
TCCR1B = 0;
// Disable RX pin interrupt mask
switch(_sonar_active_so->bank) {
switch (_so->bank)
{
case 0:
PCMSK0 &= ~(1 << (_sonar_active_so->nrx));
PCMSK0 &= ~(1 << (_so->nrx));
break;
case 1:
PCMSK1 &= ~(1 << (_sonar_active_so->nrx));
PCMSK1 &= ~(1 << (_so->nrx));
break;
case 2:
PCMSK2 &= ~(1 << (_sonar_active_so->nrx));
PCMSK2 &= ~(1 << (_so->nrx));
break;
}
// Disable timer1 overflow interrupt
TIMSK1 &= ~(1 << TOIE1);
cbi(TIMSK1, TOIE1);
sonar_busy = false;
}
@@ -133,11 +142,13 @@ inline bool sonar_handle_t1ovf()
/** Handle pin change interrupt (returns true if consumed) */
inline bool sonar_handle_pci()
{
if (!sonar_busy) {
if (!sonar_busy)
{
return false; // nothing
}
if (*(_sonar_active_so->pin) & (1 << _sonar_active_so->nrx)) {
if (bit_is_high_p(_so->pin, _so->nrx))
{
// rx is high, not our pin change event
return false;
}
+6 -5
View File
@@ -11,7 +11,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "lib/pins.h"
#include "iopins.h"
// Calib constant for the module
// CM = uS / _DIV_CONST
@@ -25,7 +25,8 @@
// Sonar data object
typedef struct {
typedef struct
{
PORT_P port; // Tx PORT
uint8_t ntx; // Tx bit number
PORT_P pin; // Rx PIN
@@ -41,9 +42,9 @@ extern volatile int16_t sonar_result;
// Create a Sonar port
// Args: sonar_t* so, Trig pin, Echo pin
#define sonar_init(so, trig, echo) do { \
as_output(io_pack(trig)); \
as_input_pu(io_pack(echo)); \
_sonar_init_do(so, &io2port(io_pack(trig)), io2n(io_pack(trig)), &io2pin(io_pack(echo)), io2n(io_pack(echo))); \
as_output(trig); \
as_input_pu(echo); \
_sonar_init_do(so, &_port(trig), _pn(trig), &_pin(echo), _pn(echo)); \
} while(0)
// private, in header because of the macro.
+35
View File
@@ -0,0 +1,35 @@
#include <avr/io.h>
#include <stdint.h>
#include <stdbool.h>
#include "iopins.h"
#include "spi.h"
bool spi_inited = false;
/** Init SPI (for SD card communication) */
void spi_init()
{
if (spi_inited) return;
spi_inited = true;
// Pin configuration
as_output(PIN_SS);
as_output(PIN_MOSI);
as_output(PIN_SCK);
as_input_pu(PIN_MISO);
// Enable SPI, master, clock = F_CPU/128
SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0) | _BV(SPR1);
}
/** Write a byte to SPI. Returns received byte. */
uint8_t spi_write(uint8_t b)
{
SPDR = b;
while (!(SPSR & _BV(SPIF)));
return SPDR;
}
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <stdint.h>
#include "iopins.h"
#define PIN_MISO 12
#define PIN_MOSI 11
#define PIN_SCK 13
#define PIN_SS 10
/** Set SS to active state (LOW) */
#define spi_ss_enable() pin_low(PIN_SS)
/** Set SS to disabled state (HIGH) */
#define spi_ss_disable() pin_high(PIN_SS)
/** Init SPI (for SD card communication) */
void spi_init();
/**
* Write / read a byte to SPI.
*
* @param ch the written byte
* @return received byte
*/
uint8_t spi_write(uint8_t b);
+44 -14
View File
@@ -6,14 +6,25 @@
#include "calc.h"
static char tmpstr[20]; // buffer for number rendering
static char tmpstr[16]; // buffer for number rendering
void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len)
{
for (uint16_t i = 0; i < len; i++)
{
p->tx(str[i]);
}
}
void put_str(const STREAM *p, char* str)
{
char c;
while ((c = *str++))
{
p->tx(c);
}
}
@@ -21,7 +32,9 @@ void put_str_P(const STREAM *p, const char* str)
{
char c;
while ((c = pgm_read_byte(str++)))
{
p->tx(c);
}
}
@@ -80,15 +93,22 @@ void put_i32(const STREAM *p, const int32_t num)
/** Print number as hex */
void _print_hex(const STREAM *p, uint8_t* start, uint8_t bytes)
{
for (; bytes > 0; bytes--) {
for (; bytes > 0; bytes--)
{
uint8_t b = *(start + bytes - 1);
for(uint8_t j = 0; j < 2; j++) {
for (uint8_t j = 0; j < 2; j++)
{
uint8_t x = high_nibble(b);
b = b << 4;
if (x < 0xA) {
if (x < 0xA)
{
p->tx('0' + x);
} else {
}
else
{
p->tx('A' + (x - 0xA));
}
}
@@ -138,10 +158,13 @@ void put_u16f(const STREAM *p, const uint16_t num, const uint8_t places)
/** Send signed int as float */
void put_i16f(const STREAM *p, const int16_t num, const uint8_t places)
{
if (num < 0) {
if (num < 0)
{
p->tx('-');
itoa(-num, tmpstr, 10);
} else {
}
else
{
itoa(num, tmpstr, 10);
}
@@ -160,10 +183,13 @@ void put_u32f(const STREAM *p, const uint32_t num, const uint8_t places)
/** Send signed long as float */
void put_i32f(const STREAM *p, const int32_t num, const uint8_t places)
{
if (num < 0) {
if (num < 0)
{
p->tx('-');
ltoa(-num, tmpstr, 10);
} else {
}
else
{
ltoa(num, tmpstr, 10);
}
@@ -176,15 +202,17 @@ void _putnf(const STREAM *p, const uint8_t places)
{
// measure text length
uint8_t len = 0;
while(tmpstr[len] != 0) len++;
while (tmpstr[len] != 0) len++;
int8_t at = len - places;
// print virtual zeros
if (at <= 0) {
if (at <= 0)
{
p->tx('0');
p->tx('.');
while(at <= -1) {
while (at <= -1)
{
p->tx('0');
at++;
}
@@ -193,8 +221,10 @@ void _putnf(const STREAM *p, const uint8_t places)
// print the number
uint8_t i = 0;
while(i < len) {
if (at-- == 0) {
while (i < len)
{
if (at-- == 0)
{
p->tx('.');
}
+8 -3
View File
@@ -23,12 +23,17 @@
#include <avr/pgmspace.h>
/** Stream structure */
typedef struct {
void (*tx) (uint8_t b);
uint8_t (*rx) (void);
typedef struct
{
void (*tx)(uint8_t b);
uint8_t (*rx)(void);
} STREAM;
/** Send bytes to stream */
void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len);
/** Print string into a stream */
void put_str(const STREAM *p, char* str);
+625 -23
View File
@@ -5,17 +5,19 @@
#include <stdint.h>
#include <stdlib.h>
#include "calc.h"
#include "uart.h"
#include "stream.h"
// Shared stream instance
static STREAM _uart_singleton;
STREAM* uart;
STREAM* uart = &_uart_singleton;
void _uart_init_do(uint16_t ubrr) {
void _uart_init_do(uint16_t ubrr)
{
/*Set baud rate */
UBRR0H = (uint8_t) (ubrr >> 8);
UBRR0H = (uint8_t)(ubrr >> 8);
UBRR0L = (uint8_t) ubrr;
// Enable Rx and Tx
@@ -26,41 +28,27 @@ void _uart_init_do(uint16_t ubrr) {
_uart_singleton.tx = &uart_tx;
_uart_singleton.rx = &uart_rx;
uart = &_uart_singleton;
}
/** Enable or disable RX ISR */
void uart_isr_rx(bool yes)
{
if(yes) {
UCSR0B |= (1 << RXCIE0);
} else {
UCSR0B &= ~(1 << RXCIE0);
}
set_bit(UCSR0B, RXCIE0, yes);
}
/** Enable or disable TX ISR (1 byte is sent) */
void uart_isr_tx(bool yes)
{
if(yes) {
UCSR0B |= (1 << TXCIE0);
} else {
UCSR0B &= ~(1 << TXCIE0);
}
set_bit(UCSR0B, TXCIE0, yes);
}
/** Enable or disable DRE ISR (all is sent) */
void uart_isr_dre(bool yes)
{
if(yes) {
UCSR0B |= (1 << UDRIE0);
} else {
UCSR0B &= ~(1 << UDRIE0);
}
set_bit(UCSR0B, UDRIE0, yes);
}
@@ -87,7 +75,8 @@ uint8_t uart_rx()
/** Send string over UART */
void uart_puts(const char* str)
{
while (*str) {
while (*str)
{
uart_tx(*str++);
}
}
@@ -97,7 +86,8 @@ void uart_puts(const char* str)
void uart_puts_P(const char* str)
{
char c;
while ((c = pgm_read_byte(str++))) {
while ((c = pgm_read_byte(str++)))
{
uart_tx(c);
}
}
@@ -107,6 +97,618 @@ void uart_puts_P(const char* str)
void uart_flush()
{
uint8_t dummy;
while (UCSR0A & (1 << RXC0))
while (bit_is_high(UCSR0A, RXC0))
{
dummy = UDR0;
}
}
// ------------- VT100 extension --------------
void _vt_apply_style();
void _vt_reset_attribs_do();
void _vt_style_do();
void _vt_color_do();
void vt_goto(uint8_t x, uint8_t y)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, y + 1); // one-based !
uart_tx(';');
put_u8(uart, x + 1);
uart_tx('H');
}
void vt_goto_x(uint8_t x)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, x + 1);
uart_tx('`');
}
void vt_goto_y(uint8_t y)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, y + 1);
uart_tx('d');
}
void vt_move(int8_t x, int8_t y)
{
vt_move_x(x);
vt_move_y(y);
}
void vt_move_x(int8_t x)
{
if (x < 0)
{
vt_left(-x);
}
else
{
vt_right(x);
}
}
void vt_move_y(int8_t y)
{
if (y < 0)
{
vt_up(-y);
}
else
{
vt_down(y);
}
}
void vt_up(uint8_t y)
{
if (y == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, y);
uart_tx('A');
}
void vt_down(uint8_t y)
{
if (y == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, y);
uart_tx('B');
}
void vt_left(uint8_t x)
{
if (x == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, x);
uart_tx('D');
}
void vt_right(uint8_t x)
{
if (x == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, x);
uart_tx('C');
}
void vt_scroll(int8_t y)
{
while (y < 0)
{
uart_tx(27);
uart_tx('D'); // up
y++;
}
while (y > 0)
{
uart_tx(27);
uart_tx('M'); // down
y--;
}
}
void vt_scroll_set(uint8_t from, uint8_t to)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, from);
uart_tx(';');
put_u8(uart, to);
uart_tx('r');
}
void vt_scroll_reset()
{
uart_tx(27);
uart_tx('[');
uart_tx('r');
}
typedef struct
{
uint8_t flags;
uint8_t fg;
uint8_t bg;
} vt_style_t;
vt_style_t saved_style;
vt_style_t current_style;
void vt_save()
{
uart_puts_P(PSTR("\x1B[s"));
saved_style = current_style;
}
void vt_restore()
{
uart_puts_P(PSTR("\x1B[u"));
current_style = saved_style;
}
/** Disable all text attributes (excluding color) */
void vt_attr_reset()
{
current_style.flags = 0;
_vt_reset_attribs_do();
_vt_apply_style();
}
/** Set color to white on black */
void vt_color_reset()
{
current_style.fg = VT_WHITE;
current_style.bg = VT_BLACK;
_vt_color_do();
}
/** Enable or disable a text attribute */
void vt_attr(uint8_t attribute, bool on)
{
// flags are powers of two
// so this can handle multiple OR'd flags
for (uint8_t c = 1; c <= VT_FAINT; c *= 2)
{
if (attribute & c)
{
if (on)
{
current_style.flags |= c;
}
else
{
current_style.flags &= ~c;
}
}
}
_vt_apply_style();
}
/** Send style and color commands */
void _vt_apply_style()
{
_vt_reset_attribs_do();
_vt_style_do();
_vt_color_do();
}
/** Set color 0..7 */
void vt_color(uint8_t fg, uint8_t bg)
{
current_style.fg = fg;
current_style.bg = bg;
_vt_color_do();
}
/** Set FG color 0..7 */
void vt_color_fg(uint8_t fg)
{
current_style.fg = fg;
_vt_color_do();
}
/** Set BG color 0..7 */
void vt_color_bg(uint8_t bg)
{
current_style.bg = bg;
_vt_color_do();
}
/** Send reset command */
inline void _vt_reset_attribs_do()
{
uart_puts_P(PSTR("\x1B[m")); // reset
}
/** Send commands for text attribs */
void _vt_style_do()
{
if (current_style.flags & VT_BOLD)
{
uart_puts_P(PSTR("\x1B[1m"));
}
if (current_style.flags & VT_FAINT)
{
uart_puts_P(PSTR("\x1B[2m"));
}
if (current_style.flags & VT_ITALIC)
{
uart_puts_P(PSTR("\x1B[3m"));
}
if (current_style.flags & VT_UNDERLINE)
{
uart_puts_P(PSTR("\x1B[4m"));
}
if (current_style.flags & VT_BLINK)
{
uart_puts_P(PSTR("\x1B[5m"));
}
if (current_style.flags & VT_REVERSE)
{
uart_puts_P(PSTR("\x1B[7m"));
}
}
/** Send commands for xolor */
void _vt_color_do()
{
uart_tx(27);
uart_tx('[');
put_u8(uart, 30 + current_style.fg);
uart_tx(';');
put_u8(uart, 40 + current_style.bg);
uart_tx('m');
}
/** Insert blank lines febore the current line */
void vt_insert_lines(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('L');
}
/** Delete lines from the current line down */
void vt_delete_lines(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('M');
}
/** Insert empty characters at cursor */
void vt_insert_chars(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('@');
}
/** Delete characters at cursor */
void vt_delete_chars(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('P');
}
void vt_clear()
{
uart_puts_P(PSTR("\x1B[2J"));
}
void vt_erase_forth()
{
uart_puts_P(PSTR("\x1B[K"));
}
void vt_erase_back()
{
uart_puts_P(PSTR("\x1B[1K"));
}
void vt_erase_line()
{
uart_puts_P(PSTR("\x1B[2K"));
}
void vt_erase_above()
{
uart_puts_P(PSTR("\x1B[1J"));
}
void vt_erase_below()
{
uart_puts_P(PSTR("\x1B[J"));
}
void vt_home()
{
uart_puts_P(PSTR("\x1B[H"));
}
/** Initialize helper variables */
void vt_init()
{
vt_reset();
}
/** Reset state and clear screen */
void vt_reset()
{
// reset color and attributes
vt_color_reset();
vt_attr_reset();
vt_scroll_reset();
// clear screen
vt_clear();
// go to top left
vt_home();
// overwrite saved state
vt_save();
}
// Assigned keyhandler
void (*_vt_kh)(uint8_t, bool) = NULL;
/** Assign a key handler (later used with vt_handle_key) */
void vt_set_key_handler(void (*handler)(uint8_t, bool))
{
_vt_kh = handler;
}
// state machine states
typedef enum
{
GROUND = 0,
ESC = 1,
BR = 2,
O = 3,
WAITING_TILDE = 4
} KSTATE;
// code received before started to wait for a tilde
uint8_t _before_wtilde;
// current state
KSTATE _kstate = GROUND;
void _vt_kh_abort()
{
switch (_kstate)
{
case ESC:
_vt_kh(VK_ESC, true);
break;
case BR:
_vt_kh(VK_ESC, true);
_vt_kh('[', false);
break;
case O:
_vt_kh(VK_ESC, true);
_vt_kh('O', false);
break;
case WAITING_TILDE:
_vt_kh(VK_ESC, true);
_vt_kh('[', false);
vt_handle_key(_before_wtilde);
break;
case GROUND:
// nop
break;
}
_kstate = GROUND;
}
/**
* Handle a key received over UART
* Takes care of multi-byte keys and translates them to special
* constants.
*/
void vt_handle_key(uint8_t c)
{
if (_vt_kh == NULL) return;
switch (_kstate)
{
case GROUND:
switch (c)
{
case 27:
_kstate = ESC;
break;
case VK_ENTER:
case VK_TAB:
case VK_BACKSPACE:
_vt_kh(c, true);
return;
default:
_vt_kh(c, false);
return;
}
break; // continue to next char
case ESC:
switch (c)
{
case '[':
_kstate = BR;
break; // continue to next char
case 'O':
_kstate = O;
break; // continue to next char
default:
// bad code
_vt_kh_abort();
vt_handle_key(c);
return;
}
break;
case BR:
switch (c)
{
// arrows
case 65:
case 66:
case 67:
case 68:
_vt_kh(c, true);
_kstate = GROUND;
return;
// ins del pgup pgdn
case 50:
case 51:
case 53:
case 54:
// wait for terminating tilde
_before_wtilde = c;
_kstate = WAITING_TILDE;
break; // continue to next char
// bad key
default:
_vt_kh_abort();
vt_handle_key(c);
return;
}
break;
case O:
switch (c)
{
// F keys
case 80:
case 81:
case 82:
case 83:
// home, end
case 72:
case 70:
_vt_kh(c, true);
_kstate = GROUND;
return;
// bad key
default:
_vt_kh_abort();
vt_handle_key(c);
return;
}
case WAITING_TILDE:
if (c != '~')
{
_vt_kh_abort();
vt_handle_key(c);
return;
}
else
{
_vt_kh(_before_wtilde, true);
_kstate = GROUND;
return;
}
}
// wait for next key
if (_kstate != GROUND)
{
_delay_ms(2);
if (!uart_rx_ready())
{
// abort receiving
_vt_kh_abort();
}
else
{
vt_handle_key(uart_rx());
}
}
}
+185
View File
@@ -66,3 +66,188 @@ void uart_puts(const char* str);
/** Send progmem string over UART */
void uart_puts_P(const char* str);
//
// ANSI / VT100 utilities for UART
//
// To use this, first call uart_init(baud) and vt_init()
// To print stuff on the screen, use uart_puts() etc from uart.h
//
// INIT
/** Initialize helper variables */
void vt_init();
/** Reset state and clear screen */
void vt_reset();
// CURSOR MOVE
/** Move cursor to top left corner */
void vt_home();
/** Jump to a location on the screen */
void vt_goto(uint8_t x, uint8_t y);
/** Jump to given X, keep Y */
void vt_goto_x(uint8_t x);
/** Jump to given Y, keep X */
void vt_goto_y(uint8_t y);
/** Move cursor relative to current location */
void vt_move(int8_t x, int8_t y);
/** Move cursor horizontally */
void vt_move_x(int8_t x);
/** Move cursor vertically */
void vt_move_y(int8_t y);
/** Move cursor up y cells */
void vt_up(uint8_t y);
/** Move cursor down y cells */
void vt_down(uint8_t y);
/** Move cursor left x cells */
void vt_left(uint8_t x);
/** Move cursor right x cells */
void vt_right(uint8_t x);
// SCROLLING
/** Scroll y lines down (like up/down, but moves window if needed) */
void vt_scroll(int8_t down);
/** Set scrolling region (lines) */
void vt_scroll_set(uint8_t from, uint8_t to);
/** Sets scrolling region to the entire screen. */
void vt_scroll_reset();
// COLOR
#define VT_BLACK 0
#define VT_RED 1
#define VT_GREEN 2
#define VT_YELLOW 3
#define VT_BLUE 4
#define VT_MAGENTA 5
#define VT_CYAN 6
#define VT_WHITE 7
/** Set color 0..7 */
void vt_color(uint8_t fg, uint8_t bg);
/** Set FG color 0..7 */
void vt_color_fg(uint8_t fg);
/** Set BG color 0..7 */
void vt_color_bg(uint8_t bg);
/** Set color to white on black */
void vt_color_reset();
// STYLES
#define VT_BOLD 1
#define VT_UNDERLINE 2
#define VT_BLINK 4
#define VT_REVERSE 8
#define VT_ITALIC 16
#define VT_FAINT 32
/** Enable or disable a text attribute */
void vt_attr(uint8_t attribute, bool on);
/** Disable all text attributes (excluding color) */
void vt_attr_reset();
// SAVE & RESTORE
/** Save cursor position & text attributes */
void vt_save();
/** Restore cursor to saved values */
void vt_restore();
// MODIFY
/** Insert blank lines febore the current line */
void vt_insert_lines(uint8_t count);
/** Delete lines from the current line down */
void vt_delete_lines(uint8_t count);
/** Insert empty characters at cursor */
void vt_insert_chars(uint8_t count);
/** Delete characters at cursor */
void vt_delete_chars(uint8_t count);
// ERASING
/** Clear the screen */
void vt_clear();
/** Erase to the end of line */
void vt_erase_forth();
/** Erase line to cursor */
void vt_erase_back();
/** Erase entire line */
void vt_erase_line();
/** Erase screen below the line */
void vt_erase_above();
/** Erase screen above the line */
void vt_erase_below();
// KEY HANDLER
// Special keys from key handler
#define VK_LEFT 68
#define VK_RIGHT 67
#define VK_UP 65
#define VK_DOWN 66
#define VK_DELETE 51
#define VK_INSERT 50
#define VK_PGUP 53
#define VK_PGDN 54
#define VK_HOME 72
#define VK_END 70
#define VK_F1 80
#define VK_F2 81
#define VK_F3 82
#define VK_F4 83
#define VK_BACKSPACE 8
#define VK_TAB 9
#define VK_ENTER 13
#define VK_ESC 27
void vt_handle_key(uint8_t c);
void vt_set_key_handler(void (*handler)(uint8_t, bool));
-581
View File
@@ -1,581 +0,0 @@
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <stdint.h>
#include "uart.h"
#include "uart_ansi.h"
#include "stream.h"
void _vt_apply_style();
void _vt_reset_attribs_do();
void _vt_style_do();
void _vt_color_do();
void vt_goto(uint8_t x, uint8_t y)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, y+1); // one-based !
uart_tx(';');
put_u8(uart, x+1);
uart_tx('H');
}
void vt_goto_x(uint8_t x)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, x+1);
uart_tx('`');
}
void vt_goto_y(uint8_t y)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, y+1);
uart_tx('d');
}
void vt_move(int8_t x, int8_t y)
{
vt_move_x(x);
vt_move_y(y);
}
void vt_move_x(int8_t x)
{
if (x < 0) {
vt_left(-x);
} else {
vt_right(x);
}
}
void vt_move_y(int8_t y)
{
if (y < 0) {
vt_up(-y);
} else {
vt_down(y);
}
}
void vt_up(uint8_t y)
{
if (y == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, y);
uart_tx('A');
}
void vt_down(uint8_t y)
{
if (y == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, y);
uart_tx('B');
}
void vt_left(uint8_t x)
{
if (x == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, x);
uart_tx('D');
}
void vt_right(uint8_t x)
{
if (x == 0) return;
uart_tx(27);
uart_tx('[');
put_u8(uart, x);
uart_tx('C');
}
void vt_scroll(int8_t y)
{
while (y < 0) {
uart_tx(27);
uart_tx('D'); // up
y++;
}
while (y > 0) {
uart_tx(27);
uart_tx('M'); // down
y--;
}
}
void vt_scroll_set(uint8_t from, uint8_t to)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, from);
uart_tx(';');
put_u8(uart, to);
uart_tx('r');
}
void vt_scroll_reset()
{
uart_tx(27);
uart_tx('[');
uart_tx('r');
}
typedef struct {
uint8_t flags;
uint8_t fg;
uint8_t bg;
} vt_style_t;
vt_style_t saved_style;
vt_style_t current_style;
void vt_save()
{
uart_puts_P(PSTR("\x1B[s"));
saved_style = current_style;
}
void vt_restore()
{
uart_puts_P(PSTR("\x1B[u"));
current_style = saved_style;
}
/** Disable all text attributes (excluding color) */
void vt_attr_reset()
{
current_style.flags = 0;
_vt_reset_attribs_do();
_vt_apply_style();
}
/** Set color to white on black */
void vt_color_reset()
{
current_style.fg = VT_WHITE;
current_style.bg = VT_BLACK;
_vt_color_do();
}
/** Enable or disable a text attribute */
void vt_attr(uint8_t attribute, bool on)
{
// flags are powers of two
// so this can handle multiple OR'd flags
for(uint8_t c = 1; c <= VT_FAINT; c *= 2) {
if (attribute & c) {
if (on) {
current_style.flags |= c;
} else {
current_style.flags &= ~c;
}
}
}
_vt_apply_style();
}
/** Send style and color commands */
void _vt_apply_style()
{
_vt_reset_attribs_do();
_vt_style_do();
_vt_color_do();
}
/** Set color 0..7 */
void vt_color(uint8_t fg, uint8_t bg)
{
current_style.fg = fg;
current_style.bg = bg;
_vt_color_do();
}
/** Set FG color 0..7 */
void vt_color_fg(uint8_t fg)
{
current_style.fg = fg;
_vt_color_do();
}
/** Set BG color 0..7 */
void vt_color_bg(uint8_t bg)
{
current_style.bg = bg;
_vt_color_do();
}
/** Send reset command */
inline void _vt_reset_attribs_do()
{
uart_puts_P(PSTR("\x1B[m")); // reset
}
/** Send commands for text attribs */
void _vt_style_do()
{
if (current_style.flags & VT_BOLD) {
uart_puts_P(PSTR("\x1B[1m"));
}
if (current_style.flags & VT_FAINT) {
uart_puts_P(PSTR("\x1B[2m"));
}
if (current_style.flags & VT_ITALIC) {
uart_puts_P(PSTR("\x1B[3m"));
}
if (current_style.flags & VT_UNDERLINE) {
uart_puts_P(PSTR("\x1B[4m"));
}
if (current_style.flags & VT_BLINK) {
uart_puts_P(PSTR("\x1B[5m"));
}
if (current_style.flags & VT_REVERSE) {
uart_puts_P(PSTR("\x1B[7m"));
}
}
/** Send commands for xolor */
void _vt_color_do()
{
uart_tx(27);
uart_tx('[');
put_u8(uart, 30 + current_style.fg);
uart_tx(';');
put_u8(uart, 40 + current_style.bg);
uart_tx('m');
}
/** Insert blank lines febore the current line */
void vt_insert_lines(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('L');
}
/** Delete lines from the current line down */
void vt_delete_lines(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('M');
}
/** Insert empty characters at cursor */
void vt_insert_chars(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('@');
}
/** Delete characters at cursor */
void vt_delete_chars(uint8_t count)
{
uart_tx(27);
uart_tx('[');
put_u8(uart, count);
uart_tx('P');
}
void vt_clear()
{
uart_puts_P(PSTR("\x1B[2J"));
}
void vt_erase_forth()
{
uart_puts_P(PSTR("\x1B[K"));
}
void vt_erase_back()
{
uart_puts_P(PSTR("\x1B[1K"));
}
void vt_erase_line()
{
uart_puts_P(PSTR("\x1B[2K"));
}
void vt_erase_above()
{
uart_puts_P(PSTR("\x1B[1J"));
}
void vt_erase_below()
{
uart_puts_P(PSTR("\x1B[J"));
}
void vt_home()
{
uart_puts_P(PSTR("\x1B[H"));
}
/** Initialize helper variables */
void vt_init()
{
vt_reset();
}
/** Reset state and clear screen */
void vt_reset()
{
// reset color and attributes
vt_color_reset();
vt_attr_reset();
vt_scroll_reset();
// clear screen
vt_clear();
// go to top left
vt_home();
// overwrite saved state
vt_save();
}
// Assigned keyhandler
void (*_vt_kh)(uint8_t, bool) = NULL;
/** Assign a key handler (later used with vt_handle_key) */
void vt_set_key_handler(void (*handler)(uint8_t, bool))
{
_vt_kh = handler;
}
// state machine states
typedef enum {
GROUND = 0,
ESC = 1,
BR = 2,
O = 3,
WAITING_TILDE = 4
} KSTATE;
// code received before started to wait for a tilde
uint8_t _before_wtilde;
// current state
KSTATE _kstate = GROUND;
void _vt_kh_abort()
{
switch (_kstate) {
case ESC:
_vt_kh(VK_ESC, true);
break;
case BR:
_vt_kh(VK_ESC, true);
_vt_kh('[', false);
break;
case O:
_vt_kh(VK_ESC, true);
_vt_kh('O', false);
break;
case WAITING_TILDE:
_vt_kh(VK_ESC, true);
_vt_kh('[', false);
vt_handle_key(_before_wtilde);
break;
case GROUND:
// nop
break;
}
_kstate = GROUND;
}
/**
* Handle a key received over UART
* Takes care of multi-byte keys and translates them to special
* constants.
*/
void vt_handle_key(uint8_t c)
{
if (_vt_kh == NULL) return;
switch (_kstate) {
case GROUND:
switch (c) {
case 27:
_kstate = ESC;
break;
case VK_ENTER:
case VK_TAB:
case VK_BACKSPACE:
_vt_kh(c, true);
return;
default:
_vt_kh(c, false);
return;
}
break; // continue to next char
case ESC:
switch (c) {
case '[':
_kstate = BR;
break; // continue to next char
case 'O':
_kstate = O;
break; // continue to next char
default:
// bad code
_vt_kh_abort();
vt_handle_key(c);
return;
}
break;
case BR:
switch (c) {
// arrows
case 65:
case 66:
case 67:
case 68:
_vt_kh(c, true);
_kstate = GROUND;
return;
// ins del pgup pgdn
case 50:
case 51:
case 53:
case 54:
// wait for terminating tilde
_before_wtilde = c;
_kstate = WAITING_TILDE;
break; // continue to next char
// bad key
default:
_vt_kh_abort();
vt_handle_key(c);
return;
}
break;
case O:
switch (c) {
// F keys
case 80:
case 81:
case 82:
case 83:
// home, end
case 72:
case 70:
_vt_kh(c, true);
_kstate = GROUND;
return;
// bad key
default:
_vt_kh_abort();
vt_handle_key(c);
return;
}
case WAITING_TILDE:
if (c != '~') {
_vt_kh_abort();
vt_handle_key(c);
return;
} else {
_vt_kh(_before_wtilde, true);
_kstate = GROUND;
return;
}
}
// wait for next key
if (_kstate != GROUND) {
_delay_ms(2);
if (!uart_rx_ready()) {
// abort receiving
_vt_kh_abort();
} else {
vt_handle_key(uart_rx());
}
}
}
-192
View File
@@ -1,192 +0,0 @@
#pragma once
//
// ANSI / VT100 utilities for UART
//
// To use this, first call uart_init(baud) and vt_init()
// To print stuff on the screen, use uart_puts() etc from uart.h
//
#include <avr/io.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include "uart.h"
// INIT
/** Initialize helper variables */
void vt_init();
/** Reset state and clear screen */
void vt_reset();
// CURSOR MOVE
/** Move cursor to top left corner */
void vt_home();
/** Jump to a location on the screen */
void vt_goto(uint8_t x, uint8_t y);
/** Jump to given X, keep Y */
void vt_goto_x(uint8_t x);
/** Jump to given Y, keep X */
void vt_goto_y(uint8_t y);
/** Move cursor relative to current location */
void vt_move(int8_t x, int8_t y);
/** Move cursor horizontally */
void vt_move_x(int8_t x);
/** Move cursor vertically */
void vt_move_y(int8_t y);
/** Move cursor up y cells */
void vt_up(uint8_t y);
/** Move cursor down y cells */
void vt_down(uint8_t y);
/** Move cursor left x cells */
void vt_left(uint8_t x);
/** Move cursor right x cells */
void vt_right(uint8_t x);
// SCROLLING
/** Scroll y lines down (like up/down, but moves window if needed) */
void vt_scroll(int8_t down);
/** Set scrolling region (lines) */
void vt_scroll_set(uint8_t from, uint8_t to);
/** Sets scrolling region to the entire screen. */
void vt_scroll_reset();
// COLOR
#define VT_BLACK 0
#define VT_RED 1
#define VT_GREEN 2
#define VT_YELLOW 3
#define VT_BLUE 4
#define VT_MAGENTA 5
#define VT_CYAN 6
#define VT_WHITE 7
/** Set color 0..7 */
void vt_color(uint8_t fg, uint8_t bg);
/** Set FG color 0..7 */
void vt_color_fg(uint8_t fg);
/** Set BG color 0..7 */
void vt_color_bg(uint8_t bg);
/** Set color to white on black */
void vt_color_reset();
// STYLES
#define VT_BOLD 1
#define VT_UNDERLINE 2
#define VT_BLINK 4
#define VT_REVERSE 8
#define VT_ITALIC 16
#define VT_FAINT 32
/** Enable or disable a text attribute */
void vt_attr(uint8_t attribute, bool on);
/** Disable all text attributes (excluding color) */
void vt_attr_reset();
// SAVE & RESTORE
/** Save cursor position & text attributes */
void vt_save();
/** Restore cursor to saved values */
void vt_restore();
// MODIFY
/** Insert blank lines febore the current line */
void vt_insert_lines(uint8_t count);
/** Delete lines from the current line down */
void vt_delete_lines(uint8_t count);
/** Insert empty characters at cursor */
void vt_insert_chars(uint8_t count);
/** Delete characters at cursor */
void vt_delete_chars(uint8_t count);
// ERASING
/** Clear the screen */
void vt_clear();
/** Erase to the end of line */
void vt_erase_forth();
/** Erase line to cursor */
void vt_erase_back();
/** Erase entire line */
void vt_erase_line();
/** Erase screen below the line */
void vt_erase_above();
/** Erase screen above the line */
void vt_erase_below();
// KEY HANDLER
// Special keys from key handler
#define VK_LEFT 68
#define VK_RIGHT 67
#define VK_UP 65
#define VK_DOWN 66
#define VK_DELETE 51
#define VK_INSERT 50
#define VK_PGUP 53
#define VK_PGDN 54
#define VK_HOME 72
#define VK_END 70
#define VK_F1 80
#define VK_F2 81
#define VK_F3 82
#define VK_F4 83
#define VK_BACKSPACE 8
#define VK_TAB 9
#define VK_ENTER 13
#define VK_ESC 27
void vt_handle_key(uint8_t c);
void vt_set_key_handler(void (*handler)(uint8_t, bool));
-126
View File
@@ -1,126 +0,0 @@
#pragma once
//
// Utils for driving a WS28xx (tested on WS2812B) RGB LED strips.
//
// It's implemented as macros to avoid overhead when passing values, and to
// enable driving multiple strips at once.
//
// To avoid bloating your code, try to reduce the number of invocations -
// compute color and then send it.
//
// [IMPORTANT]
//
// Some seemingly random influences can ruin the communication.
// If you have enough memory, consider preparing the colors in array,
// and sending this array using one of the "ws_send_XXX_array" macros.
//
#include <avr/io.h>
#include "pins.h"
#include "nsdelay.h"
#include "colors.h"
/* Driver code for WS2812B */
// --- timing constraints (NS) ---
#ifndef WS_T_1H
# define WS_T_1H 700
#endif
#ifndef WS_T_1L
# define WS_T_1L 150
#endif
#ifndef WS_T_0H
# define WS_T_0H 150
#endif
#ifndef WS_T_0L
# define WS_T_0L 700
#endif
#ifndef WS_T_LATCH
# define WS_T_LATCH 7000
#endif
/** Wait long enough for the colors to show */
#define ws_show() do {delay_ns_c(WS_T_LATCH, 0); } while(0)
/** Send one byte to the RGB strip */
#define ws_send_byte(io, bb) do { \
for (volatile int8_t __ws_tmp = 7; __ws_tmp >= 0; --__ws_tmp) { \
if ((bb) & (1 << __ws_tmp)) { \
pin_high(io_pack(io)); delay_ns_c(WS_T_1H, -2); \
pin_low(io_pack(io)); delay_ns_c(WS_T_1L, -10); \
} else { \
pin_high(io_pack(io)); delay_ns_c(WS_T_0H, -2); \
pin_low(io_pack(io)); delay_ns_c(WS_T_0L, -10); \
} \
} \
} while(0)
/** Send R,G,B color to the strip */
#define ws_send_rgb(io, r, g, b) do { \
ws_send_byte(io_pack(io), g); \
ws_send_byte(io_pack(io), r); \
ws_send_byte(io_pack(io), b); \
} while(0)
/** Send a RGB struct */
#define ws_send_xrgb(io, xrgb) ws_send_rgb(io_pack(io), (xrgb).r, (xrgb).g, (xrgb).b)
/** Send color hex */
#define ws_send_rgb24(io, rgb) ws_send_rgb(io_pack(io), rgb24_r(rgb), rgb24_g(rgb), rgb24_b(rgb))
#define ws_send_rgb15(io, rgb) ws_send_rgb(io_pack(io), rgb15_r(rgb), rgb15_g(rgb), rgb15_b(rgb))
#define ws_send_rgb12(io, rgb) ws_send_rgb(io_pack(io), rgb12_r(rgb), rgb12_g(rgb), rgb12_b(rgb))
#define ws_send_rgb6(io, rgb) ws_send_rgb(io_pack(io), rgb6_r(rgb), rgb6_g(rgb), rgb6_b(rgb))
/** Send array of colors */
#define ws_send_xrgb_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), xrgb)
#define ws_send_rgb24_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), rgb24)
#define ws_send_rgb15_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), rgb15)
#define ws_send_rgb12_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), rgb12)
#define ws_send_rgb6_array(io, rgbs, length) __ws_send_array_proto(io_pack(io), (rgbs), (length), rgb6)
// prototype for sending array. it's ugly, sorry.
#define __ws_send_array_proto(io, rgbs, length, style) do { \
for (uint8_t __ws_sap_i = 0; __ws_sap_i < length; __ws_sap_i++) { \
style ## _t __ws_sap2 = (rgbs)[__ws_sap_i]; \
ws_send_ ## style(io_pack(io), __ws_sap2); \
} \
} while(0)
/** Send a 2D array to a zig-zag display */
#define ws_send_xrgb_array_zigzag(io, rgbs, width, height) do { \
int8_t __ws_sxaz_y, __ws_sxaz_x; \
for(__ws_sxaz_y = 0; __ws_sxaz_y < (height); __ws_sxaz_y ++) { \
for(__ws_sxaz_x = 0; __ws_sxaz_x < (width); __ws_sxaz_x++) { \
ws_send_xrgb(io_pack(io), (rgbs)[__ws_sxaz_y][__ws_sxaz_x]); \
} \
__ws_sxaz_y++; \
for(__ws_sxaz_x = (width) - 1; __ws_sxaz_x >= 0; __ws_sxaz_x--) { \
ws_send_xrgb(io_pack(io), (rgbs)[__ws_sxaz_y][__ws_sxaz_x]); \
} \
} \
} while(0)
/** Send a linear array to a zig-zag display as a n*m board (row-by-row) */
#define ws_send_xrgb_array_zigzag_linear(io, rgbs, width, height) do { \
int8_t __ws_sxazl_x, __ws_sxazl_y; \
for(__ws_sxazl_y = 0; __ws_sxazl_y < (height); __ws_sxazl_y++) { \
for(__ws_sxazl_x = 0; __ws_sxazl_x < (width); __ws_sxazl_x++) { \
ws_send_xrgb(io_pack(io), (rgbs)[__ws_sxazl_y * (width) + __ws_sxazl_x]); \
} \
__ws_sxazl_y++; \
for(__ws_sxazl_x = width-1; __ws_sxazl_x >=0; __ws_sxazl_x--) { \
ws_send_xrgb(io_pack(io), (rgbs)[__ws_sxazl_y * (width) + __ws_sxazl_x]); \
} \
} \
} while(0)
+139
View File
@@ -0,0 +1,139 @@
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include "iopins.h"
#include "nsdelay.h"
#include "wsrgb.h"
#include "color.h"
#include "ws_config.h"
/* Driver code for WS2812B */
void ws_init()
{
as_output(WS_PIN);
}
/** Wait long enough for the colors to show */
void ws_show()
{
delay_ns_c(WS_T_LATCH, 0);
}
/** Send one byte to the RGB strip */
void ws_send_byte(const uint8_t bb)
{
for (volatile int8_t i = 7; i >= 0; --i)
{
if ((bb) & (1 << i))
{
pin_high(WS_PIN);
delay_ns_c(WS_T_1H, -2);
pin_low(WS_PIN);
delay_ns_c(WS_T_1L, -10);
}
else
{
pin_high(WS_PIN);
delay_ns_c(WS_T_0H, -2);
pin_low(WS_PIN);
delay_ns_c(WS_T_0L, -10);
}
}
}
/** Send R,G,B color to the strip */
void ws_send_rgb(const uint8_t r, const uint8_t g, const uint8_t b)
{
ws_send_byte(g);
ws_send_byte(r);
ws_send_byte(b);
}
/** Send a RGB struct */
void ws_send_xrgb(xrgb_t xrgb)
{
ws_send_byte(xrgb.g);
ws_send_byte(xrgb.r);
ws_send_byte(xrgb.b);
}
/** Send color hex */
void ws_send_rgb24(rgb24_t rgb)
{
ws_send_byte(rgb24_g(rgb));
ws_send_byte(rgb24_r(rgb));
ws_send_byte(rgb24_b(rgb));
}
/** Send array of colors */
void ws_send_xrgb_array(const xrgb_t rgbs[], const uint8_t length)
{
for (uint8_t i = 0; i < length; i++)
{
const xrgb_t c = rgbs[i];
ws_send_byte(c.g);
ws_send_byte(c.r);
ws_send_byte(c.b);
}
}
/** Send array of colors */
void ws_send_rgb24_array(const rgb24_t rgbs[], const uint8_t length)
{
for (uint8_t i = 0; i < length; i++)
{
const rgb24_t c = rgbs[i];
ws_send_byte(rgb24_g(c));
ws_send_byte(rgb24_r(c));
ws_send_byte(rgb24_b(c));
}
}
//#define ws_send_rgb24_array(rgbs, length) __ws_send_array_proto((rgbs), (length), rgb24)
// prototype for sending array. it's ugly, sorry.
/*#define __ws_send_array_proto(rgbs, length, style) { \
for (uint8_t __rgb_sap_i = 0; __rgb_sap_i < length; __rgb_sap_i++) { \
style ## _t __rgb_sap2 = (rgbs)[__rgb_sap_i]; \
ws_send_ ## style(__rgb_sap2); \
} \
}*/
// /** Send a 2D array to a zig-zag display */
// #define ws_send_xrgb_array_zigzag(rgbs, width, height) { \
// int8_t __rgb_sxaz_y, __rgb_sxaz_x; \
// for(__rgb_sxaz_y = 0; __rgb_sxaz_y < (height); __rgb_sxaz_y ++) { \
// for(__rgb_sxaz_x = 0; __rgb_sxaz_x < (width); __rgb_sxaz_x++) { \
// ws_send_xrgb((rgbs)[__rgb_sxaz_y][__rgb_sxaz_x]); \
// } \
// __rgb_sxaz_y++; \
// for(__rgb_sxaz_x = (width) - 1; __rgb_sxaz_x >= 0; __rgb_sxaz_x--) { \
// ws_send_xrgb((rgbs)[__rgb_sxaz_y][__rgb_sxaz_x]); \
// } \
// } \
// }
// /* Send a linear array to a zig-zag display as a n*m board (row-by-row)
// #define ws_send_xrgb_array_zigzag_linear(rgbs, width, height) { \
// int8_t __rgb_sxazl_x, __rgb_sxazl_y; \
// for(__rgb_sxazl_y = 0; __rgb_sxazl_y < (height); __rgb_sxazl_y++) { \
// for(__rgb_sxazl_x = 0; __rgb_sxazl_x < (width); __rgb_sxazl_x++) { \
// ws_send_xrgb((rgbs)[__rgb_sxazl_y * (width) + __rgb_sxazl_x]); \
// } \
// __rgb_sxazl_y++; \
// for(__rgb_sxazl_x = width-1; __rgb_sxazl_x >=0; __rgb_sxazl_x--) { \
// ws_send_xrgb((rgbs)[__rgb_sxazl_y * (width) + __rgb_sxazl_x]); \
// } \
// } \
// }
+51
View File
@@ -0,0 +1,51 @@
#pragma once
//
// Utils for driving a WS2812 RGB LED strips, and color manipulation in general.
//
// Timing is critical!
//
// Create a config file rgb_config.h next to your main.c
//
#include "iopins.h"
#include "color.h"
// Your config file
#include "ws_config.h"
/*
#define WS_T_1H 700
#define WS_T_1L 150
#define WS_T_0H 150
#define WS_T_0L 700
#define WS_T_LATCH 7000
#define WS_PIN 2
*/
// --- functions for RGB strips ---
/** Initialize OI */
void ws_init();
/** Wait long enough for the colors to show */
void ws_show();
/** Send one byte to the RGB strip */
void ws_send_byte(const uint8_t bb);
/** Send R,G,B color to the strip */
void ws_send_rgb(const uint8_t r, const uint8_t g, const uint8_t b);
/** Send a RGB struct */
void ws_send_xrgb(xrgb_t xrgb);
/** Send color hex */
void ws_send_rgb24(rgb24_t rgb);
/** Send array of colors */
void ws_send_xrgb_array(const xrgb_t rgbs[], const uint8_t length);
/** Send array of colors */
void ws_send_rgb24_array(const rgb24_t rgbs[], const uint8_t length);