diff options
| author | Shlomo Hecht <shlomo@twine-s.com> | 2018-03-06 12:09:02 +0200 |
|---|---|---|
| committer | Shlomo Hecht <shlomo@twine-s.com> | 2018-03-06 12:09:02 +0200 |
| commit | fb2d080fbbcea3a91e598b4ea8837a230de6a319 (patch) | |
| tree | 6b3ce09a252d2ebab8189a92b3326ffbba6dbe4b /Software/Embedded_SW/Embedded/Common/Utilities | |
| parent | d734bb5cf08ba2433b74fc86a8858d2437d1a237 (diff) | |
| download | Tango-fb2d080fbbcea3a91e598b4ea8837a230de6a319.tar.gz Tango-fb2d080fbbcea3a91e598b4ea8837a230de6a319.zip | |
A new forlder for embedded software in our common structure
Diffstat (limited to 'Software/Embedded_SW/Embedded/Common/Utilities')
4 files changed, 2201 insertions, 0 deletions
diff --git a/Software/Embedded_SW/Embedded/Common/Utilities/Update.c b/Software/Embedded_SW/Embedded/Common/Utilities/Update.c new file mode 100644 index 000000000..8eeee64cf --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Utilities/Update.c @@ -0,0 +1,98 @@ + +#include "include.h" +//#include <stdbool.h> + +//#include "Drivers/USB_Communication/USBCDCD.h" + + +extern Semaphore_Handle updateSem; + + +void UpdateUsb(void) +{ + // + // Terminate the USB device and detach from the bus. + // + USBDCDTerm(0); + + // + // Disable all interrupts. + // + ROM_IntMasterDisable(); + + // + // Disable SysTick and its interrupt. + // + ROM_SysTickIntDisable(); + ROM_SysTickDisable(); + + // + // Disable all processor interrupts. Instead of disabling them one at a + // time, a direct write to NVIC is done to disable all peripheral + // interrupts. + // + HWREG(NVIC_DIS0) = 0xffffffff; + HWREG(NVIC_DIS1) = 0xffffffff; + HWREG(NVIC_DIS2) = 0xffffffff; + HWREG(NVIC_DIS3) = 0xffffffff; + HWREG(NVIC_DIS4) = 0xffffffff; + + // + // Enable and reset the USB peripheral. + // + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0); + ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0); + ROM_USBClockEnable(USB0_BASE, 8, USB_CLOCK_INTERNAL); + + // + // Wait for about a second. + // + ROM_SysCtlDelay(SYS_CLK_FREQ / 3); + + // + // Re-enable interrupts at the NVIC level. + // + ROM_IntMasterEnable(); + + // + // Call the USB boot loader. + // + ROM_UpdateUSB(0); + + // + // Should never get here, but just in case. + // + while(1) + { + } +} + +Void updateTask(UArg arg0, UArg arg1) +{ + + // + // Wait until new updTE ARRIVED + // + Semaphore_pend(updateSem, BIOS_WAIT_FOREVER); + UpdateUsb(); +} +extern Semaphore_Handle ReconnectSem; + + +void ReconnectUsb(void) +{ + //USBCDC_close(); +} + +Void ReconnectTask(UArg arg0, UArg arg1) +{ + + // + // Wait until new updTE ARRIVED + // + while (1) + { + Semaphore_pend(ReconnectSem, BIOS_WAIT_FOREVER); + ReconnectUsb(); + } +} diff --git a/Software/Embedded_SW/Embedded/Common/Utilities/Utils.c b/Software/Embedded_SW/Embedded/Common/Utilities/Utils.c new file mode 100644 index 000000000..d792d9b5f --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Utilities/Utils.c @@ -0,0 +1,245 @@ +/************************************************************ + * Utils.h + * general module of system utility functions + **************************************************************/ + +#include <inc/hw_ints.h> +#include <inc/hw_memmap.h> +#include <driverlib/rom.h> +#include <time.h> +#include "Common/Utilities/Utils.h" +//#include <driverlib/systick.h> +#include "driverlib/hibernate.h" + +static const float speedCoef = 5.3051647697298445256294587790838f;//(200 micro steping)/2*Pi*Radius - 200 micro steping + +//***************************************************************************** + +bool DanserCheckPosition(uint16_t position , Danser_t danser, bool test) +{ + if (test == false) return true; +#ifdef DEBUG_DANCER + ProfileType_t profileType = GetCurrentProfileType(); + if (position < DANSER_POS_MIN) + { + if(danser == Winder) + { + if(profileType == Manual) + { + JigStopAllWithError("Thread torn in winder danser");//for stoping the system operation + } + else if (profileType == User) + { + //notify the UI about an error and pause the system + SendMessageToHost(ERROR_IN_PROFILE_EXECUTION,"Thread torn in winder danser"); + JigPauseAll(); + } + } + else + { + if(profileType == Manual) + { + JigStopAllWithError("Thread torn in pooler danser");//for stoping the system operation + } + else if (profileType == User) + { + //notify the UI about an error and pause the system + SendMessageToHost(ERROR_IN_PROFILE_EXECUTION,"Thread torn in pooler danser"); + JigPauseAll(); + } + } + return false; + } + + if (position > DANSER_POS_MAX) + { + if(danser == Pooler) + { + if(profileType == Manual) + { + JigStopAllWithError("Thread stocked in pooler danser"); + } + else if (profileType == User) + { + SendMessageToHost(ERROR_IN_PROFILE_EXECUTION,"Thread stuck in pooler danser"); + JigPauseAll(); + } + } + else + { + if(profileType == Manual) + { + JigStopAllWithError("Thread stocked in winder danser"); + } + else if (profileType ==User) + { + SendMessageToHost(ERROR_IN_PROFILE_EXECUTION,"Thread stuck in winder danser"); + JigPauseAll(); + } + } + return false; + } +#endif + return true; +} + +//***************************************************************************** +//convert thread speed recieved in milimeters per second into motor steps of pps +//***************************************************************************** +uint16_t ConvertSpeed2Pps(uint16_t milimeterPerSecond) +{ + float res = speedCoef*(float)milimeterPerSecond; + return (uint16_t)res; +} +//***************************************************************************** + +uint16_t ConvertPpsToSpeed(uint16_t Pps) +{ + float res = (float)Pps/speedCoef; + return (uint16_t)res; + +} + +//***************************************************************************** +// +// Init WD timer +// +//***************************************************************************** +void InitWatchdog(uint32_t clock) +{ + // + // Enable the watchdog interrupt. + // + ROM_IntEnable(INT_WATCHDOG); + + // + // Set the period of the watchdog timer. + // + ROM_WatchdogReloadSet(WATCHDOG0_BASE, clock); + + // + // Enable reset generation from the watchdog timer. + // + ROM_WatchdogResetEnable(WATCHDOG0_BASE); + + // + // Enable the watchdog timer. + // + ROM_WatchdogEnable(WATCHDOG0_BASE); +} +void utilsInit(uint32_t ui32SysClock) +{ + + cb_init(); +// SysTickPeriodSet(120000); +// SysTickEnable(); + // Configure Hibernate module clock. + // + HibernateEnableExpClk(ui32SysClock); + + + // Enable RTC mode. + // + HibernateRTCEnable(); + + // + // Configure the hibernate module counter to 24-hour calendar mode. + // + // HibernateCounterMode(HIBERNATE_COUNTER_24HR); + // Configure the hibernate module counter to RTC counter mode. + HibernateCounterMode(HIBERNATE_COUNTER_RTC); + + +} + + +uint32_t UsersysTickGet (void) { + uint32_t tick = 0; +// tick = SysTickValueGet(); + tick = HibernateRTCSSGet()*10000/0x8000; + return tick; +} + +//***************************************************************************** +// +// The interrupt handler for the watchdog. This feeds the dog (so that the +// processor does not get reset) and winks the LED connected to GPIO B3. +// +//***************************************************************************** +void WatchdogIntHandler(void) +{ + // + // Clear the watchdog interrupt. + // + ROM_WatchdogIntClear(WATCHDOG0_BASE); +} + +bool sendDataToHost = false; +void UtilsSetCommunicationOk(void) +{ + sendDataToHost = true; +} + +typedef struct circular_buffer +{ + void *buffer; // data buffer + void *buffer_end; // end of data buffer + uint16_t capacity; // maximum number of items in the buffer + uint16_t count; // number of items in the buffer + uint16_t sz; // size of each item in the buffer + void *head; // pointer to head + void *tail; // pointer to tail +} circular_buffer; + +uint8_t LogBuffer[8002]; +circular_buffer cb; +void cb_init() +{ + //cb.buffer = malloc(capacity * sz); + //if(cb.buffer == NULL) + // handle error + cb.buffer = LogBuffer; + cb.buffer_end = &LogBuffer[3950]; + cb.capacity = 4000; + cb.count = 0; + cb.sz = 60; + cb.head = cb.buffer; + cb.tail = cb.buffer; +} + +void cb_free(circular_buffer *cb) +{ + //free(cb.buffer); + // clear out other fields too, just to be safe +} + +void cb_push_back(/*circular_buffer *cb,*/ const void *item, int size) +{ + if(cb.count == cb.capacity){ + return; + // handle error + } + if ((int)(cb.head) + size > (int)(cb.buffer_end)){ + size = (int)(cb.buffer_end) - (int)(cb.head); + } + + memcpy(cb.head, item, size); + cb.head = (char*)cb.head + size; + if(cb.head >= cb.buffer_end) + cb.head = cb.buffer; + cb.count++; +// if (sendDataToHost) +// SendMessageToHost(DEBUG_LOG,item); +} + +void cb_pop_front(/*circular_buffer *cb,*/ void *item) +{ + if(cb.count == 0){ + // handle error + } + memcpy(item, cb.tail, cb.sz); + cb.tail = (char*)cb.tail + cb.sz; + if(cb.tail == cb.buffer_end) + cb.tail = cb.buffer; + cb.count--; +} diff --git a/Software/Embedded_SW/Embedded/Common/Utilities/Utils.h b/Software/Embedded_SW/Embedded/Common/Utilities/Utils.h new file mode 100644 index 000000000..363cf6eec --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Utilities/Utils.h @@ -0,0 +1,33 @@ +/************************************************************ + * Utils.h + * general module of system utility functions + **************************************************************/ + +#ifndef COMMON_UTILS_H_ +#define COMMON_UTILS_H_ + +#include <stdbool.h> +#include <stdint.h> + + +//digital read of the potentiometer limits +#define DANSER_POS_MIN 1300 +#define DANSER_POS_MAX 3500 + +typedef enum +{ + Winder = 0, + Pooler +}Danser_t; + + +void cb_init(); +void cb_push_back(/*void *cb,*/ const void *item, int size); +void utilsInit(uint32_t ui32SysClock); +uint32_t UsersysTickGet (void); +bool DanserCheckPosition(uint16_t position , Danser_t danser, bool test); +void InitWatchdog(uint32_t clock); +uint16_t ConvertSpeed2Pps(uint16_t milimeterPerSecond); +uint16_t ConvertPpsToSpeed(uint16_t Pps); +void UtilsSetCommunicationOk(void); +#endif /* COMMON_UTILS_H_ */ diff --git a/Software/Embedded_SW/Embedded/Common/Utilities/ustdlib.c b/Software/Embedded_SW/Embedded/Common/Utilities/ustdlib.c new file mode 100644 index 000000000..efee94611 --- /dev/null +++ b/Software/Embedded_SW/Embedded/Common/Utilities/ustdlib.c @@ -0,0 +1,1825 @@ +//***************************************************************************** +// +// ustdlib.c - Simple standard library functions. +// +// Copyright (c) 2007-2015 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 2.1.2.111 of the Tiva Utility Library. +// +//***************************************************************************** + +#include <stdint.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 s1 is a pointer to the destination buffer into which characters +//! are to be copied. +//! \param s2 is a pointer to the string from which characters are to be +//! copied. +//! \param n is the number of characters to copy to the destination buffer. +//! +//! This function copies at most \e n characters from the string pointed to +//! by \e s2 into the buffer pointed to by \e s1. If the end of \e s2 is found +//! before \e n characters have been copied, remaining characters in \e s1 +//! will be padded with zeroes until \e n 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 s2. +//! +//! \return Returns \e s1. +// +//***************************************************************************** +char * +ustrncpy(char * restrict s1, const char * restrict s2, size_t n) +{ + size_t count; + + // + // Check the arguments. + // + ASSERT(s1); + ASSERT(s2); + + // + // Start at the beginning of the source string. + // + count = 0; + + // + // Copy the source string until we run out of source characters or + // destination space. + // + while(n && s2[count]) + { + s1[count] = s2[count]; + count++; + n--; + } + + // + // Pad the destination if we are not yet done. + // + while(n) + { + s1[count++] = (char)0; + n--; + } + + // + // Pass the destination pointer back to the caller. + // + return(s1); +} + +//***************************************************************************** +// +//! A simple vsnprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and +//! \%X. +//! +//! \param s points to the buffer where the converted string is stored. +//! \param n is the size of the buffer. +//! \param format is the format string. +//! \param arg 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 format 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 n parameter limits the number of characters that will be +//! stored in the buffer pointed to by \e s 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 * restrict s, size_t n, const char * restrict format, + va_list arg) +{ + unsigned long ulIdx, ulValue, ulCount, ulBase, ulNeg; + char *pcStr, cFill; + int iConvertCount = 0; + + // + // Check the arguments. + // + ASSERT(s); + ASSERT(n); + ASSERT(format); + + // + // Adjust buffer size limit to allow one space for null termination. + // + if(n) + { + n--; + } + + // + // Initialize the count of characters converted. + // + iConvertCount = 0; + + // + // Loop while there are more characters in the format string. + // + while(*format) + { + // + // Find the first non-% character, or the end of the string. + // + for(ulIdx = 0; (format[ulIdx] != '%') && (format[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 > n) + { + ustrncpy(s, format, n); + s += n; + n = 0; + } + else + { + ustrncpy(s, format, ulIdx); + s += ulIdx; + n -= 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. + // + format += ulIdx; + + // + // See if the next character is a %. + // + if(*format == '%') + { + // + // Skip the %. + // + format++; + + // + // 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(*format++) + { + // + // 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((format[-1] == '0') && (ulCount == 0)) + { + cFill = '0'; + } + + // + // Update the digit count. + // + ulCount *= 10; + ulCount += format[-1] - '0'; + + // + // Get the next character. + // + goto again; + } + + // + // Handle the %c command. + // + case 'c': + { + // + // Get the value from the varargs. + // + ulValue = va_arg(arg, unsigned long); + + // + // Copy the character to the output buffer, if there is + // room. Update the buffer size remaining. + // + if(n != 0) + { + *s++ = (char)ulValue; + n--; + } + + // + // 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(arg, 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(arg, 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 > n) + { + ustrncpy(s, pcStr, n); + s += n; + n = 0; + } + else + { + ustrncpy(s, pcStr, ulIdx); + s += ulIdx; + n -= ulIdx; + + // + // Write any required padding spaces assuming there is + // still space in the buffer. + // + if(ulCount > ulIdx) + { + ulCount -= ulIdx; + if(ulCount > n) + { + ulCount = n; + } + n = -ulCount; + + while(ulCount--) + { + *s++ = ' '; + } + } + } + + // + // 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(arg, 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(arg, 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 && (n != 0) && (cFill == '0')) + { + // + // Place the minus sign in the output buffer. + // + *s++ = '-'; + n--; + + // + // 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(n != 0) + { + *s++ = cFill; + n--; + } + + // + // Update the conversion count. + // + iConvertCount++; + } + } + + // + // If the value is negative, then place the minus sign + // before the number. + // + if(ulNeg && (n != 0)) + { + // + // Place the minus sign in the output buffer. + // + *s++ = '-'; + n--; + + // + // 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(n != 0) + { + *s++ = g_pcHex[(ulValue / ulIdx) % ulBase]; + n--; + } + + // + // Update the conversion count. + // + iConvertCount++; + } + + // + // This command has been handled. + // + break; + } + + // + // Handle the %% command. + // + case '%': + { + // + // Simply write a single %. + // + if(n != 0) + { + *s++ = format[-1]; + n--; + } + + // + // Update the conversion count. + // + iConvertCount++; + + // + // This command has been handled. + // + break; + } + + // + // Handle all other commands. + // + default: + { + // + // Indicate an error. + // + if(n >= 5) + { + ustrncpy(s, "ERROR", 5); + s += 5; + n -= 5; + } + else + { + ustrncpy(s, "ERROR", n); + s += n; + n = 0; + } + + // + // Update the conversion count. + // + iConvertCount += 5; + + // + // This command has been handled. + // + break; + } + } + } + } + + // + // Null terminate the string in the buffer. + // + *s = 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 s is the buffer where the converted string is stored. +//! \param format 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 format 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 s 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 * restrict s, const char *format, ...) +{ + va_list arg; + int ret; + + // + // Start the varargs processing. + // + va_start(arg, format); + + // + // Call vsnprintf to perform the conversion. Use a large number for the + // buffer size. + // + ret = uvsnprintf(s, 0xffff, format, arg); + + // + // End the varargs processing. + // + va_end(arg); + + // + // Return the conversion count. + // + return(ret); +} + +//***************************************************************************** +// +//! A simple snprintf function supporting \%c, \%d, \%p, \%s, \%u, \%x, and +//! \%X. +//! +//! \param s is the buffer where the converted string is stored. +//! \param n is the size of the buffer. +//! \param format 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 format 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 n - 1 characters into the buffer +//! \e s. 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 * restrict s, size_t n, const char * restrict format, ...) +{ + va_list arg; + int ret; + + // + // Start the varargs processing. + // + va_start(arg, format); + + // + // Call vsnprintf to perform the conversion. + // + ret = uvsnprintf(s, n, format, arg); + + // + // End the varargs processing. + // + va_end(arg); + + // + // Return the conversion count. + // + return(ret); +} + +//***************************************************************************** +// +// 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 time_t g_psDaysToMonth[12] = +{ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +//***************************************************************************** +// +//! Converts from seconds to calendar date and time. +//! +//! \param timer is the number of seconds. +//! \param tm 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(time_t timer, struct tm *tm) +{ + time_t temp, months; + + // + // Extract the number of seconds, converting time to the number of minutes. + // + temp = timer / 60; + tm->tm_sec = timer - (temp * 60); + timer = temp; + + // + // Extract the number of minutes, converting time to the number of hours. + // + temp = timer / 60; + tm->tm_min = timer - (temp * 60); + timer = temp; + + // + // Extract the number of hours, converting time to the number of days. + // + temp = timer / 24; + tm->tm_hour = timer - (temp * 24); + timer = temp; + + // + // Compute the day of the week. + // + tm->tm_wday = (timer + 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. + // + timer += 366 + 365; + temp = timer / ((4 * 365) + 1); + if((timer - (temp * ((4 * 365) + 1))) > (31 + 28)) + { + temp++; + months = 12; + } + else + { + months = 2; + } + + // + // Extract the year. + // + tm->tm_year = ((timer - temp) / 365) + 68; + timer -= ((tm->tm_year - 68) * 365) + temp; + + // + // Extract the month. + // + for(temp = 0; temp < months; temp++) + { + if(g_psDaysToMonth[temp] > timer) + { + break; + } + } + tm->tm_mon = temp - 1; + + // + // Extract the day of the month. + // + tm->tm_mday = timer - g_psDaysToMonth[temp - 1] + 1; +} + +//***************************************************************************** +// +//! Compares two time structures and determines if one is greater than, +//! less than, or equal to the other. +//! +//! \param t1 is the first time structure to compare. +//! \param t2 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 t1 is greater than the time represented by \e t2 then a positive +//! number is returned. Likewise if \e t1 is less than \e t2 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 t1 is greater +//! than \e t2, and -1 if \e t1 is less than \e t2. +// +//***************************************************************************** +static int +ucmptime(struct tm *t1, struct tm *t2) +{ + // + // Compare each field in descending signficance to determine if + // greater than, less than, or equal. + // + if(t1->tm_year > t2->tm_year) + { + return(1); + } + else if(t1->tm_year < t2->tm_year) + { + return(-1); + } + else if(t1->tm_mon > t2->tm_mon) + { + return(1); + } + else if(t1->tm_mon < t2->tm_mon) + { + return(-1); + } + else if(t1->tm_mday > t2->tm_mday) + { + return(1); + } + else if(t1->tm_mday < t2->tm_mday) + { + return(-1); + } + else if(t1->tm_hour > t2->tm_hour) + { + return(1); + } + else if(t1->tm_hour < t2->tm_hour) + { + return(-1); + } + else if(t1->tm_min > t2->tm_min) + { + return(1); + } + else if(t1->tm_min < t2->tm_min) + { + return(-1); + } + else if(t1->tm_sec > t2->tm_sec) + { + return(1); + } + else if(t1->tm_sec < t2->tm_sec) + { + 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 timeptr 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 timeptr +//! 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 (uint32_t)(-1). +// +//***************************************************************************** +time_t +umktime(struct tm *timeptr) +{ + struct tm sTimeGuess; + unsigned long ulTimeGuess = 0x80000000; + unsigned long ulAdjust = 0x40000000; + int iSign; + + // + // Seed the binary search with the first guess. + // + ulocaltime(ulTimeGuess, &sTimeGuess); + iSign = ucmptime(timeptr, &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(timeptr, &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 nptr is a pointer to the string containing the integer. +//! \param endptr is a pointer that will be set to the first character past +//! the integer in the string. +//! \param base 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 * restrict nptr, const char ** restrict endptr, int base) +{ + unsigned long ulRet, ulDigit, ulNeg, ulValid; + const char *pcPtr; + + // + // Check the arguments. + // + ASSERT(nptr); + ASSERT((base == 0) || ((base > 1) && (base <= 16))); + + // + // Initially, the result is zero. + // + ulRet = 0; + ulNeg = 0; + ulValid = 0; + + // + // Skip past any leading white space. + // + pcPtr = nptr; + 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(((base == 0) || (base == 16)) && (*pcPtr == '0') && + ((pcPtr[1] == 'x') || (pcPtr[1] == 'X'))) + { + // + // Skip the leading "0x". + // + pcPtr += 2; + + // + // Set the radix to 16. + // + base = 16; + } + + // + // See if the radix was not specified. + // + if(base == 0) + { + // + // See if the value starts with "0". + // + if(*pcPtr == '0') + { + // + // Values that start with "0" are assumed to be radix 8. + // + base = 8; + } + else + { + // + // Otherwise, the values are assumed to be radix 10. + // + base = 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 >= base) + { + // + // 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 *= base; + 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(endptr) + { + *endptr = ulValid ? pcPtr : nptr; + } + + // + // Return the converted value. + // + return(ulNeg ? (0 - ulRet) : ulRet); +} + +//***************************************************************************** +// +// An array of the value of ten raised to the power-of-two exponents. This is +// used for converting the decimal exponent into the floating-point value of +// 10^exp. +// +//***************************************************************************** +static const float g_pfExponents[] = +{ + 1.0e+01, + 1.0e+02, + 1.0e+04, + 1.0e+08, + 1.0e+16, + 1.0e+32, +}; + +//***************************************************************************** +// +//! Converts a string into its floating-point equivalent. +//! +//! \param nptr is a pointer to the string containing the floating-point +//! value. +//! \param endptr is a pointer that will be set to the first character past +//! the floating-point value in the string. +//! +//! This function is very similar to the C library <tt>strtof()</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 a floating-point +//! value. +//! +//! \return Returns the result of the conversion. +// +//***************************************************************************** +float +ustrtof(const char *nptr, const char **endptr) +{ + unsigned long ulNeg, ulValid; + float fRet; + const char *pcPtr; + + // + // Check the arguments. + // + ASSERT(nptr); + + // + // Initially, the result is zero. + // + fRet = 0; + ulNeg = 0; + ulValid = 0; + + // + // Skip past any leading white space. + // + pcPtr = nptr; + while((*pcPtr == ' ') || (*pcPtr == '\t')) + { + pcPtr++; + } + + // + // Take a leading + or - from the value. + // + if(*pcPtr == '-') + { + ulNeg = 1; + pcPtr++; + } + else if(*pcPtr == '+') + { + pcPtr++; + } + + // + // Loop while there are valid digits to consume. + // + while((*pcPtr >= '0') && (*pcPtr <= '9')) + { + // + // Add this digit to the converted value. + // + fRet *= 10; + fRet += *pcPtr++ - '0'; + + // + // Since a digit has been added, this is now a valid result. + // + ulValid = 1; + } + + // + // See if the next character is a period and the character after that is a + // digit, indicating the start of the fractional portion of the value. + // + if((*pcPtr == '.') && (pcPtr[1] >= '0') && (pcPtr[1] <= '9')) + { + // + // Skip the period. + // + pcPtr++; + + // + // Loop while there are valid fractional digits to consume. + // + float fDigit = 0.1; + while((*pcPtr >= '0') && (*pcPtr <= '9')) + { + // + // Add this digit to the converted value. + // + fRet += (*pcPtr++ - '0') * fDigit; + fDigit /= (float)10.0; + + // + // Since a digit has been added, this is now a valid result. + // + ulValid = 1; + } + } + + // + // See if the next character is an "e" and a valid number has been + // converted, indicating the start of the exponent. + // + if(((pcPtr[0] == 'e') || (pcPtr[0] == 'E')) && (ulValid == 1) && + (((pcPtr[1] >= '0') && (pcPtr[1] <= '9')) || + (((pcPtr[1] == '+') || (pcPtr[1] == '-')) && + (pcPtr[2] >= '0') && (pcPtr[2] <= '9')))) + { + // + // Skip the "e". + // + pcPtr++; + + // + // Take a leading + or - from the exponenet. + // + unsigned long ulExpNeg = 0; + if(*pcPtr == '-') + { + ulExpNeg = 1; + pcPtr++; + } + else if(*pcPtr == '+') + { + pcPtr++; + } + + // + // Loop while there are valid digits in the exponent. + // + unsigned long ulExp = 0; + while((*pcPtr >= '0') && (*pcPtr <= '9')) + { + // + // Add this digit to the converted value. + // + ulExp *= 10; + ulExp += *pcPtr++ - '0'; + } + + // + // Raise ten to the power of the exponent. Do this via binary + // decomposition; for each binary bit set in the exponent, multiply the + // floating-point representation by ten raised to that binary value + // (extracted from the table above). + // + float fExp = 1; + unsigned long ulIdx = 0; + for(; ulIdx < 7; ulIdx++) + { + if(ulExp & (1 << ulIdx)) + { + fExp *= g_pfExponents[ulIdx]; + } + } + + // + // If the exponent is negative, then the exponent needs to be inverted. + // + if(ulExpNeg == 1) + { + fExp = 1 / fExp; + } + + // + // Multiply the result by the computed exponent value. + // + fRet *= fExp; + } + + // + // Set the return string pointer to the first character not consumed. + // + if(endptr) + { + *endptr = ulValid ? pcPtr : nptr; + } + + // + // Return the converted value. + // + return(ulNeg ? (0 - fRet) : fRet); +} + +//***************************************************************************** +// +//! Returns the length of a null-terminated string. +//! +//! \param s 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 s. +// +//***************************************************************************** +size_t +ustrlen(const char *s) +{ + size_t len; + + // + // Check the arguments. + // + ASSERT(s); + + // + // Initialize the length. + // + len = 0; + + // + // Step throug the string looking for a zero character (marking its end). + // + while(s[len]) + { + // + // Zero not found so move on to the next character. + // + len++; + } + + return(len); +} + +//***************************************************************************** +// +//! Finds a substring within a string. +//! +//! \param s1 is a pointer to the string that will be searched. +//! \param s2 is a pointer to the substring that is to be found within +//! \e s1. +//! +//! 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 s2 within +//! \e s1 or NULL if no match is found. +// +//***************************************************************************** +char * +ustrstr(const char *s1, const char *s2) +{ + size_t n; + + // + // Get the length of the string to be found. + // + n = ustrlen(s2); + + // + // Loop while we have not reached the end of the string. + // + while(*s1) + { + // + // Check to see if the substring appears at this position. + // + if(ustrncmp(s2, s1, n) == 0) + { + // + // It does so return the pointer. + // + return((char *)s1); + } + + // + // Move to the next position in the string being searched. + // + s1++; + } + + // + // 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 s1 points to the first string to be compared. +//! \param s2 points to the second string to be compared. +//! \param n is the maximum number of characters to compare. +//! +//! This function is very similar to the C library <tt>strncasecmp()</tt> +//! function. It compares at most \e n characters of two strings without +//! regard to case. The comparison ends if a terminating NULL character is +//! found in either string before \e n 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 s1 is less +//! than \e s2 and 1 if \e s1 is greater than \e s2. +// +//***************************************************************************** +int +ustrncasecmp(const char *s1, const char *s2, size_t n) +{ + // + // Loop while there are more characters to compare. + // + while(n) + { + // + // If we reached a NULL in both strings, they must be equal so + // we end the comparison and return 0 + // + if(!*s1 && !*s2) + { + return(0); + } + + // + // Lower case the characters at the current position before we compare. + // + char c1 = (((*s1 >= 'A') && (*s1 <= 'Z')) ? (*s1 + ('a' - 'A')) : *s1); + char c2 = (((*s2 >= 'A') && (*s2 <= 'Z')) ? (*s2 + ('a' - 'A')) : *s2); + + // + // Compare the two characters and, if different, return the relevant + // return code. + // + if(c2 < c1) + { + return(1); + } + if(c1 < c2) + { + return(-1); + } + + // + // Move on to the next character. + // + s1++; + s2++; + n--; + } + + // + // If we fall out, the strings must be equal for at least the first n + // characters so return 0 to indicate this. + // + return(0); +} + +//***************************************************************************** +// +//! Compares two strings without regard to case. +//! +//! \param s1 points to the first string to be compared. +//! \param s2 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 int16_ter string is deemed the lesser. +//! +//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less +//! than \e s2 and 1 if \e s1 is greater than \e s2. +// +//***************************************************************************** +int +ustrcasecmp(const char *s1, const char *s2) +{ + // + // Just let ustrncasecmp() handle this. + // + return(ustrncasecmp(s1, s2, (size_t)-1)); +} + +//***************************************************************************** +// +//! Compares two strings. +//! +//! \param s1 points to the first string to be compared. +//! \param s2 points to the second string to be compared. +//! \param n 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 n characters of two strings taking case into +//! account. The comparison ends if a terminating NULL character is found in +//! either string before \e n characters are compared. In this case, the +//! int16_ter string is deemed the lesser. +//! +//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less +//! than \e s2 and 1 if \e s1 is greater than \e s2. +// +//***************************************************************************** +int +ustrncmp(const char *s1, const char *s2, size_t n) +{ + // + // Loop while there are more characters. + // + while(n) + { + // + // If we reached a NULL in both strings, they must be equal so we end + // the comparison and return 0 + // + if(!*s1 && !*s2) + { + return(0); + } + + // + // Compare the two characters and, if different, return the relevant + // return code. + // + if(*s2 < *s1) + { + return(1); + } + if(*s1 < *s2) + { + return(-1); + } + + // + // Move on to the next character. + // + s1++; + s2++; + n--; + } + + // + // If we fall out, the strings must be equal for at least the first n + // characters so return 0 to indicate this. + // + return(0); +} + +//***************************************************************************** +// +//! Compares two strings. +//! +//! \param s1 points to the first string to be compared. +//! \param s2 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 int16_ter string is deemed the lesser. +//! +//! \return Returns 0 if the two strings are equal, -1 if \e s1 is less +//! than \e s2 and 1 if \e s1 is greater than \e s2. +// +//***************************************************************************** +int +ustrcmp(const char *s1, const char *s2) +{ + // + // Pass this on to ustrncmp. + // + return(ustrncmp(s1, s2, (size_t)-1)); +} + +//***************************************************************************** +// +// Random Number Generator Seed Value +// +//***************************************************************************** +static unsigned int g_iRandomSeed = 1; + +//***************************************************************************** +// +//! Set the random number generator seed. +//! +//! \param seed 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 int seed) +{ + g_iRandomSeed = seed; +} + +//***************************************************************************** +// +//! 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_iRandomSeed = (g_iRandomSeed * 1664525) + 1013904223; + + // + // Return the new random number. + // + return((int)g_iRandomSeed); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** |
