From 033273b9d1ce7505228f66eb23ca849cbe88bba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Wed, 10 Jun 2015 01:57:45 +0200 Subject: [PATCH] added devel folder.. --- .gitignore | 2 - devel/README.md | 5 + devel/dht11/Makefile | 147 +++++ devel/dht11/lib | 1 + devel/dht11/main.c | 35 ++ devel/iopins/Makefile | 137 ++++ devel/iopins/avrlib_1-0-0.zip | Bin 0 -> 23019 bytes devel/iopins/iopins.c | 276 ++++++++ devel/iopins/iopins.h | 190 ++++++ devel/iopins/lib | 1 + devel/iopins/main.c | 27 + devel/lcdsnake/Makefile | 167 +++++ devel/lcdsnake/README.md | 10 + devel/lcdsnake/debo_config.h | 5 + devel/lcdsnake/lcd_config.h | 13 + devel/lcdsnake/lib | 1 + devel/lcdsnake/main.c | 429 +++++++++++++ devel/onewire/Makefile | 141 +++++ devel/onewire/lib | 1 + devel/onewire/main.c | 38 ++ devel/rgb_hsl/Makefile | 170 +++++ devel/rgb_hsl/README.md | 11 + devel/rgb_hsl/lib | 1 + devel/rgb_hsl/main.c | 69 ++ devel/sd_bad/Makefile | 147 +++++ devel/sd_bad/deployment.pri | 191 ++++++ devel/sd_bad/main.c | 57 ++ devel/sd_bad/main.h | 10 + devel/sd_bad/sd.c | 467 ++++++++++++++ devel/sd_bad/sd.h | 25 + devel/sd_bad/sd_bad.pro | 25 + devel/sd_bad/sd_bad.pro.user | 250 ++++++++ devel/sd_bad/sdcomm_spi.h | 152 +++++ devel/sd_bad/spi.c | 88 +++ devel/sd_bad/spi.h | 15 + devel/sd_bad/style.astylerc | 13 + devel/sdcard/Makefile | 147 +++++ devel/sdcard/deployment.pri | 191 ++++++ devel/sdcard/lib | 1 + devel/sdcard/main.c | 64 ++ devel/sdcard/sdcard.pro | 56 ++ devel/sdcard/sdcard.pro.user | 250 ++++++++ devel/sdcard/style.astylerc | 13 + devel/snake/Makefile | 166 +++++ devel/snake/lcd_default.asm | 351 +++++++++++ devel/snake/lib | 1 + devel/snake/main.c | 426 +++++++++++++ devel/try_ws/Makefile | 147 +++++ devel/try_ws/client | Bin 0 -> 10160 bytes devel/try_ws/lib | 1 + devel/try_ws/main.c | 32 + devel/try_ws/ws_config.h | 7 + devel/uart/Makefile | 147 +++++ devel/uart/client | Bin 0 -> 10160 bytes devel/uart/clientd/Makefile | 7 + devel/uart/clientd/client | Bin 0 -> 10160 bytes devel/uart/clientd/main | 0 devel/uart/clientd/main.c | 37 ++ devel/uart/clientd/serial.c | 89 +++ devel/uart/clientd/serial.h | 27 + devel/uart/lib | 1 + devel/uart/main.c | 25 + devel/uart/special_keys.txt | 25 + devel/ultrasonic/Makefile | 137 ++++ devel/ultrasonic/lcd_config.h | 13 + devel/ultrasonic/lib | 1 + devel/ultrasonic/main.c | 91 +++ devel/xxx/Makefile | 147 +++++ devel/xxx/client | Bin 0 -> 10160 bytes devel/xxx/clientd/Makefile | 7 + devel/xxx/clientd/client | Bin 0 -> 10160 bytes devel/xxx/clientd/main | 0 devel/xxx/clientd/main.c | 37 ++ devel/xxx/clientd/serial.c | 89 +++ devel/xxx/clientd/serial.h | 27 + devel/xxx/fat16.c | 1112 +++++++++++++++++++++++++++++++++ devel/xxx/fat16.h | 260 ++++++++ devel/xxx/lib | 1 + devel/xxx/main.c | 103 +++ 79 files changed, 7551 insertions(+), 2 deletions(-) create mode 100644 devel/README.md create mode 100644 devel/dht11/Makefile create mode 120000 devel/dht11/lib create mode 100644 devel/dht11/main.c create mode 100644 devel/iopins/Makefile create mode 100644 devel/iopins/avrlib_1-0-0.zip create mode 100644 devel/iopins/iopins.c create mode 100644 devel/iopins/iopins.h create mode 120000 devel/iopins/lib create mode 100644 devel/iopins/main.c create mode 100644 devel/lcdsnake/Makefile create mode 100644 devel/lcdsnake/README.md create mode 100644 devel/lcdsnake/debo_config.h create mode 100644 devel/lcdsnake/lcd_config.h create mode 120000 devel/lcdsnake/lib create mode 100644 devel/lcdsnake/main.c create mode 100644 devel/onewire/Makefile create mode 120000 devel/onewire/lib create mode 100644 devel/onewire/main.c create mode 100644 devel/rgb_hsl/Makefile create mode 100644 devel/rgb_hsl/README.md create mode 120000 devel/rgb_hsl/lib create mode 100644 devel/rgb_hsl/main.c create mode 100644 devel/sd_bad/Makefile create mode 100644 devel/sd_bad/deployment.pri create mode 100644 devel/sd_bad/main.c create mode 100644 devel/sd_bad/main.h create mode 100644 devel/sd_bad/sd.c create mode 100644 devel/sd_bad/sd.h create mode 100644 devel/sd_bad/sd_bad.pro create mode 100644 devel/sd_bad/sd_bad.pro.user create mode 100644 devel/sd_bad/sdcomm_spi.h create mode 100644 devel/sd_bad/spi.c create mode 100644 devel/sd_bad/spi.h create mode 100644 devel/sd_bad/style.astylerc create mode 100644 devel/sdcard/Makefile create mode 100644 devel/sdcard/deployment.pri create mode 120000 devel/sdcard/lib create mode 100644 devel/sdcard/main.c create mode 100644 devel/sdcard/sdcard.pro create mode 100644 devel/sdcard/sdcard.pro.user create mode 100644 devel/sdcard/style.astylerc create mode 100644 devel/snake/Makefile create mode 100644 devel/snake/lcd_default.asm create mode 120000 devel/snake/lib create mode 100644 devel/snake/main.c create mode 100644 devel/try_ws/Makefile create mode 100755 devel/try_ws/client create mode 120000 devel/try_ws/lib create mode 100644 devel/try_ws/main.c create mode 100644 devel/try_ws/ws_config.h create mode 100644 devel/uart/Makefile create mode 100755 devel/uart/client create mode 100644 devel/uart/clientd/Makefile create mode 100755 devel/uart/clientd/client create mode 100644 devel/uart/clientd/main create mode 100644 devel/uart/clientd/main.c create mode 100644 devel/uart/clientd/serial.c create mode 100644 devel/uart/clientd/serial.h create mode 120000 devel/uart/lib create mode 100644 devel/uart/main.c create mode 100644 devel/uart/special_keys.txt create mode 100644 devel/ultrasonic/Makefile create mode 100644 devel/ultrasonic/lcd_config.h create mode 120000 devel/ultrasonic/lib create mode 100644 devel/ultrasonic/main.c create mode 100644 devel/xxx/Makefile create mode 100755 devel/xxx/client create mode 100644 devel/xxx/clientd/Makefile create mode 100755 devel/xxx/clientd/client create mode 100644 devel/xxx/clientd/main create mode 100644 devel/xxx/clientd/main.c create mode 100644 devel/xxx/clientd/serial.c create mode 100644 devel/xxx/clientd/serial.h create mode 100644 devel/xxx/fat16.c create mode 100644 devel/xxx/fat16.h create mode 120000 devel/xxx/lib create mode 100644 devel/xxx/main.c diff --git a/.gitignore b/.gitignore index 37ad9be..934c62e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,3 @@ *.so *.out *.hex - -devel/ diff --git a/devel/README.md b/devel/README.md new file mode 100644 index 0000000..18568a3 --- /dev/null +++ b/devel/README.md @@ -0,0 +1,5 @@ +**Files in this folder are experimental, work-in-progress projects.** + +Do not expect them to work. + +For finished stuff, look into the /projects folder. diff --git a/devel/dht11/Makefile b/devel/dht11/Makefile new file mode 100644 index 0000000..6ed6ce1 --- /dev/null +++ b/devel/dht11/Makefile @@ -0,0 +1,147 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === 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/ + + +# C files in the library directory +EXTRA_SOURCE_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c +#Files that need config file: +# EXTRA_SOURCE_FILES += lcd.c +# EXTRA_SOURCE_FILES += color.c wsrgb.c +# EXTRA_SOURCE_FILES += debouce.c + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +fser: all flash ser + +ser: + gtkterm -p /dev/ttyUSB0 + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/dht11/lib b/devel/dht11/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/dht11/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/dht11/main.c b/devel/dht11/main.c new file mode 100644 index 0000000..157c43c --- /dev/null +++ b/devel/dht11/main.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/iopins.h" +#include "lib/uart.h" +#include "lib/stream.h" +#include "lib/dht11.h" + +void main() +{ + uart_init(9600); + uart_puts_P(PSTR("*** DHT11 test ***\r\n")); + + while(1) + { + dht11_result_t result; + + if (dht11_read(2, &result)) { + // Temperature + put_i8(uart, result.temp); + uart_puts_P(PSTR(" °C, ")); + // Humidity + put_i8(uart, result.rh); + uart_puts_P(PSTR(" %r.H\r\n")); + } else { + uart_puts_P(PSTR("Read error!\r\n")); + } + + _delay_ms(500); + } +} diff --git a/devel/iopins/Makefile b/devel/iopins/Makefile new file mode 100644 index 0000000..b7fde89 --- /dev/null +++ b/devel/iopins/Makefile @@ -0,0 +1,137 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === 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/ +# C files in the library directory +EXTRA_SOURCE_FILES = uart.c uart_ansi.c iopins.c + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/iopins/avrlib_1-0-0.zip b/devel/iopins/avrlib_1-0-0.zip new file mode 100644 index 0000000000000000000000000000000000000000..fbe89ed9ace54e2271360d48aa35ca3a97d54373 GIT binary patch literal 23019 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 +#include +#include + +#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 set_low_n(const uint8_t pin) +{ + switch(pin) { + case 0: set_low(0); return; + case 1: set_low(1); return; + case 2: set_low(2); return; + case 3: set_low(3); return; + case 4: set_low(4); return; + case 5: set_low(5); return; + case 6: set_low(6); return; + case 7: set_low(7); return; + case 8: set_low(8); return; + case 9: set_low(9); return; + case 10: set_low(10); return; + case 11: set_low(11); return; + case 12: set_low(12); return; + case 13: set_low(13); return; + case 14: set_low(14); return; + case 15: set_low(15); return; + case 16: set_low(16); return; + case 17: set_low(17); return; + case 18: set_low(18); return; + case 19: set_low(19); return; + case 20: set_low(20); return; + case 21: set_low(21); return; + } +} + +void set_high_n(const uint8_t pin) +{ + switch(pin) { + case 0: set_high(0); return; + case 1: set_high(1); return; + case 2: set_high(2); return; + case 3: set_high(3); return; + case 4: set_high(4); return; + case 5: set_high(5); return; + case 6: set_high(6); return; + case 7: set_high(7); return; + case 8: set_high(8); return; + case 9: set_high(9); return; + case 10: set_high(10); return; + case 11: set_high(11); return; + case 12: set_high(12); return; + case 13: set_high(13); return; + case 14: set_high(14); return; + case 15: set_high(15); return; + case 16: set_high(16); return; + case 17: set_high(17); return; + case 18: set_high(18); return; + case 19: set_high(19); return; + case 20: set_high(20); return; + case 21: set_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); +} diff --git a/devel/iopins/iopins.h b/devel/iopins/iopins.h new file mode 100644 index 0000000..ba2354e --- /dev/null +++ b/devel/iopins/iopins.h @@ -0,0 +1,190 @@ +#pragma once + +#include +#include +#include + +#include "calc.h" + +/** 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 + + +/** 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); set_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 set_low(pin) cbi(_PORT_##pin, _PN_##pin) +void set_low_n(const uint8_t pin); + + +/** Write 1 to a pin */ +#define set_high(pin) sbi(_PORT_##pin, _PN_##pin) +void set_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 diff --git a/devel/iopins/lib b/devel/iopins/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/iopins/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/iopins/main.c b/devel/iopins/main.c new file mode 100644 index 0000000..f9817cc --- /dev/null +++ b/devel/iopins/main.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/iopins.h" + +void main() +{ + for (int i = 2; i <= 5; i++) { + as_output_n(i); + } + + as_input_pu(12); + + while(1) { + for (int i = 2; i <= 5; i++) { + if (is_low(12)) { + set_high_n(i); + _delay_ms(100); + set_low_n(i); + } + } + } +} diff --git a/devel/lcdsnake/Makefile b/devel/lcdsnake/Makefile new file mode 100644 index 0000000..3b7b0bb --- /dev/null +++ b/devel/lcdsnake/Makefile @@ -0,0 +1,167 @@ + +MCU = atmega328p + +F_CPU = 16000000 + +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + +MAIN = main.c + +## If you've split your program into multiple files, +## include the additional .c source (in same directory) here +## (and include the .h files in your foo.c) +LOCAL_SOURCE = + +## Here you can link to one more directory (and multiple .c files) +# EXTRA_SOURCE_DIR = ../AVR-Programming-Library/ +EXTRA_SOURCE_DIR = lib/ +EXTRA_SOURCE_FILES = debounce.c lcd.c adc.c + +EXTRA_CFLAGS = + +##########------------------------------------------------------########## +########## Programmer Defaults ########## +########## Set up once, then forget about it ########## +########## (Can override. See bottom of file.) ########## +##########------------------------------------------------------########## +#19200 +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +##########------------------------------------------------------########## +########## Makefile Magic! ########## +########## Summary: ########## +########## We want a .hex file ########## +########## Compile source files into .elf ########## +########## Convert .elf file into .hex ########## +########## You shouldn't need to edit below. ########## +##########------------------------------------------------------########## + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## Compilation options, type man avr-gcc if you're curious. +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 +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax +CFLAGS += $(EXTRA_CFLAGS) + +CFLAGS_BUILD = $(CFLAGS) -Os + +# CFLAGS += -lm +## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf +## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf + +## Lump target and extra source files together +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +## List of all header files +HEADERS = $(SRC:.c=.h) + +## For every .c file, compile an .o object file +OBJ = $(SRC:.c=.o) + +## Generic Makefile targets. (Only .hex file is necessary) +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + +# Optionally create listing file from .elf +# This creates approximate assembly-language equivalent of your code. +# Useful for debugging time-sensitive bits, +# or making sure the compiler does what you want. +disassemble: $(TARGET).lst + +dis: disassemble +lst: disassemble + +eeprom: $(TARGET).eeprom + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Optionally show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +squeaky_clean: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +##########------------------------------------------------------########## +########## Programmer-specific details ########## +########## Flashing code to AVR using avrdude ########## +##########------------------------------------------------------########## + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flash_eeprom: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +terminal: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + + +flash_arduino: PROGRAMMER_TYPE = arduino +flash_arduino: PROGRAMMER_ARGS = +flash_arduino: flash + +flash_dragon_isp: PROGRAMMER_TYPE = dragon_isp +flash_dragon_isp: PROGRAMMER_ARGS = +flash_dragon_isp: flash + + +##########------------------------------------------------------########## +########## Fuse settings and suitable defaults ########## +##########------------------------------------------------------########## + +## Generic +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +## Called with no extra definitions, sets to defaults +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/lcdsnake/README.md b/devel/lcdsnake/README.md new file mode 100644 index 0000000..10be780 --- /dev/null +++ b/devel/lcdsnake/README.md @@ -0,0 +1,10 @@ +Snake for HD44780 +================= + +This is a Snake game (known from old Nokia phones) played on a character display with HD44780. + +Program tested on Arduino Pro Mini (flashed with avrdude using the Makefile). + +**Connections** are `#define`d in `main.c`, board size and snake speed can also be adjusted. No external parts except the display and buttons required. + +Best works with a gamepad, but any buttons will work. diff --git a/devel/lcdsnake/debo_config.h b/devel/lcdsnake/debo_config.h new file mode 100644 index 0000000..3b06634 --- /dev/null +++ b/devel/lcdsnake/debo_config.h @@ -0,0 +1,5 @@ +#pragma once + +// Config file for debouncer +#define DEBO_CHANNELS 6 +#define DEBO_TICKS 1 diff --git a/devel/lcdsnake/lcd_config.h b/devel/lcdsnake/lcd_config.h new file mode 100644 index 0000000..82e8a80 --- /dev/null +++ b/devel/lcdsnake/lcd_config.h @@ -0,0 +1,13 @@ +#pragma once + +// 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 diff --git a/devel/lcdsnake/lib b/devel/lcdsnake/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/lcdsnake/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/lcdsnake/main.c b/devel/lcdsnake/main.c new file mode 100644 index 0000000..85114a3 --- /dev/null +++ b/devel/lcdsnake/main.c @@ -0,0 +1,429 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lib/meta.h" +#include "lib/arduino_pins.h" +#include "lib/calc.h" +#include "lib/adc.h" +#include "lib/lcd.h" +#include "lib/debounce.h" + +// Buttons (to ground) +#define BTN_LEFT A0 +#define BTN_RIGHT A1 +#define BTN_UP A2 +#define BTN_DOWN A3 +#define BTN_PAUSE A4 +#define BTN_RESTART A5 + +// Debouncer channels for buttons +// (Must be added in this order to debouncer) +#define D_LEFT 0 +#define D_RIGHT 1 +#define D_UP 2 +#define D_DOWN 3 +#define D_PAUSE 4 +#define D_RESTART 5 + +// Board size (!!! rows = 2x number of display lines, max 2*4 = 8 !!!) +#define ROWS 8 +#define COLS 20 + +// Delay between snake steps, in 10 ms +#define STEP_DELAY 24 + +// proto +void update(); +void init_cgram(); +void init_gameboard(); + +void init() +{ + // Randomize RNG + adc_init(); + srand(adc_read_word(3)); + + // Init LCD + lcd_init(); + init_cgram(); // load default glyphs + + // Init game board. + init_gameboard(); + + // gamepad buttons + as_input_pu(BTN_LEFT); + as_input_pu(BTN_RIGHT); + as_input_pu(BTN_UP); + as_input_pu(BTN_DOWN); + as_input_pu(BTN_PAUSE); + as_input_pu(BTN_RESTART); + + // add buttons to debouncer + debo_add_rev(BTN_LEFT); + debo_add_rev(BTN_RIGHT); + debo_add_rev(BTN_UP); + debo_add_rev(BTN_DOWN); + debo_add_rev(BTN_PAUSE); + debo_add_rev(BTN_RESTART); + + // setup timer + TCCR0A = _BV(WGM01); // CTC + TCCR0B = _BV(CS02) | _BV(CS00); // prescaler 1024 + OCR0A = 156; // interrupt every 10 ms + sbi(TIMSK0, OCIE0A); + sei(); +} + + +/** timer 0 interrupt vector */ +ISR(TIMER0_COMPA_vect) +{ + debo_tick(); // poll debouncer + update(); // update and display +} + + + +// sub-glyphs +#define _HEAD_ 15, 21, 21, 30 +#define _BODY_ 15, 31, 31, 30 +#define _FOOD_ 10, 21, 17, 14 +//14, 17, 17, 14 +#define _NONE_ 0, 0, 0, 0 + +// complete glyphs for loading into memory + +// Only one food & one head glyph have to be loaded at a time. + +// Body - Body +const uint8_t SYMBOL_BB[] PROGMEM = {_BODY_, _BODY_}; + +// Body - None +const uint8_t SYMBOL_BX[] PROGMEM = {_BODY_, _NONE_}; +const uint8_t SYMBOL_XB[] PROGMEM = {_NONE_, _BODY_}; + +// Head - None +const uint8_t SYMBOL_HX[] PROGMEM = {_HEAD_, _NONE_}; +const uint8_t SYMBOL_XH[] PROGMEM = {_NONE_, _HEAD_}; + +// Body - Head +const uint8_t SYMBOL_BH[] PROGMEM = {_BODY_, _HEAD_}; +const uint8_t SYMBOL_HB[] PROGMEM = {_HEAD_, _BODY_}; + +// Head - Food +const uint8_t SYMBOL_HF[] PROGMEM = {_HEAD_, _FOOD_}; +const uint8_t SYMBOL_FH[] PROGMEM = {_FOOD_, _HEAD_}; + +// Food - None +const uint8_t SYMBOL_FX[] PROGMEM = {_FOOD_, _NONE_}; +const uint8_t SYMBOL_XF[] PROGMEM = {_NONE_, _FOOD_}; + +// Body - Food +const uint8_t SYMBOL_BF[] PROGMEM = {_BODY_, _FOOD_}; +const uint8_t SYMBOL_FB[] PROGMEM = {_FOOD_, _BODY_}; + + +// board block (snake, food...) +typedef enum { + bEMPTY = 0x00, + bHEAD = 0x01, + bFOOD = 0x02, + bBODY_LEFT = 0x80, + bBODY_RIGHT = 0x81, + bBODY_UP = 0x82, + bBODY_DOWN = 0x83, +} block_t; + +// Snake direction +typedef enum { + dLEFT = 0x00, + dRIGHT = 0x01, + dUP = 0x02, + dDOWN = 0x03, +} dir_t; + +// Coordinate on board +typedef struct { + int8_t x; + int8_t y; +} coord_t; + +#define is_body(blk) (((blk) & 0x80) != 0) +#define mk_body_dir(dir) (0x80 + (dir)) + +// compare two coords +#define coord_eq(a, b) (((a).x == (b).x) && ((a).y == (b).y)) + + +bool crashed; +uint8_t snake_len; + +// y, x indexing +block_t board[ROWS][COLS]; + +coord_t head_pos; +coord_t tail_pos; +dir_t head_dir; + +const uint8_t CODE_BB = 0; +const uint8_t CODE_BX = 1; +const uint8_t CODE_XB = 2; +const uint8_t CODE_H = 3; // glyph with head, dynamic +const uint8_t CODE_F = 4; // glyph with food, dynamic +const uint8_t CODE_XX = 32; // space + + +// Set a block in board +#define set_block_xy(x, y, block) do { board[y][x] = (block); } while(0) +#define get_block_xy(x, y) board[y][x] +#define get_block(pos) get_block_xy((pos).x, (pos).y) +#define set_block(pos, block) set_block_xy((pos).x, (pos).y, (block)) + + +void init_cgram() +{ + // those will be always the same + lcd_glyph_P(CODE_BB, SYMBOL_BB); + lcd_glyph_P(CODE_BX, SYMBOL_BX); + lcd_glyph_P(CODE_XB, SYMBOL_XB); + lcd_glyph_P(5, SYMBOL_XF); +} + + +void place_food() +{ + while(1) { + const uint8_t xx = rand() % COLS; + const uint8_t yy = rand() % ROWS; + + if (get_block_xy(xx, yy) == bEMPTY) { + set_block_xy(xx, yy, bFOOD); + break; + } + } +} + + +void init_gameboard() +{ + //erase the board + for (uint8_t x = 0; x < COLS; x++) { + for (uint8_t y = 0; y < ROWS; y++) { + set_block_xy(x, y, bEMPTY); + } + } + + lcd_clear(); + + tail_pos = (coord_t) {.x = 0, .y = 0}; + + set_block_xy(0, 0, bBODY_RIGHT); + set_block_xy(1, 0, bBODY_RIGHT); + set_block_xy(2, 0, bBODY_RIGHT); + set_block_xy(3, 0, bHEAD); + + head_pos = (coord_t) {.x = 3, .y = 0}; + + snake_len = 4; // includes head + + head_dir = dRIGHT; + crashed = false; + + place_food(); +} + + +uint8_t presc = 0; + +bool restart_held; +bool pause_held; +bool paused; +void update() +{ + if (debo_get_pin(D_RESTART)) { + + if (!restart_held) { + // restart + init_gameboard(); + presc = 0; + restart_held = true; + } + + } else { + restart_held = false; + } + + if (debo_get_pin(D_PAUSE)) { + + if (!pause_held) { + paused ^= true; + pause_held = true; + } + + } else { + pause_held = false; + } + + if(!crashed && !paused) { + + // resolve movement direction + if (debo_get_pin(D_LEFT)) + head_dir = dLEFT; + else if (debo_get_pin(D_RIGHT)) + head_dir = dRIGHT; + else if (debo_get_pin(D_UP)) + head_dir = dUP; + else if (debo_get_pin(D_DOWN)) + head_dir = dDOWN; + + // time's up for a move + if (presc++ == STEP_DELAY) { + presc = 0; + + // move snake + const coord_t oldpos = head_pos; + + switch (head_dir) { + case dLEFT: head_pos.x--; break; + case dRIGHT: head_pos.x++; break; + case dUP: head_pos.y--; break; + case dDOWN: head_pos.y++; break; + } + + bool do_move = false; + bool do_grow = false; + + if (head_pos.x < 0 || head_pos.x >= COLS || head_pos.y < 0 || head_pos.y >= ROWS) { + // ouch, a wall! + crashed = true; + } else { + // check if tile occupied or not + if (coord_eq(head_pos, tail_pos)) { + // head moved in previous tail, that's OK. + do_move = true; + } else { + // moved to other tile than tail + switch (get_block(head_pos)) { + + case bFOOD: + do_grow = true; // fall through + case bEMPTY: + do_move = true; + break; + + default: // includes all BODY_xxx + crashed = true; // snake crashed into some block + } + } + } + + if (do_move) { + // Move tail + if (do_grow) { + // let tail as is + snake_len++; // grow the counter + } else { + // tail dir + dir_t td = get_block(tail_pos) & 0xF; + + // clean tail + set_block(tail_pos, bEMPTY); + + // move tail based on old direction of tail block + switch (td) { + case dLEFT: tail_pos.x--; break; + case dRIGHT: tail_pos.x++; break; + case dUP: tail_pos.y--; break; + case dDOWN: tail_pos.y++; break; + } + } + + // Move head + set_block(head_pos, bHEAD); // place head in new pos + set_block(oldpos, mk_body_dir(head_dir)); // directional body in old head pos + + if (do_grow) { + // food eaten, place new + place_food(); + } + } + } + } // end !crashed + + + // Render the board + for (uint8_t r = 0; r < ROWS / 2; r++) { + lcd_xy(0, r); + for (uint8_t c = 0; c < COLS; c++) { + const block_t t1 = get_block_xy(c, r * 2); + const block_t t2 = get_block_xy(c, (r * 2) + 1); + + uint8_t code = '!'; // ! marks fail + + if ((t1 == bEMPTY) && (t2 == bEMPTY)) { + code = CODE_XX; + if (crashed) code = '*'; + } else if (is_body(t1) && is_body(t2)) + code = CODE_BB; + else if (is_body(t1) && (t2 == bEMPTY)) + code = CODE_BX; + else if (t1 == bEMPTY && is_body(t2)) + code = CODE_XB; + else if ((t1 == bFOOD) || (t2 == bFOOD)) { + // one is food + + code = CODE_F; + + if (t1 == bFOOD) { + if (t2 == bEMPTY) + lcd_glyph_P(code, SYMBOL_FX); + else if (t2 == bHEAD) + lcd_glyph_P(code, SYMBOL_FH); + else if (is_body(t2)) + lcd_glyph_P(code, SYMBOL_FB); + } else { // t2 is food + if (t1 == bEMPTY) + lcd_glyph_P(code, SYMBOL_XF); + else if (t1 == bHEAD) + lcd_glyph_P(code, SYMBOL_HF); + else if (is_body(t1)) + lcd_glyph_P(code, SYMBOL_BF); + } + lcd_xy(c,r); + + } else if ((t1 == bHEAD )|| (t2 == bHEAD)) { + // one is head + + code = CODE_H; + + if (t1 == bHEAD) { + if (t2 == bEMPTY) + lcd_glyph_P(code, SYMBOL_HX); + else if (is_body(t2)) + lcd_glyph_P(code, SYMBOL_HB); + } else { // t2 is head + if (t1 == bEMPTY) + lcd_glyph_P(code, SYMBOL_XH); + else if (is_body(t1)) + lcd_glyph_P(code, SYMBOL_BH); + } + + lcd_xy(c,r); + } + + lcd_putc(code); + } + } +} + +void main() +{ + init(); + + while(1); // timer does everything +} diff --git a/devel/onewire/Makefile b/devel/onewire/Makefile new file mode 100644 index 0000000..fb45811 --- /dev/null +++ b/devel/onewire/Makefile @@ -0,0 +1,141 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === 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/ +# C files in the library directory +EXTRA_SOURCE_FILES = uart.c iopins.c stream.c onewire.c + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +fser: all flash ser + +ser: + gtkterm -p /dev/ttyUSB0 + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/onewire/lib b/devel/onewire/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/onewire/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/onewire/main.c b/devel/onewire/main.c new file mode 100644 index 0000000..a678e44 --- /dev/null +++ b/devel/onewire/main.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/iopins.h" +#include "lib/uart.h" +#include "lib/stream.h" +#include "lib/onewire.h" + +void main() +{ + uart_init(9600); + uart_puts_P(PSTR("*** OneWire test ***\r\n")); + + while(1) + { + _delay_ms(100); + + if (ds1820_single_measure(2)) + { + int16_t temp = ds1820_read_temp_c(2); + + if (temp == TEMP_ERROR) { + // Checksum mismatch + uart_puts_P(PSTR("Corrupt data!\r\n")); + } else { + put_i16f(uart, temp, 1); + uart_puts_P(PSTR(" °C\r\n")); + } + + } else { + uart_puts_P(PSTR("Device not connected!\r\n")); + } + } +} diff --git a/devel/rgb_hsl/Makefile b/devel/rgb_hsl/Makefile new file mode 100644 index 0000000..820f029 --- /dev/null +++ b/devel/rgb_hsl/Makefile @@ -0,0 +1,170 @@ + +MCU = atmega328p + +F_CPU = 16000000 + +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + +MAIN = main.c + +## If you've split your program into multiple files, +## include the additional .c source (in same directory) here +## (and include the .h files in your foo.c) +LOCAL_SOURCE = + +## Here you can link to one more directory (and multiple .c files) +# EXTRA_SOURCE_DIR = ../AVR-Programming-Library/ +EXTRA_SOURCE_DIR = lib/ +EXTRA_SOURCE_FILES = adc.c hsl.c + +EXTRA_FLAGS = +#-DHSL_LINEAR=1 + + + +##########------------------------------------------------------########## +########## Programmer Defaults ########## +########## Set up once, then forget about it ########## +########## (Can override. See bottom of file.) ########## +##########------------------------------------------------------########## +#19200 +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +##########------------------------------------------------------########## +########## Makefile Magic! ########## +########## Summary: ########## +########## We want a .hex file ########## +########## Compile source files into .elf ########## +########## Convert .elf file into .hex ########## +########## You shouldn't need to edit below. ########## +##########------------------------------------------------------########## + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## Compilation options, type man avr-gcc if you're curious. +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 -pedantic -Wfatal-errors +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax +CFLAGS += $(EXTRA_FLAGS) + +CFLAGS_BUILD = $(CFLAGS) -Os + +# CFLAGS += -lm +## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf +## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf + +## Lump target and extra source files together +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +## List of all header files +HEADERS = $(SRC:.c=.h) + +## For every .c file, compile an .o object file +OBJ = $(SRC:.c=.o) + +## Generic Makefile targets. (Only .hex file is necessary) +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + +# Optionally create listing file from .elf +# This creates approximate assembly-language equivalent of your code. +# Useful for debugging time-sensitive bits, +# or making sure the compiler does what you want. +disassemble: $(TARGET).lst + +dis: disassemble +lst: disassemble + +eeprom: $(TARGET).eeprom + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Optionally show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +squeaky_clean: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +##########------------------------------------------------------########## +########## Programmer-specific details ########## +########## Flashing code to AVR using avrdude ########## +##########------------------------------------------------------########## + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flash_eeprom: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +terminal: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + + +flash_arduino: PROGRAMMER_TYPE = arduino +flash_arduino: PROGRAMMER_ARGS = +flash_arduino: flash + +flash_dragon_isp: PROGRAMMER_TYPE = dragon_isp +flash_dragon_isp: PROGRAMMER_ARGS = +flash_dragon_isp: flash + + +##########------------------------------------------------------########## +########## Fuse settings and suitable defaults ########## +##########------------------------------------------------------########## + +## Generic +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +## Called with no extra definitions, sets to defaults +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/rgb_hsl/README.md b/devel/rgb_hsl/README.md new file mode 100644 index 0000000..c4480bd --- /dev/null +++ b/devel/rgb_hsl/README.md @@ -0,0 +1,11 @@ +Random color flasher, with fading. + +Color is atm restricted to hues of blue-cyan. + +Works with a 4x4 zigzag screen + +0->1->2->3 +7<-6<-5<-4 +8->... + +(But will work with any screen since there's no pattern to be preserved) diff --git a/devel/rgb_hsl/lib b/devel/rgb_hsl/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/rgb_hsl/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/rgb_hsl/main.c b/devel/rgb_hsl/main.c new file mode 100644 index 0000000..6f7bc78 --- /dev/null +++ b/devel/rgb_hsl/main.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +#include "lib/meta.h" +#include "lib/arduino_pins.h" +#include "lib/calc.h" + +#include "lib/colors.h" +#include "lib/hsl.h" +#include "lib/adc.h" + +#define WS_T_1H 650 +#define WS_T_1L 200 +#define WS_T_0H 120 +#define WS_T_0L 650 + +#include "lib/ws_rgb.h" + +#define WS1 D2 + +void SECTION(".init8") init() +{ + adc_init(); + srand(adc_read_word(0)); + + as_output(WS1); +} + + +void main() +{ + #define WIDTH 4 + #define HEIGHT 4 + #define SIZE (WIDTH*HEIGHT) + hsl_t board[SIZE]; + xrgb_t screen[SIZE]; + + for (uint8_t i = 0; i < SIZE; i++) { + board[i] = (hsl_t) {.h=0, .s=255, .l=0}; + screen[i] = (xrgb_t) {.r=0, .g=0, .b=0}; + } + + while(1) { + for(uint8_t i = 0; i < SIZE; i++) { + if (board[i].l > 0) { + board[i].l--; + } + + screen[i] = hsl2xrgb(board[i]); + } + + if (rand() % 4 == 0) { + uint8_t i = rand() % SIZE; + + if (board[i].l == 0) { + board[i].h = 125 + rand() % 57; + board[i].s = 200 + rand() % 56; + board[i].l = 150 + rand() % 106; + } + } + + //ws_send_xrgb_array_zigzag_linear(WS1, screen, 4, 4); + ws_send_xrgb_array_zigzag_linear(WS1, screen, 4, 4); + _delay_ms(10); + } +} diff --git a/devel/sd_bad/Makefile b/devel/sd_bad/Makefile new file mode 100644 index 0000000..6ed6ce1 --- /dev/null +++ b/devel/sd_bad/Makefile @@ -0,0 +1,147 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === 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/ + + +# C files in the library directory +EXTRA_SOURCE_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c +#Files that need config file: +# EXTRA_SOURCE_FILES += lcd.c +# EXTRA_SOURCE_FILES += color.c wsrgb.c +# EXTRA_SOURCE_FILES += debouce.c + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +fser: all flash ser + +ser: + gtkterm -p /dev/ttyUSB0 + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/sd_bad/deployment.pri b/devel/sd_bad/deployment.pri new file mode 100644 index 0000000..5f1749f --- /dev/null +++ b/devel/sd_bad/deployment.pri @@ -0,0 +1,191 @@ +# This file was generated by an application wizard of Qt Creator. +# The code below handles deployment to Android and Maemo, aswell as copying +# of the application data to shadow build directories on desktop. +# It is recommended not to modify this file, since newer versions of Qt Creator +# may offer an updated version of it. + +defineTest(qtcAddDeployment) { +for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + greaterThan(QT_MAJOR_VERSION, 4) { + itemsources = $${item}.files + } else { + itemsources = $${item}.sources + } + $$itemsources = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath= $$eval($${deploymentfolder}.target) + export($$itemsources) + export($$itempath) + DEPLOYMENT += $$item +} + +MAINPROFILEPWD = $$PWD + +android-no-sdk { + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = /data/user/qt/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + target.path = /data/user/qt + + export(target.path) + INSTALLS += target +} else:android { + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = /assets/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + x86 { + target.path = /libs/x86 + } else: armeabi-v7a { + target.path = /libs/armeabi-v7a + } else { + target.path = /libs/armeabi + } + + export(target.path) + INSTALLS += target +} else:win32 { + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, /, \\) + sourcePathSegments = $$split(source, \\) + target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments) + target = $$replace(target, /, \\) + target ~= s,\\\\\\.?\\\\,\\, + !isEqual(source,$$target) { + !isEmpty(copyCommand):copyCommand += && + isEqual(QMAKE_DIR_SEP, \\) { + copyCommand += $(COPY_DIR) \"$$source\" \"$$target\" + } else { + source = $$replace(source, \\\\, /) + target = $$OUT_PWD/$$eval($${deploymentfolder}.target) + target = $$replace(target, \\\\, /) + copyCommand += test -d \"$$target\" || mkdir -p \"$$target\" && cp -r \"$$source\" \"$$target\" + } + } + } + !isEmpty(copyCommand) { + copyCommand = @echo Copying application data... && $$copyCommand + copydeploymentfolders.commands = $$copyCommand + first.depends = $(first) copydeploymentfolders + export(first.depends) + export(copydeploymentfolders.commands) + QMAKE_EXTRA_TARGETS += first copydeploymentfolders + } +} else:ios { + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, \\\\, /) + target = $CODESIGNING_FOLDER_PATH/$$eval($${deploymentfolder}.target) + target = $$replace(target, \\\\, /) + sourcePathSegments = $$split(source, /) + targetFullPath = $$target/$$last(sourcePathSegments) + targetFullPath ~= s,/\\.?/,/, + !isEqual(source,$$targetFullPath) { + !isEmpty(copyCommand):copyCommand += && + copyCommand += mkdir -p \"$$target\" + copyCommand += && cp -r \"$$source\" \"$$target\" + } + } + !isEmpty(copyCommand) { + copyCommand = echo Copying application data... && $$copyCommand + !isEmpty(QMAKE_POST_LINK): QMAKE_POST_LINK += ";" + QMAKE_POST_LINK += "$$copyCommand" + export(QMAKE_POST_LINK) + } +} else:unix { + maemo5 { + desktopfile.files = $${TARGET}.desktop + desktopfile.path = /usr/share/applications/hildon + icon.files = $${TARGET}64.png + icon.path = /usr/share/icons/hicolor/64x64/apps + } else:!isEmpty(MEEGO_VERSION_MAJOR) { + desktopfile.files = $${TARGET}_harmattan.desktop + desktopfile.path = /usr/share/applications + icon.files = $${TARGET}80.png + icon.path = /usr/share/icons/hicolor/80x80/apps + } else { # Assumed to be a Desktop Unix + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, \\\\, /) + macx { + target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target) + } else { + target = $$OUT_PWD/$$eval($${deploymentfolder}.target) + } + target = $$replace(target, \\\\, /) + sourcePathSegments = $$split(source, /) + targetFullPath = $$target/$$last(sourcePathSegments) + targetFullPath ~= s,/\\.?/,/, + !isEqual(source,$$targetFullPath) { + !isEmpty(copyCommand):copyCommand += && + copyCommand += $(MKDIR) \"$$target\" + copyCommand += && $(COPY_DIR) \"$$source\" \"$$target\" + } + } + !isEmpty(copyCommand) { + copyCommand = @echo Copying application data... && $$copyCommand + copydeploymentfolders.commands = $$copyCommand + first.depends = $(first) copydeploymentfolders + export(first.depends) + export(copydeploymentfolders.commands) + QMAKE_EXTRA_TARGETS += first copydeploymentfolders + } + } + !isEmpty(target.path) { + installPrefix = $${target.path} + } else { + installPrefix = /opt/$${TARGET} + } + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + !isEmpty(desktopfile.path) { + export(icon.files) + export(icon.path) + export(desktopfile.files) + export(desktopfile.path) + INSTALLS += icon desktopfile + } + + isEmpty(target.path) { + target.path = $${installPrefix}/bin + export(target.path) + } + INSTALLS += target +} + +export (ICON) +export (INSTALLS) +export (DEPLOYMENT) +export (LIBS) +export (QMAKE_EXTRA_TARGETS) +} + diff --git a/devel/sd_bad/main.c b/devel/sd_bad/main.c new file mode 100644 index 0000000..69f92b5 --- /dev/null +++ b/devel/sd_bad/main.c @@ -0,0 +1,57 @@ +#include "main.h" +#include "sd.h" +#include "spi.h" + +static uint8_t sd_buffer[512]; +static sd_context_t sdc; + +void main(void) +{ + int j, ok; + ok = 0; + + /* Stop the watchdog timer */ + WDTCTL = WDTPW | WDTHOLD; + + /* Set some reasonable values for the timeouts. + */ + sdc.timeout_write = PERIPH_CLOCKRATE / 8; + sdc.timeout_read = PERIPH_CLOCKRATE / 20; + + sdc.busyflag = 0; + for (j = 0; j < SD_INIT_TRY && ok != 1; j++) + { + ok = do_sd_initialize(&sdc); + } + + /* Read in the first block on the SD Card */ + if (ok == 1) + { + sd_read_block(&sdc, 0, sd_buffer); + sd_wait_notbusy(&sdc); + } + + /* Wait forever */ + while (1) { } +} + + +int do_sd_initialize(sd_context_t *sdc) +{ + /* Initialize the SPI controller */ + spi_initialize(); + + /* Start out with a slow SPI clock, 400kHz, as required + by the SD spec + (for MMC compatibility). */ + spi_set_divisor(PERIPH_CLOCKRATE / 400000); + + /* Initialization OK? */ + if (sd_initialize(sdc) != 1) + return 0; + + /* Set the maximum SPI clock rate possible */ + spi_set_divisor(2); + + return 1; +} diff --git a/devel/sd_bad/main.h b/devel/sd_bad/main.h new file mode 100644 index 0000000..b0e53a6 --- /dev/null +++ b/devel/sd_bad/main.h @@ -0,0 +1,10 @@ +#ifndef MAIN_H +#define MAIN_H + +#include "sdcomm_spi.h" + +/* Peripheral clock rate, in Hz, used for timing. */ +#define PERIPH_CLOCKRATE 8000000 +int do_sd_initialize(sd_context_t *sdc); + +#endif diff --git a/devel/sd_bad/sd.c b/devel/sd_bad/sd.c new file mode 100644 index 0000000..ef364ce --- /dev/null +++ b/devel/sd_bad/sd.c @@ -0,0 +1,467 @@ +#include "main.h" +#include "sd.h" +#include "sdcomm_spi.h" +#include "spi.h" + +static uint8_t response[5]; +static uint8_t argument[4]; + +int sd_card_present() +{ + return (!(P3IN & 0x01)); +} + +/* This function initializes the SD card. It returns 1 if + initialization was successful, 0 otherwise. + + sd_context_t *sdc -- pointer to a data structure containing + information about the card. For now, the + timeouts MUST be specified in advance. This + function does not yet calculate them from the + card data. +*/ + +int sd_initialize(sd_context_t *sdc) +{ + char i, j; + /* SPI SD initialization sequence: + * CMD0 + * CMD55 + * ACMD41 + * CMD58 + * (Note there is no CMD2 or CMD3 in SPI mode. These + * instructions are devoted to addressing on the SD bus.) + * + * SD memory card SD initialization sequence: + * CMD0 + * CMD55 + * ACMD41 + * CMD2 + * CMD3 + */ + sdc->busyflag = 0; + for (i = 0; i < 4; i++) + argument[i] = 0; + + /* Delay for at least 74 clock cycles. This means to actually + * *clock* out at least 74 clock cycles with no data present on + * the clock. In SPI mode, send at least 10 idle bytes (0xFF). */ + + spi_cs_assert(); + sd_delay(100); + spi_cs_deassert(); + sd_delay(2); + + /* Put the card in the idle state */ + if (sd_send_command(sdc, CMD0, CMD0_R, response, argument) == 0) + return 0; + + /* Now wait until the card goes idle. Retry at most SD_IDLE_WAIT_MAX + times */ + + j = 0; + do + { + j++; + /* Flag the next command as an application-specific command */ + if (sd_send_command(sdc, CMD55, CMD55_R, response, argument) == 1) + { + /* Tell the card to send its OCR */ + sd_send_command(sdc, ACMD41, ACMD41_R, response, argument); + } + else + { + /* No response, bail early */ + j = SD_IDLE_WAIT_MAX; + } + } + while ((response[0] & MSK_IDLE) == MSK_IDLE && j < SD_IDLE_WAIT_MAX); + + /* As long as we didn’t hit the timeout, assume we’re OK. */ + if (j >= SD_IDLE_WAIT_MAX) + return 0; + + if (sd_send_command(sdc, CMD58, CMD58_R, response, argument) == 0) + return 0; + + /* At a very minimum, we must allow 3.3V. */ + if ((response[2] & MSK_OCR_33) != MSK_OCR_33) + return 0; + + /* Set the block length */ + if (sd_set_blocklen(sdc, SD_BLOCKSIZE) != 1) + return 0; + + /* If we got this far, initialization was OK. + */ + return 1; +} + +/* + This function reads a single block from the SD card at block + blockaddr. The buffer must be preallocated. Returns 1 if the + command was successful, zero otherwise. + + This is an ASYNCHRONOUS call. + + The transfer will not be complete when the function returns. + If you want to explicitly wait until any pending transfers are + finished, use the command sd_wait_notbusy(sdc). + + sd_context_t *sdc + -- a pointer to an sd device context structure, + populated by the function sd_initialize() + + u32 blockaddr + -- The block address to read from the card. + This is a block address, not a linear address. + + uint8_t *data + -- The data, a pointer to an array of uint8_ts. +*/ + +int sd_read_block(sd_context_t *sdc, uint32_t blockaddr, + uint8_t *data) +{ + unsigned long int i = 0; + uint8_t tmp; + uint8_t blank = 0xFF; + + /* Adjust the block address to a linear address */ + blockaddr <<= SD_BLOCKSIZE_NBITS; + + /* Wait until any old transfers are finished */ + sd_wait_notbusy(sdc); + + /* Pack the address */ + sd_packarg(argument, blockaddr); + + /* Need to add size checking */ + if (sd_send_command(sdc, CMD17, CMD17_R, response, argument) == 0) + return 0; + + /* Check for an error, like a misaligned read */ + if (response[0] != 0) + return 0; + + /* Re-assert CS to continue the transfer */ + spi_cs_assert(); + + /* Wait for the token */ + i = 0; + do + { + tmp = spi_rcv_byte(); + i++; + } + while ((tmp == 0xFF) && i < sdc->timeout_read); + + if ((tmp & MSK_TOK_DATAERROR) == 0) + { + /* Clock out a byte before returning */ + spi_send_byte(0xFF); + + /* The card returned an error response. Bail and return 0 */ + return 0; + } + + /* Prime the interrupt flags so things happen in the correct order. */ + IFG1 &= ~URXIFG0; + IFG1 &= ~UTXIFG0; + + /* Get the block */ + /* Source DMA address: receive register. */ + DMA0SA = U0RXBUF_; + + /* Destination DMA address: the user data buffer. */ + DMA0DA = (unsigned short) data; + + /* The size of the block to be transferred */ + DMA0SZ = SD_BLOCKSIZE; + + /* Configure the DMA transfer*/ + DMA0CTL = + DMADT_0 | /* Single transfer mode */ + DMASBDB | /* Byte mode */ + DMAEN | /* Enable DMA */ + DMADSTINCR1 | DMADSTINCR0; /* Increment the destination address */ + + /* We depend on the DMA priorities here. Both triggers occur at + the same time, since the source is identical. DMA0 is handled + first, and retrieves the byte. DMA1 is triggered next, and + sends the next byte. */ + + /* Source DMA address: constant 0xFF (don’t increment)*/ + DMA1SA = (unsigned short) ␣ + + /* Destination DMA address: the transmit buffer. */ + DMA1DA = U0TXBUF_; + + /* Increment the destination address */ + /* The size of the block to be transferred */ + DMA1SZ = SD_BLOCKSIZE - 1; + + /* Configure the DMA transfer*/ + DMA1CTL = + DMADT_0 | /* Single transfer mode */ + DMASBDB | /* Byte mode */ + DMAEN; /* Enable DMA */ + + /* DMA trigger is UART receive for both DMA0 and DMA1 */ + DMACTL0 = DMA0TSEL_3 | DMA1TSEL_3; + + /* Kick off the transfer by sending the first byte */ + U0TXBUF = 0xFF; + + return 1; +} + + +/* + This function writes a single block to the SD card at block + blockaddr. Returns 1 if the command was successful, zero + otherwise. + + This is an ASYNCHRONOUS call. The transfer will not be complete + when the function returns. If you want to explicitly wait until + any pending transfers are finished, use the command + sd_wait_notbusy(sdc). + + sd_context_t *sdc + -- a pointer to an sd device context structure, + populated by the function sd_initialize() + + u32 blockaddr + -- The block address to read from the card. + This is a block address, not a linear address. + + uint8_t *data + -- The data, a pointer to an array of unsigned + chars. +*/ +int sd_write_block(sd_context_t *sdc, uint32_t blockaddr, + uint8_t *data) +{ + /* Adjust the block address to a linear address */ + blockaddr <<= SD_BLOCKSIZE_NBITS; + + /* Wait until any old transfers are finished */ + sd_wait_notbusy(sdc); + + /* Pack the address */ + sd_packarg(argument, blockaddr); + + if (sd_send_command(sdc, CMD24, CMD24_R, response, argument) == 0) + return 0; + + /* Check for an error, like a misaligned write */ + if (response[0] != 0) + return 0; + + /* Re-assert CS to continue the transfer */ + spi_cs_assert(); + + /* The write command needs an additional 8 clock cycles before + * the block write is started. */ + spi_rcv_byte(); + + /* Clear any pending flags */ + IFG1 &= ~(URXIFG0 | UTXIFG0); + + /* Get the block */ + /* Source DMA address: the data buffer. */ + DMA0SA = (unsigned short)data; + + /* Destination DMA address: the UART send register. */ + DMA0DA = U0TXBUF_; + + /* The size of the block to be transferred */ + DMA0SZ = SD_BLOCKSIZE; + + /* Configure the DMA transfer*/ + DMA0CTL = + DMADT_0 | /* Single transfer mode */ + DMASBDB | /* Byte mode */ + DMAEN | /* Enable DMA */ + DMASRCINCR1 | DMASRCINCR0; /* Increment the source address */ + + /* DMA trigger is UART send */ + DMACTL0 = DMA0TSEL_3; + + /* Kick off the transfer by sending the first byte, the "start block" + * token */ + U0TXBUF = SD_TOK_WRITE_STARTBLOCK; + + /* Signal that the card may be busy, so any subsequent commands + should wait for the busy signalling to end (indicated by a + nonzero response). */ + sdc->busyflag = 1; + + return 1; +} + +/* + This function synchronously waits until any pending block transfers + are finished. If your program needs to ensure a block has finished + transferring, call this function. + + Note that sd_read_block() and sd_write_block() already call this + function internally before attempting a new transfer, so there are + only two times when a user would need to use this function. + + 1) When the processor will be shutting down. All pending + writes should be finished first. + + 2) When the user needs the results of an sd_read_block() call + right away. +*/ +void sd_wait_notbusy(sd_context_t *sdc) +{ + /* Just twiddle our thumbs until the transfer’s done */ + while ((DMA0CTL & DMAEN) != 0) { } + + /* Reset the DMA controller */ + DMACTL0 = 0; + + /* Ignore the checksum */ + sd_delay(4); + + /* Check for the busy flag (set on a write block) */ + if (sdc->busyflag == 1) + { + while (spi_rcv_byte() != 0xFF); + } + + sdc->busyflag = 0; + + /* Deassert CS */ + spi_cs_deassert(); + + /* Send some extra clocks so the card can resynchronize on the next + transfer */ + + sd_delay(2); +} + + +void sd_packarg(uint8_t *argument, uint32_t value) +{ + argument[3] = (uint8_t)(value >> 24); + argument[2] = (uint8_t)(value >> 16); + argument[1] = (uint8_t)(value >> 8); + argument[0] = (uint8_t)(value); +} + +int sd_send_command(sd_context_t *sdc, + uint8_t cmd, uint8_t response_type, + uint8_t *response, uint8_t *argument) +{ + int i; + char response_length; + uint8_t tmp; + spi_cs_assert(); + + /* All data is sent MSB first, and MSb first */ + /* Send the header/command */ + /* Format: + cmd[7:6] : 01 + cmd[5:0] : command */ + spi_send_byte((cmd & 0x3F) | 0x40); + for (i = 3; i >= 0; i--) + { + spi_send_byte(argument[i]); + } + + /* This is the CRC. It only matters what we put here for the first + command. Otherwise, the CRC is ignored for SPI mode unless we + enable CRC checking. */ + spi_send_byte(0x95); + + response_length = 0; + switch (response_type) + { + case R1: + case R1B: + response_length = 1; + break; + case R2: + response_length = 2; + break; + case R3: + response_length = 5; + break; + default: + break; + } + + /* Wait for a response. A response can be recognized by the + start bit (a zero) */ + i = 0; + do + { + tmp = spi_rcv_byte(); + i++; + } + while (((tmp & 0x80) != 0) && i < SD_CMD_TIMEOUT); + + /* Just bail if we never got a response */ + if (i >= SD_CMD_TIMEOUT) + { + spi_cs_deassert(); + return 0; + } + + for (i = response_length - 1; i >= 0; i--) + { + response[i] = tmp; + /* This handles the trailing-byte requirement. */ + tmp = spi_rcv_byte(); + } + + /* If the response is a "busy" type (R1B), then there’s some + * special handling that needs to be done. The card will + * output a continuous stream of zeros, so the end of the BUSY + * state is signaled by any nonzero response. The bus idles + * high. + */ + i = 0; + if (response_type == R1B) + { + do + { + i++; + tmp = spi_rcv_byte(); + } + /* This should never time out, unless SDI is grounded. + * Don’t bother forcing a timeout condition here. */ + while (tmp != 0xFF); + + spi_send_byte(0xFF); + } + + spi_cs_deassert(); + return 1; +} + +void sd_delay(char number) +{ + char i; + + /* Null for now */ + for (i = 0; i < number; i++) + { + /* Clock out an idle byte (0xFF) */ + spi_send_byte(0xFF); + } +} + +/* Set the block length for all future block transactions */ +/* Returns 1 if the function was successful */ +int sd_set_blocklen(sd_context_t *sdc, uint32_t length) +{ + /* Pack the block length */ + sd_packarg(argument, length); + + return (sd_send_command(sdc, CMD16, CMD16_R, response, argument)); +} + diff --git a/devel/sd_bad/sd.h b/devel/sd_bad/sd.h new file mode 100644 index 0000000..d041d32 --- /dev/null +++ b/devel/sd_bad/sd.h @@ -0,0 +1,25 @@ +#ifndef SD_H +#define SD_H + +#include "sdcomm_spi.h" +#include + +#define SD_BLOCKSIZE 512 +#define SD_BLOCKSIZE_NBITS 9 + +/* User functions */ +int sd_card_present(); +int sd_initialize(sd_context_t *sdc); +int sd_read_block(sd_context_t *sdc, uint32_t blockaddr, uint8_t *data); +int sd_write_block(sd_context_t *sdc, uint32_t blockaddr, uint8_t *data); +void sd_wait_notbusy(sd_context_t *sdc); + +/* Internal functions, used for SD card communications. */ +void sd_packarg(uint8_t *argument, uint32_t value); +int sd_set_blocklen(sd_context_t *sdc, uint32_t length); +int sd_send_command(sd_context_t *sdc, + uint8_t cmd, uint8_t response_type, + uint8_t *response, uint8_t *argument); +void sd_delay(char number); + +#endif diff --git a/devel/sd_bad/sd_bad.pro b/devel/sd_bad/sd_bad.pro new file mode 100644 index 0000000..6cc0902 --- /dev/null +++ b/devel/sd_bad/sd_bad.pro @@ -0,0 +1,25 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +INCLUDEPATH += /usr/avr/include + +include(deployment.pri) +qtcAddDeployment() + +DISTFILES += \ + Makefile \ + style.astylerc + +HEADERS += \ + main.h \ + sd.h \ + sdcomm_spi.h \ + spi.h + +SOURCES += \ + main.c \ + sd.c \ + spi.c + diff --git a/devel/sd_bad/sd_bad.pro.user b/devel/sd_bad/sd_bad.pro.user new file mode 100644 index 0000000..1a24635 --- /dev/null +++ b/devel/sd_bad/sd_bad.pro.user @@ -0,0 +1,250 @@ + + + + + + EnvironmentId + {dfe3cb4a-0f3e-4da9-9c52-5d2c464adafb} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + 1 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + 1 + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {ee748544-c6c0-4f44-9cef-fbb65dc2525a} + 0 + 0 + 0 + + /home/ondra/git/avr-projects/devel/sdcard/ + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/ondra/git/avr-projects/devel/sdcard/build-sdcard-Desktop-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + + true + flash + make + %{buildDir} + Custom Process Step + + ProjectExplorer.ProcessStep + + 1 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + 2 + + -p /dev/ttyUSB0 + gtkterm + false + %{buildDir} + Run gtkterm + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + + 2 + + sd_bad + + Qt4ProjectManager.Qt4RunConfiguration:/home/ondra/git/avr-projects/devel/sd_bad/sd_bad.pro + + sd_bad.pro + false + true + + 3768 + false + true + false + false + true + + 2 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/devel/sd_bad/sdcomm_spi.h b/devel/sd_bad/sdcomm_spi.h new file mode 100644 index 0000000..ad13e60 --- /dev/null +++ b/devel/sd_bad/sdcomm_spi.h @@ -0,0 +1,152 @@ +#ifndef SDCOMM_SPI_H +#define SDCOMM_SPI_H + +typedef struct +{ + unsigned long int timeout_write; + unsigned long int timeout_read; + char busyflag; +} sd_context_t; + +#define R1 1 +#define R1B 2 +#define R2 3 +#define R3 4 + +#define MSK_IDLE 0x01 +#define MSK_ERASE_RST 0x02 +#define MSK_ILL_CMD 0x04 +#define MSK_CRC_ERR 0x08 +#define MSK_ERASE_SEQ_ERR 0x10 +#define MSK_ADDR_ERR 0x20 +#define MSK_PARAM_ERR 0x40 +#define SD_TOK_READ_STARTBLOCK 0xFE +#define SD_TOK_WRITE_STARTBLOCK 0xFE +#define SD_TOK_READ_STARTBLOCK_M 0xFE +#define SD_TOK_WRITE_STARTBLOCK_M 0xFC +#define SD_TOK_STOP_MULTI 0xFD + +/* Error token is 111XXXXX */ +#define MSK_TOK_DATAERROR 0xE0 + +/* Bit fields */ +#define MSK_TOK_ERROR 0x01 +#define MSK_TOK_CC_ERROR 0x02 +#define MSK_TOK_ECC_FAILED 0x04 +#define MSK_TOK_CC_OUTOFRANGE 0x08 +#define MSK_TOK_CC_LOCKED 0x10 + +/* Mask off the bits in the OCR corresponding to voltage range 3.2V to +* 3.4V, OCR bits 20 and 21 */ +#define MSK_OCR_33 0xC0 + +/* Number of times to retry the probe cycle during initialization */ +#define SD_INIT_TRY 50 +/* Number of tries to wait for the card to go idle during initialization */ +#define SD_IDLE_WAIT_MAX 100 +/* Hardcoded timeout for commands. 8 words, or 64 clocks. Do 10 +* words instead */ +#define SD_CMD_TIMEOUT 100 + +/******************************** Basic command set **************************/ +/* Reset cards to idle state */ +#define CMD0 0 +#define CMD0_R R1 +/* Read the OCR (MMC mode, do not use for SD cards) */ +#define CMD1 1 +#define CMD1_R R1 +/* Card sends the CSD */ +#define CMD9 9 +#define CMD9_R R1 +/* Card sends CID */ +#define CMD10 10 +#define CMD10_R R1 +/* Stop a multiple block (stream) read/write operation */ +#define CMD12 12 +#define CMD12_R R1B +/* Get the addressed card’s status register */ +#define CMD13 13 +#define CMD13_R R2 + +/***************************** Block read commands **************************/ +/* Set the block length */ +#define CMD16 16 +#define CMD16_R R1 +/* Read a single block */ +#define CMD17 17 +#define CMD17_R R1 +/* Read multiple blocks until a CMD12 */ +#define CMD18 18 +#define CMD18_R R1 + +/***************************** Block write commands *************************/ +/* Write a block of the size selected with CMD16 */ +#define CMD24 24 +#define CMD24_R R1 +/* Multiple block write until a CMD12 */ +#define CMD25 25 +#define CMD25_R R1 +/* Program the programmable bits of the CSD */ +#define CMD27 27 +#define CMD27_R R1 + +/***************************** Write protection *****************************/ +/* Set the write protection bit of the addressed group */ +#define CMD28 28 +#define CMD28_R R1B +/* Clear the write protection bit of the addressed group */ +#define CMD29 29 +#define CMD29_R R1B +/* Ask the card for the status of the write protection bits */ +#define CMD30 30 +#define CMD30_R R1 + +/***************************** Erase commands *******************************/ +/* Set the address of the first write block to be erased */ +#define CMD32 32 +#define CMD32_R R1 +/* Set the address of the last write block to be erased */ +#define CMD33 33 +#define CMD33_R R1 +/* Erase the selected write blocks */ +#define CMD38 38 +#define CMD38_R R1B + +/***************************** Lock Card commands ***************************/ +/* Commands from 42 to 54, not defined here */ +/***************************** Application-specific commands ****************/ +/* Flag that the next command is application-specific */ +#define CMD55 55 +#define CMD55_R R1 +/* General purpose I/O for application-specific commands */ +#define CMD56 56 +#define CMD56_R R1 +/* Read the OCR (SPI mode only) */ +#define CMD58 58 +#define CMD58_R R3 +/* Turn CRC on or off */ +#define CMD59 59 +#define CMD59_R R1 + +/***************************** Application-specific commands ***************/ +/* Get the SD card’s status */ +#define ACMD13 13 +#define ACMD13_R R2 +/* Get the number of written write blocks (Minus errors ) */ +#define ACMD22 22 +#define ACMD22_R R1 +/* Set the number of write blocks to be pre-erased before writing */ +#define ACMD23 23 +#define ACMD23_R R1 +/* Get the card’s OCR (SD mode) */ +#define ACMD41 41 +#define ACMD41_R R1 +/* Connect or disconnect the 50kOhm internal pull-up on CD/DAT[3] */ +#define ACMD42 42 +#define ACMD42_R R1 +/* Get the SD configuration register */ +#define ACMD51 42 +#define ACMD51_R R1 + +#endif + diff --git a/devel/sd_bad/spi.c b/devel/sd_bad/spi.c new file mode 100644 index 0000000..a9b28a3 --- /dev/null +++ b/devel/sd_bad/spi.c @@ -0,0 +1,88 @@ +#include "main.h" +#include "spi.h" + +/* Initialize and enable the SPI module */ +void spi_initialize() +{ + P3SEL = 0x00E; // Setup P3 for SPI mode + P3OUT |= 0x010; // Setup P3.4 as the SS signal, active low. So, initialize it high. + P3DIR |= 0x010; // Set up P3.4 as an output + + U0CTL = (CHAR | SYNC | MM | SWRST); // 8-bit, SPI, Master + U0TCTL = (SSEL1 | STC | CKPH); // Normal polarity, 3-wire + U0BR0 = 0x002; // SPICLK = SMCLK/2 (2=Minimum divisor) + U0BR1 = 0x000; + U0MCTL = 0x000; + ME1 |= USPIE0; // Module enable + U0CTL &= ~SWRST; // SPI enable +} + +/* Set the baud-rate divisor. The correct value is computed by dividing + the clock rate by the desired baud rate. The minimum divisor allowed + is 2. */ + +void spi_set_divisor(unsigned int divisor) +{ + U0CTL |= SWRST; // Temporarily disable the SPI module + U0BR1 = divisor >> 8; + U0BR0 = divisor; + U0CTL &= ~SWRST; // Re-enable SPI +} + +/* Assert the CS signal, active low (CS=0) */ +void spi_cs_assert() +{ + // Pin 3.4, Pin 32 + P3OUT &= ~0x010; +} + +/* Deassert the CS signal (CS=1) */ +void spi_cs_deassert() +{ + // Pin 3.4, Pin 32 + P3OUT |= 0x010; +} + + +/* Send a single byte over the SPI port */ +void spi_send_byte(uint8_t input) +{ + IFG1 &= ~URXIFG0; + /* Send the byte */ + TXBUF0 = input; + /* Wait for the byte to be sent */ + while ((IFG1 & URXIFG0) == 0) { } +} + + +/* Receive a byte. Output an 0xFF (the bus idles high) to receive the byte */ +uint8_t spi_rcv_byte() +{ + uint8_t tmp; + IFG1 &= ~URXIFG0; + /* Send the byte */ + TXBUF0 = 0xFF; + /* Wait for the byte to be received */ + while ((IFG1 & URXIFG0) == 0) { } + tmp = U0RXBUF; + return (tmp); +} + + +/* Disable the SPI module. This function assumes the module had + * already been initialized. */ +void spi_disable() +{ + /* Put the SPI module in reset mode */ + U0CTL |= SWRST; + /* Disable the USART module */ + ME1 &= ~USPIE0; +} + +void spi_enable() +{ + /* Enable the USART module */ + ME1 |= USPIE0; + /* Take the SPI module out of reset mode */ + U0CTL &= ~SWRST; +} diff --git a/devel/sd_bad/spi.h b/devel/sd_bad/spi.h new file mode 100644 index 0000000..b67a1c0 --- /dev/null +++ b/devel/sd_bad/spi.h @@ -0,0 +1,15 @@ +#ifndef SPI_H +#define SPI_H + +#include + +void spi_initialize(); +void spi_set_divisor(unsigned int divisor); +void spi_cs_assert(); +void spi_cs_deassert(); +void spi_send_byte(uint8_t input); +uint8_t spi_rcv_byte(); +void spi_enable(); +void spi_disable(); + +#endif diff --git a/devel/sd_bad/style.astylerc b/devel/sd_bad/style.astylerc new file mode 100644 index 0000000..f6ea396 --- /dev/null +++ b/devel/sd_bad/style.astylerc @@ -0,0 +1,13 @@ +style=allman +indent=tab +max-instatement-indent=60 + +convert-tabs + +indent-switches + +pad-oper +unpad-paren +pad-header + +verbose diff --git a/devel/sdcard/Makefile b/devel/sdcard/Makefile new file mode 100644 index 0000000..4dba31f --- /dev/null +++ b/devel/sdcard/Makefile @@ -0,0 +1,147 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === 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/ + + +# C files in the library directory +EXTRA_SOURCE_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c spi.c sd.c fat16.c +#Files that need config file: +# EXTRA_SOURCE_FILES += lcd.c +# EXTRA_SOURCE_FILES += color.c wsrgb.c +# EXTRA_SOURCE_FILES += debouce.c + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +fser: all flash ser + +ser: + gtkterm -p /dev/ttyUSB0 + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/sdcard/deployment.pri b/devel/sdcard/deployment.pri new file mode 100644 index 0000000..5f1749f --- /dev/null +++ b/devel/sdcard/deployment.pri @@ -0,0 +1,191 @@ +# This file was generated by an application wizard of Qt Creator. +# The code below handles deployment to Android and Maemo, aswell as copying +# of the application data to shadow build directories on desktop. +# It is recommended not to modify this file, since newer versions of Qt Creator +# may offer an updated version of it. + +defineTest(qtcAddDeployment) { +for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + greaterThan(QT_MAJOR_VERSION, 4) { + itemsources = $${item}.files + } else { + itemsources = $${item}.sources + } + $$itemsources = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath= $$eval($${deploymentfolder}.target) + export($$itemsources) + export($$itempath) + DEPLOYMENT += $$item +} + +MAINPROFILEPWD = $$PWD + +android-no-sdk { + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = /data/user/qt/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + target.path = /data/user/qt + + export(target.path) + INSTALLS += target +} else:android { + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = /assets/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + x86 { + target.path = /libs/x86 + } else: armeabi-v7a { + target.path = /libs/armeabi-v7a + } else { + target.path = /libs/armeabi + } + + export(target.path) + INSTALLS += target +} else:win32 { + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, /, \\) + sourcePathSegments = $$split(source, \\) + target = $$OUT_PWD/$$eval($${deploymentfolder}.target)/$$last(sourcePathSegments) + target = $$replace(target, /, \\) + target ~= s,\\\\\\.?\\\\,\\, + !isEqual(source,$$target) { + !isEmpty(copyCommand):copyCommand += && + isEqual(QMAKE_DIR_SEP, \\) { + copyCommand += $(COPY_DIR) \"$$source\" \"$$target\" + } else { + source = $$replace(source, \\\\, /) + target = $$OUT_PWD/$$eval($${deploymentfolder}.target) + target = $$replace(target, \\\\, /) + copyCommand += test -d \"$$target\" || mkdir -p \"$$target\" && cp -r \"$$source\" \"$$target\" + } + } + } + !isEmpty(copyCommand) { + copyCommand = @echo Copying application data... && $$copyCommand + copydeploymentfolders.commands = $$copyCommand + first.depends = $(first) copydeploymentfolders + export(first.depends) + export(copydeploymentfolders.commands) + QMAKE_EXTRA_TARGETS += first copydeploymentfolders + } +} else:ios { + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, \\\\, /) + target = $CODESIGNING_FOLDER_PATH/$$eval($${deploymentfolder}.target) + target = $$replace(target, \\\\, /) + sourcePathSegments = $$split(source, /) + targetFullPath = $$target/$$last(sourcePathSegments) + targetFullPath ~= s,/\\.?/,/, + !isEqual(source,$$targetFullPath) { + !isEmpty(copyCommand):copyCommand += && + copyCommand += mkdir -p \"$$target\" + copyCommand += && cp -r \"$$source\" \"$$target\" + } + } + !isEmpty(copyCommand) { + copyCommand = echo Copying application data... && $$copyCommand + !isEmpty(QMAKE_POST_LINK): QMAKE_POST_LINK += ";" + QMAKE_POST_LINK += "$$copyCommand" + export(QMAKE_POST_LINK) + } +} else:unix { + maemo5 { + desktopfile.files = $${TARGET}.desktop + desktopfile.path = /usr/share/applications/hildon + icon.files = $${TARGET}64.png + icon.path = /usr/share/icons/hicolor/64x64/apps + } else:!isEmpty(MEEGO_VERSION_MAJOR) { + desktopfile.files = $${TARGET}_harmattan.desktop + desktopfile.path = /usr/share/applications + icon.files = $${TARGET}80.png + icon.path = /usr/share/icons/hicolor/80x80/apps + } else { # Assumed to be a Desktop Unix + copyCommand = + for(deploymentfolder, DEPLOYMENTFOLDERS) { + source = $$MAINPROFILEPWD/$$eval($${deploymentfolder}.source) + source = $$replace(source, \\\\, /) + macx { + target = $$OUT_PWD/$${TARGET}.app/Contents/Resources/$$eval($${deploymentfolder}.target) + } else { + target = $$OUT_PWD/$$eval($${deploymentfolder}.target) + } + target = $$replace(target, \\\\, /) + sourcePathSegments = $$split(source, /) + targetFullPath = $$target/$$last(sourcePathSegments) + targetFullPath ~= s,/\\.?/,/, + !isEqual(source,$$targetFullPath) { + !isEmpty(copyCommand):copyCommand += && + copyCommand += $(MKDIR) \"$$target\" + copyCommand += && $(COPY_DIR) \"$$source\" \"$$target\" + } + } + !isEmpty(copyCommand) { + copyCommand = @echo Copying application data... && $$copyCommand + copydeploymentfolders.commands = $$copyCommand + first.depends = $(first) copydeploymentfolders + export(first.depends) + export(copydeploymentfolders.commands) + QMAKE_EXTRA_TARGETS += first copydeploymentfolders + } + } + !isEmpty(target.path) { + installPrefix = $${target.path} + } else { + installPrefix = /opt/$${TARGET} + } + for(deploymentfolder, DEPLOYMENTFOLDERS) { + item = item$${deploymentfolder} + itemfiles = $${item}.files + $$itemfiles = $$eval($${deploymentfolder}.source) + itempath = $${item}.path + $$itempath = $${installPrefix}/$$eval($${deploymentfolder}.target) + export($$itemfiles) + export($$itempath) + INSTALLS += $$item + } + + !isEmpty(desktopfile.path) { + export(icon.files) + export(icon.path) + export(desktopfile.files) + export(desktopfile.path) + INSTALLS += icon desktopfile + } + + isEmpty(target.path) { + target.path = $${installPrefix}/bin + export(target.path) + } + INSTALLS += target +} + +export (ICON) +export (INSTALLS) +export (DEPLOYMENT) +export (LIBS) +export (QMAKE_EXTRA_TARGETS) +} + diff --git a/devel/sdcard/lib b/devel/sdcard/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/sdcard/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/sdcard/main.c b/devel/sdcard/main.c new file mode 100644 index 0000000..960cb0d --- /dev/null +++ b/devel/sdcard/main.c @@ -0,0 +1,64 @@ +#include +#include + +#include "lib/uart.h" +#include "lib/stream.h" +#include "lib/sd.h" + +void main() +{ + uart_init(9600); + uart_puts_P(PSTR("*** SD CARD SPI TEST ***\r\n")); + + if (!sd_init()) + { + put_str_P(uart, PSTR("Failed to init.")); + while (1); + } + + + uint8_t text[512]; + + + + put_str_P(uart, PSTR("\r\nReading...\r\n")); + if (sd_read(0, 0, text, 0, 512)) + { + put_bytes(uart, text, 512); + put_nl(uart); + put_nl(uart); + + for (uint8_t i = 0; i < 60; i++) + { + text[i] = ('A' + i); + } + + put_str_P(uart, PSTR("\r\nWriting...\r\n")); + sd_write(1, text); + put_str_P(uart, PSTR("\r\nWrite done.\r\n")); + + for (uint16_t i = 0; i < 512; i++) + { + text[i] = 0; + } + + if (sd_read(1, 0, text, 0, 512)) + { + put_str_P(uart, PSTR("\r\nWritten, result: \r\n")); + put_bytes(uart, text, 512); + put_nl(uart); + put_nl(uart); + } + else + { + put_str_P(uart, PSTR("\r\nRead failed.\r\n")); + } + } + else + { + put_str_P(uart, PSTR("Failed to read.")); + while (1); + } + + while (1); +} diff --git a/devel/sdcard/sdcard.pro b/devel/sdcard/sdcard.pro new file mode 100644 index 0000000..b856652 --- /dev/null +++ b/devel/sdcard/sdcard.pro @@ -0,0 +1,56 @@ +TEMPLATE = app +CONFIG += console +CONFIG -= app_bundle +CONFIG -= qt + +INCLUDEPATH += /usr/avr/include + +SOURCES += main.c \ + lib/adc.c \ + lib/color.c \ + lib/debounce.c \ + lib/dht11.c \ + lib/iopins.c \ + lib/lcd.c \ + lib/onewire.c \ + lib/sonar.c \ + lib/stream.c \ + lib/uart.c \ + lib/wsrgb.c \ + sd/main.c \ + sd/sd.c \ + sd/spi.c \ + lib/fat16.c \ + lib/sd.c \ + lib/spi.c + +include(deployment.pri) +qtcAddDeployment() + +HEADERS += \ + lib/adc.h \ + lib/calc.h \ + lib/color.h \ + lib/debounce.h \ + lib/dht11.h \ + lib/iopins.h \ + lib/lcd.h \ + lib/nsdelay.h \ + lib/onewire.h \ + lib/sonar.h \ + lib/stream.h \ + lib/uart.h \ + lib/wsrgb.h \ + sd/main.h \ + sd/sd.h \ + sd/sdcomm_spi.h \ + sd/spi.h \ + lib/fat16.h \ + lib/fat16_internal.h \ + lib/spi.h \ + lib/sd.h + +DISTFILES += \ + Makefile \ + style.astylerc + diff --git a/devel/sdcard/sdcard.pro.user b/devel/sdcard/sdcard.pro.user new file mode 100644 index 0000000..28194b6 --- /dev/null +++ b/devel/sdcard/sdcard.pro.user @@ -0,0 +1,250 @@ + + + + + + EnvironmentId + {dfe3cb4a-0f3e-4da9-9c52-5d2c464adafb} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + 1 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + 1 + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {ee748544-c6c0-4f44-9cef-fbb65dc2525a} + 0 + 0 + 1 + + /home/ondra/git/avr-projects/devel/sdcard/ + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + -B + + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/ondra/git/avr-projects/devel/sdcard/build-sdcard-Desktop-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 2 + + + + true + flash -B + make + %{buildDir} + Custom Process Step + + ProjectExplorer.ProcessStep + + 1 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + 2 + + sdcard + sdcard2 + Qt4ProjectManager.Qt4RunConfiguration:/home/ondra/git/avr-projects/devel/sdcard/sdcard.pro + + sdcard.pro + false + true + + 3768 + false + true + false + false + true + + + 2 + + -p /dev/ttyUSB0 + gtkterm + false + %{buildDir} + Run gtkterm + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + 2 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/devel/sdcard/style.astylerc b/devel/sdcard/style.astylerc new file mode 100644 index 0000000..f6ea396 --- /dev/null +++ b/devel/sdcard/style.astylerc @@ -0,0 +1,13 @@ +style=allman +indent=tab +max-instatement-indent=60 + +convert-tabs + +indent-switches + +pad-oper +unpad-paren +pad-header + +verbose diff --git a/devel/snake/Makefile b/devel/snake/Makefile new file mode 100644 index 0000000..56fe6f8 --- /dev/null +++ b/devel/snake/Makefile @@ -0,0 +1,166 @@ + +MCU = atmega328p + +F_CPU = 16000000 + +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + +MAIN = main.c + +## If you've split your program into multiple files, +## include the additional .c source (in same directory) here +## (and include the .h files in your foo.c) +LOCAL_SOURCE = + +## Here you can link to one more directory (and multiple .c files) +# EXTRA_SOURCE_DIR = ../AVR-Programming-Library/ +EXTRA_SOURCE_DIR = +EXTRA_SOURCE_FILES = + + + +##########------------------------------------------------------########## +########## Programmer Defaults ########## +########## Set up once, then forget about it ########## +########## (Can override. See bottom of file.) ########## +##########------------------------------------------------------########## +#19200 +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +##########------------------------------------------------------########## +########## Makefile Magic! ########## +########## Summary: ########## +########## We want a .hex file ########## +########## Compile source files into .elf ########## +########## Convert .elf file into .hex ########## +########## You shouldn't need to edit below. ########## +##########------------------------------------------------------########## + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = sudo avrdude + +## Compilation options, type man avr-gcc if you're curious. +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 +CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax + +CFLAGS_BUILD = $(CFLAGS) -Os + +# CFLAGS += -lm +## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf +## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf + +## Lump target and extra source files together +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +## List of all header files +HEADERS = $(SRC:.c=.h) + +## For every .c file, compile an .o object file +OBJ = $(SRC:.c=.o) + +## Generic Makefile targets. (Only .hex file is necessary) +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + +# Optionally create listing file from .elf +# This creates approximate assembly-language equivalent of your code. +# Useful for debugging time-sensitive bits, +# or making sure the compiler does what you want. +disassemble: $(TARGET).lst + +dis: disassemble +lst: disassemble + +eeprom: $(TARGET).eeprom + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Optionally show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +squeaky_clean: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +##########------------------------------------------------------########## +########## Programmer-specific details ########## +########## Flashing code to AVR using avrdude ########## +##########------------------------------------------------------########## + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flash_eeprom: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +terminal: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + + +flash_arduino: PROGRAMMER_TYPE = arduino +flash_arduino: PROGRAMMER_ARGS = +flash_arduino: flash + +flash_dragon_isp: PROGRAMMER_TYPE = dragon_isp +flash_dragon_isp: PROGRAMMER_ARGS = +flash_dragon_isp: flash + + +##########------------------------------------------------------########## +########## Fuse settings and suitable defaults ########## +##########------------------------------------------------------########## + +## Generic +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +## Called with no extra definitions, sets to defaults +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/snake/lcd_default.asm b/devel/snake/lcd_default.asm new file mode 100644 index 0000000..05e064a --- /dev/null +++ b/devel/snake/lcd_default.asm @@ -0,0 +1,351 @@ +; Zapojeni (Připojen DMC-50399 v 4-bitovem modu): +; +------u------+ +; Vcc -> reset --+ /RST Vcc +-- napajeni +5V +; --+ PD0 PB7 +-- RS (0=instr W, BF+addr R; 1=data W/R) +; --+ PD1 PB6 +-- R/W (1=read,0=write) +; --+ PA1 PB5 +-- E (clock, active falling edge) +; --+ PA0 PB4 +-- +; --+ PD2 PB3 +-- DATA 7 +; --+ PD3 PB2 +-- DATA 6 +; --+ PD4 PB1 +-- DATA 5 +; --+ PD5 PB0 +-- DATA 4 +; GND --+ GND PD6 +-- +; +-------------+ + +;DMC-50399: +; 1 - GND +; 2 - +5V +; 3 - 0V (lcd driver) +; 4 - RS +; 5 - R/W +; 6 - E +; 7 - DATA 0 +; 8 - DATA 1 +;... +;14 - DATA 7 + +.device attiny2313 +;běží na 4MHz, ckdiv8=1 (vypnuto) +;250x16=1ms=1000us + +;LFUSE: 0xE2 -U lfuse:w:0xE2:m +;HFUSE: 0xDF -U hfuse:w:0xDF:m + + +;K O N S T A N T Y + P R E Z D I V K Y P O R T U A P I N U +.equ LCDPORT = PORTB +.equ LCDPIN = PINB +.equ LCDDDR = DDRB + +.equ RS = 7 +.equ RW = 6 +.equ E = 5 + +.equ LCD_CLEAR = 0b00000001 +.equ LCD_HOME = 0b00000010 + +.equ LCD_MODE_INC_NOSHIFT = 0b00000110 +.equ LCD_MODE_INC_SHIFT = 0b00000111 +.equ LCD_MODE_DEC_NOSHIFT = 0b00000100 +.equ LCD_MODE_DEC_SHIFT = 0b00000101 + +.equ LCD_DISPLAY_DISABLED = 0b00001000 +.equ LCD_DISPLAY_NOCURSOR = 0b00001100 +.equ LCD_DISPLAY_CURSOR = 0b00001110 +.equ LCD_DISPLAY_ALTER = 0b00001101 +.equ LCD_DISPLAY_CURSOR_ALTER = 0b00001111 + +.equ LCD_CURSOR_LEFT = 0b00010000 +.equ LCD_CURSOR_RIGHT = 0b00010100 +.equ LCD_SHIFT_LEFT = 0b00011000 +.equ LCD_SHIFT_RIGHT = 0b00011100 + + +;5x7 font, 1-line +.equ LCD_MODE_4BIT_1LINE = 0b00100000 +;.equ LCD_MODE_8BIT_1LINE = 0b00110000 +;5x7 font, 2-line +.equ LCD_MODE_4BIT_2LINE = 0b00101000 +;.equ LCD_MODE_8BIT_2LINE = 0b00111000 + +.equ ROW1_ADDR = 0x00 +.equ ROW2_ADDR = 0x40 +.equ ROW3_ADDR = 0x14 +.equ ROW4_ADDR = 0x54 + + + +;aliases +.def ZH = r31 +.def ZL = r30 +.def YH = r29 +.def YL = r28 +.def XH = r27 +.def XL = r26 + +; Z A C A T E K P R O G R A M U +;vektory preruseni +.org 0x0000 ;RESET + rjmp RESET ;skok na start po resetu + +.org 0x0013 + +;nastaveni po resetu +.DB "HD44780 INTERFACE" ;(nazev programu) +RESET: + ldi r16,low(RAMEND) ;nastavi stack pointer + out SPL,r16 + cli ;zakazat vsechna preruseni + +; Nastaveni portu + ;PORTB = LCDPORT + ldi r16,0b11111111 ;smer portu B + out LCDDDR,r16 + ldi r16,0b00000000 ;vypnout B + out LCDPORT,r16 + + sei ;Global Interrupt Enable + +; == display init == + rcall LCD_INIT + + ldi r17,LCD_MODE_INC_NOSHIFT + rcall TX_INSTR + + ldi r17,LCD_DISPLAY_NOCURSOR + rcall TX_INSTR + +; == load user-defined characters to CGRAM == (default, array label named MYCHARS, end-mark=0xFE) + ldi r17,0 + rcall CGRAM_SET_ADDR + + ldi ZH,high(MYCHARS*2) + ldi ZL,low(MYCHARS*2) +CGRAM_loop: + lpm r17,Z+ + cpi r17,0xFE + breq CGRAM_loop_end + rcall TX_DATA + rjmp CGRAM_loop +CGRAM_loop_end: + + +; == pgm body == + +;load text to DDRAM + ldi r17,ROW1_ADDR + rcall DDRAM_SET_ADDR + + ldi ZH,high(MYTEXT1*2) + ldi ZL,low(MYTEXT1*2) +DDRAM_loop: + lpm r17,Z+ + cpi r17,0xFE + breq DDRAM_loop_end + rcall TX_DATA + rjmp DDRAM_loop +DDRAM_loop_end: + +;load text to DDRAM + ldi r17,ROW2_ADDR + rcall DDRAM_SET_ADDR + + ldi ZH,high(MYTEXT2*2) + ldi ZL,low(MYTEXT2*2) +DDRAM2_loop: + lpm r17,Z+ + cpi r17,0xFE + breq DDRAM2_loop_end + rcall TX_DATA + rjmp DDRAM2_loop +DDRAM2_loop_end: + +;direct write to X,Y - example + ldi r16,3 ;Y, zacina 0 a roste smerem dolu + ldi r17,5 ;X, zacina nulou a roste smerem doprava + rcall LCD_CURSOR_XY + ldi r17,"%" + rcall TX_DATA + ldi r17,"%" + rcall TX_DATA + ldi r17,"%" + rcall TX_DATA +;infinite loop +loop: rjmp loop + + +MYTEXT1: +.DB 0,0,0," POKUSNY TEXT ",0,0,0,0xFE +MYTEXT2: +.DB "Opravdu pekny text!",0xFE + + + +; == USER-DEFINED CHARS == +MYCHARS: +; 5x8, first 3 bits are not used +;end of mychars +.DB 0xe,0x1f,0x15,0x1f,0x1f,0x1f,0x15 ;smajlik + +;konec +.DB 0xFE + + + + + +;r16=Y +;r17=X +LCD_CURSOR_XY: + cpi r16,0 + brne test1 +fail: ldi r16,ROW1_ADDR + rjmp addrdone +test1: + cpi r16,1 + brne test2 + ldi r16,ROW2_ADDR + rjmp addrdone +test2: + cpi r16,2 + brne test3 + ldi r16,ROW3_ADDR + rjmp addrdone +test3: + cpi r16,3 + brne fail + ldi r16,ROW4_ADDR +addrdone: + add r17,r16 + rcall DDRAM_SET_ADDR + ret + +;r16=počet ms (cca) +delay: + push r17 ;2 + push r18 ;2 +d1: + ldi r17,250 ;1 +d2: + ldi r18,14 ;1 +d3: + dec r18 ;1 + nop + brne d3 ;2 (1 + dec r17 ; +1) + brne d2 ;2 (1 + dec r16 ; +1) + brne d1 ;2 (1) + + pop r18 ;2 + pop r17 ;2 + ret + + +LCD_INIT: + ldi r16,16 + rcall delay + ldi r16,0b00000010 ;4bit + out PORTB,r16 + rcall LCD_CLK + ldi r16,5 + rcall delay + ldi r17,LCD_MODE_4BIT_2LINE ;set 4-bit mode + rcall TX_INSTR + ret + +;r17 +TX_INSTR: + swap r17 ;send high nibble + mov r16,r17 + andi r16,0b00001111 + out LCDPORT,r16 + rcall LCD_CLK + + swap r17 ;send low nibble + mov r16,r17 + andi r16,0b00001111 + out LCDPORT,r16 + rcall LCD_CLK + + ret + +;r17 +TX_DATA: + swap r17 ;send high nibble + mov r16,r17 + andi r16,0b00001111 + sbr r16,(1< +#include +#include +#include +#include +#include +#include + +#include "lib/meta.h" +#include "lib/arduino_pins.h" +#include "lib/calc.h" +#include "lib/adc.h" + +#define LCD_PIN_RS D10 +#define LCD_PIN_RW D11 +#define LCD_PIN_E D12 +#define LCD_PIN_D4 D13 +#define LCD_PIN_D5 D14 +#define LCD_PIN_D6 D15 +#define LCD_PIN_D7 D16 +// D17 = A3 = source of entropy for random. + +#include "lib/lcd.h" + + +// Buttons (to ground) +#define BTN_LEFT D2 +#define BTN_RIGHT D3 +#define BTN_UP D4 +#define BTN_DOWN D5 +#define BTN_SELECT D6 +#define BTN_RESTART D7 + +// Debouncer channels for buttons +// (Must be added in this order to debouncer) +#define D_LEFT 0 +#define D_RIGHT 1 +#define D_UP 2 +#define D_DOWN 3 +#define D_SELECT 4 +#define D_RESTART 5 + +#define DEBO_CHANNELS 6 +#define DEBO_TICKS 1 // in 0.01s + +#include "lib/debounce.h" + +// Board size (!!! rows = 2x number of display lines, max 2*4 = 8 !!!) +#define ROWS 4 +#define COLS 20 + +// Delay between snake steps, in 10 ms +#define STEP_DELAY 24 + +// proto +void update(); +void init_cgram(); +void init_gameboard(); + +void SECTION(".init8") init() +{ + // Randomize RNG + adc_init(); + srand(adc_read_word(3)); + + // Init LCD + lcd_init(); + init_cgram(); // load default glyphs + + // Init game board. + init_gameboard(); + + // gamepad buttons + as_input_pu(BTN_LEFT); + as_input_pu(BTN_RIGHT); + as_input_pu(BTN_UP); + as_input_pu(BTN_DOWN); + as_input_pu(BTN_SELECT); + as_input_pu(BTN_RESTART); + + // add buttons to debouncer + debo_add_rev(BTN_LEFT); + debo_add_rev(BTN_RIGHT); + debo_add_rev(BTN_UP); + debo_add_rev(BTN_DOWN); + debo_add_rev(BTN_SELECT); + debo_add_rev(BTN_RESTART); + + // setup timer + TCCR0A = _BV(WGM01); // CTC + TCCR0B = _BV(CS02) | _BV(CS00); // prescaler 1024 + OCR0A = 156; // interrupt every 10 ms + sbi(TIMSK0, OCIE0A); + sei(); +} + + +/** timer 0 interrupt vector */ +ISR(TIMER0_COMPA_vect) +{ + debo_tick(); // poll debouncer + update(); // update and display +} + + + +// sub-glyphs +#define _HEAD_ 15, 21, 21, 30 +#define _BODY_ 15, 31, 31, 30 +#define _FOOD_ 10, 21, 17, 14 +//14, 17, 17, 14 +#define _NONE_ 0, 0, 0, 0 + +// complete glyphs for loading into memory + +// Only one food & one head glyph have to be loaded at a time. + +// Body - Body +const uint8_t SYMBOL_BB[] PROGMEM = {_BODY_, _BODY_}; + +// Body - None +const uint8_t SYMBOL_BX[] PROGMEM = {_BODY_, _NONE_}; +const uint8_t SYMBOL_XB[] PROGMEM = {_NONE_, _BODY_}; + +// Head - None +const uint8_t SYMBOL_HX[] PROGMEM = {_HEAD_, _NONE_}; +const uint8_t SYMBOL_XH[] PROGMEM = {_NONE_, _HEAD_}; + +// Body - Head +const uint8_t SYMBOL_BH[] PROGMEM = {_BODY_, _HEAD_}; +const uint8_t SYMBOL_HB[] PROGMEM = {_HEAD_, _BODY_}; + +// Head - Food +const uint8_t SYMBOL_HF[] PROGMEM = {_HEAD_, _FOOD_}; +const uint8_t SYMBOL_FH[] PROGMEM = {_FOOD_, _HEAD_}; + +// Food - None +const uint8_t SYMBOL_FX[] PROGMEM = {_FOOD_, _NONE_}; +const uint8_t SYMBOL_XF[] PROGMEM = {_NONE_, _FOOD_}; + +// Body - Food +const uint8_t SYMBOL_BF[] PROGMEM = {_BODY_, _FOOD_}; +const uint8_t SYMBOL_FB[] PROGMEM = {_FOOD_, _BODY_}; + + +// board block (snake, food...) +typedef enum { + bEMPTY = 0x00, + bHEAD = 0x01, + bFOOD = 0x02, + bBODY_LEFT = 0x80, + bBODY_RIGHT = 0x81, + bBODY_UP = 0x82, + bBODY_DOWN = 0x83, +} block_t; + +// Snake direction +typedef enum { + dLEFT = 0x00, + dRIGHT = 0x01, + dUP = 0x02, + dDOWN = 0x03, +} dir_t; + +// Coordinate on board +typedef struct { + int8_t x; + int8_t y; +} coord_t; + +#define is_body(blk) (((blk) & 0x80) != 0) +#define mk_body_dir(dir) (0x80 + (dir)) + +// compare two coords +#define coord_eq(a, b) (((a).x == (b).x) && ((a).y == (b).y)) + + +bool crashed; +uint8_t snake_len; + +// y, x indexing +block_t board[ROWS][COLS]; + +coord_t head_pos; +coord_t tail_pos; +dir_t head_dir; + +const uint8_t CODE_BB = 0; +const uint8_t CODE_BX = 1; +const uint8_t CODE_XB = 2; +const uint8_t CODE_H = 3; // glyph with head, dynamic +const uint8_t CODE_F = 4; // glyph with food, dynamic +const uint8_t CODE_XX = 32; // space + + +// Set a block in board +#define set_block_xy(x, y, block) do { board[y][x] = (block); } while(0) +#define get_block_xy(x, y) board[y][x] +#define get_block(pos) get_block_xy((pos).x, (pos).y) +#define set_block(pos, block) set_block_xy((pos).x, (pos).y, (block)) + + +void init_cgram() +{ + // those will be always the same + lcd_define_glyph_pgm(CODE_BB, SYMBOL_BB); + lcd_define_glyph_pgm(CODE_BX, SYMBOL_BX); + lcd_define_glyph_pgm(CODE_XB, SYMBOL_XB); + lcd_define_glyph_pgm(5, SYMBOL_XF); +} + + +void place_food() +{ + while(1) { + const uint8_t xx = rand() % COLS; + const uint8_t yy = rand() % ROWS; + + if (get_block_xy(xx, yy) == bEMPTY) { + set_block_xy(xx, yy, bFOOD); + break; + } + } +} + + +void init_gameboard() +{ + //erase the board + for (uint8_t x = 0; x < COLS; x++) { + for (uint8_t y = 0; y < ROWS; y++) { + set_block_xy(x, y, bEMPTY); + } + } + + lcd_clear(); + + tail_pos = (coord_t) {.x = 0, .y = 0}; + + set_block_xy(0, 0, bBODY_RIGHT); + set_block_xy(1, 0, bBODY_RIGHT); + set_block_xy(2, 0, bBODY_RIGHT); + set_block_xy(3, 0, bHEAD); + + head_pos = (coord_t) {.x = 3, .y = 0}; + + snake_len = 4; // includes head + + head_dir = dRIGHT; + crashed = false; + + place_food(); +} + + +uint8_t presc = 0; + +bool restart_held; +void update() +{ + if (debo_get_pin(D_RESTART)) { + + if (!restart_held) { + // restart + init_gameboard(); + presc = 0; + restart_held = true; + } + + } else { + restart_held = false; + } + + if(!crashed) { + + // resolve movement direction + if (debo_get_pin(D_LEFT)) + head_dir = dLEFT; + else if (debo_get_pin(D_RIGHT)) + head_dir = dRIGHT; + else if (debo_get_pin(D_UP)) + head_dir = dUP; + else if (debo_get_pin(D_DOWN)) + head_dir = dDOWN; + + // time's up for a move + if (presc++ == STEP_DELAY) { + presc = 0; + + // move snake + const coord_t oldpos = head_pos; + + switch (head_dir) { + case dLEFT: head_pos.x--; break; + case dRIGHT: head_pos.x++; break; + case dUP: head_pos.y--; break; + case dDOWN: head_pos.y++; break; + } + + bool do_move = false; + bool do_grow = false; + + if (head_pos.x < 0 || head_pos.x >= COLS || head_pos.y < 0 || head_pos.y >= ROWS) { + // ouch, a wall! + crashed = true; + } else { + // check if tile occupied or not + if (coord_eq(head_pos, tail_pos)) { + // head moved in previous tail, that's OK. + do_move = true; + } else { + // moved to other tile than tail + switch (get_block(head_pos)) { + + case bFOOD: + do_grow = true; // fall through + case bEMPTY: + do_move = true; + break; + + default: // includes all BODY_xxx + crashed = true; // snake crashed into some block + } + } + } + + if (do_move) { + // Move tail + if (do_grow) { + // let tail as is + snake_len++; // grow the counter + } else { + // tail dir + dir_t td = get_block(tail_pos) & 0xF; + + // clean tail + set_block(tail_pos, bEMPTY); + + // move tail based on old direction of tail block + switch (td) { + case dLEFT: tail_pos.x--; break; + case dRIGHT: tail_pos.x++; break; + case dUP: tail_pos.y--; break; + case dDOWN: tail_pos.y++; break; + } + } + + // Move head + set_block(head_pos, bHEAD); // place head in new pos + set_block(oldpos, mk_body_dir(head_dir)); // directional body in old head pos + + if (do_grow) { + // food eaten, place new + place_food(); + } + } + } + } // end !crashed + + + // Render the board + for (uint8_t r = 0; r < ROWS / 2; r++) { + lcd_xy(0, r); + for (uint8_t c = 0; c < COLS; c++) { + const block_t t1 = get_block_xy(c, r * 2); + const block_t t2 = get_block_xy(c, (r * 2) + 1); + + uint8_t code = '!'; // ! marks fail + + if ((t1 == bEMPTY) && (t2 == bEMPTY)) { + code = CODE_XX; + if (crashed) code = '*'; + } else if (is_body(t1) && is_body(t2)) + code = CODE_BB; + else if (is_body(t1) && (t2 == bEMPTY)) + code = CODE_BX; + else if (t1 == bEMPTY && is_body(t2)) + code = CODE_XB; + else if ((t1 == bFOOD) || (t2 == bFOOD)) { + // one is food + + code = CODE_F; + + if (t1 == bFOOD) { + if (t2 == bEMPTY) + lcd_define_glyph_pgm(code, SYMBOL_FX); + else if (t2 == bHEAD) + lcd_define_glyph_pgm(code, SYMBOL_FH); + else if (is_body(t2)) + lcd_define_glyph_pgm(code, SYMBOL_FB); + } else { // t2 is food + if (t1 == bEMPTY) + lcd_define_glyph_pgm(code, SYMBOL_XF); + else if (t1 == bHEAD) + lcd_define_glyph_pgm(code, SYMBOL_HF); + else if (is_body(t1)) + lcd_define_glyph_pgm(code, SYMBOL_BF); + } + lcd_xy(c,r); + + } else if ((t1 == bHEAD )|| (t2 == bHEAD)) { + // one is head + + code = CODE_H; + + if (t1 == bHEAD) { + if (t2 == bEMPTY) + lcd_define_glyph_pgm(code, SYMBOL_HX); + else if (is_body(t2)) + lcd_define_glyph_pgm(code, SYMBOL_HB); + } else { // t2 is head + if (t1 == bEMPTY) + lcd_define_glyph_pgm(code, SYMBOL_XH); + else if (is_body(t1)) + lcd_define_glyph_pgm(code, SYMBOL_BH); + } + + lcd_xy(c,r); + } + + lcd_char(code); + } + } +} + +void main() { while(1); } // timer does everything diff --git a/devel/try_ws/Makefile b/devel/try_ws/Makefile new file mode 100644 index 0000000..9735d38 --- /dev/null +++ b/devel/try_ws/Makefile @@ -0,0 +1,147 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === 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/ +# C files in the library directory +EXTRA_SOURCE_FILES = uart.c iopins.c color.c wsrgb.c + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +fser: all flash ser + +ser: + gtkterm -p /dev/ttyUSB0 + +cl: + ./client /dev/ttyUSB0 9600 + +fcl: all flash + ./client /dev/ttyUSB0 9600 + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/try_ws/client b/devel/try_ws/client new file mode 100755 index 0000000000000000000000000000000000000000..02f9449a22ecd2d370135c0a762a783e3c0474da GIT binary patch literal 10160 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 +#include +#include +#include +#include +#include + +#include "lib/iopins.h" +#include "lib/wsrgb.h" +#include "lib/uart.h" + +void main() +{ + ws_init(); + + xrgb_t c[3]; + c[0] = xrgb(255, 0, 255); + c[1] = xrgb(0, 255, 255); + c[2] = xrgb(255, 255, 0); + + while(1) { + ws_send_xrgb_array(c, 3); + + ws_show(); + + c[0].r++; + c[1].b++; + c[2].g++; + + _delay_ms(10); + } +} diff --git a/devel/try_ws/ws_config.h b/devel/try_ws/ws_config.h new file mode 100644 index 0000000..f7315b2 --- /dev/null +++ b/devel/try_ws/ws_config.h @@ -0,0 +1,7 @@ +#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 diff --git a/devel/uart/Makefile b/devel/uart/Makefile new file mode 100644 index 0000000..659c3d1 --- /dev/null +++ b/devel/uart/Makefile @@ -0,0 +1,147 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === 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/ +# C files in the library directory +EXTRA_SOURCE_FILES = uart.c uart_ansi.c + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +fser: all flash serial + +ser: + gtkterm -p /dev/ttyUSB0 + +cl: + ./client /dev/ttyUSB0 9600 + +fcl: all flash + ./client /dev/ttyUSB0 9600 + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/uart/client b/devel/uart/client new file mode 100755 index 0000000000000000000000000000000000000000..02f9449a22ecd2d370135c0a762a783e3c0474da GIT binary patch literal 10160 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 +#include +#include +#include +#include + +#include "serial.h" + +int main(int argc, char const *argv[]) +{ + if (argc < 2) { fprintf(stderr, "Missing parameter \n"); return 1; } + + int baud = 9600; + if (argc == 3) sscanf(argv[2], "%d", &baud); + + int fd = serial_open(argv[1], baud); + + // Wait for the Arduino to start + usleep(1500000); + + // Redirecting stdin/stdout to arduino + while(1) { + char buf[1]; + if (fread(buf, 1, 1, stdin) > 0) { + serial_write(fd, buf[0]); + fflush(stdout); + } + + char c; + c = serial_read(fd, 10); + if (c > 0) { + putchar(c); + fflush(stdout); + } + } +} + diff --git a/devel/uart/clientd/serial.c b/devel/uart/clientd/serial.c new file mode 100644 index 0000000..5516304 --- /dev/null +++ b/devel/uart/clientd/serial.c @@ -0,0 +1,89 @@ +#define _POSIX_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "serial.h" + + +/** Open a serial port */ +int serial_open(const char* port, const unsigned int baud) +{ + int fd = open(port, O_RDWR | O_NONBLOCK); + + struct termios tio; + memset(&tio, 0, sizeof(tio)); + + speed_t bd = baud; + switch(bd) { + case 1200: bd = B1200; break; + case 1800: bd = B1800; break; + case 2400: bd = B2400; break; + case 4800: bd = B4800; break; + case 9600: bd = B9600; break; + case 19200: bd = B19200; break; + case 38400: bd = B38400; break; + } + + tio.c_cflag = bd | CS8 | CLOCAL | CREAD | CRTSCTS; + tio.c_iflag = IGNPAR; + + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &tio); + return fd; +} + + +/** Close a serial port */ +int serial_close(int fd) +{ + return close(fd); +} + + +/** Write a byte. Returns false on failure */ +int serial_write(int fd, uint8_t b) +{ + return write(fd, &b, 1); +} + + +int serial_puts(int fd, const char* str) +{ + int len = strlen(str); + return write(fd, str, len); +} + + +uint8_t serial_read(int fd, int timeout) +{ + uint8_t b[1]; + do { + int n = read(fd, b, 1); + if (n == -1) return -1; + if (n == 0) { + usleep(1 * 1000); // wait 1 ms + timeout--; + continue; + } + return b[0]; + } while(timeout > 0); + return -1; +} + + +int serial_flush(int fd) +{ + sleep(2); + return tcflush(fd, TCIOFLUSH); +} diff --git a/devel/uart/clientd/serial.h b/devel/uart/clientd/serial.h new file mode 100644 index 0000000..aebcbf7 --- /dev/null +++ b/devel/uart/clientd/serial.h @@ -0,0 +1,27 @@ +#pragma once + +#include + + +/** Open a serial port */ +int serial_open(const char* port, const unsigned int baud); + + +/** Close a serial port */ +int serial_close(int fd); + + +/** Write a byte. Returns false on failure */ +int serial_write(int fd, uint8_t b); + + +/** Send a string */ +int serial_puts(int fd, const char* str); + + +/** Read a byte */ +uint8_t serial_read(int fd, int timeout); + + +/** Flush */ +int serial_flush(int fd); diff --git a/devel/uart/lib b/devel/uart/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/uart/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/uart/main.c b/devel/uart/main.c new file mode 100644 index 0000000..44735a3 --- /dev/null +++ b/devel/uart/main.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lib/uart.h" + +ISR(USART_RX_vect) +{ + uint8_t x = uart_rx(); + uart_tx(x); +} + +void main() +{ + uart_init(9600); + uart_isr_rx(1); + sei(); + while(1) { + //uart_puts_P(PSTR("TEST")); + } +} diff --git a/devel/uart/special_keys.txt b/devel/uart/special_keys.txt new file mode 100644 index 0000000..5f63c5f --- /dev/null +++ b/devel/uart/special_keys.txt @@ -0,0 +1,25 @@ + + Es [ ? +left 27 91 68 +right 27 91 67 +up 27 91 65 +down 27 91 66 + + Es [ ? ~ +insert 27 91 50 126 +delete 27 91 51 126 +pgup 27 91 53 126 +pgdn 27 91 54 126 + + Es O ? +f1 27 79 80 +f2 27 79 81 +f3 27 79 82 +f4 27 79 83 +home 27 79 72 +end 27 79 70 + +back 8 +tab 9 +enter 13 +esc 27 diff --git a/devel/ultrasonic/Makefile b/devel/ultrasonic/Makefile new file mode 100644 index 0000000..bfd145e --- /dev/null +++ b/devel/ultrasonic/Makefile @@ -0,0 +1,137 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === 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/ +# C files in the library directory +EXTRA_SOURCE_FILES = uart.c uart_ansi.c sonar.c + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/ultrasonic/lcd_config.h b/devel/ultrasonic/lcd_config.h new file mode 100644 index 0000000..594b506 --- /dev/null +++ b/devel/ultrasonic/lcd_config.h @@ -0,0 +1,13 @@ +#pragma once + +// 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 diff --git a/devel/ultrasonic/lib b/devel/ultrasonic/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/ultrasonic/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/ultrasonic/main.c b/devel/ultrasonic/main.c new file mode 100644 index 0000000..871f7a2 --- /dev/null +++ b/devel/ultrasonic/main.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include + +#include "lib/calc.h" +#include "lib/uart.h" +#include "lib/uart_ansi.h" +#include "lib/pins.h" +#include "lib/arduino_pins.h" +#include "lib/sonar.h" + +ISR(PCINT0_vect) +{ + if (sonar_handle_pci()) return; +} + +// All PCINT vectors must call sonar_handle_pci +// This way, they are linked to PCINT0 +// so we can avoid code duplication +ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect)); +ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect)); + + +// Timer overflow - if sonar has a timeout -> 0xFFFF in result. +ISR(TIMER1_OVF_vect) +{ + if (sonar_handle_t1ovf()) return; +} + + +void main() +{ + uart_init(9600); + vt_init(); + + sonar_t so; + sonar_t so2; + + sonar_init(&so, A0, A1); + sonar_init(&so2, A2, A3); + + sei(); + + // end + int16_t res; + while(1) { + vt_clear(); + vt_home(); + uart_puts_pgm(PSTR("SONAR\r\n===================")); + + // first + vt_goto(99, 99); // move cursor away + sonar_start(&so); + while(sonar_busy()); + res = sonar_result(); + + // print value + vt_goto(0, 2); + uart_puts_pgm(PSTR("A: ")); + + if (res < 0) { + uart_puts_pgm(PSTR("No Obstacle")); + } else { + uart_puti(res, 1); + uart_puts_pgm(PSTR(" cm")); + } + + // second + vt_goto(99, 99); // move cursor away + sonar_start(&so2); + while(sonar_busy()); + res = sonar_result(); + + // print value + vt_goto(0, 3); + uart_puts_pgm(PSTR("B: ")); + + if (res < 0) { + uart_puts_pgm(PSTR("No Obstacle")); + } else { + uart_puti(res, 1); + uart_puts_pgm(PSTR(" cm")); + } + + vt_goto(99, 99); // move cursor away + _delay_ms(200); + } +} diff --git a/devel/xxx/Makefile b/devel/xxx/Makefile new file mode 100644 index 0000000..45868f3 --- /dev/null +++ b/devel/xxx/Makefile @@ -0,0 +1,147 @@ +## === CPU settings === +# CPU type +MCU = atmega328p +# CPU frequency +F_CPU = 16000000 +# Fuses +LFUSE = 0xFF +HFUSE = 0xDE +EFUSE = 0x05 + + +## === Source files === +# Main C file +MAIN = main.c +# Extra C files in this folder +LOCAL_SOURCE = fat16.c + +# Library directory (with C files) +EXTRA_SOURCE_DIR = lib/ +# C files in the library directory +EXTRA_SOURCE_FILES = + + +## === Programmer === +PROGRAMMER_TYPE = arduino +PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0 + + +## === 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 + + +# --------------------------------------------------------------------------- + +## Defined programs / locations +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +AVRSIZE = avr-size +AVRDUDE = avrdude + +## === File lists === +TARGET = $(strip $(basename $(MAIN))) +SRC1 = $(TARGET).c +SRC = $(SRC1) +EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES)) +SRC += $(EXTRA_SOURCE) +SRC += $(LOCAL_SOURCE) + +HEADERS = $(SRC:.c=.h) +OBJ = $(SRC:.c=.o) + + +## === File generation === +all: $(TARGET).hex size +pre: $(TARGET).pre + +%.hex: %.elf + $(OBJCOPY) -R .eeprom -O ihex $< $@ + +%.elf: $(SRC) + $(CC) $(CFLAGS_BUILD) $(SRC) --output $@ + +%.pre: $(SRC1) + $(CC) $(CFLAGS) -E $(SRC1) --output $@ + +%.eeprom: %.elf + $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +# Show debug info +debug: + @echo + @echo "Source files:" $(SRC) + @echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD) + @echo + + +# Disassemble the ELF +disassemble: $(TARGET).lst +dis: disassemble +lst: disassemble + +# Make eeprom file +eeprom: $(TARGET).eeprom + +# Show how big the resulting program is +size: $(TARGET).elf + $(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf + +# Clean all produced trash +clean: + rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \ + $(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \ + $(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \ + $(TARGET).eeprom + +# Clean all trash +purge: + rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~ + + +## === avrdude === + +flash: $(TARGET).hex + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$< + +flashe: $(TARGET).eeprom + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$< + +shell: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt + +fser: all flash serial + +ser: + gtkterm -p /dev/ttyUSB0 + +cl: + ./client /dev/ttyUSB0 9600 + +fcl: all flash + ./client /dev/ttyUSB0 9600 + +# === fuses === + +FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m + +fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \ + $(PROGRAMMER_ARGS) $(FUSE_STRING) +show_fuses: + $(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv + +set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m +set_default_fuses: fuses diff --git a/devel/xxx/client b/devel/xxx/client new file mode 100755 index 0000000000000000000000000000000000000000..02f9449a22ecd2d370135c0a762a783e3c0474da GIT binary patch literal 10160 zcmc&)eQaCR6~DHd#{F`f0;RMCywXCcR+E;tw2-uR8n-Vj{h&=crcqv8+iA=aJF=fk zi|7bSVf8{sv`wr+Vv8m;I&FVM6RIjSwJF`2Z9-c>z|cNW#Q@n2Y=st7XleF4_ub>X z_hM^k(zF}-oqK-g3Kk>P~NQocgV~ry1?WFQ;v`*l{b+>Dr?fGYD|`?5CI90 z9mOjAk_BxyGl~wXI7T@hWk)R8%~f`Dl|Iu^a*V{3>qm8?-vZ@tfjb0__z)4%B%c#h zwgs?l?-_B*8?#IWV^&CJn8r<5FlD>@U?=OR;VS^1BJU20u!--}uymj<%?O?Z^Gx-KN0uT!=i`I1{x)IsCy2cwGhj zp$hn274S?2JW&BZPyv4$cmO|VngO6(y$CCZud9IXtAOvSfPcLLzOw?Z0k0J|h{4(I z$O)_qW?BkD_>cqNs_hA7P#{s0$d) z0iJi)CzF`r9`R#^<>n=)k?m3NlnS-&lG2=>E_3FC+nLrt>p0+cCYi&MJ=pUEI-rv+C_v6S{$aGyngp9NR1ASvy&;N15lIAp7`)#m8|p*=BdR26;!q1N{s?`czMd{rYvvRXDAoC|k-ljeN zPwC*)RSz6!`SaST!g|ehMtk+Dab3yV4E9!YGx?F__cnwPzsS|L!LX1*V7ty#1p&D( zoTmOg>Bk3$*0)~ds>Xf*yOOhy$Y6YQSMd?pP#z;EkU#K&md~B-JMe+)u_YKrZ+inm z%b$8_J|aIsW8!2hTBGm+8tS+?M1YM%F7_@K0!E(PSG4}fS*>r_uk{Pha(rX{HrffVKM+x zzW)ozF}N4j9E)72IX2oKxsrbq_)cgc=xH+Ok-{mcL3Dz~4x~SV^ibq-?}5wW+w*Ep zL@oondWA}=`g1i^bENPzEXJPr{b|)4?OOi8(R}WCM0@mv+Y9Ghk!PTok6c1@Lod}+ zX!uDFU%+91QyUJQDpuAv=c+gQ;sgeha(FxJ)}zJ^RggLnpH zeFL?maqHN+k;oP3iLq74PzA=miVThVv0IR#;XXDG85-wfwaCx_AM+wZBYOaa&l>WI z-hAZvNQ6of{gF#DNYt{KDt)+Z$O0XcVP7iM+@C){6@YR*BsMsI{t#7s^Cie-w`lo4 zLhtp<7CjzEvYR0sfzWIcEjFt4Z$8@}!8jwc=bUEwTmjB6L&4%)+4mi|GM=kGj`2D^ zb{iOxn{%>&m8ftRg6!)qxcUwh#ACx_Q!y?sk5x%UTkI!k87q8-G7ISs`RjhooM zC4a6Z|7jCEj9>dVt?#r;TRWCJM+@*bcZDAa?+QN{*0BVX=Klq(%hH=#qUk-qIhoBS zQ+onE(M+^EVI(qv`gme*GL~33T`Z2{eLLTCPdkFA;ZTnNehK;jYVj!Ob~MH7pizv_ zi=f}cT)Gw`KLffF^jXkW&{shX&>$M~hoBFDz6kmX=oL_Y*Sj9sE?oQkuK6>oy#ual zKjHL|{T9ky3d*Uxz7UI`K>CM18y^qAukiUd`sUtSGvi@zuUJ3to~3s#T1Y-frwPBk zs7DRyg?;`f-5X|2^-Oo6Xeme4MFREv9JC~Ne?np@KL~g|>V3UczFmr?{CVK3AzxyZ z$0p>z0lp4$`erZr&rHbQ1>6QXefyT=?)yvSPeI(@hx}HnJZjoE0b2z5Amj;>H~Rcf zyBmFTzvqeg0*9wG`j$LZrTOZfoT~ZO^i^;5g?fBz!oIq&Z%Lys06pk8`njzxH1X~35S|lz{6kYro<2Y*4Y)%@O5emUO3s{1l%1>i>l9@|A3T)KtM6)V z`y;A?JpTFHQ;tFCU#bd`nPB{g;yLbiDHVbidrDkBrl+h=r_#r?lsvcRdBxW&xoQ2s zfAYD7v!pYsU*A;peMLW2bgDNbP39tF-KgkJMLQJTtLT%8KBMT*6g{Ts8AY9O zZQ8Km?!Xe9F5Dhi8C)A&5m-^Td{y0@bt?l)dNPSjqAL;2CT_<%nBCuPM0bN48IyK$ zE}6m-+#`aiw2=sg8=IFI(LIXWlgb5m=aM-6NXA8wxXviHp27J36#SVKn@TC!o5*C7 z>6DGpAwvvNGEljmE<*&9sU)68VjrFzU?5A!qefH&6Pkf)ZjhZos6OAG#ug)l%<#+cW1LA7)y6|CsKy9_3XTdX0tnF2f@*PbwOF&BkIfI zQ%dvH>db?aIi8<(e5&AiY{#obx$*D8s=)Kcu0Kui{IlcJOY_u@&nT@|c6_E7Qsdf= z&nlgJ+Hs%YbB}q;a^RZMcfQXal>ToJzf<+%b+}vNliT@+%Fm#~|De>L z++Qbwm#f#A3V5Y<_>=TsD-P9!kef(pm$-y%kNbcJY>3Hp121=e__)-cJPw}%jwmOkpC~^=s(<J|w;43TOJAhOC&UxAnJYcPm z%BO+Xy61``j`}`IxR_YSrYQY>;MBi=nh}x+e-9l|_#4wrTz<<#<9UVCF$<-HdLhN*JY*e?B8m92vWW19Eg(KtANgw zxP)wvTPonIfCp@vCey6^|5Vji?j<1FsqptzdoEG7u?qel22TCujK2?fK-pT!bIN~2 zl`Ho+Q22QT|G$>_I7pVmNBwM4jbbb&d%@Muw8Fy-qEV- z0>|))J;^M-z;vTq$C-O7kribiU5}^rJzeSD(Jno1q%&DPn%gJvS<};n9dtandiAR1 z@LWborw=Uib4kZ1P-Z{Q`RM~Ip6l-34-*TgQ?NEwI_yWt*+eE8?UJ!?+#cQ>(IZ=$ z5WHCv&fARRLT~!Umhk504bZYk zg#45=qcU$+>-7$`JM|RHaG{h{mrc$9Y&TC6!n*`U783+hpd!H($n?$x)eX|bUzn$2QPsDRD8DaEL3t8zW2V_@(or4hqZ%06D?u!aoR zUh*c)5r%9H^N!3eF|W_;n02-J@AGsnfLCMbdqKEE;E=FhQ{r<0lQVTWPxKc2XfLkR zOZyhSXAeMTP5eG%Y&kMkd*0vFD~F3%QBkLT6Yx*5cjxlk-60@!ZXt=NGfC-x6!<$t z!D0(CGw@@3-Y*R(;1V?s5}kKYmhJgmf$m|k6qoFIUv)?Y%I6_akx98@R?v4aokei@ zy#K1NGFABfsn}9Etp6>j(b)#`yib!iMv!s+o$;IAg?I!R3YG17KX*hG*sc`0d}sX+ zD*HyI$LBMblmVaT5KCuPPW$fxqc)-VDDipL01XNx=T1g7t0}}YkDt|^_mM-&KHz9@ zzp`XX`wFW)f47XPKr@a4*-p6;&pPaRU)rP&1=(;2okasM$kjEoOIngcTNepfY=Q{TzI0;3xI z*q-;--Y;qY7Hla*w&(q-|4Z7_K90s7+w*>%|G$X;kBG-7$Is*7eMkAcuP@X>fW-PH zH^DPL27xtxJ`X*w><8IUQMO}x(P7W~j{&u*;W*h1+c8i31;V)g{Czv9?CV%j(SU=e z0|koTsmJ!WIrMorF{Ns9*;dsNRlb)MmC(W3#=g~llnyYEdQ^pPME(x^xcz|cNW#Q@n2Y=st7XleF4_ub>X z_hM^k(zF}-oqK-g3Kk>P~NQocgV~ry1?WFQ;v`*l{b+>Dr?fGYD|`?5CI90 z9mOjAk_BxyGl~wXI7T@hWk)R8%~f`Dl|Iu^a*V{3>qm8?-vZ@tfjb0__z)4%B%c#h zwgs?l?-_B*8?#IWV^&CJn8r<5FlD>@U?=OR;VS^1BJU20u!--}uymj<%?O?Z^Gx-KN0uT!=i`I1{x)IsCy2cwGhj zp$hn274S?2JW&BZPyv4$cmO|VngO6(y$CCZud9IXtAOvSfPcLLzOw?Z0k0J|h{4(I z$O)_qW?BkD_>cqNs_hA7P#{s0$d) z0iJi)CzF`r9`R#^<>n=)k?m3NlnS-&lG2=>E_3FC+nLrt>p0+cCYi&MJ=pUEI-rv+C_v6S{$aGyngp9NR1ASvy&;N15lIAp7`)#m8|p*=BdR26;!q1N{s?`czMd{rYvvRXDAoC|k-ljeN zPwC*)RSz6!`SaST!g|ehMtk+Dab3yV4E9!YGx?F__cnwPzsS|L!LX1*V7ty#1p&D( zoTmOg>Bk3$*0)~ds>Xf*yOOhy$Y6YQSMd?pP#z;EkU#K&md~B-JMe+)u_YKrZ+inm z%b$8_J|aIsW8!2hTBGm+8tS+?M1YM%F7_@K0!E(PSG4}fS*>r_uk{Pha(rX{HrffVKM+x zzW)ozF}N4j9E)72IX2oKxsrbq_)cgc=xH+Ok-{mcL3Dz~4x~SV^ibq-?}5wW+w*Ep zL@oondWA}=`g1i^bENPzEXJPr{b|)4?OOi8(R}WCM0@mv+Y9Ghk!PTok6c1@Lod}+ zX!uDFU%+91QyUJQDpuAv=c+gQ;sgeha(FxJ)}zJ^RggLnpH zeFL?maqHN+k;oP3iLq74PzA=miVThVv0IR#;XXDG85-wfwaCx_AM+wZBYOaa&l>WI z-hAZvNQ6of{gF#DNYt{KDt)+Z$O0XcVP7iM+@C){6@YR*BsMsI{t#7s^Cie-w`lo4 zLhtp<7CjzEvYR0sfzWIcEjFt4Z$8@}!8jwc=bUEwTmjB6L&4%)+4mi|GM=kGj`2D^ zb{iOxn{%>&m8ftRg6!)qxcUwh#ACx_Q!y?sk5x%UTkI!k87q8-G7ISs`RjhooM zC4a6Z|7jCEj9>dVt?#r;TRWCJM+@*bcZDAa?+QN{*0BVX=Klq(%hH=#qUk-qIhoBS zQ+onE(M+^EVI(qv`gme*GL~33T`Z2{eLLTCPdkFA;ZTnNehK;jYVj!Ob~MH7pizv_ zi=f}cT)Gw`KLffF^jXkW&{shX&>$M~hoBFDz6kmX=oL_Y*Sj9sE?oQkuK6>oy#ual zKjHL|{T9ky3d*Uxz7UI`K>CM18y^qAukiUd`sUtSGvi@zuUJ3to~3s#T1Y-frwPBk zs7DRyg?;`f-5X|2^-Oo6Xeme4MFREv9JC~Ne?np@KL~g|>V3UczFmr?{CVK3AzxyZ z$0p>z0lp4$`erZr&rHbQ1>6QXefyT=?)yvSPeI(@hx}HnJZjoE0b2z5Amj;>H~Rcf zyBmFTzvqeg0*9wG`j$LZrTOZfoT~ZO^i^;5g?fBz!oIq&Z%Lys06pk8`njzxH1X~35S|lz{6kYro<2Y*4Y)%@O5emUO3s{1l%1>i>l9@|A3T)KtM6)V z`y;A?JpTFHQ;tFCU#bd`nPB{g;yLbiDHVbidrDkBrl+h=r_#r?lsvcRdBxW&xoQ2s zfAYD7v!pYsU*A;peMLW2bgDNbP39tF-KgkJMLQJTtLT%8KBMT*6g{Ts8AY9O zZQ8Km?!Xe9F5Dhi8C)A&5m-^Td{y0@bt?l)dNPSjqAL;2CT_<%nBCuPM0bN48IyK$ zE}6m-+#`aiw2=sg8=IFI(LIXWlgb5m=aM-6NXA8wxXviHp27J36#SVKn@TC!o5*C7 z>6DGpAwvvNGEljmE<*&9sU)68VjrFzU?5A!qefH&6Pkf)ZjhZos6OAG#ug)l%<#+cW1LA7)y6|CsKy9_3XTdX0tnF2f@*PbwOF&BkIfI zQ%dvH>db?aIi8<(e5&AiY{#obx$*D8s=)Kcu0Kui{IlcJOY_u@&nT@|c6_E7Qsdf= z&nlgJ+Hs%YbB}q;a^RZMcfQXal>ToJzf<+%b+}vNliT@+%Fm#~|De>L z++Qbwm#f#A3V5Y<_>=TsD-P9!kef(pm$-y%kNbcJY>3Hp121=e__)-cJPw}%jwmOkpC~^=s(<J|w;43TOJAhOC&UxAnJYcPm z%BO+Xy61``j`}`IxR_YSrYQY>;MBi=nh}x+e-9l|_#4wrTz<<#<9UVCF$<-HdLhN*JY*e?B8m92vWW19Eg(KtANgw zxP)wvTPonIfCp@vCey6^|5Vji?j<1FsqptzdoEG7u?qel22TCujK2?fK-pT!bIN~2 zl`Ho+Q22QT|G$>_I7pVmNBwM4jbbb&d%@Muw8Fy-qEV- z0>|))J;^M-z;vTq$C-O7kribiU5}^rJzeSD(Jno1q%&DPn%gJvS<};n9dtandiAR1 z@LWborw=Uib4kZ1P-Z{Q`RM~Ip6l-34-*TgQ?NEwI_yWt*+eE8?UJ!?+#cQ>(IZ=$ z5WHCv&fARRLT~!Umhk504bZYk zg#45=qcU$+>-7$`JM|RHaG{h{mrc$9Y&TC6!n*`U783+hpd!H($n?$x)eX|bUzn$2QPsDRD8DaEL3t8zW2V_@(or4hqZ%06D?u!aoR zUh*c)5r%9H^N!3eF|W_;n02-J@AGsnfLCMbdqKEE;E=FhQ{r<0lQVTWPxKc2XfLkR zOZyhSXAeMTP5eG%Y&kMkd*0vFD~F3%QBkLT6Yx*5cjxlk-60@!ZXt=NGfC-x6!<$t z!D0(CGw@@3-Y*R(;1V?s5}kKYmhJgmf$m|k6qoFIUv)?Y%I6_akx98@R?v4aokei@ zy#K1NGFABfsn}9Etp6>j(b)#`yib!iMv!s+o$;IAg?I!R3YG17KX*hG*sc`0d}sX+ zD*HyI$LBMblmVaT5KCuPPW$fxqc)-VDDipL01XNx=T1g7t0}}YkDt|^_mM-&KHz9@ zzp`XX`wFW)f47XPKr@a4*-p6;&pPaRU)rP&1=(;2okasM$kjEoOIngcTNepfY=Q{TzI0;3xI z*q-;--Y;qY7Hla*w&(q-|4Z7_K90s7+w*>%|G$X;kBG-7$Is*7eMkAcuP@X>fW-PH zH^DPL27xtxJ`X*w><8IUQMO}x(P7W~j{&u*;W*h1+c8i31;V)g{Czv9?CV%j(SU=e z0|koTsmJ!WIrMorF{Ns9*;dsNRlb)MmC(W3#=g~llnyYEdQ^pPME(x^xc +#include +#include +#include +#include + +#include "serial.h" + +int main(int argc, char const *argv[]) +{ + if (argc < 2) { fprintf(stderr, "Missing parameter \n"); return 1; } + + int baud = 9600; + if (argc == 3) sscanf(argv[2], "%d", &baud); + + int fd = serial_open(argv[1], baud); + + // Wait for the Arduino to start + usleep(1500000); + + // Redirecting stdin/stdout to arduino + while(1) { + char buf[1]; + if (fread(buf, 1, 1, stdin) > 0) { + serial_write(fd, buf[0]); + fflush(stdout); + } + + char c; + c = serial_read(fd, 10); + if (c > 0) { + putchar(c); + fflush(stdout); + } + } +} + diff --git a/devel/xxx/clientd/serial.c b/devel/xxx/clientd/serial.c new file mode 100644 index 0000000..5516304 --- /dev/null +++ b/devel/xxx/clientd/serial.c @@ -0,0 +1,89 @@ +#define _POSIX_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "serial.h" + + +/** Open a serial port */ +int serial_open(const char* port, const unsigned int baud) +{ + int fd = open(port, O_RDWR | O_NONBLOCK); + + struct termios tio; + memset(&tio, 0, sizeof(tio)); + + speed_t bd = baud; + switch(bd) { + case 1200: bd = B1200; break; + case 1800: bd = B1800; break; + case 2400: bd = B2400; break; + case 4800: bd = B4800; break; + case 9600: bd = B9600; break; + case 19200: bd = B19200; break; + case 38400: bd = B38400; break; + } + + tio.c_cflag = bd | CS8 | CLOCAL | CREAD | CRTSCTS; + tio.c_iflag = IGNPAR; + + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &tio); + return fd; +} + + +/** Close a serial port */ +int serial_close(int fd) +{ + return close(fd); +} + + +/** Write a byte. Returns false on failure */ +int serial_write(int fd, uint8_t b) +{ + return write(fd, &b, 1); +} + + +int serial_puts(int fd, const char* str) +{ + int len = strlen(str); + return write(fd, str, len); +} + + +uint8_t serial_read(int fd, int timeout) +{ + uint8_t b[1]; + do { + int n = read(fd, b, 1); + if (n == -1) return -1; + if (n == 0) { + usleep(1 * 1000); // wait 1 ms + timeout--; + continue; + } + return b[0]; + } while(timeout > 0); + return -1; +} + + +int serial_flush(int fd) +{ + sleep(2); + return tcflush(fd, TCIOFLUSH); +} diff --git a/devel/xxx/clientd/serial.h b/devel/xxx/clientd/serial.h new file mode 100644 index 0000000..aebcbf7 --- /dev/null +++ b/devel/xxx/clientd/serial.h @@ -0,0 +1,27 @@ +#pragma once + +#include + + +/** Open a serial port */ +int serial_open(const char* port, const unsigned int baud); + + +/** Close a serial port */ +int serial_close(int fd); + + +/** Write a byte. Returns false on failure */ +int serial_write(int fd, uint8_t b); + + +/** Send a string */ +int serial_puts(int fd, const char* str); + + +/** Read a byte */ +uint8_t serial_read(int fd, int timeout); + + +/** Flush */ +int serial_flush(int fd); diff --git a/devel/xxx/fat16.c b/devel/xxx/fat16.c new file mode 100644 index 0000000..6658830 --- /dev/null +++ b/devel/xxx/fat16.c @@ -0,0 +1,1112 @@ +//#include +#include +#include +#include + +#include "fat16.h" + + + +// ============== INTERNAL PROTOTYPES ================== + +/** Read boot sector from given address */ +void read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr); + +/** Find absolute address of first BootSector. Returns 0 on failure. */ +uint32_t find_bs(const BLOCKDEV* dev); + +/** Get cluster's starting address */ +uint32_t clu_addr(const FAT16* fat, const uint16_t cluster); + +/** Find following cluster using FAT for jumps */ +uint16_t next_clu(const FAT16* fat, uint16_t cluster); + +/** Find relative address in a file, using FAT for cluster lookup */ +uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr); + +/** Read a file entry from directory (dir starting cluster, entry number) */ +void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num); + +/** Allocate and chain new cluster to a chain starting at given cluster */ +bool append_cluster(const FAT16* fat, const uint16_t clu); + +/** Allocate a new cluster, clean it, and mark with 0xFFFF in FAT */ +uint16_t alloc_cluster(const FAT16* fat); + +/** Zero out entire cluster. */ +void wipe_cluster(const FAT16* fat, const uint16_t clu); + +/** Free cluster chain, starting at given number */ +void free_cluster_chain(const FAT16* fat, uint16_t clu); + +/** + * Check if there is already a file of given RAW name + * Raw name - name as found on disk, not "display name". + */ +bool dir_contains_file_raw(FAT16_FILE* dir, char* fname); + +/** Write a value into FAT */ +void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value); + +/** Read a value from FAT */ +uint16_t read_fat(const FAT16* fat, const uint16_t cluster); + +/** Go through a directory, and open first NONE or DELETED file. */ +bool find_empty_file_slot(FAT16_FILE* file); + + +// =========== INTERNAL FUNCTION IMPLEMENTATIONS ========= + + +uint16_t read16(const BLOCKDEV* dev) +{ + uint16_t a; + dev->load(&a, 2); + return a; +} + + +void write16(const BLOCKDEV* dev, const uint16_t val) +{ + dev->store(&val, 2); +} + +/** Find absolute address of first boot sector. Returns 0 on failure. */ +uint32_t find_bs(const BLOCKDEV* dev) +{ + // Reference structure: + // + // typedef struct __attribute__((packed)) { + // uint8_t first_byte; + // uint8_t start_chs[3]; + // uint8_t partition_type; + // uint8_t end_chs[3]; + // uint32_t start_sector; + // uint32_t length_sectors; + // } PartitionTable; + + uint16_t addr = 0x1BE + 4; // fourth byte of structure is the type. + uint32_t tmp = 0; + uint16_t tmp2; + + for (uint8_t i = 0; i < 4; i++, addr += 16) + { + // Read partition type + dev->seek(addr); + tmp = dev->read(); + + // Check if type is valid + if (tmp == 4 || tmp == 6 || tmp == 14) + { + // read MBR address + dev->rseek(3);// skip 3 bytes + dev->load(&tmp, 4); + + tmp = tmp << 9; // multiply address by 512 (sector size) + + // Verify that the boot sector has a valid signature mark + dev->seek(tmp + 510); + dev->load(&tmp2, 2); + if (tmp2 != 0xAA55) continue; // continue to next entry + + // return absolute MBR address + return tmp; + } + } + + return 0; +} + + +/** Read the boot sector */ +void read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr) +{ + dev->seek(addr + 13); // skip 13 + + dev->load(&(info->sectors_per_cluster), 6); // spc, rs, nf, re + + info->total_sectors = 0; + dev->load(&(info->total_sectors), 2); // short sectors + + dev->rseek(1); // md + + dev->load(&(info->fat_size_sectors), 2); + + dev->rseek(8); // spt, noh, hs + + // read or skip long sectors field + if (info->total_sectors == 0) + { + dev->load(&(info->total_sectors), 4); + } + else + { + dev->rseek(4); // tsl + } + + dev->rseek(7); // dn, ch, bs, vi + + dev->load(&(info->volume_label), 11); +} + + +void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value) +{ + fat->dev->seek(fat->fat_addr + (cluster * 2)); + write16(fat->dev, value); +} + + +uint16_t read_fat(const FAT16* fat, const uint16_t cluster) +{ + fat->dev->seek(fat->fat_addr + (cluster * 2)); + return read16(fat->dev); +} + + +/** Get cluster starting address */ +uint32_t clu_addr(const FAT16* fat, const uint16_t cluster) +{ + if (cluster < 2) return fat->rd_addr; + return fat->data_addr + (cluster - 2) * fat->bs.bytes_per_cluster; +} + + +uint16_t next_clu(const FAT16* fat, uint16_t cluster) +{ + return read_fat(fat, cluster); +} + + +/** Find file-relative address in fat table */ +uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr) +{ + while (addr >= fat->bs.bytes_per_cluster) + { + cluster = next_clu(fat, cluster); + if (cluster == 0xFFFF) return 0xFFFF; // fail + addr -= fat->bs.bytes_per_cluster; + } + + return clu_addr(fat, cluster) + addr; +} + + +/** + * Zero out entire cluster + * This is important only for directory clusters, so we can + * zero only every first byte of each file entry, to indicate + * that it is unused (FT_NONE). + */ +void wipe_cluster(const FAT16* fat, const uint16_t clu) +{ + uint32_t addr = clu_addr(fat, clu); + + const BLOCKDEV* dev = fat->dev; + + dev->seek(addr); + + for (uint32_t b = 0; b < fat->bs.bytes_per_cluster; b += 32) + { + dev->write(0); + dev->rseek(32); + } +} + + +/** Allocate a new cluster, clean it, and mark with 0xFFFF in FAT */ +uint16_t alloc_cluster(const FAT16* fat) +{ + // find new unclaimed cluster that can be added to the chain. + uint16_t i, b; + for (i = 2; i < fat->bs.fat_size_sectors * 256; i++) + { + // read value from FAT + b = read_fat(fat, i); + if (b == 0) // unused cluster + { + // Write FFFF to "i", to mark end of file + write_fat(fat, i, 0xFFFF); + + // Wipe the cluster + wipe_cluster(fat, i); + + return i; + } + } + + return 0xFFFF;//error code +} + + +/** Allocate and chain new cluster to a chain starting at given cluster */ +bool append_cluster(const FAT16* fat, const uint16_t clu) +{ + uint16_t clu2 = alloc_cluster(fat); + if (clu2 == 0xFFFF) return false; + + // Write "i" to "clu" + write_fat(fat, clu, clu2); + + return true; +} + + +void free_cluster_chain(const FAT16* fat, uint16_t clu) +{ + do + { + // get address of the next cluster + const uint16_t clu2 = read_fat(fat, clu); + + // mark cluster as unused + write_fat(fat, clu, 0x0000); + + // advance + clu = clu2; + } + while (clu != 0xFFFF); +} + + +/** + * Check if there is already a file of given RAW name + * Raw name - name as found on disk, not "display name". + */ +bool dir_contains_file_raw(FAT16_FILE* dir, char* fname) +{ + do + { + bool diff = false; + for (uint8_t i = 0; i < 11; i++) + { + if (dir->name[i] != fname[i]) + { + diff = true; + break; + } + } + + if (!diff) return true; + + } + while (fat16_next(dir)); + + return false; +} + + +/** + * Read a file entry + * + * dir_cluster ... directory start cluster + * num ... entry number in the directory + */ +void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num) +{ + // Resolve starting address + uint32_t addr; + if (dir_cluster == 0) + { + addr = clu_addr(fat, dir_cluster) + num * 32; // root directory, max 512 entries. + } + else + { + addr = clu_offs(fat, dir_cluster, num * 32); // cluster + N (wrapping to next cluster if needed) + } + + fat->dev->seek(addr); + fat->dev->load(file, 12); // name, ext, attribs + fat->dev->rseek(14); // skip 14 bytes + fat->dev->load(((void*)file) + 12, 6); // read remaining bytes + + file->clu = dir_cluster; + file->num = num; + + // Resolve filename & type + + file->type = FT_FILE; + + const uint8_t c = file->name[0]; + switch (c) + { + case 0x00: + file->type = FT_NONE; + return; + + case 0xE5: + file->type = FT_DELETED; + return; + + case 0x05: // Starting with 0xE5 + file->type = FT_FILE; + file->name[0] = 0xE5; // convert to the real character + break; + + case 0x2E: + if (file->name[1] == 0x2E) + { + // ".." directory + file->type = FT_PARENT; + } + else + { + // "." directory + file->type = FT_SELF; + } + break; + + default: + if (c < 32) + { + file->type = FT_INVALID; // File is corrupt, treat it as invalid + } + else + { + file->type = FT_FILE; + } + } + + // handle subdir, label + if (file->attribs & FA_DIR && file->type == FT_FILE) + { + file->type = FT_SUBDIR; + } + else if (file->attribs == FA_LABEL) + { + file->type = FT_LABEL; // volume label special file + } + else if (file->attribs == 0x0F) + { + file->type = FT_LFN; // long name special file, can be ignored + } + + // add a FAT pointer + file->fat = fat; + + // Init cursors + fat16_fseek(file, 0); +} + + +void delete_file_do(FAT16_FILE* file) +{ + const FAT16* fat = file->fat; + + // seek to file record + fat->dev->seek(clu_offs(fat, file->clu, file->num * 32)); + + // mark as deleted + fat->dev->write(0xE5); // "deleted" mark + + // free allocated clusters + free_cluster_chain(fat, file->clu_start); + + file->type = FT_DELETED; +} + + + +/** + * Write information into a file header. + * "file" is an open handle. + */ +void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start) +{ + const BLOCKDEV* dev = file->fat->dev; + + const uint32_t entrystart = clu_offs(file->fat, file->clu, file->num * 32); + + // store the file name + dev->seek(entrystart); + dev->store(fname_raw, 11); + + // attributes + dev->write(attribs); + + // 10 reserved, 2+2 date & time + // (could just skip, but better to fill with zeros) + for (uint8_t i = 0; i < 14; i++) + { + dev->write(0); + } + + // addr of the first file cluster + write16(dev, clu_start); + + // file size (uint32_t) + write16(dev, 0); + write16(dev, 0); + + // reopen file - load & parse the information just written + open_file(file->fat, file, file->clu, file->num); +} + + +/** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */ +bool find_empty_file_slot(FAT16_FILE* file) +{ + const uint16_t clu = file->clu; + const FAT16* fat = file->fat; + + // Find free directory entry that can be used + for (uint16_t num = 0; num < 0xFFFF; num++) + { + // root directory has fewer entries, error if trying + // to add one more. + if (file->clu == 0 && num >= fat->bs.root_entries) + return false; + + // Resolve addres of next file entry + uint32_t addr; + do + { + addr = clu_offs(fat, file->clu, num * 32); + + if (addr == 0xFFFF) + { + // end of chain of allocated clusters for the directory + // append new cluster, return false on failure + if (!append_cluster(fat, file->clu)) return false; + } + + // if new cluster was just added, repeat. + } + while (addr == 0xFFFF); + + // Open the file entry + open_file(fat, file, clu, num); + + // Check if can be overwritten + if (file->type == FT_DELETED || file->type == FT_NONE) + { + return true; + } + } + + return false; // not found. +} + + +// =============== PUBLIC FUNCTION IMPLEMENTATIONS ================= + +/** Initialize a FAT16 handle */ +void fat16_init(const BLOCKDEV* dev, FAT16* fat) +{ + const uint32_t bs_a = find_bs(dev); + fat->dev = dev; + read_bs(dev, &(fat->bs), bs_a); + fat->fat_addr = bs_a + (fat->bs.reserved_sectors * 512); + fat->rd_addr = bs_a + (fat->bs.reserved_sectors + fat->bs.fat_size_sectors * fat->bs.num_fats) * 512; + fat->data_addr = fat->rd_addr + (fat->bs.root_entries * 32); // entry is 32B long + + fat->bs.bytes_per_cluster = (fat->bs.sectors_per_cluster * 512); +} + + +/** + * Move file cursor to a position relative to file start + * Allows seek past end of file, will allocate new cluster if needed. + */ +bool fat16_fseek(FAT16_FILE* file, uint32_t addr) +{ + const FAT16* fat = file->fat; + + // Store as rel + file->cur_rel = addr; + + // Rewind and resolve abs, clu, ofs + file->cur_clu = file->clu_start; + + while (addr >= fat->bs.bytes_per_cluster) + { + uint32_t next; + + // Go to next cluster, allocate if needed + do + { + next = next_clu(fat, file->cur_clu); + if (next == 0xFFFF) + { + // reached end of allocated space + // add one more cluster + if (!append_cluster(fat, file->cur_clu)) + { + return false; + } + } + } + while (next == 0xFFFF); + + file->cur_clu = next; + addr -= fat->bs.bytes_per_cluster; + } + + file->cur_abs = clu_addr(fat, file->cur_clu) + addr; + file->cur_ofs = addr; + + // Physically seek to that location + fat->dev->seek(file->cur_abs); + + return true; +} + + +/** + * Check if file is a valid entry (to be shown) + */ +bool fat16_is_file_valid(const FAT16_FILE* file) +{ + switch (file->type) + { + case FT_FILE: + case FT_SUBDIR: + case FT_SELF: + case FT_PARENT: + return true; + + default: + return false; + } +} + + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len) +{ + if (file->cur_abs == 0xFFFF) + return false; // file at the end already + + if (file->cur_rel + len > file->size) + return false; // Attempt to read more than what is available + + const FAT16* fat = file->fat; + const BLOCKDEV* dev = fat->dev; + + while (len > 0 && file->cur_rel < file->size) + { + // How much can be read from the cluster + uint16_t chunk = MIN(file->size - file->cur_rel, MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len)); + + // read the chunk + dev->seek(file->cur_abs); + dev->load(target, chunk); + + // move the cursors + file->cur_abs += chunk; + file->cur_rel += chunk; + file->cur_ofs += chunk; + + // move target pointer + target += chunk; + + // reached end of cluster? + if (file->cur_ofs >= fat->bs.bytes_per_cluster) + { + file->cur_clu = next_clu(fat, file->cur_clu); + file->cur_abs = clu_addr(fat, file->cur_clu); + file->cur_ofs = 0; + } + + // subtract read length + len -= chunk; + } + + return true; +} + + +bool fat16_fwrite(FAT16_FILE* file, void* source, uint32_t len) +{ + const FAT16* fat = file->fat; + const BLOCKDEV* dev = fat->dev; + + + if (file->cur_abs == 0xFFFF) + return false; // file at the end already + + // Attempt to write past end of file + if (file->cur_rel + len >= file->size) + { + const uint32_t pos_start = file->cur_rel; + + // Seek to the last position + // -> fseek will allocate clusters + if (!fat16_fseek(file, pos_start + len)) + return false; // error in seek + + // Write starts beyond EOF - creating a zero-filled "hole" + if (file->cur_rel > file->size) + { + // Seek to the end of valid data + fat16_fseek(file, file->size); + + // fill space between EOF and start-of-write with zeros + uint32_t fill = pos_start - file->size; + + // repeat until all "fill" zeros are stored + while (fill > 0) + { + // How much will fit into this cluster + const uint16_t chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, fill); + + // write the zeros + dev->seek(file->cur_abs); + for (uint16_t i = 0; i < chunk; i++) + { + dev->write(0); + } + + // subtract from "needed" what was just placed + fill -= chunk; + + // advance cursors to the next cluster + file->cur_clu = next_clu(fat, file->cur_clu); + file->cur_abs = clu_addr(fat, file->cur_clu); + file->cur_ofs = 0; + } + } + + // Save new size + fat16_resize(file, pos_start + len); + + // Seek back to where it was before + fat16_fseek(file, pos_start); + } // (end zerofill) + + + // write the data + while (len > 0) + { + // How much can be stored in this cluster + const uint16_t chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len); + + // store the chunk + dev->seek(file->cur_abs); + dev->store(source, chunk); + + // advance cursors + file->cur_abs += chunk; + file->cur_rel += chunk; + file->cur_ofs += chunk; + + // Pointer arith! + source += chunk; // advance the source pointer + + // detect cluster overflow + if (file->cur_ofs >= fat->bs.bytes_per_cluster) + { + // advance to following cluster + file->cur_clu = next_clu(fat, file->cur_clu); + file->cur_abs = clu_addr(fat, file->cur_clu); + file->cur_ofs = 0; + } + + // subtract written length + len -= chunk; + } + + return true; +} + + + +/** Open next file in the directory */ +bool fat16_next(FAT16_FILE* file) +{ + const FAT16* fat = file->fat; + const BLOCKDEV* dev = fat->dev; + + if (file->clu == 0 && file->num >= fat->bs.root_entries) + return false; // attempt to read outside root directory. + + const uint32_t addr = clu_offs(fat, file->clu, (file->num + 1) * 32); + if (addr == 0xFFFF) + return false; // next file is out of the directory cluster + + // read first byte of the file entry + dev->seek(addr); + if (dev->read() == 0) + return false; // can't read (file is NONE) + + open_file(fat, file, file->clu, file->num + 1); + + return true; +} + + +/** Open previous file in the directory */ +bool fat16_prev(FAT16_FILE* file) +{ + if (file->num == 0) + return false; // first file already + + open_file(file->fat, file, file->clu, file->num - 1); + + return true; +} + + +/** Rewind to first file in directory */ +void fat16_first(FAT16_FILE* file) +{ + open_file(file->fat, file, file->clu, 0); +} + + +/** Open a directory denoted by the file. */ +bool fat16_opendir(FAT16_FILE* file) +{ + // Don't open non-dirs and "." directory. + if (!(file->attribs & FA_DIR) || file->type == FT_SELF) + return false; + + open_file(file->fat, file, file->clu_start, 0); + return true; +} + + +void fat16_root(const FAT16* fat, FAT16_FILE* file) +{ + open_file(fat, file, 0, 0); +} + + +/** + * Find a file with given "display name" in this directory. + * If file is found, "dir" will contain it's handle. + * Either way, "dir" gets modified and you may need to rewind it afterwards. + */ +bool fat16_find(FAT16_FILE* dir, const char* name) +{ + char fname[11]; + fat16_rawname(name, fname); + return dir_contains_file_raw(dir, fname); +} + +bool fat16_mkfile(FAT16_FILE* file, const char* name) +{ + // Convert filename to zero padded raw string + char fname[11]; + fat16_rawname(name, fname); + + // Abort if file already exists + bool exists = dir_contains_file_raw(file, fname); + fat16_first(file); // rewind dir + if (exists) + return false; // file already exists in the dir. + + + if (!find_empty_file_slot(file)) + return false; // error finding a slot + + // Write into the new slot + const uint16_t newclu = alloc_cluster(file->fat); + write_file_header(file, fname, 0, newclu); + + return true; +} + + +/** + * Create a sub-directory of given name. + * Directory is allocated and populated with entries "." and ".." + */ +bool fat16_mkdir(FAT16_FILE* file, const char* name) +{ + // Convert filename to zero padded raw string + char fname[11]; + fat16_rawname(name, fname); + + // Abort if file already exists + bool exists = dir_contains_file_raw(file, fname); + fat16_first(file); // rewind dir + if (exists) + return false; // file already exusts in the dir. + + if (!find_empty_file_slot(file)) + return false; // error finding a slot + + + // Write into the new slot + const uint16_t newclu = alloc_cluster(file->fat); + write_file_header(file, fname, FA_DIR, newclu); + + const uint32_t parent_clu = file->clu; + open_file(file->fat, file, file->clu_start, 0); + + write_file_header(file, ". ", FA_DIR, newclu); + + // Advance to next file slot + find_empty_file_slot(file); + + write_file_header(file, ".. ", FA_DIR, parent_clu); + + // rewind. + fat16_first(file); + + return true; +} + + +char* fat16_disk_label(const FAT16* fat, char* label_out) +{ + FAT16_FILE first; + fat16_root(fat, &first); + + if (first.type == FT_LABEL) + { + return fat16_dispname(&first, label_out); + } + + // find where spaces end + int8_t j = 10; + for (; j >= 0; j--) + { + if (fat->bs.volume_label[j] != ' ') break; + } + + // copy all until spaces + uint8_t i; + for (i = 0; i <= j; i++) + { + label_out[i] = fat->bs.volume_label[i]; + } + + label_out[i] = 0; // ender + + return label_out; +} + + +char* fat16_dispname(const FAT16_FILE* file, char* disp_out) +{ + // Cannot get name for special files + if (file->type == FT_NONE || // not-yet-used directory location + file->type == FT_DELETED || // deleted file entry + file->attribs == 0x0F) // long name special entry (system, hidden) + return NULL; + + // find first non-space + int8_t j = 7; + for (; j >= 0; j--) + { + if (file->name[j] != ' ') break; + } + + // j ... last no-space char + + uint8_t i; + for (i = 0; i <= j; i++) + { + disp_out[i] = file->name[i]; + } + + + // directory entry, no extension + if (file->type == FT_SUBDIR || file->type == FT_SELF || file->type == FT_PARENT) + { + disp_out[i] = 0; // end of string + return disp_out; + } + + + // add a dot + if (file->type != FT_LABEL) // volume label has no dot! + disp_out[i++] = '.'; + + // Add extension chars + for (j = 8; j < 11; j++, i++) + { + const char c = file->name[j]; + if (c == ' ') break; + disp_out[i] = c; + } + + disp_out[i] = 0; // end of string + + return disp_out; +} + + +char* fat16_rawname(const char* disp_in, char* raw_out) +{ + uint8_t name_c = 0, wr_c = 0; + bool filling = false; + bool at_ext = false; + for (; wr_c < 11; wr_c++) + { + // start filling with spaces if end of filename reached + uint8_t c = disp_in[name_c]; + // handle special rule for 0xE5 + if (name_c == 0 && c == 0xE5) + { + c = 0x05; + } + + if (c == '.' || c == 0) + { + if (!filling) + { + filling = true; + + if (c == '.') + { + name_c++; // skip the dot + c = disp_in[name_c]; + at_ext = true; + } + } + } + + // if at the start of ext + if (wr_c == 8) + { + if (!at_ext) + { + // try to advance past dot (if any) + while (true) + { + c = disp_in[name_c++]; + if (c == 0) break; + if (c == '.') + { + // read char PAST the dot + c = disp_in[name_c]; + at_ext = true; + break; + } + } + } + + // if c has valid char for extension + if (c != 0 && c != '.') + { + // start copying again. + filling = false; + } + } + + if (!filling) + { + // copy char of filename + raw_out[wr_c] = disp_in[name_c++]; + } + else + { + // add a filler space + raw_out[wr_c] = ' '; + } + } + + return raw_out; +} + + +/** Write new file size (also to the disk). Does not allocate clusters. */ +void fat16_resize(FAT16_FILE* file, uint32_t size) +{ + const FAT16* fat = file->fat; + const BLOCKDEV* dev = file->fat->dev; + + // Find address for storing the size + const uint32_t addr = clu_offs(fat, file->clu, file->num * 32 + 28); + file->size = size; + + dev->seek(addr); + dev->store(&size, 4); + + // Seek to the end of the file, to make sure clusters are allocated + fat16_fseek(file, size - 1); + + const uint16_t next = next_clu(fat, file->cur_clu); + if (next != 0xFFFF) + { + free_cluster_chain(fat, next); + + // Mark that there's no further clusters + write_fat(fat, file->cur_clu, 0xFFFF); + } +} + +/** Delete a simple file */ +bool fat16_rmfile(FAT16_FILE* file) +{ + if (file->type != FT_FILE) + return false; // not a simple file + + delete_file_do(file); + return true; +} + + +/** Delete an empty directory */ +bool fat16_rmdir(FAT16_FILE* file) +{ + if (file->type != FT_SUBDIR) + return false; // not a subdirectory entry + + const FAT16* fat = file->fat; + + const uint16_t dir_clu = file->clu; + const uint16_t dir_num = file->num; + + // Look for valid files and subdirs in the directory + if (!fat16_opendir(file)) + return false; // could not open + + uint8_t cnt = 0; + do + { + // Stop on apparent corrupt structure (missing "." or "..") + // Can safely delete the folder. + if (cnt == 0 && file->type != FT_SELF) break; + if (cnt == 1 && file->type != FT_PARENT) break; + + // Found valid file + if (file->type == FT_SUBDIR || file->type == FT_FILE) + { + // Valid child file was found, aborting. + // reopen original file + open_file(fat, file, dir_clu, dir_num); + return false; + } + + if (cnt < 2) cnt++; + } + while (fat16_next(file)); + + // reopen original file + open_file(fat, file, dir_clu, dir_num); + + // and delete as ordinary file + delete_file_do(file); + + return true; +} + + +bool fat16_parent(FAT16_FILE* file) +{ + const uint16_t clu = file->clu; + const uint16_t num = file->num; + + // open second entry of the directory + open_file(file->fat, file, file->clu, 1); + + // if it's a valid PARENT link, follow it. + if (file->type == FT_PARENT) + { + open_file(file->fat, file, file->clu_start, 0); + return true; + } + else + { + // maybe in root already? + + // reopen original file + open_file(file->fat, file, clu, num); + return false; + } +} diff --git a/devel/xxx/fat16.h b/devel/xxx/fat16.h new file mode 100644 index 0000000..ff34d92 --- /dev/null +++ b/devel/xxx/fat16.h @@ -0,0 +1,260 @@ +#pragma once + +/** Abstract block device interface */ +typedef struct +{ + // Sequential read + void (*load)(void* dest, const uint16_t len); + // Sequential write + void (*store)(const void* src, const uint16_t len); + // Sequential byte write + void (*write)(const uint8_t b); + // Sequential byte read + uint8_t (*read)(void); + // Absolute seek + void (*seek)(const uint32_t); + // Relative seek + void (*rseek)(const int16_t); +} BLOCKDEV; + + +// ------------------------------- + +/** file types (values don't matter) */ +typedef enum +{ + FT_NONE = '-', + FT_DELETED = 'x', + FT_SUBDIR = 'D', + FT_PARENT = 'P', + FT_LABEL = 'L', + FT_LFN = '~', + FT_INVALID = 'i', // not recognized weird file + FT_SELF = '.', + FT_FILE = 'F' +} FAT16_FT; + + +// File Attributes (bit flags) +#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 + + +/** Boot Sector structure - INTERNAL! */ +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 - private fields! */ +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 handle struct */ +typedef struct __attribute__((packed)) +{ + // Fields loaded directly from disk: + + uint8_t name[11]; // Starting 0x05 converted to 0xE5, other "magic chars" left intact + uint8_t attribs; // composed of FA_* constants + // 14 bytes skipped + uint16_t clu_start; + uint32_t size; + + // Added fields: + + FAT16_FT type; + + // --- Private fields --- + + // Cursor + 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 + uint16_t clu; // first cluster of directory + uint16_t num; // fiel entry number + + // pointer to FAT + const FAT16* fat; +} +FAT16_FILE; + + +/** Initialize a filesystem */ +void 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. + * + * Either way, the prev and next functions will work as expected. + */ +void fat16_root(const FAT16* fat, FAT16_FILE* file); + + +/** + * Resolve the disk label. + */ +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_fseek(FAT16_FILE* file, uint32_t addr); + + +/** + * Read bytes from file into memory + * Returns false on I/O error (bad file, out of range...) + */ +bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len); + + +/** + * Write into file at a "seek" position. + * "seek" cursor must be within (0..filesize) + */ +bool fat16_fwrite(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); + + +/** + * Write new file size (also to the disk). + * Allocates / frees needed clusters, does not erase them. + */ +void fat16_resize(FAT16_FILE* file, uint32_t size); + + +/** + * Delete a file entry and free clusters. + * Does NOT work on folders. + */ +bool fat16_rmfile(FAT16_FILE* file); + + +/** + * Delete an empty directory. + * Calling with non-subfolder entry or non-empty directory will cause error. + */ +bool fat16_rmdir(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 first entry of the directory. + */ +bool fat16_opendir(FAT16_FILE* file); + +/** + * Open a parent directory. Fails in root. + */ +bool fat16_parent(FAT16_FILE* file); + + +/** Rewind to first file in 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. + * Either way, "dir" gets modified and you may need to rewind it afterwards. + */ +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_file_valid(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); + diff --git a/devel/xxx/lib b/devel/xxx/lib new file mode 120000 index 0000000..f6a9085 --- /dev/null +++ b/devel/xxx/lib @@ -0,0 +1 @@ +/home/ondra/git/avr-lib/lib \ No newline at end of file diff --git a/devel/xxx/main.c b/devel/xxx/main.c new file mode 100644 index 0000000..ac387f3 --- /dev/null +++ b/devel/xxx/main.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "fat16.h" + +BLOCKDEV test; + +void test_seek(const uint32_t pos) +{ + asm volatile (""); +} + +void test_rseek(const int16_t pos) +{ + asm volatile (""); +} + +void test_load(void* dest, const uint16_t len) +{ + asm volatile (""); +} + +void test_store(const void* source, const uint16_t len) +{ + asm volatile (""); +} + +void test_write(const uint8_t b) +{ + asm volatile (""); +} + +uint8_t test_read() +{ + return 0; +} + +void test_open() +{ + test.read = &test_read; + test.write = &test_write; + + test.load = &test_load; + test.store = &test_store; + + test.seek = &test_seek; + test.rseek = &test_rseek; +} + + +void main() +{ + test_open(); + + // Initialize the FS + FAT16 fat; + fat16_init(&test, &fat); + + FAT16_FILE file; + fat16_root(&fat, &file); + + char str[10]; + +fat16_disk_label(&fat, str); + + +// ----------- FILE I/O ------------- + + +/** + * Move file cursor to a position relative to file start + * Returns false on I/O error (bad file, out of range...) + */ +fat16_fseek(&file, 1234); + + +/** + * Read bytes from file into memory + * Returns false on I/O error (bad file, out of range...) + */ +fat16_fread(&file, str, 10); + + +/** + * Write into file at a "seek" position. + * "seek" cursor must be within (0..filesize) + */ +fat16_fwrite(&file, str, 10); + + +/** Go to next file in directory (false = no next file) */ +fat16_next(&file); + + + while(1) { + //uart_puts_P(PSTR("TEST")); + } +}