NutFs.h 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#ifndef NUTFS_H
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define NUTFS_H
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include "NutFile.h"
#ifdef __cplusplus
extern "C" { /* Assume C declarations for C++ */
#endif /* __cplusplus */
/******************************************************************************
* *
* G L O B A L D E F I N E S *
* *
******************************************************************************/
/*!
* \brief Obtain information about a specified file entry.
*/
#define FS_STATUS 0x1101
/*!
* \brief Create a new directory entry.
*/
#define FS_DIR_CREATE 0x1111
/*!
* \brief Remove a previously created directory entry.
*/
#define FS_DIR_REMOVE 0x1112
/*!
* \brief Open a directory stream.
*/
#define FS_DIR_OPEN 0x1113
/*!
* \brief Close a directory stream.
*/
#define FS_DIR_CLOSE 0x1114
/*!
* \brief Read the next directory entry.
*/
#define FS_DIR_READ 0x1115
/*!
* \brief Obtain information about an opened file.
*/
#define FS_FILE_STATUS 0x1121
/*!
* \brief Remove a previously created file.
*/
#define FS_FILE_DELETE 0x1122
/*!
* \brief Set a file pointer position.
*/
#define FS_FILE_SEEK 0x1123
#define FS_VOL_MOUNT 0x1130
#define FS_VOL_UNMOUNT 0x1131
#define FS_RENAME 0x1132
#define NUTFS_UNLINK 0x1133
#define NUTFS_MKDIR 0x1134
#define NUTFS_RMDIR 0x1135
/******************************************************************************
* *
* S T R U C T U R E D E F I N I T I O N S *
* *
******************************************************************************/
/*!
* \brief General structure for two arguments.
*
* Used to pass two arguments to an I/O control function.
*/
typedef struct {
void *arg1;
void *arg2;
} IOCTL_ARG2;
/*!
* \brief General structure for three arguments.
*
* Used to pass three arguments to an I/O control function.
*/
typedef struct {
void *arg1;
void *arg2;
void *arg3;
} IOCTL_ARG3;
typedef struct _FSCP_VOL_MOUNT {
/*! \brief Block device mount. */
NUTFILE *fscp_bmnt;
/*! \brief Partition type. */
u_char fscp_part_type;
} FSCP_VOL_MOUNT;
typedef struct _FSCP_RENAME {
CONST char *par_old;
CONST char *par_new;
} FSCP_RENAME;
//typedef struct _FSCP_STATUS {
// CONST char *par_path;
// struct stat *par_stp;
//} FSCP_STATUS;
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - N O I N I T I A L I Z E R S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - I N I T I A L I Z E R S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
#ifdef __cplusplus
} /* End of extern "C" { */
#endif /* __cplusplus */
#endif
NutHeap.c 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define NUTHEAP_C
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include <stdio.h>
#include <string.h>
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include "Common.h"
#include "XCore.h"
#include "NutHeap.h"
#if defined(NUTOS)
/******************************************************************************
* *
* L O C A L D E F I N E S *
* *
******************************************************************************/
#ifndef NUTMEM_ALIGNMENT
#define NUTMEM_ALIGNMENT sizeof(int)
#endif
/*!
* \brief Return the next lower aligned value.
*/
#define NUTMEM_BOTTOM_ALIGN(s) ((s) & ~(NUTMEM_ALIGNMENT - 1))
/*!
* \brief Return the next higher aligned value.
*/
#define NUTMEM_TOP_ALIGN(s) NUTMEM_BOTTOM_ALIGN((s + (NUTMEM_ALIGNMENT - 1)))
/*
* Set optional memory guard bytes.
*/
#ifdef NUTMEM_GUARD
#ifndef NUTMEM_GUARD_PATTERN
#define NUTMEM_GUARD_PATTERN ((int)(0xDEADBEEF))
#endif
#define NUTMEM_GUARD_BYTES sizeof(NUTMEM_GUARD_PATTERN)
#else /* NUTMEM_GUARD */
#define NUTMEM_GUARD_BYTES 0
#endif /* NUTMEM_GUARD */
/*! \brief Number of bytes used for management information. */
#define NUT_HEAP_OVERHEAD (sizeof(HEAPNODE) - sizeof(HEAPNODE *))
/*! \brief Minimum size of a node. */
#ifndef NUTMEM_HEAPNODE_MIN
#define NUTMEM_HEAPNODE_MIN (sizeof(HEAPNODE) + (2 * NUTMEM_GUARD_BYTES))
#endif
/******************************************************************************
* *
* L O C A L T Y P E D E F S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L I N I T I A L I Z E D D A T A D E F I N I T I O N S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L U N I T I A L I Z E D D A T A D E F I N I T I O N S *
* *
******************************************************************************/
/*
* Prepare the user region.
*
* Returns a pointer to the memory block's user region, after optionally
* having added guard patterns at both ends.
*/
static INLINE void *PrepareUserArea(HEAPNODE * node)
{
int *tp = (int *) (uptr_t) &node->hn_next;
#ifdef NUTMEM_GUARD
size_t off = (node->hn_size - NUT_HEAP_OVERHEAD) / sizeof(int) - 2;
*tp++ = NUTMEM_GUARD_PATTERN;
*(tp + off) = NUTMEM_GUARD_PATTERN;
#endif
return tp;
}
/*
* Validate the user region.
*
* If we have guarded user regions, then this routine will do a sanity
* check. If the guards had been overridden, then -1 is returned.
* However, if running in debug mode, then NUTPANIC is called instead.
*
* If the guards are still OK or if guard protection is not available,
* then zero is returned.
*/
static INLINE int ValidateUserArea(HEAPNODE * node)
{
#ifdef NUTMEM_GUARD
size_t off = (node->hn_size - NUT_HEAP_OVERHEAD) / sizeof(int) - 1;
int *tp = (int *) (uptr_t) &node->hn_next;
if (*tp != NUTMEM_GUARD_PATTERN || *(tp + off) != NUTMEM_GUARD_PATTERN) {
return -1;
}
#endif
return 0;
}
/*!
* \brief Allocate a block from heap memory.
*
* This functions allocates a memory block of the specified size and
* returns a pointer to that block.
*
* The actual size of the allocated block is larger than the requested
* size because of space required for maintenance information. This
* additional information is invisible to the application.
*
* The routine looks for the smallest block that will meet the required
* size and releases it to the caller. If the block being requested is
* usefully smaller than the smallest free block then the block from
* which the request is being met is split in two. The unused portion is
* put back into the free-list.
*
* The contents of the allocated block is unspecified. To allocate a
* block with all bytes set to zero use NutHeapAllocClear().
*
* \param root Points to the linked list of free nodes.
* \param size Size of the requested memory block.
*
* \return Pointer to the allocated memory block if the function is
* successful or NULL if no free block of the requested size
* is available.
*/
void *NutHeapRootAlloc(HEAPNODE ** root, size_t size)
{
HEAPNODE *node;
HEAPNODE **npp;
HEAPNODE *fit = NULL;
HEAPNODE **fpp = NULL;
size_t need;
/* Determine the minimum size. Add optional guard and alignment bytes.
** Make sure that a HEAPNODE structure fits. */
need = size + NUT_HEAP_OVERHEAD + 2 * NUTMEM_GUARD_BYTES;
if (need < sizeof(HEAPNODE)) {
need = sizeof(HEAPNODE);
}
need = NUTMEM_TOP_ALIGN(need);
/*
* Walk through the linked list of free nodes and find the best fit.
*/
node = *root;
npp = root;
while (node) {
/* Found a note that fits? */
if (node->hn_size >= need) {
/* Is it the first one we found or was the previous
** one larger? */
if (fit == NULL || fit->hn_size > node->hn_size) {
/* This is the best fit so far. */
fit = node;
fpp = npp;
/* Is this an exact match? */
if (node->hn_size == need) {
/* Exact match found. Stop searching. */
break;
}
}
}
npp = &node->hn_next;
node = node->hn_next;
}
if (fit) {
/* Is remaining space of the node we found large enough for
another node? Honor the specified threshold. */
if (fit->hn_size - need >= NUTMEM_HEAPNODE_MIN) {
/* Split the node. */
node = (HEAPNODE *) ((uptr_t) fit + need);
node->hn_size = fit->hn_size - need;
node->hn_next = fit->hn_next;
fit->hn_size = need;
*fpp = node;
} else {
/* Use the full node. */
*fpp = fit->hn_next;
}
fit = (HEAPNODE *) PrepareUserArea(fit);
}
return fit;
}
/*!
* \brief Allocate an initialized block from heap memory.
*
* This functions allocates a memory block of the specified
* size with all bytes initialized to zero and returns a
* pointer to that block.
*
* \param root Points to the linked list of free nodes.
* \param size Size of the requested memory block.
*
* \return Pointer to the allocated memory block if the
* function is successful or NULL if the requested
* amount of memory is not available.
*/
void *NutHeapRootAllocClear(HEAPNODE ** root, size_t size)
{
void *ptr;
if ((ptr = NutHeapRootAlloc(root, size)) != 0)
memset(ptr, 0, size);
return ptr;
}
/*!
* \brief Return a block to heap memory.
*
* An application calls this function, when a previously allocated
* memory block is no longer needed.
*
* The heap manager checks, if the released block adjoins any other
* free regions. If it does, then the adjacent free regions are joined
* together to form one larger region.
*
* \param root Points to the linked list of free nodes.
* \param block Points to a memory block previously allocated.
*
* \return 0 on success, -1 if the caller tried to free a block which
* had been previously released, -2 if the block had been
* corrupted. Furthermore, -3 is returned if block is a NULL
* pointer, but using this may change as C99 allows this.
*/
int NutHeapRootFree(HEAPNODE ** root, void *block)
{
HEAPNODE *node;
HEAPNODE **npp;
HEAPNODE *fnode;
/* IMHO, this should be removed. It adds additional code, which is
useless for most applications. Those, who are interested, can
easily do their own check. C99 declares this as a NUL op. */
if (block == NULL) {
return -3;
}
/* Revive our node pointer. */
fnode = (HEAPNODE *) ((uptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
if (ValidateUserArea(fnode)) {
return -2;
}
/*
* Walk through the linked list of free nodes and try
* to link us in.
*/
node = *root;
npp = root;
while (node) {
/* If this node is directly in front of ours, merge it. */
if ((uptr_t) node + node->hn_size == (uptr_t) fnode) {
node->hn_size += fnode->hn_size;
/*
* If another free node is directly following us, merge it.
*/
if (((uptr_t) node + node->hn_size) == (uptr_t) node->hn_next) {
node->hn_size += node->hn_next->hn_size;
node->hn_next = node->hn_next->hn_next;
}
break;
}
/*
* If we walked past our address, link us to the list.
*/
if ((uptr_t) node > (uptr_t) fnode) {
*npp = fnode;
/*
* If a free node is following us, merge it.
*/
if (((uptr_t) fnode + fnode->hn_size) == (uptr_t) node) {
fnode->hn_size += node->hn_size;
fnode->hn_next = node->hn_next;
} else
fnode->hn_next = node;
break;
}
/*
* If we are within a free node, somebody tried
* to free a block twice.
*/
if (((uptr_t) node + node->hn_size) > (uptr_t) fnode) {
return -1;
}
npp = &node->hn_next;
node = node->hn_next;
}
/*
* If no link was found, put us at the end of the list
*/
if (node == NULL) {
fnode->hn_next = node;
*npp = fnode;
}
return 0;
}
/*!
* \brief Add a new memory region to the heap.
*
* This function can be called more than once to manage non-continous
* memory regions. It is automatically called by Nut/OS during
* initialization.
*
* \param addr Start address of the memory region.
* \param size Number of bytes of the memory region.
*/
void NutHeapRootAdd(HEAPNODE ** root, void *addr, size_t size)
{
HEAPNODE *node = (HEAPNODE *) NUTMEM_TOP_ALIGN((uptr_t) addr);
node->hn_size = NUTMEM_BOTTOM_ALIGN(size - ((uptr_t) node - (uptr_t) addr));
NutHeapRootFree(root, PrepareUserArea(node));
}
/*!
* \brief Return the total number of bytes available.
*
* \return Number of bytes.
*/
size_t NutHeapRootAvailable(HEAPNODE ** root)
{
size_t rc = 0;
HEAPNODE *node;
/* Collect all free nodes. */
for (node = *root; node; node = node->hn_next) {
/* Reduce the size of each node by the required overhead. */
rc += node->hn_size - NUT_HEAP_OVERHEAD;
}
return rc;
}
/*!
* \brief Return the size of the largest block available.
*
* \return Number of bytes.
*/
size_t NutHeapRootRegionAvailable(HEAPNODE ** root)
{
size_t rc = 0;
HEAPNODE *node;
/* Collect all free nodes. */
for (node = *root; node; node = node->hn_next) {
if (rc < node->hn_size) {
rc = node->hn_size;
}
}
/* Reduce the size by the required overhead. */
return rc - NUT_HEAP_OVERHEAD;
}
/**
* \brief Change the size of an allocated memory block.
*
* If more memory is requested than available at that block the data
* is copied to a new, bigger block.
*
* \param block Points to a previously allocated memory block. If NULL,
* then this call is equivalent to NutHeapRootAlloc().
* \param size The requested new size. If 0, then this call is
* equivalent to NutHeapRootFree().
*
* \return A pointer to the memory block on success or NULL on failures.
*/
void *NutHeapRootRealloc(HEAPNODE ** root, void *block, size_t size)
{
HEAPNODE *node;
HEAPNODE **npp;
HEAPNODE *fnode;
void *newmem;
if (block == NULL) {
return NutHeapRootAlloc(root, size);
}
if (size == 0) {
if (NutHeapRootFree(root, block)) {
return NULL;
}
return block;
}
fnode = (HEAPNODE *) ((uptr_t) block - (NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES));
if (ValidateUserArea(fnode)) {
return NULL;
}
/* Determine the minimum size. Add optional guard and alignment bytes.
Make sure that a HEAPNODE structure fits. */
size += NUT_HEAP_OVERHEAD + NUTMEM_GUARD_BYTES * 2;
if (size < sizeof(HEAPNODE)) {
size = sizeof(HEAPNODE);
}
size = NUTMEM_TOP_ALIGN(size);
/*
* Expansion.
*/
if (size > fnode->hn_size) {
size_t size_miss = size - fnode->hn_size;
/* Find the free node following next. */
node = *root;
npp = root;
while (node && node < fnode) {
npp = &node->hn_next;
node = node->hn_next;
}
/* If we found a node and if this node is large enough and
if it directly follows without a gap, then use it. */
if (node && node->hn_size >= size_miss && /* */
(uptr_t) fnode + fnode->hn_size == (uptr_t) node) {
/* Check if the following node is large enough to be split. */
if (node->hn_size - size_miss >= NUTMEM_HEAPNODE_MIN) {
/* Adjust the allocated size. */
fnode->hn_size += size_miss;
/* Insert the remaining part into the free list. */
*npp = (HEAPNODE *) ((uptr_t) node + size_miss);
/* Due to possible overlapping it is important to set
the pointer first, then the size. */
(*npp)->hn_next = node->hn_next;
(*npp)->hn_size = node->hn_size - size_miss;
PrepareUserArea(fnode);
} else {
/* Adjust the allocated size. */
fnode->hn_size += node->hn_size;
PrepareUserArea(fnode);
/* Remove the merged node from the free list. */
*npp = node->hn_next;
}
/* Return the original pointer. */
return block;
}
/* Relocate if no sufficiently large block follows. */
newmem = NutHeapRootAlloc(root, size);
if (newmem) {
memcpy(newmem, block,
fnode->hn_size - NUT_HEAP_OVERHEAD - 2 * NUTMEM_GUARD_BYTES);
NutHeapRootFree(root, block);
}
return newmem;
}
/*
* Reduction.
*/
if (size < fnode->hn_size - NUTMEM_HEAPNODE_MIN) {
/* Release the remaining part to the free list. */
node = (HEAPNODE *) ((uptr_t) fnode + size);
node->hn_size = fnode->hn_size - size;
NutHeapRootFree(root, PrepareUserArea(node));
/* Adjust the allocated size. */
fnode->hn_size = size;
PrepareUserArea(fnode);
}
return block;
}
/*!
* \brief Dump heap memory to a given stream.
*/
void NutHeapDump(void * stream)
{
HEAPNODE *node;
for (node = heapFreeList; node; node = node->hn_next) {
fprintf(stream, "%p(%d)\n", node, (int) node->hn_size);
}
}
#endif
NutHeap.h 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#ifndef NUTHEAP_H
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define NUTHEAP_H
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include <stdio.h>
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#ifdef __cplusplus
extern "C" { /* Assume C declarations for C++ */
#endif /* __cplusplus */
/******************************************************************************
* *
* G L O B A L D E F I N E S *
* *
******************************************************************************/
#define NutHeapAdd(a, s) NutHeapRootAdd(&heapFreeList, a, s)
#define NutHeapAvailable() NutHeapRootAvailable(&heapFreeList)
#define NutHeapRegionAvailable() NutHeapRootRegionAvailable(&heapFreeList)
#define NutHeapAlloc(s) NutHeapRootAlloc(&heapFreeList, s)
#define NutHeapAllocClear(s) NutHeapRootAllocClear(&heapFreeList, s)
#define NutHeapFree(p) NutHeapRootFree(&heapFreeList, p)
#define NutHeapRealloc(p, s) NutHeapRootRealloc(&heapFreeList, p, s)
/* Thread stacks resides in normal heap. */
#define NutStackAlloc(s) NutHeapAlloc(s)
#define NutStackFree(p) NutHeapFree(p)
/******************************************************************************
* *
* S T R U C T U R E D E F I N I T I O N S *
* *
******************************************************************************/
/*!
* \struct _HEAPNODE heap.h sys/heap.h
* \brief Heap memory node information structure.
*/
typedef struct _HEAPNODE HEAPNODE;
/*!
* \typedef HEAPNODE
* \brief Heap memory node type.
*/
struct _HEAPNODE {
size_t hn_size; /*!< \brief Size of this node. */
HEAPNODE *hn_next; /*!< \brief Link to next free node. */
};
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - N O I N I T I A L I Z E R S *
* *
******************************************************************************/
#ifdef NUTHEAP_C
#define EXTERN
#else
#define EXTERN extern
#endif
/*!
* \brief List of free nodes in normal memory.
*/
EXTERN HEAPNODE *heapFreeList;
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - I N I T I A L I Z E R S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
#if defined(NUTOS)
void NutHeapRootAdd(HEAPNODE** root, void *addr, size_t size);
size_t NutHeapRootAvailable(HEAPNODE** root);
size_t NutHeapRootRegionAvailable(HEAPNODE** root);
void *NutHeapRootAlloc(HEAPNODE** root, size_t size);
void *NutHeapRootAllocClear(HEAPNODE** root, size_t size);
int NutHeapRootFree(HEAPNODE** root, void *block);
void *NutHeapRootRealloc(HEAPNODE** root, void * block, size_t size);
void NutHeapDump(void * stream);
#else
#define NutHeapRootAdd(root, addr, size)
#define NutHeapRootAvailable(root) (0)
#define NutHeapRootRegionAvailable(root) (0)
#define NutHeapRootAlloc(root, size) (0)
#define NutHeapRootAllocClear(root, size) (0)
#define NutHeapRootFree(root, block) (0)
#define NutHeapRootRealloc(root, block, size) (0)
#define NutHeapDump(stream)
#endif
#undef EXTERN
#ifdef __cplusplus
} /* End of extern "C" { */
#endif /* __cplusplus */
#endif
NutOS.h 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#ifndef NUTOS_H
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define NUTOS_H
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include "NutHeap.h"
#include "NutConfos.h"
#include "NutDevice.h"
#include "NutTimer.h"
#include "NutEvent.h"
#include "NutThread.h"
#include "NutFs.h"
#include "NutDebug.h"
#ifdef __cplusplus
extern "C" { /* Assume C declarations for C++ */
#endif /* __cplusplus */
/******************************************************************************
* *
* G L O B A L D E F I N E S *
* *
******************************************************************************/
/*!
* Number of bytes of the stack space allocated for the new thread.
*/
#define NUT_HEAP_SIZE (1024 * 1024/*512*/)
#define NUT_THREAD_IDLE_STACK (1024 * 1)
#define NUT_THREAD_MAIN_STACK (1024 * 64)
#define NUT_THREAD_TASK_STACK (1024 * 2)
#define NUT_THREAD_HOST_STACK (1024 * 4)
#define NUT_THREAD_ETHERNET_STACK (1024 * 2)
#define NUT_THREAD_NICRX_STACK (1024 * 2)
#define NUT_THREAD_DHCP_STACK (1024 * 1)
#define NUT_THREAD_TCPSM_STACK (1024 * 1)
#define NUT_THREAD_SNTP_STACK (1024 * 1)
#define NUT_THREAD_SNMP_STACK (1024 * 2)
#define NUT_THREAD_UTILITY_STACK (1024 * 2)
#define NUT_THREAD_MAIL_STACK (1024 * 4)
#define NUT_THREAD_FTP_STACK (1024 * 2)
#define NUT_THREAD_TELNET_STACK (1024 * 2)
#define NUT_THREAD_HTTP_STACK (1024 * 4)
#define NUT_THREAD_LPR_STACK (1024 * 2)
#define NUT_THREAD_RAW_STACK (1024 * 2)
#define NUT_THREAD_CARRIAGE_HOME_STACK (1024 * 1)
/*!
* The priority of newly created threads is set to 64,
* but may be changed when the thread starts running.
*
* 255 to kill the thread. Zero specifies the highest priority.
* The idle thread is running at level 254 (lowest priority).
* Application threads should use levels from 32 to 253.
*/
#define NUT_THREAD_KILL_PRIORITY 255
#define NUT_THREAD_IDLE_PRIORITY 254
#define NUT_THREAD_MAIN_PRIORITY 200
#define NUT_THREAD_TASK_PRIORITY 128
#define NUT_THREAD_HOST_PRIORITY 48
#define NUT_THREAD_ETHERNET_PRIORITY
#define NUT_THREAD_NICRX_PRIORITY 9
#define NUT_THREAD_DHCP_PRIORITY
#define NUT_THREAD_TCPSM_PRIORITY 32
#define NUT_THREAD_SNTP_PRIORITY 63
#define NUT_THREAD_SNMP_PRIORITY
#define NUT_THREAD_UTILITY_PRIORITY
#define NUT_THREAD_MAIL_PRIORITY 96
#define NUT_THREAD_SERVICE_PRIORITY
/******************************************************************************
* *
* S T R U C T U R E D E F I N I T I O N S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - N O I N I T I A L I Z E R S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - I N I T I A L I Z E R S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
#ifdef __cplusplus
} /* End of extern "C" { */
#endif /* __cplusplus */
#endif
NutThread.c 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define NUTTHREAD_C
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include <string.h>
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include "Common.h"
#include "XCore.h"
#include "NutHeap.h"
#include "NutTimer.h"
#include "NutEvent.h"
#include "NutThread.h"
#include "XComm.h"
#ifdef NUTDEBUG
#include "NutDebug.h"
#endif
#if defined(NUTOS)
/******************************************************************************
* *
* L O C A L D E F I N E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L T Y P E D E F S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L I N I T I A L I Z E D D A T A D E F I N I T I O N S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L U N I T I A L I Z E D D A T A D E F I N I T I O N S *
* *
******************************************************************************/
/*!
* \brief Thread to be killed.
*
* Pointer to the NUTTHREADINFO structure of the latest
* killed thread.
*/
NUTTHREADINFO * killedThread;
/*!
* \brief Add a thread to a prioritiy ordered queue.
*
* Insert the thread into a specified queue behind
* the last thread with lower or equal priority.
*
* \param td Pointer to NUTTHREADINFO of the thread to be
* inserted in the queue.
* \param tqpp Pointer to the root of the queue.
*/
void NutThreadAddPriQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp)
{
NUTTHREADINFO *tqp;
td->td_queue = (NUTHANDLE) tqpp;
td->td_qpec = 0; // start with clean event count
/*
* Be most careful not to override an intermediate event from interrupt
* context, which may change a queue from empty to signaled state. Many
* thanks to Michael Jones, who detected and corrected this bug.
*/
NutEnterCritical();
tqp = *tqpp;
if (tqp == SIGNALED) {
tqp = 0;
td->td_qpec++; // transfer the signaled state
} else if (tqp) {
NutExitCritical(); // there are other threads in queue
// so its save to leave critical.
while (tqp && tqp->td_priority <= td->td_priority) {
tqpp = &tqp->td_qnxt;
tqp = tqp->td_qnxt;
}
NutEnterCritical(); // back into critical
}
td->td_qnxt = tqp;
*tqpp = td;
if (td->td_qnxt && td->td_qnxt->td_qpec) {
// td->td_qpec += (u_int)td->td_qnxt->td_qpec; // don't overwrite count
u_int qpec = td->td_qnxt->td_qpec;
td->td_qpec += qpec; // don't overwrite count
td->td_qnxt->td_qpec = 0;
}
NutExitCritical();
}
/*!
* \brief Remove a thread from a specified queue.
*
* \note Depending on the given queue, CPU interrupts must have
* been disabled before calling this function.
*
* \param td Pointer to NUTTHREADINFO of the thread to be
* removed from the queue.
* \param tqpp Pointer to the root of the queue.
*/
void NutThreadRemoveQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp)
{
NUTTHREADINFO *tqp;
NutEnterCritical();
tqp = *tqpp;
NutExitCritical();
if (tqp != SIGNALED) {
while (tqp) {
if (tqp == td) {
NutEnterCritical();
*tqpp = td->td_qnxt;
if (td->td_qpec) {
if (td->td_qnxt) {
td->td_qnxt->td_qpec = td->td_qpec;
}
td->td_qpec = 0;
}
NutExitCritical();
td->td_qnxt = 0;
td->td_queue = 0;
break;
}
tqpp = &tqp->td_qnxt;
tqp = tqp->td_qnxt;
}
}
}
/*!
* \brief Continue with the highest priority thread, which is ready to run.
*
* If the currently running thread lost its top position in the queue
* of ready-to-run threads, then the context will be switched.
*
* \todo Removing a single thread from a wait queue only improves context
* switching, but may result in an event time-out for remaining
* threads, although events had been posted already.
*/
void NutThreadResume(void)
{
NUTTHREADINFO *td;
NUTTHREADINFO **qhp;
NUTTHREADINFO *tqp;
u_int cnt;
/*
* Process events that have been posted from interrupt context.
*/
td = nutThreadList;
while (td) {
NutEnterCritical();
cnt = td->td_qpec;
NutExitCritical();
if (cnt) {
/* In order to reduce context switching time, it is sufficient
* to remove the thread on top of the priority ordered list. */
qhp = (NUTTHREADINFO **)(td->td_queue);
NutEnterCritical();
td->td_qpec--;
tqp = *qhp;
NutExitCritical();
if (tqp != SIGNALED) {
NutEventPostAsync((NUTHANDLE *)qhp);
}
}
td = td->td_next;
}
/*
* Process elapsed timers. Must be done after processing the
* events from interupt routines.
*/
NutTimerProcessElapsed();
/* Check for context switch. */
if (runningThread != runQueue) {
if (runningThread->td_state == TDS_RUNNING) {
runningThread->td_state = TDS_READY;
}
NutEnterCritical();
NutThreadSwitch();
NutExitCritical();
}
}
/*!
* \brief Resume a previously suspended thread.
*
* This routine is called by the system when a
* sleep timer elapses.
*
* \note This routine is used as a timer callback
* for NutSleep implementation
* Applications typically do not call this
* function.
*
* \param timer Handle of the elapsed timer.
* \param th Handle of the thread to wake up.
*
* \todo Used by the timer module. Should be moved there, because not all
* applications will use of NutSleep().
*/
void NutThreadWake(NUTHANDLE timer, NUTHANDLE th)
{
/* clear pointer on timer and waiting queue */
((NUTTHREADINFO *) th)->td_timer = 0;
((NUTTHREADINFO *) th)->td_state = TDS_READY;
NutThreadAddPriQueue(th, (NUTTHREADINFO **) & runQueue);
}
/*!
* \brief Give up the CPU.
*
* If another thread within the same or higher priority
* is ready to run, then the current thread is stopped
* and the other one is started.
*
*/
void NutThreadYield(void)
{
/*
* Remove current thread from runQueue and reinsert it.
* The idle thread is the last one in the queue and will
* never be removed.
*/
if (runningThread->td_qnxt) {
NutThreadRemoveQueue(runningThread, (NUTTHREADINFO **) & runQueue);
NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
}
/* Continue with the highest priority thread, which is ready to run. */
NutThreadResume();
}
/*!
* \brief Set the current thread's priority.
*
* The priority of newly created threads is set to 64,
* but may be changed when the thread starts running.
*
* Changing the priority level to 255 will kill the
* calling thread.
*
* When another thread with a higher or equal priority
* is ready to run, the current thread will be stopped
* and control of the CPU is passed to the other thread.
*
* The function returns the old priority, which makes it
* easy to temporarily switch to another priority and
* later set back the old one.
*
* \param level New priority level or 255 to kill the thread. Zero
* specifies the highest priority. The idle thread is
* running at level 254 (lowest priority). Application
* threads should use levels from 32 to 253.
*
* \return The old priority of this thread.
*
* \todo Using a specific priority level for killing a thread is actually
* not the best idea. NutThreadKill() can be used instead.
*/
u_char NutThreadSetPriority(u_char level)
{
u_char last = runningThread->td_priority;
/*
* Remove the thread from the run queue and re-insert it with a new
* priority, if this new priority level is below 255. A priotity of
* 255 will kill the thread.
*/
NutThreadRemoveQueue(runningThread, &runQueue);
runningThread->td_priority = level;
if (level < 255) {
NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) & runQueue);
} else {
NutThreadKill();
}
/*
* Are we still on top of the queue? If yes, then change our status
* back to running, otherwise do a context switch.
*/
if (runningThread == runQueue) {
runningThread->td_state = TDS_RUNNING;
} else {
runningThread->td_state = TDS_READY;
NutEnterCritical();
NutThreadSwitch();
NutExitCritical();
}
return last;
}
/*!
* \brief End the current thread
*
* Terminates the current thread, in due course the memory associated
* with the thread will be released back to the OS this is done by the
* idle thread.
*
* \todo NutThreadKill() can be used instead of setting the priority level
* to 255.
*/
void NutThreadExit(void)
{
NutThreadSetPriority(255);
}
/*!
* \brief Free a thread that was previously killed and release memory
* back to the OS.
*
* Called when another thread is killed and by the idle thread.
*
* Applications generally do not call this function, however you could
* call it to try to reclaim memory.
*/
void NutThreadDestroy(void)
{
if (killedThread) {
NutStackFree(killedThread->td_memory);
killedThread = 0;
}
}
/*!
* \brief Kill the running thread.
*
* The thread is moved from the schedule que and
*
* Applications generally do not call this function.
*/
void NutThreadKill(void)
{
NUTTHREADINFO *pCur = nutThreadList;
NUTTHREADINFO **pp = (NUTTHREADINFO **) & nutThreadList;
/* Free up any unfinished already killed threads. */
NutThreadDestroy();
/* Remove from the thread list. */
while (pCur) {
if (pCur == runningThread) {
*pp = pCur->td_next;
break;
}
pp = (NUTTHREADINFO **) & pCur->td_next;
pCur = pCur->td_next;
}
/* Schedule for cleanup. */
killedThread = runningThread;
}
/*!
* \brief Query handle of a thread with a specific name.
*
* \param name Case sensitive symbolic name of the thread.
*
* \return Handle of the thread, if it exists. Otherwise NULL is returned.
*
* \todo Rarely used helper function. Should be placed in a seperate module.
*/
NUTHANDLE GetThreadByName(char * name)
{
NUTTHREADINFO *tdp;
if (name) {
for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
if (strcmp(tdp->td_name, name) == 0)
return tdp;
}
} else {
return runningThread;
}
return NULL;
}
#endif
NutThread.h 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#ifndef NUTTHREAD_H
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define NUTTHREAD_H
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include <stdio.h>
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#ifdef __cplusplus
extern "C" { /* Assume C declarations for C++ */
#endif /* __cplusplus */
/******************************************************************************
* *
* G L O B A L D E F I N E S *
* *
******************************************************************************/
#define DEADBEEF 0xDEADBEEF
/*!
* \name Thread States
*/
#define TDS_TERM 0 /*!< Thread has exited. */
#define TDS_RUNNING 1 /*!< Thread is running. */
#define TDS_READY 2 /*!< Thread is ready to run. */
#define TDS_SLEEP 3 /*!< Thread is sleeping. */
#define SLEEP_MODE_NONE 0xff
/******************************************************************************
* *
* S T R U C T U R E D E F I N I T I O N S *
* *
******************************************************************************/
/*!
* Thread information structure type.
*/
typedef struct _NUTTHREADINFO NUTTHREADINFO;
/*!
* \struct _NUTTHREADINFO thread.h sys/thread.h
* \brief Thread information structure.
*
* \todo Sort items while considering alignment.
*/
struct _NUTTHREADINFO {
NUTTHREADINFO *td_next; /*!< \brief Linked list of all threads. */
NUTTHREADINFO *td_qnxt; /*!< \brief Linked list of all queued thread. */
volatile u_int td_qpec; /*!< \brief Pending event counter. */
char td_name[9]; /*!< \brief Name of this thread. */
u_char td_state; /*!< \brief Operating state. One of TDS_ */
uptr_t td_sp; /*!< \brief Stack pointer. */
u_char td_priority; /*!< \brief Priority level. 0 is highest priority. */
u_char *td_memory; /*!< \brief Pointer to heap memory used for stack. */
NUTHANDLE td_timer; /*!< \brief Event timer. */
volatile NUTHANDLE td_queue; /*!< \brief Root entry of the waiting queue. */
};
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - N O I N I T I A L I Z E R S *
* *
******************************************************************************/
#ifdef NUTTHREAD_C
#define EXTERN
#else
#define EXTERN extern
#endif
/*!
* \brief Currently running thread.
*
* Pointer to the NUTTHREADINFO structure of the currently
* running thread.
*/
EXTERN NUTTHREADINFO * runningThread;
/*!
* \brief List of all created threads.
*
* Linked list of NUTTHREADINFO structures of all threads.
* New threads are put in front. This list contains at
* least two threads, the main application thread followed
* by the idle thread.
*/
EXTERN NUTTHREADINFO * nutThreadList;
/*!
* \brief List of ready-to-run threads.
*
* Priority ordered linked list of NUTTHREADINFO structures
* of all threads which are ready to run. The idle thread
* will always remain at the end of this list.
*/
EXTERN NUTTHREADINFO * runQueue;
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - I N I T I A L I Z E R S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
#if defined(NUTOS)
NUTHANDLE NutThreadCreate(char *name, void (*fn) (void *), void *arg, size_t stackSize);
u_char NutThreadSetPriority(u_char level);
void NutThreadKill(void);
void NutThreadDestroy(void);
void NutThreadExit(void);
void NutThreadResume(void);
void NutThreadWake(NUTHANDLE timer, NUTHANDLE th);
void NutThreadYield(void);
void NutThreadAddPriQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp);
void NutThreadRemoveQueue(NUTTHREADINFO * td, NUTTHREADINFO * volatile *tqpp);
void NutThreadSwitch(void);
NUTHANDLE GetThreadByName(char *name);
#else
#define NutThreadCreate(name, fn, arg, stackSize) (0)
#define NutThreadSetPriority(level) (64)
#define NutThreadKill()
#define NutThreadDestroy()
#define NutThreadExit()
#define NutThreadResume()
#define NutThreadWake(timer, th)
#define NutThreadYield()
#define NutThreadAddPriQueue(td, tqpp)
#define NutThreadRemoveQueue(td, tqpp)
#define NutThreadSwitch()
#define GetThreadByName(name) (0)
#endif
/*!
* \brief Macro for thread entry definitions.
*/
#define THREAD(threadfn, arg) \
void threadfn(void *arg) __attribute__ ((noreturn)); \
void threadfn(void *arg)
#undef EXTERN
#ifdef __cplusplus
} /* End of extern "C" { */
#endif /* __cplusplus */
#endif
NutTimer.c 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define NUTTIMER_C
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#include "Common.h"
#include "XCore.h"
#include "XTimer.h"
#include "NutHeap.h"
#include "NutThread.h"
#include "NutTimer.h"
#include "XComm.h"
#ifdef NUTDEBUG
#include "NutDebug.h"
#endif
#if defined(NUTOS)
/******************************************************************************
* *
* L O C A L D E F I N E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L T Y P E D E F S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L I N I T I A L I Z E D D A T A D E F I N I T I O N S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* L O C A L U N I T I A L I Z E D D A T A D E F I N I T I O N S *
* *
******************************************************************************/
/*
* Last processing time of elapsed timers.
*/
static u_long nut_ticks_resume;
/*!
* \brief System tick counter
*/
volatile u_long nut_ticks;
/*!
* \brief Loops per microsecond.
*/
#if defined(NUT_DELAYLOOPS)
volatile u_long nut_delay_loops = NUT_DELAYLOOPS;
#else
volatile u_long nut_delay_loops;
#endif
/*!
* \brief Return the number of system ticks per second.
*
* \return System tick frequency in Hertz.
*/
static u_long NutGetTickClock(void)
{
return (1000UL / PERIOD_TIMES);
}
/*!
* \brief Calculate system ticks for a given number of milliseconds.
*/
static u_long NutTimerMillisToTicks(u_long ms)
{
return (ms * NutGetTickClock()) / 1000;
}
/*!
* \brief System timer interrupt handler.
*/
static void NutTimerIntr(void *arg)
{
nut_ticks++;
}
/*!
* \brief Initialize system timer.
*
* This function is automatically called by Nut/OS during system
* initialization. It calls the hardware dependent layer to initialze
* the timer hardware and register a timer interrupt handler.
*/
void NutTimerInit(void)
{
// NutRegisterTimer(NutTimerIntr);
// NutEnableTimerIrq();
StartPeriodFunc((PERIODFUNC)NutTimerIntr);
#if !defined(NUT_DELAYLOOPS)
{
/* Wait for the next tick. */
u_long cnt = NutGetTickCount();
while (cnt == NutGetTickCount());
/* Wait for the next tick, counting loops. */
cnt = NutGetTickCount();
while (cnt == NutGetTickCount()) {
nut_delay_loops++;
}
/*
* The loop above needs more cycles than the actual delay loop.
* Apply the correction found by trial and error. Works acceptable
* with GCC for Ethernut 1 and 3.
*/
nut_delay_loops *= 103UL;
nut_delay_loops /= 26UL;
}
#endif
}
/*!
* \brief Loop for a specified number of microseconds.
*
* This call will not release the CPU and will not switch to another
* thread. However, interrupts are not disabled and introduce some
* jitter. Furthermore, unless NUT_DELAYLOOPS is not defined, the
* deviation may be greater than 10%.
*
* If you need exact timing, use timer/counter hardware instead.
*
* \param us Delay time in microseconds. Values above 255 milliseconds
* may not work.
*
* \todo Overflow handling.
*/
void NutMicroDelay(u_long us)
{
register u_long cnt = nut_delay_loops * us / 1000 / PERIOD_TIMES;
while (cnt--) {
_NOP();
}
}
/*!
* \brief Loop for a specified number of milliseconds.
*
* This call will not release the CPU and will not switch to another
* thread. Because of absent thread switching, the delay time is more
* exact than with NutSleep().
*
* \param ms Delay time in milliseconds, maximum is 255.
*
* \deprecated New applications should use NutMicroDelay().
*/
void NutDelay(u_char ms)
{
NutMicroDelay((u_long)ms * 1000);
}
/*!
* \brief Insert a new timer in the global timer list.
*
* Applications should not call this function.
*
* \param tn Pointer to the timer structure to insert.
*
* \todo Make this local function static.
*/
void NutTimerInsert(NUTTIMERINFO * tn)
{
NUTTIMERINFO *tnp;
tn->tn_prev = NULL;
for (tnp = nutTimerList; tnp; tnp = tnp->tn_next) {
if (tn->tn_ticks_left < tnp->tn_ticks_left) {
tnp->tn_ticks_left -= tn->tn_ticks_left;
break;
}
tn->tn_ticks_left -= tnp->tn_ticks_left;
tn->tn_prev = tnp;
}
tn->tn_next = tnp;
if (tn->tn_next) {
tn->tn_next->tn_prev = tn;
}
if (tn->tn_prev) {
tn->tn_prev->tn_next = tn;
}
else {
nutTimerList = tn;
}
}
/*!
* \brief Process elapsed timers.
*
* This routine is called during context switch processing.
* Applications should not use this function.
*/
void NutTimerProcessElapsed(void)
{
NUTTIMERINFO *tn;
u_long ticks;
u_long ticks_new;
// calculate ticks since last call
ticks = NutGetTickCount();
ticks_new = ticks - nut_ticks_resume;
nut_ticks_resume = ticks;
// process timers
while (nutTimerList && ticks_new){
tn = nutTimerList;
// subtract time
if (ticks_new < tn->tn_ticks_left) {
tn->tn_ticks_left -= ticks_new;
ticks_new = 0;
} else {
ticks_new -= tn->tn_ticks_left;
tn->tn_ticks_left = 0;
}
// elapsed
if (tn->tn_ticks_left == 0){
// callback
if (tn->tn_callback) {
(*tn->tn_callback) (tn, (void *) tn->tn_arg);
}
// remove from list
nutTimerList = nutTimerList->tn_next;
if (nutTimerList) {
nutTimerList->tn_prev = NULL;
}
if ((tn->tn_ticks_left = tn->tn_ticks) == 0) {
NutHeapFree(tn);
}
else {
NutTimerInsert(tn);
}
}
}
}
/*!
* \brief Create a new system timer.
*
* Applications should not call this function.
*
* \param ticks Specifies the timer interval in system ticks.
* \param callback Identifies the function to be called on each
* timer interval.
* \param arg The argument passed to the callback function.
* \param flags If set to TM_ONESHOT, the timer will be stopped
* after the first interval. Set to 0 for periodic
* timers.
*
* \return Timer handle if successfull, 0 otherwise. The handle
* may be used to release the timer by calling TimerStop.
*
* \todo Make this local function static or directly integrate it into
* NutTimerStartTicks().
*/
NUTTIMERINFO * NutTimerCreate(u_long ticks, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags)
{
NUTTIMERINFO *tn;
tn = NutHeapAlloc(sizeof(NUTTIMERINFO));
if (tn) {
tn->tn_ticks_left = ticks + NutGetTickCount() - nut_ticks_resume;
/*
* Periodic timers will reload the tick counter on each timer
* intervall.
*/
if (flags & TM_ONESHOT) {
tn->tn_ticks = 0;
} else {
tn->tn_ticks = ticks;
}
/* Set callback and callback argument. */
tn->tn_callback = callback;
tn->tn_arg = arg;
}
return tn;
}
/*!
* \brief Start a system timer.
*
* The function returns immediately, while the timer runs asynchronously in
* the background.
*
* The timer counts for a specified number of ticks, then calls the callback
* routine with a given argument.
*
* Even after the timer elapsed, the callback function is not executed
* before the currently running thread is ready to give up the CPU. Thus,
* system timers may not fulfill the required accuracy. For precise or
* high resolution timing, native timer interrupt routines are a better
* choice.
*
* \param ticks Specifies the timer interval in system ticks.
* \param callback Identifies the function to be called on each
* timer interval.
* \param arg The argument passed to the callback function.
* \param flags If set to TM_ONESHOT, the timer will be stopped
* after the first interval. Set to 0 for periodic
* timers.
*
* \return Timer handle if successfull, 0 otherwise. The handle
* may be used to stop the timer by calling TimerStop.
*/
NUTHANDLE NutTimerStartTicks(u_long ticks, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags)
{
NUTTIMERINFO *tn;
tn = NutTimerCreate( ticks, callback, arg, flags);
if (tn) {
/* Add the timer to the list. */
NutTimerInsert(tn);
}
return tn;
}
/*!
* \brief Start a system timer.
*
* The function returns immediately, while the timer runs
* asynchronously in the background.
*
* The timer counts for a specified number of milliseconds,
* then calls the callback routine with a given argument.
*
* Even after the timer elapsed, the callback function is not executed
* before the currently running thread is ready to give up the CPU. Thus,
* system timers may not fulfill the required accuracy. For precise or
* high resolution timing, native timer interrupt routines are a better
* choice.
*
* \param ms Specifies the timer interval in milliseconds. The
* resolution is limited to the granularity of the system
* timer.
* \param callback Identifies the function to be called on each
* timer interval.
* \param arg The argument passed to the callback function.
* \param flags If set to TM_ONESHOT, the timer will be stopped
* after the first interval. Set to 0 for periodic
* timers.
*
* \return Timer handle if successfull, 0 otherwise. The handle
* may be used to stop the timer by calling TimerStop.
*/
NUTHANDLE NutTimerStart(u_long ms, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags)
{
return NutTimerStartTicks(NutTimerMillisToTicks(ms), callback, arg, flags);
}
/*!
* \brief Temporarily suspends the current thread.
*
* Causes the current thread to wait for a specified interval or,
* if the specified interval is zero, to give up the CPU for
* another thread with higher or same priority.
*
* This function may switch to another application thread, that
* got the same or a higher priority and is ready to run.
*
* \note Threads may sleep longer than the specified number of
* milliseconds, depending on the number of threads
* with higher or equal priority, which are ready to run.
*
* \param ms Milliseconds to sleep. If 0, the current thread will not
* sleep, but may give up the CPU. The resolution is limited
* to the granularity of the system timer.
*
* \todo Code size can be reduced by trying to create the timer before
* removing the thread from the run queue.
*/
void NutSleep(u_long ms)
{
if (ms) {
/* remove running thread from runQueue */
NutThreadRemoveQueue(runningThread, &runQueue);
runningThread->td_state = TDS_SLEEP;
if ((runningThread->td_timer = NutTimerStart(ms, NutThreadWake, runningThread, TM_ONESHOT)) != 0) {
NutThreadResume();
} else
{
/* timer creation failed, restore queues */
runningThread->td_queue = &runQueue;
runningThread->td_qnxt = runQueue;
runningThread->td_state = TDS_RUNNING;
runQueue = runningThread;
}
} else
NutThreadYield();
}
/*!
* \brief Stop a specified timer.
*
* Only periodic timers need to be stopped. One-shot timers
* are automatically stopped by the timer management after
* ther first timer interval. Anyway, long running one-shot
* timers may be stopped to release the occupied memory.
*
* \param handle Identifies the timer to be stopped. This handle must
* have been created by calling NutTimerStart() or
* NutTimerStartTicks().
*/
void NutTimerStop(NUTHANDLE handle)
{
NUTTIMERINFO *tn = (NUTTIMERINFO *)handle;
/* Disable periodic operation and callback. */
tn->tn_ticks = 0;
tn->tn_callback = NULL;
/* If not already elapsed, expire the timer. */
if (tn->tn_ticks_left) {
if (tn->tn_prev) {
tn->tn_prev->tn_next = tn->tn_next;
}
else {
nutTimerList = tn->tn_next;
}
if (tn->tn_next) {
tn->tn_next->tn_prev = tn->tn_prev;
tn->tn_next->tn_ticks_left += tn->tn_ticks_left;
}
tn->tn_ticks_left = 0;
NutTimerInsert(tn);
}
}
/*!
* \brief Return the number of system timer ticks.
*
* This function returns the number of system ticks since the system was
* started.
*
* \return Number of ticks.
*/
u_long NutGetTickCount(void)
{
u_long rc;
NutEnterCritical();
rc = nut_ticks;
NutExitCritical();
return rc;
}
/*!
* \brief Return the seconds counter value.
*
* This function returns the value of a counter, which is incremented
* every second. During system start, the counter is cleared to zero.
*
* \note There is intentionally no provision to modify the seconds counter.
* Callers can rely on a continuous update and use this value for
* system tick independend timeout calculations. Applications,
* which want to use this counter for date and time functions,
* should use an offset value.
*
* \return Value of the seconds counter.
*/
u_long NutGetSeconds(void)
{
return NutGetTickCount() / NutGetTickClock();
}
/*!
* \brief Return the milliseconds counter value.
*
* This function returns the value of a counter, which is incremented
* every system timer tick. During system start, the counter is cleared
* to zero and will overflow with the 32 bit tick counter (4294967296).
* With the default 1024 ticks/s this will happen after 49.71 days.
* The resolution is also given by the system ticks.
*
* \note There is intentionally no provision to modify the seconds counter.
* Callers can rely on a continuous update and use this value for
* system tick independend timeout calculations.
* Depending on
*
* \return Value of the seconds counter.
*/
u_long NutGetMillis(void)
{
// carefully stay within 32 bit values
u_long ticks = NutGetTickCount();
u_long seconds = ticks / NutGetTickClock();
ticks -= seconds * NutGetTickClock();
return seconds * 1000 + (ticks * 1000 ) / NutGetTickClock();
}
#endif
NutTimer.h 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
#ifndef NUTTIMER_H
/******************************************************************************
* *
* M O D U L E D E F I N E *
* *
******************************************************************************/
#define NUTTIMER_H
/******************************************************************************
* *
* C O M P I L E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
/******************************************************************************
* *
* U S E R D E F I N E D I N C L U D E F I L E S *
* *
******************************************************************************/
#ifdef __cplusplus
extern "C" { /* Assume C declarations for C++ */
#endif /* __cplusplus */
/******************************************************************************
* *
* G L O B A L D E F I N E S *
* *
******************************************************************************/
#define TM_ONESHOT 0x01
/******************************************************************************
* *
* S T R U C T U R E D E F I N I T I O N S *
* *
******************************************************************************/
/*!
* \brief Timer type.
*/
typedef struct _NUTTIMERINFO NUTTIMERINFO;
/*!
* \struct _NUTTIMERINFO timer.h sys/timer.h
* \brief Timer information structure.
*/
struct _NUTTIMERINFO {
/*! \brief Link to next timer.
*/
NUTTIMERINFO *tn_next;
/*! \brief Link to previous timer.
*/
NUTTIMERINFO *tn_prev;
/*! \brief Number of system ticks.
* Set to zero on one-shot timers.
*/
u_long tn_ticks;
/*! \brief Decremented by one on each system tick intervall.
*/
u_long tn_ticks_left;
/*! \brief Callback function.
*/
void (*tn_callback)(NUTHANDLE, void *);
/*! \brief Argument pointer passed to callback function.
*/
volatile void *tn_arg;
};
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - N O I N I T I A L I Z E R S *
* *
******************************************************************************/
#ifdef NUTTIMER_C
#define EXTERN
#else
#define EXTERN extern
#endif
/*!
* \brief Double linked list of all system timers.
*/
EXTERN NUTTIMERINFO * nutTimerList;
/******************************************************************************
* *
* G L O B A L V A R I A B L E S - I N I T I A L I Z E R S *
* *
******************************************************************************/
/* None */
/******************************************************************************
* *
* F U N C T I O N P R O T O T Y P E S *
* *
******************************************************************************/
#if defined(NUTOS)
/*
* Functions used by the kernel.
*/
void NutTimerInit(void);
NUTTIMERINFO * NutTimerCreate(u_long ticks, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags);
void NutTimerInsert(NUTTIMERINFO * tn);
void NutTimerProcessElapsed(void);
/*
* API declarations.
*/
void NutSleep(u_long ms);
void NutDelay(u_char ms);
void NutMicroDelay(u_long us);
u_long NutGetTickCount(void);
u_long NutGetSeconds(void);
u_long NutGetMillis(void);
NUTHANDLE NutTimerStart(u_long ms, void (*callback)(NUTHANDLE, void *), void *arg, u_char flags);
NUTHANDLE NutTimerStartTicks(u_long ticks, void (*callback) (NUTHANDLE, void *), void *arg, u_char flags);
void NutTimerStop(NUTHANDLE handle);
#else
#define NutTimerInit()
#define NutTimerCreate(ticks, callback, arg, flags) (0)
#define NutTimerInsert(tn)
#define NutTimerProcessElapsed()
#define NutDelay(ms)
#define NutSleep(ms)
#define NutGetTickCount() (0)
#define NutGetSeconds() (0)
#define NutGetMillis() (0)
#define NutTimerStart(ms, callback, arg, flags) (0)
#define NutTimerStartTicks(ticks, callback, arg, flags) (0)
#define NutTimerStop(handle)
#endif
#undef EXTERN
#ifdef __cplusplus
} /* End of extern "C" { */
#endif /* __cplusplus */
#endif