Initial import
authorKevin Rosenberg <kevin@rosenberg.net>
Sun, 16 Mar 2008 15:14:10 +0000 (09:14 -0600)
committerKevin Rosenberg <kevin@rosenberg.net>
Sun, 16 Mar 2008 15:14:10 +0000 (09:14 -0600)
19 files changed:
.gitignore [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
cv_c/serlcd_cv.prj [new file with mode: 0644]
gcc_c/Makefile [new file with mode: 0644]
gcc_cpp/Makefile [new file with mode: 0644]
gcc_cpp_obj/Makefile [new file with mode: 0644]
iar_c/Makefile [new file with mode: 0644]
iar_cpp/Makefile [new file with mode: 0644]
iar_cpp_obj/Makefile [new file with mode: 0644]
icc_c/Makefile [new file with mode: 0644]
serial_lcd.c [new file with mode: 0644]
serial_lcd.h [new file with mode: 0644]
serial_lcd_cpp.cpp [new file with mode: 0644]
serial_lcd_obj.cpp [new file with mode: 0644]
tester/Makefile [new file with mode: 0644]
tester/serial_lcd_tester.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..b2273ca
--- /dev/null
@@ -0,0 +1,2 @@
+tester-build
+*.~[0-9]~
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..8c13117
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,179 @@
+2008-03-15  Kevin Rosenberg <kevin@rosenberg.net>\r
+       * serial_lcd.c: Add 4-bit interface mode\r
+       * serial_lcd.h: Move LCD control codes here with renaming.  Use\r
+       new device-independant iccioavr.h file for ImageCraft\r
+       (requires ICC V7.16+). Use __flash keyword for\r
+       Imagecraft (requires ICC V7.15+)\r
+       * Use custom Makefiles for all IAR, GCC, and ICC compilations\r
+       \r
+2008-02-24  Kevin Rosenberg <kevin@rosenberg.net>\r
+       * Enscapulate MAIN_FUNC() and MAIN_FUNC_LAST to avoid compile\r
+       warnings on all platforms\r
+       \r
+2008-01-04  Kevin Rosenberg <kevin@rosenberg.net>\r
+       * README: Update sizes for 20080104 release\r
+\r
+2008-01-03  Kevin Rosenberg <kevin@rosenberg.net>\r
+\r
+       * README: Update with information about the two C++ variants.\r
+       \r
+       * serial_lcd.h: Rename LCD_DATA_OUT to LCD_DATA_PORT. Create IO\r
+       definitions for baud rate jumpers to segment their access in\r
+       serial_lcd_obj.cpp. Add MAIN_FUNC() macro for new GCC OS_main\r
+       attribute.\r
+       \r
+       * serial_lcd.c: GetUsartBaud() move variable declaration to\r
+       assignment. Rename LCD_DATA_OUT to LCD_DATA_PORT. Use MAIN_FUNC().\r
+\r
+       * serial_lcd.cpp: Rename some member variables by prepending "m_".\r
+       Modify UART_UBRR() to round to nearest integer. Rename\r
+       LCD_DATA_OUT to LCD_DATA_PORT. Remove intermediate Baud Divisors\r
+       since C++ can employ preprocessor macro in array\r
+       initialization. Use MAIN_FUNC().\r
+\r
+       * serial_lcd_obj.cpp: Rename some member variables by prepending\r
+       "m_". Move GetBaud from Uart class to standalone function\r
+       GetBaudDivisor(). Use that divisor as for Uart::setBaudDivisor()\r
+       method.  Modify UART_UBRR() to round to nearest integer. Rename\r
+       LCD_DATA_OUT to LCD_DATA_PORT. Remove intermediate Baud Divisors\r
+       since C++ can employ preprocessor macro in array\r
+       initialization. Use MAIN_FUNC().  Modify Lcd::init() to accept\r
+       parameters to define io definitions.  Separate and add methods for\r
+       setting Uart baud divisor, parity, rx/tx enable and interrupt\r
+       enable configurations.\r
+       \r
+2008-01-01  Kevin Rosenberg <kevin@rosenberg.net>\r
+       \r
+       * ChangeLog: Renamed from CHANGES\r
+\r
+       * serial_lcd.h: Move LED_BRIGHTNESS_LEVELS to .c and .cpp\r
+       functions so value can be encapsulated in .cpp LedPwm class. Move\r
+       LCD command codes to .c and .cpp files so that they can be\r
+       encapsulated by C++ classes.\r
+\r
+       * serial_lcd.c: Make init functions inline to correspond to C++ versions.\r
+       Change GetUsartBaud to inline since it is only called once in a program.\r
+       Move LED PWM brightness computation to inline function. Make LED switch\r
+       on and off code into inline functions. Move CTS initialization to UsartInit.\r
+\r
+       * serial_lcd.cpp: Change GetUsartBaud to inline since it is only called\r
+       once in a program. Move RX buffer into member variable of object (saves\r
+       2 bytes in GCC and no change in IAR size). Change UART_RX_BUFFER_SIZE\r
+       from preprocessor definition to static const in class (no change in\r
+       code size). Move pwmPattern array to static variable in LedPwm class\r
+       and make pwmPattern an inline method (no change in code size). Make\r
+       setting LedPwmBrightness a class method. Move LED switch on and off code\r
+       to class methods. Move baud rate constants into Uart class. Change\r
+       UBRR from numeric constants to values computed from F_CPU. Move CTS init\r
+       to Uart::init(). Convert Watchdog and SleepMode to fully static classes.\r
+       Add Delay class.\r
+\r
+       * serial_lcd_obj.cpp: New source file to test the implementation\r
+       and impact of using independed C++ classes which can potentially\r
+       be used as part of a standalone C++ AVR library. \r
+\r
+2007-12-31  Kevin Rosenberg <kevin@rosenberg.net>\r
+       \r
+       * LICENSE: Include appropriate copyright statements  \r
+       (Thanks to AVRFreaks member cpluscon)\r
+\r
+       * serial_lcd.c: Fix Livingston's name Thanks to AVRFreaks member\r
+       cpluscon)\r
+\r
+       * serial_lcd.cpp: Remove all object constructors to reduce code\r
+       size by eliminating constructors. Fix Livinston's name (Thanks to\r
+       AVRFreaks member cpluscon)\r
+\r
+       * gcc_c_cpp/Makefile: Use proper map file for C++ code (Thanks to\r
+       AVRFreaks member cpluscon)\r
+\r
+       * gcc_c_cpp: Directory renamed from gcc_c_cpp_comparison\r
+\r
+       * iar_c_cpp: new directory\r
+\r
+       * icc_c: new directory\r
+\r
+       * Add assembly listings, map files, and hex files for all compiled\r
+       output\r
+\r
+       * serial_lcd_tester.c: Serial_Lcd tester (tested on Cygwin, should\r
+       work on Linux)\r
+\r
+       * serial_lcd_tester.exe: Compiled version of serial_lcd_tester.c\r
+       for Windows (requires Cygwin DLL file)\r
+       \r
+\r
+2007-12-30  Kevin Rosenberg <kevin@rosenberg.net>\r
+\r
+       * Initial source code\r
+\r
+       * Change UART RX from polling to interrupt-driven circular buffer\r
+\r
+       * LED backlight PWM brightness setting (8-levels) using Timer0\r
+       COMPA interrupt. Store PWM patterns in flash ram.\r
+       \r
+       * Port code to IAR and GCC using kavr_compat.h compatibility\r
+       defintions and macros\r
+       \r
+       * NO_RETURN_FUNC macro on main to remove unnecessary\r
+       prologue/epilogue code\r
+\r
+       * Move BaudLookupTable array from heap to flash ram. Requires 4\r
+       more bytes of program code, but frees 4 bytes of SRAM.\r
+\r
+       * Use _delay_ms functions for GCC and _delay_cycles for IAR\r
+\r
+       * Add idle sleep mode setup and enter sleep when no input is\r
+       waiting\r
+\r
+       * Add watchdog timer setups and resets\r
+\r
+       * Bind key variables to registers\r
+\r
+       * Change from IO Pin numbers to Pin names\r
+\r
+       * Instead of NULL definition, use 0 to be explicit\r
+\r
+       * If F_CPU (frequency of CPU) is not specified, default to value\r
+       for standard serial_backpack hardware\r
+\r
+       * Define CPU type (__AVR_ATTiny2313__) for kavr_compat.h if not\r
+       already defined\r
+\r
+       * Rename preprocessor definition LED to LED_PIN\r
+\r
+       * Move USART_DATA from heap allocated to stack allocated, renamed\r
+       rx_byte\r
+\r
+       * Remove auto-initialized variable so that auto-initialize code is\r
+       not included in binary (for compilers that support this\r
+       optimization)\r
+\r
+       * New BIT variable for led_on status (stored in GPIO register)\r
+\r
+       * Added CTS (clear to send) signal on PA2 pin since RESET pin\r
+       isn't used by original hardware design\r
+\r
+       * Add conditional compilation of SLEEP_MODE, WATCHDOG, CTS\r
+       features\r
+\r
+       * Add LED_PORT and LED_DIR definitions (in care LED not on same\r
+       PORT as LCD control)\r
+\r
+       * Rename LCD_CONTROL_OUT to LCD_CONTROL_PORT, LCD_CONTROL_IN to\r
+       LCD_CONTROL_PIN_REG, LCD_CONTROL_DDR to LCD_CONTROL_DIR,\r
+       LCD_DATA_DDR to LCD_DATA_DIR, LCD_DATA_IN to LCD_DATA_PIN_REG\r
+\r
+       * Use "= 0xFF" rather than "|= 0xFF" and simplify compare in\r
+       LcdBusyWait\r
+\r
+       * Create ENABLE_WAIT() to reuse in 3 functions\r
+\r
+       * Separate common declarations for .c and .cpp versions into .h\r
+       file\r
+\r
+       * Rename a number of functions for common naming format\r
+\r
+Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved.\r
+Copying and distribution of this file, with or without modification, are\r
+permitted provided the copyright notice and this notice are preserved.\r
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..6373c96
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved.\r
+\r
+ Redistribution and use in source and binary forms, with or without\r
+ modification, are permitted provided that the following conditions\r
+ are met:\r
+ 1. Redistributions of source code must retain the above copyright\r
+    notice, this list of conditions and the following disclaimer.\r
+ 2. Redistributions in binary form must reproduce the above copyright\r
+    notice, this list of conditions and the following disclaimer in the\r
+    documentation and/or other materials provided with the distribution.\r
+ 3. Neither the name of the author nor the names of the contributors\r
+    may be used to endorse or promote products derived from this software\r
+    without specific prior written permission.\r
+\r
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND\r
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE\r
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+ SUCH DAMAGE.\r
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..7dd0c84
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,60 @@
+date := $(shell date +"%Y%m%d")\r
+\r
+.PHONY: all\r
+all: build\r
+\r
+tester := tester/serial_lcd_tester\r
+\r
+tester-build: $(tester).exe\r
+       touch tester-build\r
+\r
+$(tester).exe:\r
+       (cd tester && make)\r
+\r
+.PHONY: build\r
+build: tester-build\r
+       (cd gcc_c; make; make clean)\r
+       (cd gcc_cpp; make; make clean)\r
+       (cd gcc_cpp_obj; make; make clean)\r
+       (cd iar_c; make; make clean)\r
+       (cd iar_cpp; make; make clean)\r
+       (cd iar_cpp_obj; make; make clean)\r
+       (cd icc_c; make; make clean)\r
+\r
+dist: tester-build  build\r
+       @chmod -x *.c *.h *.cpp README ChangeLog LICENSE\r
+       @find $(GCCDIR) -type f -exec chmod -x {} \;\r
+       @find $(IARDIR) -type f -exec chmod -x {} \;\r
+       @find $(ICCDIR) -type f -exec chmod -x {} \;\r
+       @zip serial_lcd-$(date).zip README serial_lcd.c serial_lcd.cpp serial_lcd_obj.cpp serial_lcd.h LICENSE ChangeLog \\r
+       $(GCCDIR)/Makefile $(GCCDIR)/serial_lcd.map $(GCCDIR)/serial_lcd_cpp.map $(GCCDIR)/serial_lcd.lss \\r
+       $(GCCDIR)/serial_lcd_cpp.lss $(GCCDIR)/serial_lcd.hex $(GCCDIR)/serial_lcd_cpp.hex \\r
+       $(GCCDIR)/serial_lcd_obj.lss $(GCCDIR)/serial_lcd_obj.map $(GCCDIR)/serial_lcd_obj.map \\r
+       $(IARDIR)/*.lst $(IARDIR)/*.map $(IARDIR)/*.hex $(ICCDIR)/*.mp $(ICCDIR)/*.lst $(ICCDIR)/*.hex \\r
+       $(tester).c $(tester).exe\r
+\r
+.PHONY: clean\r
+clean:\r
+       @rm -rf tester-build\r
+       $(MAKE) -C tester clean\r
+       $(MAKE) -C gcc_c clean\r
+       $(MAKE) -C gcc_cpp clean\r
+       $(MAKE) -C gcc_cpp_obj clean\r
+       $(MAKE) -C iar_c clean\r
+       $(MAKE) -C iar_cpp clean\r
+       $(MAKE) -C iar_cpp_obj clean\r
+       $(MAKE) -C iar_cpp_obj clean\r
+       $(MAKE) -C icc_c clean\r
+\r
+.PHONY: distclean\r
+distclean: \r
+       @rm -rf tester-build\r
+       $(MAKE) -C tester distclean\r
+       $(MAKE) -C gcc_c distclean\r
+       $(MAKE) -C gcc_cpp distclean\r
+       $(MAKE) -C gcc_cpp_obj distclean\r
+       $(MAKE) -C iar_c distclean\r
+       $(MAKE) -C iar_cpp distclean\r
+       $(MAKE) -C iar_cpp_obj distclean\r
+       $(MAKE) -C iar_cpp_obj distclean\r
+       $(MAKE) -C icc_c distclean\r
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..87d1346
--- /dev/null
+++ b/README
@@ -0,0 +1,54 @@
+AVR SERIAL_LCD C/C++ PROJECT\r
+Kevin M. Rosenberg <kevin@rosenberg.net>\r
+=====================================================================\r
+\r
+The home for this project is http://www.avrcode/serial_lcd/\r
+\r
+This is my version of AVR code to drive the Serial Backpack\r
+Project created by Carl W. Livingston. I've rewritten the original\r
+firmware to add a number of features, add compatibility for IAR and\r
+GCC, and well as create two different C++ version.\r
+\r
+Tthis project is also used to demonstrate how C code can be turned\r
+into C++ classes and to view the resulting differences in assembly\r
+output.\r
+\r
+There are two versions of the C++ code: serial_lcd.cpp (which\r
+generates output files with the prefix serial_lcd_cpp) and\r
+serial_lcd_obj.cpp (generates output files with the prefix\r
+serial_lcd_obj).\r
+\r
+The first C++ variant is designed to be "equivalent" to the C code in\r
+that the same inlining of functions were used. Also, the C++ classes\r
+were only to segment functions. No C++ class object contents member\r
+variables. The global variables in the C code remain global in the C++\r
+code. Primarily, because these variables are stored in CPU and IO\r
+registers for greater efficiency. Other variables, like the UART\r
+circular buffer, remain in global memory space so its address is known\r
+at compile time and spare the address computation required if the\r
+variable was a member of a C++ object.\r
+\r
+The second C++ variant uses classes that contain member variables and\r
+to which initialization parameters are sent. In this way, multiple\r
+objects of that class can be created. As an example, for connecting 2\r
+LCD panels or multiple LED PWM outputs.\r
+\r
+The code can be modified and redistributed as governed by the terms of\r
+the accompaning LICENSE file.\r
+\r
+\r
+Code/Data Sizes (for 20080316 release)\r
+======================================\r
+\r
+Compiler    Code  Data  Notes\r
+---------   ----  ----  -----\r
+AVR-GCC C    720    48  -Os\r
+AVR-GCC C++  806    50  -Os\r
+AVR-GCC Obj 1574    72  -Os\r
+IAR C        648    48  Size optimization high (+ 64 bytes stack)\r
+IAR C++      746    49  Size optimization high (+ 64 bytes stack)\r
+IAR Obj     1130    65  Size optimization high (+ 63 bytes stack)\r
+ICC7 C       834    48  Full optimizations\r
+\r
+Please consider forwarding suggestions, improvements, or bug fixes to\r
+me.\r
diff --git a/cv_c/serlcd_cv.prj b/cv_c/serlcd_cv.prj
new file mode 100644 (file)
index 0000000..2a35dbe
--- /dev/null
@@ -0,0 +1,223 @@
+[Project]\r
+Toolset=AVR\r
+FormatVersion=2\r
+Files=1\r
+OpenedFiles=3\r
+Top0=430\r
+Left0=711\r
+Height0=339\r
+Width0=497\r
+Active0=0\r
+State0=0\r
+OF1=c:\home\kevin\src\avr\serial_lcd\serial_lcd.c\r
+Top1=151\r
+Left1=84\r
+Height1=509\r
+Width1=614\r
+Row1=135\r
+Collumn1=0\r
+Active1=0\r
+State1=0\r
+OF2=C:\home\kevin\src\avr\serial_lcd\serial_lcd.h\r
+Top2=257\r
+Left2=268\r
+Height2=339\r
+Width2=497\r
+Row2=0\r
+Collumn2=0\r
+Active2=0\r
+State2=0\r
+F1=C:\home\kevin\src\avr\serial_lcd\serial_lcd.c\r
+OF3=c:\cvavreval\inc\tiny2313.h\r
+Top3=197\r
+Left3=133\r
+Height3=339\r
+Width3=497\r
+Row3=84\r
+Collumn3=3\r
+Active3=1\r
+State3=0\r
+[Compiler]\r
+Chip=ATtiny2313\r
+CPUClock=14745600\r
+MemoryModel=0\r
+OptimizeSize=1\r
+OptimizationLevel=2\r
+PrintfFeatures=1\r
+ScanfFeatures=0\r
+DataStackSize=64\r
+PgmMemSize=2048\r
+RAMStart=96\r
+RAMEnd=223\r
+XRAMSize=0\r
+XRAMWaitState=0\r
+HeapSize=0\r
+ExternalInterruptVectors=0\r
+InterruptVectorsNumber=19\r
+InterruptVectorJump=0\r
+ResetVector=0\r
+PromoteCharToInt=0\r
+CharIsUnsigned=1\r
+8BitEnums=1\r
+EnhancedCoreInstructions=1\r
+AutomaticRegisterAllocation=1\r
+SmartRegisterAllocation=1\r
+WordAlignFLASHStructMembers=0\r
+PreprocessorOutput=1\r
+ExternalStartupFile=0\r
+ExternalStartupFileWarning=0\r
+BitVariablesSize=8\r
+UseHiGPIORbit=0\r
+StackEndMarkers=0\r
+Warnings=1\r
+WarningConstantRange=0\r
+WarningPossibleLossOfPrecision=0\r
+WarningArrayIndex=1\r
+WarningGlobalVariableAddress=1\r
+WarningInterruptVector=1\r
+WarningUninitializedFLASH=1\r
+WarningUninitializedEEPROM=1\r
+WarningSuspiciousPointerConversion=1\r
+WarningRegisterAllocated=1\r
+WarningMacroRedefined=1\r
+WarningFunctionReturn=1\r
+WarningUnreferencedFunction=1\r
+WarningUnreferencedFunctionParameter=1\r
+WarningUnreferencedLocalVariable=1\r
+WarningUnreferencedGlobalVariable=1\r
+WarningUnreferencedLabel=1\r
+WarningEmptyLine=1\r
+WarningExpressionHasNoEffect=1\r
+WarningUnknownEscapeSequence=1\r
+WarningShiftResult0=1\r
+Warning8BitAdditionOverflow=1\r
+Warning8BitMultiplicationOverflow=1\r
+Warning16BitAdditionOverflow=1\r
+Warning16BitMultiplicationOverflow=1\r
+WarningPossiblyIncorrectAssignment=1\r
+WarningPointlessComparison=1\r
+WarningConstCtrlExpr=1\r
+WarningUndefinedSymbol=1\r
+WarningCantAllocVarToReg=1\r
+WarningDataStackUsage=1\r
+WarningDataStackRecursion=1\r
+WarningHardwareStackLow=1\r
+DebugBootLoader=0\r
+Build=5\r
+UseEEPROMLocation0=1\r
+IncludePath0=\r
+IncludePath1=\r
+IncludePath2=\r
+IncludePath3=\r
+IncludePath4=\r
+IncludePath5=\r
+IncludePath6=\r
+IncludePath7=\r
+IncludePath8=\r
+IncludePath9=\r
+IncludePath10=\r
+IncludePath11=\r
+IncludePath12=\r
+IncludePath13=\r
+IncludePath14=\r
+IncludePath15=\r
+IncludePath16=\r
+IncludePath17=\r
+IncludePath18=\r
+IncludePath19=\r
+IncludePath20=\r
+IncludePath21=\r
+IncludePath22=\r
+IncludePath23=\r
+IncludePath24=\r
+IncludePath25=\r
+IncludePath26=\r
+IncludePath27=\r
+IncludePath28=\r
+IncludePath29=\r
+IncludePath30=\r
+IncludePath31=\r
+LibraryPath0=\r
+LibraryPath1=\r
+LibraryPath2=\r
+LibraryPath3=\r
+LibraryPath4=\r
+LibraryPath5=\r
+LibraryPath6=\r
+LibraryPath7=\r
+LibraryPath8=\r
+LibraryPath9=\r
+LibraryPath10=\r
+LibraryPath11=\r
+LibraryPath12=\r
+LibraryPath13=\r
+LibraryPath14=\r
+LibraryPath15=\r
+LibraryPath16=\r
+LibraryPath17=\r
+LibraryPath18=\r
+LibraryPath19=\r
+LibraryPath20=\r
+LibraryPath21=\r
+LibraryPath22=\r
+LibraryPath23=\r
+LibraryPath24=\r
+LibraryPath25=\r
+LibraryPath26=\r
+LibraryPath27=\r
+LibraryPath28=\r
+LibraryPath29=\r
+LibraryPath30=\r
+LibraryPath31=\r
+[DefinedSymbols]\r
+Count=0\r
+[Assembler]\r
+OutputFormat=1\r
+TerminalIO=0\r
+[AfterMake]\r
+ProgrammChip=0\r
+MergeROMFile=0\r
+ROMFilePath=\r
+SCKFrequency=230400\r
+LockBits=0\r
+BootLockBits0=0\r
+BootLockBits1=0\r
+ProgramFuseBits=1\r
+Fuse1=0\r
+Fuse2=0\r
+Fuse3=0\r
+Fuse4=0\r
+Fuse5=0\r
+Fuse6=0\r
+Fuse7=0\r
+Fuse8=0\r
+Fuse9=0\r
+Fuse10=0\r
+Fuse11=0\r
+Fuse12=0\r
+Fuse13=0\r
+Fuse14=0\r
+Fuse15=0\r
+Fuse16=0\r
+Fuse17=0\r
+Fuse18=0\r
+Fuse19=0\r
+Fuse20=0\r
+Fuse21=0\r
+Fuse22=0\r
+Fuse23=0\r
+Fuse24=0\r
+CheckSignature=1\r
+CheckErasure=1\r
+PreserveEEPROM=0\r
+VerifyProgramming=1\r
+ProgrammingCounter=0\r
+RunUserProg=0\r
+UserProgPath=\r
+UserProgCmdLine=\r
+UserProgWorkDir=\r
+[BeforeMake]\r
+RunUserProg=0\r
+UserProgPath=\r
+UserProgCmdLine=\r
+UserProgWorkDir=\r
diff --git a/gcc_c/Makefile b/gcc_c/Makefile
new file mode 100644 (file)
index 0000000..47eb208
--- /dev/null
@@ -0,0 +1,80 @@
+###############################################################################\r
+# Makefile for the serial_lcd C & CPP versions \r
+\r
+## General Flags\r
+PROJECT = serial_lcd\r
+MCU = attiny2313\r
+TARGET = $(PROJECT).elf\r
+CC = avr-gcc\r
+\r
+## Options common to compile, link and assembly rules\r
+COMMON = -mmcu=$(MCU)\r
+\r
+## Compile options common for all C compilation units.\r
+CFLAGS = $(COMMON)\r
+CFLAGS += -Wall -gdwarf-2  -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums\r
+CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d \r
+\r
+## Assembly specific flags\r
+ASMFLAGS = $(COMMON)\r
+ASMFLAGS += $(CFLAGS)\r
+ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2\r
+\r
+## Linker flags\r
+LDFLAGS = $(COMMON)\r
+LDFLAGS +=  -Wl,-Map=$(PROJECT).map\r
+\r
+\r
+## Intel Hex file production flags\r
+HEX_FLASH_FLAGS = -R .eeprom\r
+HEX_EEPROM_FLAGS = -j .eeprom\r
+HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"\r
+HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings\r
+\r
+\r
+## Include Directories\r
+INCLUDES = -I.\r
+\r
+## Objects that must be built in order to link\r
+OBJECTS = $(PROJECT).o \r
+\r
+## Objects explicitly added by the user\r
+LINKONLYOBJECTS = \r
+\r
+## Build\r
+all: $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss size \r
+\r
+## Compile\r
+$(PROJECT).o: ../serial_lcd.c\r
+       $(CC) $(INCLUDES) $(CFLAGS) -std=gnu99 -c  $< -o $(PROJECT).o\r
+\r
+##Link\r
+$(TARGET): $(OBJECTS)\r
+        $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)\r
+\r
+$(PROJECT).hex: $(TARGET)\r
+       avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@\r
+\r
+$(PROJECT).eep: $(TARGET)\r
+       -avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0\r
+\r
+$(PROJECT).lss: $(TARGET)\r
+       avr-objdump -h -S $< > $@\r
+\r
+.PHONY: size\r
+size: ${TARGET}\r
+       @echo $(TARGET) size\r
+       @avr-size -C --mcu=${MCU} ${TARGET}\r
+\r
+## Clean target\r
+.PHONY: distclean\r
+distclean: clean\r
+       @rm -rf $(PROJECT).hex $(PROJECT).lss $(PROJECT).map \r
+\r
+.PHONY: clean\r
+clean:\r
+       @rm -rf $(OBJECTS) $(TARGET) dep $(PROJECT).eep\r
+\r
+## Other dependencies\r
+-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)\r
+\r
diff --git a/gcc_cpp/Makefile b/gcc_cpp/Makefile
new file mode 100644 (file)
index 0000000..1e142cf
--- /dev/null
@@ -0,0 +1,81 @@
+###############################################################################\r
+# Makefile for the serial_lcd C & CPP versions \r
+\r
+## General Flags\r
+PROJECT = serial_lcd_cpp\r
+MCU = attiny2313\r
+TARGET = $(PROJECT).elf\r
+CC = avr-g++\r
+\r
+## Options common to compile, link and assembly rules\r
+COMMON = -mmcu=$(MCU)\r
+\r
+## Compile options common for all C compilation units.\r
+CFLAGS = $(COMMON)\r
+CFLAGS += -Wall -gdwarf-2  -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums\r
+CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d \r
+\r
+## Assembly specific flags\r
+ASMFLAGS = $(COMMON)\r
+ASMFLAGS += $(CFLAGS)\r
+ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2\r
+\r
+## Linker flags\r
+LDFLAGS = $(COMMON)\r
+LDFLAGS +=  -Wl,-Map=$(PROJECT).map\r
+\r
+\r
+## Intel Hex file production flags\r
+HEX_FLASH_FLAGS = -R .eeprom\r
+HEX_EEPROM_FLAGS = -j .eeprom\r
+HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"\r
+HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings\r
+\r
+\r
+## Include Directories\r
+INCLUDES = -I.\r
+\r
+## Objects that must be built in order to link\r
+OBJECTS = $(PROJECT).o \r
+\r
+## Objects explicitly added by the user\r
+LINKONLYOBJECTS = \r
+\r
+## Build\r
+all: $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss size \r
+\r
+## Compile\r
+$(PROJECT).o: ../$(PROJECT).cpp\r
+       $(CC) $(INCLUDES) $(CFLAGS) -c  $< -o $(PROJECT).o\r
+\r
+##Link\r
+$(TARGET): $(OBJECTS)\r
+        $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)\r
+\r
+$(PROJECT).hex: $(TARGET)\r
+       avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@\r
+\r
+$(PROJECT).eep: $(TARGET)\r
+       -avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0\r
+\r
+$(PROJECT).lss: $(TARGET)\r
+       avr-objdump -h -S $< > $@\r
+\r
+.PHONY: size\r
+\r
+size: ${TARGET}\r
+       @echo $(TARGET) size\r
+       @avr-size -C --mcu=${MCU} ${TARGET}\r
+\r
+## Clean target\r
+.PHONY: distclean\r
+distclean: clean\r
+       @rm -rf $(PROJECT).hex $(PROJECT).lss $(PROJECT).map \r
+\r
+.PHONY: clean\r
+clean:\r
+       @rm -rf $(OBJECTS) $(TARGET) dep $(PROJECT).eep\r
+\r
+## Other dependencies\r
+-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)\r
+\r
diff --git a/gcc_cpp_obj/Makefile b/gcc_cpp_obj/Makefile
new file mode 100644 (file)
index 0000000..9f5811c
--- /dev/null
@@ -0,0 +1,80 @@
+###############################################################################\r
+# Makefile for the serial_lcd C & CPP versions \r
+\r
+## General Flags\r
+PROJECT = serial_lcd_obj\r
+MCU = attiny2313\r
+TARGET = $(PROJECT).elf\r
+CC = avr-g++\r
+\r
+## Options common to compile, link and assembly rules\r
+COMMON = -mmcu=$(MCU)\r
+\r
+## Compile options common for all C compilation units.\r
+CFLAGS = $(COMMON)\r
+CFLAGS += -Wall -gdwarf-2  -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums\r
+CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d \r
+\r
+## Assembly specific flags\r
+ASMFLAGS = $(COMMON)\r
+ASMFLAGS += $(CFLAGS)\r
+ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2\r
+\r
+## Linker flags\r
+LDFLAGS = $(COMMON)\r
+LDFLAGS +=  -Wl,-Map=$(PROJECT).map\r
+\r
+\r
+## Intel Hex file production flags\r
+HEX_FLASH_FLAGS = -R .eeprom\r
+HEX_EEPROM_FLAGS = -j .eeprom\r
+HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"\r
+HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings\r
+\r
+\r
+## Include Directories\r
+INCLUDES = -I.\r
+\r
+## Objects that must be built in order to link\r
+OBJECTS = $(PROJECT).o \r
+\r
+## Objects explicitly added by the user\r
+LINKONLYOBJECTS = \r
+\r
+## Build\r
+all: $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss size \r
+\r
+## Compile\r
+$(PROJECT).o: ../$(PROJECT).cpp\r
+       $(CC) $(INCLUDES) $(CFLAGS) -c  $< -o $(PROJECT).o\r
+\r
+##Link\r
+$(TARGET): $(OBJECTS)\r
+        $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)\r
+\r
+$(PROJECT).hex: $(TARGET)\r
+       avr-objcopy -O ihex $(HEX_FLASH_FLAGS)  $< $@\r
+\r
+$(PROJECT).eep: $(TARGET)\r
+       -avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0\r
+\r
+$(PROJECT).lss: $(TARGET)\r
+       avr-objdump -h -S $< > $@\r
+\r
+.PHONY: size\r
+\r
+size: ${TARGET}\r
+       @echo $(TARGET) size\r
+       @avr-size -C --mcu=${MCU} ${TARGET}\r
+\r
+## Clean target\r
+.PHONY: distclean\r
+distclean: clean\r
+       @rm -rf $(PROJECT).hex $(PROJECT).lss $(PROJECT).map \r
+\r
+.PHONY: clean\r
+clean:\r
+       @rm -rf $(OBJECTS) $(TARGET) $(PROJECT).eep dep\r
+\r
+## Other dependencies\r
+-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)\r
diff --git a/iar_c/Makefile b/iar_c/Makefile
new file mode 100644 (file)
index 0000000..c0dfcb5
--- /dev/null
@@ -0,0 +1,42 @@
+###############################################################################\r
+# Makefile for the serial_lcd C & CPP versions \r
+\r
+## General Flags\r
+PROJECT = serial_lcd\r
+MCU = tiny2313\r
+TARGET = $(PROJECT).hex\r
+CC = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/iccavr.exe\r
+LD = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/xlink.exe\r
+\r
+## Compile options common for all C compilation units.\r
+CFLAGS = --cpu $(MCU) -lA $(PROJECT).lst -z9 -e --lock_regs 4 -D ENABLE_BIT_DEFINITIONS\r
+\r
+## Linker flags\r
+LDFLAGS = -Fubrof9 -xm -xs -f '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/config/lnktiny2313t.xcl' -l $(PROJECT).map -s main\r
+LIBS =  '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/lib/clib/cl0t.r90'\r
+\r
+## Include Directories\r
+INCLUDES = -I .. -I . -I '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/inc'\r
+\r
+## Objects that must be built in order to link\r
+OBJECTS = $(PROJECT).r90\r
+\r
+## Build\r
+all: $(TARGET)\r
+\r
+## Compile\r
+$(PROJECT).r90: ../$(PROJECT).c\r
+       $(CC) $(INCLUDES) $(CFLAGS) $<\r
+\r
+##Link\r
+$(TARGET): $(OBJECTS)\r
+        $(LD) $(LDFLAGS) $(OBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)\r
+\r
+## Clean target\r
+.PHONY: distclean\r
+distclean: clean\r
+       @rm -f $(TARGET) $(PROJECT).lst $(PROJECT).map \r
+\r
+.PHONY: clean\r
+clean:\r
+       @rm -f $(OBJECTS)\r
diff --git a/iar_cpp/Makefile b/iar_cpp/Makefile
new file mode 100644 (file)
index 0000000..5c63854
--- /dev/null
@@ -0,0 +1,42 @@
+###############################################################################\r
+# Makefile for the serial_lcd C & CPP versions \r
+\r
+## General Flags\r
+PROJECT = serial_lcd_cpp\r
+MCU = tiny2313\r
+TARGET = $(PROJECT).hex\r
+CC = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/iccavr.exe\r
+LD = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/xlink.exe\r
+\r
+## Compile options common for all C compilation units.\r
+CFLAGS = --cpu $(MCU) -lA $(PROJECT).lst -z9 -e  --ec++ --lock_regs 4 -D ENABLE_BIT_DEFINITIONS\r
+\r
+## Linker flags\r
+LDFLAGS = -Fubrof9 -xm -xs -f '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/config/lnktiny2313t.xcl' -l $(PROJECT).map -s main\r
+LIBS =  '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/lib/clib/cl0t.r90'\r
+\r
+## Include Directories\r
+INCLUDES = -I .. -I . -I '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/inc'\r
+\r
+## Objects that must be built in order to link\r
+OBJECTS = $(PROJECT).r90\r
+\r
+## Build\r
+all: $(TARGET)\r
+\r
+## Compile\r
+$(PROJECT).r90: ../$(PROJECT).cpp\r
+       $(CC) $(INCLUDES) $(CFLAGS) $<\r
+\r
+##Link\r
+$(TARGET): $(OBJECTS)\r
+        $(LD) $(LDFLAGS) $(OBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)\r
+\r
+## Clean target\r
+.PHONY: distclean\r
+distclean: clean\r
+       @rm -f $(TARGET) $(PROJECT).lst $(PROJECT).map \r
+\r
+.PHONY: clean\r
+clean:\r
+       @rm -f $(OBJECTS)\r
diff --git a/iar_cpp_obj/Makefile b/iar_cpp_obj/Makefile
new file mode 100644 (file)
index 0000000..c9ddf60
--- /dev/null
@@ -0,0 +1,42 @@
+###############################################################################\r
+# Makefile for the serial_lcd C & CPP versions \r
+\r
+## General Flags\r
+PROJECT = serial_lcd_obj\r
+MCU = tiny2313\r
+TARGET = $(PROJECT).hex\r
+CC = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/iccavr.exe\r
+LD = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/xlink.exe\r
+\r
+## Compile options common for all C compilation units.\r
+CFLAGS = --cpu $(MCU) -lA $(PROJECT).lst -z9 -e  --ec++ --lock_regs 4 -D ENABLE_BIT_DEFINITIONS\r
+\r
+## Linker flags\r
+LDFLAGS = -Fubrof9 -xm -xs -f '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/config/lnktiny2313t.xcl' -l $(PROJECT).map -s main\r
+LIBS =  '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/lib/clib/cl0t.r90'\r
+\r
+## Include Directories\r
+INCLUDES = -I .. -I . -I '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/inc'\r
+\r
+## Objects that must be built in order to link\r
+OBJECTS = $(PROJECT).r90\r
+\r
+## Build\r
+all: $(TARGET)\r
+\r
+## Compile\r
+$(PROJECT).r90: ../$(PROJECT).cpp\r
+       $(CC) $(INCLUDES) $(CFLAGS) $<\r
+\r
+##Link\r
+$(TARGET): $(OBJECTS)\r
+        $(LD) $(LDFLAGS) $(OBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET)\r
+\r
+## Clean target\r
+.PHONY: distclean\r
+distclean: clean\r
+       @rm -f $(TARGET) $(PROJECT).lst $(PROJECT).map \r
+\r
+.PHONY: clean\r
+clean:\r
+       @rm -f $(OBJECTS)\r
diff --git a/icc_c/Makefile b/icc_c/Makefile
new file mode 100644 (file)
index 0000000..dd575ab
--- /dev/null
@@ -0,0 +1,45 @@
+###############################################################################\r
+# Makefile for the serial_lcd C & CPP versions \r
+\r
+## General Flags\r
+PROJECT = serial_lcd\r
+MCU = attiny2313\r
+TARGET = $(PROJECT).hex\r
+CC = iccavr\r
+OBJECTS = $(PROJECT).o\r
+\r
+## Compile options common for all C compilation units.\r
+CFLAGS =  -e -D__ICC_VERSION="7.16A" -DATtiny2313  -l -A -A -g -Wf-r20_23 \r
+\r
+## Linker flags\r
+LDFLAGS = -g -e:0x0800 -bfunc_lit:0x26.0x800 -dram_end:0xdf -bdata:0x60.0xdf -dhwstk_size:30 -beeprom:0.128 -fihx_coff -S2\r
+\r
+## Assembler flags\r
+ASMFLAGS = $(CFLAGS)  -Wa-g\r
+\r
+## Include Directories\r
+INCLUDES = -I.\r
+\r
+## Objects explicitly added by the user\r
+LINKONLYOBJECTS = \r
+\r
+## Build\r
+all: $(TARGET)\r
+\r
+## Compile\r
+$(PROJECT).o: ../serial_lcd.c\r
+       $(CC) -c $(CFLAGS) $(INCLUDES) $<\r
+\r
+$(TARGET): $(OBJECTS)\r
+       $(CC) -o SERIAL_LCD $(LDFLAGS) $(OBJECTS) -lcavrgr\r
+\r
+## Clean target\r
+.PHONY: distclean\r
+distclean: clean\r
+       @rm -f $(OBJECTS) $(TARGET) $(PROJECT).lst $(PROJECT).mp $(PROJECT).hex\r
+\r
+.PHONY: clean\r
+clean:\r
+       @rm -f $(OBJECTS) $(PROJECT).dbg $(PROJECT).cof $(PROJECT).s \\r
+       $(PROJECT).cof $(PROJECT).lis\r
+\r
diff --git a/serial_lcd.c b/serial_lcd.c
new file mode 100644 (file)
index 0000000..0c8bb10
--- /dev/null
@@ -0,0 +1,478 @@
+/*****************************************************************************\r
+** FILE IDENTIFICATION\r
+**\r
+**   Name:          serial_lcd.cpp\r
+**   Purpose:       USART driven HD44780 LCD Driver\r
+**   Programmer:    Kevin Rosenberg <kevin@rosenberg.net>\r
+**                    (AVR Freaks member kmr)\r
+**   Date Started:  Dec 2007\r
+**\r
+**   Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved.\r
+**\r
+** Compilers supported:\r
+**   - WinAVR-20071221 (includes avr-libc 1.6 required for proper _delay_us)\r
+**   - IAR AVR 4.30\r
+**   - Imagecraft AVR 7\r
+**\r
+** LICENSE\r
+**   See accompaning LICENSE file\r
+**\r
+** CHANGES\r
+**   See accompaning CHANGES file for modifications log from original\r
+******************************************************************************/\r
+\r
+#include "serial_lcd.h"\r
+\r
+#if defined(__GNUC__)\r
+FUSES = {\r
+  .low = SUT1, \r
+  .high = (unsigned char) (DWEN & WDTON & RSTDISBL & BODLEVEL1 & BODLEVEL2),\r
+  .extended = EFUSE_DEFAULT,\r
+};\r
+#endif\r
+\r
+// Number of PWM brightness levels supported\r
+#define LED_BRIGHTNESS_LEVELS 8\r
+\r
+////// LCD Commands ///////\r
+// Turn on power to the display, no cursor\r
+#define        LCD_ON  0x0C\r
+// Clear display command\r
+#define LCD_CLR 0x01\r
+// Set 4 data bits \r
+#define LCD_4_Bit 0x20 \r
+// Set 8 data bits \r
+#define LCD_8_Bit 0x30 \r
+// Set number of lines \r
+#define LCD_4_Line 0x08 \r
+// Set 8 data bits\r
+#define        DATA_8  0x30\r
+// Set character font \r
+#define LCD_Font 0x04 \r
+// Turn the cursor on \r
+#define LCD_CURSOR_ON 0x02 \r
+// Turn on cursor blink \r
+#define LCD_CURSOR_BLINK 0x01 \r
+\r
+////// Serial command codes ///////\r
+// ASCII control code to set brightness level\r
+// Next byte is brightness ranging from 0 (no backlight) to 255 (max backlight)\r
+#define LED_SET_BRIGHTNESS 0xFB\r
+// ASCII control code turns on LED\r
+#define LED_SW_ON 0xFC\r
+// ASCII control code turns off LED\r
+#define LED_SW_OFF 0xFD\r
+// Character generator RAM command\r
+#define REG_MODE 0xFE\r
+\r
+// Circular buffer for UART RX\r
+#define UART_RX_BUFFER_SIZE 48\r
+#if defined(__IMAGECRAFT__)\r
+#pragma data:noinit\r
+volatile unsigned char sUartRxBuf[UART_RX_BUFFER_SIZE];\r
+#pragma data:data\r
+#else\r
+NO_INIT_DECLARE(volatile unsigned char sUartRxBuf[UART_RX_BUFFER_SIZE]);\r
+#endif\r
+\r
+// PWM Patterns (8-brightness levels)\r
+static FLASH_DECLARE(const unsigned char ledPwmPatterns[]) =\r
+{\r
+  0x10, // 0b00010000  0\r
+  0x11, // 0b00010001  1\r
+  0x4A, // 0b01001010  2\r
+  0x55, // 0b01010101  3\r
+  0x5D, // 0b01011101  4\r
+  0xEE, // 0b11101110  5\r
+  0x7F, // 0b11110111  6\r
+  0xFF, // 0b11111111  7\r
+};\r
+\r
+// register variables\r
+#if defined(__IMAGECRAFT__)\r
+#pragma global_register ledPwmCount:20 sUartRxHead:21 sUartRxTail:22 ledPwmCycling:23\r
+unsigned char ledPwmCount, sUartRxHead, sUartRxTail, ledPwmCycling;\r
+\r
+#else\r
+REGISTER_VAR(unsigned char ledPwmCount, "r4", 15);\r
+REGISTER_VAR(unsigned char sUartRxHead, "r5", 14);\r
+REGISTER_VAR(unsigned char sUartRxTail, "r6", 13);\r
+REGISTER_VAR(unsigned char ledPwmCycling, "r7", 12);\r
+#endif\r
+\r
+#define ledPwmPattern GPIOR0\r
+#define ledStatus GPIOR1\r
+#define BIT_led_on REGISTER_BIT(GPIOR1,0)\r
+\r
+// Function declarations\r
+void LcdWriteCmd (unsigned char);\r
+void LcdWriteData (unsigned char);\r
+unsigned char LcdBusyWait (void);\r
+static unsigned char WaitRxChar (void);\r
+\r
+// ImageCraft doesn't support inline functions, so use preprocessor\r
+#if defined(__IMAGECRAFT__)\r
+#define LedTimerStop() TCCR0B = 0\r
+// Start with 256 prescaler\r
+#define LedTimerStart() TCCR0B = (1<<CS02)\r
+\r
+#else\r
+// Using a platform that has proper inline functions\r
+INLINE_FUNC_DECLARE(static void LedTimerStop (void));\r
+static inline void LedTimerStop (void) {\r
+  TCCR0B = 0;\r
+}\r
+\r
+INLINE_FUNC_DECLARE(static void LedTimerStart (void));\r
+static inline void LedTimerStart (void) {\r
+  TCCR0B = (1<<CS02); // Start with 256 prescaler\r
+}\r
+#endif\r
+\r
+INLINE_FUNC_DECLARE(static void LedPwmInit (void));\r
+static inline void LedPwmInit (void) {\r
+  // setup PWM to run at 1.25ms per interrupt.\r
+  // This allows 8 levels of brightness at minimum of 100Hz flicker rate.\r
+  TCCR0A = (1<<WGM01);  // CTC mode\r
+  TCCR0B = 0;           // timer off\r
+  OCR0A = 72;           // 1.25ms with CLK/256 prescaler @ 14.7456MHz\r
+  TIMSK = (1<<OCIE0A);  // Turn on timer0 COMPA intr (all other timer intr off)\r
+  LED_PORT &= ~(1<<LED_PIN); // Ensure LED is off during initialization\r
+  LED_DIR |= (1<<LED_PIN);   // Ensure LED is output direction\r
+  BIT_led_on = 0;       // note that LED is off\r
+  ledPwmPattern = 0xFF; // maximum brightness\r
+}\r
+\r
+\r
+INLINE_FUNC_DECLARE(static void LedPwmSetBrightness (unsigned char brightness));\r
+static inline void LedPwmSetBrightness (unsigned char brightness) {\r
+  unsigned char ledPwmPos;\r
+\r
+  if (brightness == 0) { // turn backlight off for 0 brightness\r
+    if (BIT_led_on) {\r
+      LedTimerStop();\r
+      ledPwmPattern = 0;\r
+      ledPwmCycling = 0;\r
+      LED_PORT &= ~(1<<LED_PIN);\r
+    }\r
+    return;\r
+  }\r
+\r
+  ledPwmPos = (brightness * (LED_BRIGHTNESS_LEVELS-1) + 127) >> 8;\r
+  // Below is probably not required, but ensures we don't exceed array\r
+  if (ledPwmPos > LED_BRIGHTNESS_LEVELS - 1)\r
+    ledPwmPos = LED_BRIGHTNESS_LEVELS - 1;\r
+\r
+  ledPwmPattern = PGM_READ_BYTE (&ledPwmPatterns[ledPwmPos]);\r
+  ledPwmCount = 0;\r
+  ledPwmCycling = ledPwmPattern;\r
+  if (ledPwmPos >= LED_BRIGHTNESS_LEVELS-1) { // maximum brightness\r
+    // don't need PWM for continuously on\r
+    if (BIT_led_on) {\r
+      LedTimerStop();\r
+      LED_PORT |= (1<<LED_PIN);\r
+    }\r
+  } else {\r
+    if (BIT_led_on) {\r
+      LedTimerStart();\r
+    }\r
+  }\r
+}\r
+\r
+INLINE_FUNC_DECLARE(static void LedPwmSwitchOff (void));\r
+static inline void LedPwmSwitchOff (void) {\r
+  LED_PORT &= ~(1<<LED_PIN);\r
+  BIT_led_on = 0;\r
+  LedTimerStop();\r
+}\r
+\r
+INLINE_FUNC_DECLARE(static void LedPwmSwitchOn (void));\r
+static inline void LedPwmSwitchOn (void) {\r
+  BIT_led_on = 1;\r
+  if (ledPwmPattern == 0xFF) { // maximum brightness, no need for PWM\r
+    LedTimerStop();\r
+    LED_PORT |= (1<<LED_PIN); // keep LED on at all times\r
+  } else {\r
+    LedTimerStart();\r
+  }\r
+}\r
+\r
+// Actual baud rate = 9600 BAUD, (0.0% error) @ 14.7456MHz\r
+// Actual baud rate = 19.2K BAUD, (0.0% error) @ 14.7456MHz\r
+// Actual baud rate = 38.4K BAUD, (0.0% error) @ 14.7456MHz\r
+// Actual baud rate = 115.2K BAUD, (0.0% error) @ 14.7456MHz\r
+#define BAUD_4800 191\r
+#define BAUD_9600 95\r
+#define BAUD_14400 63\r
+#define BAUD_19200 47\r
+#define BAUD_28800 31\r
+#define BAUD_38400 23\r
+#define BAUD_57600 15\r
+#define BAUD_76800 11\r
+#define BAUD_115200 7\r
+\r
+FLASH_DECLARE(static const unsigned char BaudLookupTable[])\r
+= {BAUD_115200, BAUD_38400, BAUD_19200, BAUD_9600};\r
+\r
+INLINE_FUNC_DECLARE(static unsigned char GetUsartBaud (void));\r
+static inline unsigned char GetUsartBaud (void) {\r
+  // Get BAUD rate jumper settings\r
+  unsigned char BaudSelectJumpersValue  = BAUD_PIN_REG;\r
+  // Mask off unwanted bits\r
+  BaudSelectJumpersValue &= (1<<BAUD_J2) | (1<<BAUD_J1);\r
+  // BAUD_J2 = PD.3, BAUD_J1 = PD.2\r
+  // This is two bits too far to the left and the array index will\r
+  // increment by 4, instead of 1.\r
+  // Shift BAUD_J2 & BAUD_J1 right by two bit positions for proper array indexing\r
+  BaudSelectJumpersValue = (BaudSelectJumpersValue >> BAUD_J1);\r
+\r
+  return PGM_READ_BYTE (&BaudLookupTable[BaudSelectJumpersValue]);\r
+}\r
+\r
+\r
+INLINE_FUNC_DECLARE(static void UsartInit (void));\r
+static inline void UsartInit(void) {\r
+  // Initialize USART\r
+  UCSRB = 0; // Disable while setting baud rate\r
+  UCSRA = 0;\r
+  UCSRC = (1<<UCSZ1) | (1<<UCSZ0); // 8 bit data\r
+  UBRRL = GetUsartBaud (); // Set baud rate\r
+  UBRRH = 0; // Set baud rate hi\r
+  UCSRB = (1<<RXEN)|(1<<RXCIE); // RXEN = Enable\r
+  sUartRxHead = 0; // register variable, need to explicitly zero\r
+  sUartRxTail = 0; // register variable, need to explicitly zero\r
+\r
+#if USE_CTS\r
+  CTS_PORT |= (1<<CTS_PIN);  // bring signal high\r
+  CTS_DIR |= (1<<CTS_PIN);   // CTS is active low\r
+#endif\r
+}\r
+\r
+#if defined(__IMAGECRAFT__)\r
+// Clock cycle = 67nS @ 14.7456MHz\r
+// Delay resolution ~ 1uS @ 14.7456MHz\r
+// So this function is only accurate at near above frequency\r
+void _delay_us (unsigned int d) {\r
+  while (d-- != 0);\r
+  asm("nop");\r
+}\r
+#endif\r
+\r
+\r
+INLINE_FUNC_DECLARE(static void LcdInit (void));\r
+static inline void LcdInit (void) {\r
+  // Set BAUD_J2:BAUD_J1 PULL-UPS active\r
+  LCD_CONTROL_PORT = (1<<BAUD_J2) | (1<<BAUD_J1);\r
+  // Set LCD_control BAUD_J2:BAUD_J1 to inputs\r
+  LCD_CONTROL_DIR = 0xF2;\r
+\r
+  _delay_us(15000);\r
+  LCD_CONTROL_PORT |= (1<<LCD_RS); // Set LCD_RS HIGH\r
+\r
+  // Initialize the LCD Data AVR I/O\r
+  LCD_DATA_DIR = 0xFF; // Set LCD_DATA_PORT as all outputs\r
+  LCD_DATA_PORT = 0x00; // Set LCD_DATA_PORT to logic low\r
+\r
+  // Initialize the LCD controller\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_RS);\r
+  LcdWriteData (DATA_8);\r
+\r
+  _delay_us(4100);\r
+  LcdWriteData (DATA_8);\r
+\r
+  _delay_us(100);\r
+  LcdWriteData (DATA_8);\r
+  LCD_CONTROL_PORT |= (1<<LCD_RS);\r
+\r
+  // The display will be out into 8 bit data mode here\r
+  LcdWriteCmd (LCD_8_Bit | LCD_4_Line); // Set 8 bit data, 4 display lines\r
+  LcdWriteCmd (LCD_ON); // Power up the display\r
+  LcdWriteCmd (LCD_CLR); // Power up the display\r
+}\r
+\r
+MAIN_FUNC() {\r
+  MCUSR = 0; // clear all reset flags\r
+\r
+  wdt_reset();\r
+  WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+  WDTCSR = (1<<WDE)|(1<<WDP3)|(1<<WDP0); // 1024K cycles, 8.0sec\r
+  MCUCR &= ~((1<<SM1)|(1<<SM0)); // use idle sleep mode\r
+\r
+  LedPwmInit ();\r
+  LcdInit ();\r
+\r
+  // Initialize the AVR USART\r
+  UsartInit ();\r
+\r
+  sei();\r
+  while (1) {\r
+    unsigned char tail = sUartRxTail; // explicitly set order of volatile access\r
+    if (tail != sUartRxHead) { // Check if UART RX buffer has a character\r
+      unsigned char rx_byte = WaitRxChar();\r
+\r
+      // avoid use of switch statement as ImageCraft and GCC produce signifcantly\r
+      // more code for a switch statement than a sequence of if/else if\r
+      if (rx_byte == LED_SW_OFF) {\r
+        LedPwmSwitchOff();\r
+      } else if (rx_byte == LED_SW_ON) {\r
+        LedPwmSwitchOn();\r
+      } else if (rx_byte == LED_SET_BRIGHTNESS) {\r
+        rx_byte = WaitRxChar();  // read next byte which will be brightness\r
+        LedPwmSetBrightness(rx_byte);\r
+      } else if (rx_byte == REG_MODE) {\r
+        LcdWriteCmd (WaitRxChar()); // Send LCD command character\r
+      } else {\r
+        LcdWriteData (rx_byte); // Send LCD data character\r
+      }\r
+    } else {\r
+      // No characters waiting in RX buffer\r
+\r
+      cli();\r
+      wdt_reset();\r
+      MCUSR &= ~(1<<WDRF); // clear any watchdog interrupt flags\r
+      WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+      WDTCSR &= ~(1<<WDE); // watchdog timer off\r
+      sei();\r
+\r
+      sleep_enable();\r
+      sleep_cpu();\r
+      sleep_disable();\r
+\r
+      cli();\r
+      wdt_reset();\r
+      WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+      WDTCSR &= ~(1<<WDCE);\r
+      sei();\r
+    }\r
+  }\r
+  MAIN_FUNC_LAST();\r
+}\r
+\r
+void LcdWriteCmd (unsigned char Cmd) {\r
+  LcdBusyWait();\r
+  LCD_DATA_PORT = Cmd;  // BusyWait leaves RS low in "Register mode"\r
+  NOP();\r
+  LCD_CONTROL_PORT |= (1<<LCD_E);\r
+  ENABLE_WAIT();\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
+  NOP();\r
+  LCD_CONTROL_PORT |= (1<<LCD_RS); // Set display to "Character mode"\r
+}\r
+\r
+void LcdWriteData (unsigned char c) {\r
+  LcdBusyWait();\r
+  LCD_CONTROL_PORT |= (1<<LCD_RS); // Set display to "Character Mode"\r
+  LCD_DATA_PORT = c;\r
+  NOP();\r
+  LCD_CONTROL_PORT |= (1<<LCD_E);\r
+  ENABLE_WAIT();\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
+}\r
+\r
+unsigned char LcdBusyWait (void) {\r
+  unsigned char LCDStatus;\r
+  LCD_DATA_DIR = 0x00; // Set LCD data port to inputs\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_RS); // Set display to "Register mode"\r
+  LCD_CONTROL_PORT |= (1<<LCD_RW); // Put the display in the read mode\r
+  NOP();\r
+  do {\r
+    wdt_reset();\r
+    LCD_CONTROL_PORT |= (1<<LCD_E);\r
+    ENABLE_WAIT();\r
+    LCDStatus = LCD_DATA_PIN_REG;\r
+    LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
+  } while (LCDStatus & (1<<LCD_BUSY));\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_RW); // Put display in write mode\r
+  LCD_DATA_DIR = 0xFF; // Set LCD data port to outputs\r
+  return (LCDStatus);\r
+}\r
+\r
+#if defined(__IMAGECRAFT__)\r
+#pragma interrupt_handler usart_rx_handler:iv_USART0_RXC\r
+void usart_rx_handler(void)\r
+#else\r
+ISR(USART_RX_vect)\r
+#endif\r
+{\r
+  unsigned char rx = UDR;\r
+  // Calculate next buffer position.\r
+  unsigned char tmphead = sUartRxHead;\r
+  if (tmphead == UART_RX_BUFFER_SIZE-1)\r
+    tmphead = 0;\r
+  else\r
+    tmphead++;\r
+  // store in buffer if there is room\r
+  if (tmphead != sUartRxTail) {\r
+    sUartRxHead = tmphead;         // Store new index.\r
+    sUartRxBuf[tmphead] = rx;\r
+  }\r
+#if USE_CTS\r
+  // check if buffer is now full, if so switch CTS to inactive\r
+  if (tmphead == UART_RX_BUFFER_SIZE-1)\r
+    tmphead = 0;\r
+  else\r
+    tmphead++;\r
+  // CTS active if still room in buffer\r
+  if (tmphead != sUartRxTail) {\r
+    CTS_PORT |= (1<<CTS_PIN);\r
+  } else {\r
+    // no room left in buffer, so make CTS inactive\r
+    CTS_PORT &= ~(1<<CTS_PIN);\r
+  }\r
+#endif\r
+}\r
+\r
+static unsigned char WaitRxChar (void) {\r
+  // waits for next RX character, then return it\r
+  unsigned char tail;\r
+  do {\r
+    tail = sUartRxTail; // explicitly set order of volatile variable access\r
+    wdt_reset();\r
+  } while (sUartRxHead == tail); // while buffer is empty\r
+\r
+#if USE_CTS\r
+  // turn off interrupts so that if UART char ready to be stored, then storage\r
+  // will occur after CTS pin is set active. This allows UART ISR to set\r
+  //  CTS inactive if byte fills buffer after we remove current byte\r
+  cli();\r
+#endif\r
+\r
+  // increment tail position\r
+  if (tail == UART_RX_BUFFER_SIZE-1)\r
+    sUartRxTail = 0;\r
+  else\r
+    sUartRxTail++;\r
+\r
+#if USE_CTS\r
+  CTS_PORT |= (1<<CTS_PIN); // Ensure CTS is active since just removed a byte\r
+  sei();   // Allow UART ISR to read character and change potentially change CTS\r
+#endif\r
+\r
+  return sUartRxBuf[sUartRxTail];\r
+}\r
+\r
+#if defined(__IMAGECRAFT__)\r
+#pragma interrupt_handler timer0_compa_handler:iv_TIMER0_COMPA\r
+void timer0_compa_handler(void)\r
+#else\r
+  ISR(TIMER0_COMPA_vect)\r
+#endif\r
+{\r
+  sei(); // Okay to allow USART interrupts while controlling LED PWM\r
+\r
+  // Set current LED state based on cycling variable\r
+  if (ledPwmCycling & 0x01) {\r
+    LED_PORT |= (1<<LED_PIN);\r
+  } else {\r
+    LED_PORT &= ~(1<<LED_PIN);\r
+  }\r
+\r
+  // Update cycling variable for next interrupt\r
+  if (ledPwmCount >= LED_BRIGHTNESS_LEVELS-1) {\r
+    ledPwmCount = 0;\r
+    ledPwmCycling = ledPwmPattern;\r
+  } else {\r
+    ledPwmCount++;\r
+    ledPwmCycling >>= 1;\r
+  }\r
+}\r
diff --git a/serial_lcd.h b/serial_lcd.h
new file mode 100644 (file)
index 0000000..d02e589
--- /dev/null
@@ -0,0 +1,308 @@
+/*****************************************************************************\r
+** FILE IDENTIFICATION\r
+**\r
+**   Name:          serial_lcd.h\r
+**   Purpose:       Common header file for serial_lcd.c and serial_lcd.cpp\r
+**   Programmer:    Kevin Rosenberg <kevin@rosenberg.net> (AVR Freaks member kmr)\r
+**   Date Started:  Dec 2007\r
+**\r
+**   Copyright (c) 2007-2008 by Kevin Rosenberg\r
+*******************************************************************************/\r
+\r
+#ifndef __SERIAL_LCD_H__\r
+#define __SERIAL_LCD_H__ 1\r
+\r
+#ifndef F_CPU\r
+#define F_CPU 14745600UL\r
+#endif\r
+\r
+#define CONSERVATIVE_ENABLE_DURATION 0\r
+#define USE_CTS 0\r
+\r
+// Set STANDALONE_SOURCE as 1 to compile without KMR's standard header files, using\r
+// the below excerpts from these files\r
+#define STANDALONE_SOURCE 1\r
+#if STANDALONE_SOURCE\r
+\r
+#if defined(__GNUC__)\r
+#include <avr/io.h>\r
+#include <avr/pgmspace.h>\r
+#include <avr/sleep.h>\r
+#include <avr/interrupt.h>\r
+#include <avr/wdt.h>\r
+#include <util/delay.h>\r
+\r
+typedef struct\r
+{\r
+  unsigned bit0:1;\r
+  unsigned bit1:1;\r
+  unsigned bit2:1;\r
+  unsigned bit3:1;\r
+  unsigned bit4:1;\r
+  unsigned bit5:1;\r
+  unsigned bit6:1;\r
+  unsigned bit7:1;\r
+} _io_reg;\r
+\r
+#define FLASH_DECLARE(x) const x __attribute__((progmem))\r
+#define NO_INIT_DECLARE(x) x __attribute__((section (".noinit")))\r
+#define INLINE_FUNC_DECLARE(x) inline x __attribute__((always_inline))\r
+#define PGM_READ_BYTE(x) pgm_read_byte(x)\r
+#define NOP() asm volatile("nop");\r
+#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)_SFR_MEM_ADDR(rg))->bit##bt\r
+#define REGISTER_VAR(V,GNU,IAR) register volatile V asm(GNU)\r
+#define NO_RETURN_FUNC(fn) fn __attribute__((noreturn));        \\r
+fn\r
+#define MAIN_FUNC() int main(void) __attribute__((OS_main)); \\r
+int main(void)\r
+#define MAIN_FUNC_LAST() return 0\r
+\r
+#elif defined(__ICCAVR__)\r
+#include <ioavr.h>\r
+#include <intrinsics.h>\r
+\r
+// Ensure that register/vector definitions match datasheet/GCC\r
+#if defined(__ATtiny2313__)\r
+  #if !defined(WDTCSR)\r
+    #define WDTCSR WDTCR\r
+  #endif\r
+  #if defined(USART0_RX_vect) && !defined(USART_RX_vect)\r
+    #define USART_RX_vect USART0_RX_vect\r
+  #endif\r
+#endif\r
+\r
+#define FLASH_DECLARE(x) __flash x\r
+#define PRAGMA(x) _Pragma(#x)\r
+#define NO_INIT_DECLARE(x) __no_init x\r
+#define INLINE_FUNC_DECLARE(x) PRAGMA(inline=forced) \\r
+inline x\r
+#define PGM_READ_BYTE(x) (*(x))\r
+#define NOP() __no_operation();\r
+#define REGISTER_BIT(rg,bt) rg##_Bit##bt\r
+#define REGISTER_VAR(V,GNU,IAR) __regvar __no_init V @ ## IAR\r
+#define ISR(x) PRAGMA(vector=x) \\r
+__interrupt void x##_handler(void);  \\r
+__interrupt void x##_handler(void)\r
+#define NO_RETURN_FUNC(fn) __C_task fn\r
+#define MAIN_FUNC() __task void main(void)\r
+#define MAIN_FUNC_LAST()\r
+#define cli() __disable_interrupt()\r
+#define sei() __enable_interrupt()\r
+#define wdt_reset() __watchdog_reset()\r
+#define _delay_us(us) __delay_cycles((unsigned long)(((us * F_CPU)/1e6) + 0.5))\r
+#define _delay_ms(ms) __delay_cycles((unsigned long)(((ms * F_CPU)/1e3) + 0.5))\r
+#define sleep_cpu() __sleep()\r
+#if defined(__ATtiny2313__)\r
+#define sleep_enable() MCUCR |= (1<<SE)\r
+#define sleep_disable() MCUCR &= ~(1<<SE)\r
+#endif\r
+typedef __flash unsigned char prog_uint8_t;\r
+typedef __flash unsigned int prog_uint16_t;\r
+typedef __flash unsigned int prog_uint32_t;\r
+\r
+#elif defined(__IMAGECRAFT__)\r
+\r
+// Below #include requires ICC v7.16+\r
+#include <iccioavr.h>\r
+typedef struct {\r
+  unsigned bit0:1;\r
+  unsigned bit1:1;\r
+  unsigned bit2:1;\r
+  unsigned bit3:1;\r
+  unsigned bit4:1;\r
+  unsigned bit5:1;\r
+  unsigned bit6:1;\r
+  unsigned bit7:1;\r
+} _io_reg;\r
+\r
+#define NOP() asm("nop");\r
+// ImageCraft does not support inline functions\r
+#define inline\r
+#define INLINE_FUNC_DECLARE(x) x\r
+#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt\r
+#define NO_RETURN_FUNC(fn) fn\r
+#define MAIN_FUNC() void main(void)\r
+#define MAIN_FUNC_LAST()\r
+// __flash keyword was introduced in Imagecraft v7.15\r
+#define FLASH_DECLARE(x) __flash x\r
+#define PGM_READ_BYTE(x) (*(x))\r
+#define cli() asm("cli")\r
+#define sei() asm("sei")\r
+#define wdt_reset() asm("wdr")\r
+#define sleep_cpu() asm("sleep")\r
+// Below two definition specific for ATTiny2313 compatible sleep enable\r
+#define sleep_enable() MCUCR |= (1<<SE)\r
+#define sleep_disable() MCUCR &= ~(1<<SE)\r
+\r
+// CodeVision Compiler\r
+#elif defined(__CODEVISIONAVR__)\r
+#include <io.h>\r
+\r
+typedef struct {\r
+  unsigned bit0:1;\r
+  unsigned bit1:1;\r
+  unsigned bit2:1;\r
+  unsigned bit3:1;\r
+  unsigned bit4:1;\r
+  unsigned bit5:1;\r
+  unsigned bit6:1;\r
+  unsigned bit7:1;\r
+} _io_reg;\r
+\r
+#define FLASH_DECLARE(x) flash x\r
+#define ASM(a) asm(a)\r
+#define NOP() asm("nop");\r
+#define inline\r
+#define INLINE_FUNC_DECLARE(x) x\r
+#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt\r
+#define NEAR_VAR(x) x\r
+#define NO_RETURN_FUNC(fn) fn\r
+#define MAIN_FUNC(fn) fn\r
+#define MAIN_FUNC() void main(void)\r
+#define MAIN_FUNC_LAST()\r
+\r
+// 2007/11/29 - ImageCraft states they will support _Pragma() like IAR\r
+// in a "few months". At that point, REGISTER_VAR and NO_INIT_DECLARE can\r
+// be supported. REGISTER_VAR will need to be expanded with 4th variable to\r
+// hold register number for ImageCraft.\r
+// noinit for ImageCraft requires #pragma data:noinit\r
+//#define NO_INIT_DECLARE(x) _Pragma(data:noinit); x; _Pragma(data:data);\r
+#define NO_INIT_DECLARE(x) x\r
+//#define REGISTER_VAR(V,GNUR,IAR,ICC) _Pragma(global_register V ## : ## ICC)\r
+#define REGISTER_VAR(V,GNUR,IAR) V\r
+\r
+#define cli() asm("cli")\r
+#define sei() asm("sei")\r
+#define wdt_reset() asm("wdr")\r
+\r
+#else\r
+#error Unsupported compiler\r
+#endif\r
+\r
+#else\r
+// Use local cross-compiler compability files\r
+#include "kavr_compat.h"\r
+#include "ksleep.h"\r
+#include "kdelay.h"\r
+#endif\r
+\r
+\r
+/*************************************************************/\r
+/*************************************************************/\r
+\r
+/*     //// From the LCD perspective \\\\\r
+        RxD --> PORTD:0\r
+        LED <-- PORTD:1 // High = ON, Low = OFF\r
+        J_1 --> PORTD:2 // BAUD rate select\r
+        J_2 --> PORTD:3 // BAUD rate select\r
+        LCD:R/W <-- PORTD:4\r
+        LCD:RS <-- PORTD:5\r
+        LCD:E <-- PORTD:6\r
+        N/A <-> PORTD:7\r
+\r
+        LCD:R/W <-- PORTD:4\r
+        LCD:RS <-- PORTD:5\r
+        LCD:E <-- PORTD:6\r
+        LCD:Vee <-- CONTRAST\r
+        LCD:DB0 <-- PORTB:0\r
+        LCD:DB1 <-- PORTB:1\r
+        LCD:DB2 <-- PORTB:2\r
+        LCD:DB3 <-- PORTB:3\r
+        LCD:DB4 <-- 4.7K Ohm <-- PORTx:4\r
+        LCD:DB5 <-- 4.7K Ohm <-- PORTx:5\r
+        LCD:DB6 <-- 4.7K Ohm <-- PORTx:6\r
+        LCD:DB7 <-- 4.7K Ohm <-- PORTx:7\r
+\r
+       //// From the I/O PORTx perspective \\\\\r
+        PORTD:0 <--RxD\r
+        PORTD:1 --> LED // High = ON, Low = OFF\r
+        PORTD:2 <-- J_1 // BAUD rate select\r
+        PORTD:3 <-- J_2 // BAUD rate select\r
+        PORTD:4 --> LCD:R/W\r
+        PORTD:5 --> LCD:RS\r
+        PORTD:6 --> LCD:E\r
+        PORTD:7 <-> N/A\r
+\r
+        PORTB:0 --> LCD:DB0\r
+        PORTB:1 --> LCD:DB1\r
+        PORTB:2 --> LCD:DB2\r
+        PORTB:3 --> LCD:DB3\r
+        PORTB:4 --> 4.7K Ohm --> LCD:DB4\r
+        PORTB:5 --> 4.7K Ohm --> LCD:DB5\r
+        PORTB:6 --> 4.7K Ohm --> LCD:DB6\r
+        PORTB:7 --> 4.7K Ohm --> LCD:DB7\r
+*/\r
+\r
+/*************************************************************/\r
+/*************************************************************/\r
+// If you want to use a different I/O port for LCD control & data,\r
+// do it here!!!\r
+#define LCD_DATA_PORT PORTB\r
+#define LCD_DATA_PIN_REG PINB\r
+#define LCD_DATA_DIR DDRB\r
+\r
+#define LCD_CONTROL_PORT PORTD\r
+#define LCD_CONTROL_PIN_REG PIND\r
+#define LCD_CONTROL_DIR DDRD\r
+\r
+// LED backlight control pin\r
+#define LED_DIR DDRD\r
+#define LED_PORT PORTD\r
+#define LED_PIN PD1\r
+\r
+// LCD Read/Write Pin\r
+#define LCD_RW PD4\r
+// LCD Register Select Pin\r
+#define LCD_RS PD5\r
+// LCD Enable Pin\r
+#define LCD_E PD6\r
+/*************************************************************/\r
+/*************************************************************/\r
+\r
+// LCD busy status pin\r
+#define LCD_BUSY PB7\r
+\r
+// BAID rate setting pins\r
+#define BAUD_PORT PORTD\r
+#define BAUD_DIR  DDRB\r
+#define BAUD_PIN_REG PIND\r
+#define BAUD_J1 PD2\r
+#define BAUD_J2 PD3\r
+\r
+#if USE_CTS\r
+// Direction register for clear to send signal\r
+#define CTS_DIR DDRA\r
+// Output port for clear to send signal\r
+#define CTS_PORT PORTA\r
+// Pin for clear to send signal (RESET pin on Tiny2313)\r
+// Ensure fuse is set to disable RESET function on RESET pin\r
+#define CTS_PIN PA2\r
+#endif\r
+\r
+\r
+// PWeh must be 230nS minimum, nop = 67nS @ 14.7456MHz\r
+// At 4 cycles, E = 271nS\r
+// Some slow systems require 450ns, or 7 cycles at 14.7456MHz\r
+#if defined(__ICCAVR__)\r
+  #if CONSERVATIVE_ENABLE_DURATION\r
+    #define ENABLE_WAIT() __delay_cycles(7);\r
+  #else\r
+    #define ENABLE_WAIT() __delay_cycles(4);\r
+  #endif\r
+#elif defined(__GNUC__)\r
+  static __inline__ void _NOP1 (void) { __asm__ volatile ( "nop    " "\n\t" ); }\r
+  static __inline__ void _NOP2 (void) { __asm__ volatile ( "rjmp 1f" "\n\t"  "1:" "\n\t" ); }\r
+  #if CONSERVATIVE_ENABLE_DURATION\r
+    #define ENABLE_WAIT() _NOP2(); _NOP2(); _NOP2(); _NOP1();\r
+  #else\r
+    #define ENABLE_WAIT() _NOP2(); _NOP2();\r
+  #endif\r
+#else\r
+  #if CONSERVATIVE_ENABLE_DURATION\r
+    #define ENABLE_WAIT() NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();\r
+  #else\r
+    #define ENABLE_WAIT() NOP(); NOP(); NOP(); NOP();\r
+  #endif\r
+#endif\r
+\r
+#endif\r
diff --git a/serial_lcd_cpp.cpp b/serial_lcd_cpp.cpp
new file mode 100644 (file)
index 0000000..b4f0171
--- /dev/null
@@ -0,0 +1,524 @@
+/*****************************************************************************\r
+** FILE IDENTIFICATION\r
+**\r
+**   Name:          serial_lcd.cpp\r
+**   Purpose:       Serial Backpack firmware with C++ methods (no member variables)\r
+**   Programmer:    Kevin Rosenberg <kevin@rosenberg.net> (AVR Freaks member kmr)\r
+**   Date Started:  Dec 2007 (based on Jan 2, 2007 release by C.W. Livinston)\r
+**\r
+**   Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved.\r
+**\r
+** Compilers supported:\r
+**   - WinAVR-20071221\r
+**   - IAR AVR 4.30\r
+**\r
+** LICENSE\r
+**   See accompaning LICENSE file\r
+**\r
+** CHANGES\r
+**   See accompaning CHANGES file for modifications log from original\r
+******************************************************************************/\r
+\r
+\r
+#include "serial_lcd.h"\r
+\r
+// register variables\r
+REGISTER_VAR(unsigned char ledPwmCount, "r4", 15);\r
+REGISTER_VAR(unsigned char sUartRxHead, "r5", 14);\r
+REGISTER_VAR(unsigned char sUartRxTail, "r6", 13);\r
+REGISTER_VAR(unsigned char ledPwmCycling, "r7", 12);\r
+\r
+#define ledPwmPattern GPIOR0\r
+#define ledStatus GPIOR1\r
+#define BIT_led_on REGISTER_BIT(GPIOR1,0)\r
+\r
+//// Classes with only static methods\r
+\r
+class Watchdog {\r
+public:\r
+  INLINE_FUNC_DECLARE(static void init(void)) {\r
+    reset();\r
+    WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+    WDTCSR = (1<<WDE)|(1<<WDP3)|(1<<WDP0); // 1024K cycles, 8.0sec\r
+  }\r
+  INLINE_FUNC_DECLARE(static void off(void)) {\r
+    cli();\r
+    reset();\r
+    MCUSR &= ~(1<<WDRF); // clear any watchdog interrupt flags\r
+    WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+    WDTCSR &= ~(1<<WDE); // watchdog timer off\r
+    sei();\r
+  }\r
+  \r
+  INLINE_FUNC_DECLARE(static void on(void)) {\r
+    cli();\r
+    reset();\r
+    WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+    WDTCSR &= ~(1<<WDCE);\r
+    sei();\r
+  }\r
+  \r
+  INLINE_FUNC_DECLARE(static void reset(void)) { \r
+    wdt_reset(); \r
+  }\r
+};\r
+  \r
+class SleepMode {\r
+public:\r
+  INLINE_FUNC_DECLARE(static void initIdleMode(void)) {\r
+    MCUCR &= ~((1<<SM1)|(1<<SM0)); // use idle sleep mode\r
+  }\r
+  INLINE_FUNC_DECLARE(static void enterSleep()) {\r
+    sleep_enable();\r
+    sleep_cpu();\r
+    sleep_disable();\r
+  }\r
+};\r
+\r
+class Delay {\r
+public:\r
+  INLINE_FUNC_DECLARE(static void millisec(double ms)) {\r
+    _delay_ms(ms);\r
+  }\r
+  INLINE_FUNC_DECLARE(static void microsec(double ms)) {\r
+    _delay_us(ms);\r
+  }\r
+};\r
+\r
+\r
+//// Classes with non-static methods\r
+\r
+#define USE_LED_PWM_IO_MEMBERS 0\r
+\r
+class LedPwm {\r
+private:\r
+  static const prog_uint8_t ledPwmPatterns[];\r
+  static const unsigned char LED_BRIGHTNESS_LEVELS = 8;\r
+\r
+#if USE_LED_PWM_IO_MEMBERS\r
+  // LED backlight control pin\r
+  static volatile unsigned char * const m_LedDirPtr;\r
+  static volatile unsigned char * const m_LedPortPtr;\r
+  static const unsigned char m_LedPin = LED_PIN;\r
+#endif\r
+\r
+public:\r
+  INLINE_FUNC_DECLARE(void init(void)) {\r
+    // setup PWM to run at 1.25ms per interrupt. \r
+    // This allows 8 levels of brightness at minimum of 100Hz flicker rate.\r
+    TCCR0A = (1<<WGM01); // CTC mode\r
+    TCCR0B = 0; // timer off\r
+    OCR0A = 72; // 1.25ms with CLK/256 prescaler @ 14.7456MHz\r
+    TIMSK = (1<<OCIE0A); // Turn on timer0 COMPA intr (all other timer intr off)\r
+#if USE_LED_PWM_IO_MEMBERS\r
+    *m_LedPortPtr &= ~(1<<m_LedPin); // Ensure LED is off during initialization\r
+    *m_LedDirPtr |= (1<<m_LedPin); // Ensure LED is output port\r
+#else\r
+    LED_PORT &= ~(1<<LED_PIN); // Ensure LED is off during initialization\r
+    LED_DIR |= (1<<LED_PIN); // Ensure LED is output port\r
+#endif\r
+    BIT_led_on = 0;  // note that LED is off\r
+    ledPwmPattern = 0xFF;  // maximum brightness\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void stop(void)) {\r
+    TCCR0B = 0;\r
+  }\r
+  INLINE_FUNC_DECLARE(void start(void)) {\r
+    TCCR0B = (1<<CS02);\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void switchOff(void)) {\r
+    lampOff();\r
+    BIT_led_on = 0;\r
+    stop();\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void switchOn(void)) {\r
+    BIT_led_on = 1;\r
+    if (ledPwmPattern == 0xFF) { // maximum brightness, no need for PWM\r
+      stop();\r
+      lampOn();\r
+    } else {\r
+      start();\r
+    }\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void setBrightness(unsigned char brightness)) {\r
+    if (brightness == 0) { // turn backlight off for 0 brightness\r
+      if (BIT_led_on) {\r
+        stop();\r
+        ledPwmPattern = 0;\r
+        ledPwmCycling = 0;\r
+        lampOff();\r
+      }\r
+      return;\r
+    }\r
+\r
+    unsigned char ledPwmPos = (brightness * (LED_BRIGHTNESS_LEVELS-1) + 127) >> 8; \r
+    // Below is probably not required, but ensures we don't exceed array\r
+    if (ledPwmPos > LED_BRIGHTNESS_LEVELS - 1)\r
+      ledPwmPos = LED_BRIGHTNESS_LEVELS - 1;\r
+    ledPwmPattern = pwmPattern(ledPwmPos);\r
+    ledPwmCount = 0;\r
+    ledPwmCycling = ledPwmPattern;\r
+    if (ledPwmPos >= LED_BRIGHTNESS_LEVELS-1) { // maximum brightness\r
+      // don't need PWM to continuously on\r
+      if (BIT_led_on) {\r
+        stop();\r
+        lampOn();\r
+      }\r
+    } else {\r
+      if (BIT_led_on) {\r
+        start();\r
+      }\r
+    }\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void cyclePwm(void)) {\r
+    if (ledPwmCycling & 0x01) {   // Set current LED state based on cycling variable\r
+      lampOn();\r
+    } else {\r
+      lampOff();\r
+    }\r
+\r
+    // Update cycling variable for next interrupt\r
+    if (ledPwmCount >= LED_BRIGHTNESS_LEVELS-1) {\r
+      ledPwmCount = 0;\r
+      ledPwmCycling = ledPwmPattern;\r
+    } else {\r
+      ledPwmCount++;\r
+      ledPwmCycling >>= 1;\r
+    }\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void lampOn(void)) {\r
+#if USE_LED_PWM_IO_MEMBERS\r
+    *m_LedPortPtr |= (1<<m_LedPin);\r
+#else\r
+    LED_PORT |= (1<<LED_PIN);\r
+#endif\r
+  };\r
+\r
+  INLINE_FUNC_DECLARE(void lampOff(void)) {\r
+#if USE_LED_PWM_IO_MEMBERS\r
+    *m_LedPortPtr &= ~(1<<m_LedPin);;\r
+#else\r
+    LED_PORT &= ~(1<<LED_PIN);;\r
+#endif\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(unsigned char pwmPattern(unsigned char pos)) {\r
+    return PGM_READ_BYTE (&ledPwmPatterns[pos]);\r
+  }\r
+};\r
+\r
+#if USE_LED_PWM_IO_MEMBERS\r
+volatile unsigned char * const LedPwm::m_LedDirPtr = &LED_DIR;\r
+volatile unsigned char * const LedPwm::m_LedPortPtr = &LED_PORT;\r
+#endif\r
+\r
+// PWM Patterns (8-brightness levels)\r
+const prog_uint8_t LedPwm::ledPwmPatterns[] = {\r
+  0x10, // 0b00010000  0\r
+  0x11, // 0b00010001  1\r
+  0x4A, // 0b01001010  2\r
+  0x55, // 0b01010101  3\r
+  0x5D, // 0b01011101  4\r
+  0xEE, // 0b11101110  5\r
+  0x7F, // 0b11110111  6\r
+  0xFF, // 0b11111111  7\r
+};\r
+\r
+\r
+class Lcd {\r
+private:\r
+  // Turn on power to the display, no cursor\r
+  static const unsigned char m_PWR_ON = 0x0C;\r
+  // Clear display command\r
+  static const unsigned char m_CLR_DSP = 0x01;\r
+  // Set 8 data bits, 4 display lines\r
+  static const unsigned char m_LINE_8x4 = 0x38;\r
+  // Set 8 data bits\r
+  static const unsigned char m_DATA_8 = 0x30;\r
+\r
+public:\r
+  INLINE_FUNC_DECLARE(void init(void)) {\r
+    // Set BAUD_J2:BAUD_J1 PULL-UPS active\r
+    LCD_CONTROL_PORT = (1<<BAUD_J2) | (1<<BAUD_J1);\r
+    // Set LCD_control BAUD_J2:BAUD_J1 to inputs       \r
+    LCD_CONTROL_DIR = 0xF2;\r
+    \r
+    Delay::millisec(15);\r
+    \r
+    LCD_CONTROL_PORT |= (1<<LCD_RS); // Set LCD_RS HIGH\r
+    \r
+    // Initialize the AVR controller I/O\r
+    LCD_DATA_DIR = 0xFF; // Set LCD_DATA_PORT as all outputs\r
+    LCD_DATA_PORT = 0x00; // Set LCD_DATA_PORT to logic low\r
+    \r
+    // Initialize the LCD controller\r
+    LCD_CONTROL_PORT &= ~(1<<LCD_RS);\r
+    \r
+    putChar (m_DATA_8); \r
+    Delay::millisec(4.1);\r
+    \r
+    putChar (m_DATA_8);\r
+    Delay::microsec(100);\r
+    \r
+    putChar (m_DATA_8);\r
+    LCD_CONTROL_PORT |= (1<<LCD_RS);\r
+    \r
+    // The display will be out into 8 bit data mode here\r
+    putCmd (m_LINE_8x4); // Set 8 bit data, 4 display lines\r
+    putCmd (m_PWR_ON); // Power up the display\r
+    putCmd (m_CLR_DSP); // Power up the display\r
+  }\r
+\r
+  void putChar(unsigned char ch);\r
+  void putCmd(unsigned char ch);\r
+\r
+private:\r
+  unsigned char busyWait(void);\r
+};\r
+\r
+\r
+// round to nearest integer\r
+\r
+class Uart {\r
+private:\r
+// Circular buffer for UART RX\r
+  //NO_INIT_DECLARE(volatile unsigned char sUartRxBuf[UART_RX_BUFFER_SIZE]);\r
+  static const prog_uint8_t BaudLookupTable[];\r
+\r
+  static const unsigned char UART_RX_BUFFER_SIZE = 48;\r
+  volatile unsigned char m_UartRxBuf[UART_RX_BUFFER_SIZE];\r
+\r
+  INLINE_FUNC_DECLARE(static unsigned char baud()) {\r
+    unsigned char BaudSelectJumpersValue;\r
+  \r
+    // Get BAUD rate jumper settings      \r
+    BaudSelectJumpersValue  = BAUD_PIN_REG;\r
+    // Mask off unwanted bits\r
+    BaudSelectJumpersValue &= (1<<BAUD_J2) | (1<<BAUD_J1);\r
+    // BAUD_J2 = PD.3, BAUD_J1 = PD.2\r
+    // This is two bits too far to the left and the array index will\r
+    // increment by 4, instead of 1.\r
+    // Shift BAUD_J2 & BAUD_J1 right by two bit positions for proper array indexing\r
+    BaudSelectJumpersValue = (BaudSelectJumpersValue >> BAUD_J1);\r
+    \r
+    return PGM_READ_BYTE (&BaudLookupTable[BaudSelectJumpersValue]);\r
+  }\r
+\r
+public:\r
+  INLINE_FUNC_DECLARE(void init(void)) {\r
+    // Initialize UART0 \r
+    UCSRB = 0; // Disable while setting baud rate\r
+    UCSRA = 0;\r
+    UCSRC = (1<<UCSZ1) | (1<<UCSZ0); // 8 bit data\r
+    UBRRL = baud();\r
+    UBRRH = 0; // Set baud rate hi\r
+    UCSRB = (1<<RXEN)|(1<<RXCIE); // RXEN = Enable\r
+\r
+    // Init circular buffer pointers\r
+    sUartRxHead = 0;\r
+    sUartRxTail = 0;\r
+\r
+#if USE_CTS\r
+  CTS_PORT |= (1<<CTS_PIN);  // bring signal high\r
+  CTS_DIR |= (1<<CTS_PIN);   // CTS is active low\r
+#endif\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(unsigned char storeChar(unsigned char rx)) {\r
+    // Calculate next buffer position.\r
+    unsigned char tmphead = sUartRxHead;\r
+    if (tmphead == UART_RX_BUFFER_SIZE-1)\r
+      tmphead = 0;\r
+    else\r
+      tmphead++;\r
+    \r
+    // store in buffer if there is room\r
+    if (tmphead != sUartRxTail) {\r
+      sUartRxHead = tmphead;         // Store new index.\r
+      m_UartRxBuf[tmphead] = rx;\r
+    } else {\r
+      // no room to store character -- data loss\r
+#if USE_CTS\r
+      CTS_PORT &= ~(1<<CTS_PIN);\r
+#endif\r
+      return 0;\r
+    }\r
+    \r
+#if USE_CTS\r
+    // check if buffer is now full, if so switch CTS to inactive\r
+    if (tmphead == UART_RX_BUFFER_SIZE-1)\r
+      tmphead = 0;\r
+    else\r
+      tmphead++;\r
+    // CTS active if still room in buffer\r
+    if (tmphead != sUartRxTail) {\r
+      CTS_PORT |= (1<<CTS_PIN);\r
+    } else {\r
+      // no room left in buffer, so make CTS inactive\r
+      CTS_PORT &= ~(1<<CTS_PIN);\r
+    }\r
+#endif \r
+    return 1;\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(unsigned char charAvail(void)) {\r
+    unsigned char tail = sUartRxTail; // explicitly set order of volatile access\r
+    return (tail != sUartRxHead) ? 1 : 0;\r
+  }\r
+\r
+  unsigned char waitRxChar (void);\r
+};\r
+  \r
+#define UART_UBRR(baud) ((F_CPU+(8*(unsigned long) (baud)))/ (16*((unsigned long) (baud))) - 1)\r
+const prog_uint8_t Uart::BaudLookupTable[] =\r
+  {UART_UBRR(115200), UART_UBRR(38400), UART_UBRR(19200), UART_UBRR(9600)};\r
+\r
+unsigned char Uart::waitRxChar (void) {\r
+  // waits for next RX character, then return it\r
+  unsigned char tail;\r
+  do {\r
+    tail = sUartRxTail; // explicitly set order of volatile variable access\r
+    Watchdog::reset();\r
+  } while (sUartRxHead == tail); // while buffer is empty\r
+\r
+#if USE_CTS\r
+  // turn off interrupts so that if UART char ready to be stored, then storage\r
+  // will occur after CTS pin is set active. This allows UART ISR to set\r
+  //  CTS inactive if byte fills buffer after we remove current byte\r
+  cli();\r
+#endif\r
+\r
+  // increment tail position \r
+  if (tail == UART_RX_BUFFER_SIZE-1)\r
+    sUartRxTail = 0;\r
+  else\r
+    sUartRxTail++;\r
+\r
+#if USE_CTS\r
+  CTS_PORT |= (1<<CTS_PIN); // Ensure CTS is active since just removed a byte\r
+  sei();   // Allow UART ISR to read character and change potentially change CTS\r
+#endif\r
+\r
+  return m_UartRxBuf[sUartRxTail];\r
+}\r
+\r
+LedPwm gLed;\r
+Lcd gLcd;\r
+Uart gUart;\r
+\r
+\r
+class SerialCommandProcessor {\r
+private:\r
+// ASCII control code to set brightness level\r
+// Next byte is brightness ranging from 0 (no backlight) to 255 (max backlight)\r
+  static const unsigned char m_LED_SET_BRIGHTNESS = 0xFB;\r
+// ASCII control code turns on LED\r
+  static const unsigned char m_LED_SW_ON = 0xFC;\r
+// ASCII control code turns off LED\r
+  static const unsigned char m_LED_SW_OFF = 0xFD;\r
+// Character generator RAM command\r
+  static const unsigned char m_REG_MODE = 0xFE;\r
+\r
+public:\r
+  INLINE_FUNC_DECLARE(static void processChar(unsigned char ch)) {\r
+    // avoid use of switch statement as ImageCraft and GCC produce signifcantly\r
+    // more code for a switch statement than a sequence of if/else if\r
+    if (ch == m_LED_SW_OFF) {\r
+      gLed.switchOff();\r
+    } else if (ch == m_LED_SW_ON) {\r
+      gLed.switchOn();\r
+    } else if (ch == m_LED_SET_BRIGHTNESS) {\r
+      // read next byte which will be brightness\r
+      gLed.setBrightness(gUart.waitRxChar());\r
+    } else if (ch == m_REG_MODE) {\r
+      gLcd.putCmd (gUart.waitRxChar()); // Send LCD command character\r
+    } else {\r
+      gLcd.putChar (ch); // Send LCD data character\r
+    }\r
+  }\r
+};\r
+\r
+\r
+MAIN_FUNC() {\r
+  MCUSR = 0; // clear all reset flags\r
+  Watchdog::init();\r
+\r
+  SleepMode::initIdleMode();\r
+\r
+  gLed.init();\r
+  gLcd.init();\r
+  gUart.init();   // Initialize the AVR USART  \r
+\r
+  sei();\r
+  while (1) {\r
+    if (gUart.charAvail()) {\r
+      SerialCommandProcessor::processChar (gUart.waitRxChar());\r
+    } else {\r
+      // No characters waiting in RX buffer\r
+\r
+      Watchdog::off();\r
+      SleepMode::enterSleep();\r
+      Watchdog::on();\r
+    }\r
+  }\r
+  MAIN_FUNC_LAST();\r
+}\r
+\r
+void Lcd::putCmd (unsigned char Cmd) {\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_RS);\r
+  busyWait();\r
+  LCD_DATA_PORT = Cmd; \r
+  NOP();\r
+  LCD_CONTROL_PORT |= (1<<LCD_E);\r
+  ENABLE_WAIT();\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
+  NOP();\r
+  LCD_CONTROL_PORT |= (1<<LCD_RS);\r
+}\r
+\r
+void Lcd::putChar (unsigned char c) {\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_RS);\r
+  busyWait();\r
+  LCD_CONTROL_PORT |= (1<<LCD_RS);\r
+  LCD_DATA_PORT = c;\r
+  NOP();\r
+  LCD_CONTROL_PORT |= (1<<LCD_E);\r
+  ENABLE_WAIT();\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
+}\r
+\r
+unsigned char Lcd::busyWait (void) {\r
+  unsigned char LCDStatus; \r
+  LCD_DATA_DIR = 0x00; // Set LCD data port to inputs\r
+  LCD_CONTROL_PORT |= (1<<LCD_RW);\r
+  NOP();\r
+  do {\r
+    Watchdog::reset();\r
+    LCD_CONTROL_PORT |= (1<<LCD_E);    \r
+    ENABLE_WAIT();\r
+    LCDStatus = LCD_DATA_PIN_REG;\r
+    LCD_CONTROL_PORT &= ~(1<<LCD_E);\r
+  } while (LCDStatus & (1<<LCD_BUSY));\r
+  LCD_CONTROL_PORT &= ~(1<<LCD_RW);    \r
+  LCD_DATA_DIR = 0xFF; // Set LCD data port to default output state\r
+  return (LCDStatus);\r
+}               \r
+\r
+\r
+ISR(USART_RX_vect)\r
+{\r
+  gUart.storeChar(UDR);\r
+}\r
+\r
+ISR(TIMER0_COMPA_vect)\r
+{  \r
+  sei(); // Okay to allow USART interrupts while controlling LED PWM\r
+\r
+  gLed.cyclePwm();\r
+}\r
diff --git a/serial_lcd_obj.cpp b/serial_lcd_obj.cpp
new file mode 100644 (file)
index 0000000..8d24ca3
--- /dev/null
@@ -0,0 +1,561 @@
+/*****************************************************************************\r
+** FILE IDENTIFICATION\r
+**\r
+**   Name:          serial_lcd_obj.cpp\r
+**   Purpose:       Serial backback firmware with C++ objects\r
+**   Programmer:    Kevin Rosenberg <kevin@rosenberg.net> (AVR Freaks member kmr)\r
+**   Date Started:  Dec 2007\r
+**\r
+**   Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved.\r
+**\r
+** Compilers supported:\r
+**   - WinAVR-20071221\r
+**   - IAR AVR 4.30\r
+**\r
+** LICENSE\r
+**   See accompaning LICENSE file\r
+**\r
+** CHANGES\r
+**   See accompaning CHANGES file for modifications log from original\r
+******************************************************************************/\r
+\r
+\r
+#include "serial_lcd.h"\r
+\r
+//// Classes with only static methods\r
+\r
+class Watchdog {\r
+public:\r
+  INLINE_FUNC_DECLARE(static void init(void)) {\r
+    reset();\r
+    WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+    WDTCSR = (1<<WDE)|(1<<WDP3)|(1<<WDP0); // 1024K cycles, 8.0sec\r
+  }\r
+  INLINE_FUNC_DECLARE(static void off(void)) {\r
+    cli();\r
+    reset();\r
+    MCUSR &= ~(1<<WDRF); // clear any watchdog interrupt flags\r
+    WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+    WDTCSR &= ~(1<<WDE); // watchdog timer off\r
+    sei();\r
+  }\r
+  \r
+  INLINE_FUNC_DECLARE(static void on(void)) {\r
+    cli();\r
+    reset();\r
+    WDTCSR |= (1<<WDCE)|(1<<WDE); // start timed sequence (keep old prescaler)\r
+    WDTCSR &= ~(1<<WDCE);\r
+    sei();\r
+  }\r
+  \r
+  INLINE_FUNC_DECLARE(static void reset(void)) { \r
+    wdt_reset(); \r
+  }\r
+};\r
+\r
+\r
+class SleepMode {\r
+public:\r
+  INLINE_FUNC_DECLARE(static void initIdleMode(void)) {\r
+    MCUCR &= ~((1<<SM1)|(1<<SM0)); // use idle sleep mode\r
+  }\r
+  INLINE_FUNC_DECLARE(static void enterSleep()) {\r
+    sleep_enable();\r
+    sleep_cpu();\r
+    sleep_disable();\r
+  }\r
+};\r
+\r
+class Delay {\r
+public:\r
+  INLINE_FUNC_DECLARE(static void millisec(double ms)) {\r
+    _delay_ms(ms);\r
+  }\r
+  INLINE_FUNC_DECLARE(static void microsec(double ms)) {\r
+    _delay_us(ms);\r
+  }\r
+};\r
+\r
+\r
+//// Classes with non-static functions\r
+\r
+class LedPwm {\r
+private:\r
+  static const unsigned char m_LED_BRIGHTNESS_LEVELS = 8;\r
+  static const prog_uint8_t m_ledPwmPatterns[];\r
+\r
+  volatile unsigned char m_ledPwmCount;\r
+  volatile unsigned char m_ledPwmCycling;\r
+  unsigned char m_ledPwmPattern;\r
+  unsigned char m_BIT_led_on;\r
+  volatile unsigned char * m_LedPort;\r
+  volatile unsigned char * m_LedDir;\r
+  unsigned char m_LedPin;\r
+\r
+public:\r
+  INLINE_FUNC_DECLARE(void init(volatile unsigned char* port, \r
+                                volatile unsigned char* dir, \r
+                                unsigned char pin)) {\r
+    m_LedPort = port;\r
+    m_LedDir = dir;\r
+    m_LedPin = pin;\r
+\r
+    // setup PWM to run at 1.25ms per interrupt. \r
+    // This allows 8 levels of brightness at minimum of 100Hz flicker rate.\r
+    TCCR0A = (1<<WGM01); // CTC mode\r
+    TCCR0B = 0; // timer off\r
+    OCR0A = 72; // 1.25ms with CLK/256 prescaler @ 14.7456MHz\r
+    TIMSK = (1<<OCIE0A); // Turn on timer0 COMPA intr (all other timer intr off)\r
+    *m_LedPort &= ~(1<<m_LedPin); // Ensure LED is off during initialization\r
+    *m_LedDir |= (1<<m_LedPin); // Ensure LED is output port\r
+    m_BIT_led_on = 0;  // note that LED is off\r
+    m_ledPwmPattern = 0xFF;  // maximum brightness\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void stop(void)) {\r
+    TCCR0B = 0;\r
+  }\r
+  INLINE_FUNC_DECLARE(void start(void)) {\r
+    TCCR0B = (1<<CS02);\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void switchOff(void)) {\r
+    lampOff();\r
+    m_BIT_led_on = 0;\r
+    stop();\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void switchOn(void)) {\r
+    m_BIT_led_on = 1;\r
+    if (m_ledPwmPattern == 0xFF) { // maximum brightness, no need for PWM\r
+      stop();\r
+      lampOn();\r
+    } else {\r
+      start();\r
+    }\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void setBrightness(unsigned char brightness)) {\r
+    if (brightness == 0) { // turn backlight off for 0 brightness\r
+      if (m_BIT_led_on) {\r
+        stop();\r
+        m_ledPwmPattern = 0;\r
+        m_ledPwmCycling = 0;\r
+        lampOff();\r
+      }\r
+      return;\r
+    }\r
+\r
+    unsigned char ledPwmPos = (brightness * (m_LED_BRIGHTNESS_LEVELS-1) + 127) >> 8; \r
+    // Below is probably not required, but ensures we don't exceed array\r
+    if (ledPwmPos > m_LED_BRIGHTNESS_LEVELS - 1)\r
+      ledPwmPos = m_LED_BRIGHTNESS_LEVELS - 1;\r
+    m_ledPwmPattern = pwmPattern(ledPwmPos);\r
+    m_ledPwmCount = 0;\r
+    m_ledPwmCycling = m_ledPwmPattern;\r
+    if (ledPwmPos >= m_LED_BRIGHTNESS_LEVELS-1) { // maximum brightness\r
+      // don't need PWM to continuously on\r
+      if (m_BIT_led_on) {\r
+        stop();\r
+        lampOn();\r
+      }\r
+    } else {\r
+      if (m_BIT_led_on) {\r
+        start();\r
+      }\r
+    }\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void cyclePwm(void)) {\r
+    if (m_ledPwmCycling & 0x01) {   // Set current LED state based on cycling variable\r
+      lampOn();\r
+    } else {\r
+      lampOff();\r
+    }\r
+\r
+    // Update cycling variable for next interrupt\r
+    if (m_ledPwmCount >= m_LED_BRIGHTNESS_LEVELS-1) {\r
+      m_ledPwmCount = 0;\r
+      m_ledPwmCycling = m_ledPwmPattern;\r
+    } else {\r
+      m_ledPwmCount++;\r
+      m_ledPwmCycling >>= 1;\r
+    }\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void lampOn(void)) {\r
+    *m_LedPort |= (1<<m_LedPin);\r
+  };\r
+\r
+  INLINE_FUNC_DECLARE(void lampOff(void)) {\r
+    *m_LedPort &= ~(1<<m_LedPin);;\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(unsigned char pwmPattern(unsigned char pos)) {\r
+    return PGM_READ_BYTE (&m_ledPwmPatterns[pos]);\r
+  }\r
+};\r
+\r
+// PWM Patterns (8-brightness levels)\r
+const prog_uint8_t LedPwm::m_ledPwmPatterns[] = {\r
+  0x10, // 0b00010000  0\r
+  0x11, // 0b00010001  1\r
+  0x4A, // 0b01001010  2\r
+  0x55, // 0b01010101  3\r
+  0x5D, // 0b01011101  4\r
+  0xEE, // 0b11101110  5\r
+  0x7F, // 0b11110111  6\r
+  0xFF, // 0b11111111  7\r
+};\r
+\r
+\r
+class Lcd {\r
+private:\r
+  // Turn on power to the display, no cursor\r
+  static const unsigned char m_PWR_ON = 0x0C;\r
+  // Clear display command\r
+  static const unsigned char m_CLR_DSP = 0x01;\r
+  // Set 8 data bits, 4 display lines\r
+  static const unsigned char m_LINE_8x4 = 0x38;\r
+  // Set 8 data bits\r
+  static const unsigned char m_DATA_8 = 0x30;\r
+\r
+  volatile unsigned char * m_ctrlPort;\r
+  volatile unsigned char * m_ctrlDir;\r
+  volatile unsigned char * m_dataPort;\r
+  volatile unsigned char * m_dataDir;\r
+  volatile unsigned char * m_dataPinReg;\r
+  unsigned char m_rsPin;\r
+  unsigned char m_rwPin;\r
+  unsigned char m_ePin;\r
+\r
+  unsigned char busyWait(void);\r
+\r
+public:\r
+  INLINE_FUNC_DECLARE(void init(volatile unsigned char* ctrlPort, \r
+                                volatile unsigned char* ctrlDir, \r
+                                volatile unsigned char* dataPort,\r
+                                volatile unsigned char* dataDir,\r
+                                volatile unsigned char* dataPinReg,\r
+                                unsigned char rsPin,\r
+                                unsigned char rwPin,\r
+                                unsigned char ePin)) {\r
+    m_ctrlPort = ctrlPort;\r
+    m_ctrlDir = ctrlDir;\r
+    m_dataPort = dataPort;\r
+    m_dataDir = dataDir;\r
+    m_dataPinReg = dataPinReg;\r
+    m_rsPin = rsPin;\r
+    m_rwPin = rwPin;\r
+    m_ePin = ePin;\r
+\r
+    *m_ctrlPort &= ~((1<<m_rsPin)|(1<<m_rwPin)|(1<<m_ePin)); // set low\r
+    *m_ctrlDir |= ((1<<m_rsPin)|(1<<m_rwPin)|(1<<m_ePin)); // set as output\r
+                   \r
+    Delay::millisec(15);\r
+    \r
+    *m_ctrlPort |= (1<<LCD_RS); // Set LCD_RS HIGH\r
+    \r
+    // Initialize the AVR controller I/O\r
+    *m_dataDir = 0xFF; // Set LCD_DATA_OUT as all outputs\r
+    *m_dataPort = 0x00; // Set LCD_DATA_OUT to logic low\r
+    \r
+    // Initialize the LCD controller\r
+    *m_ctrlPort &= ~(1<<LCD_RS);\r
+    \r
+    putChar (m_DATA_8); \r
+    Delay::millisec(4.1);\r
+    \r
+    putChar (m_DATA_8);\r
+    Delay::microsec(100);\r
+    \r
+    putChar (m_DATA_8);\r
+    *m_ctrlPort |= (1<<LCD_RS);\r
+    \r
+    // The display will be out into 8 bit data mode here\r
+    putCmd (m_LINE_8x4); // Set 8 bit data, 4 display lines\r
+    putCmd (m_PWR_ON); // Power up the display\r
+    putCmd (m_CLR_DSP); // Power up the display\r
+  }\r
+\r
+  void putChar(unsigned char ch);\r
+  void putCmd(unsigned char ch);\r
+\r
+};\r
+\r
+void Lcd::putCmd (unsigned char Cmd) {\r
+  *m_ctrlPort &= ~(1<<m_rsPin);\r
+  busyWait();\r
+  *m_dataPort = Cmd;   \r
+  NOP();\r
+  *m_ctrlPort |= (1<<m_ePin);\r
+  ENABLE_WAIT();\r
+  *m_ctrlPort &= ~(1<<m_ePin);\r
+  NOP();\r
+  *m_ctrlPort |= (1<<m_rsPin);\r
+}\r
+\r
+void Lcd::putChar (unsigned char c) {\r
+  *m_ctrlPort &= ~(1<<m_rsPin);\r
+  busyWait();\r
+  *m_ctrlPort |= (1<<m_rsPin);\r
+  *m_dataPort = c;\r
+  NOP();\r
+  *m_ctrlPort |= (1<<m_ePin);\r
+  ENABLE_WAIT();\r
+  *m_ctrlPort &= ~(1<<m_ePin);\r
+}\r
+\r
+unsigned char Lcd::busyWait (void) {\r
+  unsigned char LCDStatus; \r
+  *m_dataDir = 0x00; // Set LCD data port to inputs\r
+  *m_ctrlPort |= (1<<m_rwPin);\r
+  NOP();\r
+  do {\r
+    Watchdog::reset();\r
+    *m_ctrlPort |= (1<<m_ePin);        \r
+    ENABLE_WAIT();\r
+    LCDStatus = *m_dataPinReg;\r
+    *m_ctrlPort &= ~(1<<m_ePin);\r
+  } while (LCDStatus & (1<<LCD_BUSY));\r
+  *m_ctrlPort &= ~(1<<m_rwPin);        \r
+  *m_dataDir = 0xFF; // Set LCD data port to default output state\r
+  return (LCDStatus);\r
+}               \r
+\r
+\r
+\r
+class Uart {\r
+private:\r
+  // Circular buffer for UART RX\r
+  static const unsigned char UART_RX_BUFFER_SIZE = 48;\r
+  volatile unsigned char m_UartRxBuf[UART_RX_BUFFER_SIZE];\r
+\r
+  volatile unsigned char m_UartRxHead;\r
+  volatile unsigned char m_UartRxTail;\r
+\r
+public:\r
+  static const unsigned char UART_PARITY_NONE = 0;\r
+  static const unsigned char UART_PARITY_EVEN = 1;\r
+  static const unsigned char UART_PARITY_ODD = 2;\r
+  \r
+  INLINE_FUNC_DECLARE(void init(void)) {\r
+    // Default initialization is 8-bit, parity none\r
+    UCSRB = 0;\r
+    UCSRA = 0;\r
+    UCSRC = (1<<UCSZ1) | (1<<UCSZ0); // 8 bit data\r
+\r
+    // Init circular buffer pointers\r
+    m_UartRxHead = 0;\r
+    m_UartRxTail = 0;\r
+\r
+#if USE_CTS\r
+  CTS_PORT |= (1<<CTS_PIN);  // bring signal high\r
+  CTS_DIR |= (1<<CTS_PIN);   // CTS is active low\r
+#endif\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void setBaudDivisor(unsigned int baud_divisor)) {\r
+    UBRRL = baud_divisor & 0xFF;\r
+    UBRRH = baud_divisor >> 8;\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void rxEnable(void)) {\r
+    UCSRB |= (1<<RXEN);\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void rxInterruptEnable(void)) {\r
+    UCSRB |= (1<<RXCIE);\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void txEnable(void)) {\r
+    UCSRB |= (1<<TXEN);\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void txInterruptEnable(void)) {\r
+    UCSRB |= (1<<TXCIE);\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(void setParity(unsigned char mode)) {\r
+    unsigned char reg = UCSRC & ~((1<<UPM0)|(1<<UPM1));\r
+    if (mode == UART_PARITY_EVEN)\r
+      reg |= (1<<UPM1);\r
+    else if (mode == UART_PARITY_ODD)\r
+      reg |= (1<<UPM0)|(1<<UPM1);\r
+    UCSRC = reg;\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(unsigned char storeChar(unsigned char rx)) {\r
+    // Calculate next buffer position.\r
+    unsigned char tmphead = m_UartRxHead;\r
+    if (tmphead == UART_RX_BUFFER_SIZE-1)\r
+      tmphead = 0;\r
+    else\r
+      tmphead++;\r
+    \r
+    // store in buffer if there is room\r
+    if (tmphead != m_UartRxTail) {\r
+      m_UartRxHead = tmphead;         // Store new index.\r
+      m_UartRxBuf[tmphead] = rx;\r
+    } else {\r
+      // no room to store character -- data loss\r
+#if USE_CTS\r
+      CTS_PORT &= ~(1<<CTS_PIN);\r
+#endif\r
+      return 0;\r
+    }\r
+    \r
+#if USE_CTS\r
+    // check if buffer is now full, if so switch CTS to inactive\r
+    if (tmphead == UART_RX_BUFFER_SIZE-1)\r
+      tmphead = 0;\r
+    else\r
+      tmphead++;\r
+    // CTS active if still room in buffer\r
+    if (tmphead != m_UartRxTail) {\r
+      CTS_PORT |= (1<<CTS_PIN);\r
+    } else {\r
+      // no room left in buffer, so make CTS inactive\r
+      CTS_PORT &= ~(1<<CTS_PIN);\r
+    }\r
+#endif \r
+    return 1;\r
+  }\r
+\r
+  INLINE_FUNC_DECLARE(unsigned char charAvail(void)) {\r
+    unsigned char tail = m_UartRxTail; // explicitly set order of volatile access\r
+    return (tail != m_UartRxHead) ? 1 : 0;\r
+  }\r
+\r
+  unsigned char waitRxChar (void);\r
+};\r
+  \r
+unsigned char Uart::waitRxChar (void) {\r
+  // waits for next RX character, then return it\r
+  unsigned char tail;\r
+  do {\r
+    tail = m_UartRxTail; // explicitly set order of volatile variable access\r
+    Watchdog::reset();\r
+  } while (m_UartRxHead == tail); // while buffer is empty\r
+\r
+#if USE_CTS\r
+  // turn off interrupts so that if UART char ready to be stored, then storage\r
+  // will occur after CTS pin is set active. This allows UART ISR to set\r
+  //  CTS inactive if byte fills buffer after we remove current byte\r
+  cli();\r
+#endif\r
+\r
+  // increment tail position \r
+  if (tail == UART_RX_BUFFER_SIZE-1)\r
+    m_UartRxTail = 0;\r
+  else\r
+    m_UartRxTail++;\r
+\r
+#if USE_CTS\r
+  CTS_PORT |= (1<<CTS_PIN); // Ensure CTS is active since just removed a byte\r
+  sei();   // Allow UART ISR to read character and change potentially change CTS\r
+#endif\r
+\r
+  return m_UartRxBuf[m_UartRxTail];\r
+}\r
+\r
+// Round to nearest integer\r
+#define UART_UBRR(baud) ((F_CPU+(8*(unsigned long) (baud)))/ (16*((unsigned long) (baud))) - 1)\r
+const prog_uint8_t BaudLookupTable[] =\r
+  {UART_UBRR(115200), UART_UBRR(38400), UART_UBRR(19200), UART_UBRR(9600)};\r
+\r
+\r
+INLINE_FUNC_DECLARE(static unsigned char GetBaudDivisor());\r
+static inline unsigned char GetBaudDivisor() {\r
+  // Set LCD_control BAUD_J2:BAUD_J1 to inputs \r
+  BAUD_DIR &= ~((1<<BAUD_J2) | (1<<BAUD_J1));\r
+  // Set BAUD_J2:BAUD_J1 PULL-UPS active\r
+  BAUD_PORT |= (1<<BAUD_J2) | (1<<BAUD_J1);\r
+\r
+  // Get BAUD rate jumper settings        \r
+  unsigned char BaudSelectJumpersValue  = BAUD_PIN_REG;\r
+  // Mask off unwanted bits\r
+  BaudSelectJumpersValue &= (1<<BAUD_J2) | (1<<BAUD_J1);\r
+  // BAUD_J2 = PD.3, BAUD_J1 = PD.2\r
+  // This is two bits too far to the left and the array index will\r
+  // increment by 4, instead of 1.\r
+  // Shift BAUD_J2 & BAUD_J1 right by two bit positions for proper array indexing\r
+  BaudSelectJumpersValue = (BaudSelectJumpersValue >> BAUD_J1);\r
+  \r
+  return PGM_READ_BYTE (&BaudLookupTable[BaudSelectJumpersValue]);\r
+}\r
+\r
+\r
+Lcd gLcd;\r
+LedPwm gLed;\r
+Uart gUart;\r
+\r
+// This class has only static methods\r
+class SerialCommandProcessor {\r
+private:\r
+  // ASCII control code to set brightness level\r
+  // Next byte is brightness ranging from 0 (no backlight) to 255 (maximum)\r
+  static const unsigned char m_LED_SET_BRIGHTNESS = 0xFB;\r
+  // ASCII control code turns on LED\r
+  static const unsigned char m_LED_SW_ON = 0xFC;\r
+  // ASCII control code turns off LED\r
+  static const unsigned char m_LED_SW_OFF = 0xFD;\r
+  // Character generator RAM command\r
+  static const unsigned char m_REG_MODE = 0xFE;\r
+\r
+public:\r
+  INLINE_FUNC_DECLARE(static void processChar(unsigned char ch)) {\r
+    // avoid use of switch statement as ImageCraft and GCC produce signifcantly\r
+    // more code for a switch statement than a sequence of if/else if\r
+    if (ch == m_LED_SW_OFF) {\r
+      gLed.switchOff();\r
+    } else if (ch == m_LED_SW_ON) {\r
+      gLed.switchOn();\r
+    } else if (ch == m_LED_SET_BRIGHTNESS) {\r
+      // read next byte which will be brightness\r
+      gLed.setBrightness(gUart.waitRxChar());\r
+    } else if (ch == m_REG_MODE) {\r
+      gLcd.putCmd (gUart.waitRxChar()); // Send LCD command character\r
+    } else {\r
+      gLcd.putChar (ch); // Send LCD data character\r
+    }\r
+  }\r
+};\r
+\r
+\r
+MAIN_FUNC() {\r
+  MCUSR = 0; // clear all reset flags\r
+  Watchdog::init();\r
+\r
+  SleepMode::initIdleMode();\r
+\r
+  gUart.init();   // Initialize the AVR USART  \r
+  gUart.setBaudDivisor(GetBaudDivisor());\r
+  gUart.rxEnable();\r
+  gUart.rxInterruptEnable();\r
+  gLed.init(&LED_PORT, &LED_DIR, LED_PIN);\r
+  gLcd.init(&LCD_CONTROL_PORT, &LCD_CONTROL_DIR, &LCD_DATA_PORT,\r
+            &LCD_DATA_DIR, &LCD_DATA_PIN_REG, LCD_RS, LCD_RW, LCD_E);\r
+\r
+  sei();\r
+  while (1) {\r
+    if (gUart.charAvail()) {\r
+      SerialCommandProcessor::processChar (gUart.waitRxChar());\r
+    } else {       // No characters waiting in RX buffer\r
+      Watchdog::off();\r
+      SleepMode::enterSleep();\r
+      Watchdog::on();\r
+    }\r
+  }\r
+  MAIN_FUNC_LAST();\r
+}\r
+\r
+\r
+ISR(USART_RX_vect) {\r
+  gUart.storeChar(UDR);\r
+}\r
+\r
+ISR(TIMER0_COMPA_vect) {\r
+  sei(); // Okay to allow USART interrupts while controlling LED PWM\r
+  gLed.cyclePwm();\r
+}\r
diff --git a/tester/Makefile b/tester/Makefile
new file mode 100644 (file)
index 0000000..d47ec19
--- /dev/null
@@ -0,0 +1,13 @@
+tester := serial_lcd_tester
+CC := gcc
+
+all: $(tester).exe
+
+$(tester).exe: $(tester).c
+       PATH=$(PATH}:/c/cygwin/bin $(CC) -O2 $(tester).c -o $(tester).exe
+
+clean:
+       @rm -f $(tester).exe $(tester).o *~
+
+distclean: clean
+
diff --git a/tester/serial_lcd_tester.c b/tester/serial_lcd_tester.c
new file mode 100644 (file)
index 0000000..3af60b4
--- /dev/null
@@ -0,0 +1,487 @@
+/******************************************************************************\r
+ ** FILE IDENTIFICATION\r
+ **   Name:               serial_lcd_tester.c\r
+ **   Purpose:            Tests Serial_Lcd\r
+ **   Author:             Kevin M. Rosenberg\r
+ **   Last Modification:  March 2007\r
+ **\r
+ ** PLATFORM\r
+ **   Linux and Windows/Cygwin\r
+ **\r
+ ** Custom character bitmaps by Carl W. Livingston\r
+ ******************************************************************************/\r
+\r
+// Will likely need to change for your system and LCD display\r
+\r
+#define DEFAULT_PORT "/dev/com7"\r
+static unsigned char lcdCols = 20;\r
+static unsigned char lcdRows = 4;\r
+\r
+#include <stdio.h>   /* Standard input/output definitions */\r
+#include <string.h>  /* String function definitions */\r
+#include <unistd.h>  /* UNIX standard function definitions */\r
+#include <fcntl.h>   /* File control definitions */\r
+#include <errno.h>   /* Error number definitions */\r
+#include <termios.h> /* POSIX terminal control definitions */\r
+#include <sys/select.h>\r
+#include <time.h>\r
+#include <sys/time.h>\r
+#include <stdlib.h>\r
+\r
+void MakeCustomChar (const char *Symbol, char Address);\r
+void delay_ms(unsigned int t);\r
+void clear_display(void);\r
+void display_banner(void);\r
+\r
+int open_serial_port (char const* const);\r
+void close_serial_port (void);\r
+void serial_puts (const char* str);\r
+void serial_putc (const unsigned char c);\r
+void run_test(void);\r
+\r
+static inline double get_time(void) {\r
+  struct timeval tv;\r
+  gettimeofday (&tv, NULL);\r
+  return tv.tv_sec + tv.tv_usec/1e6;\r
+}\r
+\r
+// Integer delay_ms routine\r
+// 65.535 seconds maximum\r
+void delay_ms(unsigned int t)\r
+{\r
+  double start = get_time();\r
+  double end = start + t/1000;\r
+  while (get_time() < end) {}\r
+}\r
+\r
+\r
+void usage(char const* const prog) {\r
+  fprintf(stderr, "usage: %s <portname>\n", basename(prog));\r
+  fprintf(stderr, "Port name is in Cygwin format.\n");\r
+  fprintf(stderr, "Example: COM1 would be /dev/com1\n");\r
+}\r
+\r
+\r
+int main(int argc, char ** argv) {\r
+  char portName[30];\r
+  portName[sizeof(portName)] = 0;  // ensure string is zero-terminated by below strncpy\r
+  if (argc == 1) {\r
+    strncpy (portName, DEFAULT_PORT, sizeof(portName)-1);\r
+    fprintf (stderr, "Using default serial port of %s\n", portName);\r
+  } else if (argc == 2) {\r
+    strncpy (portName, argv[1], sizeof(portName));\r
+  } else {\r
+    usage(argv[0]);\r
+    exit(1);\r
+  }\r
+  if (! open_serial_port (portName)) {\r
+    fprintf(stderr, "Unable to open serial port %s\n", portName);\r
+    return 1;\r
+  }\r
+  run_test();\r
+  close_serial_port();\r
+  return 0;\r
+}\r
+\r
+// Serial_Lcd command delimiter\r
+#define SERIAL_LCD_CMD_MODE 0xFE\r
+\r
+// Display clear text command\r
+#define LCD_CLR_CMD  0x01\r
+// Display home cursor command\r
+#define LCD_HOME_CMD 0x02\r
+\r
+// Display entry mode command & parameters\r
+#define LCD_ENTRY_CMD 0x04\r
+#define CURSOR_DIR    0x02\r
+#define CURSOR_MOVE   0x01\r
+\r
+// Display control mode & parameters\r
+#define LCD_CONTROL_CMD 0x08\r
+#define LCD_ON          0x04\r
+#define CURSOR_ON       0x02\r
+#define CURSOR_BLINK    0x01\r
+\r
+// Display cursor control & parameters\r
+#define LCD_CURSOR_CMD  0x10\r
+#define LCD_SHIFT       0x08\r
+#define DISPLAY_L_R     0x04\r
+\r
+// Display line position addressing\r
+#define LINE1_ADDR      0x80\r
+#define LINE2_ADDR      0xC0\r
+#define LINE3_ADDR      0x94\r
+#define LINE4_ADDR      0xD4\r
+\r
+// Display data & character generator selection bits\r
+#define DD_RAM          0x80\r
+#define CG_RAM          0x40\r
+\r
+// Custom Character DDRAM location addressing\r
+#define DDRAM_START_ADD_0 0x00\r
+#define DDRAM_START_ADD_1 0x01\r
+#define DDRAM_START_ADD_2 0x02\r
+#define DDRAM_START_ADD_3 0x03\r
+#define DDRAM_START_ADD_4 0x04\r
+#define DDRAM_START_ADD_5 0x05\r
+#define DDRAM_START_ADD_6 0x06\r
+#define DDRAM_START_ADD_7 0x07\r
+\r
+// Custom Character CGRAM Starting addresses\r
+#define CGRAM_START_ADD_0 0x40\r
+#define CGRAM_START_ADD_1 0x48\r
+#define CGRAM_START_ADD_2 0x50\r
+#define CGRAM_START_ADD_3 0x58\r
+#define CGRAM_START_ADD_4 0x60\r
+#define CGRAM_START_ADD_5 0x68\r
+#define CGRAM_START_ADD_6 0x70\r
+#define CGRAM_START_ADD_7 0x78\r
+\r
+// ASCII control code (0xFB) to set LED brightness.\r
+// Next byte sets brightness (from 0 to 255)\r
+#define CMD_SET_BRIGHTNESS 0xFB\r
+#define NUM_BRIGHTNESS_LEVELS 8\r
+#define BRIGHTNESS_SCALE(b)  ((unsigned char) ((b * 254.) / (double) (NUM_BRIGHTNESS_LEVELS-1)) + 1)\r
+\r
+// ASCII control code (0xFC) turns on LED\r
+#define LED_ON 0xFC\r
+// ASCII control code (0xFD) turns on LED\r
+#define LED_OFF 0xFD\r
+\r
+// Smiley face\r
+const char Smiley_face[] = {// Smiley face\r
+  0x0E,  // 0b00001110,\r
+  0x1F,  // 0b00011111,\r
+  0x00,  // 0b00000000,\r
+  0x0A,  // 0b00001010,\r
+  0x04,  // 0b00000100,\r
+  0x11,  // 0b00010001,\r
+  0x0E,  // 0b00001110,\r
+  0x00,  // 0b00000000\r
+};\r
+const char Thin_cross[] = {// Thin cross\r
+  0x11,  // 0b00010001,\r
+  0x00,  // 0b00000000,\r
+  0x1F,  // 0b00011111,\r
+  0x15,  // 0b00010101,\r
+  0x1B,  // 0b00011011,\r
+  0x0E,  // 0b00001110,\r
+  0x11,  // 0b00010001,\r
+  0x00,  // 0b00000000\r
+};\r
+const char Thick_cross[] = {// Thick cross\r
+  0x00,  // 0b00000000,\r
+  0x0E,  // 0b00001110,\r
+  0x1B,  // 0b00011011,\r
+  0x11,  // 0b00010001,\r
+  0x1B,  // 0b00011011,\r
+  0x0E,  // 0b00001110,\r
+  0x00,  // 0b00000000,\r
+  0x00,  // 0b00000000\r
+};\r
+const char Music_note[] = {// Music note\r
+  0x03,  // 0b00000011,\r
+  0x02,  // 0b00000010,\r
+  0x07,  // 0b00000111,\r
+  0x02,  // 0b00000010,\r
+  0x1E,  // 0b00011110,\r
+  0x12,  // 0b00010010,\r
+  0x1E,  // 0b00011110,\r
+  0x00,  // 0b00000000\r
+};\r
+const char Loop_Antenna[] = {// Loop Antenna\r
+  0x11,  // 0b00010001,\r
+  0x11,  // 0b00010001,\r
+  0x1F,  // 0b00011111,\r
+  0x15,  // 0b00010101,\r
+  0x15,  // 0b00010101,\r
+  0x04,  // 0b00000100,\r
+  0x0E,  // 0b00001110,\r
+  0x00,  // 0b00000000\r
+};\r
+const char Lh_Yagi_Antenna[] = {// Lh Yagi Antenna\r
+  0x10,  // 0b00010000,\r
+  0x14,  // 0b00010100,\r
+  0x15,  // 0b00010101,\r
+  0x1F,  // 0b00011111,\r
+  0x15,  // 0b00010101,\r
+  0x14,  // 0b00010100,\r
+  0x10,  // 0b00010000,\r
+  0x00,  // 0b00000000\r
+};\r
+const char Diamond[] = {// Diamond\r
+  0x00,  // 0b00000000,\r
+  0x1F,  // 0b00011111,\r
+  0x11,  // 0b00010001,\r
+  0x15,  // 0b00010101,\r
+  0x11,  // 0b00010001,\r
+  0x1F,  // 0b00011111,\r
+  0x00,  // 0b00000000,\r
+  0x00,  // 0b00000000\r
+};\r
+const char Rh_Yagi_Antenna[] = {// Rh Yagi Antenna\r
+  0x01,  // 0b00000001,\r
+  0x05,  // 0b00000101,\r
+  0x15,  // 0b00010101,\r
+  0x1F,  // 0b00011111,\r
+  0x15,  // 0b00010101,\r
+  0x05,  // 0b00000101,\r
+  0x01,  // 0b00000001,\r
+  0x00,  // 0b00000000\r
+};\r
+\r
+const char BannerMessage1[] = "Serial Lcd";\r
+const char BannerMessage2[] = "Tester By";\r
+const char BannerMessage3[] = "Kevin M. Rosenberg";\r
+const char BannerMessage4[] = "www.avrcode.com";\r
+\r
+char led_on;\r
+unsigned char brightness = NUM_BRIGHTNESS_LEVELS - 1;\r
+\r
+void run_test (void) {\r
+  double start_time = get_time();\r
+\r
+  delay_ms(40); // Ensure time for LCD to be ready\r
+  led_on = 0;\r
+  serial_putc (LED_OFF); // turn off the LED\r
+\r
+  MakeCustomChar (Smiley_face, CGRAM_START_ADD_0);\r
+  MakeCustomChar (Lh_Yagi_Antenna, CGRAM_START_ADD_1);\r
+  MakeCustomChar (Diamond, CGRAM_START_ADD_2);\r
+  MakeCustomChar (Rh_Yagi_Antenna, CGRAM_START_ADD_3);\r
+  MakeCustomChar (Thin_cross, CGRAM_START_ADD_4);\r
+  MakeCustomChar (Thick_cross, CGRAM_START_ADD_5);\r
+  MakeCustomChar (Music_note, CGRAM_START_ADD_6);\r
+  MakeCustomChar (Loop_Antenna, CGRAM_START_ADD_7);\r
+\r
+  // Put the banner message on the display\r
+  clear_display(); // Clear the display for the banner message\r
+  display_banner(); // Display the banner message\r
+  delay_ms(1000); // Display banner message for 1 seconds\r
+\r
+  struct termios inopt;\r
+  funlockfile(stdin);\r
+#ifdef __CYGWIN__\r
+  tcgetattr(stdin->_file, &inopt);\r
+#else\r
+  tcgetattr(stdin->_fileno, &inopt);\r
+#endif\r
+  inopt.c_lflag &= ~ICANON;  // non-canonical mode: no waiting on read\r
+  inopt.c_cc[VMIN] = 0; // minimum read characters\r
+  inopt.c_cc[VTIME] = 0; // timeout in deciseconds\r
+#ifdef __CYGWIN__\r
+  if (tcsetattr (stdin->_file, TCSANOW, &inopt) < 0) {\r
+#else\r
+  if (tcsetattr (stdin->_fileno, TCSANOW, &inopt) < 0) {\r
+#endif\r
+    fprintf(stderr, "Error setting stdin parameters (%d: %s)\n",\r
+            errno, strerror(errno));\r
+    exit(1);\r
+  }\r
+\r
+  clear_display(); // Clear the display for updating data\r
+\r
+  while(1) {\r
+    char cntStr[20];\r
+    serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode\r
+    serial_putc (LINE2_ADDR);  // Set the LCD cursor position\r
+    double elapsed = get_time() - start_time;\r
+    snprintf(cntStr, sizeof(cntStr), "%.3lf", elapsed);\r
+    serial_puts (cntStr);\r
+\r
+    // Write the custom characters to the display\r
+    serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode\r
+    serial_putc (LINE1_ADDR);  // Set the LCD cursor position\r
+    serial_putc (DDRAM_START_ADD_0); // Display custom character 0\r
+    serial_putc (DDRAM_START_ADD_1); // Display custom character 1\r
+    serial_putc (DDRAM_START_ADD_2); // Display custom character 2\r
+    serial_putc (DDRAM_START_ADD_3); // Display custom character 3\r
+    serial_putc (DDRAM_START_ADD_4); // Display custom character 4\r
+    serial_putc (DDRAM_START_ADD_5); // Display custom character 5\r
+    serial_putc (DDRAM_START_ADD_6); // Display custom character 6\r
+    serial_putc (DDRAM_START_ADD_7); // Display custom character 7\r
+\r
+\r
+    char ch = getc_unlocked(stdin);\r
+    if (ch == 'l') {\r
+      if (led_on) {\r
+        serial_putc (LED_OFF); // Else, turn off the LED\r
+        led_on = 0;\r
+      } else {\r
+        serial_putc (LED_ON); // Turn on the LED\r
+        led_on = 1;\r
+      }\r
+    } else if (ch == 'b') {\r
+      if (brightness >= NUM_BRIGHTNESS_LEVELS - 1)\r
+        brightness = 0;\r
+      else\r
+        brightness++;\r
+      serial_putc (CMD_SET_BRIGHTNESS);\r
+      printf("%u(%u)", brightness, (unsigned int) BRIGHTNESS_SCALE(brightness));\r
+      serial_putc (BRIGHTNESS_SCALE(brightness));\r
+    }\r
+  }\r
+}\r
+\r
+void MakeCustomChar (const char *Symbol, char Address) {\r
+  // Set up the custom characters\r
+  serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode\r
+  serial_putc (Address);  // Set the display to CGRAM mode, address 0\r
+  // Output the 8 bytes of the custom character\r
+  for (unsigned char i = 0; i < 8; i++) {\r
+    serial_putc (Symbol[n]);\r
+  }\r
+}\r
+\r
+// Clear the display\r
+void clear_display(void)\r
+{\r
+  serial_putc (SERIAL_LCD_CMD_MODE);    // Put the LCD in command mode\r
+  serial_putc (LCD_CLR_CMD); // Send the clear the LCD display\r
+  delay_ms (30);             // Wait for LCD controller to startup\r
+}\r
+\r
+void tx_string_center (const char* str, unsigned char line_num) {\r
+  unsigned char pos;\r
+  switch (line_num) {\r
+  case 3:\r
+    pos = LINE4_ADDR;\r
+    break;\r
+  case 2:\r
+    pos = LINE3_ADDR;\r
+    break;\r
+  case 1:\r
+    pos = LINE2_ADDR;\r
+    break;\r
+  case 0:\r
+  default:\r
+    pos = LINE1_ADDR;\r
+    break;\r
+  }\r
+\r
+  serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode\r
+  char offset = (lcdCols - strlen(str)) / 2; // offset to center line\r
+  if (offset < 0)\r
+    offset = 0;\r
+  serial_putc (pos + offset); // Set LCD cursor position\r
+  serial_puts (str); // Display string\r
+}\r
+\r
+// Print the banner message\r
+void display_banner(void) {\r
+  tx_string_center (BannerMessage1, 0);\r
+  tx_string_center (BannerMessage2, 1);\r
+  tx_string_center (BannerMessage3, 2);\r
+  tx_string_center (BannerMessage4, 3);\r
+}\r
+\r
+\r
+// Serial port section\r
+\r
+static int serialFd = -1; // serial port file descriptor\r
+\r
+int open_serial_port(char const* const port ) {\r
+  struct termios options;\r
+  int count,ret;\r
+\r
+  serialFd = open (port, O_RDWR | O_NOCTTY | O_NONBLOCK);\r
+  if (serialFd == -1)\r
+    return 0;\r
+\r
+  fcntl(serialFd, F_SETFL, 0);\r
+\r
+  if (tcgetattr(serialFd, &options) < 0) {\r
+    fprintf(stderr, "Error reading serial port parameters (%d: %s)\n",\r
+            errno, strerror(errno));\r
+    exit(1);\r
+  }\r
+\r
+  cfsetispeed (&options, B115200); // 115200 baud\r
+  cfsetospeed (&options, B115200); // 115200 baud\r
+\r
+  options.c_cflag |= (CLOCAL | CREAD); /* enable */\r
+  options.c_cflag &= ~PARENB; // turn off parity\r
+  options.c_cflag &= ~CSTOPB; // one stop bit\r
+  options.c_cflag &= ~CSIZE;\r
+  options.c_cflag |= CS8; // 8-bit input\r
+  options.c_cflag &= ~CRTSCTS; // no flow control\r
+\r
+  options.c_lflag &= ~ICANON;  // non-canonical mode: no waiting on read\r
+  options.c_lflag &= ~ECHO;  // Do not echo bytes written\r
+  options.c_lflag &= ~ECHOE;\r
+  options.c_lflag &= ~ECHONL;  // Do not echo newline\r
+  options.c_lflag &= ~IEXTEN;  // Disable implementation input processing\r
+  options.c_lflag &= ~ISIG;  // Disable signal processing\r
+\r
+  options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INPCK | IXOFF\r
+                       | INLCR | IGNCR | ICRNL | IXON | IXANY);\r
+\r
+  options.c_oflag &= ~OPOST;   // Disable implementation output processing\r
+\r
+  options.c_cc[VMIN] = 0; // minimum read characters\r
+  options.c_cc[VTIME] = 0; // timeout in deciseconds\r
+\r
+  /* set all of the options */\r
+  tcflush(serialFd, TCIFLUSH);\r
+  if (tcsetattr (serialFd, TCSANOW, &options) < 0) {\r
+    fprintf(stderr, "Error setting serial port parameters (%d: %s)\n",\r
+            errno, strerror(errno));\r
+    exit(1);\r
+  }\r
+\r
+  // Verify settings\r
+  if (tcgetattr(serialFd, &options) < 0) {\r
+    fprintf(stderr, "Error to re-read serial port parameters (%d: %s)\n",\r
+            errno, strerror(errno));\r
+    exit(1);\r
+  }\r
+  if (options.c_lflag & ICANON) {\r
+    fprintf(stderr, "Error: still in canonical serial mode\n");\r
+    exit(1);\r
+  }\r
+  if (options.c_cc[VTIME] != 0) {\r
+    fprintf(stderr, "Error: VTIME does not equal 0, but is %d\n", options.c_cc[VTIME]);\r
+    exit(1);\r
+  }\r
+  if (options.c_cc[VMIN] != 0) {\r
+    fprintf(stderr, "Error: VMIN does not equal 0, but is %d\n", options.c_cc[VMIN]);\r
+    exit(1);\r
+  }\r
+\r
+\r
+  return 1;\r
+}\r
+\r
+void close_serial_port(void) {\r
+  if (serialFd >= 0) {\r
+    close(serialFd);\r
+    serialFd = -1;\r
+  }\r
+}\r
+\r
+void serial_puts (const char* str) {\r
+  int len = strlen(str);\r
+  int written = write (serialFd, str, len);\r
+  if (written < 0) {\r
+      fprintf (stderr, "Unable to write '%s' to fd %d, errno = %d (%s)\n",\r
+               str, serialFd, errno, strerror(errno));\r
+      close (serialFd);\r
+      exit (1);\r
+  } else if (written != len) {\r
+    fprintf (stderr, "Unable to fully write '%s', %d bytes written\n",\r
+             str, written);\r
+    close (serialFd);\r
+    exit(1);\r
+  }\r
+}\r
+\r
+\r
+void serial_putc (const unsigned char c) {\r
+  int written = write (serialFd, &c, 1);\r
+  if (written < 0) {\r
+      fprintf (stderr, "Unable to write '%c' to fd %d, errno = %d (%s)\n",\r
+               c, serialFd, errno, strerror(errno));\r
+      close (serialFd);\r
+      exit (1);\r
+  }\r
+}\r