diff options
| author | Brad Luyster <BradLuyster+git@gmail.com> | 2012-05-11 19:21:30 -0400 |
|---|---|---|
| committer | Brad Luyster <BradLuyster+git@gmail.com> | 2012-05-11 19:21:30 -0400 |
| commit | 9c96fa015ee8c80e9ab48154c4ecc4fbcfe13087 (patch) | |
| tree | d3129f21ebe1a02ab0e3722edb01e37e8d4b2158 | |
Initial Commit
| -rw-r--r-- | AVR/Examples/Makefile | 509 | ||||
| -rw-r--r-- | AVR/Examples/basicAvr.c | 95 | ||||
| -rw-r--r-- | AVR/queue.c | 138 | ||||
| -rw-r--r-- | AVR/queue.h | 26 | ||||
| -rw-r--r-- | Arduino/Queue.cpp | 147 | ||||
| -rw-r--r-- | Arduino/Queue.h | 39 | ||||
| -rw-r--r-- | Arduino/Tests/arduinoTests.ino | 185 |
7 files changed, 1139 insertions, 0 deletions
diff --git a/AVR/Examples/Makefile b/AVR/Examples/Makefile new file mode 100644 index 0000000..ee86945 --- /dev/null +++ b/AVR/Examples/Makefile @@ -0,0 +1,509 @@ +# Hey Emacs, this is a -*- makefile -*- +#---------------------------------------------------------------------------- +# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al. +# +# Released to the Public Domain +# +# Additional material for this makefile was written by: +# Peter Fleury +# Tim Henigan +# Colin O'Flynn +# Reiner Patommel +# Markus Pfaff +# Sander Pool +# Frederik Rouleau +# +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device, using avrdude. +# Please customize the avrdude settings below first! +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + + +# MCU name +MCU = atmega168 +AVRDUDEMCU = m168 + + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +F_CPU = 16000000 + + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + + +# Target file name (without extension). +TARGET = basicAvr + + +# List C source files here. (C dependencies are automatically generated.) +SRC = $(TARGET).c ../queue.c + + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + + +# Debugging format. +# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. +# AVR Studio 4.10 requires dwarf-2. +# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. +DEBUG = dwarf-2 + + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRAINCDIRS = + + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=gnu99 + + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU)UL + + +# Place -I options here +CINCS = + + + +#---------------- Compiler Options ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) $(CINCS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -Wall -Wstrict-prototypes +CFLAGS += -Wa,-adhlns=$(<:.c=.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) + + +#---------------- Assembler Options ---------------- +# -Wa,...: tell GCC to pass this to the assembler. +# -ahlms: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs + + +#---------------- Library Options ---------------- +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +# If this is left blank, then it will use the Standard printf version. +PRINTF_LIB = +#PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_FLOAT) + + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +# If this is left blank, then it will use the Standard scanf version. +SCANF_LIB = +#SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_FLOAT) + + +MATH_LIB = -lm + + + +#---------------- External Memory Options ---------------- + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + + + +#---------------- Linker Options ---------------- +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) + + + +#---------------- Programming Options (avrdude) ---------------- + +# Programming hardware: alf avr910 avrisp bascom bsd +# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 +# +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = arduino + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = /dev/ttyUSB0 + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(AVRDUDEMCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -b 19200 +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + + + +#---------------- Debugging Options ---------------- + +# For simulavr only - target MCU frequency. +DEBUG_MFREQ = $(F_CPU) + +# Set the DEBUG_UI to either gdb or insight. +# DEBUG_UI = gdb +DEBUG_UI = insight + +# Set the debugging back-end to either avarice, simulavr. +DEBUG_BACKEND = avarice +#DEBUG_BACKEND = simulavr + +# GDB Init Filename. +GDBINIT_FILE = __avr_gdbinit + +# When using avarice settings for the JTAG +JTAG_DEV = /dev/com1 + +# Debugging port used to communicate between GDB / avarice / simulavr. +DEBUG_PORT = 4242 + +# Debugging host used to communicate between GDB / avarice / simulavr, normally +# just set to localhost unless doing some sort of crazy debugging when +# avarice is running on a different computer. +DEBUG_HOST = localhost + + + +#============================================================================ + + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +COPY = cp +WINSHELL = cmd + + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: + + + + +# Define all object files. +OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(SRC:.c=.lst) $(ASRC:.S=.lst) + + +# Compiler flags to generate dependency files. +GENDEPFLAGS = -MD -MP -MF .dep/$(@F).d + + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + + + +# Default target. +all: begin gccversion sizebefore build sizeafter end + +build: elf hex eep lss sym + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym + + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) -A $(TARGET).elf +AVRMEM = avr-mem.sh $(TARGET).elf $(MCU) + +sizebefore: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ + $(AVRMEM) 2>/dev/null; echo; fi + +sizeafter: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ + $(AVRMEM) 2>/dev/null; echo; fi + + + +# Display compiler version information. +gccversion : + @$(CC) --version + + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + + +# Generate avr-gdb config/init file which does the following: +# define the reset signal, load the target file, connect to target, and set +# a breakpoint at main(). +gdb-config: + @$(REMOVE) $(GDBINIT_FILE) + @echo define reset >> $(GDBINIT_FILE) + @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) + @echo end >> $(GDBINIT_FILE) + @echo file $(TARGET).elf >> $(GDBINIT_FILE) + @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) +ifeq ($(DEBUG_BACKEND),simulavr) + @echo load >> $(GDBINIT_FILE) +endif + @echo break main >> $(GDBINIT_FILE) + +debug: gdb-config $(TARGET).elf +ifeq ($(DEBUG_BACKEND), avarice) + @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. + @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ + $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) + @$(WINSHELL) /c pause + +else + @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ + $(DEBUG_MFREQ) --port $(DEBUG_PORT) +endif + @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) + + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + +# Create preprocessed source for use in sending a bug report. +%.i : %.c + $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ + + +# Target: clean project. +clean: begin clean_list end + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lss + $(REMOVE) $(OBJ) + $(REMOVE) $(LST) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) .dep/* + + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion \ +build elf hex eep lss sym coff extcoff \ +clean clean_list program debug gdb-config + + diff --git a/AVR/Examples/basicAvr.c b/AVR/Examples/basicAvr.c new file mode 100644 index 0000000..55a3597 --- /dev/null +++ b/AVR/Examples/basicAvr.c @@ -0,0 +1,95 @@ +#include <stdio.h> +#include <avr/io.h> +#include <util/delay.h> +#include <stdint.h> + +#include "../queue.h" + +#define FOSC 16000000 +#define BAUD 9600 +#define MYUBRR FOSC/16/BAUD-1 + +#define sbi(var, mask) ((var) |= (uint8_t)(1 << mask)) +#define cbi(var, mask) ((var) &= (uint8_t)~(1 << mask)) + +#define STATUS_LED 5 + +void ioinit(void); // initializes IO +static int uart_putchar(char c, FILE *stream); +uint8_t uart_getchar(void); + +static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); + +int testFunction(queue_time_t now) +{ + printf("Hello World! Time: %d\r\n", now); + return 0; +} + +int testFunction2(queue_time_t now) +{ + printf("Stupid World! Time: %d\r\n", now); + return 0; +} + +int main (void) +{ + uint32_t x = 0; + + ioinit(); //Setup IO pins and defaults + + scheduleFunction(testFunction, "Test", 3, 3); + scheduleFunction(testFunction2, "Test2", 4, 3); + + while(1) + { + + scheduleRun(x); + x++; + + if(x == 15) + { + scheduleRemoveFunction("Test2"); + scheduleChangeFunction("Test", 15, 4); + } + + sbi(PORTB, STATUS_LED); + _delay_ms(500); + + cbi(PORTB, STATUS_LED); + _delay_ms(500); + } + + return(0); +} + +void ioinit (void) +{ + //1 = output, 0 = input + DDRB = 0b11101111; //PB4 = MISO + DDRC = 0b11111111; // + DDRD = 0b11111110; //PORTD (RX on PD0) + + //USART Baud rate: 9600 + UBRR0H = MYUBRR >> 8; + UBRR0L = MYUBRR; + UCSR0B = (1<<RXEN0)|(1<<TXEN0); + + stdout = &mystdout; //Required for printf init +} + +static int uart_putchar(char c, FILE *stream) +{ + //if (c == '\n') uart_putchar('\r', stream); + + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = c; + + return 0; +} + +uint8_t uart_getchar(void) +{ + while( !(UCSR0A & (1<<RXC0)) ); + return(UDR0); +}
\ No newline at end of file diff --git a/AVR/queue.c b/AVR/queue.c new file mode 100644 index 0000000..f758ec9 --- /dev/null +++ b/AVR/queue.c @@ -0,0 +1,138 @@ +#include <stdint.h> +#include <string.h> +#include <stdio.h> + +#include "queue.h" + +static uint8_t queueStart = 0; +static uint8_t queueEnd = 0; +static uint8_t itemsInQueue = 0; + +static queueItem scheduleQueue[QUEUE_DEPTH]; + +static int scheduleQueueGetTop(queueItem *returnItem); +static int internalScheduleFunction(queueItem pItem); + +int scheduleFunction(queuedFunction pFunction, const char *pId, queue_time_t pInitialRun, queue_time_t pRecur) +{ + int rv = 0; + + queueItem newItem; + newItem.fPtr = pFunction; + memset(newItem.itemName, 0, NAME_LIMIT); + memcpy(newItem.itemName, pId, strlen(pId)); + newItem.recur = pRecur; + newItem.next = pInitialRun; + + rv = internalScheduleFunction(newItem); + + return rv; +} + +int scheduleRemoveFunction(const char *pId) +{ + queueItem target; + int rv = 0; + for (int i = 0; i < itemsInQueue; ++i) + { + if(scheduleQueueGetTop(&target) == 0) + { + if(strcmp(target.itemName, pId) != 0) + { + internalScheduleFunction(target); + } + } else { + rv = -1; + break; + } + } + + return rv; +} + +int scheduleChangeFunction(const char *pId, queue_time_t pNewNext, queue_time_t pNewRecur) +{ + queueItem target; + int rv = 0; + for (int i = 0; i < itemsInQueue; ++i) + { + if(scheduleQueueGetTop(&target) == 0) + { + if(strcmp(target.itemName, pId) == 0) + { + target.next = pNewNext; + target.recur = pNewRecur; + } + internalScheduleFunction(target); + } else { + rv = -1; + break; + } + } + + return rv; +} + +int scheduleRun(queue_time_t pNow) +{ + queueItem target; + int rv = 0; + for (int i = 0; i < itemsInQueue; ++i) + { + if(scheduleQueueGetTop(&target)==0) + { + if(target.next <= pNow) + { + int tRv; + tRv = (target.fPtr)(pNow); + if(tRv == 0) + { + rv++; + } + if(target.recur != 0) + { + target.next = pNow + target.recur; + internalScheduleFunction(target); + } + } else { + internalScheduleFunction(target); + } + } else { + rv = -1; + break; + } + } + + return rv; +} + +static int scheduleQueueGetTop(queueItem *returnItem) +{ + int rv = 0; + //Remove the top item, stuff it into returnItem + if (queueEnd != queueStart) { + queueItem tempQueueItem = scheduleQueue[queueStart]; + //This Algorithm also from Wikipedia. + queueStart = (queueStart + 1) % QUEUE_DEPTH; + *returnItem = tempQueueItem; + itemsInQueue--; + } else { + //if the buffer is empty, return an error code + rv = -1; + } + + return rv; +} + +static int internalScheduleFunction(queueItem pItem) +{ + int rv = 0; + if ((queueEnd + 1) % QUEUE_DEPTH != queueStart) { + scheduleQueue[queueEnd] = pItem; + queueEnd = (queueEnd + 1) % QUEUE_DEPTH; + itemsInQueue++; + } else { + rv = -1; + } + return rv; +}
\ No newline at end of file diff --git a/AVR/queue.h b/AVR/queue.h new file mode 100644 index 0000000..a587d0e --- /dev/null +++ b/AVR/queue.h @@ -0,0 +1,26 @@ +#ifndef QUEUE_H +#define QUEUE_H + +// Settings +#define QUEUE_DEPTH 10 +#define NAME_LIMIT 8 +typedef uint32_t queue_time_t; + +typedef int (*queuedFunction)(queue_time_t); + +typedef struct _queue_item +{ + queuedFunction fPtr; + queue_time_t recur; + queue_time_t next; + char itemName[NAME_LIMIT]; +} queueItem; + +//Functions +int scheduleFunction(queuedFunction, const char *, queue_time_t, queue_time_t); +int scheduleRemoveFunction(const char *); +int scheduleChangeFunction(const char *, queue_time_t, queue_time_t); + +int scheduleRun(queue_time_t); + +#endif
\ No newline at end of file diff --git a/Arduino/Queue.cpp b/Arduino/Queue.cpp new file mode 100644 index 0000000..f428228 --- /dev/null +++ b/Arduino/Queue.cpp @@ -0,0 +1,147 @@ +#include "Queue.h" + +Queue::Queue() +{ + _itemsInQueue = 0; + _queueStart = 0; + _queueEnd = 0; +} + +int Queue::scheduleFunction(queuedFunction func, const char * id, unsigned long initialRun, unsigned long recur) +{ + int rv = 0; + + if(strlen(id) > 7) + { + rv = -1; + } else { + + queueItem newItem; + newItem.fPtr = func; + memset(newItem.itemName, 0, 8); + memcpy(newItem.itemName, id, strlen(id)); + newItem.recur = recur; + newItem.next = initialRun; + + rv = _addToQueue(newItem); + } + + return rv; +} + +int Queue::scheduleRemoveFunction(const char * id) +{ + queueItem target; + int rv = -1; + for (int i = 0; i < _itemsInQueue; ++i) + { + if(_queueGetTop(target) == 0) + { + if(strcmp(target.itemName, id) == 0) + { + rv = 0; + } else { + _addToQueue(target); + } + } else { + rv = -1; + break; + } + } + + return rv; +} + +int Queue::scheduleChangeFunction(const char * id, unsigned long nextRunTime, unsigned long newRecur) +{ + queueItem target; + int rv = -1; + for (int i = 0; i < _itemsInQueue; ++i) + { + if(_queueGetTop(target) == 0) + { + if(strcmp(target.itemName, id) == 0) + { + target.next = nextRunTime; + target.recur = newRecur; + rv = 0; + } + _addToQueue(target); + } else { + rv = -1; + break; + } + } + + return rv; +} + +int Queue::Run(unsigned long now) +{ + queueItem target; + int rv = 0; + if(_itemsInQueue == 0) + { + rv = -1; + } + for (int i = 0; i < _itemsInQueue; ++i) + { + if(_queueGetTop(target)==0) + { + if(target.next <= now) + { + int tRv; + tRv = (target.fPtr)(now); + if(tRv == 0) + { + rv++; + } + if(target.recur != 0) + { + target.next = now + target.recur; + _addToQueue(target); + } + } else { + _addToQueue(target); + } + } else { + rv = -1; + break; + } + } + + return rv; +} + +int Queue::_queueGetTop(queueItem &item) +{ + int rv = 0; + //Remove the top item, stuff it into item + if (_queueEnd != _queueStart) { + queueItem tempQueueItem = _schedule[_queueStart]; + //This Algorithm also from Wikipedia. + _queueStart = (_queueStart + 1) % QueueScheduleSize; + item = tempQueueItem; + _itemsInQueue--; + } else { + //if the buffer is empty, return an error code + rv = -1; + } + + return rv; +} + +int Queue::_addToQueue(queueItem item) +{ + //This is just a circular buffer, and this algorithm is stolen from wikipedia + int rv = 0; + if ((_queueEnd + 1) % QueueScheduleSize != _queueStart) { + _schedule[_queueEnd] = item; + _queueEnd = (_queueEnd + 1) % QueueScheduleSize; + _itemsInQueue++; + } else { + //if buffer is full, error + rv = -1; + } + return rv; +}
\ No newline at end of file diff --git a/Arduino/Queue.h b/Arduino/Queue.h new file mode 100644 index 0000000..d23afb3 --- /dev/null +++ b/Arduino/Queue.h @@ -0,0 +1,39 @@ +#ifndef QUEUE_H +#define QUEUE_H + +#include "Arduino.h" + +typedef int (*queuedFunction)(unsigned long); + +#define QueueScheduleSize 11 + +struct queueItem { + queuedFunction fPtr; + unsigned long next; + unsigned long recur; + char itemName[8]; +}; + +class Queue +{ +private: + unsigned int _queueStart; + unsigned int _queueEnd; + unsigned int _itemsInQueue; + queueItem _schedule[QueueScheduleSize]; + + int _queueGetTop(queueItem &item); + int _addToQueue(queueItem item); + +public: + Queue(); + + int scheduleFunction(queuedFunction func, const char * id, unsigned long initialRun, unsigned long recur); + int scheduleRemoveFunction(const char * id); + int scheduleChangeFunction(const char * id, unsigned long nextRunTime, unsigned long newRecur); + + int Run(unsigned long now); + /* data */ +}; + +#endif
\ No newline at end of file diff --git a/Arduino/Tests/arduinoTests.ino b/Arduino/Tests/arduinoTests.ino new file mode 100644 index 0000000..653ae5f --- /dev/null +++ b/Arduino/Tests/arduinoTests.ino @@ -0,0 +1,185 @@ +#include <Queue.h> + +/* + Blink + Turns on an LED on for one second, then off for one second, repeatedly. + + This example code is in the public domain. + */ + +void setup() { + // initialize the digital pin as an output. + // Pin 13 has an LED connected on most Arduino boards: + pinMode(13, OUTPUT); + Serial.begin(9600); + Serial.println("Alive"); + + int testStatus = 0; + testStatus |= test_addTooMany(); + testStatus |= test_removeNonExistent(); + testStatus |= test_tooManyCharacters(); + testStatus |= test_changeNonExistent(); + testStatus |= test_runEmpty(); + + if(testStatus == 0) + { + Serial.println("All tests passed."); + } else { + Serial.println("Something Failed."); + } + +} + +void loop() { + delay(1000); +} + +int testFunction(unsigned long now) +{ + Serial.print("Hello: "); + Serial.print(now); + Serial.println(); +} + +int test_addTooMany(void) +{ + Queue testQueue; + int rv; + int testStatus = 0; + rv = testQueue.scheduleFunction(testFunction, "Test1", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test2", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test3", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test4", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test5", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test6", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test7", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test8", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test9", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test10", 5000, 1000); + if(rv != 0) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + rv = testQueue.scheduleFunction(testFunction, "Test11", 5000, 1000); + if(rv != -1) + { + Serial.println("test_addTooMany failed."); + testStatus = -1; + } + + return testStatus; +} + +int test_removeNonExistent(void) +{ + Queue testQueue; + int rv; + int testStatus = 0; + rv = testQueue.scheduleFunction(testFunction, "Test", 5000, 1000); + if(rv != 0) + { + Serial.println("test_removeNonExistent failed."); + testStatus = -1; + } + rv = testQueue.scheduleRemoveFunction("Fail"); + if(rv != -1) + { + Serial.println("test_removeNonExistent failed."); + testStatus = -1; + } + return testStatus; +} + +int test_tooManyCharacters(void) +{ + Queue testQueue; + int rv; + int testStatus = 0; + rv = testQueue.scheduleFunction(testFunction, "ReallyLongName", 5000, 1000); + if(rv != -1) + { + Serial.println("test_tooManyCharacters failed."); + testStatus = -1; + } + return testStatus; +} + +int test_changeNonExistent(void) +{ + Queue testQueue; + int rv; + int testStatus = 0; + rv = testQueue.scheduleFunction(testFunction, "Test", 5000, 1000); + if(rv != 0) + { + Serial.println("test_changeNonExistent failed."); + testStatus = -1; + } + rv = testQueue.scheduleChangeFunction("Fail", 1000, 1000); + if(rv != -1) + { + Serial.println("test_changeNonExistent failed."); + testStatus = -1; + } + return testStatus; +} + +int test_runEmpty(void) +{ + Queue myQueue; + int rv = 0; + int testStatus = 0; + rv = myQueue.Run(10); + if (rv != -1) + { + Serial.println("test_runEmpty failed."); + testStatus = -1; + } + return testStatus; +}
\ No newline at end of file |
