manually merged with ARM version

This commit is contained in:
2025-11-13 17:43:55 +03:00
parent 77005d7863
commit b7ba42765b
463 changed files with 119514 additions and 45 deletions

View File

@ -0,0 +1,17 @@
#ifndef CRCLIB_CFG_H_
#define CRCLIB_CFG_H_
#define FAR_KEYWORD
/*===============================================================================================*/
/* Включение/выключение функций для вычисления различных контрольных сумм */
#define CRC7_EN (0)
#define CRC16_EN 1 /* 16-разрядная CRC */
#define CRC16TBL_EN 0 /* 16-разрядная CRC, вычисляемая табличным методом */
#define CRC8_EN 0 /* 8-разрядная CRC */
#define CRCMODBUS_EN 0 /* CRC шины MODBUS */
#define CRC8REVERSE_EN 0 /* 8-раязядная CRC (посчитана в обратном направлении) */
/*===============================================================================================*/
#endif /*#ifndef CRCLIB_CFG_H_*/

View File

@ -0,0 +1,31 @@
/*================================================================================================*
* Конфигурация библиотеки FAST_CRC
*================================================================================================*/
#ifndef FAST_CRC_CFG_H_
#define FAST_CRC_CFG_H_
#include <stdint.h>
/*================================================================================================*/
/* Типы */
#define FASTCRC_U8_TYPE uint8_t
#define FASTCRC_U16_TYPE uint16_t
#define FASTCRC_U32_TYPE uint32_t
#define FASTCRC_SIZE_TYPE size_t
/* Начальные значения CRC */
#define CRC16_START_VAL 0
#define CRC32_START_VAL 0
/*================================================================================================*/
/*================================================================================================*/
/* Разрешение компиляции отдельных функций */
#define FASTCRC_CRC16_ADD8 1 /* добавление в CRC16 байта */
#define FASTCRC_CRC16_ADD16 1 /* добавление в CRC16 16-битного слова */
#define FASTCRC_CRC16_BLOCK8 1 /* Вычисление CRC16 блока байтов */
#define FASTCRC_CRC16_BLOCK16 1 /* Вычисление CRC16 блока 16-битных слов */
#define FASTCRC_CRC32_BLOCK8 1 /* Вычисление CRC32 блока байтов */
/*================================================================================================*/
#endif /* FAST_CRC_CFG_H_ */

232
x502api-1.1.34/lib/crc/crc.c Executable file
View File

@ -0,0 +1,232 @@
/*
* Вычисление контрольных сумм.
*/
#include "crc.h"
#include "crclib_cfg.h"
/*===============================================================================================*/
#if CRC16TBL_EN > 0
static const unsigned short crc_table[256] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5,
0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c,
0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b,
0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5,
0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969,
0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03,
0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6,
0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1,
0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c,
0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447,
0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2,
0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c,
0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0,
0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba,
0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
#endif
/*===============================================================================================*/
/*===============================================================================================*/
/*-----------------------------------------------------------------------------------------------*/
#if CRC16_EN > 0
unsigned short eval_crc16(unsigned short crc, const unsigned char *msg, unsigned msg_len)
{
/* Вычисление 16-разрядного циклического избыточного кода (ЦИК - CRC)
* crc - исходное значение ЦИК, 0 при первом вызове
* msg - указатель блока сообщения
* msg_len - число байтов в блоке
* Возвращает 16-разрядный ЦИК
*/
const unsigned short crc_poly = 0x1021; /* порождающий многочлен */
unsigned char j;
while (msg_len-- > 0)
{
crc ^= (unsigned short)*msg++ << 8;
for (j = 8; j > 0; j--) /* проверка каждого бита */
{
if (crc & 0x8000)
{
crc = crc << 1 ^ crc_poly;
}
else
{
crc <<= 1;
}
}
}
return crc & 0xffff;
}
#endif
/*-----------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------*/
#if CRC16TBL_EN > 0
unsigned short eval_crc16tbl(unsigned short crc, const unsigned char *msg, unsigned msg_len)
{
/* Вычисление 16-разрядного циклического избыточного кода (ЦИК - CRC) табличным методом.
* ОПИСАНИЕ
* Вычисляется 16-битный циклический избыточный код при помощи таблицы.
* ПАРАМЕТРЫ
* crc - начальное значение ЦИК, 0 при первом вызове;
* msg - указатель блока сообщения;
* msg_len - число байтов в блоке.
* ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
* 16-разрядный ЦИК.
*/
unsigned temp;
while (msg_len-- > 0)
{
temp = (*msg++ ^ (crc >> 8)) & 0xFF;
crc = crc_table[temp] ^ (crc << 8);
}
return crc & 0xFFFFU;
}
#endif
/*-----------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------*/
#if CRC8_EN > 0
unsigned char eval_crc8(unsigned char crc, const unsigned char *msg, unsigned msg_len)
{
/*
* Расчет 8-битной контрольной суммы.
* ОПИСАНИЕ
* Вычисляется 8-битный циклический избыточный код.
* ПАРАМЕТРЫ
* crc - начальное значение контрольной суммы (при первом вызове должно быть равно 0);
* msg - указатель на массив данных, по которым вычисляется контрольная сумма;
* msg_len - длина обрабатываемого массива.
* ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
* Полученное значение 8-битной контрольной суммы.
*/
const unsigned char crc8_poly = 0x8c; /* порождающий полином для 8-битной CRC */
unsigned char j;
while (msg_len-- > 0)
{
crc ^= *msg++;
for (j = 8; j > 0; j--)
{
if (crc & 0x80) crc = (crc << 1) ^ crc8_poly;
else crc <<= 1;
}
}
return crc & 0xff;
}
#endif
/*-----------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------*/
#if CRCMODBUS_EN > 0
unsigned short eval_modbuscrc(unsigned short init_crc, const unsigned char *msg, unsigned msg_len)
{
/*
* Расчет контрольной суммы для протокола ModBus.
* ОПИСАНИЕ
* Вычисляется 16-битный циклический избыточный код.
* ПАРАМЕТРЫ
* init_crc - начальное значение контрольной суммы (при первом вызове должно быть равно
* 0xFFFF);
* msg - указатель на массив данных, по которым вычисляется контрольная сумма;
* msg_len - длина обрабатываемого массива.
* ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
* Полученное значение контрольной суммы.
*/
unsigned short crc = init_crc;
unsigned char j;
const unsigned short modbuscrc_poly = 0xA001U;
while (msg_len-- > 0)
{
crc ^= *msg++;
for (j = 8; j > 0; j--)
{
if (crc & 0x01) crc = (crc >> 1) ^ modbuscrc_poly;
else crc >>= 1;
}
}
return crc & 0xFFFF;
}
#endif
/*-----------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------*/
#if CRC8REVERSE_EN > 0
unsigned char eval_revcrc8(unsigned char crc, const unsigned char *msg, unsigned msg_len)
{
/*
* Расчет 8-битной контрольной суммы.
* ОПИСАНИЕ
* Вычисляется 8-битный циклический избыточный код.
* ПАРАМЕТРЫ
* crc - начальное значение контрольной суммы (при первом вызове должно быть равно 0);
* msg - указатель на массив данных, по которым вычисляется контрольная сумма;
* msg_len - длина обрабатываемого массива.
* ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
* Полученное значение 8-битной контрольной суммы.
*/
const unsigned char revcrc8_poly = 0x8c; /* порождающий полином для 8-битной CRC */
unsigned char j;
while (msg_len-- > 0)
{
crc ^= *msg++;
for (j = 8; j > 0; j--)
{
if (crc & 0x01) crc = (crc >> 1) ^ revcrc8_poly;
else crc >>= 1;
}
}
return crc & 0xff;
}
#endif
/*-----------------------------------------------------------------------------------------------*/
/*===============================================================================================*/

View File

