summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2012-10-29 23:06:01 +0200
committerYuval Adam <yuv.adm@gmail.com>2012-10-29 23:06:01 +0200
commit4ba8614c006f9828f0796c140bc3e13c9e67938c (patch)
treead204651c733250d27d20fce8820f9747c43c883 /utils
parente018ceebed74b8223482bc9d1ed0b31c938381da (diff)
Added utils
Diffstat (limited to 'utils')
-rw-r--r--utils/cmdline.c183
-rw-r--r--utils/cmdline.h135
-rw-r--r--utils/cpu_usage.c203
-rw-r--r--utils/cpu_usage.h57
-rw-r--r--utils/crc.c756
-rw-r--r--utils/crc.h65
-rw-r--r--utils/flash_pb.c486
-rw-r--r--utils/flash_pb.h58
-rw-r--r--utils/isqrt.c117
-rw-r--r--utils/isqrt.h55
-rw-r--r--utils/ringbuf.c709
-rw-r--r--utils/ringbuf.h105
-rw-r--r--utils/scheduler.c304
-rw-r--r--utils/scheduler.h140
-rw-r--r--utils/sine.c125
-rw-r--r--utils/sine.h85
-rw-r--r--utils/softi2c.c1316
-rw-r--r--utils/softi2c.h195
-rw-r--r--utils/softssi.c1288
-rw-r--r--utils/softssi.h280
-rw-r--r--utils/softuart.c2584
-rw-r--r--utils/softuart.h374
-rw-r--r--utils/uartstdio.c1732
-rw-r--r--utils/uartstdio.h85
-rw-r--r--utils/ustdlib.c1610
-rw-r--r--utils/ustdlib.h130
-rw-r--r--utils/utils.sgxxbin0 -> 744 bytes
27 files changed, 13177 insertions, 0 deletions
diff --git a/utils/cmdline.c b/utils/cmdline.c
new file mode 100644
index 0000000..67744c2
--- /dev/null
+++ b/utils/cmdline.c
@@ -0,0 +1,183 @@
+//*****************************************************************************
+//
+// cmdline.c - Functions to help with processing command lines.
+//
+// Copyright (c) 2007-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup cmdline_api
+//! @{
+//
+//*****************************************************************************
+
+#include <string.h>
+#include "utils/cmdline.h"
+
+//*****************************************************************************
+//
+// Defines the maximum number of arguments that can be parsed.
+//
+//*****************************************************************************
+#ifndef CMDLINE_MAX_ARGS
+#define CMDLINE_MAX_ARGS 8
+#endif
+
+//*****************************************************************************
+//
+//! Process a command line string into arguments and execute the command.
+//!
+//! \param pcCmdLine points to a string that contains a command line that was
+//! obtained by an application by some means.
+//!
+//! This function will take the supplied command line string and break it up
+//! into individual arguments. The first argument is treated as a command and
+//! is searched for in the command table. If the command is found, then the
+//! command function is called and all of the command line arguments are passed
+//! in the normal argc, argv form.
+//!
+//! The command table is contained in an array named <tt>g_sCmdTable</tt> which
+//! must be provided by the application.
+//!
+//! \return Returns \b CMDLINE_BAD_CMD if the command is not found,
+//! \b CMDLINE_TOO_MANY_ARGS if there are more arguments than can be parsed.
+//! Otherwise it returns the code that was returned by the command function.
+//
+//*****************************************************************************
+int
+CmdLineProcess(char *pcCmdLine)
+{
+ static char *argv[CMDLINE_MAX_ARGS + 1];
+ char *pcChar;
+ int argc;
+ int bFindArg = 1;
+ tCmdLineEntry *pCmdEntry;
+
+ //
+ // Initialize the argument counter, and point to the beginning of the
+ // command line string.
+ //
+ argc = 0;
+ pcChar = pcCmdLine;
+
+ //
+ // Advance through the command line until a zero character is found.
+ //
+ while(*pcChar)
+ {
+ //
+ // If there is a space, then replace it with a zero, and set the flag
+ // to search for the next argument.
+ //
+ if(*pcChar == ' ')
+ {
+ *pcChar = 0;
+ bFindArg = 1;
+ }
+
+ //
+ // Otherwise it is not a space, so it must be a character that is part
+ // of an argument.
+ //
+ else
+ {
+ //
+ // If bFindArg is set, then that means we are looking for the start
+ // of the next argument.
+ //
+ if(bFindArg)
+ {
+ //
+ // As long as the maximum number of arguments has not been
+ // reached, then save the pointer to the start of this new arg
+ // in the argv array, and increment the count of args, argc.
+ //
+ if(argc < CMDLINE_MAX_ARGS)
+ {
+ argv[argc] = pcChar;
+ argc++;
+ bFindArg = 0;
+ }
+
+ //
+ // The maximum number of arguments has been reached so return
+ // the error.
+ //
+ else
+ {
+ return(CMDLINE_TOO_MANY_ARGS);
+ }
+ }
+ }
+
+ //
+ // Advance to the next character in the command line.
+ //
+ pcChar++;
+ }
+
+ //
+ // If one or more arguments was found, then process the command.
+ //
+ if(argc)
+ {
+ //
+ // Start at the beginning of the command table, to look for a matching
+ // command.
+ //
+ pCmdEntry = &g_sCmdTable[0];
+
+ //
+ // Search through the command table until a null command string is
+ // found, which marks the end of the table.
+ //
+ while(pCmdEntry->pcCmd)
+ {
+ //
+ // If this command entry command string matches argv[0], then call
+ // the function for this command, passing the command line
+ // arguments.
+ //
+ if(!strcmp(argv[0], pCmdEntry->pcCmd))
+ {
+ return(pCmdEntry->pfnCmd(argc, argv));
+ }
+
+ //
+ // Not found, so advance to the next entry.
+ //
+ pCmdEntry++;
+ }
+ }
+
+ //
+ // Fall through to here means that no matching command was found, so return
+ // an error.
+ //
+ return(CMDLINE_BAD_CMD);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/cmdline.h b/utils/cmdline.h
new file mode 100644
index 0000000..581601a
--- /dev/null
+++ b/utils/cmdline.h
@@ -0,0 +1,135 @@
+//*****************************************************************************
+//
+// cmdline.h - Prototypes for command line processing functions.
+//
+// Copyright (c) 2007-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __CMDLINE_H__
+#define __CMDLINE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup cmdline_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if the command is not found.
+//
+//*****************************************************************************
+#define CMDLINE_BAD_CMD (-1)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if there are too many arguments.
+//
+//*****************************************************************************
+#define CMDLINE_TOO_MANY_ARGS (-2)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if there are too few arguments.
+//
+//*****************************************************************************
+#define CMDLINE_TOO_FEW_ARGS (-3)
+
+//*****************************************************************************
+//
+//! Defines the value that is returned if an argument is invalid.
+//
+//*****************************************************************************
+#define CMDLINE_INVALID_ARG (-4)
+
+//*****************************************************************************
+//
+// Command line function callback type.
+//
+//*****************************************************************************
+typedef int (*pfnCmdLine)(int argc, char *argv[]);
+
+//*****************************************************************************
+//
+//! Structure for an entry in the command list table.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! A pointer to a string containing the name of the command.
+ //
+ const char *pcCmd;
+
+ //
+ //! A function pointer to the implementation of the command.
+ //
+ pfnCmdLine pfnCmd;
+
+ //
+ //! A pointer to a string of brief help text for the command.
+ //
+ const char *pcHelp;
+}
+tCmdLineEntry;
+
+//*****************************************************************************
+//
+//! This is the command table that must be provided by the application.
+//
+//*****************************************************************************
+extern tCmdLineEntry g_sCmdTable[];
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern int CmdLineProcess(char *pcCmdLine);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CMDLINE_H__
diff --git a/utils/cpu_usage.c b/utils/cpu_usage.c
new file mode 100644
index 0000000..160e61c
--- /dev/null
+++ b/utils/cpu_usage.c
@@ -0,0 +1,203 @@
+//*****************************************************************************
+//
+// cpu_usage.c - Routines to determine the CPU utilization.
+//
+// Copyright (c) 2007-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/timer.h"
+#include "utils/cpu_usage.h"
+
+//*****************************************************************************
+//
+//! \addtogroup cpu_usage_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The peripheral identifier for the timer modules that could be used for
+// tracking CPU utilization.
+//
+//*****************************************************************************
+static unsigned long g_pulCPUUsageTimerPeriph[4] =
+{
+ SYSCTL_PERIPH_TIMER0, SYSCTL_PERIPH_TIMER1, SYSCTL_PERIPH_TIMER2,
+ SYSCTL_PERIPH_TIMER3
+};
+
+//*****************************************************************************
+//
+// The base address of the timer modules that could be used for tracking CPU
+// utilization.
+//
+//*****************************************************************************
+static unsigned long g_pulCPUUsageTimerBase[4] =
+{
+ TIMER0_BASE, TIMER1_BASE, TIMER2_BASE, TIMER3_BASE
+};
+
+//*****************************************************************************
+//
+// The index of the timer module that will be used for tracking CPU
+// utilization.
+//
+//*****************************************************************************
+static unsigned long g_ulCPUUsageTimer;
+
+//*****************************************************************************
+//
+// The number of processor clock ticks per timing period.
+//
+//*****************************************************************************
+static unsigned long g_ulCPUUsageTicks;
+
+//*****************************************************************************
+//
+// The value of timer two on the previous timing period. This is used to
+// determine the number of clock ticks counted by the timer during the timing
+// period.
+//
+//*****************************************************************************
+static unsigned long g_ulCPUUsagePrevious;
+
+//*****************************************************************************
+//
+//! Updates the CPU usage for the new timing period.
+//!
+//! This function, when called at the end of a timing period, will update the
+//! CPU usage.
+//!
+//! \return Returns the CPU usage percentage as a 16.16 fixed-point value.
+//
+//*****************************************************************************
+unsigned long
+CPUUsageTick(void)
+{
+ unsigned long ulValue, ulUsage;
+
+ //
+ // Get the current value of the timer.
+ //
+ ulValue = MAP_TimerValueGet(g_pulCPUUsageTimerBase[g_ulCPUUsageTimer],
+ TIMER_A);
+
+ //
+ // Based on the number of clock ticks accumulated by the timer during the
+ // previous timing period, compute the CPU usage as a 16.16 fixed-point
+ // value.
+ //
+ ulUsage = ((((g_ulCPUUsagePrevious - ulValue) * 6400) /
+ g_ulCPUUsageTicks) * 1024);
+
+ //
+ // Save the previous value of the timer.
+ //
+ g_ulCPUUsagePrevious = ulValue;
+
+ //
+ // Return the new CPU usage value.
+ //
+ return(ulUsage);
+}
+
+//*****************************************************************************
+//
+//! Initializes the CPU usage measurement module.
+//!
+//! \param ulClockRate is the rate of the clock supplied to the timer module.
+//! \param ulRate is the number of times per second that CPUUsageTick() is
+//! called.
+//! \param ulTimer is the index of the timer module to use.
+//!
+//! This function prepares the CPU usage measurement module for measuring the
+//! CPU usage of the application.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+CPUUsageInit(unsigned long ulClockRate, unsigned long ulRate,
+ unsigned long ulTimer)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ulClockRate > ulRate);
+ ASSERT(ulTimer < 4);
+
+ //
+ // Save the timer index.
+ //
+ g_ulCPUUsageTimer = ulTimer;
+
+ //
+ // Determine the number of system clocks per measurement period.
+ //
+ g_ulCPUUsageTicks = ulClockRate / ulRate;
+
+ //
+ // Set the previous value of the timer to the initial timer value.
+ //
+ g_ulCPUUsagePrevious = 0xffffffff;
+
+ //
+ // Enable peripheral clock gating.
+ //
+ MAP_SysCtlPeripheralClockGating(true);
+
+ //
+ // Enable the third timer while the processor is in run mode, but disable
+ // it in sleep mode. It will therefore count system clocks when the
+ // processor is running but not when it is sleeping.
+ //
+ MAP_SysCtlPeripheralEnable(g_pulCPUUsageTimerPeriph[ulTimer]);
+ MAP_SysCtlPeripheralSleepDisable(g_pulCPUUsageTimerPeriph[ulTimer]);
+
+ //
+ // Configure the third timer for 32-bit periodic operation.
+ //
+ MAP_TimerConfigure(g_pulCPUUsageTimerBase[ulTimer], TIMER_CFG_PERIODIC);
+
+ //
+ // Set the load value for the third timer to the maximum value.
+ //
+ MAP_TimerLoadSet(g_pulCPUUsageTimerBase[ulTimer], TIMER_A, 0xffffffff);
+
+ //
+ // Enable the third timer. It will now count the number of system clocks
+ // during which the processor is executing code.
+ //
+ MAP_TimerEnable(g_pulCPUUsageTimerBase[ulTimer], TIMER_A);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/cpu_usage.h b/utils/cpu_usage.h
new file mode 100644
index 0000000..55a6eba
--- /dev/null
+++ b/utils/cpu_usage.h
@@ -0,0 +1,57 @@
+//*****************************************************************************
+//
+// cpu_usage.h - Prototypes for the CPU utilization routines.
+//
+// Copyright (c) 2007-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __CPU_USAGE_H__
+#define __CPU_USAGE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the CPU utilization routines.
+//
+//*****************************************************************************
+extern unsigned long CPUUsageTick(void);
+extern void CPUUsageInit(unsigned long ulClockRate, unsigned long ulRate,
+ unsigned long ulTimer);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CPU_USAGE_H__
diff --git a/utils/crc.c b/utils/crc.c
new file mode 100644
index 0000000..cf60e81
--- /dev/null
+++ b/utils/crc.c
@@ -0,0 +1,756 @@
+//*****************************************************************************
+//
+// crc.c - CRC functions.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup crc_api
+//! @{
+//
+//*****************************************************************************
+
+#include "crc.h"
+
+//*****************************************************************************
+//
+// The CRC table for the polynomial C(x) = x^8 + x^2 + x + 1 (CRC-8-CCITT).
+//
+//*****************************************************************************
+static const unsigned char g_pucCrc8CCITT[256] =
+{
+ 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+ 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+ 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+ 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+ 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+ 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+ 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+ 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+ 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+ 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+ 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+ 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+ 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+ 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+ 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+ 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+ 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+//*****************************************************************************
+//
+// The CRC-16 table for the polynomial C(x) = x^16 + x^15 + x^2 + 1 (standard
+// CRC-16, also known as CRC-16-IBM and CRC-16-ANSI).
+//
+//*****************************************************************************
+static const unsigned short g_pusCrc16[256] =
+{
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+//*****************************************************************************
+//
+// The CRC-32 table for the polynomial C(x) = x^32 + x^26 + x^23 + x^22 +
+// x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 (standard
+// CRC32 as used in Ethernet, MPEG-2, PNG, etc.).
+//
+//*****************************************************************************
+const unsigned long g_pulCrc32[] =
+{
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+//*****************************************************************************
+//
+// This macro executes one iteration of the CRC-8-CCITT.
+//
+//*****************************************************************************
+#define CRC8_ITER(crc, data) g_pucCrc8CCITT[(unsigned char)((crc) ^ (data))]
+
+//*****************************************************************************
+//
+// This macro executes one iteration of the CRC-16.
+//
+//*****************************************************************************
+#define CRC16_ITER(crc, data) (((crc) >> 8) ^ \
+ g_pusCrc16[(unsigned char)((crc) ^ (data))])
+
+//*****************************************************************************
+//
+// This macro executes one iteration of the CRC-32.
+//
+//*****************************************************************************
+#define CRC32_ITER(crc, data) (((crc) >> 8) ^ \
+ g_pulCrc32[(unsigned char)((crc & 0xFF) ^ \
+ (data))])
+
+//*****************************************************************************
+//
+//! Calculates the CRC-8-CCITT of an array of bytes.
+//!
+//! \param ucCrc is the starting CRC-8-CCITT value.
+//! \param pucData is a pointer to the data buffer.
+//! \param ulCount is the number of bytes in the data buffer.
+//!
+//! This function is used to calculate the CRC-8-CCITT of the input buffer.
+//! The CRC-8-CCITT is computed in a running fashion, meaning that the entire
+//! data block that is to have its CRC-8-CCITT computed does not need to be
+//! supplied all at once. If the input buffer contains the entire block of
+//! data, then \b ucCrc should be set to 0. If, however, the entire block of
+//! data is not available, then \b ucCrc should be set to 0 for the first
+//! portion of the data, and then the returned value should be passed back in
+//! as \b ucCrc for the next portion of the data.
+//!
+//! For example, to compute the CRC-8-CCITT of a block that has been split into
+//! three pieces, use the following:
+//!
+//! \verbatim
+//! ucCrc = Crc8CCITT(0, pucData1, ulLen1);
+//! ucCrc = Crc8CCITT(ucCrc, pucData2, ulLen2);
+//! ucCrc = Crc8CCITT(ucCrc, pucData3, ulLen3);
+//! \endverbatim
+//!
+//! Computing a CRC-8-CCITT in a running fashion is useful in cases where the
+//! data is arriving via a serial link (for example) and is therefore not all
+//! available at one time.
+//!
+//! \return The CRC-8-CCITT of the input data.
+//
+//*****************************************************************************
+unsigned char
+Crc8CCITT(unsigned char ucCrc, const unsigned char *pucData,
+ unsigned long ulCount)
+{
+ unsigned long ulTemp;
+
+ //
+ // If the data buffer is not short-aligned, then perform a single step of
+ // the CRC to make it short-aligned.
+ //
+ if((unsigned long)pucData & 1)
+ {
+ //
+ // Perform the CRC on this input byte.
+ //
+ ucCrc = CRC8_ITER(ucCrc, *pucData);
+
+ //
+ // Skip this input byte.
+ //
+ pucData++;
+ ulCount--;
+ }
+
+ //
+ // If the data buffer is not word-aligned and there are at least two bytes
+ // of data left, then perform two steps of the CRC to make it word-aligned.
+ //
+ if(((unsigned long)pucData & 2) && (ulCount > 1))
+ {
+ //
+ // Read the next short.
+ //
+ ulTemp = *(unsigned short *)pucData;
+
+ //
+ // Perform the CRC on these two bytes.
+ //
+ ucCrc = CRC8_ITER(ucCrc, ulTemp);
+ ucCrc = CRC8_ITER(ucCrc, ulTemp >> 8);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 2;
+ ulCount -= 2;
+ }
+
+ //
+ // While there is at least a word remaining in the data buffer, perform
+ // four steps of the CRC to consume a word.
+ //
+ while(ulCount > 3)
+ {
+ //
+ // Read the next word.
+ //
+ ulTemp = *(unsigned long *)pucData;
+
+ //
+ // Perform the CRC on these four bytes.
+ //
+ ucCrc = CRC8_ITER(ucCrc, ulTemp);
+ ucCrc = CRC8_ITER(ucCrc, ulTemp >> 8);
+ ucCrc = CRC8_ITER(ucCrc, ulTemp >> 16);
+ ucCrc = CRC8_ITER(ucCrc, ulTemp >> 24);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 4;
+ ulCount -= 4;
+ }
+
+ //
+ // If there is a short left in the input buffer, then perform two steps of
+ // the CRC.
+ //
+ if(ulCount > 1)
+ {
+ //
+ // Read the short.
+ //
+ ulTemp = *(unsigned short *)pucData;
+
+ //
+ // Perform the CRC on these two bytes.
+ //
+ ucCrc = CRC8_ITER(ucCrc, ulTemp);
+ ucCrc = CRC8_ITER(ucCrc, ulTemp >> 8);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 2;
+ ulCount -= 2;
+ }
+
+ //
+ // If there is a final byte remaining in the input buffer, then perform a
+ // single step of the CRC.
+ //
+ if(ulCount != 0)
+ {
+ ucCrc = CRC8_ITER(ucCrc, *pucData);
+ }
+
+ //
+ // Return the resulting CRC-8-CCITT value.
+ //
+ return(ucCrc);
+}
+
+//*****************************************************************************
+//
+//! Calculates the CRC-16 of an array of bytes.
+//!
+//! \param usCrc is the starting CRC-16 value.
+//! \param pucData is a pointer to the data buffer.
+//! \param ulCount is the number of bytes in the data buffer.
+//!
+//! This function is used to calculate the CRC-16 of the input buffer. The
+//! CRC-16 is computed in a running fashion, meaning that the entire data block
+//! that is to have its CRC-16 computed does not need to be supplied all at
+//! once. If the input buffer contains the entire block of data, then \b usCrc
+//! should be set to 0. If, however, the entire block of data is not
+//! available, then \b usCrc should be set to 0 for the first portion of the
+//! data, and then the returned value should be passed back in as \b usCrc for
+//! the next portion of the data.
+//!
+//! For example, to compute the CRC-16 of a block that has been split into
+//! three pieces, use the following:
+//!
+//! \verbatim
+//! usCrc = Crc16(0, pucData1, ulLen1);
+//! usCrc = Crc16(usCrc, pucData2, ulLen2);
+//! usCrc = Crc16(usCrc, pucData3, ulLen3);
+//! \endverbatim
+//!
+//! Computing a CRC-16 in a running fashion is useful in cases where the data
+//! is arriving via a serial link (for example) and is therefore not all
+//! available at one time.
+//!
+//! \return The CRC-16 of the input data.
+//
+//*****************************************************************************
+unsigned short
+Crc16(unsigned short usCrc, const unsigned char *pucData,
+ unsigned long ulCount)
+{
+ unsigned long ulTemp;
+
+ //
+ // If the data buffer is not short-aligned, then perform a single step of
+ // the CRC to make it short-aligned.
+ //
+ if((unsigned long)pucData & 1)
+ {
+ //
+ // Perform the CRC on this input byte.
+ //
+ usCrc = CRC16_ITER(usCrc, *pucData);
+
+ //
+ // Skip this input byte.
+ //
+ pucData++;
+ ulCount--;
+ }
+
+ //
+ // If the data buffer is not word-aligned and there are at least two bytes
+ // of data left, then perform two steps of the CRC to make it word-aligned.
+ //
+ if(((unsigned long)pucData & 2) && (ulCount > 1))
+ {
+ //
+ // Read the next short.
+ //
+ ulTemp = *(unsigned short *)pucData;
+
+ //
+ // Perform the CRC on these two bytes.
+ //
+ usCrc = CRC16_ITER(usCrc, ulTemp);
+ usCrc = CRC16_ITER(usCrc, ulTemp >> 8);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 2;
+ ulCount -= 2;
+ }
+
+ //
+ // While there is at least a word remaining in the data buffer, perform
+ // four steps of the CRC to consume a word.
+ //
+ while(ulCount > 3)
+ {
+ //
+ // Read the next word.
+ //
+ ulTemp = *(unsigned long *)pucData;
+
+ //
+ // Perform the CRC on these four bytes.
+ //
+ usCrc = CRC16_ITER(usCrc, ulTemp);
+ usCrc = CRC16_ITER(usCrc, ulTemp >> 8);
+ usCrc = CRC16_ITER(usCrc, ulTemp >> 16);
+ usCrc = CRC16_ITER(usCrc, ulTemp >> 24);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 4;
+ ulCount -= 4;
+ }
+
+ //
+ // If there is a short left in the input buffer, then perform two steps of
+ // the CRC.
+ //
+ if(ulCount > 1)
+ {
+ //
+ // Read the short.
+ //
+ ulTemp = *(unsigned short *)pucData;
+
+ //
+ // Perform the CRC on these two bytes.
+ //
+ usCrc = CRC16_ITER(usCrc, ulTemp);
+ usCrc = CRC16_ITER(usCrc, ulTemp >> 8);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 2;
+ ulCount -= 2;
+ }
+
+ //
+ // If there is a final byte remaining in the input buffer, then perform a
+ // single step of the CRC.
+ //
+ if(ulCount != 0)
+ {
+ usCrc = CRC16_ITER(usCrc, *pucData);
+ }
+
+ //
+ // Return the resulting CRC-16 value.
+ //
+ return(usCrc);
+}
+
+//*****************************************************************************
+//
+//! Calculates the CRC-16 of an array of words.
+//!
+//! \param ulWordLen is the length of the array in words (the number of bytes
+//! divided by 4).
+//! \param pulData is a pointer to the data buffer.
+//!
+//! This function is a wrapper around the running CRC-16 function, providing
+//! the CRC-16 for a single block of data.
+//!
+//! \return The CRC-16 of the input data.
+//
+//*****************************************************************************
+unsigned short
+Crc16Array(unsigned long ulWordLen, const unsigned long *pulData)
+{
+ //
+ // Calculate and return the CRC-16 of this array of words.
+ //
+ return(Crc16(0, (const unsigned char *)pulData, ulWordLen * 4));
+}
+
+//*****************************************************************************
+//
+//! Calculates three CRC-16s of an array of words.
+//!
+//! \param ulWordLen is the length of the array in words (the number of bytes
+//! divided by 4).
+//! \param pulData is a pointer to the data buffer.
+//! \param pusCrc3 is a pointer to an array in which to place the three CRC-16
+//! values.
+//!
+//! This function is used to calculate three CRC-16s of the input buffer; the
+//! first uses every byte from the array, the second uses only the even-index
+//! bytes from the array (in other words, bytes 0, 2, 4, etc.), and the third
+//! uses only the odd-index bytes from the array (in other words, bytes 1, 3,
+//! 5, etc.).
+//!
+//! \return None
+//
+//*****************************************************************************
+void
+Crc16Array3(unsigned long ulWordLen, const unsigned long *pulData,
+ unsigned short *pusCrc3)
+{
+ unsigned short usCrc, usCrcOdd, usCrcEven;
+ unsigned long ulTemp;
+
+ //
+ // Initialize the CRC values to zero.
+ //
+ usCrc = 0;
+ usCrcOdd = 0;
+ usCrcEven = 0;
+
+ //
+ // Loop while there are more words in the data buffer.
+ //
+ while(ulWordLen--)
+ {
+ //
+ // Read the next word.
+ //
+ ulTemp = *pulData++;
+
+ //
+ // Perform the first CRC on all four data bytes.
+ //
+ usCrc = CRC16_ITER(usCrc, ulTemp);
+ usCrc = CRC16_ITER(usCrc, ulTemp >> 8);
+ usCrc = CRC16_ITER(usCrc, ulTemp >> 16);
+ usCrc = CRC16_ITER(usCrc, ulTemp >> 24);
+
+ //
+ // Perform the second CRC on only the even-index data bytes.
+ //
+ usCrcEven = CRC16_ITER(usCrcEven, ulTemp);
+ usCrcEven = CRC16_ITER(usCrcEven, ulTemp >> 16);
+
+ //
+ // Perform the third CRC on only the odd-index data bytes.
+ //
+ usCrcOdd = CRC16_ITER(usCrcOdd, ulTemp >> 8);
+ usCrcOdd = CRC16_ITER(usCrcOdd, ulTemp >> 24);
+ }
+
+ //
+ // Return the resulting CRC-16 values.
+ //
+ pusCrc3[0] = usCrc;
+ pusCrc3[1] = usCrcEven;
+ pusCrc3[2] = usCrcOdd;
+}
+
+//*****************************************************************************
+//
+//! Calculates the CRC-32 of an array of bytes.
+//!
+//! \param ulCrc is the starting CRC-32 value.
+//! \param pucData is a pointer to the data buffer.
+//! \param ulCount is the number of bytes in the data buffer.
+//!
+//! This function is used to calculate the CRC-32 of the input buffer. The
+//! CRC-32 is computed in a running fashion, meaning that the entire data block
+//! that is to have its CRC-32 computed does not need to be supplied all at
+//! once. If the input buffer contains the entire block of data, then \b ulCrc
+//! should be set to 0xFFFFFFFF. If, however, the entire block of data is not
+//! available, then \b ulCrc should be set to 0xFFFFFFFF for the first portion
+//! of the data, and then the returned value should be passed back in as \b
+//! ulCrc for the next portion of the data. Once all data has been passed
+//! to the function, the final CRC-32 can be obtained by inverting the last
+//! returned value.
+//!
+//! For example, to compute the CRC-32 of a block that has been split into
+//! three pieces, use the following:
+//!
+//! \verbatim
+//! ulCrc = Crc32(0xFFFFFFFF, pucData1, ulLen1);
+//! ulCrc = Crc32(ulCrc, pucData2, ulLen2);
+//! ulCrc = Crc32(ulCrc, pucData3, ulLen3);
+//! ulCrc ^= 0xFFFFFFFF;
+//! \endverbatim
+//!
+//! Computing a CRC-32 in a running fashion is useful in cases where the data
+//! is arriving via a serial link (for example) and is therefore not all
+//! available at one time.
+//!
+//! \return The accumulated CRC-32 of the input data.
+//
+//*****************************************************************************
+unsigned long
+Crc32(unsigned long ulCrc, const unsigned char *pucData, unsigned long ulCount)
+{
+ unsigned long ulTemp;
+
+ //
+ // If the data buffer is not short-aligned, then perform a single step of
+ // the CRC to make it short-aligned.
+ //
+ if((unsigned long)pucData & 1)
+ {
+ //
+ // Perform the CRC on this input byte.
+ //
+ ulCrc = CRC32_ITER(ulCrc, *pucData);
+
+ //
+ // Skip this input byte.
+ //
+ pucData++;
+ ulCount--;
+ }
+
+ //
+ // If the data buffer is not word-aligned and there are at least two bytes
+ // of data left, then perform two steps of the CRC to make it word-aligned.
+ //
+ if(((unsigned long)pucData & 2) && (ulCount > 1))
+ {
+ //
+ // Read the next short.
+ //
+ ulTemp = *(unsigned short *)pucData;
+
+ //
+ // Perform the CRC on these two bytes.
+ //
+ ulCrc = CRC32_ITER(ulCrc, ulTemp);
+ ulCrc = CRC32_ITER(ulCrc, ulTemp >> 8);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 2;
+ ulCount -= 2;
+ }
+
+ //
+ // While there is at least a word remaining in the data buffer, perform
+ // four steps of the CRC to consume a word.
+ //
+ while(ulCount > 3)
+ {
+ //
+ // Read the next word.
+ //
+ ulTemp = *(unsigned long *)pucData;
+
+ //
+ // Perform the CRC on these four bytes.
+ //
+ ulCrc = CRC32_ITER(ulCrc, ulTemp);
+ ulCrc = CRC32_ITER(ulCrc, ulTemp >> 8);
+ ulCrc = CRC32_ITER(ulCrc, ulTemp >> 16);
+ ulCrc = CRC32_ITER(ulCrc, ulTemp >> 24);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 4;
+ ulCount -= 4;
+ }
+
+ //
+ // If there is a short left in the input buffer, then perform two steps of
+ // the CRC.
+ //
+ if(ulCount > 1)
+ {
+ //
+ // Read the short.
+ //
+ ulTemp = *(unsigned short *)pucData;
+
+ //
+ // Perform the CRC on these two bytes.
+ //
+ ulCrc = CRC32_ITER(ulCrc, ulTemp);
+ ulCrc = CRC32_ITER(ulCrc, ulTemp >> 8);
+
+ //
+ // Skip these input bytes.
+ //
+ pucData += 2;
+ ulCount -= 2;
+ }
+
+ //
+ // If there is a final byte remaining in the input buffer, then perform a
+ // single step of the CRC.
+ //
+ if(ulCount != 0)
+ {
+ ulCrc = CRC32_ITER(ulCrc, *pucData);
+ }
+
+ //
+ // Return the resulting CRC-16 value.
+ //
+ return(ulCrc);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/crc.h b/utils/crc.h
new file mode 100644
index 0000000..432a558
--- /dev/null
+++ b/utils/crc.h
@@ -0,0 +1,65 @@
+//*****************************************************************************
+//
+// crc.h - Prototypes for the CRC functions.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __CRC_H__
+#define __CRC_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the functions.
+//
+//*****************************************************************************
+extern unsigned char Crc8CCITT(unsigned char ucCrc,
+ const unsigned char *pucData,
+ unsigned long ulCount);
+extern unsigned short Crc16(unsigned short usCrc, const unsigned char *pucData,
+ unsigned long ulCount);
+extern unsigned short Crc16Array(unsigned long ulWordLen,
+ const unsigned long *pulData);
+extern void Crc16Array3(unsigned long ulWordLen, const unsigned long *pulData,
+ unsigned short *pusCrc3);
+extern unsigned long Crc32(unsigned long ulCrc, const unsigned char *pucData,
+ unsigned long ulCount);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __CRC_H__
diff --git a/utils/flash_pb.c b/utils/flash_pb.c
new file mode 100644
index 0000000..e057120
--- /dev/null
+++ b/utils/flash_pb.c
@@ -0,0 +1,486 @@
+//*****************************************************************************
+//
+// flash_pb.c - Flash parameter block functions.
+//
+// Copyright (c) 2008-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#include "inc/hw_flash.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/flash.h"
+#include "driverlib/sysctl.h"
+#include "utils/flash_pb.h"
+
+//*****************************************************************************
+//
+//! \addtogroup flash_pb_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The address of the beginning of the flash used for storing parameter blocks;
+// this must be the start of an erase block in the flash.
+//
+//*****************************************************************************
+static unsigned char *g_pucFlashPBStart;
+
+//*****************************************************************************
+//
+// The address of the end of the flash used for storing parameter blocks; this
+// must be the start of an erase block in the flash, or the first location
+// after the end of the flash array if the last erase block is used for storing
+// parameters.
+//
+//*****************************************************************************
+static unsigned char *g_pucFlashPBEnd;
+
+//*****************************************************************************
+//
+// The size of the parameter block when stored in flash; this must be a power
+// of two less than or equal to 1024.
+//
+//*****************************************************************************
+static unsigned long g_ulFlashPBSize;
+
+//*****************************************************************************
+//
+// The address of the most recent parameter block in flash.
+//
+//*****************************************************************************
+static unsigned char *g_pucFlashPBCurrent;
+
+//*****************************************************************************
+//
+//! Determines if the parameter block at the given address is valid.
+//!
+//! \param pucOffset is the address of the parameter block to check.
+//!
+//! This function will compute the checksum of a parameter block in flash to
+//! determine if it is valid.
+//!
+//! \return Returns one if the parameter block is valid and zero if it is not.
+//
+//*****************************************************************************
+static unsigned long
+FlashPBIsValid(unsigned char *pucOffset)
+{
+ unsigned long ulIdx, ulSum;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pucOffset != (void *)0);
+
+ //
+ // Loop through the bytes in the block, computing the checksum.
+ //
+ for(ulIdx = 0, ulSum = 0; ulIdx < g_ulFlashPBSize; ulIdx++)
+ {
+ ulSum += pucOffset[ulIdx];
+ }
+
+ //
+ // The checksum should be zero, so return a failure if it is not.
+ //
+ if((ulSum & 255) != 0)
+ {
+ return(0);
+ }
+
+ //
+ // If the sum is equal to the size * 255, then the block is all ones and
+ // should not be considered valid.
+ //
+ if((g_ulFlashPBSize * 255) == ulSum)
+ {
+ return(0);
+ }
+
+ //
+ // This is a valid parameter block.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Gets the address of the most recent parameter block.
+//!
+//! This function returns the address of the most recent parameter block that
+//! is stored in flash.
+//!
+//! \return Returns the address of the most recent parameter block, or NULL if
+//! there are no valid parameter blocks in flash.
+//
+//*****************************************************************************
+unsigned char *
+FlashPBGet(void)
+{
+ //
+ // See if there is a valid parameter block.
+ //
+ if(g_pucFlashPBCurrent)
+ {
+ //
+ // Return the address of the most recent parameter block.
+ //
+ return(g_pucFlashPBCurrent);
+ }
+
+ //
+ // There are no valid parameter blocks in flash, so return NULL.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Writes a new parameter block to flash.
+//!
+//! \param pucBuffer is the address of the parameter block to be written to
+//! flash.
+//!
+//! This function will write a parameter block to flash. Saving the new
+//! parameter blocks involves three steps:
+//!
+//! - Setting the sequence number such that it is one greater than the sequence
+//! number of the latest parameter block in flash.
+//! - Computing the checksum of the parameter block.
+//! - Writing the parameter block into the storage immediately following the
+//! latest parameter block in flash; if that storage is at the start of an
+//! erase block, that block is erased first.
+//!
+//! By this process, there is always a valid parameter block in flash. If
+//! power is lost while writing a new parameter block, the checksum will not
+//! match and the partially written parameter block will be ignored. This is
+//! what makes this fault-tolerant.
+//!
+//! Another benefit of this scheme is that it provides wear leveling on the
+//! flash. Since multiple parameter blocks fit into each erase block of flash,
+//! and multiple erase blocks are used for parameter block storage, it takes
+//! quite a few parameter block saves before flash is re-written.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+FlashPBSave(unsigned char *pucBuffer)
+{
+ unsigned char *pucNew;
+ unsigned long ulIdx, ulSum;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pucBuffer != (void *)0);
+
+ //
+ // See if there is a valid parameter block in flash.
+ //
+ if(g_pucFlashPBCurrent)
+ {
+ //
+ // Set the sequence number to one greater than the most recent
+ // parameter block.
+ //
+ pucBuffer[0] = g_pucFlashPBCurrent[0] + 1;
+
+ //
+ // Try to write the new parameter block immediately after the most
+ // recent parameter block.
+ //
+ pucNew = g_pucFlashPBCurrent + g_ulFlashPBSize;
+ if(pucNew == g_pucFlashPBEnd)
+ {
+ pucNew = g_pucFlashPBStart;
+ }
+ }
+ else
+ {
+ //
+ // There is not a valid parameter block in flash, so set the sequence
+ // number of this parameter block to zero.
+ //
+ pucBuffer[0] = 0;
+
+ //
+ // Try to write the new parameter block at the beginning of the flash
+ // space for parameter blocks.
+ //
+ pucNew = g_pucFlashPBStart;
+ }
+
+ //
+ // Compute the checksum of the parameter block to be written.
+ //
+ for(ulIdx = 0, ulSum = 0; ulIdx < g_ulFlashPBSize; ulIdx++)
+ {
+ ulSum -= pucBuffer[ulIdx];
+ }
+
+ //
+ // Store the checksum into the parameter block.
+ //
+ pucBuffer[1] += ulSum;
+
+ //
+ // Look for a location to store this parameter block. This infinite loop
+ // will be explicitly broken out of when a valid location is found.
+ //
+ while(1)
+ {
+ //
+ // See if this location is at the start of an erase block.
+ //
+ if(((unsigned long)pucNew & 1023) == 0)
+ {
+ //
+ // Erase this block of the flash. This does not assume that the
+ // erase succeeded in case this block of the flash has become bad
+ // through too much use. Given the extremely low frequency that
+ // the parameter blocks are written, this will likely never fail.
+ // But, that assumption is not made in order to be safe.
+ //
+ FlashErase((unsigned long)pucNew);
+ }
+
+ //
+ // Loop through this portion of flash to see if is all ones (i.e. it
+ // is an erased portion of flash).
+ //
+ for(ulIdx = 0; ulIdx < g_ulFlashPBSize; ulIdx++)
+ {
+ if(pucNew[ulIdx] != 0xff)
+ {
+ break;
+ }
+ }
+
+ //
+ // If all bytes in this portion of flash are ones, then break out of
+ // the loop since this is a good location for storing the parameter
+ // block.
+ //
+ if(ulIdx == g_ulFlashPBSize)
+ {
+ break;
+ }
+
+ //
+ // Increment to the next parameter block location.
+ //
+ pucNew += g_ulFlashPBSize;
+ if(pucNew == g_pucFlashPBEnd)
+ {
+ pucNew = g_pucFlashPBStart;
+ }
+
+ //
+ // If every possible location has been checked and none are valid, then
+ // it will not be possible to write this parameter block. Simply
+ // return without writing it.
+ //
+ if((g_pucFlashPBCurrent && (pucNew == g_pucFlashPBCurrent)) ||
+ (!g_pucFlashPBCurrent && (pucNew == g_pucFlashPBStart)))
+ {
+ return;
+ }
+ }
+
+ //
+ // Write this parameter block to flash.
+ //
+ FlashProgram((unsigned long *)pucBuffer, (unsigned long)pucNew,
+ g_ulFlashPBSize);
+
+ //
+ // Compare the parameter block data to the data that should now be in
+ // flash. Return if any of the data does not compare, leaving the previous
+ // parameter block in flash as the most recent (since the current parameter
+ // block failed to properly program).
+ //
+ for(ulIdx = 0; ulIdx < g_ulFlashPBSize; ulIdx++)
+ {
+ if(pucNew[ulIdx] != pucBuffer[ulIdx])
+ {
+ return;
+ }
+ }
+
+ //
+ // The new parameter block becomes the most recent parameter block.
+ //
+ g_pucFlashPBCurrent = pucNew;
+}
+
+//*****************************************************************************
+//
+//! Initializes the flash parameter block.
+//!
+//! \param ulStart is the address of the flash memory to be used for storing
+//! flash parameter blocks; this must be the start of an erase block in the
+//! flash.
+//! \param ulEnd is the address of the end of flash memory to be used for
+//! storing flash parameter blocks; this must be the start of an erase block in
+//! the flash (the first block that is NOT part of the flash memory to be
+//! used), or the address of the first word after the flash array if the last
+//! block of flash is to be used.
+//! \param ulSize is the size of the parameter block when stored in flash;
+//! this must be a power of two less than or equal to the flash erase block
+//! size (typically 1024).
+//!
+//! This function initializes a fault-tolerant, persistent storage mechanism
+//! for a parameter block for an application. The last several erase blocks
+//! of flash (as specified by \e ulStart and \e ulEnd are used for the
+//! storage; more than one erase block is required in order to be
+//! fault-tolerant.
+//!
+//! A parameter block is an array of bytes that contain the persistent
+//! parameters for the application. The only special requirement for the
+//! parameter block is that the first byte is a sequence number (explained
+//! in FlashPBSave()) and the second byte is a checksum used to validate the
+//! correctness of the data (the checksum byte is the byte such that the sum of
+//! all bytes in the parameter block is zero).
+//!
+//! The portion of flash for parameter block storage is split into N
+//! equal-sized regions, where each region is the size of a parameter block
+//! (\e ulSize). Each region is scanned to find the most recent valid
+//! parameter block. The region that has a valid checksum and has the highest
+//! sequence number (with special consideration given to wrapping back to zero)
+//! is considered to be the current parameter block.
+//!
+//! In order to make this efficient and effective, three conditions must be
+//! met. The first is \e ulStart and \e ulEnd must be specified such that at
+//! least two erase blocks of flash are dedicated to parameter block storage.
+//! If not, fault tolerance can not be guaranteed since an erase of a single
+//! block will leave a window where there are no valid parameter blocks in
+//! flash. The second condition is that the size (\e ulSize) of the parameter
+//! block must be an integral divisor of the size of an erase block of flash.
+//! If not, a parameter block will end up spanning between two erase blocks of
+//! flash, making it more difficult to manage. The final condition is that the
+//! size of the flash dedicated to parameter blocks (\e ulEnd - \e ulStart)
+//! divided by the parameter block size (\e ulSize) must be less than or equal
+//! to 128. If not, it will not be possible in all cases to determine which
+//! parameter block is the most recent (specifically when dealing with the
+//! sequence number wrapping back to zero).
+//!
+//! When the microcontroller is initially programmed, the flash blocks used for
+//! parameter block storage are left in an erased state.
+//!
+//! This function must be called before any other flash parameter block
+//! functions are called.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+FlashPBInit(unsigned long ulStart, unsigned long ulEnd, unsigned long ulSize)
+{
+ unsigned char *pucOffset, *pucCurrent;
+ unsigned char ucOne, ucTwo;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT((ulStart % FLASH_ERASE_SIZE) == 0);
+ ASSERT((ulEnd % FLASH_ERASE_SIZE) == 0);
+ ASSERT((FLASH_ERASE_SIZE % ulSize) == 0);
+
+ //
+ // Set the number of clocks per microsecond to enable the flash controller
+ // to properly program the flash.
+ //
+ FlashUsecSet(SysCtlClockGet() / 1000000);
+
+ //
+ // Save the characteristics of the flash memory to be used for storing
+ // parameter blocks.
+ //
+ g_pucFlashPBStart = (unsigned char *)ulStart;
+ g_pucFlashPBEnd = (unsigned char *)ulEnd;
+ g_ulFlashPBSize = ulSize;
+
+ //
+ // Loop through the portion of flash memory used for storing parameter
+ // blocks.
+ //
+ for(pucOffset = g_pucFlashPBStart, pucCurrent = 0;
+ pucOffset < g_pucFlashPBEnd; pucOffset += g_ulFlashPBSize)
+ {
+ //
+ // See if this is a valid parameter block (i.e. the checksum is
+ // correct).
+ //
+ if(FlashPBIsValid(pucOffset))
+ {
+ //
+ // See if a valid parameter block has been previously found.
+ //
+ if(pucCurrent != 0)
+ {
+ //
+ // Get the sequence numbers for the current and new parameter
+ // blocks.
+ //
+ ucOne = pucCurrent[0];
+ ucTwo = pucOffset[0];
+
+ //
+ // See if the sequence number for the new parameter block is
+ // greater than the current block. The comparison isn't
+ // straightforward since the one byte sequence number will wrap
+ // after 256 parameter blocks.
+ //
+ if(((ucOne > ucTwo) && ((ucOne - ucTwo) < 128)) ||
+ ((ucTwo > ucOne) && ((ucTwo - ucOne) > 128)))
+ {
+ //
+ // The new parameter block is older than the current
+ // parameter block, so skip the new parameter block and
+ // keep searching.
+ //
+ continue;
+ }
+ }
+
+ //
+ // The new parameter block is more recent than the current one, so
+ // make it the new current parameter block.
+ //
+ pucCurrent = pucOffset;
+ }
+ }
+
+ //
+ // Save the address of the most recent parameter block found. If no valid
+ // parameter blocks were found, this will be a NULL pointer.
+ //
+ g_pucFlashPBCurrent = pucCurrent;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/flash_pb.h b/utils/flash_pb.h
new file mode 100644
index 0000000..8d8afbf
--- /dev/null
+++ b/utils/flash_pb.h
@@ -0,0 +1,58 @@
+//*****************************************************************************
+//
+// flash_pb.h - Prototypes for the flash parameter block functions.
+//
+// Copyright (c) 2008-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __FLASH_PB_H__
+#define __FLASH_PB_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// Prototype for the flash parameter block functions.
+//
+//*****************************************************************************
+extern unsigned char *FlashPBGet(void);
+extern void FlashPBSave(unsigned char *pucBuffer);
+extern void FlashPBInit(unsigned long ulStart, unsigned long ulEnd,
+ unsigned long ulSize);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FLASH_PB_H__
diff --git a/utils/isqrt.c b/utils/isqrt.c
new file mode 100644
index 0000000..d347e1e
--- /dev/null
+++ b/utils/isqrt.c
@@ -0,0 +1,117 @@
+//*****************************************************************************
+//
+// isqrt.c - Integer square root.
+//
+// Copyright (c) 2005-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#include "utils/isqrt.h"
+
+//*****************************************************************************
+//
+//! \addtogroup isqrt_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Compute the integer square root of an integer.
+//!
+//! \param ulValue is the value whose square root is desired.
+//!
+//! This function will compute the integer square root of the given input
+//! value. Since the value returned is also an integer, it is actually better
+//! defined as the largest integer whose square is less than or equal to the
+//! input value.
+//!
+//! \return Returns the square root of the input value.
+//
+//*****************************************************************************
+unsigned long
+isqrt(unsigned long ulValue)
+{
+ unsigned long ulRem, ulRoot, ulIdx;
+
+ //
+ // Initialize the remainder and root to zero.
+ //
+ ulRem = 0;
+ ulRoot = 0;
+
+ //
+ // Loop over the sixteen bits in the root.
+ //
+ for(ulIdx = 0; ulIdx < 16; ulIdx++)
+ {
+ //
+ // Shift the root up by a bit to make room for the new bit that is
+ // about to be computed.
+ //
+ ulRoot <<= 1;
+
+ //
+ // Get two more bits from the input into the remainder.
+ //
+ ulRem = ((ulRem << 2) + (ulValue >> 30));
+ ulValue <<= 2;
+
+ //
+ // Make the test root be 2n + 1.
+ //
+ ulRoot++;
+
+ //
+ // See if the root is greater than the remainder.
+ //
+ if(ulRoot <= ulRem)
+ {
+ //
+ // Subtract the test root from the remainder.
+ //
+ ulRem -= ulRoot;
+
+ //
+ // Increment the root, setting the second LSB.
+ //
+ ulRoot++;
+ }
+ else
+ {
+ //
+ // The root is greater than the remainder, so the new bit of the
+ // root is actually zero.
+ //
+ ulRoot--;
+ }
+ }
+
+ //
+ // Return the computed root.
+ //
+ return(ulRoot >> 1);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/isqrt.h b/utils/isqrt.h
new file mode 100644
index 0000000..f25f42b
--- /dev/null
+++ b/utils/isqrt.h
@@ -0,0 +1,55 @@
+//*****************************************************************************
+//
+// isqrt.h - Prototype for the integer square root function.
+//
+// Copyright (c) 2006-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __ISQRT_H__
+#define __ISQRT_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The prototype for the integer square root function.
+//
+//*****************************************************************************
+extern unsigned long isqrt(unsigned long ulValue);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/utils/ringbuf.c b/utils/ringbuf.c
new file mode 100644
index 0000000..ff49f9e
--- /dev/null
+++ b/utils/ringbuf.c
@@ -0,0 +1,709 @@
+//*****************************************************************************
+//
+// ringbuf.c - Ring buffer management utilities.
+//
+// Copyright (c) 2008-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "utils/ringbuf.h"
+
+//*****************************************************************************
+//
+//! \addtogroup ringbuf_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Define NULL, if not already defined.
+//
+//*****************************************************************************
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+//*****************************************************************************
+//
+// Change the value of a variable atomically.
+//
+// \param pulVal points to the index whose value is to be modified.
+// \param ulDelta is the number of bytes to increment the index by.
+// \param ulSize is the size of the buffer the index refers to.
+//
+// This function is used to increment a read or write buffer index that may be
+// written in various different contexts. It ensures that the read/modify/write
+// sequence is not interrupted and, hence, guards against corruption of the
+// variable. The new value is adjusted for buffer wrap.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+UpdateIndexAtomic(volatile unsigned long *pulVal, unsigned long ulDelta,
+ unsigned long ulSize)
+{
+ tBoolean bIntsOff;
+
+ //
+ // Turn interrupts off temporarily.
+ //
+ bIntsOff = IntMasterDisable();
+
+ //
+ // Update the variable value.
+ //
+ *pulVal += ulDelta;
+
+ //
+ // Correct for wrap. We use a loop here since we don't want to use a
+ // modulus operation with interrupts off but we don't want to fail in
+ // case ulDelta is greater than ulSize (which is extremely unlikely but...)
+ //
+ while(*pulVal >= ulSize)
+ {
+ *pulVal -= ulSize;
+ }
+
+ //
+ // Restore the interrupt state
+ //
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is full or not.
+//!
+//! \param ptRingBuf is the ring buffer object to empty.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! full. The structure is specifically to ensure that we do not see
+//! warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is full or \b false otherwise.
+//
+//*****************************************************************************
+tBoolean
+RingBufFull(tRingBufObject *ptRingBuf)
+{
+ unsigned long ulWrite;
+ unsigned long ulRead;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ulWrite = ptRingBuf->ulWriteIndex;
+ ulRead = ptRingBuf->ulReadIndex;
+
+ //
+ // Return the full status of the buffer.
+ //
+ return((((ulWrite + 1) % ptRingBuf->ulSize) == ulRead) ? true : false);
+}
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is empty or not.
+//!
+//! \param ptRingBuf is the ring buffer object to empty.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! empty. The structure is specifically to ensure that we do not see
+//! warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is empty or \b false otherwise.
+//
+//*****************************************************************************
+tBoolean
+RingBufEmpty(tRingBufObject *ptRingBuf)
+{
+ unsigned long ulWrite;
+ unsigned long ulRead;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ulWrite = ptRingBuf->ulWriteIndex;
+ ulRead = ptRingBuf->ulReadIndex;
+
+ //
+ // Return the empty status of the buffer.
+ //
+ return((ulWrite == ulRead) ? true : false);
+}
+
+//*****************************************************************************
+//
+//! Empties the ring buffer.
+//!
+//! \param ptRingBuf is the ring buffer object to empty.
+//!
+//! Discards all data from the ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufFlush(tRingBufObject *ptRingBuf)
+{
+ tBoolean bIntsOff;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Set the Read/Write pointers to be the same. Do this with interrupts
+ // disabled to prevent the possibility of corruption of the read index.
+ //
+ bIntsOff = IntMasterDisable();
+ ptRingBuf->ulReadIndex = ptRingBuf->ulWriteIndex;
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Returns number of bytes stored in ring buffer.
+//!
+//! \param ptRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of bytes stored in the ring buffer.
+//!
+//! \return Returns the number of bytes stored in the ring buffer.
+//
+//*****************************************************************************
+unsigned long
+RingBufUsed(tRingBufObject *ptRingBuf)
+{
+ unsigned long ulWrite;
+ unsigned long ulRead;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ulWrite = ptRingBuf->ulWriteIndex;
+ ulRead = ptRingBuf->ulReadIndex;
+
+ //
+ // Return the number of bytes contained in the ring buffer.
+ //
+ return((ulWrite >= ulRead) ? (ulWrite - ulRead) :
+ (ptRingBuf->ulSize - (ulRead - ulWrite)));
+}
+
+//*****************************************************************************
+//
+//! Returns number of bytes available in a ring buffer.
+//!
+//! \param ptRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of bytes available in the ring buffer.
+//!
+//! \return Returns the number of bytes available in the ring buffer.
+//
+//*****************************************************************************
+unsigned long
+RingBufFree(tRingBufObject *ptRingBuf)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Return the number of bytes available in the ring buffer.
+ //
+ return((ptRingBuf->ulSize - 1) - RingBufUsed(ptRingBuf));
+}
+
+//*****************************************************************************
+//
+//! Returns number of contiguous bytes of data stored in ring buffer ahead of
+//! the current read pointer.
+//!
+//! \param ptRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of contiguous bytes of data available in
+//! the ring buffer ahead of the current read pointer. This represents the
+//! largest block of data which does not straddle the buffer wrap.
+//!
+//! \return Returns the number of contiguous bytes available.
+//
+//*****************************************************************************
+unsigned long
+RingBufContigUsed(tRingBufObject *ptRingBuf)
+{
+ unsigned long ulWrite;
+ unsigned long ulRead;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ulWrite = ptRingBuf->ulWriteIndex;
+ ulRead = ptRingBuf->ulReadIndex;
+
+ //
+ // Return the number of contiguous bytes available.
+ //
+ return((ulWrite >= ulRead) ? (ulWrite - ulRead) :
+ (ptRingBuf->ulSize - ulRead));
+}
+
+//*****************************************************************************
+//
+//! Returns number of contiguous free bytes available in a ring buffer.
+//!
+//! \param ptRingBuf is the ring buffer object to check.
+//!
+//! This function returns the number of contiguous free bytes ahead of the
+//! current write pointer in the ring buffer.
+//!
+//! \return Returns the number of contiguous bytes available in the ring
+//! buffer.
+//
+//*****************************************************************************
+unsigned long
+RingBufContigFree(tRingBufObject *ptRingBuf)
+{
+ unsigned long ulWrite;
+ unsigned long ulRead;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Copy the Read/Write indices for calculation.
+ //
+ ulWrite = ptRingBuf->ulWriteIndex;
+ ulRead = ptRingBuf->ulReadIndex;
+
+ //
+ // Return the number of contiguous bytes available.
+ //
+ if(ulRead > ulWrite)
+ {
+ //
+ // The read pointer is above the write pointer so the amount of free
+ // space is the difference between the two indices minus 1 to account
+ // for the buffer full condition (write index one behind read index).
+ //
+ return((ulRead - ulWrite) - 1);
+ }
+ else
+ {
+ //
+ // If the write pointer is above the read pointer, the amount of free
+ // space is the size of the buffer minus the write index. We need to
+ // add a special-case adjustment if the read index is 0 since we need
+ // to leave 1 byte empty to ensure we can tell the difference between
+ // the buffer being full and empty.
+ //
+ return(ptRingBuf->ulSize - ulWrite - ((ulRead == 0) ? 1 : 0));
+ }
+}
+
+//*****************************************************************************
+//
+//! Return size in bytes of a ring buffer.
+//!
+//! \param ptRingBuf is the ring buffer object to check.
+//!
+//! This function returns the size of the ring buffer.
+//!
+//! \return Returns the size in bytes of the ring buffer.
+//
+//*****************************************************************************
+unsigned long
+RingBufSize(tRingBufObject *ptRingBuf)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Return the number of bytes available in the ring buffer.
+ //
+ return(ptRingBuf->ulSize);
+}
+
+//*****************************************************************************
+//
+//! Reads a single byte of data from a ring buffer.
+//!
+//! \param ptRingBuf points to the ring buffer to be written to.
+//!
+//! This function reads a single byte of data from a ring buffer.
+//!
+//! \return The byte read from the ring buffer.
+//
+//*****************************************************************************
+unsigned char
+RingBufReadOne(tRingBufObject *ptRingBuf)
+{
+ unsigned char ucTemp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(RingBufUsed(ptRingBuf) != 0);
+
+ //
+ // Write the data byte.
+ //
+ ucTemp = ptRingBuf->pucBuf[ptRingBuf->ulReadIndex];
+
+ //
+ // Increment the read index.
+ //
+ UpdateIndexAtomic(&ptRingBuf->ulReadIndex, 1, ptRingBuf->ulSize);
+
+ //
+ // Return the character read.
+ //
+ return(ucTemp);
+}
+
+//*****************************************************************************
+//
+//! Reads data from a ring buffer.
+//!
+//! \param ptRingBuf points to the ring buffer to be read from.
+//! \param pucData points to where the data should be stored.
+//! \param ulLength is the number of bytes to be read.
+//!
+//! This function reads a sequence of bytes from a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufRead(tRingBufObject *ptRingBuf, unsigned char *pucData,
+ unsigned long ulLength)
+{
+ unsigned long ulTemp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+ ASSERT(pucData != NULL);
+ ASSERT(ulLength != 0);
+
+ //
+ // Verify that data is available in the buffer.
+ //
+ ASSERT(ulLength <= RingBufUsed(ptRingBuf));
+
+ //
+ // Read the data from the ring buffer.
+ //
+ for(ulTemp = 0; ulTemp < ulLength; ulTemp++)
+ {
+ pucData[ulTemp] = RingBufReadOne(ptRingBuf);
+ }
+}
+
+//*****************************************************************************
+//
+//! Remove bytes from the ring buffer by advancing the read index.
+//!
+//! \param ptRingBuf points to the ring buffer from which bytes are to be
+//! removed.
+//! \param ulNumBytes is the number of bytes to be removed from the buffer.
+//!
+//! This function advances the ring buffer read index by a given number of
+//! bytes, removing that number of bytes of data from the buffer. If \e
+//! ulNumBytes is larger than the number of bytes currently in the buffer, the
+//! buffer is emptied.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufAdvanceRead(tRingBufObject *ptRingBuf,
+ unsigned long ulNumBytes)
+{
+ unsigned long ulCount;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Make sure that we are not being asked to remove more data than is
+ // there to be removed.
+ //
+ ulCount = RingBufUsed(ptRingBuf);
+ ulCount = (ulCount < ulNumBytes) ? ulCount : ulNumBytes;
+
+ //
+ // Advance the buffer read index by the required number of bytes.
+ //
+ UpdateIndexAtomic(&ptRingBuf->ulReadIndex, ulCount,
+ ptRingBuf->ulSize);
+}
+
+//*****************************************************************************
+//
+//! Add bytes to the ring buffer by advancing the write index.
+//!
+//! \param ptRingBuf points to the ring buffer to which bytes have been added.
+//! \param ulNumBytes is the number of bytes added to the buffer.
+//!
+//! This function should be used by clients who wish to add data to the buffer
+//! directly rather than via calls to RingBufWrite() or RingBufWriteOne(). It
+//! advances the write index by a given number of bytes. If the \e ulNumBytes
+//! parameter is larger than the amount of free space in the buffer, the
+//! read pointer will be advanced to cater for the addition. Note that this
+//! will result in some of the oldest data in the buffer being discarded.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufAdvanceWrite(tRingBufObject *ptRingBuf,
+ unsigned long ulNumBytes)
+{
+ unsigned long ulCount;
+ tBoolean bIntsOff;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Make sure we were not asked to add a silly number of bytes.
+ //
+ ASSERT(ulNumBytes <= ptRingBuf->ulSize);
+
+ //
+ // Determine how much free space we currently think the buffer has.
+ //
+ ulCount = RingBufFree(ptRingBuf);
+
+ //
+ // Advance the buffer write index by the required number of bytes and
+ // check that we have not run past the read index. Note that we must do
+ // this within a critical section (interrupts disabled) to prevent
+ // race conditions that could corrupt one or other of the indices.
+ //
+ bIntsOff = IntMasterDisable();
+
+ //
+ // Update the write pointer.
+ //
+ ptRingBuf->ulWriteIndex += ulNumBytes;
+
+ //
+ // Check and correct for wrap.
+ //
+ if(ptRingBuf->ulWriteIndex >= ptRingBuf->ulSize)
+ {
+ ptRingBuf->ulWriteIndex -= ptRingBuf->ulSize;
+ }
+
+ //
+ // Did the client add more bytes than the buffer had free space for?
+ //
+ if(ulCount < ulNumBytes)
+ {
+ //
+ // Yes - we need to advance the read pointer to ahead of the write
+ // pointer to discard some of the oldest data.
+ //
+ ptRingBuf->ulReadIndex = ptRingBuf->ulWriteIndex + 1;
+
+ //
+ // Correct for buffer wrap if necessary.
+ //
+ if(ptRingBuf->ulReadIndex >= ptRingBuf->ulSize)
+ {
+ ptRingBuf->ulReadIndex -= ptRingBuf->ulSize;
+ }
+ }
+
+ //
+ // Restore interrupts if we turned them off earlier.
+ //
+ if(!bIntsOff)
+ {
+ IntMasterEnable();
+ }
+}
+
+//*****************************************************************************
+//
+//! Writes a single byte of data to a ring buffer.
+//!
+//! \param ptRingBuf points to the ring buffer to be written to.
+//! \param ucData is the byte to be written.
+//!
+//! This function writes a single byte of data into a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufWriteOne(tRingBufObject *ptRingBuf, unsigned char ucData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(RingBufFree(ptRingBuf) != 0);
+
+ //
+ // Write the data byte.
+ //
+ ptRingBuf->pucBuf[ptRingBuf->ulWriteIndex] = ucData;
+
+ //
+ // Increment the write index.
+ //
+ UpdateIndexAtomic(&ptRingBuf->ulWriteIndex, 1, ptRingBuf->ulSize);
+}
+
+//*****************************************************************************
+//
+//! Writes data to a ring buffer.
+//!
+//! \param ptRingBuf points to the ring buffer to be written to.
+//! \param pucData points to the data to be written.
+//! \param ulLength is the number of bytes to be written.
+//!
+//! This function write a sequence of bytes into a ring buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufWrite(tRingBufObject *ptRingBuf, unsigned char *pucData,
+ unsigned long ulLength)
+{
+ unsigned long ulTemp;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+ ASSERT(pucData != NULL);
+ ASSERT(ulLength != 0);
+
+ //
+ // Verify that space is available in the buffer.
+ //
+ ASSERT(ulLength <= RingBufFree(ptRingBuf));
+
+ //
+ // Write the data into the ring buffer.
+ //
+ for(ulTemp = 0; ulTemp < ulLength; ulTemp++)
+ {
+ RingBufWriteOne(ptRingBuf, pucData[ulTemp]);
+ }
+}
+
+//*****************************************************************************
+//
+//! Initialize a ring buffer object.
+//!
+//! \param ptRingBuf points to the ring buffer to be initialized.
+//! \param pucBuf points to the data buffer to be used for the ring buffer.
+//! \param ulSize is the size of the buffer in bytes.
+//!
+//! This function initializes a ring buffer object, preparing it to store data.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+RingBufInit(tRingBufObject *ptRingBuf, unsigned char *pucBuf,
+ unsigned long ulSize)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(ptRingBuf != NULL);
+ ASSERT(pucBuf != NULL);
+ ASSERT(ulSize != 0);
+
+ //
+ // Initialize the ring buffer object.
+ //
+ ptRingBuf->ulSize = ulSize;
+ ptRingBuf->pucBuf = pucBuf;
+ ptRingBuf->ulWriteIndex = ptRingBuf->ulReadIndex = 0;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/ringbuf.h b/utils/ringbuf.h
new file mode 100644
index 0000000..7aeab65
--- /dev/null
+++ b/utils/ringbuf.h
@@ -0,0 +1,105 @@
+//*****************************************************************************
+//
+// ringbuf.h - Defines and Macros for the ring buffer utilities.
+//
+// Copyright (c) 2008-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __RINGBUF_H__
+#define __RINGBUF_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// The structure used for encapsulating all the items associated with a
+// ring buffer.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The ring buffer size.
+ //
+ unsigned long ulSize;
+
+ //
+ // The ring buffer write index.
+ //
+ volatile unsigned long ulWriteIndex;
+
+ //
+ // The ring buffer read index.
+ //
+ volatile unsigned long ulReadIndex;
+
+ //
+ // The ring buffer.
+ //
+ unsigned char *pucBuf;
+
+}
+tRingBufObject;
+
+//*****************************************************************************
+//
+// API Function prototypes
+//
+//*****************************************************************************
+extern tBoolean RingBufFull(tRingBufObject *ptRingBuf);
+extern tBoolean RingBufEmpty(tRingBufObject *ptRingBuf);
+extern void RingBufFlush(tRingBufObject *ptRingBuf);
+extern unsigned long RingBufUsed(tRingBufObject *ptRingBuf);
+extern unsigned long RingBufFree(tRingBufObject *ptRingBuf);
+extern unsigned long RingBufContigUsed(tRingBufObject *ptRingBuf);
+extern unsigned long RingBufContigFree(tRingBufObject *ptRingBuf);
+extern unsigned long RingBufSize(tRingBufObject *ptRingBuf);
+extern unsigned char RingBufReadOne(tRingBufObject *ptRingBuf);
+extern void RingBufRead(tRingBufObject *ptRingBuf, unsigned char *pucData,
+ unsigned long ulLength);
+extern void RingBufWriteOne(tRingBufObject *ptRingBuf, unsigned char ucData);
+extern void RingBufWrite(tRingBufObject *ptRingBuf, unsigned char *pucData,
+ unsigned long ulLength);
+extern void RingBufAdvanceWrite(tRingBufObject *ptRingBuf,
+ unsigned long ulNumBytes);
+extern void RingBufAdvanceRead(tRingBufObject *ptRingBuf,
+ unsigned long ulNumBytes);
+extern void RingBufInit(tRingBufObject *ptRingBuf, unsigned char *pucBuf,
+ unsigned long ulSize);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __RINGBUF_H__
diff --git a/utils/scheduler.c b/utils/scheduler.c
new file mode 100644
index 0000000..82933e1
--- /dev/null
+++ b/utils/scheduler.c
@@ -0,0 +1,304 @@
+//****************************************************************************
+//
+// scheduler.c - A simple task scheduler
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//****************************************************************************
+#include "inc/hw_types.h"
+#include "inc/hw_ints.h"
+#include "driverlib/systick.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/debug.h"
+#include "utils/scheduler.h"
+
+//*****************************************************************************
+//
+//! \addtogroup scheduler_api
+//! @{
+//
+//*****************************************************************************
+
+static volatile unsigned long g_ulSchedulerTickCount;
+
+//****************************************************************************
+//
+//! Handles the SysTick interrupt on behalf of the scheduler module.
+//!
+//! Applications using the scheduler module must ensure that this function is
+//! hooked to the SysTick interrupt vector.
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+SchedulerSysTickIntHandler(void)
+{
+ g_ulSchedulerTickCount++;
+}
+
+//****************************************************************************
+//
+//! Initializes the task scheduler.
+//!
+//! \param ulTicksPerSecond sets the basic frequency of the SysTick interrupt
+//! used by the scheduler to determine when to run the various task functions.
+//!
+//! This function must be called during application startup to configure the
+//! SysTick timer. This is used by the scheduler module to determine when each
+//! of the functions provided in the g_psSchedulerTable array is called.
+//!
+//! The caller is responsible for ensuring that SchedulerSysTickIntHandler()
+//! has previously been installed in the SYSTICK vector in the vector table
+//! and must also ensure that interrupts are enabled at the CPU level.
+//!
+//! Note that this call does not start the scheduler calling the configured
+//! functions. All function calls are made in the context of later calls to
+//! SchedulerRun(). This call merely configures the SysTick interrupt that is
+//! used by the scheduler to determine what the current system time is.
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+SchedulerInit(unsigned long ulTicksPerSecond)
+{
+ ASSERT(ulTicksPerSecond);
+
+ //
+ // Configure SysTick for a periodic interrupt.
+ //
+ SysTickPeriodSet(SysCtlClockGet() / ulTicksPerSecond);
+ SysTickEnable();
+ SysTickIntEnable();
+}
+
+//****************************************************************************
+//
+//! Instructs the scheduler to update its task table and make calls to
+//! functions needing called.
+//!
+//! This function must be called periodically by the client to allow the
+//! scheduler to make calls to any configured task functions if it is their
+//! time to be called. The call must be made at least as frequently as the
+//! most frequent task configured in the g_psSchedulerTable array.
+//!
+//! Although the scheduler makes use of the SysTick interrupt, all calls to
+//! functions configured in \e g_psSchedulerTable are made in the context of
+//! SchedulerRun().
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+SchedulerRun(void)
+{
+ unsigned long ulLoop;
+ tSchedulerTask *psTask;
+
+ //
+ // Loop through each task in the task table.
+ //
+ for(ulLoop = 0; ulLoop < g_ulSchedulerNumTasks; ulLoop++)
+ {
+ //
+ // Get a pointer to the task information.
+ //
+ psTask = &g_psSchedulerTable[ulLoop];
+
+ //
+ // Is this task active and, if so, is it time to call it's function?
+ //
+ if(psTask->bActive && (SchedulerElapsedTicksGet(psTask->ulLastCall) >=
+ psTask->ulFrequencyTicks))
+ {
+ //
+ // Remember the timestamp at which we make the function call.
+ //
+ psTask->ulLastCall = g_ulSchedulerTickCount;
+
+ //
+ // Call the task function, passing the provided parameter.
+ //
+ psTask->pfnFunction(psTask->pvParam);
+ }
+ }
+}
+
+//****************************************************************************
+//
+//! Enables a task and allows the scheduler to call it periodically.
+//!
+//! \param ulIndex is the index of the task which is to be enabled in the
+//! global \e g_psSchedulerTable array.
+//! \param bRunNow is \b true if the task is to be run on the next call to
+//! SchedulerRun() or \b false if one whole period is to elapse before
+//! the task is run.
+//!
+//! This function marks one of the configured tasks as enabled and causes
+//! SchedulerRun() to call that task periodically. The caller may choose to
+//! have the enabled task run for the first time on the next call to
+//! SchedulerRun() or to wait one full task period before making the first
+//! call.
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+SchedulerTaskEnable(unsigned long ulIndex, tBoolean bRunNow)
+{
+ //
+ // Is the task index passed valid?
+ //
+ if(ulIndex < g_ulSchedulerNumTasks)
+ {
+ //
+ // Yes - mark the task as active.
+ //
+ g_psSchedulerTable[ulIndex].bActive = true;
+
+ //
+ // Set the last call time to ensure that the function is called either
+ // next time the scheduler is run or after the desired number of ticks
+ // depending upon the value of the bRunNow parameter.
+ //
+ if(bRunNow)
+ {
+ //
+ // Cause the task to run on the next call to SchedulerRun().
+ //
+ g_psSchedulerTable[ulIndex].ulLastCall = (g_ulSchedulerTickCount -
+ g_psSchedulerTable[ulIndex].ulFrequencyTicks);
+ }
+ else
+ {
+ //
+ // Cause the task to run after one full time period.
+ //
+ g_psSchedulerTable[ulIndex].ulLastCall = g_ulSchedulerTickCount;
+ }
+ }
+}
+
+//****************************************************************************
+//
+//! Disables a task and prevents the scheduler from calling it.
+//!
+//! \param ulIndex is the index of the task which is to be disabled in the
+//! global \e g_psSchedulerTable array.
+//!
+//! This function marks one of the configured tasks as inactive and prevents
+//! SchedulerRun() from calling it. The task may be reenabled by calling
+//! SchedulerTaskEnable().
+//!
+//! \return None.
+//
+//****************************************************************************
+void
+SchedulerTaskDisable(unsigned long ulIndex)
+{
+ //
+ // Is the task index passed valid?
+ //
+ if(ulIndex < g_ulSchedulerNumTasks)
+ {
+ //
+ // Yes - mark the task as inactive.
+ //
+ g_psSchedulerTable[ulIndex].bActive = false;
+ }
+}
+
+//****************************************************************************
+//
+//! Returns the current system time in ticks since power on.
+//!
+//! This function may be called by a client to retrieve the current system
+//! time. The value returned is a count of ticks elapsed since the system
+//! last booted.
+//!
+//! \return Tick count since last boot.
+//
+//****************************************************************************
+unsigned long
+SchedulerTickCountGet(void)
+{
+ return(g_ulSchedulerTickCount);
+}
+
+//****************************************************************************
+//
+//! Returns the number of ticks elapsed since the provided tick count.
+//!
+//! \param ulTickCount is the tick count from which to determine the elapsed
+//! time.
+//!
+//! This function may be called by a client to determine how much time has
+//! passed since a particular tick count provided in the \e ulTickCount
+//! parameter. This function takes into account wrapping of the global tick
+//! counter and assumes that the provided tick count always represents a time
+//! in the past. The returned value will, of course, be wrong if the tick
+//! counter has wrapped more than once since the passed \e ulTickCount. As a
+//! result, please do not use this function if you are dealing with timeouts
+//! of 497 days or longer (assuming you use a 10mS tick period).
+//!
+//! \return The number of ticks elapsed since the provided tick count.
+//
+//****************************************************************************
+unsigned long
+SchedulerElapsedTicksGet(unsigned long ulTickCount)
+{
+ //
+ // Determine the calculation based upon whether the global tick count has
+ // wrapped since the passed ulTickCount.
+ //
+ return(SchedulerElapsedTicksCalc(ulTickCount, g_ulSchedulerTickCount));
+}
+
+//****************************************************************************
+//
+//! Returns the number of ticks elapsed between two times.
+//!
+//! \param ulTickStart is the system tick count for the start of the period.
+//! \param ulTickEnd is the system tick count for the end of the period.
+//!
+//! This function may be called by a client to determine the number of ticks
+//! which have elapsed between provided starting and ending tick counts. The
+//! function takes into account wrapping cases where the end tick count is
+//! lower than the starting count assuming that the ending tick count always
+//! represents a later time than the starting count.
+//!
+//! \return The number of ticks elapsed between the provided start and end
+//! counts.
+//
+//****************************************************************************
+unsigned long
+SchedulerElapsedTicksCalc(unsigned long ulTickStart, unsigned long ulTickEnd)
+{
+ return((ulTickEnd > ulTickStart) ? (ulTickEnd - ulTickStart) :
+ ((0xFFFFFFFF - ulTickStart) + ulTickEnd + 1));
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/scheduler.h b/utils/scheduler.h
new file mode 100644
index 0000000..23b373c
--- /dev/null
+++ b/utils/scheduler.h
@@ -0,0 +1,140 @@
+//****************************************************************************
+//
+// scheduler.h - Public header for the simple timed function scheduler module.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//****************************************************************************
+#ifndef __SCHEDULER_H__
+#define __SCHEDULER_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup scheduler_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototype of a function that the scheduler can call periodically.
+//
+//*****************************************************************************
+typedef void (*tSchedulerFunction)(void *pvParam);
+
+//*****************************************************************************
+//
+//! The structure defining a function which the scheduler will call
+//! periodically.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! A pointer to the function which is to be called periodically by the
+ //! scheduler.
+ //
+ void (*pfnFunction)(void *);
+
+ //
+ //! The parameter which is to be passed to this function when it is called.
+ //
+ void *pvParam;
+
+ //
+ //! The frequency the function is to be called expressed in terms of system
+ //! ticks. If this value is 0, the function will be called on every call
+ //! to SchedulerRun.
+ //
+ unsigned long ulFrequencyTicks;
+
+ //
+ //! Tick count when this function was last called. This field is updated
+ //! by the scheduler.
+ //
+ unsigned long ulLastCall;
+
+ //
+ //! A flag indicating whether or not this task is active. If true, the
+ //! function will be called periodically. If false, the function is
+ //! disabled and will not be called.
+ //
+ tBoolean bActive;
+}
+tSchedulerTask;
+
+//*****************************************************************************
+//
+//! This global table must be populated by the client and contains information
+//! on each function that the scheduler is to call.
+//
+//*****************************************************************************
+extern tSchedulerTask g_psSchedulerTable[];
+
+//*****************************************************************************
+//
+//! This global variable must be exported by the client. It must contain the
+//! number of entries in the g_psSchedulerTable array.
+//
+//*****************************************************************************
+extern unsigned long g_ulSchedulerNumTasks;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public function prototypes
+//
+//*****************************************************************************
+extern void SchedulerSysTickIntHandler(void);
+extern void SchedulerInit(unsigned long ulTicksPerSecond);
+extern void SchedulerRun(void);
+extern void SchedulerTaskEnable(unsigned long ulIndex, tBoolean bRunNow);
+extern void SchedulerTaskDisable(unsigned long ulIndex);
+extern unsigned long SchedulerTickCountGet(void);
+extern unsigned long SchedulerElapsedTicksGet(unsigned long ulTickCount);
+extern unsigned long SchedulerElapsedTicksCalc(unsigned long ulTickStart,
+ unsigned long ulTickEnd);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ SCHEDULER_H_
diff --git a/utils/sine.c b/utils/sine.c
new file mode 100644
index 0000000..7b971ca
--- /dev/null
+++ b/utils/sine.c
@@ -0,0 +1,125 @@
+//*****************************************************************************
+//
+// sine.c - Fixed point sine trigonometric function.
+//
+// Copyright (c) 2006-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#include "utils/sine.h"
+
+//*****************************************************************************
+//
+//! \addtogroup sine_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// A table of the value of the sine function for the first ninety degrees with
+// 129 entries (that is, [0] = 0 degrees, [128] = 90 degrees). Each entry is
+// in 0.16 fixed point notation.
+//
+//*****************************************************************************
+static const unsigned short g_pusFixedSineTable[] =
+{
+ 0x0000, 0x0324, 0x0648, 0x096C, 0x0C8F, 0x0FB2, 0x12D5, 0x15F6, 0x1917,
+ 0x1C37, 0x1F56, 0x2273, 0x2590, 0x28AA, 0x2BC4, 0x2EDB, 0x31F1, 0x3505,
+ 0x3817, 0x3B26, 0x3E33, 0x413E, 0x4447, 0x474D, 0x4A50, 0x4D50, 0x504D,
+ 0x5347, 0x563E, 0x5931, 0x5C22, 0x5F0E, 0x61F7, 0x64DC, 0x67BD, 0x6A9B,
+ 0x6D74, 0x7049, 0x7319, 0x75E5, 0x78AD, 0x7B70, 0x7E2E, 0x80E7, 0x839C,
+ 0x864B, 0x88F5, 0x8B9A, 0x8E39, 0x90D3, 0x9368, 0x95F6, 0x987F, 0x9B02,
+ 0x9D7F, 0x9FF6, 0xA267, 0xA4D2, 0xA736, 0xA994, 0xABEB, 0xAE3B, 0xB085,
+ 0xB2C8, 0xB504, 0xB73A, 0xB968, 0xBB8F, 0xBDAE, 0xBFC7, 0xC1D8, 0xC3E2,
+ 0xC5E4, 0xC7DE, 0xC9D1, 0xCBBB, 0xCD9F, 0xCF7A, 0xD14D, 0xD318, 0xD4DB,
+ 0xD695, 0xD848, 0xD9F2, 0xDB94, 0xDD2D, 0xDEBE, 0xE046, 0xE1C5, 0xE33C,
+ 0xE4AA, 0xE60F, 0xE76B, 0xE8BF, 0xEA09, 0xEB4B, 0xEC83, 0xEDB2, 0xEED8,
+ 0xEFF5, 0xF109, 0xF213, 0xF314, 0xF40B, 0xF4FA, 0xF5DE, 0xF6BA, 0xF78B,
+ 0xF853, 0xF912, 0xF9C7, 0xFA73, 0xFB14, 0xFBAC, 0xFC3B, 0xFCBF, 0xFD3A,
+ 0xFDAB, 0xFE13, 0xFE70, 0xFEC4, 0xFF0E, 0xFF4E, 0xFF84, 0xFFB1, 0xFFD3,
+ 0xFFEC, 0xFFFB, 0xFFFF
+};
+
+//*****************************************************************************
+//
+//! Computes an approximation of the sine of the input angle.
+//!
+//! \param ulAngle is an angle expressed as a 0.32 fixed-point value that is
+//! the percentage of the way around a circle.
+//!
+//! This function computes the sine for the given input angle. The angle is
+//! specified in 0.32 fixed point format, and is therefore always between 0 and
+//! 360 degrees, inclusive of 0 and exclusive of 360.
+//!
+//! \return Returns the sine of the angle, in 16.16 fixed point format.
+//
+//*****************************************************************************
+long
+sine(unsigned long ulAngle)
+{
+ unsigned long ulIdx;
+
+ //
+ // Add 0.5 to the angle. Since only the upper 9 bits are used to compute
+ // the sine value, adding one to the tenth bit is 0.5 from the point of
+ // view of the sine table.
+ //
+ ulAngle += 0x00400000;
+
+ //
+ // Get the index into the sine table from bits 30:23.
+ //
+ ulIdx = (ulAngle >> 23) & 255;
+
+ //
+ // If bit 30 is set, the angle is between 90 and 180 or 270 and 360. In
+ // these cases, the sine value is decreasing from one instead of increasing
+ // from zero. The indexing into the table needs to be reversed.
+ //
+ if(ulAngle & 0x40000000)
+ {
+ ulIdx = 256 - ulIdx;
+ }
+
+ //
+ // Get the value of the sine.
+ //
+ ulIdx = g_pusFixedSineTable[ulIdx];
+
+ //
+ // If bit 31 is set, the angle is between 180 and 360. In this case, the
+ // sine value is negative; otherwise it is positive.
+ //
+ if(ulAngle & 0x80000000)
+ {
+ return(0 - ulIdx);
+ }
+ else
+ {
+ return(ulIdx);
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/sine.h b/utils/sine.h
new file mode 100644
index 0000000..9c91255
--- /dev/null
+++ b/utils/sine.h
@@ -0,0 +1,85 @@
+//*****************************************************************************
+//
+// sine.h - Prototypes for the fixed point sine trigonometric function.
+//
+// Copyright (c) 2006-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SINE_H__
+#define __SINE_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup sine_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! Computes an approximation of the cosine of the input angle.
+//!
+//! \param ulAngle is an angle expressed as a 0.32 fixed-point value that is
+//! the percentage of the way around a circle.
+//!
+//! This function computes the cosine for the given input angle. The angle is
+//! specified in 0.32 fixed point format, and is therefore always between 0 and
+//! 360 degrees, inclusive of 0 and exclusive of 360.
+//!
+//! \return Returns the cosine of the angle, in 16.16 fixed point format.
+//
+//*****************************************************************************
+#define cosine(ulAngle) sine((ulAngle + 0x40000000))
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototype for the fixed point sine function.
+//
+//*****************************************************************************
+extern long sine(unsigned long ulAngle);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SINE_H__
diff --git a/utils/softi2c.c b/utils/softi2c.c
new file mode 100644
index 0000000..9828534
--- /dev/null
+++ b/utils/softi2c.c
@@ -0,0 +1,1316 @@
+//*****************************************************************************
+//
+// softi2c.c - Driver for the SoftI2C.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softi2c_api
+//! @{
+//
+//*****************************************************************************
+
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/gpio.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "utils/softi2c.h"
+
+//*****************************************************************************
+//
+// The states in the SoftI2C state machine. The code depends upon the fact
+// that the value of STATE_X1 is exactly one greater than STATE_X0 (for any
+// value of X and for any following digit)...however there is no dependence on
+// the values of STATE_Xn and STATE_Yn.
+//
+//*****************************************************************************
+#define SOFTI2C_STATE_IDLE 0
+#define SOFTI2C_STATE_START0 1
+#define SOFTI2C_STATE_START1 2
+#define SOFTI2C_STATE_START2 3
+#define SOFTI2C_STATE_START3 4
+#define SOFTI2C_STATE_START4 5
+#define SOFTI2C_STATE_START5 6
+#define SOFTI2C_STATE_START6 7
+#define SOFTI2C_STATE_START7 8
+#define SOFTI2C_STATE_ADDR0 9
+#define SOFTI2C_STATE_ADDR1 10
+#define SOFTI2C_STATE_ADDR2 11
+#define SOFTI2C_STATE_ADDR3 12
+#define SOFTI2C_STATE_SEND0 13
+#define SOFTI2C_STATE_SEND1 14
+#define SOFTI2C_STATE_SEND2 15
+#define SOFTI2C_STATE_SEND3 16
+#define SOFTI2C_STATE_RECV0 17
+#define SOFTI2C_STATE_RECV1 18
+#define SOFTI2C_STATE_RECV2 19
+#define SOFTI2C_STATE_RECV3 20
+#define SOFTI2C_STATE_STOP0 21
+#define SOFTI2C_STATE_STOP1 22
+#define SOFTI2C_STATE_STOP2 23
+#define SOFTI2C_STATE_STOP3 24
+#define SOFTI2C_STATE_STOP4 25
+
+//*****************************************************************************
+//
+// The flags in the SoftI2C ucFlags structure member. The first four flags,
+// RUN, START, STOP, and ACK, must match with the definitions of the
+// SOFTI2C_CMD_* commands in softi2c.h.
+//
+//*****************************************************************************
+#define SOFTI2C_FLAG_RUN 0
+#define SOFTI2C_FLAG_START 1
+#define SOFTI2C_FLAG_STOP 2
+#define SOFTI2C_FLAG_ACK 3
+#define SOFTI2C_FLAG_ADDR_ACK 5
+#define SOFTI2C_FLAG_DATA_ACK 6
+#define SOFTI2C_FLAG_RECEIVE 7
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftI2C module.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftI2C
+//! module. The transmission and reception of data over the SoftI2C link is
+//! performed by the state machine in this function.
+//!
+//! This function must be called at four times the desired SoftI2C clock rate.
+//! For example, to run the SoftI2C clock at 10 KHz, this function must be
+//! called at a 40 KHz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CTimerTick(tSoftI2C *pI2C)
+{
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(pI2C->ucState)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTI2C_STATE_IDLE:
+ {
+ //
+ // See if the START flag is set, indicating that a start condition
+ // should be generated.
+ //
+ if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_START) == 1)
+ {
+ //
+ // Based on the current state of the SCL and SDA pins, pick the
+ // appropriate place within the state machine to begin the
+ // start/repeated-start signalling.
+ //
+ if(HWREG(pI2C->ulSCLGPIO) != 0)
+ {
+ pI2C->ucState = SOFTI2C_STATE_START4;
+ }
+ else if(HWREG(pI2C->ulSDAGPIO) == 0)
+ {
+ pI2C->ucState = SOFTI2C_STATE_START0;
+ }
+ else
+ {
+ pI2C->ucState = SOFTI2C_STATE_START2;
+ }
+ }
+
+ //
+ // Otherwise, see if the RUN flag is set, indicating that a data
+ // byte should be transferred.
+ //
+ else if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RUN) == 1)
+ {
+ //
+ // Start the transfer from the first bit.
+ //
+ pI2C->ucCurrentBit = 0;
+
+ //
+ // See if a byte should be sent or received.
+ //
+ if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RECEIVE) == 0)
+ {
+ //
+ // A byte should be sent.
+ //
+ pI2C->ucState = SOFTI2C_STATE_SEND0;
+ }
+ else
+ {
+ //
+ // A byte should be received. Clear out the receive data
+ // buffer in preparation for receiving the new byte.
+ //
+ pI2C->ucData = 0;
+ pI2C->ucState = SOFTI2C_STATE_RECV0;
+ }
+ }
+
+ //
+ // Otherwise, see if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ else if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Generate a stop condition.
+ //
+ pI2C->ucState = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // See if the SoftI2C state machine has left the idle state.
+ //
+ if(pI2C->ucState != SOFTI2C_STATE_IDLE)
+ {
+ //
+ // The address and data ACK error flags should be cleared; they
+ // will be set if appropriate while the current command is
+ // being executed.
+ //
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_ADDR_ACK) = 0;
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_DATA_ACK) = 0;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The beginning of the start condition sequence when SDA and SCL are
+ // low. SDA must be driven high prior to driving SCL high so that a
+ // repeated-start is generated, instead of a stop then start.
+ //
+ case SOFTI2C_STATE_START0:
+ {
+ //
+ // Set SDA high.
+ //
+ HWREG(pI2C->ulSDAGPIO) = 255;
+
+ //
+ // Advance to the next state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_START1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // Each of these states exists only to provide some timing delay in
+ // order to conform with the signalling requirements of I2C. This
+ // depends upon STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START1:
+ case SOFTI2C_STATE_START3:
+ case SOFTI2C_STATE_START5:
+ case SOFTI2C_STATE_STOP1:
+ case SOFTI2C_STATE_STOP3:
+ {
+ //
+ // Advance to the next state.
+ //
+ pI2C->ucState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, SCL must be driven high. This depends upon
+ // STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START2:
+ case SOFTI2C_STATE_ADDR1:
+ case SOFTI2C_STATE_SEND1:
+ case SOFTI2C_STATE_RECV1:
+ case SOFTI2C_STATE_STOP2:
+ {
+ //
+ // Set SCL high.
+ //
+ HWREG(pI2C->ulSCLGPIO) = 255;
+
+ //
+ // Advance to the next state.
+ //
+ pI2C->ucState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, SDA must be driven low. This depends upon
+ // STATE_Xn and STATE_X(n+1) being consecutively numbered.
+ //
+ case SOFTI2C_STATE_START4:
+ case SOFTI2C_STATE_STOP0:
+ {
+ //
+ // Set SDA low.
+ //
+ HWREG(pI2C->ulSDAGPIO) = 0;
+
+ //
+ // Advance to the next state.
+ //
+ pI2C->ucState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low.
+ //
+ case SOFTI2C_STATE_START6:
+ {
+ //
+ // Set SCL low.
+ //
+ HWREG(pI2C->ulSCLGPIO) = 0;
+
+ //
+ // Advance to the next state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_START7;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the start condition has been generated.
+ //
+ case SOFTI2C_STATE_START7:
+ {
+ //
+ // Start with the first bit of the address.
+ //
+ pI2C->ucCurrentBit = 0;
+
+ //
+ // Advance to the address output state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_ADDR0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the slave address must be sent.
+ //
+ case SOFTI2C_STATE_ADDR0:
+ {
+ //
+ // See if this is one of the first seven bits of the address phase.
+ //
+ if(pI2C->ucCurrentBit < 7)
+ {
+ //
+ // Write the next bit of the slave address to SDA.
+ //
+ HWREG(pI2C->ulSDAGPIO) = ((pI2C->ucSlaveAddr &
+ (1 << (6 - pI2C->ucCurrentBit))) ?
+ 255 : 0);
+ }
+
+ //
+ // Otherwise, see if this is the eight bit of the address phase
+ // (which is the read/not write bit).
+ //
+ else if(pI2C->ucCurrentBit == 7)
+ {
+ //
+ // Write the read/not write bit to SDA.
+ //
+ HWREG(pI2C->ulSDAGPIO) =
+ (HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RECEIVE) ?
+ 255 : 0);
+ }
+
+ //
+ // Otherwise, this is the ninth bit of the address phase (in other
+ // words, the ACK bit).
+ //
+ else
+ {
+ //
+ // Change the SDA GPIO into an input so that the ACK or NAK
+ // provided by the slave can be read.
+ //
+ MAP_GPIODirModeSet(pI2C->ulSDAGPIO & 0xfffff000,
+ (pI2C->ulSDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_ADDR1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, wait until SCL has gone high (it has been
+ // released by the SoftI2C master, but may be held low by the slave).
+ // This depends upon STATE_Xn and STATE_X(n+1) being consecutively
+ // numbered.
+ //
+ case SOFTI2C_STATE_ADDR2:
+ case SOFTI2C_STATE_SEND2:
+ case SOFTI2C_STATE_RECV2:
+ {
+ //
+ // See if SCL has gone high.
+ //
+ if(HWREG(pI2C->ulSCLGPIO) != 0)
+ {
+ //
+ // Advance to the next state now that SCL has gone high.
+ //
+ pI2C->ucState++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. If on the ninth bit of the
+ // address transfer, the ACK/NAK status is read from the slave.
+ //
+ case SOFTI2C_STATE_ADDR3:
+ {
+ //
+ // See if this is the ninth bit of the address phase (in other
+ // words, the ACK bit).
+ //
+ if(pI2C->ucCurrentBit == 8)
+ {
+ //
+ // See if the SDA line is high.
+ //
+ if(HWREG(pI2C->ulSDAGPIO) != 0)
+ {
+ //
+ // Since the SDA line is high, the address byte has not
+ // been ACKed by any slave.
+ //
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_ADDR_ACK) = 1;
+ }
+
+ //
+ // Change the SDA GPIO back into an output.
+ //
+ MAP_GPIODirModeSet(pI2C->ulSDAGPIO & 0xfffff000,
+ (pI2C->ulSDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // The start phase (start or repeated-start, plus the address
+ // byte) have completed, so clear the START flag.
+ //
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_START) = 0;
+
+ //
+ // See if the RUN flag is set, indicating that a data byte
+ // should be transferred as well.
+ //
+ if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RUN) == 1)
+ {
+ //
+ // Reset the current bit to zero for the start of the data
+ // phase.
+ //
+ pI2C->ucCurrentBit = 0;
+
+ //
+ // See if the data byte is being sent or received.
+ //
+ if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RECEIVE) == 0)
+ {
+ //
+ // The data byte is being sent, so advance to the data
+ // send state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_SEND0;
+ }
+ else
+ {
+ //
+ // The data byte is being received, so clear the data
+ // buffer and advance to the data receive state.
+ //
+ pI2C->ucData = 0;
+ pI2C->ucState = SOFTI2C_STATE_RECV0;
+ }
+ }
+
+ //
+ // Otherwise, see if the STOP flag is set, indicating that a
+ // stop condition should be generated.
+ //
+ else if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ pI2C->ucIntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the address should be transferred.
+ //
+ else
+ {
+ //
+ // Increment the bit count.
+ //
+ pI2C->ucCurrentBit++;
+
+ //
+ // Advance to the address tranfer state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_ADDR0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(pI2C->ulSCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the data byte must be sent.
+ //
+ case SOFTI2C_STATE_SEND0:
+ {
+ //
+ // See if this is one of the first eight bits of the data phase.
+ //
+ if(pI2C->ucCurrentBit < 8)
+ {
+ //
+ // Write the next bit of the data byte to SDA.
+ //
+ HWREG(pI2C->ulSDAGPIO) = ((pI2C->ucData &
+ (1 << (7 - pI2C->ucCurrentBit))) ?
+ 255 : 0);
+ }
+
+ //
+ // Otherwise, this is the ninth bit of the data phase (in other
+ // words, the ACK bit).
+ //
+ else
+ {
+ //
+ // Change the SDA GPIO into an input so that the ACK or NAK
+ // provided by the slave can be read.
+ //
+ MAP_GPIODirModeSet(pI2C->ulSDAGPIO & 0xfffff000,
+ (pI2C->ulSDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_SEND1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. If on the ninth bit of the
+ // data transfer, the ACK/NAK status is read from the slave.
+ //
+ case SOFTI2C_STATE_SEND3:
+ {
+ //
+ // See if this is the ninth bit of the data phase (in other words,
+ // the ACK bit).
+ //
+ if(pI2C->ucCurrentBit == 8)
+ {
+ //
+ // See if the SDA line is high.
+ //
+ if(HWREG(pI2C->ulSDAGPIO) != 0)
+ {
+ //
+ // Since the SDA line is high, the data byte has not been
+ // ACKed by the slave.
+ //
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_DATA_ACK) = 1;
+ }
+
+ //
+ // Change the SDA GPIO back into an output.
+ //
+ MAP_GPIODirModeSet(pI2C->ulSDAGPIO & 0xfffff000,
+ (pI2C->ulSDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // The data phase has completed, so clear the RUN flag.
+ //
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RUN) = 0;
+
+ //
+ // See if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ pI2C->ucIntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the data should be transferred.
+ //
+ else
+ {
+ //
+ // Increment the bit count.
+ //
+ pI2C->ucCurrentBit++;
+
+ //
+ // Advance to the data transmit state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_SEND0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(pI2C->ulSCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, the next bit of the data byte must be received.
+ //
+ case SOFTI2C_STATE_RECV0:
+ {
+ //
+ // See if this is the first bit of the data phase.
+ //
+ if(pI2C->ucCurrentBit == 0)
+ {
+ //
+ // Change the SDA GPIO into an input so that the data provided
+ // by the slave can be read.
+ //
+ MAP_GPIODirModeSet(pI2C->ulSDAGPIO & 0xfffff000,
+ (pI2C->ulSDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_IN);
+ }
+
+ //
+ // Otherwise, see if this is the ninth bit of the data phase (in
+ // other words, the ACK bit).
+ //
+ else if(pI2C->ucCurrentBit == 8)
+ {
+ //
+ // Change the SDA GPIO into an output so that the ACK bit can
+ // be driven to the slave.
+ //
+ MAP_GPIODirModeSet(pI2C->ulSDAGPIO & 0xfffff000,
+ (pI2C->ulSDAGPIO & 0x00000fff) >> 2,
+ GPIO_DIR_MODE_OUT);
+
+ //
+ // See if this byte should be ACKed or NAKed.
+ //
+ if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_ACK) == 1)
+ {
+ //
+ // Drive SDA low to ACK the data byte.
+ //
+ HWREG(pI2C->ulSDAGPIO) = 0;
+ }
+ else
+ {
+ //
+ // Allow SDA to get pulled high to NAK the data byte.
+ //
+ HWREG(pI2C->ulSDAGPIO) = 255;
+ }
+ }
+
+ //
+ // Advance to the next state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_RECV1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SCL must be driven low. For the first eight bits of
+ // the data transfer, the data bits are read from the slave.
+ //
+ case SOFTI2C_STATE_RECV3:
+ {
+ //
+ // See if this is the ninth bit of the data phase (in other words,
+ // the ACK bit).
+ //
+ if(pI2C->ucCurrentBit == 8)
+ {
+ //
+ // The data phase has completed, so clear the RUN flag.
+ //
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RUN) = 0;
+
+ //
+ // See if the STOP flag is set, indicating that a stop
+ // condition should be generated.
+ //
+ if(HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_STOP) == 1)
+ {
+ //
+ // Advance to the stop state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_STOP0;
+ }
+
+ //
+ // Otherwise, go to the idle state.
+ //
+ else
+ {
+ //
+ // Since the requested operations have completed, set the
+ // SoftI2C ``interrupt''.
+ //
+ pI2C->ucIntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_IDLE;
+ }
+ }
+
+ //
+ // Otherwise, the next bit of the data should be transferred.
+ //
+ else
+ {
+ //
+ // Read the next bit of data from the SDA line.
+ //
+ pI2C->ucData |= (HWREG(pI2C->ulSDAGPIO) ?
+ (1 << (7 - pI2C->ucCurrentBit)) : 0);
+
+ //
+ // Increment the bit count.
+ //
+ pI2C->ucCurrentBit++;
+
+ //
+ // Advance to the data receive state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_RECV0;
+ }
+
+ //
+ // Set SCL low.
+ //
+ HWREG(pI2C->ulSCLGPIO) = 0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In this state, SDA must be driven high to create the stop condition.
+ //
+ case SOFTI2C_STATE_STOP4:
+ {
+ //
+ // Set SDA high to create the stop condition.
+ //
+ HWREG(pI2C->ulSDAGPIO) = 255;
+
+ //
+ // The stop condition has been generated, so clear the STOP flag.
+ //
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_STOP) = 0;
+
+ //
+ // Since the requested operations have completed, set the SoftI2C
+ // ``interrupt''.
+ //
+ pI2C->ucIntStatus = 1;
+
+ //
+ // Advance to the idle state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_IDLE;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the I2C peripheral.
+ //
+ while(((pI2C->ucIntStatus & pI2C->ucIntMask) != 0) &&
+ (pI2C->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ pI2C->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the SoftI2C module.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//!
+//! This function initializes operation of the SoftI2C module. After
+//! successful initialization of the SoftI2C module, the software I2C bus is in
+//! the idle state.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CInit(tSoftI2C *pI2C)
+{
+ //
+ // Configure the SCL pin.
+ //
+ MAP_GPIODirModeSet(pI2C->ulSCLGPIO & 0xfffff000,
+ (pI2C->ulSCLGPIO & 0x00000fff) >> 2, GPIO_DIR_MODE_OUT);
+ MAP_GPIOPadConfigSet(pI2C->ulSCLGPIO & 0xfffff000,
+ (pI2C->ulSCLGPIO & 0x00000fff) >> 2,
+ GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_OD);
+
+ //
+ // Set the SCL pin high.
+ //
+ HWREG(pI2C->ulSCLGPIO) = 255;
+
+ //
+ // Configure the SDA pin.
+ //
+ MAP_GPIODirModeSet(pI2C->ulSDAGPIO & 0xfffff000,
+ (pI2C->ulSDAGPIO & 0x00000fff) >> 2, GPIO_DIR_MODE_OUT);
+ MAP_GPIOPadConfigSet(pI2C->ulSDAGPIO & 0xfffff000,
+ (pI2C->ulSDAGPIO & 0x00000fff) >> 2,
+ GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_OD);
+
+ //
+ // Set the SDA pin high.
+ //
+ HWREG(pI2C->ulSDAGPIO) = 255;
+
+ //
+ // The ``interrupt'' is not asserted at the start.
+ //
+ pI2C->ucIntStatus = 0;
+
+ //
+ // There are no flags at the start.
+ //
+ pI2C->ucFlags = 0;
+
+ //
+ // Start the SoftI2C state machine in the idle state.
+ //
+ pI2C->ucState = SOFTI2C_STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftI2C module.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftI2C module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CCallbackSet(tSoftI2C *pI2C, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ pI2C->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftI2C SCL signal.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//! \param ulBase is the base address of the GPIO module.
+//! \param ucPin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftI2C SCL signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSCLGPIOSet(tSoftI2C *pI2C, unsigned long ulBase, unsigned char ucPin)
+{
+ //
+ // Save the base address and pin for the SCL signal.
+ //
+ pI2C->ulSCLGPIO = ulBase + (ucPin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftI2C SDA signal.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//! \param ulBase is the base address of the GPIO module.
+//! \param ucPin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftI2C SDA signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSDAGPIOSet(tSoftI2C *pI2C, unsigned long ulBase, unsigned char ucPin)
+{
+ //
+ // Save the base address and pin for the SDA signal.
+ //
+ pI2C->ulSDAGPIO = ulBase + (ucPin << 2);
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftI2C ``interrupt''.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//!
+//! Enables the SoftI2C ``interrupt'' source.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntEnable(tSoftI2C *pI2C)
+{
+ //
+ // Enable the master interrupt.
+ //
+ pI2C->ucIntMask = 1;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftI2C ``interrupt''.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//!
+//! Disables the SoftI2C ``interrupt'' source.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntDisable(tSoftI2C *pI2C)
+{
+ //
+ // Disable the master interrupt.
+ //
+ pI2C->ucIntMask = 0;
+}
+
+//*****************************************************************************
+//
+//! Gets the current SoftI2C ``interrupt'' status.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is requested and
+//! \b true if the masked ``interrupt'' status is requested.
+//!
+//! This returns the ``interrupt'' status for the SoftI2C module. Either the
+//! raw ``interrupt'' status or the status of ``interrupts'' that are allowed
+//! to reflect to the processor can be returned.
+//!
+//! \return The current interrupt status, returned as \b true if active
+//! or \b false if not active.
+//
+//*****************************************************************************
+tBoolean
+SoftI2CIntStatus(tSoftI2C *pI2C, tBoolean bMasked)
+{
+ //
+ // Return either the interrupt status or the raw interrupt status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return((pI2C->ucIntStatus & pI2C->ucIntMask) ? true : false);
+ }
+ else
+ {
+ return(pI2C->ucIntStatus ? true : false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears the SoftI2C ``interrupt''.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//!
+//! The SoftI2C ``interrupt'' source is cleared, so that it no longer asserts.
+//! This function must be called in the ``interrupt'' handler to keep it from
+//! being called again immediately on exit.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CIntClear(tSoftI2C *pI2C)
+{
+ //
+ // Clear the SoftI2C interrupt source.
+ //
+ pI2C->ucIntStatus = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the address that the SoftI2C module places on the bus.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//! \param ucSlaveAddr 7-bit slave address
+//! \param bReceive flag indicating the type of communication with the slave.
+//!
+//! This function sets the address that the SoftI2C module places on the bus
+//! when initiating a transaction. When the \e bReceive parameter is set to
+//! \b true, the address indicates that the SoftI2C moudle is initiating a read
+//! from the slave; otherwise the address indicates that the SoftI2C module is
+//! initiating a write to the slave.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CSlaveAddrSet(tSoftI2C *pI2C, unsigned char ucSlaveAddr,
+ tBoolean bReceive)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(!(ucSlaveAddr & 0x80));
+
+ //
+ // Set the address of the slave with which the master will communicate.
+ //
+ pI2C->ucSlaveAddr = ucSlaveAddr;
+
+ //
+ // Set a flag to indicate if this is a transmit or receive.
+ //
+ if(bReceive)
+ {
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RECEIVE) = 1;
+ }
+ else
+ {
+ HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_RECEIVE) = 0;
+ }
+}
+
+//*****************************************************************************
+//
+//! Indicates whether or not the SoftI2C module is busy.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//!
+//! This function returns an indication of whether or not the SoftI2C module is
+//! busy transmitting or receiving data.
+//!
+//! \return Returns \b true if the SoftI2C module is busy; otherwise, returns
+//! \b false.
+//
+//*****************************************************************************
+tBoolean
+SoftI2CBusy(tSoftI2C *pI2C)
+{
+ //
+ // Return the busy status.
+ //
+ if(pI2C->ucState != SOFTI2C_STATE_IDLE)
+ {
+ return(true);
+ }
+ else
+ {
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Controls the state of the SoftI2C module.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//! \param ulCmd command to be issued to the SoftI2C module.
+//!
+//! This function is used to control the state of the SoftI2C module send and
+//! receive operations. The \e ucCmd parameter can be one of the following
+//! values:
+//!
+//! - \b SOFTI2C_CMD_SINGLE_SEND
+//! - \b SOFTI2C_CMD_SINGLE_RECEIVE
+//! - \b SOFTI2C_CMD_BURST_SEND_START
+//! - \b SOFTI2C_CMD_BURST_SEND_CONT
+//! - \b SOFTI2C_CMD_BURST_SEND_FINISH
+//! - \b SOFTI2C_CMD_BURST_SEND_ERROR_STOP
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_START
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_CONT
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_FINISH
+//! - \b SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CControl(tSoftI2C *pI2C, unsigned long ulCmd)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ulCmd == SOFTI2C_CMD_SINGLE_SEND) ||
+ (ulCmd == SOFTI2C_CMD_SINGLE_RECEIVE) ||
+ (ulCmd == SOFTI2C_CMD_BURST_SEND_START) ||
+ (ulCmd == SOFTI2C_CMD_BURST_SEND_CONT) ||
+ (ulCmd == SOFTI2C_CMD_BURST_SEND_FINISH) ||
+ (ulCmd == SOFTI2C_CMD_BURST_SEND_ERROR_STOP) ||
+ (ulCmd == SOFTI2C_CMD_BURST_RECEIVE_START) ||
+ (ulCmd == SOFTI2C_CMD_BURST_RECEIVE_CONT) ||
+ (ulCmd == SOFTI2C_CMD_BURST_RECEIVE_FINISH) ||
+ (ulCmd == SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP));
+
+ //
+ // Send the command.
+ //
+ pI2C->ucFlags = (pI2C->ucFlags & 0xf0) | ulCmd;
+}
+
+//*****************************************************************************
+//
+//! Gets the error status of the SoftI2C module.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//!
+//! This function is used to obtain the error status of the SoftI2C module send
+//! and receive operations.
+//!
+//! \return Returns the error status, as one of \b SOFTI2C_ERR_NONE,
+//! \b SOFTI2C_ERR_ADDR_ACK, or \b SOFTI2C_ERR_DATA_ACK.
+//
+//*****************************************************************************
+unsigned long
+SoftI2CErr(tSoftI2C *pI2C)
+{
+ //
+ // If the SoftI2C is busy, there is no error to report.
+ //
+ if(pI2C->ucState != SOFTI2C_STATE_IDLE)
+ {
+ return(SOFTI2C_ERR_NONE);
+ }
+
+ //
+ // Return any errors that may have occurred.
+ //
+ return((HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_ADDR_ACK) ?
+ SOFTI2C_ERR_ADDR_ACK : 0) |
+ (HWREGBITB(&(pI2C->ucFlags), SOFTI2C_FLAG_DATA_ACK) ?
+ SOFTI2C_ERR_DATA_ACK : 0));
+}
+
+//*****************************************************************************
+//
+//! Transmits a byte from the SoftI2C module.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//! \param ucData data to be transmitted from the SoftI2C module.
+//!
+//! This function places the supplied data into SoftI2C module in preparation
+//! for being transmitted via an appropriate call to SoftI2CControl().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftI2CDataPut(tSoftI2C *pI2C, unsigned char ucData)
+{
+ //
+ // Write the byte.
+ //
+ pI2C->ucData = ucData;
+}
+
+//*****************************************************************************
+//
+//! Receives a byte that has been sent to the SoftI2C module.
+//!
+//! \param pI2C specifies the SoftI2C data structure.
+//!
+//! This function reads a byte of data from the SoftI2C module that was
+//! received as a result of an appropriate call to SoftI2CControl().
+//!
+//! \return Returns the byte received by the SoftI2C module, cast as an
+//! unsigned long.
+//
+//*****************************************************************************
+unsigned long
+SoftI2CDataGet(tSoftI2C *pI2C)
+{
+ //
+ // Read a byte.
+ //
+ return(pI2C->ucData);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softi2c.h b/utils/softi2c.h
new file mode 100644
index 0000000..6f662bf
--- /dev/null
+++ b/utils/softi2c.h
@@ -0,0 +1,195 @@
+//*****************************************************************************
+//
+// softi2c.h - Defines and macros for the SoftI2C.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SOFTI2C_H__
+#define __SOFTI2C_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softi2c_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftI2C module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware I2C implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftI2CCallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the SCL signal. This member
+ //! can be set via a direct structure access or using the SoftI2CSCLGPIOSet
+ //! function.
+ //
+ unsigned long ulSCLGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the SDA signal. This member
+ //! can be set via a direct structure access or using the SoftI2CSDAGPIOSet
+ //! function.
+ ///
+ unsigned long ulSDAGPIO;
+
+ //
+ //! The flags that control the operation of the SoftI2C module. This
+ //! member should not be accessed or modified by the application.
+ //
+ unsigned char ucFlags;
+
+ //
+ //! The slave address that is currently being accessed. This member should
+ //! not be accessed or modified by the application.
+ //
+ unsigned char ucSlaveAddr;
+
+ //
+ //! The data that is currently being transmitted or received. This member
+ //! should not be accessed or modified by the application.
+ //
+ unsigned char ucData;
+
+ //
+ //! The current state of the SoftI2C state machine. This member should not
+ //! be accessed or modified by the application.
+ //
+ unsigned char ucState;
+
+ //
+ //! The number of bits that have been transmitted and received in the
+ //! current frame. This member should not be accessed or modified by the
+ //! application.
+ //
+ unsigned char ucCurrentBit;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ unsigned char ucIntMask;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ unsigned char ucIntStatus;
+}
+tSoftI2C;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// SoftI2C commands.
+//
+//*****************************************************************************
+#define SOFTI2C_CMD_SINGLE_SEND 0x00000007
+#define SOFTI2C_CMD_SINGLE_RECEIVE \
+ 0x00000007
+#define SOFTI2C_CMD_BURST_SEND_START \
+ 0x00000003
+#define SOFTI2C_CMD_BURST_SEND_CONT \
+ 0x00000001
+#define SOFTI2C_CMD_BURST_SEND_FINISH \
+ 0x00000005
+#define SOFTI2C_CMD_BURST_SEND_ERROR_STOP \
+ 0x00000004
+#define SOFTI2C_CMD_BURST_RECEIVE_START \
+ 0x0000000b
+#define SOFTI2C_CMD_BURST_RECEIVE_CONT \
+ 0x00000009
+#define SOFTI2C_CMD_BURST_RECEIVE_FINISH \
+ 0x00000005
+#define SOFTI2C_CMD_BURST_RECEIVE_ERROR_STOP \
+ 0x00000004
+
+//*****************************************************************************
+//
+// SoftI2C error status.
+//
+//*****************************************************************************
+#define SOFTI2C_ERR_NONE 0x00000000
+#define SOFTI2C_ERR_ADDR_ACK 0x00000004
+#define SOFTI2C_ERR_DATA_ACK 0x00000008
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern tBoolean SoftI2CBusy(tSoftI2C *pI2C);
+extern void SoftI2CCallbackSet(tSoftI2C *pI2C, void (*pfnCallback)(void));
+extern void SoftI2CControl(tSoftI2C *pI2C, unsigned long ulCmd);
+extern unsigned long SoftI2CDataGet(tSoftI2C *pI2C);
+extern void SoftI2CDataPut(tSoftI2C *pI2C, unsigned char ucData);
+extern unsigned long SoftI2CErr(tSoftI2C *pI2C);
+extern void SoftI2CInit(tSoftI2C *pI2C);
+extern void SoftI2CIntClear(tSoftI2C *pI2C);
+extern void SoftI2CIntDisable(tSoftI2C *pI2C);
+extern void SoftI2CIntEnable(tSoftI2C *pI2C);
+extern tBoolean SoftI2CIntStatus(tSoftI2C *pI2C, tBoolean bMasked);
+extern void SoftI2CSCLGPIOSet(tSoftI2C *pI2C, unsigned long ulBase,
+ unsigned char ucPin);
+extern void SoftI2CSDAGPIOSet(tSoftI2C *pI2C, unsigned long ulBase,
+ unsigned char ucPin);
+extern void SoftI2CSlaveAddrSet(tSoftI2C *pI2C, unsigned char ucSlaveAddr,
+ tBoolean bReceive);
+extern void SoftI2CTimerTick(tSoftI2C *pI2C);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTI2C_H__
diff --git a/utils/softssi.c b/utils/softssi.c
new file mode 100644
index 0000000..e8c5c0b
--- /dev/null
+++ b/utils/softssi.c
@@ -0,0 +1,1288 @@
+//*****************************************************************************
+//
+// softssi.c - Driver for the SoftSSI.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softssi_api
+//! @{
+//
+//*****************************************************************************
+
+#include "inc/hw_types.h"
+#include "driverlib/gpio.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "utils/softssi.h"
+
+//*****************************************************************************
+//
+// The states in the SoftSSI state machine.
+//
+//*****************************************************************************
+#define SOFTSSI_STATE_IDLE 0
+#define SOFTSSI_STATE_START 1
+#define SOFTSSI_STATE_IN 2
+#define SOFTSSI_STATE_OUT 3
+#define SOFTSSI_STATE_STOP1 4
+#define SOFTSSI_STATE_STOP2 5
+
+//*****************************************************************************
+//
+// The flags in the SoftSSI ucFlags structure member.
+//
+//*****************************************************************************
+#define SOFTSSI_FLAG_ENABLE 0x80
+#define SOFTSSI_FLAG_SPH 0x02
+#define SOFTSSI_FLAG_SPO 0x01
+
+//*****************************************************************************
+//
+//! Sets the configuration of a SoftSSI module.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ucProtocol specifes the data transfer protocol.
+//! \param ucBits specifies the number of bits transferred per frame.
+//!
+//! This function configures the data format of a SoftSSI module. The
+//! \e ucProtocol parameter can be one of the following values:
+//! \b SOFTSSI_FRF_MOTO_MODE_0, \b SOFTSSI_FRF_MOTO_MODE_1,
+//! \b SOFTSSI_FRF_MOTO_MODE_2, or \b SOFTSSI_FRF_MOTO_MODE_3. These frame
+//! formats imply the following polarity and phase configurations:
+//!
+//! <pre>
+//! Polarity Phase Mode
+//! 0 0 SOFTSSI_FRF_MOTO_MODE_0
+//! 0 1 SOFTSSI_FRF_MOTO_MODE_1
+//! 1 0 SOFTSSI_FRF_MOTO_MODE_2
+//! 1 1 SOFTSSI_FRF_MOTO_MODE_3
+//! </pre>
+//!
+//! The \e ucBits parameter defines the width of the data transfers, and can be
+//! a value between 4 and 16, inclusive.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIConfigSet(tSoftSSI *pSSI, unsigned char ucProtocol,
+ unsigned char ucBits)
+{
+ //
+ // See if a GPIO pin has been set for Fss.
+ //
+ if(pSSI->ulFssGPIO != 0)
+ {
+ //
+ // Configure the Fss pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(pSSI->ulFssGPIO & 0xfffff000,
+ (pSSI->ulFssGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Fss pin high.
+ //
+ HWREG(pSSI->ulFssGPIO) = 255;
+ }
+
+ //
+ // Configure the Clk pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(pSSI->ulClkGPIO & 0xfffff000,
+ (pSSI->ulClkGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Clk pin high or low based on the configured clock polarity.
+ //
+ if((ucProtocol & SOFTSSI_FLAG_SPO) == 0)
+ {
+ HWREG(pSSI->ulClkGPIO) = 0;
+ }
+ else
+ {
+ HWREG(pSSI->ulClkGPIO) = 255;
+ }
+
+ //
+ // Configure the Tx pin and set it low.
+ //
+ MAP_GPIOPinTypeGPIOOutput(pSSI->ulTxGPIO & 0xfffff000,
+ (pSSI->ulTxGPIO & 0x00000fff) >> 2);
+ HWREG(pSSI->ulTxGPIO) = 0;
+
+ //
+ // See if a GPIO pin has been set for Rx.
+ //
+ if(pSSI->ulRxGPIO != 0)
+ {
+ //
+ // Configure the Rx pin.
+ //
+ MAP_GPIOPinTypeGPIOInput(pSSI->ulRxGPIO & 0xfffff000,
+ (pSSI->ulRxGPIO & 0x00000fff) >> 2);
+ }
+
+ //
+ // Make sure that the transmit and receive FIFOs are empty.
+ //
+ pSSI->usTxBufferRead = 0;
+ pSSI->usTxBufferWrite = 0;
+ pSSI->usRxBufferRead = 0;
+ pSSI->usRxBufferWrite = 0;
+
+ //
+ // Save the frame protocol.
+ //
+ pSSI->ucFlags = ucProtocol;
+
+ //
+ // Save the number of data bits.
+ //
+ pSSI->ucBits = ucBits;
+
+ //
+ // Since the FIFOs are empty, the transmit FIFO "interrupt" is asserted.
+ //
+ pSSI->ucIntStatus = SOFTSSI_TXFF;
+
+ //
+ // Reset the idle counter.
+ //
+ pSSI->ucIdleCount = 0;
+
+ //
+ // Disable the SoftSSI module.
+ //
+ pSSI->ucFlags &= ~(SOFTSSI_FLAG_ENABLE);
+
+ //
+ // Start the SoftSSI state machine in the idle state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion/deassertion of the transmit FIFO ``interrupt''.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//!
+//! This function is used to determine when to assert or deassert the transmit
+//! FIFO ``interrupt''.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftSSITxInt(tSoftSSI *pSSI)
+{
+ unsigned short usTemp;
+
+ //
+ // Determine the number of words left in the transmit FIFO.
+ //
+ if(pSSI->usTxBufferRead > pSSI->usTxBufferWrite)
+ {
+ usTemp = (pSSI->usTxBufferLen + pSSI->usTxBufferWrite -
+ pSSI->usTxBufferRead);
+ }
+ else
+ {
+ usTemp = pSSI->usTxBufferWrite - pSSI->usTxBufferRead;
+ }
+
+ //
+ // If the transmit FIFO is now half full or less, generate a transmit FIFO
+ // "interrupt". Otherwise, clear the transmit FIFO "interrupt".
+ //
+ if(usTemp <= (pSSI->usTxBufferLen / 2))
+ {
+ pSSI->ucIntStatus |= SOFTSSI_TXFF;
+ }
+ else
+ {
+ pSSI->ucIntStatus &= ~(SOFTSSI_TXFF);
+ }
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion/deassertion of the receive FIFO ``interrupt''.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//!
+//! This function is used to determine when to assert or deassert the receive
+//! FIFO ``interrupt''.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftSSIRxInt(tSoftSSI *pSSI)
+{
+ unsigned short usTemp;
+
+ //
+ // Determine the number of words in the receive FIFO.
+ //
+ if(pSSI->usRxBufferRead > pSSI->usRxBufferWrite)
+ {
+ usTemp = (pSSI->usRxBufferLen + pSSI->usRxBufferWrite -
+ pSSI->usRxBufferRead);
+ }
+ else
+ {
+ usTemp = pSSI->usRxBufferWrite - pSSI->usRxBufferRead;
+ }
+
+ //
+ // If the receive FIFO is now half full or more, generate a receive FIFO
+ // "interrupt". Otherwise, clear the receive FIFO "interrupt".
+ //
+ if(usTemp >= (pSSI->usRxBufferLen / 2))
+ {
+ pSSI->ucIntStatus |= SOFTSSI_RXFF;
+ }
+ else
+ {
+ pSSI->ucIntStatus &= ~(SOFTSSI_RXFF);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftSSI module.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftSSI
+//! module. The transmission and reception of data over the SoftSSI link is
+//! performed by the state machine in this function.
+//!
+//! This function must be called at twice the desired SoftSSI clock rate. For
+//! example, to run the SoftSSI clock at 10 KHz, this function must be called
+//! at a 20 KHz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITimerTick(tSoftSSI *pSSI)
+{
+ unsigned short usTemp;
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(pSSI->ucState)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTSSI_STATE_IDLE:
+ {
+ //
+ // See if the SoftSSI module is enabled and there is data in the
+ // transmit FIFO.
+ //
+ if(((pSSI->ucFlags & SOFTSSI_FLAG_ENABLE) != 0) &&
+ (pSSI->usTxBufferRead != pSSI->usTxBufferWrite))
+ {
+ //
+ // Assert the Fss signal if it is configured.
+ //
+ if(pSSI->ulFssGPIO != 0)
+ {
+ HWREG(pSSI->ulFssGPIO) = 0;
+ }
+
+ //
+ // Move to the start state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_START;
+ }
+
+ //
+ // Otherwise, see if there is data in the receive FIFO.
+ //
+ else if((pSSI->usRxBufferRead != pSSI->usRxBufferWrite) &&
+ (pSSI->ucIdleCount != 64))
+ {
+ //
+ // Increment the idle counter.
+ //
+ pSSI->ucIdleCount++;
+
+ //
+ // See if the idle counter has become large enough to trigger
+ // a timeout "interrupt".
+ //
+ if(pSSI->ucIdleCount == 64)
+ {
+ //
+ // Trigger the receive timeout "interrupt".
+ //
+ pSSI->ucIntStatus |= SOFTSSI_RXTO;
+ }
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The start machine is in the transfer start state.
+ //
+ case SOFTSSI_STATE_START:
+ {
+ //
+ // Get the next word to transfer from the transmit FIFO.
+ //
+ pSSI->usTxData = (pSSI->pusTxBuffer[pSSI->usTxBufferRead] <<
+ (16 - pSSI->ucBits));
+
+ //
+ // Initialize the receive buffer to zero.
+ //
+ pSSI->usRxData = 0;
+
+ //
+ // Initialize the count of bits tranferred.
+ //
+ pSSI->ucCurrentBit = 0;
+
+ //
+ // Write the first bit of the transmit word to the Tx pin.
+ //
+ HWREG(pSSI->ulTxGPIO) =
+ (pSSI->usTxData & 0x8000) ? 255 : 0;
+
+ //
+ // Shift to the next bit of the transmit word.
+ //
+ pSSI->usTxData <<= 1;
+
+ //
+ // If in SPI mode 1 or 3, then the Clk signal needs to be toggled.
+ //
+ if((pSSI->ucFlags & SOFTSSI_FLAG_SPH) != 0)
+ {
+ HWREG(pSSI->ulClkGPIO) ^= 255;
+ }
+
+ //
+ // Move to the data input state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_IN;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the data input state.
+ //
+ case SOFTSSI_STATE_IN:
+ {
+ //
+ // Read the next bit from the Rx signal if it is configured.
+ //
+ if(pSSI->ulRxGPIO != 0)
+ {
+ pSSI->usRxData = ((pSSI->usRxData << 1) |
+ (HWREG(pSSI->ulRxGPIO) ? 1 : 0));
+ }
+
+ //
+ // Toggle the Clk signal.
+ //
+ HWREG(pSSI->ulClkGPIO) ^= 255;
+
+ //
+ // Increment the number of bits transferred.
+ //
+ pSSI->ucCurrentBit++;
+
+ //
+ // See if the entire word has been transferred.
+ //
+ if(pSSI->ucCurrentBit != pSSI->ucBits)
+ {
+ //
+ // There are more bits to transfer, so move to the data output
+ // state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_OUT;
+ }
+ else
+ {
+ //
+ // Increment the transmit read pointer, removing the word that
+ // was just transferred from the transmit FIFO.
+ //
+ pSSI->usTxBufferRead++;
+ if(pSSI->usTxBufferRead == pSSI->usTxBufferLen)
+ {
+ pSSI->usTxBufferRead = 0;
+ }
+
+ //
+ // See if a transmit FIFO "interrupt" needs to be asserted.
+ //
+ SoftSSITxInt(pSSI);
+
+ //
+ // Determine the new value for the receive FIFO write pointer.
+ //
+ usTemp = pSSI->usRxBufferWrite + 1;
+ if(usTemp >= pSSI->usRxBufferLen)
+ {
+ usTemp = 0;
+ }
+
+ //
+ // See if there is space in the receive FIFO for the word that
+ // was just received.
+ //
+ if(usTemp == pSSI->usRxBufferRead)
+ {
+ //
+ // The receive FIFO is full, so generate a receive FIFO
+ // overrun "interrupt".
+ //
+ pSSI->ucIntStatus |= SOFTSSI_RXOR;
+ }
+ else
+ {
+ //
+ // Store the new word into the receive FIFO.
+ //
+ pSSI->pusRxBuffer[pSSI->usRxBufferWrite] = pSSI->usRxData;
+
+ //
+ // Save the new receive FIFO write pointer.
+ //
+ pSSI->usRxBufferWrite = usTemp;
+
+ //
+ // See if a receive FIFO "interrupt" needs to be asserted.
+ //
+ SoftSSIRxInt(pSSI);
+ }
+
+ //
+ // See if the next word should be transmitted immediately.
+ // This will occur when there is data in the transmit FIFO, the
+ // SoftSSI module is enabled, and the SoftSSI module is in SPI
+ // mode 1 or 3.
+ //
+ if(((pSSI->ucFlags & SOFTSSI_FLAG_ENABLE) != 0) &&
+ ((pSSI->ucFlags & SOFTSSI_FLAG_SPH) != 0) &&
+ (pSSI->usTxBufferRead != pSSI->usTxBufferWrite))
+ {
+ //
+ // Get the next word to transfer from the transmit FIFO.
+ //
+ pSSI->usTxData =
+ (pSSI->pusTxBuffer[pSSI->usTxBufferRead] <<
+ (16 - pSSI->ucBits));
+
+ //
+ // Initialize the receive buffer to zero.
+ //
+ pSSI->usRxData = 0;
+
+ //
+ // Initialize the count of bits tranferred.
+ //
+ pSSI->ucCurrentBit = 0;
+
+ //
+ // Move to the data output state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_OUT;
+ }
+ else
+ {
+ //
+ // The next word should not be transmitted immediately, so
+ // move to the first step of the stop state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_STOP1;
+ }
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the data output state.
+ //
+ case SOFTSSI_STATE_OUT:
+ {
+ //
+ // Write the next bit of the transmit word to the Tx pin.
+ //
+ HWREG(pSSI->ulTxGPIO) = (pSSI->usTxData & 0x8000) ? 255 : 0;
+
+ //
+ // Toggle the Clk signal.
+ //
+ HWREG(pSSI->ulClkGPIO) ^= 255;
+
+ //
+ // Shift to the next bit of the transmit word.
+ //
+ pSSI->usTxData <<= 1;
+
+ //
+ // Move to the data input state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_IN;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the first step of the stop state.
+ //
+ case SOFTSSI_STATE_STOP1:
+ {
+ //
+ // Set the Tx pin low.
+ //
+ HWREG(pSSI->ulTxGPIO) = 0;
+
+ //
+ // If in SPI mode 1 or 3, then the Clk signal needs to be toggled.
+ //
+ if((pSSI->ucFlags & SOFTSSI_FLAG_SPH) == 0)
+ {
+ HWREG(pSSI->ulClkGPIO) ^= 255;
+ }
+
+ //
+ // Move to the second step of the stop state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_STOP2;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the second step of the stop state.
+ //
+ case SOFTSSI_STATE_STOP2:
+ {
+ //
+ // Deassert the Fss signal if it is configured.
+ //
+ if(pSSI->ulFssGPIO != 0)
+ {
+ HWREG(pSSI->ulFssGPIO) = 255;
+ }
+
+ //
+ // Move to the idle state.
+ //
+ pSSI->ucState = SOFTSSI_STATE_IDLE;
+
+ //
+ // Reset the idle counter.
+ //
+ pSSI->ucIdleCount = 0;
+
+ //
+ // See if the end of transfer "interrupt" should be generated.
+ //
+ if(pSSI->usTxBufferRead == pSSI->usTxBufferWrite)
+ {
+ pSSI->ucIntStatus |= SOFTSSI_TXEOT;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the SSI peripheral.
+ //
+ while(((pSSI->ucIntStatus & pSSI->ucIntMask) != 0) &&
+ (pSSI->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ pSSI->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftSSI module.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//!
+//! This function enables operation of the SoftSSI module. The SoftSSI module
+//! must be configured before it is enabled.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIEnable(tSoftSSI *pSSI)
+{
+ //
+ // Enable the SoftSSI module.
+ //
+ pSSI->ucFlags |= SOFTSSI_FLAG_ENABLE;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftSSI module.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//!
+//! This function disables operation of the SoftSSI module. If a data transfer
+//! is in progress, it is finished before the module is fully disabled.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDisable(tSoftSSI *pSSI)
+{
+ //
+ // Disable the SoftSSI module.
+ //
+ pSSI->ucFlags &= ~(SOFTSSI_FLAG_ENABLE);
+}
+
+//*****************************************************************************
+//
+//! Enables individual SoftSSI ``interrupt'' sources.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulIntFlags is a bit mask of the ``interrupt'' sources to be enabled.
+//!
+//! Enables the indicated SoftSSI ``interrupt'' sources. Only the sources that
+//! are enabled can be reflected to the callback function; disabled sources do
+//! not result in a callback. The \e ulIntFlags parameter can be any of the
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF, \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, or
+//! \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntEnable(tSoftSSI *pSSI, unsigned long ulIntFlags)
+{
+ //
+ // Enable the specified "interrupts".
+ //
+ pSSI->ucIntMask |= ulIntFlags;
+}
+
+//*****************************************************************************
+//
+//! Disables individual SoftSSI ``interrupt'' sources.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulIntFlags is a bit mask of the ``interrupt'' sources to be
+//! disabled.
+//!
+//! Disables the indicated SoftSSI ``interrupt'' sources. The \e ulIntFlags
+//! parameter can be any of the \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF,
+//! \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, or \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntDisable(tSoftSSI *pSSI, unsigned long ulIntFlags)
+{
+ //
+ // Disable the specified "interrupts".
+ //
+ pSSI->ucIntMask &= ~(ulIntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets the current ``interrupt'' status.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is required or
+//! \b true if the masked ``interrupt'' status is required.
+//!
+//! This function returns the ``interrupt'' status for the SoftSSI module.
+//! Either the raw ``interrupt'' status or the status of ``interrupts'' that
+//! are allowed to reflect to the callback can be returned.
+//!
+//! \return The current ``interrupt'' status, enumerated as a bit field of
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_TXFF, \b SOFTSSI_RXFF, \b SOFTSSI_RXTO, and
+//! \b SOFTSSI_RXOR.
+//
+//*****************************************************************************
+unsigned long
+SoftSSIIntStatus(tSoftSSI *pSSI, tBoolean bMasked)
+{
+ //
+ // Return either the "interrupt" status or the raw "interrupt" status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return(pSSI->ucIntStatus & pSSI->ucIntMask);
+ }
+ else
+ {
+ return(pSSI->ucIntStatus);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears SoftSSI ``interrupt'' sources.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulIntFlags is a bit mask of the ``interrupt'' sources to be cleared.
+//!
+//! The specified SoftSSI ``interrupt'' sources are cleared so that they no
+//! longer assert. This function must be called in the ``interrupt'' handler
+//! to keep the ``interrupt'' from being recognized again immediately upon
+//! exit. The \e ulIntFlags parameter is the logical OR of any of the
+//! \b SOFTSSI_TXEOT, \b SOFTSSI_RXTO, and \b SOFTSSI_RXOR values.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIIntClear(tSoftSSI *pSSI, unsigned long ulIntFlags)
+{
+ //
+ // Clear the requested "interrupt" sources.
+ //
+ pSSI->ucIntStatus &= ~(ulIntFlags) | SOFTSSI_TXFF | SOFTSSI_RXFF;
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any data in the receive FIFO.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//!
+//! This function determines if there is any data available to be read from the
+//! receive FIFO.
+//!
+//! \return Returns \b true if there is data in the receive FIFO or \b false
+//! if there is no data in the receive FIFO.
+//
+//*****************************************************************************
+tBoolean
+SoftSSIDataAvail(tSoftSSI *pSSI)
+{
+ //
+ // Return the availability of data.
+ //
+ return((pSSI->usRxBufferRead == pSSI->usRxBufferWrite) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any space in the transmit FIFO.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//!
+//! This function determines if there is space available in the transmit FIFO.
+//!
+//! \return Returns \b true if there is space available in the transmit FIFO or
+//! \b false if there is no space available in the transmit FIFO.
+//
+//*****************************************************************************
+tBoolean
+SoftSSISpaceAvail(tSoftSSI *pSSI)
+{
+ unsigned short usTemp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ usTemp = pSSI->usTxBufferWrite + 1;
+ if(usTemp == pSSI->usTxBufferLen)
+ {
+ usTemp = 0;
+ }
+
+ //
+ // Return the availability of space.
+ //
+ return((pSSI->usTxBufferRead == usTemp) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Puts a data element into the SoftSSI transmit FIFO.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulData is the data to be transmitted over the SoftSSI interface.
+//!
+//! This function places the supplied data into the transmit FIFO of the
+//! specified SoftSSI module.
+//!
+//! \note The upper 32 - N bits of the \e ulData are discarded, where N is the
+//! data width as configured by SoftSSIConfigSet(). For example, if the
+//! interface is configured for 8-bit data width, the upper 24 bits of
+//! \e ulData are discarded.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDataPut(tSoftSSI *pSSI, unsigned long ulData)
+{
+ unsigned short usTemp;
+
+ //
+ // Wait until there is space.
+ //
+ usTemp = pSSI->usTxBufferWrite + 1;
+ if(usTemp == pSSI->usTxBufferLen)
+ {
+ usTemp = 0;
+ }
+ while(usTemp == *(volatile unsigned short *)(&(pSSI->usTxBufferRead)))
+ {
+ }
+
+ //
+ // Write the data to the SoftSSI.
+ //
+ pSSI->pusTxBuffer[pSSI->usTxBufferWrite] = ulData;
+ pSSI->usTxBufferWrite = usTemp;
+
+ //
+ // See if a transmit FIFO "interrupt" needs to be cleared.
+ //
+ SoftSSITxInt(pSSI);
+}
+
+//*****************************************************************************
+//
+//! Puts a data element into the SoftSSI transmit FIFO.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulData is the data to be transmitted over the SoftSSI interface.
+//!
+//! This function places the supplied data into the transmit FIFO of the
+//! specified SoftSSI module. If there is no space in the FIFO, then this
+//! function returns a zero.
+//!
+//! \note The upper 32 - N bits of the \e ulData are discarded, where N is the
+//! data width as configured by SoftSSIConfigSet(). For example, if the
+//! interface is configured for 8-bit data width, the upper 24 bits of
+//! \e ulData are discarded.
+//!
+//! \return Returns the number of elements written to the SSI transmit FIFO.
+//
+//*****************************************************************************
+long
+SoftSSIDataPutNonBlocking(tSoftSSI *pSSI, unsigned long ulData)
+{
+ unsigned short usTemp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ usTemp = pSSI->usTxBufferWrite + 1;
+ if(usTemp == pSSI->usTxBufferLen)
+ {
+ usTemp = 0;
+ }
+
+ //
+ // Check for space to write.
+ //
+ if(usTemp != pSSI->usTxBufferRead)
+ {
+ pSSI->pusTxBuffer[pSSI->usTxBufferWrite] = ulData;
+ pSSI->usTxBufferWrite = usTemp;
+ SoftSSITxInt(pSSI);
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Gets a data element from the SoftSSI receive FIFO.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param pulData is a pointer to a storage location for data that was
+//! received over the SoftSSI interface.
+//!
+//! This function gets received data from the receive FIFO of the specified
+//! SoftSSI module and places that data into the location specified by the
+//! \e pulData parameter.
+//!
+//! \note Only the lower N bits of the value written to \e pulData contain
+//! valid data, where N is the data width as configured by SoftSSIConfigSet().
+//! For example, if the interface is configured for 8-bit data width, only the
+//! lower 8 bits of the value written to \e pulData contain valid data.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIDataGet(tSoftSSI *pSSI, unsigned long *pulData)
+{
+ //
+ // Wait until there is data to be read.
+ //
+ while(pSSI->usRxBufferRead ==
+ *(volatile unsigned short *)(&(pSSI->usRxBufferWrite)))
+ {
+ }
+
+ //
+ // Read data from SoftSSI.
+ //
+ *pulData = pSSI->pusRxBuffer[pSSI->usRxBufferRead];
+ pSSI->usRxBufferRead++;
+ if(pSSI->usRxBufferRead == pSSI->usRxBufferLen)
+ {
+ pSSI->usRxBufferRead = 0;
+ }
+
+ //
+ // See if a receive FIFO "interrupt" needs to be cleared.
+ //
+ SoftSSIRxInt(pSSI);
+}
+
+//*****************************************************************************
+//
+//! Gets a data element from the SoftSSI receive FIFO.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param pulData is a pointer to a storage location for data that was
+//! received over the SoftSSI interface.
+//!
+//! This function gets received data from the receive FIFO of the specified
+//! SoftSSI module and places that data into the location specified by the
+//! \e ulData parameter. If there is no data in the FIFO, then this function
+//! returns a zero.
+//!
+//! \note Only the lower N bits of the value written to \e pulData contain
+//! valid data, where N is the data width as configured by SoftSSIConfigSet().
+//! For example, if the interface is configured for 8-bit data width, only the
+//! lower 8 bits of the value written to \e pulData contain valid data.
+//!
+//! \return Returns the number of elements read from the SoftSSI receive FIFO.
+//
+//*****************************************************************************
+long
+SoftSSIDataGetNonBlocking(tSoftSSI *pSSI, unsigned long *pulData)
+{
+ //
+ // Check for data to read.
+ //
+ if(pSSI->usRxBufferRead != pSSI->usRxBufferWrite)
+ {
+ *pulData = pSSI->pusRxBuffer[pSSI->usRxBufferRead];
+ pSSI->usRxBufferRead++;
+ if(pSSI->usRxBufferRead == pSSI->usRxBufferLen)
+ {
+ pSSI->usRxBufferRead = 0;
+ }
+ SoftSSIRxInt(pSSI);
+ return(1);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the SoftSSI transmitter is busy or not.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//!
+//! Allows the caller to determine whether all transmitted bytes have cleared
+//! the transmitter. If \b false is returned, then the transmit FIFO is empty
+//! and all bits of the last transmitted word have left the shift register.
+//!
+//! \return Returns \b true if the SoftSSI is transmitting or \b false if all
+//! transmissions are complete.
+//
+//*****************************************************************************
+tBoolean
+SoftSSIBusy(tSoftSSI *pSSI)
+{
+ //
+ // Determine if the SSI is busy.
+ //
+ return(((pSSI->ucState == SOFTSSI_STATE_IDLE) &&
+ (((pSSI->ucFlags & SOFTSSI_FLAG_ENABLE) == 0) ||
+ (pSSI->usTxBufferRead == pSSI->usTxBufferWrite))) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftSSI module.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftSSI module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSICallbackSet(tSoftSSI *pSSI, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ pSSI->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Fss signal.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulBase is the base address of the GPIO module.
+//! \param ucPin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Fss signal.
+//! If there is not a GPIO pin allocated for Fss, the SoftSSI module does not
+//! assert/deassert the Fss signal, leaving it to the application either to do
+//! manually or to not do at all if the slave device has Fss tied to ground.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIFssGPIOSet(tSoftSSI *pSSI, unsigned long ulBase, unsigned char ucPin)
+{
+ //
+ // Save the base address and pin for the Fss signal.
+ //
+ if(ulBase == 0)
+ {
+ pSSI->ulFssGPIO = 0;
+ }
+ else
+ {
+ pSSI->ulFssGPIO = ulBase + (ucPin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Clk signal.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulBase is the base address of the GPIO module.
+//! \param ucPin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Clk signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIClkGPIOSet(tSoftSSI *pSSI, unsigned long ulBase, unsigned char ucPin)
+{
+ //
+ // Save the base address and pin for the Clk signal.
+ //
+ pSSI->ulClkGPIO = ulBase + (ucPin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Tx signal.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulBase is the base address of the GPIO module.
+//! \param ucPin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Tx signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITxGPIOSet(tSoftSSI *pSSI, unsigned long ulBase, unsigned char ucPin)
+{
+ //
+ // Save the base address and pin for the Tx signal.
+ //
+ pSSI->ulTxGPIO = ulBase + (ucPin << 2);
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftSSI Rx signal.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param ulBase is the base address of the GPIO module.
+//! \param ucPin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used for the SoftSSI Rx signal. If
+//! there is not a GPIO pin allocated for Rx, the SoftSSI module does not read
+//! data from the slave device.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIRxGPIOSet(tSoftSSI *pSSI, unsigned long ulBase, unsigned char ucPin)
+{
+ //
+ // Save the base address and pin for the Rx signal.
+ //
+ if(ulBase == 0)
+ {
+ pSSI->ulRxGPIO = 0;
+ }
+ else
+ {
+ pSSI->ulRxGPIO = ulBase + (ucPin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit FIFO buffer for a SoftSSI module.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param pusTxBuffer is the address of the transmit FIFO buffer.
+//! \param usLen is the size, in 16-bit half-words, of the transmit FIFO
+//! buffer.
+//!
+//! This function sets the address and size of the transmit FIFO buffer and
+//! also resets the read and write pointers, marking the transmit FIFO as
+//! empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSITxBufferSet(tSoftSSI *pSSI, unsigned short *pusTxBuffer,
+ unsigned short usLen)
+{
+ //
+ // Save the transmit FIFO buffer address and length.
+ //
+ pSSI->pusTxBuffer = pusTxBuffer;
+ pSSI->usTxBufferLen = usLen;
+
+ //
+ // Reset the transmit FIFO read and write pointers.
+ //
+ pSSI->usTxBufferRead = 0;
+ pSSI->usTxBufferWrite = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the receive FIFO buffer for a SoftSSI module.
+//!
+//! \param pSSI specifies the SoftSSI data structure.
+//! \param pusRxBuffer is the address of the receive FIFO buffer.
+//! \param usLen is the size, in 16-bit half-words, of the receive FIFO buffer.
+//!
+//! This function sets the address and size of the receive FIFO buffer and also
+//! resets the read and write pointers, marking the receive FIFO as empty.
+//! When the buffer pointer and length are configured as zero, all data
+//! received from the slave device is discarded. This capability is useful
+//! when there is no GPIO pin allocated for the Rx signal.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftSSIRxBufferSet(tSoftSSI *pSSI, unsigned short *pusRxBuffer,
+ unsigned short usLen)
+{
+ //
+ // Save the receive FIFO buffer address and length.
+ //
+ pSSI->pusRxBuffer = pusRxBuffer;
+ pSSI->usRxBufferLen = usLen;
+
+ //
+ // Reset the receive FIFO read and write pointers.
+ //
+ pSSI->usRxBufferRead = 0;
+ pSSI->usRxBufferWrite = 0;
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softssi.h b/utils/softssi.h
new file mode 100644
index 0000000..391e901
--- /dev/null
+++ b/utils/softssi.h
@@ -0,0 +1,280 @@
+//*****************************************************************************
+//
+// softssi.h - Defines and macros for the SoftSSI.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SOFTSSI_H__
+#define __SOFTSSI_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softssi_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftSSI module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware SSI implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftSSICallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the Fss signal. If this
+ //! member is zero, the Fss signal is not generated. This member can be
+ //! set via a direct structure access or using the SoftSSIFssGPIOSet
+ //! function.
+ ///
+ unsigned long ulFssGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Clk signal. This member
+ //! can be set via a direct structure access or using the SoftSSIClkGPIOSet
+ //! function.
+ //
+ unsigned long ulClkGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Tx signal. This member
+ //! can be set via a direct structure access or using the SoftSSITxGPIOSet
+ //! function.
+ //
+ unsigned long ulTxGPIO;
+
+ //
+ //! The address of the GPIO pin to be used for the Rx signal. If this
+ //! member is zero, the Rx signal is not read. This member can be set via
+ //! a direct structure access or using the SoftSSIRxGPIOSet function.
+ //
+ unsigned long ulRxGPIO;
+
+ //
+ //! The address of the data buffer used for the transmit FIFO. This member
+ //! can be set via a direct structure access or using the
+ //! SoftSSITxBufferSet function.
+ //
+ unsigned short *pusTxBuffer;
+
+ //
+ //! The address of the data buffer used for the receive FIFO. This member
+ //! can be set via a direct structure access or using the
+ //! SoftSSIRxBufferSet function.
+ //
+ unsigned short *pusRxBuffer;
+
+ //
+ //! The length of the transmit FIFO. This member can be set via a direct
+ //! structure access or using the SoftSSITxBufferSet function.
+ //
+ unsigned short usTxBufferLen;
+
+ //
+ //! The index into the transmit FIFO of the next word to be transmitted.
+ //! This member should be initialized to zero, but should not be accessed
+ //! or modified by the application.
+ //
+ unsigned short usTxBufferRead;
+
+ //
+ //! The index into the transmit FIFO of the next location to store data
+ //! into the FIFO. This member should be initialized to zero, but should
+ //! not be accessed or modified by the application.
+ //
+ unsigned short usTxBufferWrite;
+
+ //
+ //! The length of the receive FIFO. This member can be set via a direct
+ //! structure access or using the SoftSSIRxBufferSet function.
+ //
+ unsigned short usRxBufferLen;
+
+ //
+ //! The index into the receive FIFO of the next word to be read from the
+ //! FIFO. This member should be initialized to zero, but should not be
+ //! accessed or modified by the application.
+ //
+ unsigned short usRxBufferRead;
+
+ //
+ //! The index into the receive FIFO of the location to store the next word
+ //! received. This member should be initialized to zero, but should not be
+ //! accessed or modified by the application.
+ //
+ unsigned short usRxBufferWrite;
+
+ //
+ //! The word that is currently being transmitted. This member should not
+ //! be accessed or modified by the application.
+ //
+ unsigned short usTxData;
+
+ //
+ //! The word that is currently being received. This member should not be
+ //! accessed or modified by the application.
+ //
+ unsigned short usRxData;
+
+ //
+ //! The flags that control the operation of the SoftSSI module. This
+ //! member should not be accessed or modified by the application.
+ //
+ unsigned char ucFlags;
+
+ //
+ //! The number of data bits in each SoftSSI frame, which also specifies the
+ //! width of each data item in the transmit and receive FIFOs. This member
+ //! can be set via a direct structure access or using the SoftSSIConfigSet
+ //! function.
+ //
+ unsigned char ucBits;
+
+ //
+ //! The current state of the SoftSSI state machine. This member should not
+ //! be accessed or modified by the application.
+ //
+ unsigned char ucState;
+
+ //
+ //! The number of bits that have been transmitted and received in the
+ //! current frame. This member should not be accessed or modified by the
+ //! application.
+ //
+ unsigned char ucCurrentBit;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ unsigned char ucIntMask;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ unsigned char ucIntStatus;
+
+ //
+ //! The number of tick counts that the SoftSSI module has been idle with
+ //! data stored in the receive FIFO, which is used to generate the receive
+ //! timeout interrupt. This member should not be accessed or modified by
+ //! the application.
+ //
+ unsigned char ucIdleCount;
+}
+tSoftSSI;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftSSIIntEnable, SoftSSIIntDisable, and
+// SoftSSIIntClear as the ulIntFlags parameter, and returned by
+// SoftSSIIntStatus.
+//
+//*****************************************************************************
+#define SOFTSSI_TXEOT 0x00000010 // TX end of transmit
+#define SOFTSSI_TXFF 0x00000008 // TX FIFO half full or less
+#define SOFTSSI_RXFF 0x00000004 // RX FIFO half full or more
+#define SOFTSSI_RXTO 0x00000002 // RX timeout
+#define SOFTSSI_RXOR 0x00000001 // RX overrun
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftSSIConfigSet.
+//
+//*****************************************************************************
+#define SOFTSSI_FRF_MOTO_MODE_0 0x00000000 // Moto fmt, polarity 0, phase 0
+#define SOFTSSI_FRF_MOTO_MODE_1 0x00000002 // Moto fmt, polarity 0, phase 1
+#define SOFTSSI_FRF_MOTO_MODE_2 0x00000001 // Moto fmt, polarity 1, phase 0
+#define SOFTSSI_FRF_MOTO_MODE_3 0x00000003 // Moto fmt, polarity 1, phase 1
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern tBoolean SoftSSIBusy(tSoftSSI *pSSI);
+extern void SoftSSICallbackSet(tSoftSSI *pSSI, void (*pfnCallback)(void));
+extern void SoftSSIClkGPIOSet(tSoftSSI *pSSI, unsigned long ulBase,
+ unsigned char ucPin);
+extern void SoftSSIConfigSet(tSoftSSI *pSSI, unsigned char ucProtocol,
+ unsigned char ucBits);
+extern tBoolean SoftSSIDataAvail(tSoftSSI *pSSI);
+extern void SoftSSIDataGet(tSoftSSI *pSSI, unsigned long *pulData);
+extern long SoftSSIDataGetNonBlocking(tSoftSSI *pSSI, unsigned long *pulData);
+extern void SoftSSIDataPut(tSoftSSI *pSSI, unsigned long ulData);
+extern long SoftSSIDataPutNonBlocking(tSoftSSI *pSSI, unsigned long ulData);
+extern void SoftSSIDisable(tSoftSSI *pSSI);
+extern void SoftSSIEnable(tSoftSSI *pSSI);
+extern void SoftSSIFssGPIOSet(tSoftSSI *pSSI, unsigned long ulBase,
+ unsigned char ucPin);
+extern void SoftSSIIntClear(tSoftSSI *pSSI, unsigned long ulIntFlags);
+extern void SoftSSIIntDisable(tSoftSSI *pSSI, unsigned long ulIntFlags);
+extern void SoftSSIIntEnable(tSoftSSI *pSSI, unsigned long ulIntFlags);
+extern unsigned long SoftSSIIntStatus(tSoftSSI *pSSI, tBoolean bMasked);
+extern void SoftSSIRxBufferSet(tSoftSSI *pSSI, unsigned short *pusRxBuffer,
+ unsigned short usLen);
+extern void SoftSSIRxGPIOSet(tSoftSSI *pSSI, unsigned long ulBase,
+ unsigned char ucPin);
+extern tBoolean SoftSSISpaceAvail(tSoftSSI *pSSI);
+extern void SoftSSITimerTick(tSoftSSI *pSSI);
+extern void SoftSSITxBufferSet(tSoftSSI *pSSI, unsigned short *pusTxBuffer,
+ unsigned short usLen);
+extern void SoftSSITxGPIOSet(tSoftSSI *pSSI, unsigned long ulBase,
+ unsigned char ucPin);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTSSI_H__
diff --git a/utils/softuart.c b/utils/softuart.c
new file mode 100644
index 0000000..4126bc7
--- /dev/null
+++ b/utils/softuart.c
@@ -0,0 +1,2584 @@
+//*****************************************************************************
+//
+// softuart.c - Driver for the SoftUART.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! \addtogroup softuart_api
+//! @{
+//
+//*****************************************************************************
+
+#include <string.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "inc/hw_uart.h"
+#include "driverlib/debug.h"
+#include "driverlib/gpio.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/uart.h"
+#include "utils/softuart.h"
+
+//*****************************************************************************
+//
+// The states in the SoftUART transmit state machine. The code depends upon
+// the fact that the value of TXSTATE_DATA_n is n + 1, and that TXSTATE_DATA_0
+// is 1.
+//
+//*****************************************************************************
+#define SOFTUART_TXSTATE_IDLE 0
+#define SOFTUART_TXSTATE_DATA_0 1
+#define SOFTUART_TXSTATE_DATA_1 2
+#define SOFTUART_TXSTATE_DATA_2 3
+#define SOFTUART_TXSTATE_DATA_3 4
+#define SOFTUART_TXSTATE_DATA_4 5
+#define SOFTUART_TXSTATE_DATA_5 6
+#define SOFTUART_TXSTATE_DATA_6 7
+#define SOFTUART_TXSTATE_DATA_7 8
+#define SOFTUART_TXSTATE_START 9
+#define SOFTUART_TXSTATE_PARITY 10
+#define SOFTUART_TXSTATE_STOP_0 11
+#define SOFTUART_TXSTATE_STOP_1 12
+#define SOFTUART_TXSTATE_BREAK 13
+
+//*****************************************************************************
+//
+// The states of the SoftUART receive state machine. The code depends upon the
+// the fact that the value of RXSTATE_DATA_n is n, and that RXSTATE_DATA_0 is
+// 0.
+//
+//*****************************************************************************
+#define SOFTUART_RXSTATE_DATA_0 0
+#define SOFTUART_RXSTATE_DATA_1 1
+#define SOFTUART_RXSTATE_DATA_2 2
+#define SOFTUART_RXSTATE_DATA_3 3
+#define SOFTUART_RXSTATE_DATA_4 4
+#define SOFTUART_RXSTATE_DATA_5 5
+#define SOFTUART_RXSTATE_DATA_6 6
+#define SOFTUART_RXSTATE_DATA_7 7
+#define SOFTUART_RXSTATE_IDLE 8
+#define SOFTUART_RXSTATE_PARITY 9
+#define SOFTUART_RXSTATE_STOP_0 10
+#define SOFTUART_RXSTATE_STOP_1 11
+#define SOFTUART_RXSTATE_BREAK 12
+#define SOFTUART_RXSTATE_DELAY 13
+
+//*****************************************************************************
+//
+// The flags in the SoftUART ucFlags structure member.
+//
+//*****************************************************************************
+#define SOFTUART_FLAG_ENABLE 0x01
+#define SOFTUART_FLAG_TXBREAK 0x02
+
+//*****************************************************************************
+//
+// The flags in the SoftUART ucRxFlags structure member.
+//
+//*****************************************************************************
+#define SOFTUART_RXFLAG_OE 0x08
+#define SOFTUART_RXFLAG_BE 0x04
+#define SOFTUART_RXFLAG_PE 0x02
+#define SOFTUART_RXFLAG_FE 0x01
+
+//*****************************************************************************
+//
+// Additional internal configuration stored in the SoftUART usConfig structure
+// member.
+//
+//*****************************************************************************
+#define SOFTUART_CONFIG_BASE_M 0x00ff
+#define SOFTUART_CONFIG_EXT_M 0xff00
+#define SOFTUART_CONFIG_TXLVL_M 0x0700
+#define SOFTUART_CONFIG_TXLVL_1 0x0000
+#define SOFTUART_CONFIG_TXLVL_2 0x0100
+#define SOFTUART_CONFIG_TXLVL_4 0x0200
+#define SOFTUART_CONFIG_TXLVL_6 0x0300
+#define SOFTUART_CONFIG_TXLVL_7 0x0400
+#define SOFTUART_CONFIG_RXLVL_M 0x3800
+#define SOFTUART_CONFIG_RXLVL_1 0x0000
+#define SOFTUART_CONFIG_RXLVL_2 0x0800
+#define SOFTUART_CONFIG_RXLVL_4 0x1000
+#define SOFTUART_CONFIG_RXLVL_6 0x1800
+#define SOFTUART_CONFIG_RXLVL_7 0x2000
+
+//*****************************************************************************
+//
+// The odd parity of each possible data byte. The odd parity of N can be found
+// by looking at bit N % 32 of word N / 32.
+//
+//*****************************************************************************
+static unsigned long g_pulParityOdd[] =
+{
+ 0x69969669, 0x96696996, 0x96696996, 0x69969669,
+ 0x96696996, 0x69969669, 0x69969669, 0x96696996
+};
+
+//*****************************************************************************
+//
+//! Initializes the SoftUART module.
+//!
+//! \param pUART specifies the soft UART data structure.
+//!
+//! This function initializes the data structure for the SoftUART module,
+//! putting it into the default configuration.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTInit(tSoftUART *pUART)
+{
+ //
+ // Clear the SoftUART data structure.
+ //
+ memset(pUART, 0, sizeof(tSoftUART));
+
+ //
+ // Set the default transmit and receive buffer interrupt level.
+ //
+ pUART->usConfig = SOFTUART_CONFIG_TXLVL_4 | SOFTUART_CONFIG_RXLVL_4;
+}
+
+//*****************************************************************************
+//
+//! Sets the configuration of a SoftUART module.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ulConfig is the data format for the port (number of data bits,
+//! number of stop bits, and parity).
+//!
+//! This function configures the SoftUART for operation in the specified data
+//! format, as specified in the \e ulConfig parameter.
+//!
+//! The \e ulConfig parameter is the logical OR of three values: the number of
+//! data bits, the number of stop bits, and the parity.
+//! \b SOFTUART_CONFIG_WLEN_8, \b SOFTUART_CONFIG_WLEN_7,
+//! \b SOFTUART_CONFIG_WLEN_6, and \b SOFTUART_CONFIG_WLEN_5 select from eight
+//! to five data bits per byte (respectively). \b SOFTUART_CONFIG_STOP_ONE and
+//! \b SOFTUART_CONFIG_STOP_TWO select one or two stop bits (respectively).
+//! \b SOFTUART_CONFIG_PAR_NONE, \b SOFTUART_CONFIG_PAR_EVEN,
+//! \b SOFTUART_CONFIG_PAR_ODD, \b SOFTUART_CONFIG_PAR_ONE, and
+//! \b SOFTUART_CONFIG_PAR_ZERO select the parity mode (no parity bit, even
+//! parity bit, odd parity bit, parity bit always one, and parity bit always
+//! zero, respectively).
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTConfigSet(tSoftUART *pUART, unsigned long ulConfig)
+{
+ //
+ // See if a GPIO pin has been set for Tx.
+ //
+ if(pUART->ulTxGPIO != 0)
+ {
+ //
+ // Configure the Tx pin.
+ //
+ MAP_GPIOPinTypeGPIOOutput(pUART->ulTxGPIO & 0xfffff000,
+ (pUART->ulTxGPIO & 0x00000fff) >> 2);
+
+ //
+ // Set the Tx pin high.
+ //
+ HWREG(pUART->ulTxGPIO) = 255;
+ }
+
+ //
+ // See if a GPIO pin has been set for Rx.
+ //
+ if(pUART->ulRxGPIOPort != 0)
+ {
+ //
+ // Configure the Rx pin.
+ //
+ MAP_GPIOPinTypeGPIOInput(pUART->ulRxGPIOPort, pUART->ucRxPin);
+
+ //
+ // Set the Rx pin to generate an interrupt on the next falling edge.
+ //
+ MAP_GPIOIntTypeSet(pUART->ulRxGPIOPort, pUART->ucRxPin,
+ GPIO_FALLING_EDGE);
+
+ //
+ // Enable the Rx pin interrupt.
+ //
+ MAP_GPIOPinIntClear(pUART->ulRxGPIOPort, pUART->ucRxPin);
+ MAP_GPIOPinIntEnable(pUART->ulRxGPIOPort, pUART->ucRxPin);
+ }
+
+ //
+ // Make sure that the transmit and receive buffers are empty.
+ //
+ pUART->usTxBufferRead = 0;
+ pUART->usTxBufferWrite = 0;
+ pUART->usRxBufferRead = 0;
+ pUART->usRxBufferWrite = 0;
+
+ //
+ // Save the data format.
+ //
+ pUART->usConfig = ((pUART->usConfig & SOFTUART_CONFIG_EXT_M) |
+ (ulConfig & SOFTUART_CONFIG_BASE_M));
+
+ //
+ // Enable the SoftUART module.
+ //
+ pUART->ucFlags |= SOFTUART_FLAG_ENABLE;
+
+ //
+ // The next value to be written to the Tx pin is one since the SoftUART is
+ // idle.
+ //
+ pUART->ucTxNext = 255;
+
+ //
+ // Start the SoftUART state machines in the idle state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_IDLE;
+ pUART->ucRxState = SOFTUART_RXSTATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftUART transmitter.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function performs the periodic, time-based updates to the SoftUART
+//! transmitter. The transmission of data from the SoftUART is performed by
+//! the state machine in this function.
+//!
+//! This function must be called at the desired SoftUART baud rate. For
+//! example, to run the SoftUART at 115,200 baud, this function must be called
+//! at a 115,200 Hz rate.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxTimerTick(tSoftUART *pUART)
+{
+ unsigned long ulTemp;
+
+ //
+ // Write the next value to the Tx data line. This value was computed on
+ // the previous timer tick, which helps to reduce the jitter on the Tx
+ // edges (which is important since a UART connection does not contain a
+ // clock signal).
+ //
+ HWREG(pUART->ulTxGPIO) = pUART->ucTxNext;
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(pUART->ucTxState)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTUART_TXSTATE_IDLE:
+ {
+ //
+ // See if the SoftUART module is enabled.
+ //
+ if(!(pUART->ucFlags & SOFTUART_FLAG_ENABLE))
+ {
+ //
+ // The SoftUART module is not enabled, so do nothing and stay
+ // in the idle state.
+ //
+ break;
+ }
+
+ //
+ // See if the break signal should be asserted.
+ //
+ else if(pUART->ucFlags & SOFTUART_FLAG_TXBREAK)
+ {
+ //
+ // The data line should be driven low while in the break state.
+ //
+ pUART->ucTxNext = 0;
+
+ //
+ // Move to the break state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_BREAK;
+ }
+
+ //
+ // Otherwise, see if there is data in the transmit buffer.
+ //
+ else if(pUART->usTxBufferRead != pUART->usTxBufferWrite)
+ {
+ //
+ // The data line should be driven low to indicate a start bit.
+ //
+ pUART->ucTxNext = 0;
+
+ //
+ // Move to the start bit state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_START;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the start bit state.
+ //
+ case SOFTUART_TXSTATE_START:
+ {
+ //
+ // Get the next byte to be transmitted.
+ //
+ pUART->ucTxData = pUART->pucTxBuffer[pUART->usTxBufferRead];
+
+ //
+ // The next value to be written to the data line is the LSB of the
+ // next data byte.
+ //
+ pUART->ucTxNext = (pUART->ucTxData & 1) ? 255 : 0;
+
+ //
+ // Move to the data bit 0 state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_DATA_0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte must be output.
+ // This depends upon TXSTATE_DATA_n and TXSTATE_DATA_(n+1) being
+ // consecutively numbered.
+ //
+ case SOFTUART_TXSTATE_DATA_0:
+ case SOFTUART_TXSTATE_DATA_1:
+ case SOFTUART_TXSTATE_DATA_2:
+ case SOFTUART_TXSTATE_DATA_3:
+ {
+ //
+ // The next value to be written to the data line is the next bit of
+ // the data byte.
+ //
+ pUART->ucTxNext =
+ (pUART->ucTxData & (1 << pUART->ucTxState)) ? 255 : 0;
+
+ //
+ // Advance to the next state.
+ //
+ pUART->ucTxState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte must be output.
+ // Additionally, based on the configuration of the SoftUART, this bit
+ // might be the last data bit of the data byte. This depends upon
+ // TXSTATE_DATA_n and TXSTATE_DATA_(n+1) being consecutively numbered.
+ //
+ case SOFTUART_TXSTATE_DATA_4:
+ case SOFTUART_TXSTATE_DATA_5:
+ case SOFTUART_TXSTATE_DATA_6:
+ case SOFTUART_TXSTATE_DATA_7:
+ {
+ //
+ // See if the bit that was just transferred is the last bit of the
+ // data byte (based on the configuration of the SoftUART).
+ //
+ if(((pUART->usConfig & SOFTUART_CONFIG_WLEN_MASK) >>
+ SOFTUART_CONFIG_WLEN_S) ==
+ (pUART->ucTxState - SOFTUART_TXSTATE_DATA_4))
+ {
+ //
+ // See if parity is enabled.
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) !=
+ SOFTUART_CONFIG_PAR_NONE)
+ {
+ //
+ // See if the parity is set to one.
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ONE)
+ {
+ //
+ // The next value to be written to the data line is
+ // one.
+ //
+ pUART->ucTxNext = 255;
+ }
+
+ //
+ // Otherwise, see if the parity is set to zero.
+ //
+ else if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ZERO)
+ {
+ //
+ // The next value to be written to the data line is
+ // zero.
+ //
+ pUART->ucTxNext = 0;
+ }
+
+ //
+ // Otherwise, there is either even or odd parity.
+ //
+ else
+ {
+ //
+ // Find the odd parity for the data byte.
+ //
+ pUART->ucTxNext =
+ ((g_pulParityOdd[pUART->ucTxData >> 5] &
+ (1 << (pUART->ucTxData & 31))) ? 255 : 0);
+
+ //
+ // If the parity is set to even, then invert the
+ // parity just computed (making it even parity).
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_EVEN)
+ {
+ pUART->ucTxNext ^= 255;
+ }
+ }
+
+ //
+ // Advance to the parity state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_PARITY;
+ }
+
+ //
+ // Parity is not enabled.
+ //
+ else
+ {
+ //
+ // The next value to write to the data line is the stop
+ // bit.
+ //
+ pUART->ucTxNext = 255;
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_STOP_1;
+ }
+ }
+ }
+
+ //
+ // Otherwise, there are more data bits to transfer.
+ //
+ else
+ {
+ //
+ // The next value to be written to the data line is the next
+ // bit of the data byte.
+ //
+ pUART->ucTxNext =
+ (pUART->ucTxData & (1 << pUART->ucTxState)) ? 255 : 0;
+
+ //
+ // Advance to the next state.
+ //
+ pUART->ucTxState++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the parity bit state.
+ //
+ case SOFTUART_TXSTATE_PARITY:
+ {
+ //
+ // The next value to write to the data line is the stop bit.
+ //
+ pUART->ucTxNext = 255;
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_STOP_1;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the two stop bits state.
+ //
+ case SOFTUART_TXSTATE_STOP_0:
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_STOP_1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the one stop bit state.
+ //
+ case SOFTUART_TXSTATE_STOP_1:
+ {
+ //
+ // The data byte has been completely transferred, so advance the
+ // read pointer.
+ //
+ pUART->usTxBufferRead++;
+ if(pUART->usTxBufferRead == pUART->usTxBufferLen)
+ {
+ pUART->usTxBufferRead = 0;
+ }
+
+ //
+ // Determine the number of characters in the transmit buffer.
+ //
+ if(pUART->usTxBufferRead > pUART->usTxBufferWrite)
+ {
+ ulTemp = (pUART->usTxBufferLen -
+ (pUART->usTxBufferRead - pUART->usTxBufferWrite));
+ }
+ else
+ {
+ ulTemp = pUART->usTxBufferWrite - pUART->usTxBufferRead;
+ }
+
+ //
+ // If the transmit buffer fullness just crossed the programmed
+ // level, generate a transmit "interrupt".
+ //
+ if(ulTemp == pUART->usTxBufferLevel)
+ {
+ pUART->usIntStatus |= SOFTUART_INT_TX;
+ }
+
+ //
+ // See if the SoftUART module is enabled.
+ //
+ if(!(pUART->ucFlags & SOFTUART_FLAG_ENABLE))
+ {
+ //
+ // The SoftUART module is not enabled, so do advance to the
+ // idle state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // See if the break signal should be asserted.
+ //
+ else if(pUART->ucFlags & SOFTUART_FLAG_TXBREAK)
+ {
+ //
+ // The data line should be driven low while in the break state.
+ //
+ pUART->ucTxNext = 0;
+
+ //
+ // Move to the break state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_BREAK;
+ }
+
+ //
+ // Otherwise, see if there is data in the transmit buffer.
+ //
+ else if(pUART->usTxBufferRead != pUART->usTxBufferWrite)
+ {
+ //
+ // The data line should be driven low to indicate a start bit.
+ //
+ pUART->ucTxNext = 0;
+
+ //
+ // Move to the start bit state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_START;
+ }
+
+ //
+ // Otherwise, there is nothing to do.
+ //
+ else
+ {
+ //
+ // Assert the end of transmission "interrupt".
+ //
+ pUART->usIntStatus |= SOFTUART_INT_EOT;
+
+ //
+ // Advance to the idle state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the break state.
+ //
+ case SOFTUART_TXSTATE_BREAK:
+ {
+ //
+ // See if the break should be deasserted.
+ //
+ if(!(pUART->ucFlags & SOFTUART_FLAG_ENABLE) ||
+ !(pUART->ucFlags & SOFTUART_FLAG_TXBREAK))
+ {
+ //
+ // The data line should be driven high to indicate it is idle.
+ //
+ pUART->ucTxNext = 255;
+
+ //
+ // Advance to the idle state.
+ //
+ pUART->ucTxState = SOFTUART_TXSTATE_IDLE;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the UART peripheral.
+ //
+ while(((pUART->usIntStatus & pUART->usIntMask) != 0) &&
+ (pUART->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ pUART->pfnIntCallback();
+ }
+}
+
+//*****************************************************************************
+//
+//! Handles the assertion of the receive ``interrupt''.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function is used to determine when to assert the receive ``interrupt''
+//! as a result of writing data into the receive buffer (when characters are
+//! received from the Rx pin).
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxWriteInt(tSoftUART *pUART)
+{
+ unsigned long ulTemp;
+
+ //
+ // Determine the number of characters in the receive buffer.
+ //
+ if(pUART->usRxBufferWrite > pUART->usRxBufferRead)
+ {
+ ulTemp = pUART->usRxBufferWrite - pUART->usRxBufferRead;
+ }
+ else
+ {
+ ulTemp = (pUART->usRxBufferLen + pUART->usRxBufferWrite -
+ pUART->usRxBufferRead);
+ }
+
+ //
+ // If the receive buffer fullness just crossed the programmed level,
+ // generate a receive "interrupt".
+ //
+ if(ulTemp == pUART->usRxBufferLevel)
+ {
+ pUART->usIntStatus |= SOFTUART_INT_RX;
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs the periodic update of the SoftUART receiver.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param bEdgeInt should be \b true if this function is being called because
+//! of a GPIO edge interrupt and \b false if it is being called because of a
+//! timer interrupt.
+//!
+//! This function performs the periodic, time-based updates to the SoftUART
+//! receiver. The reception of data to the SoftUART is performed by the state
+//! machine in this function.
+//!
+//! This function must be called by the GPIO interrupt handler, and then
+//! periodically at the desired SoftUART baud rate. For example, to run the
+//! SoftUART at 115,200 baud, this function must be called at a 115,200 Hz
+//! rate.
+//!
+//! \return Returns \b SOFTUART_RXTIMER_NOP if the receive timer should
+//! continue to operate or \b SOFTUART_RXTIMER_END if it should be stopped.
+//
+//*****************************************************************************
+unsigned long
+SoftUARTRxTick(tSoftUART *pUART, tBoolean bEdgeInt)
+{
+ unsigned long ulPinState, ulTemp, ulRet;
+
+ //
+ // Read the current state of the Rx data line.
+ //
+ ulPinState = MAP_GPIOPinRead(pUART->ulRxGPIOPort, pUART->ucRxPin);
+
+ //
+ // The default return code inidicates that the receive timer does not need
+ // to be stopped.
+ //
+ ulRet = SOFTUART_RXTIMER_NOP;
+
+ //
+ // See if this is an edge interrupt while delaying for the receive timeout
+ // interrupt.
+ //
+ if(bEdgeInt && (pUART->ucRxState == SOFTUART_RXSTATE_DELAY))
+ {
+ //
+ // The receive timeout has been cancelled since the next character has
+ // started, so go to the idle state.
+ //
+ pUART->ucRxState = SOFTUART_RXSTATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the state machine.
+ //
+ switch(pUART->ucRxState)
+ {
+ //
+ // The state machine is idle.
+ //
+ case SOFTUART_RXSTATE_IDLE:
+ {
+ //
+ // The falling edge of the start bit was just sampled, so disable
+ // the GPIO edge interrupt since the remainder of the character
+ // will be read using a timer tick.
+ //
+ MAP_GPIOPinIntClear(pUART->ulRxGPIOPort, pUART->ucRxPin);
+ MAP_GPIOPinIntDisable(pUART->ulRxGPIOPort, pUART->ucRxPin);
+
+ //
+ // Clear the receive data buffer.
+ //
+ pUART->ucRxData = 0;
+
+ //
+ // Clear all reception errors other than overrun (which is cleared
+ // only when the first character after the overrun is written into
+ // the receive buffer), and set the break error (which is cleared
+ // if any non-zero bits are read during this character).
+ //
+ pUART->ucRxFlags = ((pUART->ucRxFlags & SOFTUART_RXFLAG_OE) |
+ SOFTUART_RXFLAG_BE);
+
+ //
+ // Advance to the first data bit state.
+ //
+ pUART->ucRxState = SOFTUART_RXSTATE_DATA_0;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte is read. This
+ // depends upon RXSTATE_DATA_n and RXSTATE_DATA_(n+1) being
+ // consecutively numbered.
+ //
+ case SOFTUART_RXSTATE_DATA_0:
+ case SOFTUART_RXSTATE_DATA_1:
+ case SOFTUART_RXSTATE_DATA_2:
+ case SOFTUART_RXSTATE_DATA_3:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ulPinState != 0)
+ {
+ //
+ // Set this bit of the received character.
+ //
+ pUART->ucRxData |= 1 << pUART->ucRxState;
+
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Advance to the next state.
+ //
+ pUART->ucRxState++;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // In each of these states, a bit of the data byte is read.
+ // Additionally, based on the configuration of the SoftUART, this bit
+ // might be the last bit of the data byte. This depends upon
+ // RXSTATE_DATA_n and RXSTATE_DATA_(n+1) being consecutively numbered.
+ //
+ case SOFTUART_RXSTATE_DATA_4:
+ case SOFTUART_RXSTATE_DATA_5:
+ case SOFTUART_RXSTATE_DATA_6:
+ case SOFTUART_RXSTATE_DATA_7:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ulPinState != 0)
+ {
+ //
+ // Set this bit of the received character.
+ //
+ pUART->ucRxData |= 1 << pUART->ucRxState;
+
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if the bit that was just transferred is the last bit of the
+ // data byte (based on the configuration of the SoftUART).
+ //
+ if(((pUART->usConfig & SOFTUART_CONFIG_WLEN_MASK) >>
+ SOFTUART_CONFIG_WLEN_S) ==
+ (pUART->ucRxState - SOFTUART_RXSTATE_DATA_4))
+ {
+ //
+ // See if parity is enabled.
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) !=
+ SOFTUART_CONFIG_PAR_NONE)
+ {
+ //
+ // Advance to the parity state.
+ //
+ pUART->ucRxState = SOFTUART_RXSTATE_PARITY;
+ }
+
+ //
+ // Otherwise, see if there are one or two stop bits.
+ //
+ else if((pUART->usConfig & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ pUART->ucRxState = SOFTUART_RXSTATE_STOP_0;
+ }
+
+ //
+ // Otherwise, advance to the one stop bit state.
+ //
+ else
+ {
+ pUART->ucRxState = SOFTUART_RXSTATE_STOP_1;
+ }
+ }
+
+ //
+ // Otherwise, there are more bits to receive.
+ //
+ else
+ {
+ //
+ // Advance to the next state.
+ //
+ pUART->ucRxState++;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the parity bit state.
+ //
+ case SOFTUART_RXSTATE_PARITY:
+ {
+ //
+ // See if the parity is set to one.
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ONE)
+ {
+ //
+ // Set the expected parity to one.
+ //
+ ulTemp = pUART->ucRxPin;
+ }
+
+ //
+ // Otherwise, see if the parity is set to zero.
+ //
+ else if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_ZERO)
+ {
+ //
+ // Set the expected parity to zero.
+ //
+ ulTemp = 0;
+ }
+
+ //
+ // Otherwise, there is either even or odd parity.
+ //
+ else
+ {
+ //
+ // Find the odd parity for the data byte.
+ //
+ ulTemp = ((g_pulParityOdd[pUART->ucRxData >> 5] &
+ (1 << (pUART->ucRxData & 31))) ?
+ pUART->ucRxPin : 0);
+
+ //
+ // If the parity is set to even, then invert the parity just
+ // computed (making it even parity).
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) ==
+ SOFTUART_CONFIG_PAR_EVEN)
+ {
+ ulTemp ^= pUART->ucRxPin;
+ }
+ }
+
+ //
+ // See if the pin state matches the expected parity.
+ //
+ if(ulPinState != ulTemp)
+ {
+ //
+ // The parity does not match, so set the parity error flag.
+ //
+ pUART->ucRxFlags |= SOFTUART_RXFLAG_PE;
+ }
+
+ //
+ // See if the Rx pin is high.
+ //
+ if(ulPinState != 0)
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if there are one or two stop bits.
+ //
+ if((pUART->usConfig & SOFTUART_CONFIG_STOP_MASK) ==
+ SOFTUART_CONFIG_STOP_TWO)
+ {
+ //
+ // Advance to the two stop bits state.
+ //
+ pUART->ucRxState = SOFTUART_RXSTATE_STOP_0;
+ }
+ else
+ {
+ //
+ // Advance to the one stop bit state.
+ //
+ pUART->ucRxState = SOFTUART_RXSTATE_STOP_1;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the two stop bits state.
+ //
+ case SOFTUART_RXSTATE_STOP_0:
+ {
+ //
+ // See if the Rx pin is low.
+ //
+ if(ulPinState == 0)
+ {
+ //
+ // Since the Rx pin is low, there is a framing error.
+ //
+ pUART->ucRxFlags |= SOFTUART_RXFLAG_FE;
+ }
+ else
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Advance to the one stop bit state.
+ //
+ pUART->ucRxState = SOFTUART_RXSTATE_STOP_1;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the one stop bit state.
+ //
+ case SOFTUART_RXSTATE_STOP_1:
+ {
+ //
+ // See if the Rx pin is low.
+ //
+ if(ulPinState == 0)
+ {
+ //
+ // Since the Rx pin is low, there is a framing error.
+ //
+ pUART->ucRxFlags |= SOFTUART_RXFLAG_FE;
+ }
+ else
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // See if the break error is still asserted (meaning that every bit
+ // received was zero).
+ //
+ if(pUART->ucRxFlags & SOFTUART_RXFLAG_BE)
+ {
+ //
+ // Since every bit was zero, advance to the break state.
+ //
+ pUART->ucRxState = SOFTUART_RXSTATE_BREAK;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // Compute the value of the write pointer advanced by one.
+ //
+ ulTemp = pUART->usRxBufferWrite + 1;
+ if(ulTemp == pUART->usRxBufferLen)
+ {
+ ulTemp = 0;
+ }
+
+ //
+ // See if there is space in the receive buffer.
+ //
+ if(ulTemp == pUART->usRxBufferRead)
+ {
+ //
+ // Set the overrun error flag. This will remain set until a
+ // new character can be placed into the receive buffer, which
+ // will then be given this status.
+ //
+ pUART->ucRxFlags |= SOFTUART_RXFLAG_OE;
+
+ //
+ // Set the receive overrun "interrupt" and status if it is not
+ // already set.
+ //
+ if(!(pUART->ucRxStatus & SOFTUART_RXERROR_OVERRUN))
+ {
+ pUART->ucRxStatus |= SOFTUART_RXERROR_OVERRUN;
+ pUART->usIntStatus |= SOFTUART_INT_OE;
+ }
+ }
+
+ //
+ // Otherwise, there is space in the receive buffer.
+ //
+ else
+ {
+ //
+ // Write this data byte, along with the receive flags, into the
+ // receive buffer.
+ //
+ pUART->pusRxBuffer[pUART->usRxBufferWrite] =
+ pUART->ucRxData | (pUART->ucRxFlags << 8);
+
+ //
+ // Advance the write pointer.
+ //
+ pUART->usRxBufferWrite = ulTemp;
+
+ //
+ // Clear the receive flags, most importantly the overrun flag
+ // since it was just written into the receive buffer.
+ //
+ pUART->ucRxFlags = 0;
+
+ //
+ // Assert the receive "interrupt" if appropriate.
+ //
+ SoftUARTRxWriteInt(pUART);
+ }
+
+ //
+ // See if this character had a parity error.
+ //
+ if(pUART->ucRxFlags & SOFTUART_RXFLAG_PE)
+ {
+ //
+ // Assert the parity error "interrupt".
+ //
+ pUART->usIntStatus |= SOFTUART_INT_PE;
+ }
+
+ //
+ // See if this character had a framing error.
+ //
+ if(pUART->ucRxFlags & SOFTUART_RXFLAG_FE)
+ {
+ //
+ // Assert the framing error "interrupt".
+ //
+ pUART->usIntStatus |= SOFTUART_INT_FE;
+ }
+
+ //
+ // Enable the falling edge interrupt on the Rx pin so that the next
+ // start bit can be detected.
+ //
+ MAP_GPIOPinIntClear(pUART->ulRxGPIOPort, pUART->ucRxPin);
+ MAP_GPIOPinIntEnable(pUART->ulRxGPIOPort, pUART->ucRxPin);
+
+ //
+ // Advance to the receive timeout delay state.
+ //
+ pUART->ucRxData = 0;
+ pUART->ucRxState = SOFTUART_RXSTATE_DELAY;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the break state.
+ //
+ case SOFTUART_RXSTATE_BREAK:
+ {
+ //
+ // See if the Rx pin is high.
+ //
+ if(ulPinState != 0)
+ {
+ //
+ // Clear the break error since a non-zero bit was received.
+ //
+ pUART->ucRxFlags &= ~(SOFTUART_RXFLAG_BE);
+ }
+
+ //
+ // Compute the value of the write pointer advanced by one.
+ //
+ ulTemp = pUART->usRxBufferWrite + 1;
+ if(ulTemp == pUART->usRxBufferLen)
+ {
+ ulTemp = 0;
+ }
+
+ //
+ // See if there is space in the receive buffer.
+ //
+ if(ulTemp == pUART->usRxBufferRead)
+ {
+ //
+ // Set the overrun error flag. This will remain set until a
+ // new character can be placed into the receive buffer, which
+ // will then be given this status.
+ //
+ pUART->ucRxFlags |= SOFTUART_RXFLAG_OE;
+
+ //
+ // Set the receive overrun "interrupt" and status if it is not
+ // already set.
+ //
+ if(!(pUART->ucRxStatus & SOFTUART_RXERROR_OVERRUN))
+ {
+ pUART->ucRxStatus |= SOFTUART_RXERROR_OVERRUN;
+ pUART->usIntStatus |= SOFTUART_INT_OE;
+ }
+ }
+
+ //
+ // Otherwise, there is space in the receive buffer.
+ //
+ else
+ {
+ //
+ // Write this data byte, along with the receive flags, into the
+ // receive buffer.
+ //
+ pUART->pusRxBuffer[pUART->usRxBufferWrite] =
+ pUART->ucRxData | (pUART->ucRxFlags << 8);
+
+ //
+ // Advance the write pointer.
+ //
+ pUART->usRxBufferWrite = ulTemp;
+
+ //
+ // Clear the receive flags, most importantly the overrun flag
+ // since it was just written into the receive buffer.
+ //
+ pUART->ucRxFlags = 0;
+
+ //
+ // Assert the receive "interrupt" if appropriate.
+ //
+ SoftUARTRxWriteInt(pUART);
+ }
+
+ //
+ // See if this was a break error.
+ //
+ if(pUART->ucRxFlags & SOFTUART_RXFLAG_BE)
+ {
+ //
+ // Assert the break error "interrupt".
+ //
+ pUART->usIntStatus |= SOFTUART_INT_BE;
+ }
+
+ //
+ // See if this character had a parity error.
+ //
+ if(pUART->ucRxFlags & SOFTUART_RXFLAG_PE)
+ {
+ //
+ // Assert the parity error "interrupt".
+ //
+ pUART->usIntStatus |= SOFTUART_INT_PE;
+ }
+
+ //
+ // Assert the framing error "interrupt".
+ //
+ pUART->usIntStatus |= SOFTUART_INT_FE;
+
+ //
+ // Enable the falling edge interrupt on the Rx pin so that the next
+ // start bit can be detected.
+ //
+ MAP_GPIOPinIntClear(pUART->ulRxGPIOPort, pUART->ucRxPin);
+ MAP_GPIOPinIntEnable(pUART->ulRxGPIOPort, pUART->ucRxPin);
+
+ //
+ // Advance to the receive timeout delay state.
+ //
+ pUART->ucRxData = 0;
+ pUART->ucRxState = SOFTUART_RXSTATE_DELAY;
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+
+ //
+ // The state machine is in the receive timeout delay state.
+ //
+ case SOFTUART_RXSTATE_DELAY:
+ {
+ //
+ // See if the receive timeout has expired.
+ //
+ if(pUART->ucRxData++ == 32)
+ {
+ //
+ // Assert the receive timeout "interrupt".
+ //
+ pUART->usIntStatus |= SOFTUART_INT_RT;
+
+ //
+ // Tell the caller that the receive timer can be disabled.
+ //
+ ulRet = SOFTUART_RXTIMER_END;
+ }
+
+ //
+ // This state has been handled.
+ //
+ break;
+ }
+ }
+
+ //
+ // Call the "interrupt" callback while there are enabled "interrupts"
+ // asserted. By calling in a loop until the "interrupts" are no longer
+ // asserted, this mimics the behavior of a real hardware implementation of
+ // the UART peripheral.
+ //
+ while(((pUART->usIntStatus & pUART->usIntMask) != 0) &&
+ (pUART->pfnIntCallback != 0))
+ {
+ //
+ // Call the callback function.
+ //
+ pUART->pfnIntCallback();
+ }
+
+ //
+ // Return to the caller.
+ //
+ return(ulRet);
+}
+
+//*****************************************************************************
+//
+//! Sets the type of parity.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ulParity specifies the type of parity to use.
+//!
+//! Sets the type of parity to use for transmitting and expect when receiving.
+//! The \e ulParity parameter must be one of \b SOFTUART_CONFIG_PAR_NONE,
+//! \b SOFTUART_CONFIG_PAR_EVEN, \b SOFTUART_CONFIG_PAR_ODD,
+//! \b SOFTUART_CONFIG_PAR_ONE, or \b SOFTUART_CONFIG_PAR_ZERO. The last two
+//! allow direct control of the parity bit; it is always either one or zero
+//! based on the mode.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTParityModeSet(tSoftUART *pUART, unsigned long ulParity)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ulParity == SOFTUART_CONFIG_PAR_NONE) ||
+ (ulParity == SOFTUART_CONFIG_PAR_EVEN) ||
+ (ulParity == SOFTUART_CONFIG_PAR_ODD) ||
+ (ulParity == SOFTUART_CONFIG_PAR_ONE) ||
+ (ulParity == SOFTUART_CONFIG_PAR_ZERO));
+
+ //
+ // Set the parity mode.
+ //
+ pUART->usConfig = (pUART->usConfig & SOFTUART_CONFIG_PAR_MASK) | ulParity;
+}
+
+//*****************************************************************************
+//
+//! Gets the type of parity currently being used.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function gets the type of parity used for transmitting data and
+//! expected when receiving data.
+//!
+//! \return Returns the current parity settings, specified as one of
+//! \b SOFTUART_CONFIG_PAR_NONE, \b SOFTUART_CONFIG_PAR_EVEN,
+//! \b SOFTUART_CONFIG_PAR_ODD, \b SOFTUART_CONFIG_PAR_ONE, or
+//! \b SOFTUART_CONFIG_PAR_ZERO.
+//
+//*****************************************************************************
+unsigned long
+SoftUARTParityModeGet(tSoftUART *pUART)
+{
+ //
+ // Return the current parity setting.
+ //
+ return(pUART->usConfig & SOFTUART_CONFIG_PAR_MASK);
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit ``interrupt'' buffer level.
+//!
+//! \param pUART specifies the soft UART data structure.
+//!
+//! This function computes the transmit buffer level at which the transmit
+//! ``interrupt'' is generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTTxLevelSet(tSoftUART *pUART)
+{
+ //
+ // Determine the transmit buffer "interrupt" fullness setting.
+ //
+ switch(pUART->usConfig & SOFTUART_CONFIG_TXLVL_M)
+ {
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/8
+ // full.
+ //
+ case SOFTUART_CONFIG_TXLVL_1:
+ {
+ //
+ // Set the transmit buffer level to 1/8 of the buffer length.
+ //
+ pUART->usTxBufferLevel = pUART->usTxBufferLen / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/4
+ // (2/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_2:
+ {
+ //
+ // Set the transmit buffer level to 1/4 of the buffer length.
+ //
+ pUART->usTxBufferLevel = pUART->usTxBufferLen / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 1/2
+ // (4/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_4:
+ {
+ //
+ // Set the transmit buffer level to 1/2 of the buffer length.
+ //
+ pUART->usTxBufferLevel = pUART->usTxBufferLen / 2;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 3/4
+ // (6/8) full.
+ //
+ case SOFTUART_CONFIG_TXLVL_6:
+ {
+ //
+ // Set the transmit buffer level to 3/4 of the buffer length.
+ //
+ pUART->usTxBufferLevel = (pUART->usTxBufferLen * 3) / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The transmit "interrupt" should be generated when the buffer is 7/8
+ // full.
+ //
+ case SOFTUART_CONFIG_TXLVL_7:
+ {
+ //
+ // Set the transmit buffer level to 7/8 of the buffer length.
+ //
+ pUART->usTxBufferLevel = (pUART->usTxBufferLen * 7) / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the receive ``interrupt'' buffer level.
+//!
+//! \param pUART specifies the soft UART data structure.
+//!
+//! This function computes the receive buffer level at which the receive
+//! ``interrupt'' is generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxLevelSet(tSoftUART *pUART)
+{
+ //
+ // Determine the receive buffer "interrupt" fullness setting.
+ //
+ switch(pUART->usConfig & SOFTUART_CONFIG_RXLVL_M)
+ {
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/8
+ // full.
+ //
+ case SOFTUART_CONFIG_RXLVL_1:
+ {
+ //
+ // Set the receive buffer level to 1/8 of the buffer length.
+ //
+ pUART->usRxBufferLevel = pUART->usRxBufferLen / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/4
+ // (2/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_2:
+ {
+ //
+ // Set the receive buffer level to 1/4 of the buffer length.
+ //
+ pUART->usRxBufferLevel = pUART->usRxBufferLen / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 1/2
+ // (4/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_4:
+ {
+ //
+ // Set the receive buffer level to 1/2 of the buffer length.
+ //
+ pUART->usRxBufferLevel = pUART->usRxBufferLen / 2;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 3/4
+ // (6/8) full.
+ //
+ case SOFTUART_CONFIG_RXLVL_6:
+ {
+ //
+ // Set the receive buffer level to 3/4 of the buffer length.
+ //
+ pUART->usRxBufferLevel = (pUART->usRxBufferLen * 3) / 4;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+
+ //
+ // The receive "interrupt" should be generated when the buffer is 7/8
+ // full.
+ //
+ case SOFTUART_CONFIG_RXLVL_7:
+ {
+ //
+ // Set the receive buffer level to 7/8 of the buffer length.
+ //
+ pUART->usRxBufferLevel = (pUART->usRxBufferLen * 7) / 8;
+
+ //
+ // This setting has been handled.
+ //
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the buffer level at which ``interrupts'' are generated.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ulTxLevel is the transmit buffer ``interrupt'' level, specified as
+//! one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8, \b UART_FIFO_TX4_8,
+//! \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8.
+//! \param ulRxLevel is the receive buffer ``interrupt'' level, specified as
+//! one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8, \b UART_FIFO_RX4_8,
+//! \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8.
+//!
+//! This function sets the buffer level at which transmit and receive
+//! ``interrupts'' are generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTFIFOLevelSet(tSoftUART *pUART, unsigned long ulTxLevel,
+ unsigned long ulRxLevel)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ulTxLevel == SOFTUART_FIFO_TX1_8) ||
+ (ulTxLevel == SOFTUART_FIFO_TX2_8) ||
+ (ulTxLevel == SOFTUART_FIFO_TX4_8) ||
+ (ulTxLevel == SOFTUART_FIFO_TX6_8) ||
+ (ulTxLevel == SOFTUART_FIFO_TX7_8));
+ ASSERT((ulRxLevel == SOFTUART_FIFO_RX1_8) ||
+ (ulRxLevel == SOFTUART_FIFO_RX2_8) ||
+ (ulRxLevel == SOFTUART_FIFO_RX4_8) ||
+ (ulRxLevel == SOFTUART_FIFO_RX6_8) ||
+ (ulRxLevel == SOFTUART_FIFO_RX7_8));
+
+ //
+ // Save the buffer "interrupt" levels.
+ //
+ pUART->usConfig = ((pUART->usConfig & SOFTUART_CONFIG_BASE_M) |
+ ((ulTxLevel | ulRxLevel) << 8));
+
+ //
+ // Compute the new buffer "interrupt" levels.
+ //
+ SoftUARTTxLevelSet(pUART);
+ SoftUARTRxLevelSet(pUART);
+}
+
+//*****************************************************************************
+//
+//! Gets the buffer level at which ``interrupts'' are generated.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param pulTxLevel is a pointer to storage for the transmit buffer level,
+//! returned as one of \b UART_FIFO_TX1_8, \b UART_FIFO_TX2_8,
+//! \b UART_FIFO_TX4_8, \b UART_FIFO_TX6_8, or \b UART_FIFO_TX7_8.
+//! \param pulRxLevel is a pointer to storage for the receive buffer level,
+//! returned as one of \b UART_FIFO_RX1_8, \b UART_FIFO_RX2_8,
+//! \b UART_FIFO_RX4_8, \b UART_FIFO_RX6_8, or \b UART_FIFO_RX7_8.
+//!
+//! This function gets the buffer level at which transmit and receive
+//! ``interrupts'' are generated.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTFIFOLevelGet(tSoftUART *pUART, unsigned long *pulTxLevel,
+ unsigned long *pulRxLevel)
+{
+ //
+ // Extract the transmit and receive buffer levels.
+ //
+ *pulTxLevel = (pUART->usConfig & SOFTUART_CONFIG_TXLVL_M) >> 8;
+ *pulRxLevel = (pUART->usConfig & SOFTUART_CONFIG_RXLVL_M) >> 8;
+}
+
+//*****************************************************************************
+//
+//! Gets the current configuration of a UART.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param pulConfig is a pointer to storage for the data format.
+//!
+//! Returns the data format of the SoftUART. The data format returned in
+//! \e pulConfig is enumerated the same as the \e ulConfig parameter of
+//! SoftUARTConfigSet().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTConfigGet(tSoftUART *pUART, unsigned long *pulConfig)
+{
+ //
+ // Get the data format.
+ //
+ *pulConfig = pUART->usConfig & SOFTUART_CONFIG_BASE_M;
+}
+
+//*****************************************************************************
+//
+//! Enables the SoftUART.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function enables the SoftUART, allowing data to be transmitted and
+//! received.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTEnable(tSoftUART *pUART)
+{
+ //
+ // Enable the SoftUART.
+ //
+ pUART->ucFlags |= SOFTUART_FLAG_ENABLE;
+}
+
+//*****************************************************************************
+//
+//! Disables the SoftUART.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function disables the SoftUART after waiting for it to become idle.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTDisable(tSoftUART *pUART)
+{
+ //
+ // Wait for end of TX.
+ //
+ while(SoftUARTBusy(pUART))
+ {
+ }
+
+ //
+ // Disable the SoftUART.
+ //
+ pUART->ucFlags &= ~(SOFTUART_FLAG_ENABLE);
+}
+
+//*****************************************************************************
+//
+//! Determines if there are any characters in the receive buffer.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function returns a flag indicating whether or not there is data
+//! available in the receive buffer.
+//!
+//! \return Returns \b true if there is data in the receive buffer or \b false
+//! if there is no data in the receive buffer.
+//
+//*****************************************************************************
+tBoolean
+SoftUARTCharsAvail(tSoftUART *pUART)
+{
+ //
+ // Return the availability of characters.
+ //
+ return((pUART->usRxBufferRead == pUART->usRxBufferWrite) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Determines if there is any space in the transmit buffer.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function returns a flag indicating whether or not there is space
+//! available in the transmit buffer.
+//!
+//! \return Returns \b true if there is space available in the transmit buffer
+//! or \b false if there is no space available in the transmit buffer.
+//
+//*****************************************************************************
+tBoolean
+SoftUARTSpaceAvail(tSoftUART *pUART)
+{
+ unsigned short usTemp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ usTemp = pUART->usTxBufferWrite + 1;
+ if(usTemp == pUART->usTxBufferLen)
+ {
+ usTemp = 0;
+ }
+
+ //
+ // Return the availability of space.
+ //
+ return((pUART->usTxBufferRead == usTemp) ? false : true);
+}
+
+//*****************************************************************************
+//
+//! Handles the deassertion of the receive ``interrupts''.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function is used to determine when to deassert the receive
+//! ``interrupt'' as a result of reading data from the receive buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+static void
+SoftUARTRxReadInt(tSoftUART *pUART)
+{
+ unsigned long ulTemp;
+
+ //
+ // Determine the number of characters in the receive buffer.
+ //
+ if(pUART->usRxBufferWrite > pUART->usRxBufferRead)
+ {
+ ulTemp = pUART->usRxBufferWrite - pUART->usRxBufferRead;
+ }
+ else
+ {
+ ulTemp = (pUART->usRxBufferLen + pUART->usRxBufferWrite -
+ pUART->usRxBufferRead);
+ }
+
+ //
+ // See if the number of characters in the receive buffer have dropped below
+ // the receive trigger level.
+ //
+ if(ulTemp < pUART->usRxBufferLevel)
+ {
+ //
+ // Deassert the receive "interrupt".
+ //
+ pUART->usIntStatus &= ~(SOFTUART_INT_RX);
+ }
+
+ //
+ // See if the receive buffer is now empty.
+ //
+ if(ulTemp == 0)
+ {
+ //
+ // Deassert the receive timeout "interrupt".
+ //
+ pUART->usIntStatus &= ~(SOFTUART_INT_RT);
+ }
+}
+
+//*****************************************************************************
+//
+//! Receives a character from the specified port.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! Gets a character from the receive buffer for the specified port.
+//!
+//! \return Returns the character read from the specified port, cast as a
+//! \e long. A \b -1 isreturned if there are no characters present in the
+//! receive buffer. The SoftUARTCharsAvail() function should be called before
+//! attempting to call this function.
+//
+//*****************************************************************************
+long
+SoftUARTCharGetNonBlocking(tSoftUART *pUART)
+{
+ long lTemp;
+
+ //
+ // See if there are any characters in the receive buffer.
+ //
+ if(pUART->usRxBufferRead != pUART->usRxBufferWrite)
+ {
+ //
+ // Read the next character.
+ //
+ lTemp = pUART->pusRxBuffer[pUART->usRxBufferRead];
+ pUART->usRxBufferRead++;
+ if(pUART->usRxBufferRead == pUART->usRxBufferLen)
+ {
+ pUART->usRxBufferRead = 0;
+ }
+
+ //
+ // Deassert the receive "interrupt(s)" if appropriate.
+ //
+ SoftUARTRxReadInt(pUART);
+
+ //
+ // Set the receive status to match this character.
+ //
+ pUART->ucRxStatus = ((pUART->ucRxStatus & SOFTUART_RXERROR_OVERRUN) |
+ ((lTemp >> 8) & ~(SOFTUART_RXERROR_OVERRUN)));
+
+ //
+ // Return this character.
+ //
+ return(lTemp);
+ }
+ else
+ {
+ //
+ // There are no characters, so return a failure.
+ //
+ return(-1);
+ }
+}
+
+//*****************************************************************************
+//
+//! Waits for a character from the specified port.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! Gets a character from the receive buffer for the specified port. If there
+//! are no characters available, this function waits until a character is
+//! received before returning.
+//!
+//! \return Returns the character read from the specified port, cast as a
+//! \e long.
+//
+//*****************************************************************************
+long
+SoftUARTCharGet(tSoftUART *pUART)
+{
+ long lTemp;
+
+ //
+ // Wait until a char is available.
+ //
+ while(pUART->usRxBufferRead ==
+ *(volatile unsigned short *)(&(pUART->usRxBufferWrite)))
+ {
+ }
+
+ //
+ // Read the next character.
+ //
+ lTemp = pUART->pusRxBuffer[pUART->usRxBufferRead];
+ pUART->usRxBufferRead++;
+ if(pUART->usRxBufferRead == pUART->usRxBufferLen)
+ {
+ pUART->usRxBufferRead = 0;
+ }
+
+ //
+ // Deassert the receive "interrupt(s)" if appropriate.
+ //
+ SoftUARTRxReadInt(pUART);
+
+ //
+ // Set the receive status to match this character.
+ //
+ pUART->ucRxStatus = ((pUART->ucRxStatus & SOFTUART_RXERROR_OVERRUN) |
+ ((lTemp >> 8) & ~(SOFTUART_RXERROR_OVERRUN)));
+
+ //
+ // Return this character.
+ //
+ return(lTemp);
+}
+
+//*****************************************************************************
+//
+//! Sends a character to the specified port.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ucData is the character to be transmitted.
+//!
+//! Writes the character \e ucData to the transmit buffer for the specified
+//! port. This function does not block, so if there is no space available,
+//! then a \b false is returned, and the application must retry the function
+//! later.
+//!
+//! \return Returns \b true if the character was successfully placed in the
+//! transmit buffer or \b false if there was no space available in the
+//! transmit buffer.
+//
+//*****************************************************************************
+tBoolean
+SoftUARTCharPutNonBlocking(tSoftUART *pUART, unsigned char ucData)
+{
+ unsigned short usTemp;
+
+ //
+ // Determine the values of the write pointer once incremented.
+ //
+ usTemp = pUART->usTxBufferWrite + 1;
+ if(usTemp == pUART->usTxBufferLen)
+ {
+ usTemp = 0;
+ }
+
+ //
+ // See if there is space in the transmit buffer.
+ //
+ if(usTemp != pUART->usTxBufferRead)
+ {
+ //
+ // Write this character to the transmit buffer.
+ //
+ pUART->pucTxBuffer[pUART->usTxBufferWrite] = ucData;
+ pUART->usTxBufferWrite = usTemp;
+
+ //
+ // Success.
+ //
+ return(true);
+ }
+ else
+ {
+ //
+ // There is no space in the transmit buffer, so return a failure.
+ //
+ return(false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Waits to send a character from the specified port.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ucData is the character to be transmitted.
+//!
+//! Sends the character \e ucData to the transmit buffer for the specified
+//! port. If there is no space available in the transmit buffer, this function
+//! waits until there is space available before returning.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTCharPut(tSoftUART *pUART, unsigned char ucData)
+{
+ unsigned short usTemp;
+
+ //
+ // Wait until space is available.
+ //
+ usTemp = pUART->usTxBufferWrite + 1;
+ if(usTemp == pUART->usTxBufferLen)
+ {
+ usTemp = 0;
+ }
+ while(usTemp == *(volatile unsigned short *)(&(pUART->usTxBufferRead)))
+ {
+ }
+
+ //
+ // Send the char.
+ //
+ pUART->pucTxBuffer[pUART->usTxBufferWrite] = ucData;
+ pUART->usTxBufferWrite = usTemp;
+}
+
+//*****************************************************************************
+//
+//! Causes a BREAK to be sent.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param bBreakState controls the output level.
+//!
+//! Calling this function with \e bBreakState set to \b true asserts a break
+//! condition on the SoftUART. Calling this function with \e bBreakState set
+//! to \b false removes the break condition. For proper transmission of a
+//! break command, the break must be asserted for at least two complete frames.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTBreakCtl(tSoftUART *pUART, tBoolean bBreakState)
+{
+ //
+ // Set the break condition as requested.
+ //
+ if(bBreakState)
+ {
+ pUART->ucFlags |= SOFTUART_FLAG_TXBREAK;
+ }
+ else
+ {
+ pUART->ucFlags &= ~(SOFTUART_FLAG_TXBREAK);
+ }
+}
+
+//*****************************************************************************
+//
+//! Determines whether the UART transmitter is busy or not.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! Allows the caller to determine whether all transmitted bytes have cleared
+//! the transmitter hardware. If \b false is returned, the transmit buffer is
+//! empty and all bits of the last transmitted character, including all stop
+//! bits, have left the hardware shift register.
+//!
+//! \return Returns \b true if the UART is transmitting or \b false if all
+//! transmissions are complete.
+//
+//*****************************************************************************
+tBoolean
+SoftUARTBusy(tSoftUART *pUART)
+{
+ //
+ // Determine if the UART is busy.
+ //
+ return(((pUART->ucTxState == SOFTUART_TXSTATE_IDLE) &&
+ (((pUART->ucFlags & SOFTUART_FLAG_ENABLE) == 0) ||
+ (pUART->usTxBufferRead == pUART->usTxBufferWrite))) ?
+ false : true);
+}
+
+//*****************************************************************************
+//
+//! Enables individual SoftUART ``interrupt'' sources.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ulIntFlags is the bit mask of the ``interrupt'' sources to be
+//! enabled.
+//!
+//! Enables the indicated SoftUART ``interrupt'' sources. Only the sources
+//! that are enabled can be reflected to the SoftUART callback.
+//!
+//! The \e ulIntFlags parameter is the logical OR of any of the following:
+//!
+//! - \b SOFTUART_INT_OE - Overrun Error ``interrupt''
+//! - \b SOFTUART_INT_BE - Break Error ``interrupt''
+//! - \b SOFTUART_INT_PE - Parity Error ``interrupt''
+//! - \b SOFTUART_INT_FE - Framing Error ``interrupt''
+//! - \b SOFTUART_INT_RT - Receive Timeout ``interrupt''
+//! - \b SOFTUART_INT_TX - Transmit ``interrupt''
+//! - \b SOFTUART_INT_RX - Receive ``interrupt''
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntEnable(tSoftUART *pUART, unsigned long ulIntFlags)
+{
+ //
+ // Enable the specified interrupts.
+ //
+ pUART->usIntMask |= ulIntFlags;
+}
+
+//*****************************************************************************
+//
+//! Disables individual SoftUART ``interrupt'' sources.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ulIntFlags is the bit mask of the ``interrupt'' sources to be
+//! disabled.
+//!
+//! Disables the indicated SoftUART ``interrupt'' sources. Only the sources
+//! that are enabled can be reflected to the SoftUART callback.
+//!
+//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags
+//! parameter to SoftUARTIntEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntDisable(tSoftUART *pUART, unsigned long ulIntFlags)
+{
+ //
+ // Disable the specified interrupts.
+ //
+ pUART->usIntMask &= ~(ulIntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets the current SoftUART ``interrupt'' status.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param bMasked is \b false if the raw ``interrupt'' status is required and
+//! \b true if the masked ``interrupt'' status is required.
+//!
+//! This returns the ``interrupt'' status for the SoftUART. Either the raw
+//! ``interrupt'' status or the status of ``interrupts'' that are allowed to
+//! reflect to the SoftUART callback can be returned.
+//!
+//! \return Returns the current ``interrupt'' status, enumerated as a bit field
+//! of values described in SoftUARTIntEnable().
+//
+//*****************************************************************************
+unsigned long
+SoftUARTIntStatus(tSoftUART *pUART, tBoolean bMasked)
+{
+ //
+ // Return either the interrupt status or the raw interrupt status as
+ // requested.
+ //
+ if(bMasked)
+ {
+ return(pUART->usIntStatus & pUART->usIntMask);
+ }
+ else
+ {
+ return(pUART->usIntStatus);
+ }
+}
+
+//*****************************************************************************
+//
+//! Clears SoftUART ``interrupt'' sources.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ulIntFlags is a bit mask of the ``interrupt'' sources to be cleared.
+//!
+//! The specified SoftUART ``interrupt'' sources are cleared, so that they no
+//! longer assert. This function must be called in the callback function to
+//! keep the ``interrupt'' from being recognized again immediately upon exit.
+//!
+//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags
+//! parameter to SoftUARTIntEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTIntClear(tSoftUART *pUART, unsigned long ulIntFlags)
+{
+ //
+ // Clear the requested interrupt sources.
+ //
+ pUART->usIntStatus &= ~(ulIntFlags);
+}
+
+//*****************************************************************************
+//
+//! Gets current receiver errors.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function returns the current state of each of the 4 receiver error
+//! sources. The returned errors are equivalent to the four error bits
+//! returned via the previous call to SoftUARTCharGet() or
+//! SoftUARTCharGetNonBlocking() with the exception that the overrun error is
+//! set immediately when the overrun occurs rather than when a character is
+//! next read.
+//!
+//! \return Returns a logical OR combination of the receiver error flags,
+//! \b SOFTUART_RXERROR_FRAMING, \b SOFTUART_RXERROR_PARITY,
+//! \b SOFTUART_RXERROR_BREAK and \b SOFTUART_RXERROR_OVERRUN.
+//
+//*****************************************************************************
+unsigned long
+SoftUARTRxErrorGet(tSoftUART *pUART)
+{
+ //
+ // Return the current value of the receive status.
+ //
+ return(pUART->ucRxStatus);
+}
+
+//*****************************************************************************
+//
+//! Clears all reported receiver errors.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//!
+//! This function is used to clear all receiver error conditions reported via
+//! SoftUARTRxErrorGet(). If using the overrun, framing error, parity error or
+//! break interrupts, this function must be called after clearing the interrupt
+//! to ensure that later errors of the same type trigger another interrupt.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxErrorClear(tSoftUART *pUART)
+{
+ //
+ // Clear any receive error status.
+ //
+ pUART->ucRxStatus = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the callback used by the SoftUART module.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param pfnCallback is a pointer to the callback function.
+//!
+//! This function sets the address of the callback function that is called when
+//! there is an ``interrupt'' produced by the SoftUART module.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTCallbackSet(tSoftUART *pUART, void (*pfnCallback)(void))
+{
+ //
+ // Save the callback function address.
+ //
+ pUART->pfnIntCallback = pfnCallback;
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftUART Tx signal.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ulBase is the base address of the GPIO module.
+//! \param ucPin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used when the SoftUART must assert
+//! the Tx signal.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxGPIOSet(tSoftUART *pUART, unsigned long ulBase, unsigned char ucPin)
+{
+ //
+ // Save the base address and pin for the Tx signal.
+ //
+ if(ulBase == 0)
+ {
+ pUART->ulTxGPIO = 0;
+ }
+ else
+ {
+ pUART->ulTxGPIO = ulBase + (ucPin << 2);
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the GPIO pin to be used as the SoftUART Rx signal.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param ulBase is the base address of the GPIO module.
+//! \param ucPin is the bit-packed representation of the pin to use.
+//!
+//! This function sets the GPIO pin that is used when the SoftUART must sample
+//! the Rx signal. If there is not a GPIO pin allocated for Rx, the SoftUART
+//! module will not read data from the slave device.
+//!
+//! The pin is specified using a bit-packed byte, where bit 0 of the byte
+//! represents GPIO port pin 0, bit 1 represents GPIO port pin 1, and so on.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxGPIOSet(tSoftUART *pUART, unsigned long ulBase, unsigned char ucPin)
+{
+ //
+ // Save the base address and pin for the Rx signal.
+ //
+ if(ulBase == 0)
+ {
+ pUART->ulRxGPIOPort = 0;
+ pUART->ucRxPin = 0;
+ }
+ else
+ {
+ pUART->ulRxGPIOPort = ulBase;
+ pUART->ucRxPin = ucPin;
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the transmit buffer for a SoftUART module.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param pucTxBuffer is the address of the transmit buffer.
+//! \param usLen is the size, in 8-bit bytes, of the transmit buffer.
+//!
+//! This function sets the address and size of the transmit buffer. It also
+//! resets the read and write pointers, marking the transmit buffer as empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTTxBufferSet(tSoftUART *pUART, unsigned char *pucTxBuffer,
+ unsigned short usLen)
+{
+ //
+ // Save the transmit buffer address and length.
+ //
+ pUART->pucTxBuffer = pucTxBuffer;
+ pUART->usTxBufferLen = usLen;
+
+ //
+ // Reset the transmit buffer read and write pointers.
+ //
+ pUART->usTxBufferRead = 0;
+ pUART->usTxBufferWrite = 0;
+
+ //
+ // Compute the new buffer "interrupt" level.
+ //
+ SoftUARTTxLevelSet(pUART);
+}
+
+//*****************************************************************************
+//
+//! Sets the receive buffer for a SoftUART module.
+//!
+//! \param pUART specifies the SoftUART data structure.
+//! \param pusRxBuffer is the address of the receive buffer.
+//! \param usLen is the size, in 16-bit half-words, of the receive buffer.
+//!
+//! This function sets the address and size of the receive buffer. It also
+//! resets the read and write pointers, marking the receive buffer as empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SoftUARTRxBufferSet(tSoftUART *pUART, unsigned short *pusRxBuffer,
+ unsigned short usLen)
+{
+ //
+ // Save the receive buffer address and length.
+ //
+ pUART->pusRxBuffer = pusRxBuffer;
+ pUART->usRxBufferLen = usLen;
+
+ //
+ // Reset the receive read and write pointers.
+ //
+ pUART->usRxBufferRead = 0;
+ pUART->usRxBufferWrite = 0;
+
+ //
+ // Compute the new buffer "interrupt" level.
+ //
+ SoftUARTRxLevelSet(pUART);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/softuart.h b/utils/softuart.h
new file mode 100644
index 0000000..477ca86
--- /dev/null
+++ b/utils/softuart.h
@@ -0,0 +1,374 @@
+//*****************************************************************************
+//
+// softuart.h - Defines and macros for the SoftUART.
+//
+// Copyright (c) 2010-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __SOFTUART_H__
+#define __SOFTUART_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup softuart_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! This structure contains the state of a single instance of a SoftUART
+//! module.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The address of the callback function that is called to simulate the
+ //! interrupts that would be produced by a hardware UART implementation.
+ //! This address can be set via a direct structure access or using the
+ //! SoftUARTCallbackSet function.
+ //
+ void (*pfnIntCallback)(void);
+
+ //
+ //! The address of the GPIO pin to be used for the Tx signal. This member
+ //! can be set via a direct structure access or using the SoftUARTTxGPIOSet
+ //! function.
+ //
+ unsigned long ulTxGPIO;
+
+ //
+ //! The address of the GPIO port to be used for the Rx signal. This member
+ //! can be set via a direct structure access or using the SoftUARTRxGPIOSet
+ //! function.
+ //
+ unsigned long ulRxGPIOPort;
+
+ //
+ //! The address of the data buffer used for the transmit buffer. This
+ //! member can be set via a direct structure access or using the
+ //! SoftUARTTxBufferSet function.
+ //
+ unsigned char *pucTxBuffer;
+
+ //
+ //! The address of the data buffer used for the receive buffer. This
+ //! member can be set via a direct structure access or using the
+ //! SoftUARTRxBufferSet function.
+ //
+ unsigned short *pusRxBuffer;
+
+ //
+ //! The length of the transmit buffer. This member can be set via a direct
+ //! structure access or using the SoftUARTTxBufferSet function.
+ //
+ unsigned short usTxBufferLen;
+
+ //
+ //! The index into the transmit buffer of the next character to be
+ //! transmitted. This member should not be accessed or modified by the
+ //! application.
+ //
+ unsigned short usTxBufferRead;
+
+ //
+ //! The index into the transmit buffer of the next location to store a
+ //! character into the buffer. This member should not be accessed or
+ //! modified by the application.
+ //
+ unsigned short usTxBufferWrite;
+
+ //
+ //! The transmit buffer level at which the transmit interrupt is asserted.
+ //! This member should not be accessed or modified by the application.
+ //
+ unsigned short usTxBufferLevel;
+
+ //
+ //! The length of the receive buffer. This member can be set via a direct
+ //! structure access or using the SoftUARTRxBufferSet function.
+ //
+ unsigned short usRxBufferLen;
+
+ //
+ //! The index into the receive buffer of the next character to be read from
+ //! the buffer. This member should not be accessed or modified by the
+ //! application.
+ //
+ unsigned short usRxBufferRead;
+
+ //
+ //! The index into the receive buffer of the lcoation to store the next
+ //! character received. This member should not be accessed or modified by
+ //! the application.
+ //
+ unsigned short usRxBufferWrite;
+
+ //
+ //! The receive buffer level at which the receive interrupt is asserted.
+ //! This member should not be accessed or modified by the application.
+ //
+ unsigned short usRxBufferLevel;
+
+ //
+ //! The set of virtual interrupts that are currently asserted. This member
+ //! should not be accessed or modified by the application.
+ //
+ unsigned short usIntStatus;
+
+ //
+ //! The set of virtual interrupts that should be sent to the callback
+ //! function. This member should not be accessed or modified by the
+ //! application.
+ //
+ unsigned short usIntMask;
+
+ //
+ //! The configuration of the SoftUART module. This member can be set via
+ //! the SoftUARTConfigSet and SoftUARTFIFOLevelSet functions.
+ //
+ unsigned short usConfig;
+
+ //
+ //! The flags that control the operation of the SoftUART module. This
+ //! member should not be be accessed or modified by the application.
+ //
+ unsigned char ucFlags;
+
+ //
+ //! The current state of the SoftUART transmit state machine. This member
+ //! should not be accessed or modified by the application.
+ //
+ unsigned char ucTxState;
+
+ //
+ //! The value that is written to the Tx pin at the start of the next
+ //! transmit timer tick. This member should not be accessed or modified
+ //! by the application.
+ //
+ unsigned char ucTxNext;
+
+ //
+ //! The character that is currently be sent via the Tx pin. This member
+ //! should not be accessed or modified by the application.
+ //
+ unsigned char ucTxData;
+
+ //
+ //! The GPIO pin to be used for the Rx signal. This member can be set via
+ //! a direct structure access or using the SoftUARTRxGPIOSet function.
+ //
+ unsigned char ucRxPin;
+
+ //
+ //! The current state of the SoftUART receive state machine. This member
+ //! should not be accessed or modified by the application.
+ //
+ unsigned char ucRxState;
+
+ //
+ //! The character that is currently being received via the Rx pin. This
+ //! member should not be accessed or modified by the application.
+ //
+ unsigned char ucRxData;
+
+ //
+ //! The flags that indicate any errors that have occurred during the
+ //! reception of the current character via the Rx pin. This member should
+ //! not be accessed or modified by the application.
+ //
+ unsigned char ucRxFlags;
+
+ //
+ //! The receive error status. This member should only be accessed via the
+ //! SoftUARTRxErrorGet and SoftURATRxErrorClear functions.
+ //
+ unsigned char ucRxStatus;
+}
+tSoftUART;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTIntEnable, SoftUARTIntDisable, and
+// SoftUARTIntClear as the ulIntFlags parameter, and returned from
+// SoftUARTIntStatus.
+//
+//*****************************************************************************
+#define SOFTUART_INT_EOT 0x800 // End of transmission interrupt
+#define SOFTUART_INT_OE 0x400 // Overrun error interrupt
+#define SOFTUART_INT_BE 0x200 // Break error interrupt
+#define SOFTUART_INT_PE 0x100 // Parity error interrupt
+#define SOFTUART_INT_FE 0x080 // Framing error interrupt
+#define SOFTUART_INT_RT 0x040 // Receive timeout interrupt
+#define SOFTUART_INT_TX 0x020 // Transmit interrupt
+#define SOFTUART_INT_RX 0x010 // Receive interrupt
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTConfigSet as the ulConfig parameter and
+// returned by SoftUARTConfigGet in the pulConfig parameter. Additionally, the
+// UART_CONFIG_PAR_* subset can be passed to SoftUARTParityModeSet as the
+// ulParity parameter, and are returned by SoftUARTParityModeGet.
+//
+//*****************************************************************************
+#define SOFTUART_CONFIG_WLEN_MASK \
+ 0x00000060 // Mask for extracting word length
+#define SOFTUART_CONFIG_WLEN_8 0x00000060 // 8 bit data
+#define SOFTUART_CONFIG_WLEN_7 0x00000040 // 7 bit data
+#define SOFTUART_CONFIG_WLEN_6 0x00000020 // 6 bit data
+#define SOFTUART_CONFIG_WLEN_5 0x00000000 // 5 bit data
+#define SOFTUART_CONFIG_STOP_MASK \
+ 0x00000008 // Mask for extracting stop bits
+#define SOFTUART_CONFIG_STOP_ONE \
+ 0x00000000 // One stop bit
+#define SOFTUART_CONFIG_STOP_TWO \
+ 0x00000008 // Two stop bits
+#define SOFTUART_CONFIG_PAR_MASK \
+ 0x00000086 // Mask for extracting parity
+#define SOFTUART_CONFIG_PAR_NONE \
+ 0x00000000 // No parity
+#define SOFTUART_CONFIG_PAR_EVEN \
+ 0x00000006 // Even parity
+#define SOFTUART_CONFIG_PAR_ODD 0x00000002 // Odd parity
+#define SOFTUART_CONFIG_PAR_ONE 0x00000082 // Parity bit is one
+#define SOFTUART_CONFIG_PAR_ZERO \
+ 0x00000086 // Parity bit is zero
+#define SOFTUART_CONFIG_WLEN_S 5
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTFIFOLevelSet as the ulTxLevel parameter
+// and returned by SoftUARTFIFOLevelGet in the pulTxLevel.
+//
+//*****************************************************************************
+#define SOFTUART_FIFO_TX1_8 0x00000000 // Transmit interrupt at 1/8 Full
+#define SOFTUART_FIFO_TX2_8 0x00000001 // Transmit interrupt at 1/4 Full
+#define SOFTUART_FIFO_TX4_8 0x00000002 // Transmit interrupt at 1/2 Full
+#define SOFTUART_FIFO_TX6_8 0x00000003 // Transmit interrupt at 3/4 Full
+#define SOFTUART_FIFO_TX7_8 0x00000004 // Transmit interrupt at 7/8 Full
+
+//*****************************************************************************
+//
+// Values that can be passed to SoftUARTFIFOLevelSet as the ulRxLevel parameter
+// and returned by SoftUARTFIFOLevelGet in the pulRxLevel.
+//
+//*****************************************************************************
+#define SOFTUART_FIFO_RX1_8 0x00000000 // Receive interrupt at 1/8 Full
+#define SOFTUART_FIFO_RX2_8 0x00000008 // Receive interrupt at 1/4 Full
+#define SOFTUART_FIFO_RX4_8 0x00000010 // Receive interrupt at 1/2 Full
+#define SOFTUART_FIFO_RX6_8 0x00000018 // Receive interrupt at 3/4 Full
+#define SOFTUART_FIFO_RX7_8 0x00000020 // Receive interrupt at 7/8 Full
+
+//*****************************************************************************
+//
+// Values returned from SoftUARTRxErrorGet().
+//
+//*****************************************************************************
+#define SOFTUART_RXERROR_OVERRUN \
+ 0x00000008 // An overrun error occurred
+#define SOFTUART_RXERROR_BREAK 0x00000004 // A break was received
+#define SOFTUART_RXERROR_PARITY 0x00000002 // A parity error occurred
+#define SOFTUART_RXERROR_FRAMING \
+ 0x00000001 // A framing error occurred
+
+//*****************************************************************************
+//
+// Values returned from SoftUARTRxTick().
+//
+//*****************************************************************************
+#define SOFTUART_RXTIMER_NOP 0 // The timer should continue to run
+#define SOFTUART_RXTIMER_END 1 // The timer should be stopped
+
+//*****************************************************************************
+//
+// API Function prototypes
+//
+//*****************************************************************************
+extern void SoftUARTInit(tSoftUART *pUART);
+extern void SoftUARTParityModeSet(tSoftUART *pUART, unsigned long ulParity);
+extern unsigned long SoftUARTParityModeGet(tSoftUART *pUART);
+extern void SoftUARTFIFOLevelSet(tSoftUART *pUART, unsigned long ulTxLevel,
+ unsigned long ulRxLevel);
+extern void SoftUARTFIFOLevelGet(tSoftUART *pUART, unsigned long *pulTxLevel,
+ unsigned long *pulRxLevel);
+extern void SoftUARTConfigSet(tSoftUART *pUART, unsigned long ulConfig);
+extern void SoftUARTConfigGet(tSoftUART *pUART, unsigned long *pulConfig);
+extern void SoftUARTEnable(tSoftUART *pUART);
+extern void SoftUARTDisable(tSoftUART *pUART);
+extern void SoftUARTFIFOEnable(tSoftUART *pUART);
+extern void SoftUARTFIFODisable(tSoftUART *pUART);
+extern tBoolean SoftUARTCharsAvail(tSoftUART *pUART);
+extern tBoolean SoftUARTSpaceAvail(tSoftUART *pUART);
+extern long SoftUARTCharGetNonBlocking(tSoftUART *pUART);
+extern long SoftUARTCharGet(tSoftUART *pUART);
+extern tBoolean SoftUARTCharPutNonBlocking(tSoftUART *pUART,
+ unsigned char ucData);
+extern void SoftUARTCharPut(tSoftUART *pUART, unsigned char ucData);
+extern void SoftUARTBreakCtl(tSoftUART *pUART, tBoolean bBreakState);
+extern tBoolean SoftUARTBusy(tSoftUART *pUART);
+extern void SoftUARTIntEnable(tSoftUART *pUART, unsigned long ulIntFlags);
+extern void SoftUARTIntDisable(tSoftUART *pUART, unsigned long ulIntFlags);
+extern unsigned long SoftUARTIntStatus(tSoftUART *pUART, tBoolean bMasked);
+extern void SoftUARTIntClear(tSoftUART *pUART, unsigned long ulIntFlags);
+extern unsigned long SoftUARTRxErrorGet(tSoftUART *pUART);
+extern void SoftUARTRxErrorClear(tSoftUART *pUART);
+extern unsigned long SoftUARTRxTick(tSoftUART *pUART, tBoolean bEdgeInt);
+extern void SoftUARTTxIntModeSet(tSoftUART *pUART, unsigned long ulMode);
+extern unsigned long SoftUARTTxIntModeGet(tSoftUART *pUART);
+extern void SoftUARTTxTimerTick(tSoftUART *pUART);
+extern void SoftUARTCallbackSet(tSoftUART *pUART, void (*pfnCallback)(void));
+extern void SoftUARTTxGPIOSet(tSoftUART *pUART, unsigned long ulBase,
+ unsigned char ucPin);
+extern void SoftUARTRxGPIOSet(tSoftUART *pUART, unsigned long ulBase,
+ unsigned char ucPin);
+extern void SoftUARTTxBufferSet(tSoftUART *pUART, unsigned char *pucTxBuffer,
+ unsigned short usLen);
+extern void SoftUARTRxBufferSet(tSoftUART *pUART, unsigned short *pusRxBuffer,
+ unsigned short usLen);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SOFTUART_H__
diff --git a/utils/uartstdio.c b/utils/uartstdio.c
new file mode 100644
index 0000000..ff2013f
--- /dev/null
+++ b/utils/uartstdio.c
@@ -0,0 +1,1732 @@
+//*****************************************************************************
+//
+// uartstdio.c - Utility driver to provide simple UART console functions.
+//
+// Copyright (c) 2007-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdarg.h>
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "inc/hw_uart.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/uart.h"
+#include "utils/uartstdio.h"
+
+//*****************************************************************************
+//
+//! \addtogroup uartstdio_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// If buffered mode is defined, set aside RX and TX buffers and read/write
+// pointers to control them.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+
+//*****************************************************************************
+//
+// This global controls whether or not we are echoing characters back to the
+// transmitter. By default, echo is enabled but if using this module as a
+// convenient method of implementing a buffered serial interface over which
+// you will be running an application protocol, you are likely to want to
+// disable echo by calling UARTEchoSet(false).
+//
+//*****************************************************************************
+static tBoolean g_bDisableEcho;
+
+//*****************************************************************************
+//
+// Output ring buffer. Buffer is full if g_ulUARTTxReadIndex is one ahead of
+// g_ulUARTTxWriteIndex. Buffer is empty if the two indices are the same.
+//
+//*****************************************************************************
+static unsigned char g_pcUARTTxBuffer[UART_TX_BUFFER_SIZE];
+static volatile unsigned long g_ulUARTTxWriteIndex = 0;
+static volatile unsigned long g_ulUARTTxReadIndex = 0;
+
+//*****************************************************************************
+//
+// Input ring buffer. Buffer is full if g_ulUARTTxReadIndex is one ahead of
+// g_ulUARTTxWriteIndex. Buffer is empty if the two indices are the same.
+//
+//*****************************************************************************
+static unsigned char g_pcUARTRxBuffer[UART_RX_BUFFER_SIZE];
+static volatile unsigned long g_ulUARTRxWriteIndex = 0;
+static volatile unsigned long g_ulUARTRxReadIndex = 0;
+
+//*****************************************************************************
+//
+// Macros to determine number of free and used bytes in the transmit buffer.
+//
+//*****************************************************************************
+#define TX_BUFFER_USED (GetBufferCount(&g_ulUARTTxReadIndex, \
+ &g_ulUARTTxWriteIndex, \
+ UART_TX_BUFFER_SIZE))
+#define TX_BUFFER_FREE (UART_TX_BUFFER_SIZE - TX_BUFFER_USED)
+#define TX_BUFFER_EMPTY (IsBufferEmpty(&g_ulUARTTxReadIndex, \
+ &g_ulUARTTxWriteIndex))
+#define TX_BUFFER_FULL (IsBufferFull(&g_ulUARTTxReadIndex, \
+ &g_ulUARTTxWriteIndex, \
+ UART_TX_BUFFER_SIZE))
+#define ADVANCE_TX_BUFFER_INDEX(Index) \
+ (Index) = ((Index) + 1) % UART_TX_BUFFER_SIZE
+
+//*****************************************************************************
+//
+// Macros to determine number of free and used bytes in the receive buffer.
+//
+//*****************************************************************************
+#define RX_BUFFER_USED (GetBufferCount(&g_ulUARTRxReadIndex, \
+ &g_ulUARTRxWriteIndex, \
+ UART_RX_BUFFER_SIZE))
+#define RX_BUFFER_FREE (UART_RX_BUFFER_SIZE - RX_BUFFER_USED)
+#define RX_BUFFER_EMPTY (IsBufferEmpty(&g_ulUARTRxReadIndex, \
+ &g_ulUARTRxWriteIndex))
+#define RX_BUFFER_FULL (IsBufferFull(&g_ulUARTRxReadIndex, \
+ &g_ulUARTRxWriteIndex, \
+ UART_RX_BUFFER_SIZE))
+#define ADVANCE_RX_BUFFER_INDEX(Index) \
+ (Index) = ((Index) + 1) % UART_RX_BUFFER_SIZE
+#endif
+
+//*****************************************************************************
+//
+// The base address of the chosen UART.
+//
+//*****************************************************************************
+static unsigned long g_ulBase = 0;
+
+//*****************************************************************************
+//
+// A mapping from an integer between 0 and 15 to its ASCII character
+// equivalent.
+//
+//*****************************************************************************
+static const char * const g_pcHex = "0123456789abcdef";
+
+//*****************************************************************************
+//
+// The list of possible base addresses for the console UART.
+//
+//*****************************************************************************
+static const unsigned long g_ulUARTBase[3] =
+{
+ UART0_BASE, UART1_BASE, UART2_BASE
+};
+
+#ifdef UART_BUFFERED
+//*****************************************************************************
+//
+// The list of possible interrupts for the console UART.
+//
+//*****************************************************************************
+static const unsigned long g_ulUARTInt[3] =
+{
+ INT_UART0, INT_UART1, INT_UART2
+};
+
+//*****************************************************************************
+//
+// The port number in use.
+//
+//*****************************************************************************
+static unsigned long g_ulPortNum;
+#endif
+
+//*****************************************************************************
+//
+// The list of UART peripherals.
+//
+//*****************************************************************************
+static const unsigned long g_ulUARTPeriph[3] =
+{
+ SYSCTL_PERIPH_UART0, SYSCTL_PERIPH_UART1, SYSCTL_PERIPH_UART2
+};
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is full or not.
+//!
+//! \param pulRead points to the read index for the buffer.
+//! \param pulWrite points to the write index for the buffer.
+//! \param ulSize is the size of the buffer in bytes.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! full. The structure of the code is specifically to ensure that we do not
+//! see warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is full or \b false otherwise.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+static tBoolean
+IsBufferFull(volatile unsigned long *pulRead,
+ volatile unsigned long *pulWrite, unsigned long ulSize)
+{
+ unsigned long ulWrite;
+ unsigned long ulRead;
+
+ ulWrite = *pulWrite;
+ ulRead = *pulRead;
+
+ return((((ulWrite + 1) % ulSize) == ulRead) ? true : false);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Determines whether the ring buffer whose pointers and size are provided
+//! is empty or not.
+//!
+//! \param pulRead points to the read index for the buffer.
+//! \param pulWrite points to the write index for the buffer.
+//!
+//! This function is used to determine whether or not a given ring buffer is
+//! empty. The structure of the code is specifically to ensure that we do not
+//! see warnings from the compiler related to the order of volatile accesses
+//! being undefined.
+//!
+//! \return Returns \b true if the buffer is empty or \b false otherwise.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+static tBoolean
+IsBufferEmpty(volatile unsigned long *pulRead,
+ volatile unsigned long *pulWrite)
+{
+ unsigned long ulWrite;
+ unsigned long ulRead;
+
+ ulWrite = *pulWrite;
+ ulRead = *pulRead;
+
+ return((ulWrite == ulRead) ? true : false);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Determines the number of bytes of data contained in a ring buffer.
+//!
+//! \param pulRead points to the read index for the buffer.
+//! \param pulWrite points to the write index for the buffer.
+//! \param ulSize is the size of the buffer in bytes.
+//!
+//! This function is used to determine how many bytes of data a given ring
+//! buffer currently contains. The structure of the code is specifically to
+//! ensure that we do not see warnings from the compiler related to the order
+//! of volatile accesses being undefined.
+//!
+//! \return Returns the number of bytes of data currently in the buffer.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+static unsigned long
+GetBufferCount(volatile unsigned long *pulRead,
+ volatile unsigned long *pulWrite, unsigned long ulSize)
+{
+ unsigned long ulWrite;
+ unsigned long ulRead;
+
+ ulWrite = *pulWrite;
+ ulRead = *pulRead;
+
+ return((ulWrite >= ulRead) ? (ulWrite - ulRead) :
+ (ulSize - (ulRead - ulWrite)));
+}
+#endif
+
+//*****************************************************************************
+//
+// Take as many bytes from the transmit buffer as we have space for and move
+// them into the UART transmit FIFO.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+static void
+UARTPrimeTransmit(unsigned long ulBase)
+{
+ //
+ // Do we have any data to transmit?
+ //
+ if(!TX_BUFFER_EMPTY)
+ {
+ //
+ // Disable the UART interrupt. If we don't do this there is a race
+ // condition which can cause the read index to be corrupted.
+ //
+ MAP_IntDisable(g_ulUARTInt[g_ulPortNum]);
+
+ //
+ // Yes - take some characters out of the transmit buffer and feed
+ // them to the UART transmit FIFO.
+ //
+ while(MAP_UARTSpaceAvail(ulBase) && !TX_BUFFER_EMPTY)
+ {
+ MAP_UARTCharPutNonBlocking(ulBase,
+ g_pcUARTTxBuffer[g_ulUARTTxReadIndex]);
+ ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxReadIndex);
+ }
+
+ //
+ // Reenable the UART interrupt.
+ //
+ MAP_IntEnable(g_ulUARTInt[g_ulPortNum]);
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+//! Configures the UART console.
+//!
+//! \param ulPortNum is the number of UART port to use for the serial console
+//! (0-2)
+//! \param ulBaud is the bit rate that the UART is to be configured to use.
+//! \param ulSrcClock is the frequency of the source clock for the UART module.
+//!
+//! This function will configure the specified serial port to be used as a
+//! serial console. The serial parameters are set to the baud rate
+//! specified by the \e ulBaud parameter and use 8 bit, no parity, and 1 stop
+//! bit.
+//!
+//! This function must be called prior to using any of the other UART console
+//! functions: UARTprintf() or UARTgets(). This function assumes that the
+//! caller has previously configured the relevant UART pins for operation as a
+//! UART rather than as GPIOs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTStdioConfig(unsigned long ulPortNum, unsigned long ulBaud,
+ unsigned long ulSrcClock)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT((ulPortNum == 0) || (ulPortNum == 1) ||
+ (ulPortNum == 2));
+
+#ifdef UART_BUFFERED
+ //
+ // In buffered mode, we only allow a single instance to be opened.
+ //
+ ASSERT(g_ulBase == 0);
+#endif
+
+ //
+ // Check to make sure the UART peripheral is present.
+ //
+ if(!MAP_SysCtlPeripheralPresent(g_ulUARTPeriph[ulPortNum]))
+ {
+ return;
+ }
+
+ //
+ // Select the base address of the UART.
+ //
+ g_ulBase = g_ulUARTBase[ulPortNum];
+
+ //
+ // Enable the UART peripheral for use.
+ //
+ MAP_SysCtlPeripheralEnable(g_ulUARTPeriph[ulPortNum]);
+
+ //
+ // Configure the UART for 115200, n, 8, 1
+ //
+ MAP_UARTConfigSetExpClk(g_ulBase, ulSrcClock, ulBaud,
+ (UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE |
+ UART_CONFIG_WLEN_8));
+
+#ifdef UART_BUFFERED
+ //
+ // Set the UART to interrupt whenever the TX FIFO is almost empty or
+ // when any character is received.
+ //
+ MAP_UARTFIFOLevelSet(g_ulBase, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
+
+ //
+ // Flush both the buffers.
+ //
+ UARTFlushRx();
+ UARTFlushTx(true);
+
+ //
+ // Remember which interrupt we are dealing with.
+ //
+ g_ulPortNum = ulPortNum;
+
+ //
+ // We are configured for buffered output so enable the master interrupt
+ // for this UART and the receive interrupts. We don't actually enable the
+ // transmit interrupt in the UART itself until some data has been placed
+ // in the transmit buffer.
+ //
+ MAP_UARTIntDisable(g_ulBase, 0xFFFFFFFF);
+ MAP_UARTIntEnable(g_ulBase, UART_INT_RX | UART_INT_RT);
+ MAP_IntEnable(g_ulUARTInt[ulPortNum]);
+#endif
+
+ //
+ // Enable the UART operation.
+ //
+ MAP_UARTEnable(g_ulBase);
+}
+
+//*****************************************************************************
+//
+//! Initializes the UART console.
+//!
+//! \param ulPortNum is the number of UART port to use for the serial console
+//! (0-2)
+//!
+//! This function will initialize the specified serial port to be used as a
+//! serial console. The serial parameters will be set to 115200, 8-N-1.
+//! An application wishing to use a different baud rate may call
+//! UARTStdioInitExpClk() instead of this function.
+//!
+//! This function or UARTStdioInitExpClk() must be called prior to using any
+//! of the other UART console functions: UARTprintf() or UARTgets(). In order
+//! for this function to work correctly, SysCtlClockSet() must be called prior
+//! to calling this function.
+//!
+//! It is assumed that the caller has previously configured the relevant UART
+//! pins for operation as a UART rather than as GPIOs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTStdioInit(unsigned long ulPortNum)
+{
+ //
+ // Pass this call on to the version of the function allowing the baud rate
+ // to be specified.
+ //
+ UARTStdioConfig(ulPortNum, 115200, MAP_SysCtlClockGet());
+}
+
+//*****************************************************************************
+//
+//! Initializes the UART console and allows the baud rate to be selected.
+//!
+//! \param ulPortNum is the number of UART port to use for the serial console
+//! (0-2)
+//! \param ulBaud is the bit rate that the UART is to be configured to use.
+//!
+//! This function will initialize the specified serial port to be used as a
+//! serial console. The serial parameters will be set to 8-N-1 and the bit
+//! rate set according to the value of the \e ulBaud parameter.
+//!
+//! This function or UARTStdioInit() must be called prior to using any of the
+//! other UART console functions: UARTprintf() or UARTgets(). In order for
+//! this function to work correctly, SysCtlClockSet() must be called prior to
+//! calling this function. An application wishing to use 115,200 baud may call
+//! UARTStdioInit() instead of this function but should not call both
+//! functions.
+//!
+//! It is assumed that the caller has previously configured the relevant UART
+//! pins for operation as a UART rather than as GPIOs.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTStdioInitExpClk(unsigned long ulPortNum, unsigned long ulBaud)
+{
+ UARTStdioConfig(ulPortNum, ulBaud, MAP_SysCtlClockGet());
+}
+
+//*****************************************************************************
+//
+//! Writes a string of characters to the UART output.
+//!
+//! \param pcBuf points to a buffer containing the string to transmit.
+//! \param ulLen is the length of the string to transmit.
+//!
+//! This function will transmit the string to the UART output. The number of
+//! characters transmitted is determined by the \e ulLen parameter. This
+//! function does no interpretation or translation of any characters. Since
+//! the output is sent to a UART, any LF (/n) characters encountered will be
+//! replaced with a CRLF pair.
+//!
+//! Besides using the \e ulLen parameter to stop transmitting the string, if a
+//! null character (0) is encountered, then no more characters will be
+//! transmitted and the function will return.
+//!
+//! In non-buffered mode, this function is blocking and will not return until
+//! all the characters have been written to the output FIFO. In buffered mode,
+//! the characters are written to the UART transmit buffer and the call returns
+//! immediately. If insufficient space remains in the transmit buffer,
+//! additional characters are discarded.
+//!
+//! \return Returns the count of characters written.
+//
+//*****************************************************************************
+int
+UARTwrite(const char *pcBuf, unsigned long ulLen)
+{
+#ifdef UART_BUFFERED
+ unsigned int uIdx;
+
+ //
+ // Check for valid arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(g_ulBase != 0);
+
+ //
+ // Send the characters
+ //
+ for(uIdx = 0; uIdx < ulLen; uIdx++)
+ {
+ //
+ // If the character to the UART is \n, then add a \r before it so that
+ // \n is translated to \n\r in the output.
+ //
+ if(pcBuf[uIdx] == '\n')
+ {
+ if(!TX_BUFFER_FULL)
+ {
+ g_pcUARTTxBuffer[g_ulUARTTxWriteIndex] = '\r';
+ ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxWriteIndex);
+ }
+ else
+ {
+ //
+ // Buffer is full - discard remaining characters and return.
+ //
+ break;
+ }
+ }
+
+ //
+ // Send the character to the UART output.
+ //
+ if(!TX_BUFFER_FULL)
+ {
+ g_pcUARTTxBuffer[g_ulUARTTxWriteIndex] = pcBuf[uIdx];
+ ADVANCE_TX_BUFFER_INDEX(g_ulUARTTxWriteIndex);
+ }
+ else
+ {
+ //
+ // Buffer is full - discard remaining characters and return.
+ //
+ break;
+ }
+ }
+
+ //
+ // If we have anything in the buffer, make sure that the UART is set
+ // up to transmit it.
+ //
+ if(!TX_BUFFER_EMPTY)
+ {
+ UARTPrimeTransmit(g_ulBase);
+ MAP_UARTIntEnable(g_ulBase, UART_INT_TX);
+ }
+
+ //
+ // Return the number of characters written.
+ //
+ return(uIdx);
+#else
+ unsigned int uIdx;
+
+ //
+ // Check for valid UART base address, and valid arguments.
+ //
+ ASSERT(g_ulBase != 0);
+ ASSERT(pcBuf != 0);
+
+ //
+ // Send the characters
+ //
+ for(uIdx = 0; uIdx < ulLen; uIdx++)
+ {
+ //
+ // If the character to the UART is \n, then add a \r before it so that
+ // \n is translated to \n\r in the output.
+ //
+ if(pcBuf[uIdx] == '\n')
+ {
+ MAP_UARTCharPut(g_ulBase, '\r');
+ }
+
+ //
+ // Send the character to the UART output.
+ //
+ MAP_UARTCharPut(g_ulBase, pcBuf[uIdx]);
+ }
+
+ //
+ // Return the number of characters written.
+ //
+ return(uIdx);
+#endif
+}
+
+//*****************************************************************************
+//
+//! A simple UART based get string function, with some line processing.
+//!
+//! \param pcBuf points to a buffer for the incoming string from the UART.
+//! \param ulLen is the length of the buffer for storage of the string,
+//! including the trailing 0.
+//!
+//! This function will receive a string from the UART input and store the
+//! characters in the buffer pointed to by \e pcBuf. The characters will
+//! continue to be stored until a termination character is received. The
+//! termination characters are CR, LF, or ESC. A CRLF pair is treated as a
+//! single termination character. The termination characters are not stored in
+//! the string. The string will be terminated with a 0 and the function will
+//! return.
+//!
+//! In both buffered and unbuffered modes, this function will block until
+//! a termination character is received. If non-blocking operation is required
+//! in buffered mode, a call to UARTPeek() may be made to determine whether
+//! a termination character already exists in the receive buffer prior to
+//! calling UARTgets().
+//!
+//! Since the string will be null terminated, the user must ensure that the
+//! buffer is sized to allow for the additional null character.
+//!
+//! \return Returns the count of characters that were stored, not including
+//! the trailing 0.
+//
+//*****************************************************************************
+int
+UARTgets(char *pcBuf, unsigned long ulLen)
+{
+#ifdef UART_BUFFERED
+ unsigned long ulCount = 0;
+ char cChar;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(ulLen != 0);
+ ASSERT(g_ulBase != 0);
+
+ //
+ // Adjust the length back by 1 to leave space for the trailing
+ // null terminator.
+ //
+ ulLen--;
+
+ //
+ // Process characters until a newline is received.
+ //
+ while(1)
+ {
+ //
+ // Read the next character from the receive buffer.
+ //
+ if(!RX_BUFFER_EMPTY)
+ {
+ cChar = g_pcUARTRxBuffer[g_ulUARTRxReadIndex];
+ ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxReadIndex);
+
+ //
+ // See if a newline or escape character was received.
+ //
+ if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
+ {
+ //
+ // Stop processing the input and end the line.
+ //
+ break;
+ }
+
+ //
+ // Process the received character as long as we are not at the end
+ // of the buffer. If the end of the buffer has been reached then
+ // all additional characters are ignored until a newline is
+ // received.
+ //
+ if(ulCount < ulLen)
+ {
+ //
+ // Store the character in the caller supplied buffer.
+ //
+ pcBuf[ulCount] = cChar;
+
+ //
+ // Increment the count of characters received.
+ //
+ ulCount++;
+ }
+ }
+ }
+
+ //
+ // Add a null termination to the string.
+ //
+ pcBuf[ulCount] = 0;
+
+ //
+ // Return the count of chars in the buffer, not counting the trailing 0.
+ //
+ return(ulCount);
+#else
+ unsigned long ulCount = 0;
+ char cChar;
+ static char bLastWasCR = 0;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcBuf != 0);
+ ASSERT(ulLen != 0);
+ ASSERT(g_ulBase != 0);
+
+ //
+ // Adjust the length back by 1 to leave space for the trailing
+ // null terminator.
+ //
+ ulLen--;
+
+ //
+ // Process characters until a newline is received.
+ //
+ while(1)
+ {
+ //
+ // Read the next character from the console.
+ //
+ cChar = MAP_UARTCharGet(g_ulBase);
+
+ //
+ // See if the backspace key was pressed.
+ //
+ if(cChar == '\b')
+ {
+ //
+ // If there are any characters already in the buffer, then delete
+ // the last.
+ //
+ if(ulCount)
+ {
+ //
+ // Rub out the previous character.
+ //
+ UARTwrite("\b \b", 3);
+
+ //
+ // Decrement the number of characters in the buffer.
+ //
+ ulCount--;
+ }
+
+ //
+ // Skip ahead to read the next character.
+ //
+ continue;
+ }
+
+ //
+ // If this character is LF and last was CR, then just gobble up the
+ // character because the EOL processing was taken care of with the CR.
+ //
+ if((cChar == '\n') && bLastWasCR)
+ {
+ bLastWasCR = 0;
+ continue;
+ }
+
+ //
+ // See if a newline or escape character was received.
+ //
+ if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
+ {
+ //
+ // If the character is a CR, then it may be followed by a LF which
+ // should be paired with the CR. So remember that a CR was
+ // received.
+ //
+ if(cChar == '\r')
+ {
+ bLastWasCR = 1;
+ }
+
+ //
+ // Stop processing the input and end the line.
+ //
+ break;
+ }
+
+ //
+ // Process the received character as long as we are not at the end of
+ // the buffer. If the end of the buffer has been reached then all
+ // additional characters are ignored until a newline is received.
+ //
+ if(ulCount < ulLen)
+ {
+ //
+ // Store the character in the caller supplied buffer.
+ //
+ pcBuf[ulCount] = cChar;
+
+ //
+ // Increment the count of characters received.
+ //
+ ulCount++;
+
+ //
+ // Reflect the character back to the user.
+ //
+ MAP_UARTCharPut(g_ulBase, cChar);
+ }
+ }
+
+ //
+ // Add a null termination to the string.
+ //
+ pcBuf[ulCount] = 0;
+
+ //
+ // Send a CRLF pair to the terminal to end the line.
+ //
+ UARTwrite("\r\n", 2);
+
+ //
+ // Return the count of chars in the buffer, not counting the trailing 0.
+ //
+ return(ulCount);
+#endif
+}
+
+//*****************************************************************************
+//
+//! Read a single character from the UART, blocking if necessary.
+//!
+//! This function will receive a single character from the UART and store it at
+//! the supplied address.
+//!
+//! In both buffered and unbuffered modes, this function will block until a
+//! character is received. If non-blocking operation is required in buffered
+//! mode, a call to UARTRxAvail() may be made to determine whether any
+//! characters are currently available for reading.
+//!
+//! \return Returns the character read.
+//
+//*****************************************************************************
+unsigned char
+UARTgetc(void)
+{
+#ifdef UART_BUFFERED
+ unsigned char cChar;
+
+ //
+ // Wait for a character to be received.
+ //
+ while(RX_BUFFER_EMPTY)
+ {
+ //
+ // Block waiting for a character to be received (if the buffer is
+ // currently empty).
+ //
+ }
+
+ //
+ // Read a character from the buffer.
+ //
+ cChar = g_pcUARTRxBuffer[g_ulUARTRxReadIndex];
+ ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxReadIndex);
+
+ //
+ // Return the character to the caller.
+ //
+ return(cChar);
+#else
+ //
+ // Block until a character is received by the UART then return it to
+ // the caller.
+ //
+ return(MAP_UARTCharGet(g_ulBase));
+#endif
+}
+
+//*****************************************************************************
+//
+//! A simple UART based printf function supporting \%c, \%d, \%p, \%s, \%u,
+//! \%x, and \%X.
+//!
+//! \param pcString is the format string.
+//! \param ... are the optional arguments, which depend on the contents of the
+//! format string.
+//!
+//! This function is very similar to the C library <tt>fprintf()</tt> function.
+//! All of its output will be sent to the UART. Only the following formatting
+//! characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%s, \%d, \%i, \%u, \%p, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeroes instead of spaces.
+//!
+//! The type of the arguments after \e pcString must match the requirements of
+//! the format string. For example, if an integer was passed where a string
+//! was expected, an error of some kind will most likely occur.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+UARTprintf(const char *pcString, ...)
+{
+ unsigned long ulIdx, ulValue, ulPos, ulCount, ulBase, ulNeg;
+ char *pcStr, pcBuf[16], cFill;
+ va_list vaArgP;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcString != 0);
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(vaArgP, pcString);
+
+ //
+ // Loop while there are more characters in the string.
+ //
+ while(*pcString)
+ {
+ //
+ // Find the first non-% character, or the end of the string.
+ //
+ for(ulIdx = 0; (pcString[ulIdx] != '%') && (pcString[ulIdx] != '\0');
+ ulIdx++)
+ {
+ }
+
+ //
+ // Write this portion of the string.
+ //
+ UARTwrite(pcString, ulIdx);
+
+ //
+ // Skip the portion of the string that was written.
+ //
+ pcString += ulIdx;
+
+ //
+ // See if the next character is a %.
+ //
+ if(*pcString == '%')
+ {
+ //
+ // Skip the %.
+ //
+ pcString++;
+
+ //
+ // Set the digit count to zero, and the fill character to space
+ // (i.e. to the defaults).
+ //
+ ulCount = 0;
+ cFill = ' ';
+
+ //
+ // It may be necessary to get back here to process more characters.
+ // Goto's aren't pretty, but effective. I feel extremely dirty for
+ // using not one but two of the beasts.
+ //
+again:
+
+ //
+ // Determine how to handle the next character.
+ //
+ switch(*pcString++)
+ {
+ //
+ // Handle the digit characters.
+ //
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ //
+ // If this is a zero, and it is the first digit, then the
+ // fill character is a zero instead of a space.
+ //
+ if((pcString[-1] == '0') && (ulCount == 0))
+ {
+ cFill = '0';
+ }
+
+ //
+ // Update the digit count.
+ //
+ ulCount *= 10;
+ ulCount += pcString[-1] - '0';
+
+ //
+ // Get the next character.
+ //
+ goto again;
+ }
+
+ //
+ // Handle the %c command.
+ //
+ case 'c':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(vaArgP, unsigned long);
+
+ //
+ // Print out the character.
+ //
+ UARTwrite((char *)&ulValue, 1);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %d and %i commands.
+ //
+ case 'd':
+ case 'i':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(vaArgP, unsigned long);
+
+ //
+ // Reset the buffer position.
+ //
+ ulPos = 0;
+
+ //
+ // If the value is negative, make it positive and indicate
+ // that a minus sign is needed.
+ //
+ if((long)ulValue < 0)
+ {
+ //
+ // Make the value positive.
+ //
+ ulValue = -(long)ulValue;
+
+ //
+ // Indicate that the value is negative.
+ //
+ ulNeg = 1;
+ }
+ else
+ {
+ //
+ // Indicate that the value is positive so that a minus
+ // sign isn't inserted.
+ //
+ ulNeg = 0;
+ }
+
+ //
+ // Set the base to 10.
+ //
+ ulBase = 10;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %s command.
+ //
+ case 's':
+ {
+ //
+ // Get the string pointer from the varargs.
+ //
+ pcStr = va_arg(vaArgP, char *);
+
+ //
+ // Determine the length of the string.
+ //
+ for(ulIdx = 0; pcStr[ulIdx] != '\0'; ulIdx++)
+ {
+ }
+
+ //
+ // Write the string.
+ //
+ UARTwrite(pcStr, ulIdx);
+
+ //
+ // Write any required padding spaces
+ //
+ if(ulCount > ulIdx)
+ {
+ ulCount -= ulIdx;
+ while(ulCount--)
+ {
+ UARTwrite(" ", 1);
+ }
+ }
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %u command.
+ //
+ case 'u':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(vaArgP, unsigned long);
+
+ //
+ // Reset the buffer position.
+ //
+ ulPos = 0;
+
+ //
+ // Set the base to 10.
+ //
+ ulBase = 10;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ulNeg = 0;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %x and %X commands. Note that they are treated
+ // identically; i.e. %X will use lower case letters for a-f
+ // instead of the upper case letters is should use. We also
+ // alias %p to %x.
+ //
+ case 'x':
+ case 'X':
+ case 'p':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(vaArgP, unsigned long);
+
+ //
+ // Reset the buffer position.
+ //
+ ulPos = 0;
+
+ //
+ // Set the base to 16.
+ //
+ ulBase = 16;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ulNeg = 0;
+
+ //
+ // Determine the number of digits in the string version of
+ // the value.
+ //
+convert:
+ for(ulIdx = 1;
+ (((ulIdx * ulBase) <= ulValue) &&
+ (((ulIdx * ulBase) / ulBase) == ulIdx));
+ ulIdx *= ulBase, ulCount--)
+ {
+ }
+
+ //
+ // If the value is negative, reduce the count of padding
+ // characters needed.
+ //
+ if(ulNeg)
+ {
+ ulCount--;
+ }
+
+ //
+ // If the value is negative and the value is padded with
+ // zeros, then place the minus sign before the padding.
+ //
+ if(ulNeg && (cFill == '0'))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ pcBuf[ulPos++] = '-';
+
+ //
+ // The minus sign has been placed, so turn off the
+ // negative flag.
+ //
+ ulNeg = 0;
+ }
+
+ //
+ // Provide additional padding at the beginning of the
+ // string conversion if needed.
+ //
+ if((ulCount > 1) && (ulCount < 16))
+ {
+ for(ulCount--; ulCount; ulCount--)
+ {
+ pcBuf[ulPos++] = cFill;
+ }
+ }
+
+ //
+ // If the value is negative, then place the minus sign
+ // before the number.
+ //
+ if(ulNeg)
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ pcBuf[ulPos++] = '-';
+ }
+
+ //
+ // Convert the value into a string.
+ //
+ for(; ulIdx; ulIdx /= ulBase)
+ {
+ pcBuf[ulPos++] = g_pcHex[(ulValue / ulIdx) % ulBase];
+ }
+
+ //
+ // Write the string.
+ //
+ UARTwrite(pcBuf, ulPos);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %% command.
+ //
+ case '%':
+ {
+ //
+ // Simply write a single %.
+ //
+ UARTwrite(pcString - 1, 1);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle all other commands.
+ //
+ default:
+ {
+ //
+ // Indicate an error.
+ //
+ UARTwrite("ERROR", 5);
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // End the varargs processing.
+ //
+ va_end(vaArgP);
+}
+
+//*****************************************************************************
+//
+//! Returns the number of bytes available in the receive buffer.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to determine the number
+//! of bytes of data currently available in the receive buffer.
+//!
+//! \return Returns the number of available bytes.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+int
+UARTRxBytesAvail(void)
+{
+ return(RX_BUFFER_USED);
+}
+#endif
+
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+//*****************************************************************************
+//
+//! Returns the number of bytes free in the transmit buffer.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to determine the amount
+//! of space currently available in the transmit buffer.
+//!
+//! \return Returns the number of free bytes.
+//
+//*****************************************************************************
+int
+UARTTxBytesFree(void)
+{
+ return(TX_BUFFER_FREE);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Looks ahead in the receive buffer for a particular character.
+//!
+//! \param ucChar is the character that is to be searched for.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to look ahead in the
+//! receive buffer for a particular character and report its position if found.
+//! It is typically used to determine whether a complete line of user input is
+//! available, in which case ucChar should be set to CR ('\\r') which is used
+//! as the line end marker in the receive buffer.
+//!
+//! \return Returns -1 to indicate that the requested character does not exist
+//! in the receive buffer. Returns a non-negative number if the character was
+//! found in which case the value represents the position of the first instance
+//! of \e ucChar relative to the receive buffer read pointer.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+int
+UARTPeek(unsigned char ucChar)
+{
+ int iCount;
+ int iAvail;
+ unsigned long ulReadIndex;
+
+ //
+ // How many characters are there in the receive buffer?
+ //
+ iAvail = (int)RX_BUFFER_USED;
+ ulReadIndex = g_ulUARTRxReadIndex;
+
+ //
+ // Check all the unread characters looking for the one passed.
+ //
+ for(iCount = 0; iCount < iAvail; iCount++)
+ {
+ if(g_pcUARTRxBuffer[ulReadIndex] == ucChar)
+ {
+ //
+ // We found it so return the index
+ //
+ return(iCount);
+ }
+ else
+ {
+ //
+ // This one didn't match so move on to the next character.
+ //
+ ADVANCE_RX_BUFFER_INDEX(ulReadIndex);
+ }
+ }
+
+ //
+ // If we drop out of the loop, we didn't find the character in the receive
+ // buffer.
+ //
+ return(-1);
+}
+#endif
+
+//*****************************************************************************
+//
+//! Flushes the receive buffer.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to discard any data
+//! received from the UART but not yet read using UARTgets().
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+void
+UARTFlushRx(void)
+{
+ unsigned long ulInt;
+
+ //
+ // Temporarily turn off interrupts.
+ //
+ ulInt = MAP_IntMasterDisable();
+
+ //
+ // Flush the receive buffer.
+ //
+ g_ulUARTRxReadIndex = 0;
+ g_ulUARTRxWriteIndex = 0;
+
+ //
+ // If interrupts were enabled when we turned them off, turn them
+ // back on again.
+ //
+ if(!ulInt)
+ {
+ MAP_IntMasterEnable();
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+//! Flushes the transmit buffer.
+//!
+//! \param bDiscard indicates whether any remaining data in the buffer should
+//! be discarded (\b true) or transmitted (\b false).
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to flush the transmit
+//! buffer, either discarding or transmitting any data received via calls to
+//! UARTprintf() that is waiting to be transmitted. On return, the transmit
+//! buffer will be empty.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+void
+UARTFlushTx(tBoolean bDiscard)
+{
+ unsigned long ulInt;
+
+ //
+ // Should the remaining data be discarded or transmitted?
+ //
+ if(bDiscard)
+ {
+ //
+ // The remaining data should be discarded, so temporarily turn off
+ // interrupts.
+ //
+ ulInt = MAP_IntMasterDisable();
+
+ //
+ // Flush the transmit buffer.
+ //
+ g_ulUARTTxReadIndex = 0;
+ g_ulUARTTxWriteIndex = 0;
+
+ //
+ // If interrupts were enabled when we turned them off, turn them
+ // back on again.
+ //
+ if(!ulInt)
+ {
+ MAP_IntMasterEnable();
+ }
+ }
+ else
+ {
+ //
+ // Wait for all remaining data to be transmitted before returning.
+ //
+ while(!TX_BUFFER_EMPTY)
+ {
+ }
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+//! Enables or disables echoing of received characters to the transmitter.
+//!
+//! \param bEnable must be set to \b true to enable echo or \b false to
+//! disable it.
+//!
+//! This function, available only when the module is built to operate in
+//! buffered mode using \b UART_BUFFERED, may be used to control whether or not
+//! received characters are automatically echoed back to the transmitter. By
+//! default, echo is enabled and this is typically the desired behavior if
+//! the module is being used to support a serial command line. In applications
+//! where this module is being used to provide a convenient, buffered serial
+//! interface over which application-specific binary protocols are being run,
+//! however, echo may be undesirable and this function can be used to disable
+//! it.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+void
+UARTEchoSet(tBoolean bEnable)
+{
+ g_bDisableEcho = !bEnable;
+}
+#endif
+
+//*****************************************************************************
+//
+//! Handles UART interrupts.
+//!
+//! This function handles interrupts from the UART. It will copy data from the
+//! transmit buffer to the UART transmit FIFO if space is available, and it
+//! will copy data from the UART receive FIFO to the receive buffer if data is
+//! available.
+//!
+//! \return None.
+//
+//*****************************************************************************
+#if defined(UART_BUFFERED) || defined(DOXYGEN)
+void
+UARTStdioIntHandler(void)
+{
+ unsigned long ulInts;
+ char cChar;
+ long lChar;
+ static tBoolean bLastWasCR = false;
+
+ //
+ // Get and clear the current interrupt source(s)
+ //
+ ulInts = MAP_UARTIntStatus(g_ulBase, true);
+ MAP_UARTIntClear(g_ulBase, ulInts);
+
+ //
+ // Are we being interrupted because the TX FIFO has space available?
+ //
+ if(ulInts & UART_INT_TX)
+ {
+ //
+ // Move as many bytes as we can into the transmit FIFO.
+ //
+ UARTPrimeTransmit(g_ulBase);
+
+ //
+ // If the output buffer is empty, turn off the transmit interrupt.
+ //
+ if(TX_BUFFER_EMPTY)
+ {
+ MAP_UARTIntDisable(g_ulBase, UART_INT_TX);
+ }
+ }
+
+ //
+ // Are we being interrupted due to a received character?
+ //
+ if(ulInts & (UART_INT_RX | UART_INT_RT))
+ {
+ //
+ // Get all the available characters from the UART.
+ //
+ while(MAP_UARTCharsAvail(g_ulBase))
+ {
+ //
+ // Read a character
+ //
+ lChar = MAP_UARTCharGetNonBlocking(g_ulBase);
+ cChar = (unsigned char)(lChar & 0xFF);
+
+ //
+ // If echo is disabled, we skip the various text filtering
+ // operations that would typically be required when supporting a
+ // command line.
+ //
+ if(!g_bDisableEcho)
+ {
+ //
+ // Handle backspace by erasing the last character in the buffer.
+ //
+ if(cChar == '\b')
+ {
+ //
+ // If there are any characters already in the buffer, then
+ // delete the last.
+ //
+ if(!RX_BUFFER_EMPTY)
+ {
+ //
+ // Rub out the previous character on the users terminal.
+ //
+ UARTwrite("\b \b", 3);
+
+ //
+ // Decrement the number of characters in the buffer.
+ //
+ if(g_ulUARTRxWriteIndex == 0)
+ {
+ g_ulUARTRxWriteIndex = UART_RX_BUFFER_SIZE - 1;
+ }
+ else
+ {
+ g_ulUARTRxWriteIndex--;
+ }
+ }
+
+ //
+ // Skip ahead to read the next character.
+ //
+ continue;
+ }
+
+ //
+ // If this character is LF and last was CR, then just gobble up
+ // the character since we already echoed the previous CR and we
+ // don't want to store 2 characters in the buffer if we don't
+ // need to.
+ //
+ if((cChar == '\n') && bLastWasCR)
+ {
+ bLastWasCR = false;
+ continue;
+ }
+
+ //
+ // See if a newline or escape character was received.
+ //
+ if((cChar == '\r') || (cChar == '\n') || (cChar == 0x1b))
+ {
+ //
+ // If the character is a CR, then it may be followed by an
+ // LF which should be paired with the CR. So remember that
+ // a CR was received.
+ //
+ if(cChar == '\r')
+ {
+ bLastWasCR = 1;
+ }
+
+ //
+ // Regardless of the line termination character received,
+ // put a CR in the receive buffer as a marker telling
+ // UARTgets() where the line ends. We also send an
+ // additional LF to ensure that the local terminal echo
+ // receives both CR and LF.
+ //
+ cChar = '\r';
+ UARTwrite("\n", 1);
+ }
+ }
+
+ //
+ // If there is space in the receive buffer, put the character
+ // there, otherwise throw it away.
+ //
+ if(!RX_BUFFER_FULL)
+ {
+ //
+ // Store the new character in the receive buffer
+ //
+ g_pcUARTRxBuffer[g_ulUARTRxWriteIndex] =
+ (unsigned char)(lChar & 0xFF);
+ ADVANCE_RX_BUFFER_INDEX(g_ulUARTRxWriteIndex);
+
+ //
+ // If echo is enabled, write the character to the transmit
+ // buffer so that the user gets some immediate feedback.
+ //
+ if(!g_bDisableEcho)
+ {
+ UARTwrite(&cChar, 1);
+ }
+ }
+ }
+
+ //
+ // If we wrote anything to the transmit buffer, make sure it actually
+ // gets transmitted.
+ //
+ UARTPrimeTransmit(g_ulBase);
+ MAP_UARTIntEnable(g_ulBase, UART_INT_TX);
+ }
+}
+#endif
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/uartstdio.h b/utils/uartstdio.h
new file mode 100644
index 0000000..d54d573
--- /dev/null
+++ b/utils/uartstdio.h
@@ -0,0 +1,85 @@
+//*****************************************************************************
+//
+// uartstdio.h - Prototypes for the UART console functions.
+//
+// Copyright (c) 2007-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __UARTSTDIO_H__
+#define __UARTSTDIO_H__
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+// If built for buffered operation, the following labels define the sizes of
+// the transmit and receive buffers respectively.
+//
+//*****************************************************************************
+#ifdef UART_BUFFERED
+#ifndef UART_RX_BUFFER_SIZE
+#define UART_RX_BUFFER_SIZE 128
+#endif
+#ifndef UART_TX_BUFFER_SIZE
+#define UART_TX_BUFFER_SIZE 1024
+#endif
+#endif
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern void UARTStdioConfig(unsigned long ulPort, unsigned long ulBaud,
+ unsigned long ulSrcClock);
+extern void UARTStdioInit(unsigned long ulPort);
+extern void UARTStdioInitExpClk(unsigned long ulPort, unsigned long ulBaud);
+extern int UARTgets(char *pcBuf, unsigned long ulLen);
+extern unsigned char UARTgetc(void);
+extern void UARTprintf(const char *pcString, ...);
+extern int UARTwrite(const char *pcBuf, unsigned long ulLen);
+#ifdef UART_BUFFERED
+extern int UARTPeek(unsigned char ucChar);
+extern void UARTFlushTx(tBoolean bDiscard);
+extern void UARTFlushRx(void);
+extern int UARTRxBytesAvail(void);
+extern int UARTTxBytesFree(void);
+extern void UARTEchoSet(tBoolean bEnable);
+#endif
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UARTSTDIO_H__
diff --git a/utils/ustdlib.c b/utils/ustdlib.c
new file mode 100644
index 0000000..a330a53
--- /dev/null
+++ b/utils/ustdlib.c
@@ -0,0 +1,1610 @@
+//*****************************************************************************
+//
+// ustdlib.c - Simple standard library functions.
+//
+// Copyright (c) 2007-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <string.h>
+#include "driverlib/debug.h"
+#include "utils/ustdlib.h"
+
+//*****************************************************************************
+//
+//! \addtogroup ustdlib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// A mapping from an integer between 0 and 15 to its ASCII character
+// equivalent.
+//
+//*****************************************************************************
+static const char * const g_pcHex = "0123456789abcdef";
+
+//*****************************************************************************
+//
+//! Copies a certain number of characters from one string to another.
+//!
+//! \param pcDst is a pointer to the destination buffer into which characters
+//! are to be copied.
+//! \param pcSrc is a pointer to the string from which characters are to be
+//! copied.
+//! \param iNum is the number of characters to copy to the destination buffer.
+//!
+//! This function copies at most \e iNum characters from the string pointed to
+//! by \e pcSrc into the buffer pointed to by \e pcDst. If the end of \e
+//! pcSrc is found before \e iNum characters have been copied, remaining
+//! characters in \e pcDst will be padded with zeroes until \e iNum characters
+//! have been written. Note that the destination string will only be NULL
+//! terminated if the number of characters to be copied is greater than the
+//! length of \e pcSrc.
+//!
+//! \return Returns \e pcDst.
+//
+//*****************************************************************************
+char *
+ustrncpy (char *pcDst, const char *pcSrc, int iNum)
+{
+ int iCount;
+
+ ASSERT(pcSrc);
+ ASSERT(pcDst);
+
+ //
+ // Start at the beginning of the source string.
+ //
+ iCount = 0;
+
+ //
+ // Copy the source string until we run out of source characters or
+ // destination space.
+ //
+ while(iNum && pcSrc[iCount])
+ {
+ pcDst[iCount] = pcSrc[iCount];
+ iCount++;
+ iNum--;
+ }
+
+ //
+ // Pad the destination if we are not yet done.
+ //
+ while(iNum)
+ {
+ pcDst[iCount++] = (char)0;
+ iNum--;
+ }
+
+ //
+ // Pass the destination pointer back to the caller.
+ //
+ return(pcDst);
+}
+
+//*****************************************************************************
+//
+//! A simple vsnprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and
+//! \%X.
+//!
+//! \param pcBuf points to the buffer where the converted string is stored.
+//! \param ulSize is the size of the buffer.
+//! \param pcString is the format string.
+//! \param vaArgP is the list of optional arguments, which depend on the
+//! contents of the format string.
+//!
+//! This function is very similar to the C library <tt>vsnprintf()</tt>
+//! function. Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeroes instead of spaces.
+//!
+//! The type of the arguments after \e pcString must match the requirements of
+//! the format string. For example, if an integer was passed where a string
+//! was expected, an error of some kind will most likely occur.
+//!
+//! The \e ulSize parameter limits the number of characters that will be stored
+//! in the buffer pointed to by \e pcBuf to prevent the possibility of a buffer
+//! overflow. The buffer size should be large enough to hold the expected
+//! converted output string, including the null termination character.
+//!
+//! The function will return the number of characters that would be converted
+//! as if there were no limit on the buffer size. Therefore it is possible for
+//! the function to return a count that is greater than the specified buffer
+//! size. If this happens, it means that the output was truncated.
+//!
+//! \return Returns the number of characters that were to be stored, not
+//! including the NULL termination character, regardless of space in the
+//! buffer.
+//
+//*****************************************************************************
+int
+uvsnprintf(char *pcBuf, unsigned long ulSize, const char *pcString,
+ va_list vaArgP)
+{
+ unsigned long ulIdx, ulValue, ulCount, ulBase, ulNeg;
+ char *pcStr, cFill;
+ int iConvertCount = 0;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcString != 0);
+ ASSERT(pcBuf != 0);
+ ASSERT(ulSize != 0);
+
+ //
+ // Adjust buffer size limit to allow one space for null termination.
+ //
+ if(ulSize)
+ {
+ ulSize--;
+ }
+
+ //
+ // Initialize the count of characters converted.
+ //
+ iConvertCount = 0;
+
+ //
+ // Loop while there are more characters in the format string.
+ //
+ while(*pcString)
+ {
+ //
+ // Find the first non-% character, or the end of the string.
+ //
+ for(ulIdx = 0; (pcString[ulIdx] != '%') && (pcString[ulIdx] != '\0');
+ ulIdx++)
+ {
+ }
+
+ //
+ // Write this portion of the string to the output buffer. If there are
+ // more characters to write than there is space in the buffer, then
+ // only write as much as will fit in the buffer.
+ //
+ if(ulIdx > ulSize)
+ {
+ ustrncpy(pcBuf, pcString, ulSize);
+ pcBuf += ulSize;
+ ulSize = 0;
+ }
+ else
+ {
+ ustrncpy(pcBuf, pcString, ulIdx);
+ pcBuf += ulIdx;
+ ulSize -= ulIdx;
+ }
+
+ //
+ // Update the conversion count. This will be the number of characters
+ // that should have been written, even if there was not room in the
+ // buffer.
+ //
+ iConvertCount += ulIdx;
+
+ //
+ // Skip the portion of the format string that was written.
+ //
+ pcString += ulIdx;
+
+ //
+ // See if the next character is a %.
+ //
+ if(*pcString == '%')
+ {
+ //
+ // Skip the %.
+ //
+ pcString++;
+
+ //
+ // Set the digit count to zero, and the fill character to space
+ // (that is, to the defaults).
+ //
+ ulCount = 0;
+ cFill = ' ';
+
+ //
+ // It may be necessary to get back here to process more characters.
+ // Goto's aren't pretty, but effective. I feel extremely dirty for
+ // using not one but two of the beasts.
+ //
+again:
+
+ //
+ // Determine how to handle the next character.
+ //
+ switch(*pcString++)
+ {
+ //
+ // Handle the digit characters.
+ //
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ //
+ // If this is a zero, and it is the first digit, then the
+ // fill character is a zero instead of a space.
+ //
+ if((pcString[-1] == '0') && (ulCount == 0))
+ {
+ cFill = '0';
+ }
+
+ //
+ // Update the digit count.
+ //
+ ulCount *= 10;
+ ulCount += pcString[-1] - '0';
+
+ //
+ // Get the next character.
+ //
+ goto again;
+ }
+
+ //
+ // Handle the %c command.
+ //
+ case 'c':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(vaArgP, unsigned long);
+
+ //
+ // Copy the character to the output buffer, if there is
+ // room. Update the buffer size remaining.
+ //
+ if(ulSize != 0)
+ {
+ *pcBuf++ = (char)ulValue;
+ ulSize--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %d and %i commands.
+ //
+ case 'd':
+ case 'i':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(vaArgP, unsigned long);
+
+ //
+ // If the value is negative, make it positive and indicate
+ // that a minus sign is needed.
+ //
+ if((long)ulValue < 0)
+ {
+ //
+ // Make the value positive.
+ //
+ ulValue = -(long)ulValue;
+
+ //
+ // Indicate that the value is negative.
+ //
+ ulNeg = 1;
+ }
+ else
+ {
+ //
+ // Indicate that the value is positive so that a
+ // negative sign isn't inserted.
+ //
+ ulNeg = 0;
+ }
+
+ //
+ // Set the base to 10.
+ //
+ ulBase = 10;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %s command.
+ //
+ case 's':
+ {
+ //
+ // Get the string pointer from the varargs.
+ //
+ pcStr = va_arg(vaArgP, char *);
+
+ //
+ // Determine the length of the string.
+ //
+ for(ulIdx = 0; pcStr[ulIdx] != '\0'; ulIdx++)
+ {
+ }
+
+ //
+ // Update the convert count to include any padding that
+ // should be necessary (regardless of whether we have space
+ // to write it or not).
+ //
+ if(ulCount > ulIdx)
+ {
+ iConvertCount += (ulCount - ulIdx);
+ }
+
+ //
+ // Copy the string to the output buffer. Only copy as much
+ // as will fit in the buffer. Update the output buffer
+ // pointer and the space remaining.
+ //
+ if(ulIdx > ulSize)
+ {
+ ustrncpy(pcBuf, pcStr, ulSize);
+ pcBuf += ulSize;
+ ulSize = 0;
+ }
+ else
+ {
+ ustrncpy(pcBuf, pcStr, ulIdx);
+ pcBuf += ulIdx;
+ ulSize -= ulIdx;
+
+ //
+ // Write any required padding spaces assuming there is
+ // still space in the buffer.
+ //
+ if(ulCount > ulIdx)
+ {
+ ulCount -= ulIdx;
+ if(ulCount > ulSize)
+ {
+ ulCount = ulSize;
+ }
+ ulSize =- ulCount;
+
+ while(ulCount--)
+ {
+ *pcBuf++ = ' ';
+ }
+ }
+ }
+
+ //
+ // Update the conversion count. This will be the number of
+ // characters that should have been written, even if there
+ // was not room in the buffer.
+ //
+ iConvertCount += ulIdx;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %u command.
+ //
+ case 'u':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(vaArgP, unsigned long);
+
+ //
+ // Set the base to 10.
+ //
+ ulBase = 10;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ulNeg = 0;
+
+ //
+ // Convert the value to ASCII.
+ //
+ goto convert;
+ }
+
+ //
+ // Handle the %x and %X commands. Note that they are treated
+ // identically; that is, %X will use lower case letters for a-f
+ // instead of the upper case letters is should use. We also
+ // alias %p to %x.
+ //
+ case 'x':
+ case 'X':
+ case 'p':
+ {
+ //
+ // Get the value from the varargs.
+ //
+ ulValue = va_arg(vaArgP, unsigned long);
+
+ //
+ // Set the base to 16.
+ //
+ ulBase = 16;
+
+ //
+ // Indicate that the value is positive so that a minus sign
+ // isn't inserted.
+ //
+ ulNeg = 0;
+
+ //
+ // Determine the number of digits in the string version of
+ // the value.
+ //
+convert:
+ for(ulIdx = 1;
+ (((ulIdx * ulBase) <= ulValue) &&
+ (((ulIdx * ulBase) / ulBase) == ulIdx));
+ ulIdx *= ulBase, ulCount--)
+ {
+ }
+
+ //
+ // If the value is negative, reduce the count of padding
+ // characters needed.
+ //
+ if(ulNeg)
+ {
+ ulCount--;
+ }
+
+ //
+ // If the value is negative and the value is padded with
+ // zeros, then place the minus sign before the padding.
+ //
+ if(ulNeg && (ulSize != 0) && (cFill == '0'))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ *pcBuf++ = '-';
+ ulSize--;
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // The minus sign has been placed, so turn off the
+ // negative flag.
+ //
+ ulNeg = 0;
+ }
+
+ //
+ // See if there are more characters in the specified field
+ // width than there are in the conversion of this value.
+ //
+ if((ulCount > 1) && (ulCount < 65536))
+ {
+ //
+ // Loop through the required padding characters.
+ //
+ for(ulCount--; ulCount; ulCount--)
+ {
+ //
+ // Copy the character to the output buffer if there
+ // is room.
+ //
+ if(ulSize != 0)
+ {
+ *pcBuf++ = cFill;
+ ulSize--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+ }
+
+ //
+ // If the value is negative, then place the minus sign
+ // before the number.
+ //
+ if(ulNeg && (ulSize != 0))
+ {
+ //
+ // Place the minus sign in the output buffer.
+ //
+ *pcBuf++ = '-';
+ ulSize--;
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+
+ //
+ // Convert the value into a string.
+ //
+ for(; ulIdx; ulIdx /= ulBase)
+ {
+ //
+ // Copy the character to the output buffer if there is
+ // room.
+ //
+ if(ulSize != 0)
+ {
+ *pcBuf++ = g_pcHex[(ulValue / ulIdx) % ulBase];
+ ulSize--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+ }
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle the %% command.
+ //
+ case '%':
+ {
+ //
+ // Simply write a single %.
+ //
+ if(ulSize != 0)
+ {
+ *pcBuf++ = pcString[-1];
+ ulSize--;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount++;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+
+ //
+ // Handle all other commands.
+ //
+ default:
+ {
+ //
+ // Indicate an error.
+ //
+ if(ulSize >= 5)
+ {
+ ustrncpy(pcBuf, "ERROR", 5);
+ pcBuf += 5;
+ ulSize -= 5;
+ }
+ else
+ {
+ ustrncpy(pcBuf, "ERROR", ulSize);
+ pcBuf += ulSize;
+ ulSize = 0;
+ }
+
+ //
+ // Update the conversion count.
+ //
+ iConvertCount += 5;
+
+ //
+ // This command has been handled.
+ //
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Null terminate the string in the buffer.
+ //
+ *pcBuf = 0;
+
+ //
+ // Return the number of characters in the full converted string.
+ //
+ return(iConvertCount);
+}
+
+//*****************************************************************************
+//
+//! A simple sprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and \%X.
+//!
+//! \param pcBuf is the buffer where the converted string is stored.
+//! \param pcString is the format string.
+//! \param ... are the optional arguments, which depend on the contents of the
+//! format string.
+//!
+//! This function is very similar to the C library <tt>sprintf()</tt> function.
+//! Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeros instead of spaces.
+//!
+//! The type of the arguments after \e pcString must match the requirements of
+//! the format string. For example, if an integer was passed where a string
+//! was expected, an error of some kind will most likely occur.
+//!
+//! The caller must ensure that the buffer \e pcBuf is large enough to hold the
+//! entire converted string, including the null termination character.
+//!
+//! \return Returns the count of characters that were written to the output
+//! buffer, not including the NULL termination character.
+//
+//*****************************************************************************
+int
+usprintf(char *pcBuf, const char *pcString, ...)
+{
+ va_list vaArgP;
+ int iRet;
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(vaArgP, pcString);
+
+ //
+ // Call vsnprintf to perform the conversion. Use a large number for the
+ // buffer size.
+ //
+ iRet = uvsnprintf(pcBuf, 0xffff, pcString, vaArgP);
+
+ //
+ // End the varargs processing.
+ //
+ va_end(vaArgP);
+
+ //
+ // Return the conversion count.
+ //
+ return(iRet);
+}
+
+//*****************************************************************************
+//
+//! A simple snprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and
+//! \%X.
+//!
+//! \param pcBuf is the buffer where the converted string is stored.
+//! \param ulSize is the size of the buffer.
+//! \param pcString is the format string.
+//! \param ... are the optional arguments, which depend on the contents of the
+//! format string.
+//!
+//! This function is very similar to the C library <tt>sprintf()</tt> function.
+//! Only the following formatting characters are supported:
+//!
+//! - \%c to print a character
+//! - \%d or \%i to print a decimal value
+//! - \%s to print a string
+//! - \%u to print an unsigned decimal value
+//! - \%x to print a hexadecimal value using lower case letters
+//! - \%X to print a hexadecimal value using lower case letters (not upper case
+//! letters as would typically be used)
+//! - \%p to print a pointer as a hexadecimal value
+//! - \%\% to print out a \% character
+//!
+//! For \%d, \%i, \%p, \%s, \%u, \%x, and \%X, an optional number may reside
+//! between the \% and the format character, which specifies the minimum number
+//! of characters to use for that value; if preceded by a 0 then the extra
+//! characters will be filled with zeros instead of spaces. For example,
+//! ``\%8d'' will use eight characters to print the decimal value with spaces
+//! added to reach eight; ``\%08d'' will use eight characters as well but will
+//! add zeros instead of spaces.
+//!
+//! The type of the arguments after \e pcString must match the requirements of
+//! the format string. For example, if an integer was passed where a string
+//! was expected, an error of some kind will most likely occur.
+//!
+//! The function will copy at most \e ulSize - 1 characters into the buffer
+//! \e pcBuf. One space is reserved in the buffer for the null termination
+//! character.
+//!
+//! The function will return the number of characters that would be converted
+//! as if there were no limit on the buffer size. Therefore it is possible for
+//! the function to return a count that is greater than the specified buffer
+//! size. If this happens, it means that the output was truncated.
+//!
+//! \return Returns the number of characters that were to be stored, not
+//! including the NULL termination character, regardless of space in the
+//! buffer.
+//
+//*****************************************************************************
+int
+usnprintf(char *pcBuf, unsigned long ulSize, const char *pcString, ...)
+{
+ int iRet;
+ va_list vaArgP;
+
+ //
+ // Start the varargs processing.
+ //
+ va_start(vaArgP, pcString);
+
+ //
+ // Call vsnprintf to perform the conversion.
+ //
+ iRet = uvsnprintf(pcBuf, ulSize, pcString, vaArgP);
+
+ //
+ // End the varargs processing.
+ //
+ va_end(vaArgP);
+
+ //
+ // Return the conversion count.
+ //
+ return(iRet);
+}
+
+//*****************************************************************************
+//
+// This array contains the number of days in a year at the beginning of each
+// month of the year, in a non-leap year.
+//
+//*****************************************************************************
+static const short g_psDaysToMonth[12] =
+{
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+};
+
+//*****************************************************************************
+//
+//! Converts from seconds to calendar date and time.
+//!
+//! \param ulTime is the number of seconds.
+//! \param psTime is a pointer to the time structure that is filled in with the
+//! broken down date and time.
+//!
+//! This function converts a number of seconds since midnight GMT on January 1,
+//! 1970 (traditional Unix epoch) into the equivalent month, day, year, hours,
+//! minutes, and seconds representation.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+ulocaltime(unsigned long ulTime, tTime *psTime)
+{
+ unsigned long ulTemp, ulMonths;
+
+ //
+ // Extract the number of seconds, converting time to the number of minutes.
+ //
+ ulTemp = ulTime / 60;
+ psTime->ucSec = ulTime - (ulTemp * 60);
+ ulTime = ulTemp;
+
+ //
+ // Extract the number of minutes, converting time to the number of hours.
+ //
+ ulTemp = ulTime / 60;
+ psTime->ucMin = ulTime - (ulTemp * 60);
+ ulTime = ulTemp;
+
+ //
+ // Extract the number of hours, converting time to the number of days.
+ //
+ ulTemp = ulTime / 24;
+ psTime->ucHour = ulTime - (ulTemp * 24);
+ ulTime = ulTemp;
+
+ //
+ // Compute the day of the week.
+ //
+ psTime->ucWday = (ulTime + 4) % 7;
+
+ //
+ // Compute the number of leap years that have occurred since 1968, the
+ // first leap year before 1970. For the beginning of a leap year, cut the
+ // month loop below at March so that the leap day is classified as February
+ // 29 followed by March 1, instead of March 1 followed by another March 1.
+ //
+ ulTime += 366 + 365;
+ ulTemp = ulTime / ((4 * 365) + 1);
+ if((ulTime - (ulTemp * ((4 * 365) + 1))) > (31 + 28))
+ {
+ ulTemp++;
+ ulMonths = 12;
+ }
+ else
+ {
+ ulMonths = 2;
+ }
+
+ //
+ // Extract the year.
+ //
+ psTime->usYear = ((ulTime - ulTemp) / 365) + 1968;
+ ulTime -= ((psTime->usYear - 1968) * 365) + ulTemp;
+
+ //
+ // Extract the month.
+ //
+ for(ulTemp = 0; ulTemp < ulMonths; ulTemp++)
+ {
+ if(g_psDaysToMonth[ulTemp] > ulTime)
+ {
+ break;
+ }
+ }
+ psTime->ucMon = ulTemp - 1;
+
+ //
+ // Extract the day of the month.
+ //
+ psTime->ucMday = ulTime - g_psDaysToMonth[ulTemp - 1] + 1;
+}
+
+//*****************************************************************************
+//
+//! Compares two time structures and determines if one is greater than,
+//! less than, or equal to the other.
+//!
+//! \param pTime1 is the first time structure to compare.
+//! \param pTime2 is the second time structure to compare.
+//!
+//! This function compares two time structures and returns a signed number
+//! to indicate the result of the comparison. If the time represented by
+//! \e pTime1 is greater than the time represented by \e pTime2 then a positive
+//! number is returned. Likewise if \e pTime1 is less than \e pTime2 then a
+//! negative number is returned. If the two times are equal then the function
+//! returns 0.
+//!
+//! \return Returns 0 if the two times are equal, +1 if \e pTime1 is greater
+//! than \e pTime2, and -1 if \e pTime1 is less than \e pTime2.
+//
+//*****************************************************************************
+static int
+ucmptime(tTime *pTime1, tTime *pTime2)
+{
+ //
+ // Compare each field in descending signficance to determine if
+ // greater than, less than, or equal.
+ //
+ if(pTime1->usYear > pTime2->usYear)
+ {
+ return(1);
+ }
+ else if(pTime1->usYear < pTime2->usYear)
+ {
+ return(-1);
+ }
+ else if(pTime1->ucMon > pTime2->ucMon)
+ {
+ return(1);
+ }
+ else if(pTime1->ucMon < pTime2->ucMon)
+ {
+ return(-1);
+ }
+ else if(pTime1->ucMday > pTime2->ucMday)
+ {
+ return(1);
+ }
+ else if(pTime1->ucMday < pTime2->ucMday)
+ {
+ return(-1);
+ }
+ else if(pTime1->ucHour > pTime2->ucHour)
+ {
+ return(1);
+ }
+ else if(pTime1->ucHour < pTime2->ucHour)
+ {
+ return(-1);
+ }
+ else if(pTime1->ucMin > pTime2->ucMin)
+ {
+ return(1);
+ }
+ else if(pTime1->ucMin < pTime2->ucMin)
+ {
+ return(-1);
+ }
+ else if(pTime1->ucSec > pTime2->ucSec)
+ {
+ return(1);
+ }
+ else if(pTime1->ucSec < pTime2->ucSec)
+ {
+ return(-1);
+ }
+ else
+ {
+ //
+ // Reaching this branch of the conditional means that all of the
+ // fields are equal, and thus the two times are equal.
+ //
+ return(0);
+ }
+}
+
+//*****************************************************************************
+//
+//! Converts calendar date and time to seconds.
+//!
+//! \param psTime is a pointer to the time structure that is filled in with the
+//! broken down date and time.
+//!
+//! This function converts the date and time represented by the \e psTime
+//! structure pointer to the number of seconds since midnight GMT on January 1,
+//! 1970 (traditional Unix epoch).
+//!
+//! \return Returns the calendar time and date as seconds. If the conversion
+//! was not possible then the function returns (unsigned long)(-1).
+//
+//*****************************************************************************
+unsigned long
+umktime(tTime *psTime)
+{
+ tTime sTimeGuess;
+ unsigned long ulTimeGuess = 0x80000000;
+ unsigned long ulAdjust = 0x40000000;
+ int iSign;
+
+ //
+ // Seed the binary search with the first guess.
+ //
+ ulocaltime(ulTimeGuess, &sTimeGuess);
+ iSign = ucmptime(psTime, &sTimeGuess);
+
+ //
+ // While the time is not yet found, execute a binary search.
+ //
+ while(iSign && ulAdjust)
+ {
+ //
+ // Adjust the time guess up or down depending on the result of the
+ // last compare.
+ //
+ ulTimeGuess = (iSign > 0) ? (ulTimeGuess + ulAdjust) :
+ (ulTimeGuess - ulAdjust);
+ ulAdjust /= 2;
+
+ //
+ // Compare the new time guess against the time pointed at by the
+ // function parameters.
+ //
+ ulocaltime(ulTimeGuess, &sTimeGuess);
+ iSign = ucmptime(psTime, &sTimeGuess);
+ };
+
+ //
+ // If the above loop was exited with iSign == 0, that means that the
+ // time in seconds was found, so return that value to the caller.
+ //
+ if(iSign == 0)
+ {
+ return(ulTimeGuess);
+ }
+
+ //
+ // Otherwise the time could not be converted so return an error.
+ //
+ else
+ {
+ return((unsigned long)-1);
+ }
+}
+
+//*****************************************************************************
+//
+//! Converts a string into its numeric equivalent.
+//!
+//! \param pcStr is a pointer to the string containing the integer.
+//! \param ppcStrRet is a pointer that will be set to the first character past
+//! the integer in the string.
+//! \param iBase is the radix to use for the conversion; can be zero to
+//! auto-select the radix or between 2 and 16 to explicitly specify the radix.
+//!
+//! This function is very similar to the C library <tt>strtoul()</tt> function.
+//! It scans a string for the first token (that is, non-white space) and
+//! converts the value at that location in the string into an integer value.
+//!
+//! \return Returns the result of the conversion.
+//
+//*****************************************************************************
+unsigned long
+ustrtoul(const char *pcStr, const char **ppcStrRet, int iBase)
+{
+ unsigned long ulRet, ulDigit, ulNeg, ulValid;
+ const char *pcPtr;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(pcStr);
+ ASSERT((iBase == 0) || ((iBase > 1) && (iBase <= 16)));
+
+ //
+ // Initially, the result is zero.
+ //
+ ulRet = 0;
+ ulNeg = 0;
+ ulValid = 0;
+
+ //
+ // Skip past any leading white space.
+ //
+ pcPtr = pcStr;
+ while((*pcPtr == ' ') || (*pcPtr == '\t'))
+ {
+ pcPtr++;
+ }
+
+ //
+ // Take a leading + or - from the value.
+ //
+ if(*pcPtr == '-')
+ {
+ ulNeg = 1;
+ pcPtr++;
+ }
+ else if(*pcPtr == '+')
+ {
+ pcPtr++;
+ }
+
+ //
+ // See if the radix was not specified, or is 16, and the value starts with
+ // "0x" or "0X" (to indicate a hex value).
+ //
+ if(((iBase == 0) || (iBase == 16)) && (*pcPtr == '0') &&
+ ((pcPtr[1] == 'x') || (pcPtr[1] == 'X')))
+ {
+ //
+ // Skip the leading "0x".
+ //
+ pcPtr += 2;
+
+ //
+ // Set the radix to 16.
+ //
+ iBase = 16;
+ }
+
+ //
+ // See if the radix was not specified.
+ //
+ if(iBase == 0)
+ {
+ //
+ // See if the value starts with "0".
+ //
+ if(*pcPtr == '0')
+ {
+ //
+ // Values that start with "0" are assumed to be radix 8.
+ //
+ iBase = 8;
+ }
+ else
+ {
+ //
+ // Otherwise, the values are assumed to be radix 10.
+ //
+ iBase = 10;
+ }
+ }
+
+ //
+ // Loop while there are more valid digits to consume.
+ //
+ while(1)
+ {
+ //
+ // See if this character is a number.
+ //
+ if((*pcPtr >= '0') && (*pcPtr <= '9'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - '0';
+ }
+
+ //
+ // Otherwise, see if this character is an upper case letter.
+ //
+ else if((*pcPtr >= 'A') && (*pcPtr <= 'Z'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - 'A' + 10;
+ }
+
+ //
+ // Otherwise, see if this character is a lower case letter.
+ //
+ else if((*pcPtr >= 'a') && (*pcPtr <= 'z'))
+ {
+ //
+ // Convert the character to its integer equivalent.
+ //
+ ulDigit = *pcPtr++ - 'a' + 10;
+ }
+
+ //
+ // Otherwise, this is not a valid character.
+ //
+ else
+ {
+ //
+ // Stop converting this value.
+ //
+ break;
+ }
+
+ //
+ // See if this digit is valid for the chosen radix.
+ //
+ if(ulDigit >= iBase)
+ {
+ //
+ // Since this was not a valid digit, move the pointer back to the
+ // character that therefore should not have been consumed.
+ //
+ pcPtr--;
+
+ //
+ // Stop converting this value.
+ //
+ break;
+ }
+
+ //
+ // Add this digit to the converted value.
+ //
+ ulRet *= iBase;
+ ulRet += ulDigit;
+
+ //
+ // Since a digit has been added, this is now a valid result.
+ //
+ ulValid = 1;
+ }
+
+ //
+ // Set the return string pointer to the first character not consumed.
+ //
+ if(ppcStrRet)
+ {
+ *ppcStrRet = ulValid ? pcPtr : pcStr;
+ }
+
+ //
+ // Return the converted value.
+ //
+ return(ulNeg ? (0 - ulRet) : ulRet);
+}
+
+//*****************************************************************************
+//
+//! Retruns the length of a null-terminated string.
+//!
+//! \param pcStr is a pointer to the string whose length is to be found.
+//!
+//! This function is very similar to the C library <tt>strlen()</tt> function.
+//! It determines the length of the null-terminated string passed and returns
+//! this to the caller.
+//!
+//! This implementation assumes that single byte character strings are passed
+//! and will return incorrect values if passed some UTF-8 strings.
+//!
+//! \return Returns the length of the string pointed to by \e pcStr.
+//
+//*****************************************************************************
+int
+ustrlen(const char * pcStr)
+{
+ int iLen;
+
+ ASSERT(pcStr);
+
+ //
+ // Initialize the length.
+ //
+ iLen = 0;
+
+ //
+ // Step throug the string looking for a zero character (marking its end).
+ //
+ while(pcStr[iLen])
+ {
+ //
+ // Zero not found so move on to the next character.
+ //
+ iLen++;
+ }
+
+ return(iLen);
+}
+
+//*****************************************************************************
+//
+//! Finds a substring within a string.
+//!
+//! \param pcHaystack is a pointer to the string that will be searched.
+//! \param pcNeedle is a pointer to the substring that is to be found within
+//! \e pcHaystack.
+//!
+//! This function is very similar to the C library <tt>strstr()</tt> function.
+//! It scans a string for the first instance of a given substring and returns
+//! a pointer to that substring. If the substring cannot be found, a NULL
+//! pointer is returned.
+//!
+//! \return Returns a pointer to the first occurrence of \e pcNeedle within
+//! \e pcHaystack or NULL if no match is found.
+//
+//*****************************************************************************
+char *
+ustrstr(const char *pcHaystack, const char *pcNeedle)
+{
+ unsigned long ulLength;
+
+ //
+ // Get the length of the string to be found.
+ //
+ ulLength = ustrlen(pcNeedle);
+
+ //
+ // Loop while we have not reached the end of the string.
+ //
+ while(*pcHaystack)
+ {
+ //
+ // Check to see if the substring appears at this position.
+ //
+ if(ustrncmp(pcNeedle, pcHaystack, ulLength) == 0)
+ {
+ //
+ // It does so return the pointer.
+ //
+ return((char *)pcHaystack);
+ }
+
+ //
+ // Move to the next position in the string being searched.
+ //
+ pcHaystack++;
+ }
+
+ //
+ // We reached the end of the string without finding the substring so
+ // return NULL.
+ //
+ return((char *)0);
+}
+
+//*****************************************************************************
+//
+//! Compares two strings without regard to case.
+//!
+//! \param pcStr1 points to the first string to be compared.
+//! \param pcStr2 points to the second string to be compared.
+//! \param iCount is the maximum number of characters to compare.
+//!
+//! This function is very similar to the C library <tt>strnicmp()</tt> function.
+//! It compares at most \e iCount characters of two strings without regard to
+//! case. The comparison ends if a terminating NULL character is found in
+//! either string before \e iCount characters are compared. In this case, the
+//! shorter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e pcStr1 is less
+//! than \e pcStr2 and 1 if \e pcStr1 is greater than \e pcStr2.
+//
+//*****************************************************************************
+int
+ustrnicmp(const char *pcStr1, const char *pcStr2, int iCount)
+{
+ char cL1, cL2;
+
+ while(iCount)
+ {
+ //
+ // If we reached a NULL in both strings, they must be equal so
+ // we end the comparison and return 0
+ //
+ if(!*pcStr1 && !*pcStr2)
+ {
+ return(0);
+ }
+
+ //
+ // Lower case the characters at the current position before we compare.
+ //
+ cL1 = (((*pcStr1 >= 'A') && (*pcStr1 <= 'Z')) ?
+ (*pcStr1 + ('a' - 'A')) : *pcStr1);
+ cL2 = (((*pcStr2 >= 'A') && (*pcStr2 <= 'Z')) ?
+ (*pcStr2 + ('a' - 'A')) : *pcStr2);
+ //
+ // Compare the two characters and, if different, return the relevant
+ // return code.
+ //
+ if(cL2 < cL1)
+ {
+ return(1);
+ }
+ if(cL1 < cL2)
+ {
+ return(-1);
+ }
+
+ //
+ // Move on to the next character.
+ //
+ pcStr1++;
+ pcStr2++;
+ iCount--;
+ }
+
+ //
+ // If we fall out, the strings must be equal for at least the first iCount
+ // characters so return 0 to indicate this.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+//! Compares two strings without regard to case.
+//!
+//! \param pcStr1 points to the first string to be compared.
+//! \param pcStr2 points to the second string to be compared.
+//!
+//! This function is very similar to the C library <tt>strcasecmp()</tt>
+//! function. It compares two strings without regard to case. The comparison
+//! ends if a terminating NULL character is found in either string. In this
+//! case, the shorter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e pcStr1 is less
+//! than \e pcStr2 and 1 if \e pcStr1 is greater than \e pcStr2.
+//
+//*****************************************************************************
+int
+ustrcasecmp(const char *pcStr1, const char *pcStr2)
+{
+ //
+ // Just let ustrnicmp() handle this.
+ //
+ return(ustrnicmp(pcStr1, pcStr2, -1));
+}
+
+//*****************************************************************************
+//
+//! Compares two strings.
+//!
+//! \param pcStr1 points to the first string to be compared.
+//! \param pcStr2 points to the second string to be compared.
+//! \param iCount is the maximum number of characters to compare.
+//!
+//! This function is very similar to the C library <tt>strncmp()</tt> function.
+//! It compares at most \e iCount characters of two strings taking case into
+//! account. The comparison ends if a terminating NULL character is found in
+//! either string before \e iCount characters are compared. In this case, the
+//! shorter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e pcStr1 is less
+//! than \e pcStr2 and 1 if \e pcStr1 is greater than \e pcStr2.
+//
+//*****************************************************************************
+int
+ustrncmp(const char *pcStr1, const char *pcStr2, int iCount)
+{
+ while(iCount)
+ {
+ //
+ // If we reached a NULL in both strings, they must be equal so
+ // we end the comparison and return 0
+ //
+ if(!*pcStr1 && !*pcStr2)
+ {
+ return(0);
+ }
+
+ //
+ // Compare the two characters and, if different, return the relevant
+ // return code.
+ //
+ if(*pcStr2 < *pcStr1)
+ {
+ return(1);
+ }
+ if(*pcStr1 < *pcStr2)
+ {
+ return(-1);
+ }
+
+ //
+ // Move on to the next character.
+ //
+ pcStr1++;
+ pcStr2++;
+ iCount--;
+ }
+
+ //
+ // If we fall out, the strings must be equal for at least the first iCount
+ // characters so return 0 to indicate this.
+ //
+ return(0);
+
+}
+
+//*****************************************************************************
+//
+//! Compares two strings.
+//!
+//! \param pcStr1 points to the first string to be compared.
+//! \param pcStr2 points to the second string to be compared.
+//!
+//! This function is very similar to the C library <tt>strcmp()</tt>
+//! function. It compares two strings, taking case into account. The
+//! comparison ends if a terminating NULL character is found in either string.
+//! In this case, the shorter string is deemed the lesser.
+//!
+//! \return Returns 0 if the two strings are equal, -1 if \e pcStr1 is less
+//! than \e pcStr2 and 1 if \e pcStr1 is greater than \e pcStr2.
+//
+//*****************************************************************************
+int
+ustrcmp(const char *pcStr1, const char *pcStr2)
+{
+ //
+ // Pass this on to ustrncmp.
+ //
+ return(ustrncmp(pcStr1, pcStr2, -1));
+}
+
+//*****************************************************************************
+//
+// Random Number Generator Seed Value
+//
+//*****************************************************************************
+static unsigned long g_ulRandomSeed = 1;
+
+//*****************************************************************************
+//
+//! Set the random number generator seed.
+//!
+//! \param ulSeed is the new seed value to use for the random number generator.
+//!
+//! This function is very similar to the C library <tt>srand()</tt> function.
+//! It will set the seed value used in the <tt>urand()</tt> function.
+//!
+//! \return None
+//
+//*****************************************************************************
+void
+usrand(unsigned long ulSeed)
+{
+ g_ulRandomSeed = ulSeed;
+}
+
+//*****************************************************************************
+//
+//! Generate a new (pseudo) random number
+//!
+//! This function is very similar to the C library <tt>rand()</tt> function.
+//! It will generate a pseudo-random number sequence based on the seed value.
+//!
+//! \return A pseudo-random number will be returned.
+//
+//*****************************************************************************
+int
+urand(void)
+{
+ //
+ // Generate a new pseudo-random number with a linear congruence random
+ // number generator. This new random number becomes the seed for the next
+ // random number.
+ //
+ g_ulRandomSeed = (g_ulRandomSeed * 1664525) + 1013904223;
+
+ //
+ // Return the new random number.
+ //
+ return((int)g_ulRandomSeed);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
diff --git a/utils/ustdlib.h b/utils/ustdlib.h
new file mode 100644
index 0000000..3d359a6
--- /dev/null
+++ b/utils/ustdlib.h
@@ -0,0 +1,130 @@
+//*****************************************************************************
+//
+// ustdlib.h - Prototypes for simple standard library functions.
+//
+// Copyright (c) 2007-2012 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 9453 of the Stellaris Firmware Development Package.
+//
+//*****************************************************************************
+
+#ifndef __USTDLIB_H__
+#define __USTDLIB_H__
+
+#include <stdarg.h>
+
+//*****************************************************************************
+//
+// If building with a C++ compiler, make all of the definitions in this header
+// have a C binding.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+//*****************************************************************************
+//
+//! \addtogroup ustdlib_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+//! A structure that contains the broken down date and time.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ //! The number of years since 0 AD.
+ //
+ unsigned short usYear;
+
+ //
+ //! The month, where January is 0 and December is 11.
+ //
+ unsigned char ucMon;
+
+ //
+ //! The day of the month.
+ //
+ unsigned char ucMday;
+
+ //
+ //! The day of the week, where Sunday is 0 and Saturday is 6.
+ //
+ unsigned char ucWday;
+
+ //
+ //! The number of hours.
+ //
+ unsigned char ucHour;
+
+ //
+ //! The number of minutes.
+ //
+ unsigned char ucMin;
+
+ //
+ //! The number of seconds.
+ //
+ unsigned char ucSec;
+}
+tTime;
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Prototypes for the APIs.
+//
+//*****************************************************************************
+extern int uvsnprintf(char *pcBuf, unsigned long ulSize, const char *pcString,
+ va_list vaArgP);
+extern int usprintf(char *pcBuf, const char *pcString, ...);
+extern int usnprintf(char *pcBuf, unsigned long ulSize, const char *pcString,
+ ...);
+extern void ulocaltime(unsigned long ulTime, tTime *psTime);
+extern unsigned long umktime(tTime *psTime);
+extern int ustrlen (const char *pcStr);
+extern char *ustrncpy (char *pcDst, const char *pcSrc, int iNum);
+extern unsigned long ustrtoul(const char *pcStr, const char **ppcStrRet,
+ int iBase);
+extern char *ustrstr(const char *pcHaystack, const char *pcNeedle);
+extern int ustrnicmp(const char *pcStr1, const char *pcStr2, int iCount);
+extern int ustrncmp(const char *pcStr1, const char *pcStr2, int iCount);
+extern int ustrcmp(const char *pcStr1, const char *pcStr2);
+extern int ustrcasecmp(const char *pcStr1, const char *pcStr2);
+
+//*****************************************************************************
+//
+// Mark the end of the C bindings section for C++ compilers.
+//
+//*****************************************************************************
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __USTDLIB_H__
diff --git a/utils/utils.sgxx b/utils/utils.sgxx
new file mode 100644
index 0000000..a4f24d2
--- /dev/null
+++ b/utils/utils.sgxx
Binary files differ