diff --git a/firmware/Makefile b/firmware/Makefile index 703c456d..befddb99 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -40,25 +40,8 @@ BOARD ?= qmod # Defines which are the available memory targets for the SAM3S-EK board. MEMORIES ?= flash dfu -# Trace level used for compilation -# (can be overriden by adding TRACE_LEVEL=#number to the command-line) -# TRACE_LEVEL_DEBUG 5 -# TRACE_LEVEL_INFO 4 -# TRACE_LEVEL_WARNING 3 -# TRACE_LEVEL_ERROR 2 -# TRACE_LEVEL_FATAL 1 -# TRACE_LEVEL_NO_TRACE 0 -TRACE_LEVEL ?= 4 - -DEBUG_PHONE_SNIFF=0 - -#CFLAGS+=-DUSB_NO_DEBUG=1 - -# Optimization level, put in comment for debugging -OPTIMIZATION = -O0 - # Output file basename -APP = dfu +APP ?= dfu # Output directories OUTPUT = $(BOARD)-$(APP) @@ -78,7 +61,7 @@ AT91LIB_USB_DFU_PATH = $(AT91LIB)/usb/device/dfu # Tool suffix when cross-compiling CROSS_COMPILE = arm-none-eabi- -LIBS = -Wl,--start-group -lgcc -lc -Wl,--end-group +LIBS = -Wl,--start-group -lgcc -Wl,--end-group -nostdlib # Compilation tools CC = $(CROSS_COMPILE)gcc @@ -92,6 +75,60 @@ NM = $(CROSS_COMPILE)nm TOP=.. GIT_VERSION=$(shell $(TOP)/git-version-gen $(TOP)/.tarvers) +#------------------------------------------------------------------------------- +# Files +#------------------------------------------------------------------------------- + +# Directories where source files can be found + +USB_PATHS = $(AT91LIB_USB_CORE_PATH) $(AT91LIB_USB_DFU_PATH) $(AT91LIB_USB_COMMON_CORE_PATH) + +VPATH += $(USB_PATHS) +VPATH += $(AT91LIB)/libchip_sam3s/source/ $(AT91LIB)/libchip_sam3s/cmsis +VPATH += libboard/common/source libboard/$(BOARD)/source +VPATH += libcommon/source +VPATH += libosmocore/source src_board src_simtrace +VPATH += apps/$(APP) + +# Objects built from C source files +C_OSMOCORE = $(notdir $(wildcard libosmocore/source/*.c)) +C_LIBCHIP = $(notdir $(wildcard $(AT91LIB)/libchip_sam3s/source/*.c) $(wildcard $(AT91LIB)/libchip_sam3s/cmsis/*.c)) + +C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.c USBDDriverCallbacks.c +C_LIBUSB_RT = dfu.c dfu_desc.c dfu_runtime.c +C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c +C_LIBCOMMON = string.c stdio.c fputs.c req_ctx.c ringbuffer.c + +C_BOARD = $(notdir $(wildcard libboard/common/source/*.c)) +C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c)) + +C_APPLEVEL = $(notdir $(wildcard apps/$(APP)/*.c)) + +C_FILES = $(C_OSMOCORE) $(C_LIBCHIP) $(C_LIBUSB) $(C_LIBCOMMON) $(C_BOARD) $(C_APPLEVEL) + +-include apps/$(APP)/Makefile + +C_OBJECTS = $(C_FILES:%.c=%.o) + +# Trace level used for compilation +# (can be overriden by adding TRACE_LEVEL=#number to the command-line) +# TRACE_LEVEL_DEBUG 5 +# TRACE_LEVEL_INFO 4 +# TRACE_LEVEL_WARNING 3 +# TRACE_LEVEL_ERROR 2 +# TRACE_LEVEL_FATAL 1 +# TRACE_LEVEL_NO_TRACE 0 +TRACE_LEVEL ?= 4 + +DEBUG_PHONE_SNIFF?=0 + +#CFLAGS+=-DUSB_NO_DEBUG=1 + +# Optimization level, put in comment for debugging +OPTIMIZATION ?= -O0 + + + # Flags INCLUDES_USB = -I$(AT91LIB)/usb/include -I$(AT91LIB) @@ -122,9 +159,6 @@ CFLAGS += -Wmissing-noreturn CFLAGS += -Wno-unused-but-set-variable -Wno-unused-variable CFLAGS += -Wno-suggest-attribute=noreturn -# To reduce application size use only integer printf function. -CFLAGS += -Dprintf=iprintf - # -mlong-calls -Wall #CFLAGS += -save-temps -fverbose-asm #CFLAGS += -Wa,-a,-ad @@ -136,40 +170,6 @@ ASFLAGS = -mcpu=cortex-m3 -mthumb -Wall -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) LDFLAGS = -mcpu=cortex-m3 -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=ResetException -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols $(LIB) #LD_OPTIONAL=-Wl,--print-gc-sections -Wl,--stats -#------------------------------------------------------------------------------- -# Files -#------------------------------------------------------------------------------- - -# Directories where source files can be found - -USB_PATHS = $(AT91LIB_USB_CORE_PATH) $(AT91LIB_USB_DFU_PATH) $(AT91LIB_USB_COMMON_CORE_PATH) - -VPATH += $(USB_PATHS) -VPATH += $(AT91LIB)/libchip_sam3s/source/ $(AT91LIB)/libchip_sam3s/cmsis -VPATH += libboard/common/source libboard/$(BOARD)/source -VPATH += libcommon/source -VPATH += libosmocore/source src_board src_simtrace -VPATH += apps/$(APP) - -# Objects built from C source files -C_OSMOCORE = $(notdir $(wildcard libosmocore/source/*.c)) -C_LIBCHIP = $(notdir $(wildcard $(AT91LIB)/libchip_sam3s/source/*.c) $(wildcard $(AT91LIB)/libchip_sam3s/cmsis/*.c)) - -C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.c USBDDriverCallbacks.c -C_LIBUSB_RT = dfu.c dfu_desc.c dfu_runtime.c -C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c -C_LIBCOMMON = syscalls.c req_ctx.c ringbuffer.c - -C_BOARD = $(notdir $(wildcard libboard/common/source/*.c)) -C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c)) - -C_APPLEVEL = $(notdir $(wildcard apps/$(APP)/*.c)) - -C_FILES = $(C_OSMOCORE) $(C_LIBCHIP) $(C_LIBUSB) $(C_LIBCOMMON) $(C_BOARD) $(C_APPLEVEL) - --include apps/$(APP)/Makefile - -C_OBJECTS = $(C_FILES:%.c=%.o) # Append OBJ and BIN directories to output filename OUTPUT := $(BIN)/$(OUTPUT) diff --git a/firmware/apps/dfu/Makefile b/firmware/apps/dfu/Makefile index 0d19e699..141b01fb 100644 --- a/firmware/apps/dfu/Makefile +++ b/firmware/apps/dfu/Makefile @@ -1 +1,12 @@ + C_FILES += $(C_LIBUSB_DFU) + +# Trace level used for compilation +# (can be overriden by adding TRACE_LEVEL=#number to the command-line) +# TRACE_LEVEL_DEBUG 5 +# TRACE_LEVEL_INFO 4 +# TRACE_LEVEL_WARNING 3 +# TRACE_LEVEL_ERROR 2 +# TRACE_LEVEL_FATAL 1 +# TRACE_LEVEL_NO_TRACE 0 +TRACE_LEVEL ?= 3 diff --git a/firmware/libboard/common/source/board_cstartup_gnu.c b/firmware/libboard/common/source/board_cstartup_gnu.c index 42556466..17592b03 100644 --- a/firmware/libboard/common/source/board_cstartup_gnu.c +++ b/firmware/libboard/common/source/board_cstartup_gnu.c @@ -61,7 +61,6 @@ extern uint32_t _ezero; extern int main( void ) ; /** \endcond */ void ResetException( void ) ; -extern void __libc_init_array( void ) ; /*------------------------------------------------------------------------------ * Exception Table @@ -181,9 +180,6 @@ void ResetException( void ) SCB->VTOR |= 1 << SCB_VTOR_TBLBASE_Pos ; } - /* Initialize the C library */ - __libc_init_array() ; - /* Branch to main function */ main() ; diff --git a/firmware/libcommon/include/assert.h b/firmware/libcommon/include/assert.h new file mode 100644 index 00000000..f96339ee --- /dev/null +++ b/firmware/libcommon/include/assert.h @@ -0,0 +1,115 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !Purpose +/// +/// Definition of the ASSERT() and SANITY_CHECK() macros, which are used for +/// runtime condition & parameter verifying. +/// +/// !Usage +/// +/// -# Use ASSERT() in your code to check the value of function parameters, +/// return values, etc. *Warning:* the ASSERT() condition must not have +/// any side-effect; otherwise, the program may not work properly +/// anymore when assertions are disabled. +/// -# Use SANITY_CHECK() to perform checks with a default error message +/// (outputs the file and line number where the error occured). This +/// reduces memory overhead caused by assertion error strings. +/// -# Initialize the dbgu to see failed assertions at run-time. +/// -# Assertions can be entirely disabled by defining the NOASSERT symbol +/// at compilation time. +//------------------------------------------------------------------------------ + +#ifndef ASSERT_H +#define ASSERT_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include "trace.h" + +#define assert ASSERT + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ +#if defined(NOASSERT) + #define ASSERT(...) + #define SANITY_CHECK(...) +#else + + #if (TRACE_LEVEL == 0) + /// Checks that the given condition is true, + /// otherwise stops the program execution. + /// \param condition Condition to verify. + #define ASSERT(condition) { \ + if (!(condition)) { \ + while (1); \ + } \ + } + + /// Performs the same duty as the ASSERT() macro + /// \param condition Condition to verify. + #define SANITY_CHECK(condition) ASSERT(condition, ...) + + #else + /// Checks that the given condition is true, otherwise displays an error + /// message and stops the program execution. + /// \param condition Condition to verify. + #define ASSERT(condition) { \ + if (!(condition)) { \ + printf("-F- ASSERT: %s %s:%d\r\n", #condition, __BASE_FILE__, __LINE__); \ + while (1); \ + } \ + } + #define SANITY_ERROR "Sanity check failed at %s:%d\n\r" + + /// Performs the same duty as the ASSERT() macro, except a default error + /// message is output if the condition is false. + /// \param condition Condition to verify. + #define SANITY_CHECK(condition) ASSERT(condition, SANITY_ERROR, __FILE__, __LINE__) + #endif +#endif + + + + + + + + + + +#endif //#ifndef ASSERT_H + diff --git a/firmware/libcommon/source/fputs.c b/firmware/libcommon/source/fputs.c new file mode 100644 index 00000000..f7add108 --- /dev/null +++ b/firmware/libcommon/source/fputs.c @@ -0,0 +1,15 @@ +#include +#include "uart_console.h" + +int fputc(int c, FILE *stream) +{ + UART_PutChar(c); + return c; +} + +int fputs(const char *s, FILE *stream) +{ + while (*s != '\0') + UART_PutChar(*s++); + return 0; +} diff --git a/firmware/libcommon/source/stdio.c b/firmware/libcommon/source/stdio.c new file mode 100644 index 00000000..f69e8bd0 --- /dev/null +++ b/firmware/libcommon/source/stdio.c @@ -0,0 +1,512 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !Purpose +/// +/// Implementation of several stdio.h methods, such as printf(), sprintf() and +/// so on. This reduces the memory footprint of the binary when using those +/// methods, compared to the libc implementation. +/// +/// !Usage +/// +/// Adds stdio.c to the list of file to compile for the project. This will +/// automatically replace libc methods by the custom ones. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include +#include + +//------------------------------------------------------------------------------ +// Local Definitions +//------------------------------------------------------------------------------ + +// Maximum string size allowed (in bytes). +#define MAX_STRING_SIZE 100 + +//------------------------------------------------------------------------------ +// Global Variables +//------------------------------------------------------------------------------ + +// Required for proper compilation. +struct _reent r = {0, (FILE *) 0, (FILE *) 1, (FILE *) 0}; +struct _reent *_impure_ptr = &r; + +//------------------------------------------------------------------------------ +// Local Functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Writes a character inside the given string. Returns 1. +// \param pStr Storage string. +// \param c Character to write. +//------------------------------------------------------------------------------ +signed int PutChar(char *pStr, char c) +{ + *pStr = c; + return 1; +} + +//------------------------------------------------------------------------------ +// Writes a string inside the given string. +// Returns the size of the written +// string. +// \param pStr Storage string. +// \param pSource Source string. +//------------------------------------------------------------------------------ +signed int PutString(char *pStr, const char *pSource) +{ + signed int num = 0; + + while (*pSource != 0) { + + *pStr++ = *pSource++; + num++; + } + + return num; +} + +//------------------------------------------------------------------------------ +// Writes an unsigned int inside the given string, using the provided fill & +// width parameters. +// Returns the size in characters of the written integer. +// \param pStr Storage string. +// \param fill Fill character. +// \param width Minimum integer width. +// \param value Integer value. +//------------------------------------------------------------------------------ +signed int PutUnsignedInt( + char *pStr, + char fill, + signed int width, + unsigned int value) +{ + signed int num = 0; + + // Take current digit into account when calculating width + width--; + + // Recursively write upper digits + if ((value / 10) > 0) { + + num = PutUnsignedInt(pStr, fill, width, value / 10); + pStr += num; + } + // Write filler characters + else { + + while (width > 0) { + + PutChar(pStr, fill); + pStr++; + num++; + width--; + } + } + + // Write lower digit + num += PutChar(pStr, (value % 10) + '0'); + + return num; +} + +//------------------------------------------------------------------------------ +// Writes a signed int inside the given string, using the provided fill & width +// parameters. +// Returns the size of the written integer. +// \param pStr Storage string. +// \param fill Fill character. +// \param width Minimum integer width. +// \param value Signed integer value. +//------------------------------------------------------------------------------ +signed int PutSignedInt( + char *pStr, + char fill, + signed int width, + signed int value) +{ + signed int num = 0; + unsigned int absolute; + + // Compute absolute value + if (value < 0) { + + absolute = -value; + } + else { + + absolute = value; + } + + // Take current digit into account when calculating width + width--; + + // Recursively write upper digits + if ((absolute / 10) > 0) { + + if (value < 0) { + + num = PutSignedInt(pStr, fill, width, -(absolute / 10)); + } + else { + + num = PutSignedInt(pStr, fill, width, absolute / 10); + } + pStr += num; + } + else { + + // Reserve space for sign + if (value < 0) { + + width--; + } + + // Write filler characters + while (width > 0) { + + PutChar(pStr, fill); + pStr++; + num++; + width--; + } + + // Write sign + if (value < 0) { + + num += PutChar(pStr, '-'); + pStr++; + } + } + + // Write lower digit + num += PutChar(pStr, (absolute % 10) + '0'); + + return num; +} + +//------------------------------------------------------------------------------ +// Writes an hexadecimal value into a string, using the given fill, width & +// capital parameters. +// Returns the number of char written. +// \param pStr Storage string. +// \param fill Fill character. +// \param width Minimum integer width. +// \param maj Indicates if the letters must be printed in lower- or upper-case. +// \param value Hexadecimal value. +//------------------------------------------------------------------------------ +signed int PutHexa( + char *pStr, + char fill, + signed int width, + unsigned char maj, + unsigned int value) +{ + signed int num = 0; + + // Decrement width + width--; + + // Recursively output upper digits + if ((value >> 4) > 0) { + + num += PutHexa(pStr, fill, width, maj, value >> 4); + pStr += num; + } + // Write filler chars + else { + + while (width > 0) { + + PutChar(pStr, fill); + pStr++; + num++; + width--; + } + } + + // Write current digit + if ((value & 0xF) < 10) { + + PutChar(pStr, (value & 0xF) + '0'); + } + else if (maj) { + + PutChar(pStr, (value & 0xF) - 10 + 'A'); + } + else { + + PutChar(pStr, (value & 0xF) - 10 + 'a'); + } + num++; + + return num; +} + +//------------------------------------------------------------------------------ +// Global Functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Stores the result of a formatted string into another string. Format +/// arguments are given in a va_list instance. +/// Return the number of characters written. +/// \param pStr Destination string. +/// \param length Length of Destination string. +/// \param pFormat Format string. +/// \param ap Argument list. +//------------------------------------------------------------------------------ +signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap) +{ + char fill; + unsigned char width; + signed int num = 0; + signed int size = 0; + + // Clear the string + if (pStr) { + + *pStr = 0; + } + + // Phase string + while (*pFormat != 0 && size < length) { + + // Normal character + if (*pFormat != '%') { + + *pStr++ = *pFormat++; + size++; + } + // Escaped '%' + else if (*(pFormat+1) == '%') { + + *pStr++ = '%'; + pFormat += 2; + size++; + } + // Token delimiter + else { + + fill = ' '; + width = 0; + pFormat++; + + // Parse filler + if (*pFormat == '0') { + + fill = '0'; + pFormat++; + } + + // Parse width + while ((*pFormat >= '0') && (*pFormat <= '9')) { + + width = (width*10) + *pFormat-'0'; + pFormat++; + } + + // Check if there is enough space + if (size + width > length) { + + width = length - size; + } + + // Parse type + switch (*pFormat) { + case 'd': + case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break; + case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break; + case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break; + case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break; + case 's': num = PutString(pStr, va_arg(ap, char *)); break; + case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break; + default: + return EOF; + } + + pFormat++; + pStr += num; + size += num; + } + } + + // NULL-terminated (final \0 is not counted) + if (size < length) { + + *pStr = 0; + } + else { + + *(--pStr) = 0; + size--; + } + + return size; +} + +//------------------------------------------------------------------------------ +/// Stores the result of a formatted string into another string. Format +/// arguments are given in a va_list instance. +/// Return the number of characters written. +/// \param pString Destination string. +/// \param length Length of Destination string. +/// \param pFormat Format string. +/// \param ... Other arguments +//------------------------------------------------------------------------------ +signed int snprintf(char *pString, size_t length, const char *pFormat, ...) +{ + va_list ap; + signed int rc; + + va_start(ap, pFormat); + rc = vsnprintf(pString, length, pFormat, ap); + va_end(ap); + + return rc; +} + +//------------------------------------------------------------------------------ +/// Stores the result of a formatted string into another string. Format +/// arguments are given in a va_list instance. +/// Return the number of characters written. +/// \param pString Destination string. +/// \param pFormat Format string. +/// \param ap Argument list. +//------------------------------------------------------------------------------ +signed int vsprintf(char *pString, const char *pFormat, va_list ap) +{ + return vsnprintf(pString, MAX_STRING_SIZE, pFormat, ap); +} + +//------------------------------------------------------------------------------ +/// Outputs a formatted string on the given stream. Format arguments are given +/// in a va_list instance. +/// \param pStream Output stream. +/// \param pFormat Format string +/// \param ap Argument list. +//------------------------------------------------------------------------------ +signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap) +{ + char pStr[MAX_STRING_SIZE]; + char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r"; + + // Write formatted string in buffer + if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) { + + fputs(pError, stderr); + while (1); // Increase MAX_STRING_SIZE + } + + // Display string + return fputs(pStr, pStream); +} + +//------------------------------------------------------------------------------ +/// Outputs a formatted string on the DBGU stream. Format arguments are given +/// in a va_list instance. +/// \param pFormat Format string +/// \param ap Argument list. +//------------------------------------------------------------------------------ +signed int vprintf(const char *pFormat, va_list ap) +{ + return vfprintf(stdout, pFormat, ap); +} + +//------------------------------------------------------------------------------ +/// Outputs a formatted string on the given stream, using a variable number of +/// arguments. +/// \param pStream Output stream. +/// \param pFormat Format string. +//------------------------------------------------------------------------------ +signed int fprintf(FILE *pStream, const char *pFormat, ...) +{ + va_list ap; + signed int result; + + // Forward call to vfprintf + va_start(ap, pFormat); + result = vfprintf(pStream, pFormat, ap); + va_end(ap); + + return result; +} + +//------------------------------------------------------------------------------ +/// Outputs a formatted string on the DBGU stream, using a variable number of +/// arguments. +/// \param pFormat Format string. +//------------------------------------------------------------------------------ +signed int printf(const char *pFormat, ...) +{ + va_list ap; + signed int result; + + // Forward call to vprintf + va_start(ap, pFormat); + result = vprintf(pFormat, ap); + va_end(ap); + + return result; +} + +//------------------------------------------------------------------------------ +/// Writes a formatted string inside another string. +/// \param pStr Storage string. +/// \param pFormat Format string. +//------------------------------------------------------------------------------ +signed int sprintf(char *pStr, const char *pFormat, ...) +{ + va_list ap; + signed int result; + + // Forward call to vsprintf + va_start(ap, pFormat); + result = vsprintf(pStr, pFormat, ap); + va_end(ap); + + return result; +} + +//------------------------------------------------------------------------------ +/// Outputs a string on stdout. +/// \param pStr String to output. +//------------------------------------------------------------------------------ +signed int puts(const char *pStr) +{ + return fputs(pStr, stdout); +} + diff --git a/firmware/libcommon/source/string.c b/firmware/libcommon/source/string.c new file mode 100644 index 00000000..dbbb0e9e --- /dev/null +++ b/firmware/libcommon/source/string.c @@ -0,0 +1,239 @@ +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +//------------------------------------------------------------------------------ +/// \unit +/// +/// !Purpose +/// +/// Implementation of several methods defined in string.h, for reducing the +/// memory footprint when using them (since the whole libc.o file gets included +/// even when using a single method). +/// +/// !Usage +/// +/// Add string.c to the list of files to compile for the project. This will +/// automatically replace standard libc methods by the custom ones. +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include + +//------------------------------------------------------------------------------ +// Global Functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Copies data from a source buffer into a destination buffer. The two buffers +/// must NOT overlap. Returns the destination buffer. +/// \param pDestination Destination buffer. +/// \param pSource Source buffer. +/// \param num Number of bytes to copy. +//------------------------------------------------------------------------------ +void * memcpy(void *pDestination, const void *pSource, size_t num) +{ + unsigned char *pByteDestination; + unsigned char *pByteSource; + unsigned int *pAlignedSource = (unsigned int *) pSource; + unsigned int *pAlignedDestination = (unsigned int *) pDestination; + + // If num is more than 4 bytes, and both dest. and source are aligned, + // then copy dwords + if ((((unsigned int) pAlignedDestination & 0x3) == 0) + && (((unsigned int) pAlignedSource & 0x3) == 0) + && (num >= 4)) { + + while (num >= 4) { + + *pAlignedDestination++ = *pAlignedSource++; + num -= 4; + } + } + + // Copy remaining bytes + pByteDestination = (unsigned char *) pAlignedDestination; + pByteSource = (unsigned char *) pAlignedSource; + while (num--) { + + *pByteDestination++ = *pByteSource++; + } + + return pDestination; +} + +//------------------------------------------------------------------------------ +/// Fills a memory region with the given value. Returns a pointer to the +/// memory region. +/// \param pBuffer Pointer to the start of the memory region to fill +/// \param value Value to fill the region with +/// \param num Size to fill in bytes +//------------------------------------------------------------------------------ +void * memset(void *pBuffer, int value, size_t num) +{ + unsigned char *pByteDestination; + unsigned int *pAlignedDestination = (unsigned int *) pBuffer; + unsigned int alignedValue = (value << 24) | (value << 16) | (value << 8) | value; + + // Set words if possible + if ((((unsigned int) pAlignedDestination & 0x3) == 0) && (num >= 4)) { + while (num >= 4) { + *pAlignedDestination++ = alignedValue; + num -= 4; + } + } + // Set remaining bytes + pByteDestination = (unsigned char *) pAlignedDestination; + while (num--) { + *pByteDestination++ = value; + } + return pBuffer; +} + +//----------------------------------------------------------------------------- +/// Search a character in the given string. +/// Returns a pointer to the character location. +/// \param pString Pointer to the start of the string to search. +/// \param character The character to find. +//----------------------------------------------------------------------------- +char * strchr(const char *pString, int character) +{ + char * p = (char *)pString; + char c = character & 0xFF; + + while(*p != c) { + if (*p == 0) { + return 0; + } + p++; + } + return p; +} + +//----------------------------------------------------------------------------- +/// Return the length of a given string +/// \param pString Pointer to the start of the string. +//----------------------------------------------------------------------------- +size_t strlen(const char *pString) +{ + unsigned int length = 0; + + while(*pString++ != 0) { + length++; + } + return length; +} + + +//----------------------------------------------------------------------------- +/// Search a character backword from the end of given string. +/// Returns a pointer to the character location. +/// \param pString Pointer to the start of the string to search. +/// \param character The character to find. +//----------------------------------------------------------------------------- +char * strrchr(const char *pString, int character) +{ + char *p = 0; + + while(*pString != 0) { + if (*pString++ == character) { + p = (char*)pString; + } + } + return p; +} + +//----------------------------------------------------------------------------- +/// Copy from source string to destination string +/// Return a pointer to the destination string +/// \param pDestination Pointer to the destination string. +/// \param pSource Pointer to the source string. +//----------------------------------------------------------------------------- +char * strcpy(char *pDestination, const char *pSource) +{ + char *pSaveDest = pDestination; + + for(; (*pDestination = *pSource) != 0; ++pSource, ++pDestination); + return pSaveDest; +} + +//----------------------------------------------------------------------------- +/// Compare the first specified bytes of 2 given strings +/// Return 0 if equals +/// Return >0 if 1st string > 2nd string +/// Return <0 if 1st string < 2nd string +/// \param pString1 Pointer to the start of the 1st string. +/// \param pString2 Pointer to the start of the 2nd string. +/// \param count Number of bytes that should be compared. +//----------------------------------------------------------------------------- +int strncmp(const char *pString1, const char *pString2, size_t count) +{ + int r; + + while(count) { + r = *pString1 - *pString2; + if (r == 0) { + if (*pString1 == 0) { + break; + } + pString1++; + pString2++; + count--; + continue; + } + return r; + } + return 0; +} + +//----------------------------------------------------------------------------- +/// Copy the first number of bytes from source string to destination string +/// Return the pointer to the destination string. +/// \param pDestination Pointer to the start of destination string. +/// \param pSource Pointer to the start of the source string. +/// \param count Number of bytes that should be copied. +//----------------------------------------------------------------------------- +char * strncpy(char *pDestination, const char *pSource, size_t count) +{ + char *pSaveDest = pDestination; + + while (count) { + *pDestination = *pSource; + if (*pSource == 0) { + break; + } + pDestination++; + pSource++; + count--; + } + return pSaveDest; +} + diff --git a/firmware/libcommon/source/syscalls.c b/firmware/libcommon/source/syscalls.c deleted file mode 100644 index 71cc69a8..00000000 --- a/firmware/libcommon/source/syscalls.c +++ /dev/null @@ -1,138 +0,0 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * ---------------------------------------------------------------------------- - */ - -/** - * \file syscalls.c - * - * Implementation of newlib syscall. - * - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - - -#include "board.h" - -#include -#include -#include -#include - -/*---------------------------------------------------------------------------- - * Exported variables - *----------------------------------------------------------------------------*/ - -#undef errno -extern int errno ; -extern int _end ; - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ -extern void _exit( int status ) ; -extern void _kill( int pid, int sig ) ; -extern int _getpid ( void ) ; - -extern caddr_t _sbrk ( int incr ) -{ - static unsigned char *heap = NULL ; - unsigned char *prev_heap ; - - if ( heap == NULL ) - { - heap = (unsigned char *)&_end ; - } - prev_heap = heap; - - heap += incr ; - - return (caddr_t) prev_heap ; -} - -extern int link( char *old, char *new ) -{ - return -1 ; -} - -extern int _close( int file ) -{ - return -1 ; -} - -extern int _fstat( int file, struct stat *st ) -{ - st->st_mode = S_IFCHR ; - - return 0 ; -} - -extern int _isatty( int file ) -{ - return 1 ; -} - -extern int _lseek( int file, int ptr, int dir ) -{ - return 0 ; -} - -extern int _read(int file, char *ptr, int len) -{ - return 0 ; -} - -extern int _write( int file, char *ptr, int len ) -{ - int iIndex ; - - for ( iIndex=0 ; iIndex < len ; iIndex++, ptr++ ) - { - UART_PutChar( *ptr ) ; - } - return iIndex ; -} - -extern void _exit( int status ) -{ - printf( "Exiting with status %d.\n", status ) ; - - for ( ; ; ) ; -} - -extern void _kill( int pid, int sig ) -{ - return ; -} - -extern int _getpid ( void ) -{ - return -1 ; -}