@ -0,0 +1,21 @@
#ifndef CRC_H_
#define CRC_H_
#ifdef __cplusplus
extern "C" {
#endif
/*===============================================================================================================*/
extern unsigned short eval_crc16 (unsigned short crc, const unsigned char *msg, unsigned msg_len);
extern unsigned short eval_crc16tbl (unsigned short crc, const unsigned char *msg, unsigned msg_len);
extern unsigned char eval_crc8 (unsigned char crc, const unsigned char *msg, unsigned msg_len);
extern unsigned short eval_modbuscrc (unsigned short init_crc, const unsigned char *msg, unsigned msg_len);
#ifdef REV_CRC
extern unsigned char eval_revcrc8 (unsigned char crc, const unsigned char *msg, unsigned msg_len);
#endif
/*===============================================================================================================*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,207 @@
/*================================================================================================*
* Контрольные суммы CRC-16 и CRC-32 с повышенной скоростью вычислений
*================================================================================================*/
#include "fast_crc.h"
#if FASTCRC_CRC32_BLOCK8
/*================================================================================================*/
/* Table of CRC-32s of all single-byte values */
static const FASTCRC_U32_TYPE f_crc_table[256] =
{
0x00000000UL, 0x77073096UL, 0xEE0E612CUL, 0x990951BAUL, 0x076DC419UL,
0x706AF48FUL, 0xE963A535UL, 0x9E6495A3UL, 0x0EDB8832UL, 0x79DCB8A4UL,
0xE0D5E91EUL, 0x97D2D988UL, 0x09B64C2BUL, 0x7EB17CBDUL, 0xE7B82D07UL,
0x90BF1D91UL, 0x1DB71064UL, 0x6AB020F2UL, 0xF3B97148UL, 0x84BE41DEUL,
0x1ADAD47DUL, 0x6DDDE4EBUL, 0xF4D4B551UL, 0x83D385C7UL, 0x136C9856UL,
0x646BA8C0UL, 0xFD62F97AUL, 0x8A65C9ECUL, 0x14015C4FUL, 0x63066CD9UL,
0xFA0F3D63UL, 0x8D080DF5UL, 0x3B6E20C8UL, 0x4C69105EUL, 0xD56041E4UL,
0xA2677172UL, 0x3C03E4D1UL, 0x4B04D447UL, 0xD20D85FDUL, 0xA50AB56BUL,
0x35B5A8FAUL, 0x42B2986CUL, 0xDBBBC9D6UL, 0xACBCF940UL, 0x32D86CE3UL,
0x45DF5C75UL, 0xDCD60DCFUL, 0xABD13D59UL, 0x26D930ACUL, 0x51DE003AUL,
0xC8D75180UL, 0xBFD06116UL, 0x21B4F4B5UL, 0x56B3C423UL, 0xCFBA9599UL,
0xB8BDA50FUL, 0x2802B89EUL, 0x5F058808UL, 0xC60CD9B2UL, 0xB10BE924UL,
0x2F6F7C87UL, 0x58684C11UL, 0xC1611DABUL, 0xB6662D3DUL, 0x76DC4190UL,
0x01DB7106UL, 0x98D220BCUL, 0xEFD5102AUL, 0x71B18589UL, 0x06B6B51FUL,
0x9FBFE4A5UL, 0xE8B8D433UL, 0x7807C9A2UL, 0x0F00F934UL, 0x9609A88EUL,
0xE10E9818UL, 0x7F6A0DBBUL, 0x086D3D2DUL, 0x91646C97UL, 0xE6635C01UL,
0x6B6B51F4UL, 0x1C6C6162UL, 0x856530D8UL, 0xF262004EUL, 0x6C0695EDUL,
0x1B01A57BUL, 0x8208F4C1UL, 0xF50FC457UL, 0x65B0D9C6UL, 0x12B7E950UL,
0x8BBEB8EAUL, 0xFCB9887CUL, 0x62DD1DDFUL, 0x15DA2D49UL, 0x8CD37CF3UL,
0xFBD44C65UL, 0x4DB26158UL, 0x3AB551CEUL, 0xA3BC0074UL, 0xD4BB30E2UL,
0x4ADFA541UL, 0x3DD895D7UL, 0xA4D1C46DUL, 0xD3D6F4FBUL, 0x4369E96AUL,
0x346ED9FCUL, 0xAD678846UL, 0xDA60B8D0UL, 0x44042D73UL, 0x33031DE5UL,
0xAA0A4C5FUL, 0xDD0D7CC9UL, 0x5005713CUL, 0x270241AAUL, 0xBE0B1010UL,
0xC90C2086UL, 0x5768B525UL, 0x206F85B3UL, 0xB966D409UL, 0xCE61E49FUL,
0x5EDEF90EUL, 0x29D9C998UL, 0xB0D09822UL, 0xC7D7A8B4UL, 0x59B33D17UL,
0x2EB40D81UL, 0xB7BD5C3BUL, 0xC0BA6CADUL, 0xEDB88320UL, 0x9ABFB3B6UL,
0x03B6E20CUL, 0x74B1D29AUL, 0xEAD54739UL, 0x9DD277AFUL, 0x04DB2615UL,
0x73DC1683UL, 0xE3630B12UL, 0x94643B84UL, 0x0D6D6A3EUL, 0x7A6A5AA8UL,
0xE40ECF0BUL, 0x9309FF9DUL, 0x0A00AE27UL, 0x7D079EB1UL, 0xF00F9344UL,
0x8708A3D2UL, 0x1E01F268UL, 0x6906C2FEUL, 0xF762575DUL, 0x806567CBUL,
0x196C3671UL, 0x6E6B06E7UL, 0xFED41B76UL, 0x89D32BE0UL, 0x10DA7A5AUL,
0x67DD4ACCUL, 0xF9B9DF6FUL, 0x8EBEEFF9UL, 0x17B7BE43UL, 0x60B08ED5UL,
0xD6D6A3E8UL, 0xA1D1937EUL, 0x38D8C2C4UL, 0x4FDFF252UL, 0xD1BB67F1UL,
0xA6BC5767UL, 0x3FB506DDUL, 0x48B2364BUL, 0xD80D2BDAUL, 0xAF0A1B4CUL,
0x36034AF6UL, 0x41047A60UL, 0xDF60EFC3UL, 0xA867DF55UL, 0x316E8EEFUL,
0x4669BE79UL, 0xCB61B38CUL, 0xBC66831AUL, 0x256FD2A0UL, 0x5268E236UL,
0xCC0C7795UL, 0xBB0B4703UL, 0x220216B9UL, 0x5505262FUL, 0xC5BA3BBEUL,
0xB2BD0B28UL, 0x2BB45A92UL, 0x5CB36A04UL, 0xC2D7FFA7UL, 0xB5D0CF31UL,
0x2CD99E8BUL, 0x5BDEAE1DUL, 0x9B64C2B0UL, 0xEC63F226UL, 0x756AA39CUL,
0x026D930AUL, 0x9C0906A9UL, 0xEB0E363FUL, 0x72076785UL, 0x05005713UL,
0x95BF4A82UL, 0xE2B87A14UL, 0x7BB12BAEUL, 0x0CB61B38UL, 0x92D28E9BUL,
0xE5D5BE0DUL, 0x7CDCEFB7UL, 0x0BDBDF21UL, 0x86D3D2D4UL, 0xF1D4E242UL,
0x68DDB3F8UL, 0x1FDA836EUL, 0x81BE16CDUL, 0xF6B9265BUL, 0x6FB077E1UL,
0x18B74777UL, 0x88085AE6UL, 0xFF0F6A70UL, 0x66063BCAUL, 0x11010B5CUL,
0x8F659EFFUL, 0xF862AE69UL, 0x616BFFD3UL, 0x166CCF45UL, 0xA00AE278UL,
0xD70DD2EEUL, 0x4E048354UL, 0x3903B3C2UL, 0xA7672661UL, 0xD06016F7UL,
0x4969474DUL, 0x3E6E77DBUL, 0xAED16A4AUL, 0xD9D65ADCUL, 0x40DF0B66UL,
0x37D83BF0UL, 0xA9BCAE53UL, 0xDEBB9EC5UL, 0x47B2CF7FUL, 0x30B5FFE9UL,
0xBDBDF21CUL, 0xCABAC28AUL, 0x53B39330UL, 0x24B4A3A6UL, 0xBAD03605UL,
0xCDD70693UL, 0x54DE5729UL, 0x23D967BFUL, 0xB3667A2EUL, 0xC4614AB8UL,
0x5D681B02UL, 0x2A6F2B94UL, 0xB40BBE37UL, 0xC30C8EA1UL, 0x5A05DF1BUL,
0x2D02EF8DUL
};
/*================================================================================================*/
#endif
/*================================================================================================*/
/* Вычисление CRC16 (CCITT, 0x1021) */
#if FASTCRC_CRC16_ADD8
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U16_TYPE CRC16_Add8 /* Добавление байта */
(
FASTCRC_U16_TYPE crc, /* (вх) - начальное значение */
FASTCRC_U8_TYPE byte /* (вх) - данные */
)
{
/* Оптимизированный алгоритм без цикла по битам */
/* Original code by Ashley Roll */
register FASTCRC_U16_TYPE x = ((crc >> 8) ^ byte) & 0xFF;
x ^= (x >> 4);
return (crc << 8) ^ (x << 12) ^ (x << 5) ^ x;
}
/*------------------------------------------------------------------------------------------------*/
#endif
#if FASTCRC_CRC16_ADD16
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U16_TYPE CRC16_Add16 /* Добавление 16-битного слова (младший байт первым) */
(
FASTCRC_U16_TYPE crc, /* (вх) - начальное значение */
FASTCRC_U16_TYPE word /* (вх) - данные */
)
{
/* Оптимизированный алгоритм без цикла по битам */
/* Наличие преимущества в скорости по сравнению с двумя CRC16_Add8() зависит от системы */
register FASTCRC_U16_TYPE y = ((crc >> 8) ^ word) & 0xFF;
register FASTCRC_U16_TYPE z = (crc ^ (word >> 8)) & 0xFF;
register FASTCRC_U16_TYPE t = y ^ z;
register FASTCRC_U16_TYPE q = (y ^ (y << 1)) << 12;
t ^= (t >> 4);
t ^= (y >> 3);
q ^= (q >> 4);
z ^= (z >> 4);
return t ^ (t << 5) ^ (y << 4) ^ (z << 12) ^ q;
}
/*------------------------------------------------------------------------------------------------*/
#endif
#if FASTCRC_CRC16_BLOCK8
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U16_TYPE CRC16_Block8 /* Вычисление CRC16 блока байтов */
(
FASTCRC_U16_TYPE crc, /* (вх) - начальное значение */
const FASTCRC_U8_TYPE* pdata, /* (вх) - данные */
FASTCRC_SIZE_TYPE num_bytes /* (вх) - размер данных */
)
{
/* Оптимизированный алгоритм без цикла по битам */
/* Original code by Ashley Roll */
if (pdata)
{
register FASTCRC_U16_TYPE x;
while (num_bytes--)
{
x = ((crc >> 8) ^ (*pdata++)) & 0xFF;
x ^= (x >> 4);
crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x;
}
}
return crc;
}
/*------------------------------------------------------------------------------------------------*/
#endif
#if FASTCRC_CRC16_BLOCK16
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U16_TYPE CRC16_Block16 /* Вычисление CRC16 блока 16-битных слов */
(
FASTCRC_U16_TYPE crc, /* (вх) - начальное значение */
const FASTCRC_U16_TYPE* pdata, /* (вх) - данные */
FASTCRC_SIZE_TYPE num_words /* (вх) - размер данных */
)
{
/* Оптимизированный алгоритм без цикла по битам */
/* Наличие преимущества в скорости по сравнению с двумя CRC16_Add8() зависит от системы */
if (pdata)
{
register FASTCRC_U16_TYPE y, z, t, q;
while (num_words--)
{
t = *pdata++;
y = ((crc >> 8) ^ t) & 0xFF;
z = (crc ^ (t >> 8)) & 0xFF;
t = y ^ z;
q = (y ^ (y << 1)) << 12;
t ^= (t >> 4);
t ^= (y >> 3);
q ^= (q >> 4);
z ^= (z >> 4);
crc = t ^ (t << 5) ^ (y << 4) ^ (z << 12) ^ q;
}
}
return crc;
}
/*------------------------------------------------------------------------------------------------*/
#endif
/* Вычисление CRC32 (CCITT) */
#if FASTCRC_CRC32_BLOCK8
/*------------------------------------------------------------------------------------------------*/
/* crc32 -- compute the CRC-32 of a data stream
* Copyright (C) 1995-2005 Mark Adler
*
* THIS VERSION HAS BEEN MODIFIED:
* No BYFOUR code (fast, but requires 8 tables)
* No dynamic table generation
* CRC concatenation function removed
* Code reformatted for cosmetic uniformity
*/
FASTCRC_U32_TYPE CRC32_Block8 /* Вычисление CRC32 блока байтов */
(
FASTCRC_U32_TYPE crc, /* (вх) - начальное значение (при первом блоке 0) */
const FASTCRC_U8_TYPE* pdata, /* (вх) - данные */
FASTCRC_SIZE_TYPE num_bytes /* (вх) - размер данных */
)
{
#define DO1 crc = f_crc_table[(crc ^ (*pdata++)) & 0xFF] ^ (crc >> 8)
if (!pdata) return crc;
crc ^= 0xFFFFFFFFUL;
while (num_bytes >= 8)
{
DO1; DO1; DO1; DO1;
DO1; DO1; DO1; DO1;
num_bytes -= 8;
}
if (num_bytes) do
{
DO1;
}
while (--num_bytes);
return crc ^ 0xFFFFFFFFUL;
#undef DO1
}
/*------------------------------------------------------------------------------------------------*/
#endif
/*================================================================================================*/

View File

@ -0,0 +1,75 @@
/*================================================================================================*
* Контрольные суммы CRC-16 и CRC-32 с повышенной скоростью вычислений
*================================================================================================*/
#ifndef FAST_CRC_H_
#define FAST_CRC_H_
#include "fast_crc_cfg.h"
#ifdef __cplusplus
extern "C" {
#endif
/*================================================================================================*/
/* Вычисление CRC16 (CCITT, 0x1021) */
#if FASTCRC_CRC16_ADD8
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U16_TYPE CRC16_Add8 /* Добавление байта */
(
FASTCRC_U16_TYPE crc, /* (вх) - начальное значение */
FASTCRC_U8_TYPE byte /* (вх) - данные */
);
/*------------------------------------------------------------------------------------------------*/
#endif
#if FASTCRC_CRC16_ADD16
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U16_TYPE CRC16_Add16 /* Добавление 16-битного слова (младший байт первым) */
(
FASTCRC_U16_TYPE crc, /* (вх) - начальное значение */
FASTCRC_U16_TYPE word /* (вх) - данные */
);
/*------------------------------------------------------------------------------------------------*/
#endif
#if FASTCRC_CRC16_BLOCK8
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U16_TYPE CRC16_Block8 /* Вычисление CRC16 блока байтов */
(
FASTCRC_U16_TYPE crc, /* (вх) - начальное значение */
const FASTCRC_U8_TYPE* pdata, /* (вх) - данные */
FASTCRC_SIZE_TYPE num_bytes /* (вх) - размер данных */
);
/*------------------------------------------------------------------------------------------------*/
#endif
#if FASTCRC_CRC16_BLOCK16
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U16_TYPE CRC16_Block16 /* Вычисление CRC16 блока 16-битных слов */
(
FASTCRC_U16_TYPE crc, /* (вх) - начальное значение */
const FASTCRC_U16_TYPE* pdata, /* (вх) - данные */
FASTCRC_SIZE_TYPE num_words /* (вх) - размер данных */
);
/*------------------------------------------------------------------------------------------------*/
#endif
/* Вычисление CRC32 (CCITT) */
#if FASTCRC_CRC32_BLOCK8
/*------------------------------------------------------------------------------------------------*/
FASTCRC_U32_TYPE CRC32_Block8 /* Вычисление CRC32 блока байтов */
(
FASTCRC_U32_TYPE crc, /* (вх) - начальное значение (при первом блоке 0) */
const FASTCRC_U8_TYPE* pdata, /* (вх) - данные */
FASTCRC_SIZE_TYPE num_bytes /* (вх) - размер данных */
);
/*------------------------------------------------------------------------------------------------*/
#endif
/*================================================================================================*/
#ifdef __cplusplus
}
#endif
#endif /* FAST_CRC_H_ */

View File

@ -0,0 +1 @@
#pragma pack()

View File

@ -0,0 +1 @@
#pragma pack(1)

View File

@ -0,0 +1 @@
__attribute__ ((__aligned__ (LSPEC_ALIGNMENT)))

View File

@ -0,0 +1 @@
__attribute__ ((__interrupt__))

View File

@ -0,0 +1 @@
#pragma data_alignment=LSPEC_ALIGNMENT

View File

@ -0,0 +1 @@
__irq

View File

@ -0,0 +1 @@
#pragma pack(pop)

View File

@ -0,0 +1 @@
#pragma pack(push, 1)

View File

@ -0,0 +1,22 @@
# Файл для включения в проект на CMAKE.
# Перед включением необходимо определить переменные
# LCSPEC_DIR - путь к директории, где находится файлы lcspec (по умолчанию lib/lcspec)
#
# После включения будут добавлены в директории заголовков нужные для lcspec директории
if (NOT LCSPEC_DIR)
set(LCSPEC_DIR lib/lcspec)
endif(NOT LCSPEC_DIR)
include_directories(${LCSPEC_DIR})
if(MSVC)
include_directories(${LCSPEC_DIR}/msvc)
elseif(CMAKE_COMPILER_IS_GNUCC)
include_directories(${LCSPEC_DIR}/gcc)
elseif(${CMAKE_C_COMPILER_ID} STREQUAL "Watcom")
include_directories(${LCSPEC_DIR}/watcom)
elseif(${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
include_directories(${LCSPEC_DIR}/gcc)
endif()

View File

@ -0,0 +1,96 @@
/***************************************************************************//**
@file lcspec.h
Файл вместе с файлами из подкаталога с именем компилятора определяет набор
макросов и заголовочных файлов для выполнения действий, которые определяются
специфичным для компилятора способом:
- упаковка структур
- выравнивание переменных
- определение inline-функций
Для задания упаковки структур используются два файла lcspec_pack_start.h и
lcspec_pack_restore.h для возможности указать упаковку через \#pragma.
Кроме того используется определение #LATTRIBUTE_PACKED для определения
упаковки с помощью атрибутов (как в gcc).
Упакованная структура должна быть обявлена следующим образом :
@code
#include "lcspec_pack_start.h"
struct struct_name {
...
} LATTRIBUTE_PACKED;
typedef struct struct_name type_name;
...
#include "lcspec_pack_restore.h"
@endcode
Выравнивание на n байт выполняется также через включение файла с предварительным
определением границы выравнивания через LSPEC_ALIGNMENT.
Ниже объявлены две переменные с выравниванием 128 байт:
@code
#define LSPEC_ALIGNMENT 128
#include "lcspec_align.h"
int v1;
#include "lcspec_align.h"
unsigned v2;
#undef LSPEC_ALIGNMENT
@endcode
Для встроенных функций определено определение #LINLINE, которое должно быть указано
в начале определения функции перед типом возвращаемого значения
(после слова static для статической функции)
На настоящий момент реализованы определения для GCC, IAR, MSVC, OpenWatcom и LabWindow/CVI.
@author Borisov Alexey <borisov@lcard.ru>
@date 10.01.2011
*******************************************************************************/
#ifndef LCSPEC_H_
#define LCSPEC_H_
#if defined ( __GNUC__ )
/*------------------------ определения GCC -------------------------------*/
#define LINLINE inline
#define LATTRIBUTE_PACKED __attribute__ ((packed))
#elif defined ( _MSC_VER )
/*------------------------ определения MSVC ------------------------------*/
#define LINLINE __inline
#define LATTRIBUTE_PACKED
/*------------------------ Watcom/Open Watcom ----------------------------*/
#elif defined ( _WATCOMC_ ) || defined (__WATCOMC__)
#define LINLINE __inline
#define LATTRIBUTE_PACKED
#elif defined ( _CVI_ )
/*------------------- определения для LabWindow/CVI ----------------------*/
#define LINLINE inline
#define LATTRIBUTE_PACKED
#elif defined ( __CC_ARM )
#error "cc arm compiler spec. is't defined"
#elif defined ( __ICCARM__ )
#define LINLINE inline
#define LATTRIBUTE_PACKED
#elif defined ( __TASKING__ )
#error "tasking compiler spec. is't defined"
#else
#error "compiler is't specified"
/** Определение встраиваемой (inline) функции */
#define LINLINE inline
/** Определение упакованной структуры через атрибут в конце структуры (как в GCC).
Если не используется, то этот макрос должен быть определен как пустой. */
#define LATTRIBUTE_PACKED __attribute__ ((packed))
#endif
/* теперь вместо определения содержимого\#pragma используются include-файлы
* (так как предыдущий вариант работал не на всех компиляторах) */
#define LPRAGMA_PACKED error: you must use new syntax for packed structs
#define LPRAGMA_PACK_RESTORE error: you must use new syntax for packed structs
#define LALIGN error: you must use new syntax for aligned variables
#endif /* LCSPEC_H_ */

View File

@ -0,0 +1 @@
__declspec( align( LSPEC_ALIGNMENT ) )

View File

@ -0,0 +1 @@
#pragma pack(pop)

View File

@ -0,0 +1,2 @@
#pragma warning(disable : 4103)
#pragma pack(push, 1)

View File

@ -0,0 +1 @@
#pragma pack()

View File

@ -0,0 +1 @@
#pragma pack(1)

View File

@ -0,0 +1,74 @@
/***************************************************************************//**
@addtogroup ltimer
@{
@file lclock.h
Файл содержит заголовки функций для работы с системным счетчиком. Сами функции
реализуются портом для соответствующей платформы.
@author Borisov Alexey <borisov@lcard.ru>
*****************************************************************************/
#ifndef LCLOCK_H_
#define LCLOCK_H_
#include "lclock_arch.h"
#include "lcspec.h"
#ifndef LCLOCK_TICKS_PER_SECOND
/** Константа, определяющее количество отсчетов системного счетчика в секунду */
#define LCLOCK_TICKS_PER_SECOND 1000
#endif
#if LCLOCK_TICKS_PER_SECOND == 1000
/** Макрос для перевода интервала в мс в количество отсчетов системного счетчика */
#define LTIMER_MS_TO_CLOCK_TICKS(tout) (tout)
/** Макрос для перевода интервала в количестве отсчетов системного счетчика в интервал в мс */
#define LTIMER_CLOCK_TICKS_TO_MS(tout) (tout)
#else
#define LTIMER_MS_TO_CLOCK_TICKS(tout) ((tout)*(LCLOCK_TICKS_PER_SECOND/1000))
#define LTIMER_CLOCK_TICKS_TO_MS(tout) ((tout)*1000/LCLOCK_TICKS_PER_SECOND)
#endif
/** Маска для выделения старшего бита в типе #t_lclock_ticks */
#define LCLOCK_HIGH_BIT (((t_lclock_ticks)-1)/2 + 1)
/** Проверка, установлен ли старший бит для типа #t_lclock_ticks. Если
переменная данного типа содержит интервал в отсчетах системного счетчика,
полученный как разность значений отсчетов счетчика, то данный макрос
можно использовать как признак, отрицательный ли интервал */
#define LCLOCK_IS_NEG(clock) ((clock) & LCLOCK_HIGH_BIT)
#ifdef __cplusplus
extern "C" {
#endif
/** Инициализация системного счетчика заданным значением и его запуск */
void lclock_init_val(t_lclock_ticks init_val);
/** Получение текущего значения системного счетчика */
t_lclock_ticks lclock_get_ticks(void);
/** Запуск системного счетчика в случае, если его начальное значение не важно */
static LINLINE void lclock_init(void) {
lclock_init_val(0);
}
/** Проверка, был ли уже инициализирован системный счетчик */
char lclock_is_initialized(void);
/** Запрет работы системного счетчика */
void lclock_disable(void);
/** Для некоторых портов есть возможность реализовать пользовательскую функцию,
* которая будет вызываться раз в мс. Для этого необходимо глобально определить
* LCLOCK_USE_USER_MS_CB и реализовать функцию lclock_user_ms_cb() */
#ifdef LCLOCK_USE_USER_MS_CB
extern void lclock_user_ms_cb(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* LCLOCK_H_ */
/** @} */

View File

@ -0,0 +1,56 @@
# Файл для включения в проект на CMAKE.
# Перед включением необходимо определить переменные
# LTIMER_DIR - путь к директории, где находится ltimer.cmake
# LCSPEC_DIR - путь к директории, где находится файлы lcspec
#
# После включения будут установлены следующие перменные:
# LTIMER_HEADERS - используемые заголовочные файлы
# LTIMER_SOURCES - используемые файлы исходных кодов
# LTIMER_LIBS - используемые библиотеки
# LTIMER_DEFINITIONS - используемые определения компилятора
cmake_policy(PUSH)
cmake_minimum_required(VERSION 2.8.12)
include(CheckLibraryExists)
include(CheckFunctionExists)
set (LTIMER_HEADERS
${LTIMER_DIR}/ltimer.h
${LCSPEC_DIR}/lcspec.h
)
if(UNIX)
set(LTIMER_SOURCES ${LTIMER_DIR}/ports/linux/lclock.c)
include_directories(${LTIMER_DIR}/ports/linux)
elseif(WIN32)
set(LTIMER_SOURCES ${LTIMER_DIR}/ports/win/lclock.c)
include_directories(${LTIMER_DIR}/ports/win)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "QNX4")
set(LTIMER_SOURCES ${LTIMER_DIR}/ports/linux/lclock.c)
include_directories(${LTIMER_DIR}/ports/linux)
endif(UNIX)
include_directories(${LCSPEC_DIR} ${LTIMER_DIR})
if(UNIX)
check_library_exists(rt clock_gettime "" HAVE_LIBRT)
if(HAVE_LIBRT)
set(LTIMER_LIBS ${TIMER_LIBS} rt)
else(HAVE_LIBRT)
set(CMAKE_REQUIRED_INCLUDES time.h)
# проверяем наличие clock_gettime вне librt.
# если нет, то можем откатиться к gettimeofday
check_function_exists("clock_gettime" HAVE_CLOCKGETTIME)
if(NOT HAVE_CLOCKGETTIME)
set(LTIMER_DEFINITIONS NO_CLOCKGETTIME)
endif(NOT HAVE_CLOCKGETTIME)
endif(HAVE_LIBRT)
endif(UNIX)
cmake_policy(POP)

View File

@ -0,0 +1,278 @@
/***************************************************************************//**
@defgroup ltimer Таймер
Модуль представляет собой набор функций для реализации таймера на основе
системных часов процессора (контроллера) или ОС.
Работа таймера основана на системном счетчике, который должен равномерно
увеличиваться с течением времени.
Реализация функций для инициализации системного счетчика и получения его значения
реализуются для каждой платформы своим портом. Также порт определяет количество
тиков системного счетчика за секунду с помощью константы #LCLOCK_TICKS_PER_SECOND
и тип #t_lclock_ticks для представления текущего значения системного счетчика.
Эти функции могут использоваться как напрямую, так и через общее API для работы
с таймером из ltimer.h, который может использоваться для отсчета интервалов
времени.
Все функции принимают значения в отсчетах системного счетчика, поэтому необходимо
использовать константу #LCLOCK_TICKS_PER_SECOND для перевода времени в количество отсчетов.
Также можно использовать макросы LTIMER_MS_TO_CLOCK_TICKS() и LTIMER_CLOCK_TICKS_TO_MS()
для перевода интервалов в миллисекундах в количество отсчетов и наоборот.
Для работы с модулем в проекте нужно добавить в стандартные пути
для включения заголовочных файлов пути к файлу ltimer.h и к директории с портом
для используемой платформы, а также путь к файлу lcspec.h, в котором
описаны специфические для компилятора макросы (в данном случае используется
#LINLINE для определения inline-функций). Также необходимо в исходники
добавить файл lclock.c из нужного порта.
При работе с системным счетчиком контроллера перед вызовом функций данного модуля
необходимо вызвать функцию lclock_init() (или lclock_init_val(), если нужно задать
начальное значение системного счетчика). При работе с системными часами ОС
обычно эта функция не требуется, так как таймер ОС уже инициализирован
самой ОС (однако ее вызов можно оставить, так как каждый порт реализует хотя бы
"пустую" версию этой функции).
Для работы с системным счетчиком напрямую используется функция lclock_get_ticks(),
возвращающая значение системного счетчика.
Для работы с API таймера, необходимо объявить переменную типа #t_ltimer, которая
будет хранить состояние таймра. Работать с полями структуры напрямую не рекомендуется.
Вместо этого следует использовать функции из ltimer.h, которые принимают эту
переменную в качестве первого аргумента.
При стандартной работе, сперва таймер устанавливается для отсчета заданного
интервала с помощью ltimer_set(). Проверить, истек ли заданный интервал,
можно с помощью ltimer_expired(). Количество отсчетов системного счетчика
до истечения интервала можно получить с помощью ltimer_expiration().
Перезапустить таймер на установленный в предыдущем ltimer_set() интервал можно
с помощью ltimer_reset() или ltimer_restart() (относительно времени последнего
истечения таймера или текущего времени соответственно).
Например, если какие-то действия нужно выполнять в течении заданного интервала,
то это можно сделать следующим образом:
@code
//время интервала в мс
#define TIMEOUT_MS 200
void main(void) {
t_ltimer tmr;
//инициализируем системный счетчик
lclock_init();
// устанавливаем таймер на заданное кол-во мс
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(TIMEOUT_MS));
while (!ltimer_expired(&tmr)) {
//выполняем требуемые действия
}
//интервал завершился
}
@endcode
В качестве основной идеи была взята реализация таймера для стека uIP от
Adam Dunkels <adam@sics.se>
*****************************************************************************/
/***************************************************************************//**
@addtogroup ltimer
@{
@file ltimer.h
Файл содержит описание функций для работы с таймером. Все функции реализованы
как inline-функции, так что файл содержит и реализацию функций
@author Borisov Alexey <borisov@lcard.ru>
*****************************************************************************/
#ifndef __LTIMER_H__
#define __LTIMER_H__
#include "lclock.h"
#include "lcspec.h"
/** Структура для описания состояния таймера */
typedef struct ltimer {
t_lclock_ticks start; /**< Значение системного таймера, с которого ведется отсчет */
t_lclock_ticks interval; /**< Интервал времени, после которого таймер считается истекшим */
} t_ltimer;
/***************************************************************************//**
@brief Получить время запуска таймера
@param[in] t Указатель на состояние таймера
@return Значение времени запуска таймера в системных клоках
******************************************************************************/
static LINLINE t_lclock_ticks ltimer_start_time(t_ltimer *t) {
return t->start;
}
/***************************************************************************//**
@brief Получить время срабатывания таймера
@param[in] t Указатель на состояние таймера
@return Значение времени срабатывания таймера в системных клоках
******************************************************************************/
static LINLINE t_lclock_ticks ltimer_expiration_time(t_ltimer *t) {
return t->start + t->interval;
}
/***************************************************************************//**
@brief Получить установленный интервал для таймера
@param[in] t Указатель на состояние таймера
@return Значение установленного интервала в системных клоках
******************************************************************************/
static LINLINE t_lclock_ticks ltimer_interval(t_ltimer *t) {
return t->interval;
}
/***************************************************************************//**
@brief Установить временной интервал относительно заданного времени
Функция устанавливает таймер на заданный интервал, аналогично ltimer_set(),
но относительно заданного времени (значения системного счетчика), а не
относительно текущего.
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
заданный интервал.
@param[in] t Указатель на состояние таймера
@param[in] interval Интервал, через который таймер истечет в системных клоках.
@param[in] start_time Значение системного счетчика, относительно которого
устанавливается временной интервал
******************************************************************************/
static LINLINE void ltimer_set_at(t_ltimer *t, t_lclock_ticks interval, t_lclock_ticks start_time) {
t->interval = interval;
t->start = start_time;
}
/***************************************************************************//**
@brief Установить временной интервал
Функция устанавливает таймер на заданный интервал относительно текущего времени.
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
заданный интервал.
@param[in] t Указатель на состояние таймера
@param[in] interval Интервал, через который таймер истечет в системных клоках.
******************************************************************************/
static LINLINE void ltimer_set(t_ltimer *t, t_lclock_ticks interval) {
ltimer_set_at(t, interval, lclock_get_ticks());
}
/***************************************************************************//**
@brief Установить временной интервал в мс
Функция устанавливает таймер на заданный интервал в милисекундах относительно
текущего времени.
С помощью функции ltimer_expired() можно в дальнейшем проверить, истек ли
заданный интервал.
@param[in] t Указатель на состояние таймера
@param[in] ms Интервал, через который таймер истечет в милисекундах.
******************************************************************************/
static LINLINE void ltimer_set_ms(t_ltimer *t, unsigned ms) {
ltimer_set(t, LTIMER_MS_TO_CLOCK_TICKS(ms));
}
/***************************************************************************//**
@brief Сброс таймера.
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set()
относительно времени последнего истечения таймера (а не текущего времени, как
ltimer_restart()). По сути функция продлевает время истечения таймера на тот
же интервал, что был задан. Интервалы между срабатыванием таймеров
сохраняется во времени, в отличие от использования ltimer_restart().
@param[in] t Указатель на состояние таймера
*****************************************************************************/
static LINLINE void ltimer_reset(t_ltimer *t) {
t->start += t->interval;
}
/***************************************************************************//**
@brief Перезапуск таймера с заданного времени.
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set(),
относительно текущего времени, начиная с указанного времени.
@param[in] t Указатель на состояние таймера
@param[in] start_time Значение системного счетчика, соответствующего времени,
с которого перезапускается таймер
*****************************************************************************/
static LINLINE void ltimer_restart_at(t_ltimer *t, t_lclock_ticks time) {
t->start = time;
}
/***************************************************************************//**
@brief Перезапуск таймера.
Данная функции перезапускает таймер на интервал, заданный в последнем ltimer_set(),
относительно текущего времени.
@note Время срабатывания периодического таймер будет "плыть" при использовании
данной функции (из-за случайной разницы между текущим временем и временем
завершения предыдущего интервала). Для периодического таймера можно использовать
ltimer_reset()
@param[in] t Указатель на состояние таймера
*****************************************************************************/
static LINLINE void ltimer_restart(t_ltimer *t) {
ltimer_restart_at(t, lclock_get_ticks());
}
/***************************************************************************//**
@brief Проверка, истечет ли заданный интервал в определенное время
Функция проверяет, истечет ли установленный с помощью ltimer_set() интервал
в моент времени, определяемый заданным значением системного счетчика.
@param[in] t Указатель на состояние таймера
@param[in] exp_time Значение системного счетчика, для которого проверяется,
истечет ли таймер в данный момент
@return Не ноль, если интервал истечет, иначе --- ноль
******************************************************************************/
static LINLINE int ltimer_expired_at(const t_ltimer *t, t_lclock_ticks exp_time) {
return (t_lclock_ticks)(exp_time - t->start) > (t_lclock_ticks)t->interval;
}
/***************************************************************************//**
@brief Проверка, истек ли заданный интервал
Функция проверяет, истек ли заданный с помощью ltimer_set() интервал.
@param[in] t Указатель на состояние таймера
@return Не ноль, если интервал истек, иначе --- ноль
******************************************************************************/
static LINLINE int ltimer_expired(const t_ltimer *t) {
return ltimer_expired_at(t, lclock_get_ticks());
}
/***************************************************************************//**
@brief Получить время до истечения интервала от заданного момента
Функция возвращает значение интервала времени (в системных клоках) от заданного
момента до времени истечения установленного с помощью ltimer_set() интервала.
@param[in] t Указатель на состояние таймера
@param[in] cur_time Значение системного счетчика, от которого считается время
до момента истечения интервала
@return Время (в клоках системного счетчика) до истечения интервала
*******************************************************************************/
static LINLINE t_lclock_ticks ltimer_expiration_from(const t_ltimer *t, t_lclock_ticks cur_time) {
t_lclock_ticks expired = (cur_time-t->start);
return (expired > t->interval) ? 0 : t->interval - expired;
}
/***************************************************************************//**
@brief Получить время до истечения интервала
Функция возвращает значение интервала времени (в системных клоках) от текущего
момента до времени истечения установленного с помощью ltimer_set() интервала.
@param[in] t Указатель на состояние таймера
@return Время (в клоках системного счетчика) до истечения интервала
*******************************************************************************/
static LINLINE t_lclock_ticks ltimer_expiration(const t_ltimer *t) {
return ltimer_expiration_from(t, lclock_get_ticks());
}
#endif /* __LTIMER_H__ */
/** @} */

View File

@ -0,0 +1,45 @@
# makefile для включения в проект.
#
# на входе принимает параметры:
# TARGET_CPU (или может быть переопределен через LTIMER_TARGET) - если явно
# не установлена переменная LTIMER_PORT, то по данной переменной
# выбирается подходящий порт
# LTIMER_PORT - опционально можно явно указать порт (на случай, если несколько
# портов могут относится к одной архитектуре)
# LSCPEC_DIR - путь к определениям к lcspec (по-умолчанию ../lcspec относительно данного файла)
#
# устанавливает следующие параметры:
# LTIMER_SRC - исходные файлы на C
# LTIMER_INC_DIRS - директории с заголовками, которые должны быть добавлены
# в список директорий для поиска заголовков проекта
LTIMER_MAKEFILE = $(abspath $(lastword $(MAKEFILE_LIST)))
LTIMER_DIR := $(dir $(LTIMER_MAKEFILE))
LCSPEC_DIR ?= $(LTIMER_DIR)/../lcspec
LTIMER_TARGET ?= $(TARGET_CPU)
ifndef LTIMER_PORT
ifeq ($(LTIMER_TARGET), lpc17xx)
LTIMER_PORT = cm_systick
else ifeq ($(LTIMER_TARGET), lpc43xx)
LTIMER_PORT = cm_systick
else ifeq ($(LTIMER_TARGET), lpc11u6x)
LTIMER_PORT = cm_systick
else ifeq ($(LTIMER_TARGET), bf609)
LTIMER_PORT = bf_core_tmr
else ifeq ($(LTIMER_TARGET), imx6)
LTIMER_PORT = imx6_epit
else ifeq ($(LTIMER_TARGET), stm32h7xx)
LTIMER_PORT = cm_systick
endif
endif
ifndef LTIMER_PORT
$(error unknown port. LTIMER_PORT or one of supported target in LTIMER_TARGET or TARGET_CPU must be specified)
endif
LTIMER_SRC := $(LTIMER_DIR)/ports/$(LTIMER_PORT)/lclock.c
LTIMER_INC_DIRS := $(LCSPEC_DIR) $(LTIMER_DIR) $(LTIMER_DIR)/ports/$(LTIMER_PORT)

View File

@ -0,0 +1,12 @@
#include "chip.h"
#include "lclock_arch.h"
t_lclock_ticks g_lclock_tiks_per_sec;
void lclock_init_val(t_lclock_ticks init_val) {
g_lclock_tiks_per_sec = chip_gtim_freq();
}
t_lclock_ticks lclock_get_ticks(void) {
return chip_gtim_cntr();
}

View File

@ -0,0 +1,15 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include <stdint.h>
typedef uint64_t t_lclock_ticks;
extern t_lclock_ticks g_lclock_tiks_per_sec;
#define LCLOCK_TICKS_PER_SECOND g_lclock_tiks_per_sec
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,70 @@
#include "chip.h"
#include "lclock.h"
static volatile t_lclock_ticks lclock_systicks;
static uint8_t f_initialized = 0;
ISR(TIMER2_COMPA_vect) {
lclock_systicks++;
}
#define CLOCK_IRQ_TICKS (CHIP_CLK_SYS_FREQ/LCLOCK_TICKS_PER_SECOND)
#if CLOCK_IRQ_TICKS < 256
#define LCLOCK_SYS_CLK_DIV 1
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_1
#elif CLOCK_IRQ_TICKS/8 < 256
#define LCLOCK_SYS_CLK_DIV 8
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_8
#elif CLOCK_IRQ_TICKS/32 < 256
#define LCLOCK_SYS_CLK_DIV 32
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_32
#elif CLOCK_IRQ_TICKS/64 < 256
#define LCLOCK_SYS_CLK_DIV 64
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_64
#elif CLOCK_IRQ_TICKS/128 < 256
#define LCLOCK_SYS_CLK_DIV 128
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_128
#elif CLOCK_IRQ_TICKS/256 < 256
#define LCLOCK_SYS_CLK_DIV 256
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_256
#elif CLOCK_IRQ_TICKS/1024 < 256
#define LCLOCK_SYS_CLK_DIV 1024
#define LCLOCK_TCCR0B_CS_RVAL CHIP_REGFLDVAL_TCCR2B_CS_FSYS_1024
#else
#error "unsupported system clock frequency"
#endif
/*************************************************************************
* инициализация системного таймера
* использует для этого RIT
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализируем счетчик */
lclock_systicks = init_val;
f_initialized = 1;
CHIP_REG_TIMSK2 = CHIP_REGFLD_TIMSK0_OCIE0A;
CHIP_REG_OCR2A = ((CLOCK_IRQ_TICKS + LCLOCK_SYS_CLK_DIV/2)/LCLOCK_SYS_CLK_DIV -1);
CHIP_REG_TCCR2A = LBITFIELD_SET(CHIP_REGFLD_TCCR0A_WGM0_01, CHIP_REGFLDVAL_TC2_WGM_CTC);
CHIP_REG_TCCR2B = LBITFIELD_SET(CHIP_REGFLD_TCCR0B_WGM0_2, CHIP_REGFLDVAL_TC2_WGM_CTC >> 2)
| LBITFIELD_SET(CHIP_REGFLD_TCCR0B_CS, LCLOCK_TCCR0B_CS_RVAL);
}
char lclock_is_initialized(void) {
return f_initialized;
}
t_lclock_ticks lclock_get_ticks(void) {
return lclock_systicks;
}
void lclock_disable(void) {
CHIP_REG_TCCR2B = 0;
f_initialized = 0;
}

View File

@ -0,0 +1,10 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include <stdint.h>
#define LCLOCK_TICKS_PER_SECOND 1000
typedef uint32_t t_lclock_ticks;
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,47 @@
/***************************************************************************//**
@ingroup ltimer_bf_core_tmr
@file ports/bf_core_tmr/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
для процессора BlackFin
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
/* файл должен определять LPC_SYSCLK и включать cmsis.h */
#include "chip.h"
volatile t_lclock_ticks lclock_systicks;
static char f_initialized = 0;
ISR(lclock_isr);
/*************************************************************************
* инициализация системного таймера
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализируем счетчик */
lclock_systicks = init_val;
REGISTER_ISR(6, lclock_isr);
*pTCNTL = BITM_TCNTL_AUTORLD | BITM_TCNTL_PWR;
*pTPERIOD = CHIP_CLKF_CCLK/LCLOCK_TICKS_PER_SECOND;
*pTSCALE = 0;
*pTCNTL |= BITM_TCNTL_EN;
f_initialized = 1;
}
char lclock_is_initialized(void) {
return f_initialized;
}
void lclock_disable(void) {
*pTCNTL = 0;
f_initialized = 0;
}
ISR(lclock_isr) {
lclock_systicks++;
#ifdef LCLOCK_USE_USER_MS_CB
lclock_user_ms_cb();
#endif
}

View File

@ -0,0 +1,38 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_bf_core_tmr Порт таймера для BlackFin
Порт для работы с таймером для сигнальных процессоров BlackFin от Analog Devices.
Для получения системного счетчика использует таймер ядра
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_bf_core_tmr
@file ports/bf_core_tmr/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
для процессоров BlackFin
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#include "lcspec.h"
#ifndef LCLOCK_TICKS_PER_SECOND
/** Количество тиков системного таймера в секунду */
#define LCLOCK_TICKS_PER_SECOND 1000
#endif
/** Тип для представления количества системных тиков */
typedef unsigned int t_lclock_ticks;
extern volatile t_lclock_ticks lclock_systicks;
static LINLINE t_lclock_ticks lclock_get_ticks(void) {
return lclock_systicks;
}
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,66 @@
/***************************************************************************//**
@ingroup ltimer_cm_systick
@file ports/cm_systick/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
для Cortex-M с использованием системного таймера.
Порт требует наличие файла chip.h, который включает определение LPC_SYSCLK
и включать функции CMSIS (используется SysTick_Config).
Если LPC_SYSCLK не определена, то используется значение из переменной SystemCoreClock
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
/* файл должен определять LPC_SYSCLK и включать cmsis.h */
#include "chip.h"
#ifndef LCLOCK_IN_CLK_FREQ
#ifdef CHIP_CLK_SYSTICK_FREQ
/* используем частоту SysTick, если она определена в chip */
#define LCLOCK_IN_CLK_FREQ CHIP_CLK_SYSTICK_FREQ
#elif defined LPC_SYSCLK
/* для совместимости с версией chip, где определялось только значение LPC_SYSCLK */
#define LCLOCK_IN_CLK_FREQ LPC_SYSCLK
#else
/* если другие варианты не определены, то используем вариант с внешней
* переменной, который в частности используется в lpcopen */
extern uint32_t SystemCoreClock;
#define LCLOCK_IN_CLK_FREQ SystemCoreClock
#endif
#endif
volatile t_lclock_ticks lclock_systicks;
static char f_initialized = 0;
/*************************************************************************
* инициализация системного таймера
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализируем счетчик */
lclock_systicks = init_val;
SysTick_Config(LCLOCK_IN_CLK_FREQ / LCLOCK_TICKS_PER_SECOND);
f_initialized = 1;
}
char lclock_is_initialized(void) {
return f_initialized;
}
void lclock_disable(void) {
SysTick->CTRL = 0;
f_initialized = 0;
}
/* обработка прерывания от системного таймера - обновление числа тиков */
#if defined ( __ICCARM__ )
void SysTick_Handler(void) {
#else
void SysTick_IRQHandler(void) {
#endif
lclock_systicks++;
#ifdef LCLOCK_USE_USER_MS_CB
lclock_user_ms_cb();
#endif
}

View File

@ -0,0 +1,44 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_cm_systick Порт таймера для Cortex-M
Порт для работы с таймером для микроконтроллеров с ядром Cortex-M.
Для получения системного счетчика использует системный таймер (SysTick).
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_cm_systick
@file ports/cm_systick/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
для процессоров с ядром Cortex-M с использованием системного таймера.
Порт использует внешний файл chip.h, в котором должно быть определено
значение частоты входной частоты системного таймера одним из следующих способов
(в порядке убывания приоритетов):
- определен явно макрос LCLOCK_IN_CLK_FREQ
- определен макрос CHIP_CLK_SYSTICK_FREQ (в новых версиях библиотеки chip)
- определен макрос LPC_SYSCLK (старая версия библиотеки chip или порта контроллера для LPC)
- в проекте должна существовать глобальная переменная SystemCoreClock типа uint32_t,
которая на момент lcock_init() должна содержать действительную частоту
системного таймера
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#include "lcspec.h"
/** Количество тиков системного таймера в секунду */
#define LCLOCK_TICKS_PER_SECOND 1000
/** Тип для представления количества системных тиков */
typedef unsigned int t_lclock_ticks;
extern volatile t_lclock_ticks lclock_systicks;
static LINLINE t_lclock_ticks lclock_get_ticks(void) {
return lclock_systicks;
}
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,7 @@
#ifndef LCLOCK_CONF_H
#define LCLOCK_CONF_H
/* задает, какой именно EPIT таймер будет использован (HW_EPIT1 или HW_EPIT2) */
#define LCLOCK_CONF_EPIT_INST HW_EPIT2
#endif // LCLOCK_CONF_H

View File

@ -0,0 +1,79 @@
/***************************************************************************//**
@ingroup ltimer_imx6_epit
@file ports/imx6_epit/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
для процессора imx6, использующую один из EPIT-таймеров.
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include <stdint.h>
#include "lclock.h"
#include "core/ccm_pll.h"
#include "registers/regsepit.h"
//! @brief Available clock sources for the timers.
enum _timer_clock_sources {
CLKSRC_OFF = 0, //!< clock source is OFF
CLKSRC_IPG_CLK = 1, //!< clock source is peripheral clock
CLKSRC_PER_CLK = 2, //!< clock source is high-freq reference clock
CLKSRC_CLKIN = 3, //!< clock source is external from a CLKIN input
CLKSRC_CKIL = 3 //!< clock source is low-freq reference clock
};
static char f_initialized = 0;
/*************************************************************************
* инициализация системного таймера
* использует для этого RIT
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
uint32_t freq = get_main_clock(IPG_CLK);
uint32_t control_reg_tmp = 0;
uint32_t base = REGS_EPIT_BASE(LCLOCK_CONF_EPIT_INST);
uint32_t prescaler = freq / LCLOCK_TICKS_PER_SECOND;
// enable the source clocks to the EPIT port
clock_gating_config(base, CLOCK_ON);
// start with a known state by disabling and reseting the module
HW_EPIT_CR_WR(LCLOCK_CONF_EPIT_INST, BM_EPIT_CR_SWR);
// wait for the reset to complete
while ((HW_EPIT_CR(LCLOCK_CONF_EPIT_INST).B.SWR) != 0) ;
// set the reference source clock for the counter
control_reg_tmp |= BF_EPIT_CR_CLKSRC(CLKSRC_IPG_CLK);
// set the counter clock prescaler value - 0 to 4095
control_reg_tmp |= BF_EPIT_CR_PRESCALAR(prescaler-1);
// set behavior for low power mode
control_reg_tmp |= BM_EPIT_CR_WAITEN;
control_reg_tmp |= BM_EPIT_CR_STOPEN;
// make the counter start from a known value when enabled, this is loaded from
// EPITLR register if RLD=reload_mode=1 or 0xFFFFFFFF if RLD=reload_mode=0
control_reg_tmp |= BM_EPIT_CR_IOVW | BM_EPIT_CR_ENMOD;
// finally write the control register
HW_EPIT_CR_WR(LCLOCK_CONF_EPIT_INST, control_reg_tmp);
// finally, enable the counter
HW_EPIT_CR_SET(LCLOCK_CONF_EPIT_INST, BM_EPIT_CR_EN);
f_initialized = 1;
}
char lclock_is_initialized(void) {
return f_initialized;
}
t_lclock_ticks lclock_get_ticks(void) {
t_lclock_ticks val = -HW_EPIT_CNR_RD(LCLOCK_CONF_EPIT_INST);
return val;
}

View File

@ -0,0 +1,29 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_imx6_epit Порт таймера для процессора iMX6
Порт для работы с таймером для процессоров iMX6 от Freescale на базе таймера EPIT.
Для данного порта необходим файл в проекте lclock_conf.h, который бы задавал номер
используемого EPIT-таймера
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_imx6_epit
@file ports/imx6_epit/lclock_arch.h
Файл содержит определение типов и констант для работы с системным таймером
для процессоров iMX6 от Freescale на базе таймера EPIT.
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#include "lclock_conf.h"
#ifndef LCLOCK_TICKS_PER_SECOND
#define LCLOCK_TICKS_PER_SECOND 1000000
#endif
typedef unsigned int t_lclock_ticks;
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,34 @@
#include "lclock_arch.h"
static char f_initialized = 0;
char lclock_is_initialized(void) {
return f_initialized;
}
void lclock_init_val(t_lclock_ticks init_val) {
chip_per_clk_en(CHIP_PER_CLK_NUM_SYSCTR);
CHIP_REGS_SYSCTR_CTRL->CNTCR = 0;
CHIP_REGS_SYSCTR_CTRL->CNTCV0 = init_val & 0xFFFFFFFFUL;
CHIP_REGS_SYSCTR_CTRL->CNTCV1 = (init_val >> 32) & 0xFFFFFFFFUL;
CHIP_REGS_SYSCTR_CTRL->CNTCR = CHIP_REGFLD_SYSCTR_CNTCR_EN | CHIP_REGFLD_SYSCTR_CNTCR_FCR(0);
f_initialized = 1;
}
void lclock_disable(void) {
CHIP_REGS_SYSCTR_CTRL->CNTCR = 0;
chip_per_clk_dis(CHIP_PER_CLK_NUM_SYSCTR);
f_initialized = 0;
}
t_lclock_ticks lclock_get_ticks(void) {
chip_isb();
uint32_t h1 = CHIP_REGS_SYSCTR_CTRL->CNTCV1;
uint32_t l = CHIP_REGS_SYSCTR_CTRL->CNTCV0;
uint32_t h2 = CHIP_REGS_SYSCTR_CTRL->CNTCV1;
if ((h2 != h1) && (l > 0x80000000U)) {
h2 = h1;
}
return ((uint64_t)h2 << 32) | l;
}

View File

@ -0,0 +1,12 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include <chip.h>
#include <stdint.h>
typedef uint64_t t_lclock_ticks;
#define LCLOCK_TICKS_PER_SECOND CHIP_CLK_SYSCTR_BASE_FREQ
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,58 @@
/***************************************************************************//**
@ingroup ltimer_linux
@file ports/linux/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком в OC Linux
через clock_gettime() из librt.
@date 16.09.2011
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
#include <time.h>
#include <stddef.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_SYS_TIMERS_H
#include <sys/timers.h>
#endif
#ifdef NO_CLOCKGETTIME
#include <sys/time.h>
#else
#ifdef CLOCK_MONOTONIC
#define LTIMER_CLK_ID CLOCK_MONOTONIC
#else
#define LTIMER_CLK_ID TIMEOFDAY
#endif
#endif
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализация системного таймера не требуется */
}
char lclock_is_initialized(void) {
return 1;
}
t_lclock_ticks lclock_get_ticks(void) {
#ifdef NO_CLOCKGETTIME
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000 + tv.tv_usec/1000;
#else
struct timespec tp;
clock_gettime(LTIMER_CLK_ID, &tp);
return tp.tv_sec*1000 + tp.tv_nsec/1000000;
#endif
}

View File

@ -0,0 +1,30 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_linux Порт таймера для Linux
Порт для работы с таймером в ОС Linux. Для получения системного счетчика
использует функцию clock_gettime() из librt для получения CLOCK_MONOTONIC,
который нельзя устанавливать и дает приемлемую точность (если нет в ОС, то
используется TIMEOFDAY).
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_linux
@file ports/linux/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
в OC Linux через функцию clock_gettime().
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#include <stdint.h>
/* Возвращаем счетчик в миллисекундах, хотя clock_gettime() может дать нс,
но реально они не изменяются + с мс сохраняется достаточное время
переполнения для 32-битного счетчика */
#define LCLOCK_TICKS_PER_SECOND 1000
/* для простоты и скорости операций используем 32-битное слово */
typedef uint32_t t_lclock_ticks;
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,70 @@
/***************************************************************************//**
@ingroup ltimer_lpc17xx_rit
@file ports/lpc17xx_rit/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
в LPC17xx с использованием RIT.
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
#include "LPC17xx.h"
#include "iolpc17XX.h"
#include "system_LPC17xx.h"
static volatile t_lclock_ticks lclock_systicks;
static char f_initialized = 0;
/*************************************************************************
* инициализация системного таймера
* использует для этого RIT
* ***********************************************************************/
void lclock_init_val(t_lclock_ticks init_val) {
/* инициализируем счетчик */
lclock_systicks = init_val;
/* подаем питание на RIT */
LPC_SC->PCONP |= LPC_SC_PCONP_PCRIT_Msk;
/* останавливаем счетчик (на случай если был запущен) и иницилизируем его */
LPC_RIT->RICTRL =0;
LPC_RIT->RICOUNTER = 0;
LPC_RIT->RICOMPVAL = SystemCoreClock / (4 * 1000);
LPC_RIT->RIMASK = 0x0;
LPC_RIT->RICTRL = LPC_RIT_RICTRL_RITENCLR_Msk | LPC_RIT_RICTRL_RITEN_Msk
| LPC_RIT_RICTRL_RITENBR_Msk;
/* разрешаем прерывания */
NVIC_EnableIRQ(RIT_IRQn);
f_initialized = 1;
}
char lclock_is_initialized(void) {
return f_initialized;
}
t_lclock_ticks lclock_get_ticks(void) {
return lclock_systicks;
}
void lclock_disable(void) {
NVIC_DisableIRQ(RIT_IRQn);
LPC_RIT->RICTRL = 0;
f_initialized = 0;
}
/* обработка прерывания от RIT - обновление числа тиков */
#include "lcspec_interrupt.h"
void RIT_IRQHandler(void) {
LPC_RIT->RICTRL |= LPC_RIT_RICTRL_RITINT_Msk;
lclock_systicks++;
#ifdef LCLOCK_USE_USER_MS_CB
lclock_user_ms_cb();
#endif
}

View File

@ -0,0 +1,24 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_lpc17xx_rit Порт таймера для LPC17xx
Порт для работы с таймером для микроконтроллеров семейства LPC17xx (Cortex-M3).
Для получения системного счетчика использует RIT (Repetitive Interrupt Timer).
*****************************************************************************/
/***************************************************************************//**
@ingroup timer_lpc17xx_rit
@file ports/lpc17xx_rit/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
в LPC17xx с использованием RIT.
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#define LCLOCK_TICKS_PER_SECOND 1000
typedef unsigned int t_lclock_ticks;
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,22 @@
#include "chip.h"
#include "lclock_arch.h"
void lclock_init_val(t_lclock_ticks init_val) {
uint32_t l = init_val & 0xFFFFFFFF;
uint32_t h = (init_val >> 32) & 0xFFFFFFFF;
if (l < 0xE0000000) {
CHIP_REGS_MCHTMR->MTIME.l = l;
CHIP_REGS_MCHTMR->MTIME.h = h;
} else {
CHIP_REGS_MCHTMR->MTIME.l = 0;
CHIP_REGS_MCHTMR->MTIME.h = h;
CHIP_REGS_MCHTMR->MTIME.l = l;
}
}
t_lclock_ticks lclock_get_ticks(void) {
return CHIP_REGS_MCHTMR->MTIME.val64;
}

View File

@ -0,0 +1,11 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include "chip.h"
typedef uint64_t t_lclock_ticks;
#define LCLOCK_TICKS_PER_SECOND CHIP_CLK_MCHTMR_FREQ
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,18 @@
#include "chip.h"
#include "lclock_arch.h"
void lclock_init_val(t_lclock_ticks init_val) {
CHIP_REGS_STK->CTLR = 0;
CHIP_REGS_STK->CNTH = (init_val >> 32) & 0xFFFFFFFF;
CHIP_REGS_STK->CNTL = init_val & 0xFFFFFFFF;
CHIP_REGS_STK->CTLR |= CHIP_REGFLD_STK_CTLR_STE;
}
t_lclock_ticks lclock_get_ticks(void) {
uint32_t h = CHIP_REGS_STK->CNTH;
uint32_t l = CHIP_REGS_STK->CNTL;
uint32_t h2 = CHIP_REGS_STK->CNTH;
return ((uint64_t)h << 32) | l;
}

View File

@ -0,0 +1,11 @@
#ifndef LCLOCK_ARCH_H
#define LCLOCK_ARCH_H
#include "chip.h"
typedef uint64_t t_lclock_ticks;
#define LCLOCK_TICKS_PER_SECOND (CHIP_CLK_SYSTICK_FREQ/8)
#endif // LCLOCK_ARCH_H

View File

@ -0,0 +1,24 @@
/***************************************************************************//**
@ingroup ltimer_win
@file ports/win/lclock.c
Файл содержит реализацию функций для работы с системным счетчиком
в OC Windows через функцию GetTickCount().
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#include "lclock.h"
void lclock_init_val(t_lclock_ticks init_val) {
}
char lclock_is_initialized(void) {
return 1;
}
t_lclock_ticks lclock_get_ticks(void) {
return GetTickCount();
}

View File

@ -0,0 +1,30 @@
/***************************************************************************//**
@ingroup ltimer
@defgroup ltimer_win Порт таймера для Windows
Порт для работы с таймером в ОС Windows. Для получения системного счетчика
использует функцию WinApi GetTickCount().
*****************************************************************************/
/***************************************************************************//**
@ingroup ltimer_win
@file ports/win/lclock_arch.h
Файл содержит определение типов и констант для работы с системным счетчиком
в OC Windows через функцию GetTickCount().
@date 10.06.2011
@author Borisov Alexey <borisov@lcard.ru>
******************************************************************************/
#ifndef LCLOCK_ARCH_H_
#define LCLOCK_ARCH_H_
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include "Windows.h"
/* GetTickCount() возвращает счетчик в миллисекундах */
#define LCLOCK_TICKS_PER_SECOND 1000
/* GetTickCount() возвращает в качестве значения DWORD */
typedef DWORD t_lclock_ticks;
#endif /* LCLOCK_ARCH_H_ */

View File

@ -0,0 +1,25 @@
#ifndef OS_SPEC_CFG_H_
#define OS_SPEC_CFG_H_
//#define OSSPEC_USE_MUTEX
//#define OSSPEC_USE_EVENTS
//#define OSSPEC_USE_THREADS
#define OSSPEC_ERR_MUTEX_INVALID_HANDLE -1
#define OSSPEC_ERR_MUTEX_LOCK_TOUT -2
#define OSSPEC_ERR_MUTEX_RELEASE -3
#define OSSPEC_ERR_EVENT_INVALID_HANDLE OSSPEC_ERR_MUTEX_INVALID_HANDLE
#define OSSPEC_ERR_EVENT_WAIT_TOUT OSSPEC_ERR_MUTEX_LOCK_TOUT
#define OSSPEC_ERR_THREAD_INVALID_HANDLE OSSPEC_ERR_MUTEX_INVALID_HANDLE
#define OSSPEC_ERR_THREAD_WAIT_TOUT OSSPEC_ERR_MUTEX_LOCK_TOUT
#endif

View File

@ -0,0 +1,309 @@
/***************************************************************************//**
@file osspec.c
Файл содержит некоторые внутренние функции, которые скрывают вызовы ОС:
функции работы с объектами синхронизации, потоками и т.д.
@author Borisov Alexey <borisov@lcard.ru>
@date 28.05.2012
***************************************************************************/
#include "osspec.h"
#include <stdlib.h>
#ifndef _WIN32
#include <sys/time.h>
#include <errno.h>
static void f_get_abs_time(uint32_t timeout, struct timespec *timeToWait) {
#ifdef NO_CLOCKGETTIME
struct timeval tv;
gettimeofday(&tv, NULL);
timeToWait->tv_sec = tv.tv_sec;
timeToWait->tv_nsec = tv.tv_usec * 1000;
#else
clock_gettime(CLOCK_REALTIME, timeToWait);
#endif
timeToWait->tv_sec += timeout/1000;
timeToWait->tv_nsec += 1000000*(timeout%1000) + 1;
while (timeToWait->tv_nsec >= 1000000000) {
timeToWait->tv_sec++;
timeToWait->tv_nsec -=1000000000;
}
}
#endif
#ifdef OSSPEC_USE_MUTEX
/***************************************************************************
Вспомогательная функции для работы с мьютексами....
**************************************************************************/
//создание мьютекса
t_mutex osspec_mutex_create(void) {
t_mutex hnd;
#ifdef _WIN32
hnd = CreateMutex(NULL, FALSE, NULL);
#else
hnd = (t_mutex)malloc(sizeof(pthread_mutex_t));
if (hnd!=NULL) {
int err = pthread_mutex_init(hnd, NULL);
if (err) {
free(hnd);
hnd = OSSPEC_INVALID_MUTEX;
}
} else {
hnd = OSSPEC_INVALID_MUTEX;
}
#endif
return hnd;
}
//захват мьютекса
int32_t osspec_mutex_lock(t_mutex handle, uint32_t timeout) {
int32_t err = 0;
if (handle == OSSPEC_INVALID_MUTEX)
err = OSSPEC_ERR_MUTEX_INVALID_HANDLE;
#ifdef _WIN32
if (!err) {
err = WaitForSingleObject(handle, timeout)==WAIT_OBJECT_0 ? 0 : OSSPEC_ERR_MUTEX_LOCK_TOUT;
}
#else
if (!err) {
int wt_res;
#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK
if (timeout == OSSPEC_TIMEOUT_INFINITY) {
wt_res = pthread_mutex_lock(handle);
} else {
struct timespec timeToWait;
f_get_abs_time(timeout, &timeToWait);
wt_res = pthread_mutex_timedlock(handle, &timeToWait);
}
#else // HAVE_PTHREAD_MUTEX_TIMEDLOCK
(void)timeout;
wt_res = pthread_mutex_lock(handle);
#endif // HAVE_PTHREAD_MUTEX_TIMEDLOCK
if (wt_res == ETIMEDOUT) {
err = OSSPEC_ERR_MUTEX_LOCK_TOUT;
} else if (wt_res != 0) {
err = OSSPEC_ERR_MUTEX_INVALID_HANDLE;
}
}
#endif
return err;
}
//освобождение мьютекса
int32_t osspec_mutex_release(t_mutex handle) {
int32_t res = 0;
if (handle == OSSPEC_INVALID_MUTEX)
res = OSSPEC_ERR_MUTEX_INVALID_HANDLE;
#ifdef _WIN32
if (!res)
res = ReleaseMutex(handle) ? 0 : OSSPEC_ERR_MUTEX_RELEASE;
#else
if (!res && pthread_mutex_unlock(handle))
res = OSSPEC_ERR_MUTEX_RELEASE;
#endif
return res;
}
int32_t osspec_mutex_destroy(t_mutex handle) {
int32_t res = (handle != OSSPEC_INVALID_MUTEX) ?
0 : OSSPEC_ERR_MUTEX_INVALID_HANDLE;
#ifdef _WIN32
if (!res)
CloseHandle(handle);
#else
if (!res) {
pthread_mutex_destroy(handle);
free(handle);
}
#endif
return res;
}
#endif
#ifdef OSSPEC_USE_EVENTS
#ifdef _WIN32
#else
struct st_osspec_event {
pthread_cond_t cond;
pthread_mutex_t mutex;
int flags;
int val;
};
#endif
t_event osspec_event_create(int32_t flags) {
t_event evt;
#ifdef _WIN32
evt = CreateEvent(NULL, TRUE, FALSE, NULL);
#else
evt = malloc(sizeof(struct st_osspec_event));
if (evt!=NULL) {
if (pthread_mutex_init(&evt->mutex, NULL) != 0) {
free(evt);
evt = NULL;
} else {
if (pthread_cond_init(&evt->cond, NULL)!= 0) {
pthread_mutex_destroy(&evt->mutex);
free(evt);
evt = NULL;
} else {
evt->flags = flags;
evt->val = 0;
}
}
}
#endif
return evt;
}
int32_t osspec_event_destroy(t_event event) {
int32_t res = (event != OSSPEC_INVALID_EVENT) ?
0 : OSSPEC_ERR_EVENT_INVALID_HANDLE;
#ifdef _WIN32
if (!res)
CloseHandle(event);
#else
if (!res) {
pthread_mutex_destroy(&event->mutex);
pthread_cond_destroy(&event->cond);
free(event);
}
#endif
return res;
}
int32_t osspec_event_set(t_event event) {
int32_t res = (event != OSSPEC_INVALID_EVENT) ?
0 : OSSPEC_ERR_EVENT_INVALID_HANDLE;
if (res == 0) {
#ifdef _WIN32
if (!SetEvent(event))
res = OSSPEC_ERR_EVENT_INVALID_HANDLE;
#else
pthread_mutex_lock(&event->mutex);
if (!event->val) {
event->val = 1;
pthread_cond_signal(&event->cond);
}
pthread_mutex_unlock(&event->mutex);
#endif
}
return res;
}
int32_t osspec_event_clear(t_event event) {
int32_t res = (event != OSSPEC_INVALID_EVENT) ?
0 : OSSPEC_ERR_EVENT_INVALID_HANDLE;
if (res == 0) {
#ifdef _WIN32
if (!ResetEvent(event))
res = OSSPEC_ERR_EVENT_INVALID_HANDLE;
#else
pthread_mutex_lock(&event->mutex);
event->val = 0;
pthread_mutex_unlock(&event->mutex);
#endif
}
return res;
}
int32_t osspec_event_wait(t_event event, uint32_t timeout) {
int32_t err = (event != OSSPEC_INVALID_EVENT) ?
0 : OSSPEC_ERR_EVENT_INVALID_HANDLE;
if (err == 0) {
#ifdef _WIN32
err = WaitForSingleObject(event, timeout)==WAIT_OBJECT_0 ? 0 : OSSPEC_ERR_EVENT_WAIT_TOUT;
#else
struct timespec timeToWait;
int out = 0;
if (timeout != OSSPEC_TIMEOUT_INFINITY)
f_get_abs_time(timeout, &timeToWait);
while (!out && !err) {
pthread_mutex_lock(&event->mutex);
if (!event->val) {
int wait_res = timeout == OSSPEC_TIMEOUT_INFINITY ?
pthread_cond_wait(&event->cond,&event->mutex) :
pthread_cond_timedwait(&event->cond,&event->mutex, &timeToWait);
if (event->val) {
out = 1;
} else if (wait_res == ETIMEDOUT) {
err = OSSPEC_ERR_EVENT_WAIT_TOUT;
} else if (wait_res == EINVAL) {
err = OSSPEC_ERR_EVENT_INVALID_HANDLE;
}
} else {
out = 1;
}
pthread_mutex_unlock(&event->mutex);
}
#endif
}
return err;
}
#endif
#ifdef OSSPEC_USE_THREADS
t_thread osspec_thread_create(t_osspec_thread_func func, void *arg, uint32_t flags) {
t_thread thread;
#ifdef _WIN32
thread = CreateThread(NULL, 0, func, arg, 0, NULL);
#else
if (pthread_create(&thread, NULL, func, arg) != 0) {
thread = OSSPEC_INVALID_THREAD;
}
#endif
return thread;
}
int32_t osspec_thread_wait(t_thread thread, uint32_t timeout) {
int32_t err = (thread != OSSPEC_INVALID_THREAD) ?
0 : OSSPEC_ERR_THREAD_INVALID_HANDLE;
if (!err) {
#ifdef _WIN32
err = WaitForSingleObject(thread, timeout)==WAIT_OBJECT_0 ? 0 : OSSPEC_ERR_THREAD_WAIT_TOUT;
#else
int wt_res;
#ifndef OSSPEC_THREAD_NO_TIMEOUT
if (timeout != OSSPEC_TIMEOUT_INFINITY) {
struct timespec timeToWait;
f_get_abs_time(timeout, &timeToWait);
wt_res = pthread_timedjoin_np(thread, NULL, &timeToWait);
} else {
#endif
wt_res = pthread_join(thread, NULL);
#ifndef OSSPEC_THREAD_NO_TIMEOUT
}
#endif
if (wt_res == ETIMEDOUT) {
err = OSSPEC_ERR_THREAD_WAIT_TOUT;
} else if (wt_res != 0) {
err = OSSPEC_ERR_THREAD_INVALID_HANDLE;
}
#endif
}
return err;
}
#endif

View File

@ -0,0 +1,59 @@
# Файл для включения в проект на CMAKE.
# Перед включением необходимо определить переменные
# OSSPEC_DIR - путь к директории, где находится osspec.cmake
# OSSPEC_USE_EVENTS - использовать события
# OSSPEC_USE_THREADS - использовать потоки
# OSSPEC_USE_MUTEX - использовать мьютексы
# После включения будут установлены следующие перменные:
# OSSPEC_HEADERS - используемые заголовочные файлы
# OSSPEC_SOURCES - используемые файлы исходных кодов
# OSSPEC_DEFINITIONS - используемые определения компилятора
cmake_policy(PUSH)
cmake_minimum_required(VERSION 2.8.12)
if(OSSPEC_USE_EVENTS OR OSSPEC_USE_THREADS OR OSSPEC_USE_MUTEX)
find_package(Threads)
# set(OSSPEC_LIBS ${CMAKE_THREAD_LIBS_INIT})
unset(OSSPEC_LIBS)
unset(OSSPEC_DEFINITIONS)
set(OSSPEC_HEADERS ${OSSPEC_DIR}/osspec.h)
set(OSSPEC_SOURCES ${OSSPEC_DIR}/osspec.c)
if(CMAKE_USE_PTHREADS_INIT)
include(CheckLibraryExists)
if(OSSPEC_USE_MUTEX)
set(OSSPEC_DEFINITIONS ${OSSPEC_DEFINITIONS} OSSPEC_USE_MUTEX)
check_library_exists(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK)
if(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
set(OSSPEC_DEFINITIONS ${OSSPEC_DEFINITIONS} HAVE_PTHREAD_MUTEX_TIMEDLOCK)
#заглушки для _timedlock функций отстутсвуют в libc, поэтому в любом случае включаем pthread
set(OSSPEC_LIBS ${OSSPEC_LIBS} ${CMAKE_THREAD_LIBS_INIT})
endif(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
endif(OSSPEC_USE_MUTEX)
if(OSSPEC_USE_THREADS)
set(OSSPEC_DEFINITIONS ${OSSPEC_DEFINITIONS} OSSPEC_USE_THREADS)
if (NOT OSSPEC_LIBS)
set(OSSPEC_LIBS ${CMAKE_THREAD_LIBS_INIT})
endif (NOT OSSPEC_LIBS)
check_library_exists(pthread pthread_timedjoin_np "" HAVE_PTHREAD_TIMEDJOIN_NP)
if(HAVE_PTHREAD_TIMEDJOIN_NP)
set(OSSPEC_DEFINITIONS ${OSSPEC_DEFINITIONS} HAVE_PTHREAD_TIMEDJOIN_NP)
endif(HAVE_PTHREAD_TIMEDJOIN_NP)
endif(OSSPEC_USE_THREADS)
else(CMAKE_USE_PTHREADS_INIT)
if(OSSPEC_USE_MUTEX)
set(OSSPEC_DEFINITIONS ${OSSPEC_DEFINITIONS} OSSPEC_USE_MUTEX)
endif(OSSPEC_USE_MUTEX)
if(OSSPEC_USE_THREADS)
set(OSSPEC_DEFINITIONS ${OSSPEC_DEFINITIONS} OSSPEC_USE_THREADS)
endif(OSSPEC_USE_THREADS)
endif(CMAKE_USE_PTHREADS_INIT)
if(OSSPEC_USE_EVENTS)
set(OSSPEC_DEFINITIONS ${OSSPEC_DEFINITIONS} OSSPEC_USE_EVENTS)
endif(OSSPEC_USE_EVENTS)
endif(OSSPEC_USE_EVENTS OR OSSPEC_USE_THREADS OR OSSPEC_USE_MUTEX)
cmake_policy(POP)

View File

@ -0,0 +1,93 @@
/***************************************************************************//**
@file osspec.h
Файл содержит объявления функций, которые скрывают вызовы ОС:
функции работы с объектами синхронизации, потоками и т.д.
@author Borisov Alexey <borisov@lcard.ru>
@date 28.05.2012
***************************************************************************/
#ifndef OSSPEC_H_
#define OSSPEC_H_
#ifdef __cplusplus
extern "C" {
#endif
#if !defined _WIN32 && !defined _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "osspec_cfg.h"
#ifdef _WIN32
#include <Windows.h>
#define OSSPEC_TIMEOUT_INFINITY INFINITE
#else
#include <pthread.h>
#define OSSPEC_TIMEOUT_INFINITY ((uint32_t)-1)
#endif
#ifndef NO_OSSPEC_USE_MUTEX
#ifdef _WIN32
typedef HANDLE t_mutex;
#else
typedef pthread_mutex_t* t_mutex;
#endif
#define OSSPEC_INVALID_MUTEX NULL
t_mutex osspec_mutex_create(void);
int32_t osspec_mutex_lock(t_mutex handle, uint32_t tout);
int32_t osspec_mutex_release(t_mutex handle);
int32_t osspec_mutex_destroy(t_mutex handle);
#endif
#ifndef NO_OSSPEC_USE_EVENTS
#ifdef _WIN32
typedef HANDLE t_event;
#else
struct st_osspec_event;
typedef struct st_osspec_event *t_event;
#endif
#define OSSPEC_INVALID_EVENT NULL
t_event osspec_event_create(int32_t flags);
int32_t osspec_event_destroy(t_event event);
int32_t osspec_event_set(t_event event);
int32_t osspec_event_clear(t_event event);
int32_t osspec_event_wait(t_event event, uint32_t timeout);
#endif
#ifndef NO_OSSPEC_USE_THREADS
#ifdef _WIN32
typedef HANDLE t_thread;
#define OSSPEC_INVALID_THREAD NULL
#define OSSPEC_THREAD_FUNC_RET DWORD
#define OSSPEC_THREAD_FUNC_CALL WINAPI
#else
typedef pthread_t t_thread;
#define OSSPEC_INVALID_THREAD ((pthread_t)-1)
#define OSSPEC_THREAD_FUNC_RET void*
#define OSSPEC_THREAD_FUNC_CALL
#endif
typedef OSSPEC_THREAD_FUNC_RET (OSSPEC_THREAD_FUNC_CALL *t_osspec_thread_func)(void *arg);
t_thread osspec_thread_create(t_osspec_thread_func func, void *arg, uint32_t flags);
int32_t osspec_thread_wait(t_thread thread, uint32_t timeout);
#endif
#ifdef __cplusplus
}
#endif
#endif