河北水利局项目
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
Debug/
|
||||
settings/
|
||||
Source Insight/
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"workspace": {
|
||||
"path": "${workspaceFolder}\\HunanProcotol.eww"
|
||||
},
|
||||
"workbench": {
|
||||
"path": "C:\\Program Files\\IAR Systems\\Embedded Workbench 9.1"
|
||||
},
|
||||
"workspaces": {
|
||||
"${workspaceFolder}\\HunanProcotol.eww": {
|
||||
"configs": {
|
||||
"${workspaceFolder}\\Backup of Backup of RTOSDemo.ewp": "Debug"
|
||||
},
|
||||
"selected": {
|
||||
"path": "${workspaceFolder}\\Backup of Backup of RTOSDemo.ewp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
#ifndef _BASEDEFINE_H_
|
||||
#define _BASEDEFINE_H_
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Basedefine.h
|
||||
* 文件说明:基础库头文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
|
||||
/***************标准库函数************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
/************stm32固件库头文件******/
|
||||
#include "stm32f10x.h"
|
||||
|
||||
#define true TRUE
|
||||
#define false FALSE
|
||||
|
||||
//真假值
|
||||
typedef enum
|
||||
{
|
||||
FALSE = 0, //假
|
||||
TRUE = !FALSE //真
|
||||
}bool;
|
||||
|
||||
|
||||
|
||||
|
||||
//模式
|
||||
typedef enum
|
||||
{
|
||||
MODE_BPSK = 4, //BPSK模式
|
||||
MODE_QPSK = 5, //QPSK模式
|
||||
MODE_ENHANCE = 7, //ENHANCE模式
|
||||
MODE_ROBUST = 8 //鲁棒模式
|
||||
}eMode;
|
||||
|
||||
//设备类型
|
||||
typedef enum
|
||||
{
|
||||
TYPE_MASTER, //主节点
|
||||
TYPE_METER_SINGLE, //单相载波表节点
|
||||
TYPE_METER_THREE, //三相载波表节点
|
||||
TYPE_COLLECT_I, //I型采集器节点
|
||||
TYPE_COLLECT_II, //II型采集器节点
|
||||
TYPE_RELAY, //中继节点
|
||||
TYPE_METER_485, //485表非载波节点
|
||||
TYPE_UNKNOWN //未知设备类型
|
||||
}eType;
|
||||
|
||||
//路由状态
|
||||
typedef enum
|
||||
{
|
||||
ROUTE_PTOP, //点对点
|
||||
ROUTE_SOURCE, //源路由
|
||||
ROUTE_BLIND, //盲中继
|
||||
ROUTE_UNKNOWN //未知路由
|
||||
}eRouteStatus;
|
||||
|
||||
//路由方式
|
||||
typedef enum
|
||||
{
|
||||
MODE_PTOP, //点对点
|
||||
MODE_SOURCE, //源路由
|
||||
MODE_BLIND //盲中继
|
||||
}eRouteMode;
|
||||
|
||||
//网络标识
|
||||
typedef enum
|
||||
{
|
||||
NET_SELF, //本网
|
||||
NET_ALL //全网
|
||||
}eNet;
|
||||
|
||||
//抄读标志
|
||||
typedef enum
|
||||
{
|
||||
READ_PREPARE, //待抄读
|
||||
READ_SUCCESS_PART, //部分抄读成功
|
||||
READ_SUCCESS_ALL, //全部抄读成功
|
||||
READ_FAIL //全部抄读失败
|
||||
}eReadFlag;
|
||||
|
||||
//地址模式
|
||||
typedef enum
|
||||
{
|
||||
ADDRTYPE_LONG, //长地址模式
|
||||
ADDRTYPE_SHORT //短地址模式
|
||||
}eAddrType;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GPIO_TypeDef* GPIO_port;
|
||||
uint32_t GPIO_clk;
|
||||
uint16_t GPIO_Pin;
|
||||
GPIOMode_TypeDef GPIO_mode;
|
||||
|
||||
}st_gpio_config;
|
||||
|
||||
|
||||
|
||||
|
||||
//喂狗
|
||||
#define FEED_WDG do{IWDG_ReloadCounter();}while(0)
|
||||
#define USE_LORA_MODE
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+1913
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,57 @@
|
||||
/*—————————————————————----------
|
||||
* 文 件 名:Cmd.h
|
||||
* 作 者:邹亮
|
||||
* 日 期:2013-12-30
|
||||
* 文件说明:控制台头文件
|
||||
*——————————————————————————*/
|
||||
#ifndef _CMD_H
|
||||
#define _CMD_H
|
||||
|
||||
#include "Basedefine.h"
|
||||
#include "uart.h"
|
||||
|
||||
|
||||
typedef const struct
|
||||
{
|
||||
const u8 *cmd;
|
||||
void (*action)(void);
|
||||
const u8 *info;
|
||||
} sCmd;
|
||||
|
||||
|
||||
extern void add_in_flash(void);
|
||||
extern void add_list_node(void);
|
||||
extern char change_parity(u16 parity);
|
||||
extern float change_stop_bits(u16 uart_stopbit);
|
||||
extern u16 change_string_to_arry16(char * input);
|
||||
extern u8 CharToU8(u8 data);
|
||||
extern void Cmd_Exe(void);
|
||||
extern void Cmd_Proc(void);
|
||||
extern void delete_space_key(u8 *buf);
|
||||
extern u8 find_cmd_length(u8 * buf);
|
||||
extern u16 find_string16_len(char * str);
|
||||
extern u8 GetStrPara(u8* buffer, u8 index);
|
||||
extern void GetTime(void);
|
||||
extern void GetU16Para(u16 *para,u8 index);
|
||||
extern void GetU8Para(u8 *para,u8 index);
|
||||
extern void ListCmd(void);
|
||||
extern void lora_cmd_tx(void );
|
||||
extern void mbus_direct_tx(void);
|
||||
extern void printf_uart_port(st_uart_int port_init);
|
||||
extern void read_curent_protocl(void);
|
||||
extern void read_local_addr(void);
|
||||
extern void read_maintain(void);
|
||||
extern void read_mbus_power(void);
|
||||
extern void release_debug(void);
|
||||
extern void SetTime(void);
|
||||
extern void set_gMeterConfig(void);
|
||||
extern void set_local_addr(void);
|
||||
extern void set_mbus_port(void);
|
||||
extern void set_mbus_power(void);
|
||||
extern void simul_plc_rx(void);
|
||||
extern void simul_read_meter(void);
|
||||
extern void write_maintain(void);
|
||||
extern void scan_ports(void);
|
||||
|
||||
#endif
|
||||
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Flash.c
|
||||
* 作 者:于涛
|
||||
* 日 期:2014-01-15
|
||||
* 文件说明:内部FLASH源文件
|
||||
*——————————————————————————*/
|
||||
#include "Flash.h"
|
||||
#include "General.h"
|
||||
#include "Mem.h"
|
||||
|
||||
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:STM32_FlashPageErase
|
||||
* 输入参数:pageAddr 页地址
|
||||
* 输出参数:None
|
||||
* 返 回 值:0 成功
|
||||
1 失败
|
||||
* 功能说明:内部FLASH页擦除
|
||||
*——————————————————————————*/
|
||||
u8 STM32_FlashPageErase(u32 pageAddr)
|
||||
{
|
||||
FLASH_Status status = FLASH_COMPLETE;
|
||||
|
||||
FEED_WDG;
|
||||
|
||||
FLASH_Unlock();
|
||||
/* Clear All pending flags */
|
||||
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
|
||||
//FLHDBG(printf("STM32_FlashPageErase pageAddr = %08x\r\n",pageAddr););
|
||||
status = FLASH_ErasePage(pageAddr);
|
||||
|
||||
if(status != FLASH_COMPLETE)
|
||||
{
|
||||
printf("STM32_FlashPageErase Err pageAddr = %08x status = %d\r\n",pageAddr,status);
|
||||
return FLH_ERASE_ERR;
|
||||
}
|
||||
|
||||
FLASH_Lock();
|
||||
|
||||
return FLH_SUCCESS;
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:STM32_FlashWrite
|
||||
* 输入参数:programAddr 写地址
|
||||
pBuffer 写缓冲区
|
||||
size 写缓冲区大小
|
||||
* 输出参数:None
|
||||
* 返 回 值:0 成功
|
||||
>0 失败
|
||||
* 功能说明:内部FLASH写操作
|
||||
*——————————————————————————*/
|
||||
u8 STM32_FlashWrite(u32 programAddr, u8* pBuffer, u16 size)
|
||||
{
|
||||
u8 sflag;
|
||||
u16 offset = 0,len = size;
|
||||
FLASH_Status status = FLASH_COMPLETE;
|
||||
|
||||
FLASH_Unlock();
|
||||
/* Clear All pending flags */
|
||||
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
|
||||
sflag = len%2;
|
||||
if(sflag)
|
||||
{
|
||||
len --;
|
||||
}
|
||||
|
||||
for(offset = 0; offset < len; offset += 2)
|
||||
{
|
||||
status = FLASH_ProgramHalfWord(programAddr + offset, ((u16)(pBuffer[offset + 1]) << 8) | (pBuffer[offset]));
|
||||
if(status != FLASH_COMPLETE)
|
||||
{
|
||||
printf("STM32_FlashWrite Err programAddr = %08x size = %d offset = %d status = %d\r\n",programAddr,size,offset,status);
|
||||
return FLH_WRITE_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(sflag && size>=1)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
val = pBuffer[size - 1]|0xFF00;
|
||||
status = FLASH_ProgramHalfWord(programAddr + offset, val);
|
||||
if(status != FLASH_COMPLETE)
|
||||
{
|
||||
printf("STM32_FlashWrite Err programAddr = %08x size = %d offset = %d status = %d\r\n",programAddr,size,offset,status);
|
||||
return FLH_WRITE_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
FLASH_Lock();
|
||||
|
||||
return FLH_SUCCESS;
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:STM32_FlashWriteZero
|
||||
* 输入参数:None
|
||||
* 输出参数:None
|
||||
* 返 回 值:见错误代码表
|
||||
* 功能说明:对某一地址写0
|
||||
*——————————————————————————*/
|
||||
u8 STM32_FlashWriteZero(u32 programAddr, u16 size)
|
||||
{
|
||||
u16 offset = 0;
|
||||
FLASH_Status status = FLASH_COMPLETE;
|
||||
|
||||
FLASH_Unlock();
|
||||
/* Clear All pending flags */
|
||||
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
|
||||
|
||||
if (size%2==1)
|
||||
{
|
||||
size +=1;
|
||||
}
|
||||
|
||||
for(offset = 0; offset < size; offset += 2)
|
||||
{
|
||||
status = FLASH_ProgramHalfWord(programAddr + offset, 0);
|
||||
if(status != FLASH_COMPLETE)
|
||||
{
|
||||
//FLHDBG(printf("STM32FLASH: Write zero error."););
|
||||
return FLH_WRITE_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
FLASH_Lock();
|
||||
|
||||
return FLH_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : read_unique_id
|
||||
* Description : none
|
||||
* Input : u8 * id
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
bool read_unique_id(u8 * id)
|
||||
{
|
||||
for (u8 i = 0; i < 12; i++)
|
||||
{
|
||||
id[i] = *((u8*)(FLASH_ID_IDDR + i));
|
||||
}
|
||||
|
||||
for (u8 i = 0; i < 12; i++)
|
||||
{
|
||||
if (id[i] != 0xFF)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Flash.h
|
||||
* 作 者:于涛
|
||||
* 日 期:2014-01-15
|
||||
* 文件说明:内部FLASH头文件
|
||||
*——————————————————————————*/
|
||||
#ifndef _FLASH_H
|
||||
#define _FLASH_H
|
||||
|
||||
#include "Basedefine.h"
|
||||
//#include "Sys.h"
|
||||
|
||||
|
||||
|
||||
#ifdef STM32F10X_HD
|
||||
#define PAGE_SIZE (0x800)
|
||||
#else
|
||||
#define PAGE_SIZE (0x400)
|
||||
#endif
|
||||
|
||||
#define FLASH_ID_IDDR 0x1FFFF7E8
|
||||
#define FLASH_KEY_ADDRESS 0x08003800
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FLH_SUCCESS = 0, //返回成功
|
||||
FLH_ERASE_ERR,
|
||||
FLH_WRITE_ERR,
|
||||
FLH_WADDR_ERR,
|
||||
FLH_RADDR_ERR,
|
||||
FLH_NOSPACE_ERR,
|
||||
FLH_NOVAILD_ERR,
|
||||
FLH_NOFIELD_ERR,
|
||||
}eFlashRet;
|
||||
|
||||
|
||||
u8 STM32_FlashPageErase(u32 pageAddr);
|
||||
u8 STM32_FlashWrite(u32 programAddr, u8* pBuffer, u16 size);
|
||||
u8 STM32_FlashWriteZero(u32 programAddr, u16 size);
|
||||
bool read_unique_id(u8 * id);
|
||||
|
||||
|
||||
#endif
|
||||
+309
@@ -0,0 +1,309 @@
|
||||
/*——————————————————————————
|
||||
* 文 件 名:General.c
|
||||
* 文件说明: 普通函数源文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
|
||||
#include "General.h"
|
||||
|
||||
const u16 CRC16_Table[256] =
|
||||
{
|
||||
0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A,
|
||||
0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C,
|
||||
0x75B7, 0x643E, 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, 0x2102,
|
||||
0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1,
|
||||
0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5,
|
||||
0x453C, 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, 0x4204, 0x538D,
|
||||
0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868,
|
||||
0x99E1, 0xAB7A, 0xBAF3, 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
|
||||
0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, 0x6306, 0x728F, 0x4014,
|
||||
0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3,
|
||||
0x8A78, 0x9BF1, 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 0xFFCF,
|
||||
0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A, 0xB693,
|
||||
0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76,
|
||||
0x7CFF, 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, 0x18C1, 0x0948,
|
||||
0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E,
|
||||
0xF2A7, 0xC03C, 0xD1B5, 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
|
||||
0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3, 0x284A, 0x1AD1,
|
||||
0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1,
|
||||
0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, 0xD68D,
|
||||
0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, 0x5AC5, 0x4B4C, 0x79D7, 0x685E,
|
||||
0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238,
|
||||
0x93B1, 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, 0xF78F, 0xE606,
|
||||
0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3,
|
||||
0x2C6A, 0x1EF1, 0x0F78,
|
||||
};
|
||||
|
||||
u8 auchCRCHi[]=
|
||||
{
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
|
||||
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
|
||||
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
|
||||
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
|
||||
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
|
||||
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
|
||||
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
|
||||
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
|
||||
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
|
||||
0x40
|
||||
};
|
||||
|
||||
u8 auchCRCLo[] =
|
||||
{
|
||||
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
|
||||
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
|
||||
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
|
||||
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
|
||||
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
|
||||
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
|
||||
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
|
||||
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
|
||||
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
|
||||
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
|
||||
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
|
||||
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
|
||||
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
|
||||
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
|
||||
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
|
||||
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
|
||||
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
|
||||
0x40
|
||||
};
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:GetCRC16
|
||||
* 输入参数:*buff:内存指针 len:数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:检验结果
|
||||
* 功能说明:计算一个数组的CRC结果
|
||||
*——————————————————————————*/
|
||||
u16 GetCRC16(u8 *buff, u16 len)
|
||||
{
|
||||
u16 crc16 = 0xFFFF;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
crc16 = (crc16 >> 8 ) ^ CRC16_Table[(crc16 ^ *buff++) & 0xFF];
|
||||
}
|
||||
crc16 ^= 0xFFFF;
|
||||
|
||||
return crc16;
|
||||
}
|
||||
|
||||
u16 MODBUS_CRC16(u8 *updata, u16 len)
|
||||
{
|
||||
u8 uchCRCHi=0xff;
|
||||
u8 uchCRCLo=0xff;
|
||||
u16 uindex;
|
||||
while(len--)
|
||||
{
|
||||
uindex=uchCRCHi^*updata++;
|
||||
uchCRCHi=uchCRCLo^auchCRCHi[uindex];
|
||||
uchCRCLo=auchCRCLo[uindex];
|
||||
}
|
||||
return ( uchCRCLo<<8| uchCRCHi);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:GetCRC16
|
||||
* 输入参数:*buff:内存指针 len:数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:检验结果
|
||||
* 功能说明:计算一个数组的CRC结果
|
||||
*——————————————————————————*/
|
||||
u16 GetXYDXCRC16(u8 *buff, u16 len,u16 seed)
|
||||
{
|
||||
//u16 crc16 = 0xFFFF;
|
||||
u16 crc16 = seed;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
crc16 = (crc16 >> 8 ) ^ CRC16_Table[(crc16 ^ *buff++) & 0xFF];
|
||||
}
|
||||
|
||||
crc16 ^= 0xFFFF;
|
||||
|
||||
return crc16;
|
||||
}
|
||||
/*************** 函数实现 ***************/
|
||||
/*——————————————————————————
|
||||
* 函 数 GetSum
|
||||
* 输入参数:pMem:内存指针 Len-数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:算术累加值
|
||||
* 功能说明:获取指定长度内存算术累加值
|
||||
*——————————————————————————*/
|
||||
u8 GetSum(u8 * buffer, u16 length)
|
||||
{
|
||||
u8 sum = 0;
|
||||
|
||||
for (u8 i = 0; i < length; i++)
|
||||
{
|
||||
sum += buffer[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
/*****************************************************************************
|
||||
* Function : cmp_datas
|
||||
* Description : none
|
||||
* Input : u8 * buf1
|
||||
u8* buf2
|
||||
u8 length
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
bool cmp_datas(u8 * buf1, u8* buf2, u8 length)
|
||||
{
|
||||
for (u8 i = 0; i < length; i++)
|
||||
{
|
||||
if ( buf1[i] != buf2[i] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:CheckBCDFormat
|
||||
* 输入参数:*pDat:内存指针 dataLen-数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:检查是否是bcd码格式
|
||||
*——————————————————————————*/
|
||||
bool CheckBCDFormat(u8 *pDat, u16 dataLen)
|
||||
{
|
||||
int tmp, flag;
|
||||
|
||||
flag = 0;
|
||||
while(dataLen--)
|
||||
{
|
||||
if (flag == 0)
|
||||
{
|
||||
tmp = *pDat&0x0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = (*pDat>>4)&0x0f;
|
||||
pDat++;
|
||||
}
|
||||
flag = !flag;
|
||||
|
||||
|
||||
if (!( (tmp>=0) && (tmp<= 9) ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:HexToBCD
|
||||
* 输入参数:uValue:需要转换的数据
|
||||
* 输出参数:None
|
||||
* 返 回 值:转换结果
|
||||
* 功能说明:将Hex转换成BCD码
|
||||
*——————————————————————————*/
|
||||
u8 HexToBCD(u8 uValue)
|
||||
{
|
||||
u8 uh, ul;
|
||||
|
||||
if(uValue > 99)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
uh = (uValue / 10);
|
||||
ul = uValue % 10;
|
||||
|
||||
return (uh << 4) + (ul);
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:BCDToHex
|
||||
* 输入参数:uValue:需要转换的数据
|
||||
* 输出参数:None
|
||||
* 返 回 值:转换结果
|
||||
* 功能说明:将BCD转换成Hex码
|
||||
*——————————————————————————*/
|
||||
u8 BCDToHex(u8 uValue)
|
||||
{
|
||||
u8 uh, ul;
|
||||
|
||||
uh = (uValue >> 4);
|
||||
|
||||
if(uh > 9)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
ul = uValue & 0x0F;
|
||||
|
||||
if(ul > 9)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return (uh * 10) + (ul);
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:ShortLToH
|
||||
* 输入参数:uValue:需要转换的数据
|
||||
* 输出参数:None
|
||||
* 返 回 值:转换结果
|
||||
* 功能说明:将16位数高低位调换
|
||||
*——————————————————————————*/
|
||||
u16 ShortLToH(u16 uValue)
|
||||
{
|
||||
u16 uNewValue;
|
||||
|
||||
uNewValue = uValue << 8 | uValue >> 8;
|
||||
|
||||
return uNewValue;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : SysReset
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170313
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void SysReset(void)
|
||||
{
|
||||
__set_FAULTMASK(1);// 关闭所有中断
|
||||
NVIC_SystemReset();// 复位
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
#ifndef _GENERAL_H
|
||||
#define _GENERAL_H
|
||||
/*——————————————————————————
|
||||
* 文 件 名:General.h
|
||||
* 文件说明: 普通函数源文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
#define CRC16_POLY 0x8005
|
||||
#define CRC16_INIT 0xFFFF
|
||||
|
||||
/*************** 函数声明 ***************/
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:GetSum
|
||||
* 输入参数:pMem:内存指针 Len-数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:算术累加值
|
||||
* 功能说明:获取指定长度内存算术累加值
|
||||
*——————————————————————————*/
|
||||
u8 GetSum(u8 * buffer, u16 length);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:CheckBCDFormat
|
||||
* 输入参数:*pDat:内存指针 dataLen-数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:检查是否是bcd码格式
|
||||
*——————————————————————————*/
|
||||
bool CheckBCDFormat(u8 *pDat, u16 dataLen);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:GetCRC16
|
||||
* 输入参数:*buff:内存指针 len:数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:检验结果
|
||||
* 功能说明:计算一个数组的CRC结果
|
||||
*——————————————————————————*/
|
||||
u16 GetCRC16(u8 *buff, u16 len);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:HexToBCD
|
||||
* 输入参数:uValue:需要转换的数据
|
||||
* 输出参数:None
|
||||
* 返 回 值:转换结果
|
||||
* 功能说明:将Hex转换成BCD码
|
||||
*——————————————————————————*/
|
||||
u8 HexToBCD(u8 uValue);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:BCDToHex
|
||||
* 输入参数:uValue:需要转换的数据
|
||||
* 输出参数:None
|
||||
* 返 回 值:转换结果
|
||||
* 功能说明:将BCD转换成Hex码
|
||||
*——————————————————————————*/
|
||||
u8 BCDToHex(u8 uValue);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:ShortLToH
|
||||
* 输入参数:uValue:需要转换的数据
|
||||
* 输出参数:None
|
||||
* 返 回 值:转换结果
|
||||
* 功能说明:将16位数高低位调换
|
||||
*——————————————————————————*/
|
||||
u16 ShortLToH(u16 uValue);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:PrintBuffer
|
||||
* 输入参数:pBuf:内存指针
|
||||
len:数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:内存打印
|
||||
*——————————————————————————*/
|
||||
bool cmp_datas(u8 * buf1, u8* buf2, u8 length);
|
||||
u16 MODBUS_CRC16(u8 *updata, u16 len);
|
||||
void SysReset(void);
|
||||
u16 GetXYDXCRC16(u8 *buff, u16 len,u16 seed);
|
||||
|
||||
#define DATA_COUNT_MAX (24*30)
|
||||
//#define DATA_COUNT_MAX (24*3)
|
||||
|
||||
#define CUR_DATA_LEN (5)
|
||||
#define SUM_DATA_LEN (5)
|
||||
#define SURPLUS_DATA_LEN (6)
|
||||
#define ALA_DATA_LEN (4)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Init.c
|
||||
* 文件说明: 初始化源文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
|
||||
#include "Init.h"
|
||||
|
||||
void RCC_Init(void)
|
||||
{
|
||||
/* Enable Clock Security System(CSS): this will generate an NMI exception
|
||||
when HSE clock fails */
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
NVIC_InitStructure.NVIC_IRQChannel = RCC_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
|
||||
RCC_ClockSecuritySystemCmd(ENABLE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void gpio_init(st_gpio_config ioconfig)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
RCC_APB2PeriphClockCmd(ioconfig.GPIO_clk, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = ioconfig.GPIO_Pin;
|
||||
GPIO_InitStructure.GPIO_Mode = ioconfig.GPIO_mode;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
|
||||
GPIO_Init(ioconfig.GPIO_port, &GPIO_InitStructure);
|
||||
}
|
||||
|
||||
/*—————————————————————————
|
||||
* 函 数 名:NVIC_Init
|
||||
* 输入参数:None
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:中断向量初始化
|
||||
*——————————————————————————*/
|
||||
#define FLASH_APP_ADDRESS 0x08005000
|
||||
void Nvic_Init(void)
|
||||
{
|
||||
// NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
//NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//重定义中断向量表的位置
|
||||
NVIC_SetVectorTable(NVIC_VectTab_FLASH,FLASH_APP_ADDRESS);
|
||||
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
|
||||
|
||||
|
||||
/* Enable and configure RCC global IRQ channel */
|
||||
/*
|
||||
NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
*/
|
||||
|
||||
/* Enable and configure RCC global IRQ channel */
|
||||
|
||||
|
||||
/*
|
||||
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel4_5_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 6;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
*/
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:RCC_IRQHandler
|
||||
* 输入参数:None
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:RCC中断服务函数
|
||||
*——————————————————————————*/
|
||||
void RCC_IRQHandler(void)
|
||||
{
|
||||
if(RCC_GetITStatus(RCC_IT_HSERDY) != RESET)
|
||||
{
|
||||
/* Clear HSERDY interrupt pending bit */
|
||||
RCC_ClearITPendingBit(RCC_IT_HSERDY);
|
||||
|
||||
/* Check if the HSE clock is still available */
|
||||
if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET)
|
||||
{
|
||||
/* Enable PLL: once the PLL is ready the PLLRDY interrupt is generated */
|
||||
RCC_PLLCmd(ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
if(RCC_GetITStatus(RCC_IT_PLLRDY) != RESET)
|
||||
{
|
||||
/* Clear PLLRDY interrupt pending bit */
|
||||
RCC_ClearITPendingBit(RCC_IT_PLLRDY);
|
||||
|
||||
/* Check if the PLL is still locked */
|
||||
if (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != RESET)
|
||||
{
|
||||
/* Select PLL as system clock source */
|
||||
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#ifndef _INIT_H
|
||||
#define _INIT_H
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Init.h
|
||||
* 文件说明: 初始化源文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
/*************函数声明 **************/
|
||||
/*——————————————————————————
|
||||
* 函 数 名:RCC_Init
|
||||
* 输入参数:None
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:RCC时钟初始化
|
||||
*——————————————————————————*/
|
||||
void RCC_Init(void);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:Nvic_Init
|
||||
* 输入参数:None
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:中断向量初始化
|
||||
*——————————————————————————*/
|
||||
void Nvic_Init(void);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:Iwdg_Init
|
||||
* 输入参数:None
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:看门狗程序初始化
|
||||
*——————————————————————————*/
|
||||
void Iwdg_Init(u8 timeout);
|
||||
|
||||
#define GIPO_CFG(name) name##_PIN_CFG
|
||||
void gpio_init(st_gpio_config ioconfig );
|
||||
#endif
|
||||
+724
@@ -0,0 +1,724 @@
|
||||
#include "stm32f10x.h"
|
||||
#include "uart.h"
|
||||
#include "IrDA.h"
|
||||
#include "Mem.h"
|
||||
#include "debug_printf.h"
|
||||
#include "hal_radio.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
IRDA_STATUS_NONE,
|
||||
IRDA_STATUS_TX,
|
||||
IRDA_STATUS_RX,
|
||||
IRDA_STATUS_RECEIVE,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
END = 0,
|
||||
FINISH,
|
||||
WAIT,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 fLen;
|
||||
u8 index;
|
||||
}IRDA_FLAG;
|
||||
|
||||
enum
|
||||
{
|
||||
IRDA_ERR = 0x0000,
|
||||
IRDA_TX_START = 0x0001,
|
||||
IRDA_RX_START = 0x0002,
|
||||
IRDA_TX_FINISH = 0x0004,
|
||||
IRDA_RX_FINISH = 0x0008,
|
||||
IRDA_RX_ERR = 0x0010,
|
||||
IRDA_RX_WAIT = 0x0020,
|
||||
};
|
||||
|
||||
#define IRDA_TX_TIMEOUT 1000
|
||||
#define IRDA_RX_TIMEOUT 1000
|
||||
|
||||
|
||||
static IRDA_FLAG IRDA_TX_flag;
|
||||
u8 IRDA_TX_buf[IRDA_TX_BUFFER_SIZE];
|
||||
|
||||
static IRDA_FLAG IRDA_RX_flag;
|
||||
u8 IRDA_RX_buf[IRDA_RX_BUFFER_SIZE];
|
||||
|
||||
static u8 IRDA_status = IRDA_STATUS_NONE;
|
||||
TaskHandle_t IRDA_task_handle;
|
||||
/*****************************************************************************
|
||||
* Function : IRDA_RX_start
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void IRDA_RX_start(void)
|
||||
{
|
||||
IRDA_GPIO_RX_init();
|
||||
IRDA_RX_flag.fLen = 0;
|
||||
IRDA_RX_flag.index = 0;
|
||||
IRDA_status = IRDA_STATUS_RX;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : IRDA_RX_stop
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void IRDA_RX_stop(void)
|
||||
{
|
||||
TIM_Cmd(IRDA_BAUD_TIMER, DISABLE);
|
||||
hal_sRF_FSK_ITConfig(IRDA_RX_LINE , DISABLE);
|
||||
GPIO_SetBits(IRDA_TX_PORT, IRDA_TX_PIN);
|
||||
IRDA_RX_flag.fLen = 0;
|
||||
IRDA_RX_flag.index = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : IRDA_GPIO_RX_init
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void IRDA_GPIO_RX_init(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
EXTI_InitTypeDef EXTI_InitStructure;
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
RCC_APB2PeriphClockCmd(IRDA_RX_PORT_CLK, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = IRDA_RX_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
|
||||
GPIO_Init( IRDA_RX_PORT, &GPIO_InitStructure );
|
||||
|
||||
EXTI_ClearITPendingBit(IRDA_RX_LINE);
|
||||
|
||||
GPIO_EXTILineConfig(IRDA_RX_PORT_SOURCE, IRDA_RX_PIN_SOURCE);
|
||||
|
||||
EXTI_InitStructure.EXTI_Line = IRDA_RX_LINE;
|
||||
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
|
||||
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
|
||||
EXTI_Init(&EXTI_InitStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : IRDA_GPIO_TX_init
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void IRDA_GPIO_TX_init(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
RCC_APB2PeriphClockCmd(IRDA_TX_PORT_CLK | RCC_APB2Periph_AFIO, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = IRDA_TX_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
|
||||
GPIO_Init( IRDA_TX_PORT, &GPIO_InitStructure );
|
||||
GPIO_SetBits(IRDA_TX_PORT, IRDA_TX_PIN);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : GPIO_TX_high
|
||||
* Description : 发送高电平时无需加载载波,开始时已经启动定时器
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void GPIO_TX_high(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
TIM_Cmd(PWM_TIMER, DISABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = IRDA_TX_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
|
||||
GPIO_Init( IRDA_TX_PORT, &GPIO_InitStructure );
|
||||
|
||||
GPIO_SetBits(IRDA_TX_PORT, IRDA_TX_PIN);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : GPIO_TX_low
|
||||
* Description : IRDA发送时,低电平需要加载载波信号
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void GPIO_TX_low(void)
|
||||
{
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||
|
||||
TIM_OCInitTypeDef TIM_OCInitStructure;
|
||||
|
||||
IRDA_GPIO_TX_init();
|
||||
|
||||
RCC_APB1PeriphClockCmd(PWM_TIMER_CLK, ENABLE); //时钟使能
|
||||
|
||||
TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD; // period
|
||||
TIM_TimeBaseStructure.TIM_Prescaler = PWM_PRESC; // 时钟分频
|
||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||
TIM_TimeBaseInit(PWM_TIMER, &TIM_TimeBaseStructure);
|
||||
|
||||
//初始化TIM2 Channel1 PWM模式
|
||||
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
|
||||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
|
||||
TIM_OCInitStructure.TIM_Pulse = PWM_PERIOD / 2;
|
||||
TIM_OC1Init(PWM_TIMER, &TIM_OCInitStructure);
|
||||
|
||||
TIM_OC2PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable); //使能在CCR2上的预装载寄存器
|
||||
|
||||
TIM_CtrlPWMOutputs(PWM_TIMER, ENABLE);
|
||||
|
||||
TIM_Cmd(PWM_TIMER, ENABLE);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : baud_timer_init
|
||||
* Description : none
|
||||
* Input : u32 preriod
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void baud_timer_init(u32 preriod)
|
||||
{
|
||||
RCC_APB1PeriphClockCmd(IRDA_BAUD_TIMER_CLK, ENABLE);
|
||||
|
||||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
TIM_TimeBaseStructure.TIM_Period = preriod; // period
|
||||
TIM_TimeBaseStructure.TIM_Prescaler = IRDA_BAUD_PRESC; // 时钟分频
|
||||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||
TIM_TimeBaseInit(IRDA_BAUD_TIMER, &TIM_TimeBaseStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
TIM_ClearFlag(IRDA_BAUD_TIMER, TIM_FLAG_Update);
|
||||
|
||||
TIM_ITConfig(IRDA_BAUD_TIMER, TIM_IT_Update, ENABLE); //允许更新中断
|
||||
|
||||
TIM_Cmd(IRDA_BAUD_TIMER, ENABLE);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : IRDA_TX_bit
|
||||
* Description : none
|
||||
* Input : u8 bitVal
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void IRDA_TX_bit(u8 bitVal)
|
||||
{
|
||||
if (bitVal == 0)
|
||||
{
|
||||
GPIO_TX_low();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
GPIO_TX_high();
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : IRDA_TX
|
||||
* Description : none
|
||||
* Input : u8 *buf
|
||||
u8 length
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void IRDA_TX(u8 *buf, u8 length)
|
||||
{
|
||||
IRDA_RX_stop();
|
||||
|
||||
IRDA_TX_flag.fLen = length;
|
||||
IRDA_TX_flag.index = 0;
|
||||
|
||||
if ((IRDA_status != IRDA_STATUS_RECEIVE) || (IRDA_status != IRDA_STATUS_TX))
|
||||
{
|
||||
IRDA_GPIO_TX_init();
|
||||
IRDA_status = IRDA_STATUS_TX ;
|
||||
MemCpy(IRDA_TX_buf, buf, length);
|
||||
hal_sRF_FSK_ITConfig(IRDA_RX_LINE , DISABLE);
|
||||
|
||||
TIM_ClearITPendingBit(IRDA_BAUD_TIMER, TIM_IT_Update);
|
||||
baud_timer_init(IRDA_BAUD_PERIOD);
|
||||
xTaskNotify(IRDA_task_handle, IRDA_TX_START, eSetBits);
|
||||
printf("IRDA start tx\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("IRDA tx when rx\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : IRDA_task
|
||||
* Description : none
|
||||
* Input : void *ptr
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void IRDA_task(void *ptr)
|
||||
{
|
||||
TickType_t xTicksToWait;
|
||||
TimeOut_t xTimeOut;
|
||||
|
||||
IRDA_GPIO_RX_init();
|
||||
IRDA_GPIO_TX_init();
|
||||
//IRDA_RX_start();
|
||||
for (;;)
|
||||
{
|
||||
uint32_t notifyValue = 0;
|
||||
xTaskNotifyWait(0xFF, 0xFF, ¬ifyValue, portMAX_DELAY);
|
||||
|
||||
if (notifyValue == IRDA_TX_START)
|
||||
{
|
||||
xTicksToWait = IRDA_TX_TIMEOUT / portTICK_RATE_MS;
|
||||
vTaskSetTimeOutState(&xTimeOut);
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE)
|
||||
{
|
||||
xTaskNotifyWait(0xFF, 0xFF, ¬ifyValue, xTicksToWait);
|
||||
if (notifyValue == IRDA_TX_FINISH)
|
||||
{
|
||||
printf("IRDA tx finish\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("IRDA tx timeout\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
IRDA_RX_start();
|
||||
}
|
||||
else if (notifyValue == IRDA_RX_START)
|
||||
{
|
||||
xTicksToWait = IRDA_RX_TIMEOUT / portTICK_RATE_MS;
|
||||
vTaskSetTimeOutState(&xTimeOut);
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE)
|
||||
{
|
||||
xTaskNotifyWait(0xFF, 0xFF, ¬ifyValue, xTicksToWait);
|
||||
if (notifyValue == IRDA_RX_FINISH)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (notifyValue == IRDA_RX_ERR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
IRDA_RX_start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : create_IRDA_task
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void create_IRDA_task(void)
|
||||
{
|
||||
xTaskCreate(IRDA_task, NULL, 100, NULL, 2, &IRDA_task_handle);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : DLT645_protocol_receive
|
||||
Description :
|
||||
Input :
|
||||
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
u32 DLT645_protocol_receive(u8 * rxBuf, IRDA_FLAG * rx_flag)
|
||||
{
|
||||
u32 status = IRDA_RX_WAIT;
|
||||
|
||||
switch(rx_flag->index)
|
||||
{
|
||||
case 0:
|
||||
if(rxBuf[rx_flag->index] != 0x68)
|
||||
{
|
||||
rx_flag->index = 0;
|
||||
status = IRDA_RX_ERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
rx_flag->index++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
rx_flag->fLen = rxBuf[rx_flag->index] + 12;
|
||||
rx_flag->index++;
|
||||
break;
|
||||
|
||||
default:
|
||||
rx_flag->index++;
|
||||
|
||||
if (rx_flag->index > 9)
|
||||
{
|
||||
if ( rx_flag->index == rx_flag->fLen )
|
||||
{
|
||||
if ( (rxBuf[rx_flag->index - 1] == 0x16) && (rxBuf[rx_flag->index -2] == GetSum(rxBuf, rx_flag->fLen - 2)))
|
||||
{
|
||||
status = IRDA_RX_FINISH;
|
||||
rx_flag->index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = IRDA_RX_ERR;
|
||||
rx_flag->index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : IRDA_BAUD_IRQHandler
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void IRDA_BAUD_IRQHandler(void)
|
||||
{
|
||||
u8 start_bit = 0;
|
||||
u8 end_bit = 1;
|
||||
|
||||
u8 check_bit;
|
||||
|
||||
static u8 rxByte = 0;
|
||||
static u8 tx_bit_pos = 0;
|
||||
static u8 rx_bit_pos = 0;
|
||||
BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
|
||||
u8 status;
|
||||
|
||||
if (TIM_GetITStatus(IRDA_BAUD_TIMER, TIM_IT_Update) != RESET)
|
||||
{
|
||||
TIM_ClearITPendingBit(IRDA_BAUD_TIMER, TIM_IT_Update);
|
||||
|
||||
if (IRDA_status == IRDA_STATUS_TX)
|
||||
{
|
||||
switch (tx_bit_pos)
|
||||
{
|
||||
case 0:
|
||||
if (IRDA_TX_flag.index >= IRDA_TX_flag.fLen)
|
||||
{
|
||||
TIM_Cmd(IRDA_BAUD_TIMER, DISABLE);
|
||||
IRDA_status = IRDA_STATUS_NONE;
|
||||
xTaskNotifyFromISR(IRDA_task_handle, IRDA_TX_FINISH, eSetBits, &pxHigherPriorityTaskWoken);
|
||||
}
|
||||
else
|
||||
{
|
||||
IRDA_TX_bit( start_bit );
|
||||
}
|
||||
|
||||
tx_bit_pos++;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
IRDA_TX_bit( (IRDA_TX_buf[IRDA_TX_flag.index] >> (tx_bit_pos - 1)) & 0x01);
|
||||
tx_bit_pos++;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
check_bit = 0;
|
||||
|
||||
for (u8 i = 0; i < 8; i++)
|
||||
{
|
||||
check_bit += ((IRDA_TX_buf[IRDA_TX_flag.index] >> i) & 0x01);
|
||||
}
|
||||
|
||||
check_bit = check_bit % 2;
|
||||
|
||||
IRDA_TX_bit(check_bit);
|
||||
tx_bit_pos++;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
IRDA_TX_bit(end_bit);
|
||||
IRDA_TX_flag.index++;
|
||||
tx_bit_pos = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
else if (IRDA_status == IRDA_STATUS_RECEIVE)
|
||||
{
|
||||
switch(rx_bit_pos)
|
||||
{
|
||||
case 0:
|
||||
if (IRDA_RX_BIT_VAL == 0)
|
||||
{
|
||||
baud_timer_init(IRDA_BAUD_PERIOD);
|
||||
rxByte = 0;
|
||||
rx_bit_pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
TIM_Cmd(IRDA_BAUD_TIMER, DISABLE);
|
||||
hal_sRF_FSK_ITConfig(IRDA_RX_LINE , ENABLE);
|
||||
IRDA_RX_start();
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
rxByte += IRDA_RX_BIT_VAL << (rx_bit_pos - 1);
|
||||
rx_bit_pos++;
|
||||
break;
|
||||
|
||||
case 9:
|
||||
check_bit = 0;
|
||||
|
||||
for (u8 i = 0; i < 8; i++)
|
||||
{
|
||||
check_bit += ((rxByte >> i) & 0x01);
|
||||
}
|
||||
|
||||
check_bit = check_bit % 2;
|
||||
|
||||
if (IRDA_RX_BIT_VAL != check_bit)
|
||||
{
|
||||
rx_bit_pos = 0;
|
||||
IRDA_RX_flag.index = 0;
|
||||
TIM_Cmd(IRDA_BAUD_TIMER, DISABLE);
|
||||
hal_sRF_FSK_ITConfig(IRDA_RX_LINE , ENABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
rx_bit_pos++;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 10:
|
||||
rx_bit_pos = 0;
|
||||
|
||||
if (IRDA_RX_BIT_VAL == 1)//停止位正确
|
||||
{
|
||||
if (IRDA_RX_flag.index >= IRDA_RX_BUFFER_SIZE)
|
||||
{
|
||||
IRDA_RX_flag.index = 0;
|
||||
}
|
||||
IRDA_RX_buf[IRDA_RX_flag.index++] = rxByte;
|
||||
|
||||
if (IRDA_RX_flag.index == 1)
|
||||
{
|
||||
xTaskNotifyFromISR(IRDA_task_handle, IRDA_RX_START, eSetBits, &pxHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
status = DLT645_protocol_receive(IRDA_RX_buf, &IRDA_RX_flag);
|
||||
|
||||
if (status == IRDA_RX_WAIT)
|
||||
{
|
||||
TIM_Cmd(IRDA_BAUD_TIMER, DISABLE);
|
||||
hal_sRF_FSK_ITConfig(IRDA_RX_LINE , ENABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
IRDA_status = IRDA_STATUS_NONE;
|
||||
IRDA_RX_flag.index = 0;
|
||||
TIM_Cmd(IRDA_BAUD_TIMER, DISABLE);
|
||||
xTaskNotifyFromISR(IRDA_task_handle, status, eSetBits, &pxHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
else //停止位错误
|
||||
{
|
||||
IRDA_status = IRDA_STATUS_NONE;
|
||||
IRDA_RX_flag.index = 0;
|
||||
TIM_Cmd(IRDA_BAUD_TIMER, DISABLE);
|
||||
xTaskNotifyFromISR(IRDA_task_handle, IRDA_RX_ERR, eSetBits, &pxHigherPriorityTaskWoken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : RX_START_IRQHandler
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170515
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void RX_START_IRQHandler(void)
|
||||
{
|
||||
if(EXTI_GetITStatus(IRDA_RX_LINE) != RESET)
|
||||
{
|
||||
EXTI_ClearITPendingBit(IRDA_RX_LINE);
|
||||
|
||||
if ((IRDA_status == IRDA_STATUS_RX) || (IRDA_status == IRDA_STATUS_RECEIVE))
|
||||
{
|
||||
IRDA_status = IRDA_STATUS_RECEIVE;
|
||||
hal_sRF_FSK_ITConfig(IRDA_RX_LINE , DISABLE);
|
||||
baud_timer_init(IRDA_BAUD_PERIOD/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
#ifndef _IRDA_H_
|
||||
#define _IRDA_H_
|
||||
|
||||
#include "stm32f10x_gpio.h"
|
||||
|
||||
enum
|
||||
{
|
||||
CHECK_ODD,
|
||||
CHECK_EVEN,
|
||||
CHECK_NONE,
|
||||
};
|
||||
|
||||
#define IRDA_BAUD 1200
|
||||
#define IRDA_DATABITS 8
|
||||
#define IRDA_CHECKBIT CHECK_EVEN
|
||||
#define IRDA_STOPBIT 1
|
||||
|
||||
#define IRDA_BAUD_TIMER TIM3
|
||||
#define IRDA_BAUD_TIMER_CLK RCC_APB1Periph_TIM3
|
||||
|
||||
#define IRDA_BAUD_IRQHandler TIM3_IRQHandler
|
||||
|
||||
|
||||
#define IRDA_BAUD_PRESC 100
|
||||
#define IRDA_BAUD_PERIOD (SystemCoreClock/IRDA_BAUD_PRESC/IRDA_BAUD)
|
||||
|
||||
#define IRDA_TX_PIN GPIO_Pin_0
|
||||
#define IRDA_TX_PORT GPIOA
|
||||
#define IRDA_TX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define IRDA_RX_PIN GPIO_Pin_1
|
||||
#define IRDA_RX_PORT GPIOC
|
||||
#define IRDA_RX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define IRDA_RX_PORT_SOURCE GPIO_PortSourceGPIOC
|
||||
#define IRDA_RX_PIN_SOURCE GPIO_PinSource1
|
||||
#define IRDA_RX_LINE EXTI_Line1
|
||||
#define RX_START_IRQHandler EXTI1_IRQHandler
|
||||
|
||||
#define IRDA_RX_BIT_VAL GPIO_ReadInputDataBit(IRDA_RX_PORT, IRDA_RX_PIN)
|
||||
|
||||
#define IRDA_TX_BUFFER_SIZE 255
|
||||
#define IRDA_RX_BUFFER_SIZE 255
|
||||
|
||||
#define PWM_TIMER TIM2
|
||||
#define PWM_TIMER_CLK RCC_APB1Periph_TIM2
|
||||
#define PWM_TIMER_CHANNEL 1
|
||||
#define PWM_PRESC 100
|
||||
#define PWM_FRE 38000
|
||||
#define PWM_PERIOD (SystemCoreClock/PWM_FRE/PWM_PRESC)
|
||||
|
||||
#define IRDA_BAUD_COFF ((11.0 * 1000.0) / IRDA_BAUD)
|
||||
|
||||
void IRDA_PWM_Init();
|
||||
void IRDA_GPIO_RX_init(void);
|
||||
void IRDA_TX(u8 *buf, u8 length);
|
||||
void baud_timer_init(u32 preriod);
|
||||
void create_IRDA_task(void);
|
||||
#endif
|
||||
@@ -0,0 +1,248 @@
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Led.c
|
||||
* 文件说明:Led源文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
#include "Led.h"
|
||||
#include "include.h"
|
||||
|
||||
|
||||
bool OLDNEW_VERSION_DETECT = false;//false 旧版本,true 新版本
|
||||
/*
|
||||
st_gpio_config up_send_led = LED_INIT(UP_SEND);
|
||||
st_gpio_config up_receive_led = LED_INIT(UP_RECEIVE);
|
||||
st_gpio_config down_send_led = LED_INIT(DOWN_SEND);
|
||||
st_gpio_config down_receive_led = LED_INIT(DOWN_RECEIVE);
|
||||
st_gpio_config alarm_led = LED_INIT(ALARM);
|
||||
st_gpio_config running_led = LED_INIT(RUNNING);
|
||||
*/
|
||||
|
||||
/*
|
||||
st_gpio_config running_led = {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_1, GPIO_Mode_IPU}; //PA1 运行
|
||||
st_gpio_config alarm_led = {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_3, GPIO_Mode_IPU}; //PC3 告警
|
||||
|
||||
st_gpio_config plcRx_led = {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_0, GPIO_Mode_IPU}; //PC0 PLC RX
|
||||
st_gpio_config plcTx_led = {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_2, GPIO_Mode_IPU}; //PC2 PLC TX
|
||||
|
||||
st_gpio_config up_RS485Rx_led = {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_12, GPIO_Mode_IPU}; //PA12 4851RX 485上行
|
||||
st_gpio_config up_RS485Tx_led = {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_11, GPIO_Mode_IPU}; //PA11 4851TX
|
||||
|
||||
st_gpio_config MBUS1Rx_led = {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_8, GPIO_Mode_IPU}; //PA8 MBUS1RX
|
||||
st_gpio_config MBUS1Tx_led = {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_9, GPIO_Mode_IPU}; //PC9 MBUS1TX
|
||||
|
||||
st_gpio_config dn_RS485Rx_led = {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_8, GPIO_Mode_IPU}; //PC8 4852RX 485下行
|
||||
st_gpio_config dn_RS485Rx_led = {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_7, GPIO_Mode_IPU}; //PC7 4852TX
|
||||
|
||||
st_gpio_config MBUS2Rx_led = {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_6, GPIO_Mode_IPU}; //PC6 MBUS2RX
|
||||
st_gpio_config MBUS2Tx_led = {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_15, GPIO_Mode_IPU}; //PB15 MBUS2TX
|
||||
*/
|
||||
|
||||
st_gpio_config led_boardharddetect[1] =
|
||||
{
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_1, GPIO_Mode_IPU}, //PA1 运行
|
||||
};
|
||||
|
||||
|
||||
|
||||
st_gpio_config led_list[] =
|
||||
{
|
||||
#if HARDBOARD_VERSION == 0
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_1, GPIO_Mode_IPU}, //PA1 运行
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_3, GPIO_Mode_IPU}, //PC3 告警
|
||||
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_0, GPIO_Mode_IPU}, //PC0 PLC RX RED
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_2, GPIO_Mode_IPU}, //PC2 PLC TX
|
||||
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_12, GPIO_Mode_IPU}, //PA12 4851RX RED
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_11, GPIO_Mode_IPU}, //PA11 4851TX GREEN
|
||||
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_8, GPIO_Mode_IPU}, //PA8 MBUS1RX
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_9, GPIO_Mode_IPU}, //PC9 MBUS1TX
|
||||
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_8, GPIO_Mode_IPU}, //PC8 4852RX
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_7, GPIO_Mode_IPU}, //PC7 4852TX
|
||||
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_6, GPIO_Mode_IPU}, //PC6 MBUS2RX
|
||||
{GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_15, GPIO_Mode_IPU}, //PB15 MBUS2TX
|
||||
|
||||
|
||||
// {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_1, GPIO_Mode_IPD}, //PA1 运行
|
||||
// {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_3, GPIO_Mode_IPD}, //PC3 告警
|
||||
//
|
||||
// {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_0, GPIO_Mode_IPD}, //PC0 PLC RX RED
|
||||
// {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_2, GPIO_Mode_IPD}, //PC2 PLC TX
|
||||
//
|
||||
// {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_12, GPIO_Mode_IPD}, //PA12 4851RX RED
|
||||
// {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_11, GPIO_Mode_IPD}, //PA11 4851TX GREEN
|
||||
//
|
||||
// {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_8, GPIO_Mode_IPD}, //PA8 MBUS1RX
|
||||
// {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_9, GPIO_Mode_IPD}, //PC9 MBUS1TX
|
||||
//
|
||||
// {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_8, GPIO_Mode_IPD}, //PC8 4852RX
|
||||
// {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_7, GPIO_Mode_IPD}, //PC7 4852TX
|
||||
//
|
||||
// {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_6, GPIO_Mode_IPD}, //PC6 MBUS2RX
|
||||
// {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_15, GPIO_Mode_IPD}, //PB15 MBUS2TX
|
||||
|
||||
#else
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_1, GPIO_Mode_Out_OD}, //PA1 运行
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_3, GPIO_Mode_Out_OD}, //PC3 告警
|
||||
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_0, GPIO_Mode_Out_OD}, //PC0 PLC RX RED
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_2, GPIO_Mode_Out_OD}, //PC2 PLC TX
|
||||
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_12, GPIO_Mode_Out_OD}, //PA12 4851RX RED
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_11, GPIO_Mode_Out_OD}, //PA11 4851TX GREEN
|
||||
|
||||
{GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_8, GPIO_Mode_Out_OD}, //PA8 MBUS1RX
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_9, GPIO_Mode_Out_OD}, //PC9 MBUS1TX
|
||||
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_8, GPIO_Mode_Out_OD}, //PC8 4852RX
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_7, GPIO_Mode_Out_OD}, //PC7 4852TX
|
||||
|
||||
{GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_6, GPIO_Mode_Out_OD}, //PC6 MBUS2RX
|
||||
{GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_15, GPIO_Mode_Out_OD}, //PB15 MBUS2TX
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
st_gpio_config * CurrentOperationLED = &led_list[0];
|
||||
/*——————————————————————————
|
||||
* 函 数 名:LED_Init
|
||||
* 输入参数:led 灯
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:初始化LED灯
|
||||
*——————————————————————————*/
|
||||
void LED_Init(st_gpio_config led)
|
||||
{
|
||||
gpio_init(led);
|
||||
LED_Off(led);
|
||||
}
|
||||
|
||||
|
||||
void init_all_led(void)
|
||||
{
|
||||
|
||||
LED_Init(led_boardharddetect[0]);
|
||||
if(GPIO_ReadInputDataBit(led_boardharddetect[0].GPIO_port,led_boardharddetect[0].GPIO_Pin) == 0x01)
|
||||
{
|
||||
OLDNEW_VERSION_DETECT = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
OLDNEW_VERSION_DETECT = false;
|
||||
}
|
||||
|
||||
for (u8 i = 0; i < sizeof(led_list) / sizeof(st_gpio_config); i++)
|
||||
{
|
||||
if(OLDNEW_VERSION_DETECT == false)
|
||||
{
|
||||
led_list[i].GPIO_mode = GPIO_Mode_IPU;
|
||||
}
|
||||
else
|
||||
{
|
||||
led_list[i].GPIO_mode = GPIO_Mode_Out_OD;
|
||||
}
|
||||
|
||||
LED_Init(led_list[i]);
|
||||
LED_Off(led_list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_led(void)
|
||||
{
|
||||
for (u8 i = 0; i < sizeof(led_list) / sizeof(st_gpio_config); i++)
|
||||
{
|
||||
COM_led_on(i);
|
||||
//vTaskDelay( 1000 / portTICK_RATE_MS );
|
||||
//COM_led_off(i);
|
||||
//vTaskDelay( 1000 / portTICK_RATE_MS );
|
||||
}
|
||||
|
||||
printf("OK\r\n");
|
||||
}
|
||||
|
||||
|
||||
void COM_led_init(u8 led)
|
||||
{
|
||||
LED_Init(led_list[led]);
|
||||
}
|
||||
|
||||
void COM_led_on(u8 led)
|
||||
{
|
||||
LED_On(led_list[led]);
|
||||
}
|
||||
|
||||
void COM_led_off(u8 led)
|
||||
{
|
||||
LED_Off(led_list[led]);
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:LED_On
|
||||
* 输入参数:led 灯
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:点亮Led灯
|
||||
*——————————————————————————*/
|
||||
void LED_On(st_gpio_config led)
|
||||
{
|
||||
//#if HARDBOARD_VERSION == 0
|
||||
if(OLDNEW_VERSION_DETECT == false)
|
||||
led.GPIO_port->BSRR = led.GPIO_Pin;//GPIO_PIN[led]; //设置位为 1
|
||||
//#else
|
||||
else
|
||||
led.GPIO_port->BRR = led.GPIO_Pin;
|
||||
//#endif
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:LED_Off
|
||||
* 输入参数:led 灯
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:关闭Led灯
|
||||
*——————————————————————————*/
|
||||
void LED_Off(st_gpio_config led)
|
||||
{
|
||||
//#if HARDBOARD_VERSION == 0
|
||||
if(OLDNEW_VERSION_DETECT == false)
|
||||
led.GPIO_port->BRR = led.GPIO_Pin;//GPIO_PIN[led]; //清除位为 0
|
||||
//#else
|
||||
else
|
||||
led.GPIO_port->BSRR = led.GPIO_Pin;
|
||||
//#endif
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:LED_Toggle
|
||||
* 输入参数:led 灯
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:电平反转
|
||||
*——————————————————————————*/
|
||||
void LED_Toggle(st_gpio_config led)
|
||||
{
|
||||
//#if HARDBOARD_VERSION == 0
|
||||
if(OLDNEW_VERSION_DETECT == false)
|
||||
led.GPIO_port->ODR ^= led.GPIO_Pin;//GPIO_PIN[led];
|
||||
//#else
|
||||
else
|
||||
led.GPIO_port->ODR ^= led.GPIO_Pin;
|
||||
//#endif
|
||||
}
|
||||
|
||||
|
||||
void off_all_led(void)
|
||||
{
|
||||
for (u8 i = 0; i < sizeof(led_list) / sizeof(st_gpio_config); i++)
|
||||
{
|
||||
//LED_Init(led_list[i]);
|
||||
LED_Off(led_list[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Led.h
|
||||
* 文件说明:Led头文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
#ifndef _LED_H
|
||||
#define _LED_H
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
|
||||
/*************** 宏定义 ***************/
|
||||
|
||||
#define UP_SEND_LED_PIN GPIO_Pin_7
|
||||
#define UP_SEND_LED_PORT GPIOC
|
||||
#define UP_SEND_LED_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define UP_RECEIVE_LED_PIN GPIO_Pin_8
|
||||
#define UP_RECEIVE_LED_PORT GPIOC
|
||||
#define UP_RECEIVE_LED_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
|
||||
#define ALARM_LED_PIN GPIO_Pin_3
|
||||
#define ALARM_LED_PORT GPIOC
|
||||
#define ALARM_LED_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define RUNNING_LED_PIN GPIO_Pin_1
|
||||
#define RUNNING_LED_PORT GPIOA
|
||||
#define RUNNING_LED_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define DOWN_SEND_LED_PIN GPIO_Pin_9
|
||||
#define DOWN_SEND_LED_PORT GPIOC
|
||||
#define DOWN_SEND_LED_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define DOWN_RECEIVE_LED_PIN GPIO_Pin_8
|
||||
#define DOWN_RECEIVE_LED_PORT GPIOC
|
||||
#define DOWN_RECEIVE_LED_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define LED_PIN(name) name##_LED_PIN
|
||||
#define LED_PORT(name) name##_LED_PORT
|
||||
#define LED_CLK(name) name##_LED_PORT_CLK
|
||||
#define LED_INIT(name) {LED_PIN(name), LED_PORT(name), LED_CLK(name)}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RUNING_LED = 0,
|
||||
ALARM_LED,
|
||||
PLC_RX_LED,
|
||||
PLC_TX_LED,
|
||||
RS4851_RX_LED,
|
||||
RS4851_TX_LED ,
|
||||
MBUS1RX_LED,
|
||||
MBUS1TX_LED,
|
||||
RS4852_RX_LED,
|
||||
RS4852_TX_LED ,
|
||||
MBUS2RX_LED,
|
||||
MBUS2TX_LED,
|
||||
}EN_LED_TYPE;
|
||||
|
||||
|
||||
/*************** 函数实现 ***************/
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:LED_Init
|
||||
* 输入参数:led 灯
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:初始化LED灯
|
||||
*——————————————————————————*/
|
||||
void LED_Init(st_gpio_config led);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:LED_On
|
||||
* 输入参数:led 灯
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:点亮Led灯
|
||||
*——————————————————————————*/
|
||||
void LED_On (st_gpio_config led);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:LED_Off
|
||||
* 输入参数:led 灯
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:关闭Led灯
|
||||
*——————————————————————————*/
|
||||
void LED_Off(st_gpio_config led);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:LED_Toggle
|
||||
* 输入参数:led 灯
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:电平反转
|
||||
*——————————————————————————*/
|
||||
void LED_Toggle(st_gpio_config led);
|
||||
|
||||
void init_all_led(void);
|
||||
void all_light_delay(void);
|
||||
void test_led(void );
|
||||
void COM_led_on(u8 led);
|
||||
void COM_led_off(u8 led);
|
||||
void COM_led_init(u8 led);
|
||||
void off_all_led(void);
|
||||
|
||||
|
||||
extern st_gpio_config * CurrentOperationLED;
|
||||
extern st_gpio_config led_list[] ;
|
||||
#endif
|
||||
|
||||
/******************* (C) COPYRIGHT 2011 Leaguer Microelectronics *****END OF FILE****/
|
||||
@@ -0,0 +1,189 @@
|
||||
#include "MD5.h"
|
||||
#include "Mem.h"
|
||||
#include "string.h"
|
||||
|
||||
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
void MD5Init(MD5_CTX *context)
|
||||
{
|
||||
context->count[0] = 0;
|
||||
context->count[1] = 0;
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
}
|
||||
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
|
||||
{
|
||||
unsigned int i = 0,index = 0,partlen = 0;
|
||||
index = (context->count[0] >> 3) & 0x3F;
|
||||
partlen = 64 - index;
|
||||
context->count[0] += inputlen << 3;
|
||||
if(context->count[0] < (inputlen << 3))
|
||||
context->count[1]++;
|
||||
context->count[1] += inputlen >> 29;
|
||||
|
||||
if(inputlen >= partlen)
|
||||
{
|
||||
memcpy(&context->buffer[index],input,partlen);
|
||||
MD5Transform(context->state,context->buffer);
|
||||
for(i = partlen;i+64 <= inputlen;i+=64)
|
||||
MD5Transform(context->state,&input[i]);
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
memcpy(&context->buffer[index],&input[i],inputlen-i);
|
||||
}
|
||||
void MD5Final(MD5_CTX *context,unsigned char digest[16])
|
||||
{
|
||||
unsigned int index = 0,padlen = 0;
|
||||
unsigned char bits[8];
|
||||
index = (context->count[0] >> 3) & 0x3F;
|
||||
padlen = (index < 56)?(56-index):(120-index);
|
||||
MD5Encode(bits,context->count,8);
|
||||
MD5Update(context,PADDING,padlen);
|
||||
MD5Update(context,bits,8);
|
||||
MD5Encode(digest,context->state,16);
|
||||
}
|
||||
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
|
||||
{
|
||||
unsigned int i = 0,j = 0;
|
||||
while(j < len)
|
||||
{
|
||||
output[j] = input[i] & 0xFF;
|
||||
output[j+1] = (input[i] >> 8) & 0xFF;
|
||||
output[j+2] = (input[i] >> 16) & 0xFF;
|
||||
output[j+3] = (input[i] >> 24) & 0xFF;
|
||||
i++;
|
||||
j+=4;
|
||||
}
|
||||
}
|
||||
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
|
||||
{
|
||||
unsigned int i = 0,j = 0;
|
||||
while(j < len)
|
||||
{
|
||||
output[i] = (input[j]) |
|
||||
(input[j+1] << 8) |
|
||||
(input[j+2] << 16) |
|
||||
(input[j+3] << 24);
|
||||
i++;
|
||||
j+=4;
|
||||
}
|
||||
}
|
||||
void MD5Transform(unsigned int state[4],unsigned char block[64])
|
||||
{
|
||||
unsigned int a = state[0];
|
||||
unsigned int b = state[1];
|
||||
unsigned int c = state[2];
|
||||
unsigned int d = state[3];
|
||||
unsigned int x[64];
|
||||
MD5Decode(x,block,64);
|
||||
FF(a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
|
||||
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
|
||||
FF(c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
|
||||
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
|
||||
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
|
||||
FF(d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
|
||||
FF(c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
|
||||
FF(b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
|
||||
FF(a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
|
||||
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
|
||||
FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
|
||||
FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
|
||||
FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
|
||||
FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
|
||||
FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
|
||||
FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG(a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
|
||||
GG(d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
|
||||
GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
|
||||
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
|
||||
GG(a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
|
||||
GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */
|
||||
GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
|
||||
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
|
||||
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
|
||||
GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
|
||||
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
|
||||
GG(b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
|
||||
GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
|
||||
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
|
||||
GG(c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
|
||||
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH(a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
|
||||
HH(d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
|
||||
HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
|
||||
HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
|
||||
HH(a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
|
||||
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
|
||||
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
|
||||
HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
|
||||
HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
|
||||
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
|
||||
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
|
||||
HH(b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
|
||||
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
|
||||
HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
|
||||
HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
|
||||
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II(a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
|
||||
II(d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
|
||||
II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
|
||||
II(b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
|
||||
II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
|
||||
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
|
||||
II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
|
||||
II(b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
|
||||
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
|
||||
II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
|
||||
II(c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
|
||||
II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
|
||||
II(a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
|
||||
II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
|
||||
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
|
||||
II(b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
}
|
||||
|
||||
|
||||
void MD5_TEST(void)
|
||||
{
|
||||
int i;
|
||||
unsigned char encrypt[] ="admin";//21232f297a57a5a743894a0e4a801fc3
|
||||
unsigned char decrypt[16];
|
||||
MD5_CTX md5;
|
||||
MD5Init(&md5);
|
||||
MD5Update(&md5,encrypt,strlen((char *)encrypt));
|
||||
MD5Final(&md5,decrypt);
|
||||
printf("¼ÓÃÜǰ:%s\n¼ÓÃܺó:",encrypt);
|
||||
for(i=0;i<16;i++)
|
||||
{
|
||||
printf("%02x",decrypt[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MD5_code(u8 * buf, u8 * outbuf, u32 len)
|
||||
{
|
||||
MD5_CTX md5;
|
||||
MD5Init(&md5);
|
||||
MD5Update(&md5,buf, len);
|
||||
MD5Final(&md5,outbuf);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int count[2];
|
||||
unsigned int state[4];
|
||||
unsigned char buffer[64];
|
||||
}MD5_CTX;
|
||||
|
||||
|
||||
#define F(x,y,z) ((x & y) | (~x & z))
|
||||
#define G(x,y,z) ((x & z) | (y & ~z))
|
||||
#define H(x,y,z) (x^y^z)
|
||||
#define I(x,y,z) (y ^ (x | ~z))
|
||||
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
|
||||
#define FF(a,b,c,d,x,s,ac) \
|
||||
{\
|
||||
a += F(b,c,d) + x + ac;\
|
||||
a = ROTATE_LEFT(a,s);\
|
||||
a += b;\
|
||||
}
|
||||
|
||||
#define GG(a,b,c,d,x,s,ac) \
|
||||
{\
|
||||
a += G(b,c,d) + x + ac;\
|
||||
a = ROTATE_LEFT(a,s);\
|
||||
a += b;\
|
||||
}
|
||||
|
||||
#define HH(a,b,c,d,x,s,ac) \
|
||||
{\
|
||||
a += H(b,c,d) + x + ac;\
|
||||
a = ROTATE_LEFT(a,s);\
|
||||
a += b;\
|
||||
}
|
||||
|
||||
#define II(a,b,c,d,x,s,ac) \
|
||||
{\
|
||||
a += I(b,c,d) + x + ac;\
|
||||
a = ROTATE_LEFT(a,s); \
|
||||
a += b;\
|
||||
}
|
||||
|
||||
void MD5Init(MD5_CTX *context);
|
||||
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
|
||||
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
|
||||
void MD5Transform(unsigned int state[4],unsigned char block[64]);
|
||||
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
|
||||
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
|
||||
void MD5_TEST(void);
|
||||
void MD5_code(unsigned char * buf, unsigned char * outbuf, unsigned int len);
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Mem.c
|
||||
* 文件说明:内存拷贝源文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
#include "Mem.h"
|
||||
|
||||
|
||||
/************* 函数声明 *************/
|
||||
/*——————————————————————————
|
||||
* 函 数 名:MemCpy
|
||||
* 输入参数:pSrc 源内存指针
|
||||
len 数据长度
|
||||
* 输出参数:pDsc 目的内在指针
|
||||
* 返 回 值:拷贝后的目的偏移地址
|
||||
* 功能说明:拷贝一段内存内容
|
||||
*——————————————————————————*/
|
||||
u8 *MemCpy(void *pDsc, void*pSrc, u16 len)
|
||||
{
|
||||
u8 *pAddr1 = (u8 *)pDsc;
|
||||
u8 *pAddr2 = (u8 *)pSrc;
|
||||
|
||||
while(len--)
|
||||
{
|
||||
*pAddr1++ = *pAddr2++;
|
||||
}
|
||||
|
||||
return pAddr1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:MemSet
|
||||
* 输入参数:pAddr 内存指针
|
||||
value 需要设置的值
|
||||
len 数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:设置某一段内容为某值
|
||||
*——————————————————————————*/
|
||||
void MemSet(void *pAddr, u8 value, u16 len)
|
||||
{
|
||||
u8 *pTmp = (u8 *)pAddr;
|
||||
|
||||
while(len--)
|
||||
{
|
||||
*pTmp++ = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:MemCmp
|
||||
* 输入参数:pDsc 目的地址
|
||||
pSrc 源地址
|
||||
Len 数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:1 不一致
|
||||
0 一致
|
||||
* 功能说明:比较两个内存中的值
|
||||
*——————————————————————————*/
|
||||
u8 MemCmp(void *pDsc, void *pSrc, u16 len)
|
||||
{
|
||||
u8 *pAddr1 = (u8 *)pDsc;
|
||||
u8 *pAddr2 = (u8 *)pSrc;
|
||||
|
||||
while(len--)
|
||||
{
|
||||
if (*pAddr1 != *pAddr2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
pAddr1++;
|
||||
pAddr2++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:MemCmpData
|
||||
* 输入参数:buf 数据区
|
||||
data 比较数据
|
||||
len 数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:>0 不一致
|
||||
0 一致
|
||||
* 功能说明:比较内存中的值与某个数据一致
|
||||
*——————————————————————————*/
|
||||
u8 MemCmpData(const u8 *buf,u8 data,u16 len)
|
||||
{
|
||||
while(len--)
|
||||
{
|
||||
if(buf[len] != data)
|
||||
{
|
||||
return buf[len]-data;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * w_memcpy( void *out, const void *in, size_t n)
|
||||
{
|
||||
uint8_t *src, *dest;
|
||||
src = (uint8_t *) in;
|
||||
dest = (uint8_t *) out;
|
||||
while(n-- > 0) {
|
||||
*dest++ = *src++;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void *w_memset(void *out, int value, size_t n)
|
||||
{
|
||||
uint8_t *dest;
|
||||
dest = (uint8_t *) out;
|
||||
while(n-- > 0) {
|
||||
*dest++ = value & 0xff;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#ifndef _MEM_H
|
||||
#define _MEM_H
|
||||
/*——————————————————————————
|
||||
* 文 件 名:Mem.h
|
||||
* 文件说明:内存拷贝头文件
|
||||
*
|
||||
* 当前版本:V8.0
|
||||
* 作 者:ZL
|
||||
* 开始日期:2013-12-30
|
||||
*———————————————————————————*/
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:MemCpy
|
||||
* 输入参数:pSrc 源内存指针
|
||||
len 数据长度
|
||||
* 输出参数:pDsc 目的内在指针
|
||||
* 返 回 值:拷贝后的目的偏移地址
|
||||
* 功能说明:拷贝一段内存内容
|
||||
*——————————————————————————*/
|
||||
u8 *MemCpy(void *pDsc, void*pSrc, u16 len);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:MemSet
|
||||
* 输入参数:pAddr 内存指针
|
||||
value 需要设置的值
|
||||
len 数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:None
|
||||
* 功能说明:设置某一段内容为某值
|
||||
*——————————————————————————*/
|
||||
void MemSet(void *pAddr, u8 value, u16 len);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:MemCmp
|
||||
* 输入参数:pDsc 目的地址
|
||||
pSrc 源地址
|
||||
len 数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:1 不一致
|
||||
0 一致
|
||||
* 功能说明:比较两个内存中的值
|
||||
*——————————————————————————*/
|
||||
u8 MemCmp(void *pDsc, void*pSrc, u16 len);
|
||||
|
||||
/*——————————————————————————
|
||||
* 函 数 名:MemCmpData
|
||||
* 输入参数:buf 数据区
|
||||
data 比较数据
|
||||
len 数据长度
|
||||
* 输出参数:None
|
||||
* 返 回 值:>0 不一致
|
||||
0 一致
|
||||
* 功能说明:比较内存中的值与某个数据一致
|
||||
*——————————————————————————*/
|
||||
u8 MemCmpData(const u8 *buf,u8 data,u16 len);
|
||||
|
||||
void * w_memcpy( void *out, const void *in, unsigned int n);
|
||||
void *w_memset(void *out, int value, unsigned int n);
|
||||
|
||||
#define memcpy(dest, src, count) w_memcpy(dest, src, count)
|
||||
#define memset(dest, value, count) w_memset(dest, value, count)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,416 @@
|
||||
#include "PHY.h"
|
||||
#include "uart.h"
|
||||
#
|
||||
|
||||
extern st_RF_LoRa_DypeDef g_RF_LoRa;
|
||||
extern SemaphoreHandle_t port_radio_Semaphore;
|
||||
static QueueHandle_t radioQueue;
|
||||
static TimerHandle_t radio_tx_handle;
|
||||
|
||||
static int8_t RxPacketSnr;
|
||||
static double RxPacketRssiValue;
|
||||
|
||||
#define RADIO_TX_TIMEOUT 2000/portTICK_RATE_MS
|
||||
u32 period = 1500;
|
||||
|
||||
void radio_tx_timeout_callback(TimerHandle_t xTimer)
|
||||
{
|
||||
hal_InitRF();
|
||||
SX1276LoRa_Receive_Packet(0, false);
|
||||
printf("RF tx timeout\r\n");
|
||||
}
|
||||
|
||||
|
||||
void read_radio_rssi(void)
|
||||
{
|
||||
RxPacketSnr = getPacketSnr();
|
||||
RxPacketRssiValue = get_RxPacketRssi(RxPacketSnr);
|
||||
printf("RSSI = %.2f, SNR = %d\r\n",RxPacketRssiValue, RxPacketSnr);
|
||||
}
|
||||
/*****************************************************************************
|
||||
* Function : get_radio_bufPtr
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return : u8
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170419
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
u8 * get_RF_bufPtr(void)
|
||||
{
|
||||
return g_RF_LoRa.rf_DataBuffer;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : get_radio_bufLen
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170419
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
u8 get_RF_bufLen(void)
|
||||
{
|
||||
return g_RF_LoRa.rf_RxPacketSize;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : SX1276LoRa_NormalTx
|
||||
* Description : none
|
||||
* Input : u8 chl
|
||||
u8 *PBuffer
|
||||
u8 length
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170419
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void SX1276LoRa_NormalTx(u8 chl, u8 *PBuffer,u8 length)
|
||||
{
|
||||
SX1276LoRa_Send_Packet(chl, false, PBuffer,length);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : SX1276LoRa_WokeUpTx
|
||||
* Description : none
|
||||
* Input : u8 chl
|
||||
u8 *PBuffer
|
||||
u8 length
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170419
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void SX1276LoRa_WokeUpTx(u8 chl, u8 *PBuffer,u8 length)
|
||||
{
|
||||
SX1276LoRa_Send_Packet(chl, true, PBuffer,length);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : radio_idle
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170306
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
bool radio_idle(void)
|
||||
{
|
||||
#ifdef USE_LORA_MODE
|
||||
if ( (g_RF_LoRa.rf_state != RFLR_STATE_TX_RUNNING) && (g_RF_LoRa.rf_state != RFLR_STATE_RX_RECEIVEING))
|
||||
#else
|
||||
if ( (g_fsk.states != RF_STATE_TX_RUNNING) && (g_fsk.states != RF_STATE_RX_SYNC) && (g_fsk.states != RF_STATE_RX_RUNNING))
|
||||
#endif
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : mac_data_req
|
||||
* Description : none
|
||||
* Input : u8 *buf
|
||||
u8 length
|
||||
u32 timeout
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170419
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void mac_data_req(u8 *buf, u8 length)
|
||||
{
|
||||
if (radio_idle())
|
||||
{
|
||||
SX1276LoRa_WokeUpTx(0 , buf, length);
|
||||
xTimerReset(radio_tx_handle, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("radio busy\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : vtask_mac_data_process
|
||||
* Description : none
|
||||
* Input : void *ptr
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170419
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void vtask_mac_data_process(void *ptr)
|
||||
{
|
||||
u16 flag;
|
||||
radioQueue = xQueueCreate(1, 2);
|
||||
u32 radio_rx_timeout = 4000/portTICK_RATE_MS;
|
||||
radio_tx_handle = xTimerCreate( "radio tx timer", RADIO_TX_TIMEOUT, pdFALSE, 0, radio_tx_timeout_callback);
|
||||
|
||||
Lora_lowPower_Init(period);
|
||||
hal_InitRF();
|
||||
SX1276LoRa_Receive_Packet(0, false);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
flag = 0;
|
||||
if (xQueueReceive(radioQueue, &flag, DELAY_HOUR_TIME) == pdPASS)
|
||||
{
|
||||
if (flag == RF_VALID_HEAD)
|
||||
{
|
||||
printf("valid head\r\n");
|
||||
if (xQueueReceive(radioQueue, &flag, radio_rx_timeout) == pdPASS)
|
||||
{
|
||||
printf("RSSI = %.2f, SNR = %d\r\n",RxPacketRssiValue, RxPacketSnr);
|
||||
|
||||
if (flag == RF_RX_SUCCESS)
|
||||
{
|
||||
printf("RF Rx:");
|
||||
printf_buf(g_RF_LoRa.rf_DataBuffer, g_RF_LoRa.rf_RxPacketSize);
|
||||
xSemaphoreGive(port_radio_Semaphore);
|
||||
}
|
||||
else if (flag == RF_RX_FAILED)
|
||||
{
|
||||
printf("crc err\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("RF RX timeout\r\n");
|
||||
}
|
||||
}
|
||||
SX1276LoRa_Receive_Packet(0, false);
|
||||
}
|
||||
else if ( (flag == RF_RX_SUCCESS) || (flag == RF_RX_FAILED) || (flag == RF_TX_SUCCESS) )
|
||||
{
|
||||
if (flag == RF_TX_SUCCESS)
|
||||
{
|
||||
xTimerStop(radio_tx_handle,100);
|
||||
printf("tx done\r\n");
|
||||
}
|
||||
else if (flag == RF_RX_SUCCESS)
|
||||
{
|
||||
printf("RF Rx:");
|
||||
printf_buf(g_RF_LoRa.rf_DataBuffer, g_RF_LoRa.rf_RxPacketSize);
|
||||
xSemaphoreGive(port_radio_Semaphore);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("rx crc err\r\n");
|
||||
}
|
||||
SX1276LoRa_Receive_Packet(0, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//此处可以做成绝对复位射频功能
|
||||
hal_InitRF();
|
||||
SX1276LoRa_Receive_Packet(0, false);
|
||||
printf("reset RF\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : get_lora_status
|
||||
* Description : none
|
||||
* Input : ST_irqFlag irq_flag
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170418
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
u8 get_lora_status(ST_irqFlag irq_flag)
|
||||
{
|
||||
u8 rf_status = RF_ERR;
|
||||
u8 cur_chl;
|
||||
|
||||
if ( (irq_flag.RxDone == 1) || (irq_flag.TxDone == 1) || (irq_flag.CadDone == 1) || (irq_flag.RxTimeout == 1))
|
||||
{
|
||||
hal_DIOx_ITConfig(all,DISABLE);
|
||||
hal_sRF_ClearAllRF_IT();
|
||||
SX1276Write( REG_LR_IRQFLAGS, 0xFF);
|
||||
}
|
||||
|
||||
if (irq_flag.RxDone == 1)
|
||||
{
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY);
|
||||
|
||||
RxPacketSnr = getPacketSnr();
|
||||
RxPacketRssiValue = get_RxPacketRssi(RxPacketSnr);
|
||||
|
||||
if (irq_flag.PayloadCrcError == 0)
|
||||
{
|
||||
g_RF_LoRa.rf_state = RFLR_STATE_RX_DONE;
|
||||
receiveRxData(g_RF_LoRa.rf_DataBuffer, &g_RF_LoRa.rf_RxPacketSize);
|
||||
rf_status = RF_RX_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_RF_LoRa.rf_state = RFLR_STATE_RX_ERR;
|
||||
rf_status = RF_RX_FAILED;
|
||||
}
|
||||
}
|
||||
else if (irq_flag.TxDone == 1)
|
||||
{
|
||||
switch_Rx();
|
||||
g_RF_LoRa.rf_state = RFLR_STATE_TX_DONE;
|
||||
rf_status = RF_TX_SUCCESS;
|
||||
}
|
||||
else if (irq_flag.ValidHeader == 1)
|
||||
{
|
||||
hal_DIOx_ITConfig(3,DISABLE);
|
||||
// SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_VALIDHEADER);
|
||||
if (g_RF_LoRa.rf_state == RFLR_STATE_RX_RUNNING)
|
||||
{
|
||||
g_RF_LoRa.rf_state = RFLR_STATE_RX_RECEIVEING;
|
||||
}
|
||||
rf_status = RF_VALID_HEAD;
|
||||
}
|
||||
else if (irq_flag.CadDone == 1)
|
||||
{
|
||||
if (irq_flag.CadDetected == 1)
|
||||
{
|
||||
rf_status = RF_CAD_DETECT;
|
||||
}
|
||||
else
|
||||
{
|
||||
//SX1276StartSleep();
|
||||
}
|
||||
}
|
||||
else if (irq_flag.RxTimeout == 1)
|
||||
{
|
||||
rf_status = RF_PREAMBLE_TIMEOUT;
|
||||
}
|
||||
else if (irq_flag.FhssChangeChannel == 1)
|
||||
{
|
||||
/* 此处表明在单次接收时是先收到头再跳频,在连续接收模式下是先跳频再收到头,需要验证 */
|
||||
/* 在接收模式下,谁先发生就算接收开始了,并不是接收到头才算接收开始,
|
||||
也可以处理为接收到头算接收开始,连续模式下可能头也是跳频发送的*/
|
||||
/* 统一为接收到头才算接收开始 */
|
||||
SX1276Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL );
|
||||
SX1276Read( REG_LR_HOPCHANNEL, &cur_chl);
|
||||
set_hop_Channel(cur_chl);
|
||||
}
|
||||
|
||||
return rf_status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_LORA_MODE
|
||||
/*****************************************************************************
|
||||
Prototype : EXTI4_15_IRQHandler
|
||||
Description : EXTI11 for valid header
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void EXTI15_10_IRQHandler(void)
|
||||
{
|
||||
BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
|
||||
ST_irqFlag irq_flag;
|
||||
u16 rf_flag;
|
||||
bool need_radio_process = FALSE;
|
||||
|
||||
/* tx done, rx done, cad done */
|
||||
if(EXTI_GetITStatus(DIO0_IRQ) != RESET)
|
||||
{
|
||||
need_radio_process = TRUE;
|
||||
EXTI_ClearITPendingBit(DIO0_IRQ);
|
||||
}
|
||||
else if (EXTI_GetITStatus(DIO1_IRQ) != RESET) /* Rx timeOut */
|
||||
{
|
||||
need_radio_process = TRUE;
|
||||
EXTI_ClearITPendingBit(DIO1_IRQ);
|
||||
}
|
||||
|
||||
if ( need_radio_process == TRUE)
|
||||
{
|
||||
SX1276Read( REG_LR_IRQFLAGS, (u8*)&irq_flag);
|
||||
rf_flag = get_lora_status(irq_flag);
|
||||
|
||||
if (rf_flag != 0)
|
||||
{
|
||||
xQueueSendToBackFromISR( radioQueue, &rf_flag, &pxHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR( pxHigherPriorityTaskWoken );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*****************************************************************************
|
||||
* Function : EXTI0_IRQHandler
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170419
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void EXTI0_IRQHandler(void)
|
||||
{
|
||||
BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
|
||||
ST_irqFlag irq_flag;
|
||||
u16 rf_flag;
|
||||
bool need_radio_process = FALSE;
|
||||
|
||||
if (EXTI_GetITStatus(DIO3_IRQ) != RESET)
|
||||
{
|
||||
need_radio_process= TRUE;
|
||||
EXTI_ClearITPendingBit(DIO3_IRQ);
|
||||
}
|
||||
|
||||
if ( need_radio_process == TRUE)
|
||||
{
|
||||
SX1276Read( REG_LR_IRQFLAGS, (u8*)&irq_flag);
|
||||
rf_flag = get_lora_status(irq_flag);
|
||||
|
||||
if (rf_flag != 0)
|
||||
{
|
||||
xQueueSendToBackFromISR( radioQueue, &rf_flag, &pxHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR( pxHigherPriorityTaskWoken );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "include.h"
|
||||
#include "hal_radio.h"
|
||||
|
||||
void vtask_mac_data_process(void *ptr);
|
||||
void mac_data_req(u8 *buf, u8 length);
|
||||
u8 * get_RF_bufPtr(void);
|
||||
u8 get_RF_bufLen();
|
||||
void read_radio_rssi(void);
|
||||
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hal_timer.c
|
||||
* @author William Liang
|
||||
* @version V1.0.0
|
||||
* @date 07/18/2013
|
||||
* @brief This file contains the initialization and handle of the timer.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "Rtc.h"
|
||||
#include "uart.h"
|
||||
#include "Mem.h"
|
||||
#include "Led.h"
|
||||
/** @addtogroup Timer
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
static const u8 daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
u32 g_SystickCounter = 0;
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Initialize the RTC.
|
||||
* @param None.
|
||||
* @retval None.
|
||||
*/
|
||||
void RTC_Init(void)
|
||||
{
|
||||
/* Enable PWR and BKP clocks */
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
|
||||
|
||||
/* Allow access to BKP Domain */
|
||||
PWR_BackupAccessCmd(ENABLE);
|
||||
|
||||
/* Select HSE as RTC Clock Source */
|
||||
RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);
|
||||
|
||||
//BKP_DeInit();
|
||||
|
||||
|
||||
if (BKP_ReadBackupRegister(RTC_VALID_REG) != RTC_VALID_FLAG)
|
||||
{
|
||||
|
||||
/* Enable RTC Clock */
|
||||
RCC_RTCCLKCmd(ENABLE);
|
||||
|
||||
//RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);
|
||||
|
||||
/* Wait for RTC registers synchronization */
|
||||
RTC_WaitForSynchro();
|
||||
|
||||
/* Wait until last write operation on RTC registers has finished */
|
||||
RTC_WaitForLastTask();
|
||||
|
||||
/* Set RTC prescaler: set RTC period to 1sec */
|
||||
RTC_SetPrescaler(RTC_PRESCALER); /* RTC period = RTCCLK/RTC_PR = (8 MHz /128)/(RTC_PRESCALER+1) */
|
||||
|
||||
/* Wait until last write operation on RTC registers has finished */
|
||||
RTC_WaitForLastTask();
|
||||
|
||||
/* Set RTC Valid Flag in the BKP */
|
||||
BKP_WriteBackupRegister(RTC_VALID_REG, RTC_VALID_FLAG);
|
||||
|
||||
/* Initialize current time to 2010/1/1 00:00:00 */
|
||||
Time_Set(17, 8, 17, 8, 23, 42);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Wait for RTC registers synchronization */
|
||||
RTC_WaitForSynchro();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief convert current time format from the total seconds since 2010 to the time struct.
|
||||
* @param utcTime: input variable, total seconds since 2010.
|
||||
* @retval time: the struct of current time.
|
||||
*/
|
||||
sTime TimetoBCD(u32 utcTime)
|
||||
{
|
||||
sTime time;
|
||||
|
||||
u32 secondsSince2010 = (utcTime - START_OF_2010);
|
||||
u16 daysSince2010 = (secondsSince2010 >> 2) / (u16)(SECS_IN_DAY >> 2);
|
||||
u32 secondInDay = secondsSince2010 - ((u32)daysSince2010) * SECS_IN_DAY;
|
||||
u8 yearsSince2000 = 0;
|
||||
u16 daysRemaining = daysSince2010;
|
||||
u16 accum = 10;//We start from 2010
|
||||
u8 phase;
|
||||
|
||||
for (phase = 0; phase < 2; phase++)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
u16 tick;
|
||||
|
||||
if (phase == 0)
|
||||
{
|
||||
tick = ((accum & 0x03) == 0 ? 366 : 365);
|
||||
}
|
||||
else
|
||||
{
|
||||
tick = daysInMonth[accum];
|
||||
if ((accum == 1) && ((yearsSince2000 & 0x03) == 0))
|
||||
{
|
||||
tick++;
|
||||
}
|
||||
}
|
||||
|
||||
if (tick <= daysRemaining)
|
||||
{
|
||||
daysRemaining -= tick;
|
||||
accum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (phase == 0)
|
||||
{
|
||||
yearsSince2000 = accum;
|
||||
accum = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
time.year = yearsSince2000;
|
||||
time.month = accum + 1;
|
||||
time.day = daysRemaining + 1;
|
||||
time.hour = secondInDay / 3600;
|
||||
time.minute = (secondInDay - time.hour * 3600) / 60;
|
||||
time.second = (secondInDay - time.hour * 3600) % 60;
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the current time.
|
||||
* @param year: input variable, the year of current time.
|
||||
* @param month: input variable, the month of current time.
|
||||
* @param day: input variable, the day of current time.
|
||||
* @param hour: input variable, the hour of current time.
|
||||
* @param min: input variable, the minute of current time.
|
||||
* @param sec: input variable, the second of current time.
|
||||
* @retval None.
|
||||
*/
|
||||
void Time_Set(u8 year, u8 month, u8 day, u8 hour, u8 min, u8 sec)
|
||||
{
|
||||
u32 secs = START_OF_2010 + (u32) hour * 3600 + (u32) min * 60 + (u32) sec;
|
||||
u16 days = day - 1;
|
||||
u8 i;
|
||||
|
||||
//printf("设置系统时间 %02d-%02d-%02d %02d:%02d:%02d\r\n", year, month, day, hour, min, sec);
|
||||
|
||||
for (i = 10; i < year; i++)
|
||||
{
|
||||
days += 365;
|
||||
if ((i & 0x03) == 0)
|
||||
{
|
||||
days++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < month - 1; i++)
|
||||
{
|
||||
days += daysInMonth[i];
|
||||
}
|
||||
|
||||
if ((month > 2) && ((year & 0x03) == 0))
|
||||
{
|
||||
days++;
|
||||
}
|
||||
|
||||
secs += ((u32) days) * SECS_IN_DAY;
|
||||
|
||||
/* Wait until last write operation on RTC registers has finished */
|
||||
RTC_WaitForLastTask();
|
||||
/* Change the current time */
|
||||
RTC_SetCounter(secs);
|
||||
/* Wait until last write operation on RTC registers has finished */
|
||||
RTC_WaitForLastTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the current time.
|
||||
* @param None.
|
||||
* @retval None.
|
||||
*/
|
||||
void Time_Get(void)
|
||||
{
|
||||
sTime CurrentTime;
|
||||
|
||||
CurrentTime = TimetoBCD(RTC_GetCounter());
|
||||
|
||||
printf("获取系统时间 %02d-%02d-%02d %02d:%02d:%02d %d\r\n",
|
||||
CurrentTime.year,
|
||||
CurrentTime.month,
|
||||
CurrentTime.day,
|
||||
CurrentTime.hour,
|
||||
CurrentTime.minute,
|
||||
CurrentTime.second,
|
||||
RTC_GetCounter()
|
||||
);
|
||||
}
|
||||
|
||||
void get_timeBCD(sTime * CTime)
|
||||
{
|
||||
sTime CurrentTime = TimetoBCD(RTC_GetCounter());
|
||||
|
||||
MemCpy(CTime, &CurrentTime, sizeof(sTime));
|
||||
}
|
||||
|
||||
/******************* (C) COPYRIGHT 2013 Robulink Technology Ltd.*****END OF FILE****/
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hal_rtc.h
|
||||
* @author William Liang
|
||||
* @version V1.0.0
|
||||
* @date 05/05/2014
|
||||
* @brief This file contains the headers of the rtc handlers.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef _RTC_H_
|
||||
#define _RTC_H_
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "Basedefine.h"
|
||||
|
||||
#define START_OF_2010 0
|
||||
#define SECS_IN_DAY 86400 // 24*3600
|
||||
|
||||
#define RTC_PRESCALER (HSE_VALUE / 128 - 1)
|
||||
#define RTC_VALID_REG BKP_DR1
|
||||
#define RTC_VALID_FLAG 0xA5A5
|
||||
#define GetRTCTime RTC_GetCounter
|
||||
|
||||
//ʱ¼ä
|
||||
typedef struct
|
||||
{
|
||||
u8 year;
|
||||
u8 month;
|
||||
u8 day;
|
||||
u8 hour;
|
||||
u8 minute;
|
||||
u8 second;
|
||||
}sTime;
|
||||
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void RTC_Init(void);
|
||||
sTime TimetoBCD(u32 utcTime);
|
||||
void Time_Set(u8 year, u8 month, u8 day, u8 hour, u8 min, u8 sec);
|
||||
void Time_Get(void);
|
||||
void get_timeBCD(sTime * CTime);
|
||||
|
||||
|
||||
#endif /* __HAL_TIMER_H__ */
|
||||
|
||||
/******************* (C) COPYRIGHT 2013 Robulink Technology Ltd.*****END OF FILE****/
|
||||
@@ -0,0 +1,415 @@
|
||||
#include "WaterMetermanager.h"
|
||||
#include "storage.h"
|
||||
#include "bl24c512.h"
|
||||
#include "include.h"
|
||||
#include "sx1276-Fsk.h"
|
||||
#include "rtc_ext.h"
|
||||
|
||||
|
||||
u16 read_maintain_time_ram(void);
|
||||
void Clear485PortINValidCount( void );
|
||||
//QueueHandle_t RfSendTask;
|
||||
//APP_OPER_COLLECT_MAN_UNIT_TYPE ManXTCollecterUnit; //转换器控制新天采集器数据以及任务单元
|
||||
//extern u8 HNSJ_chl ;
|
||||
static SJ_ADDRLIST_MANUNIT_TYPE SJManager = {0};
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
抄表数据以及水表档案存储读取管理任务
|
||||
------------------------------------------------------------------------------
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
//读取水表地址档案数量
|
||||
bool ReadAddrListLength( u8* Length )
|
||||
{
|
||||
u8 TempBuff[5] = {0x00};
|
||||
SP_SJ_ADDRLIST_MANUNIT_TYPE Pload = (SP_SJ_ADDRLIST_MANUNIT_TYPE)TempBuff;
|
||||
|
||||
if(Pload->ValidFlag == SHUANGJIA_MANAGERUNIT_VALID)
|
||||
{
|
||||
SJManager.ValidFlag = SHUANGJIA_MANAGERUNIT_VALID;
|
||||
*Length = Pload->AddrSum;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*Length = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//更新水表地址档案数量
|
||||
bool WriteAddrListLength( u8 Length )
|
||||
{
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//更新水表地址地址和数据
|
||||
bool WriteAddrListDataInfo( LPMETER_STRUCT_UNITTYPE Pload )
|
||||
{
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/*根据地址信息,获取某块水表的数据*/
|
||||
//当数据链表内,已经保存当前水表地址时,检查该水表数据是否有效,当无效时,返回00,表示从未监控到该水表数据
|
||||
//当数据链表内,未保存当前水表地址时,需要保存当前水表地址,并且标记数据区域无效,且返回00,方便集中器继续执行抄表动作。
|
||||
//三种情况。1.没有水表地址,2.有水表地址,但是数据无效,3.有水表地址,而且数据有效
|
||||
//save :是否保留当前地址信息
|
||||
RETURN_TYPE ReadAddrListDataInfo( LPMETER_STRUCT_UNITTYPE Pload ,bool Save)
|
||||
{
|
||||
u16 index = 0x00;
|
||||
RETURN_TYPE ret = NKNOW;
|
||||
|
||||
if(SJManager.ValidFlag != SHUANGJIA_MANAGERUNIT_VALID)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
for(index = 0x00; index < SJManager.AddrSum; index ++)
|
||||
{
|
||||
if((SJManager.Info[index].Index == index) && (SJManager.Info[index].Addr.AddrValidFlag == VALID_FLAG))
|
||||
if(MemCmp(Pload->Addr.Address,SJManager.Info[index].Addr.Address,ADDRESS_LENGTH) == 0x00)
|
||||
{
|
||||
if(SJManager.Info[index].Data.DataValidFlag == VALID_FLAG)
|
||||
{
|
||||
if(SJManager.Info[index].CRCV == GetCRC16(&SJManager.Info[index].Index, sizeof(METER_STRUCT_UNITTYPE) - sizeof(SJManager.Info[index].CRCV)))
|
||||
{
|
||||
ret = EXIST_ADDR_DATA_VALID;
|
||||
Pload->Index = index;
|
||||
Pload->Data.BCD_Decimal = SJManager.Info[index].Data.BCD_Decimal;
|
||||
Pload->Data.BCD_Integer_L = SJManager.Info[index].Data.BCD_Integer_L;
|
||||
Pload->Data.BCD_Integer_M = SJManager.Info[index].Data.BCD_Integer_M;
|
||||
Pload->Data.BCD_Integer_H = SJManager.Info[index].Data.BCD_Integer_H;
|
||||
Pload->Data.FailCount = SJManager.Info[index].Data.FailCount;
|
||||
Pload->Data.StateFlag0 = SJManager.Info[index].Data.StateFlag0;
|
||||
Pload->Data.StateFlag1 = SJManager.Info[index].Data.StateFlag1;
|
||||
memcpy(&Pload->Index,&SJManager.Info[index].Index, sizeof(METER_STRUCT_UNITTYPE));
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pload->Index = index;
|
||||
Pload->Data.FailCount = SJManager.Info[index].Data.FailCount;
|
||||
memcpy(&Pload->Index,&SJManager.Info[index].Index, sizeof(METER_STRUCT_UNITTYPE));
|
||||
ret = EXIST_ADDR_CRC_ERROR;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Pload->Index = index;
|
||||
Pload->Data.FailCount = SJManager.Info[index].Data.FailCount;
|
||||
memcpy(&Pload->Index,&SJManager.Info[index].Index, sizeof(METER_STRUCT_UNITTYPE));
|
||||
ret = EXIST_ADDR_DATA_INVALID; //存在地址但是数据无效
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// u8 Index;
|
||||
// METER_ADDR_UNITTYPE Addr;
|
||||
// METER_DATA_UNITTYPE Data;
|
||||
// u16 CRCV;
|
||||
|
||||
if( Save == false) return NO_EXIST_ADDR;
|
||||
|
||||
SJManager.AddrSum ++;
|
||||
|
||||
SJManager.Info[index].Index = index;
|
||||
|
||||
SJManager.Info[index].Addr.AddrValidFlag = VALID_FLAG;
|
||||
MemCpy(SJManager.Info[index].Addr.Address,Pload->Addr.Address,ADDRESS_LENGTH);
|
||||
|
||||
SJManager.Info[index].Data.DataValidFlag = INVALID_FLAG;
|
||||
SJManager.Info[index].Data.BCD_Decimal = 0x00;
|
||||
SJManager.Info[index].Data.BCD_Integer_H = 0x00;
|
||||
SJManager.Info[index].Data.BCD_Integer_L = 0x00;
|
||||
SJManager.Info[index].Data.BCD_Integer_M = 0x00;
|
||||
//当前地址不存在
|
||||
SJManager.Info[index].Data.FailCount = 0x00;
|
||||
Pload->Data.BCD_Decimal = SJManager.Info[index].Data.BCD_Decimal;
|
||||
Pload->Data.BCD_Integer_L = SJManager.Info[index].Data.BCD_Integer_L;
|
||||
Pload->Data.BCD_Integer_M = SJManager.Info[index].Data.BCD_Integer_M;
|
||||
Pload->Data.BCD_Integer_H = SJManager.Info[index].Data.BCD_Integer_H;
|
||||
|
||||
SJManager.Info[index].CRCV = GetCRC16(&SJManager.Info[index].Index, sizeof(METER_STRUCT_UNITTYPE) - sizeof(SJManager.Info[index].CRCV));
|
||||
|
||||
WriteAddrListLength(SJManager.AddrSum);
|
||||
WriteAddrListDataInfo(&SJManager.Info[index]);
|
||||
|
||||
return NO_EXIST_ADDR;
|
||||
}
|
||||
|
||||
|
||||
void ReadSystemMeterAddrList( void )
|
||||
{
|
||||
//u8 Length = 0x00;
|
||||
u8 index = 0x00;
|
||||
|
||||
//if(ReadAddrListLength( &Length ) == false)
|
||||
if(SJManager.AddrSum == 00)
|
||||
{
|
||||
printf("Water Meter SUM is 0\r\n");
|
||||
return ;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Water Meter SUM is %03d\r\n",SJManager.AddrSum);
|
||||
}
|
||||
printf("\r\n-序号---------地址-----------水表示数---------水表状态---------抄表时间\r\n");
|
||||
for(index = 0x00 ; index < SJManager.AddrSum; index ++)
|
||||
{
|
||||
|
||||
if(SJManager.Info[index].Addr.AddrValidFlag == VALID_FLAG)
|
||||
{
|
||||
printf(" %03d: %02X%02X%02X%02X%02X%02X%02X",index,SJManager.Info[index].Addr.Address[6],SJManager.Info[index].Addr.Address[5],SJManager.Info[index].Addr.Address[4],SJManager.Info[index].Addr.Address[3],SJManager.Info[index].Addr.Address[2],SJManager.Info[index].Addr.Address[1],SJManager.Info[index].Addr.Address[0]);
|
||||
if(SJManager.Info[index].Data.DataValidFlag == VALID_FLAG)
|
||||
{//新版本转换器使用的是内部时钟
|
||||
printf(" %02X%02X%02X.%02X %02X%02X %02d.%02d.%02d %02d:%02d:%02d\r\n",
|
||||
SJManager.Info[index].Data.BCD_Integer_H,SJManager.Info[index].Data.BCD_Integer_M,SJManager.Info[index].Data.BCD_Integer_L,SJManager.Info[index].Data.BCD_Decimal,SJManager.Info[index].Data.StateFlag0,SJManager.Info[index].Data.StateFlag1,SJManager.Info[index].Data.TYaer,SJManager.Info[index].Data.TMonth,SJManager.Info[index].Data.TDay,SJManager.Info[index].Data.THour,SJManager.Info[index].Data.TMin,SJManager.Info[index].Data.TSec);
|
||||
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
printf(" --------\r\n");
|
||||
}
|
||||
vTaskDelay( 50 / portTICK_RATE_MS );
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool manager_get_data(u8 * addr,u8* data,u8* state,u8 * state2)
|
||||
{
|
||||
for(u8 i = 0;i<SJManager.AddrSum;i++)
|
||||
{
|
||||
// if(SJManager.Info[i].Addr.AddrValidFlag == VALID_FLAG)
|
||||
{
|
||||
if(0 == memcmp(addr,SJManager.Info[i].Addr.Address,6))
|
||||
{
|
||||
if(SJManager.Info[i].Data.DataValidFlag == VALID_FLAG)
|
||||
{
|
||||
data[0] = SJManager.Info[i].Data.BCD_Decimal;
|
||||
data[1] = SJManager.Info[i].Data.BCD_Integer_L;
|
||||
data[2] = SJManager.Info[i].Data.BCD_Integer_M;
|
||||
data[3] = SJManager.Info[i].Data.BCD_Integer_H;
|
||||
* state = SJManager.Info[i].Data.StateFlag0;
|
||||
* state2 = SJManager.Info[i].Data.StateFlag1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool UpdateRFReceiveData(u8* addr,u8* data,u8* status)
|
||||
{
|
||||
RETURN_TYPE ret = NKNOW;
|
||||
sTime Temp_Time;
|
||||
bool Save = false;
|
||||
u8 TempBuff[sizeof(METER_STRUCT_UNITTYPE)] = {0x00};
|
||||
LPMETER_STRUCT_UNITTYPE Pstr = (LPMETER_STRUCT_UNITTYPE)TempBuff;
|
||||
|
||||
MemCpy(Pstr->Addr.Address,addr,ADDRESS_LENGTH);
|
||||
|
||||
//不能保存当前接收的地址,只做读取当前地址的水表数据检查
|
||||
ret = ReadAddrListDataInfo( Pstr ,false);
|
||||
|
||||
if(EXIST_ADDR_DATA_VALID == ret)
|
||||
{
|
||||
if(MemCmp(&Pstr->Data.BCD_Decimal,data,METER_DATA_MAX_SIZE) == 0x00)
|
||||
{
|
||||
//return false;
|
||||
Save = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Save = true;
|
||||
}
|
||||
}
|
||||
else if((EXIST_ADDR_DATA_INVALID == ret) || (EXIST_ADDR_CRC_ERROR == ret))
|
||||
{
|
||||
Save = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(true == Save)
|
||||
{
|
||||
Clear485PortINValidCount();
|
||||
//GetExternClockTime(&Temp_Time);
|
||||
get_timeBCD(&Temp_Time);
|
||||
|
||||
Pstr->Addr.AddrValidFlag = VALID_FLAG;
|
||||
Pstr->Data.DataValidFlag = VALID_FLAG;
|
||||
MemCpy(&Pstr->Data.BCD_Decimal,data,METER_DATA_MAX_SIZE);
|
||||
|
||||
Pstr->Data.FailCount = 0x00;
|
||||
Pstr->Data.StateFlag0 = status[0];
|
||||
Pstr->Data.StateFlag1 = status[1];
|
||||
Pstr->Data.TYaer = Temp_Time.year;
|
||||
Pstr->Data.TMonth= Temp_Time.month;
|
||||
Pstr->Data.TDay = Temp_Time.day;
|
||||
Pstr->Data.THour = Temp_Time.hour;
|
||||
Pstr->Data.TMin = Temp_Time.minute;
|
||||
Pstr->Data.TSec = Temp_Time.second;
|
||||
|
||||
Pstr->CRCV = GetCRC16(TempBuff, sizeof(METER_STRUCT_UNITTYPE) - sizeof(Pstr->CRCV));
|
||||
|
||||
MemCpy(&SJManager.Info[Pstr->Index].Index,&Pstr->Index,sizeof(METER_STRUCT_UNITTYPE));
|
||||
WriteAddrListDataInfo( Pstr );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool UpdataWMRMFailCounterProcess(u8* addr)
|
||||
{
|
||||
RETURN_TYPE ret = NKNOW;
|
||||
//sTime Temp_Time;
|
||||
bool Save = true;
|
||||
u8 TempBuff[sizeof(METER_STRUCT_UNITTYPE)] = {0x00};
|
||||
LPMETER_STRUCT_UNITTYPE Pstr = (LPMETER_STRUCT_UNITTYPE)TempBuff;
|
||||
|
||||
MemCpy(Pstr->Addr.Address,addr,ADDRESS_LENGTH);
|
||||
|
||||
//不能保存当前接收的地址,只做读取当前地址的水表数据检查
|
||||
ret = ReadAddrListDataInfo( Pstr ,false);
|
||||
|
||||
if( (ret == EXIST_ADDR_DATA_VALID) || (ret == EXIST_ADDR_CRC_ERROR) || (ret == EXIST_ADDR_DATA_INVALID) )
|
||||
{
|
||||
Pstr->Data.FailCount ++;
|
||||
|
||||
if(true == Save)
|
||||
{
|
||||
//GetExternClockTime(&Temp_Time);
|
||||
//get_timeBCD(&Temp_Time);
|
||||
|
||||
//Pstr->Addr.AddrValidFlag = VALID_FLAG;
|
||||
|
||||
Pstr->CRCV = GetCRC16(TempBuff, sizeof(METER_STRUCT_UNITTYPE) - sizeof(Pstr->CRCV));
|
||||
|
||||
MemCpy(&SJManager.Info[Pstr->Index].Index,&Pstr->Index,sizeof(METER_STRUCT_UNITTYPE));
|
||||
|
||||
//WriteAddrListDataInfo( Pstr );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CopyEEPROMInfoToRAM( void )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SJMeterInfoInit( void )
|
||||
{
|
||||
if(ReadAddrListLength( &SJManager.AddrSum ) == false)
|
||||
{
|
||||
SJManager.ValidFlag = SHUANGJIA_MANAGERUNIT_VALID;
|
||||
WriteAddrListLength( 00 );
|
||||
return ;
|
||||
}
|
||||
|
||||
CopyEEPROMInfoToRAM( );
|
||||
}
|
||||
|
||||
|
||||
void ClearMeterInfo( void )
|
||||
{
|
||||
|
||||
SJManager.AddrSum = 0x00;
|
||||
WriteAddrListLength( 00 );
|
||||
MemSet((u8*)&SJManager.Info[0].Index,0x00, sizeof(METER_STRUCT_UNITTYPE)*ADDR_LIST_LENGTH);
|
||||
printf("Success !!\r\n");
|
||||
}
|
||||
|
||||
void ClearMeterInfo_realdl( void )
|
||||
{
|
||||
SJManager.AddrSum = 0;
|
||||
}
|
||||
|
||||
|
||||
u8 GetCurrentAddrListLength( void )
|
||||
{
|
||||
return SJManager.AddrSum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool CheckDataStoreTime(u8* CurTim,u8* StoreTime,u32 MaxT)
|
||||
{
|
||||
sTime * curt = (sTime *)CurTim;
|
||||
PLst_rtc_ext storet = (PLst_rtc_ext)StoreTime;
|
||||
|
||||
|
||||
//u32 curt_hour = (BCDToHex(curt->year) * 365 * 24) + (BCDToHex(curt->month) * 30 * 24) + (BCDToHex(curt->day) * 24) + BCDToHex(curt->hour);
|
||||
u32 curt_hour = ((curt->year) * 365 * 24) + ((curt->month) * 30 * 24) + ((curt->day) * 24) + (curt->hour);//当前时间使用的是内部RTC,不是BCD码
|
||||
//u32 storet_hour = (BCDToHex(storet->year) * 365 * 24) + (BCDToHex(storet->month) * 30 * 24) + (BCDToHex(storet->day) * 24) + BCDToHex(storet->hour);
|
||||
u32 storet_hour = ((storet->year) * 365 * 24) + ((storet->month) * 30 * 24) + ((storet->day) * 24) + (storet->hour);
|
||||
|
||||
if(curt_hour > (storet_hour + MaxT))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(curt_hour < storet_hour)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ClearMeterDataTimeOuttime( void )
|
||||
{
|
||||
u8 index = 0x00;
|
||||
sTime Temp_Time;
|
||||
|
||||
//GetExternClockTime(&Temp_Time);
|
||||
|
||||
get_timeBCD(&Temp_Time);
|
||||
for(index = 0x00 ; index < SJManager.AddrSum; index ++)
|
||||
{
|
||||
if( (SJManager.Info[index].Addr.AddrValidFlag == VALID_FLAG) && (SJManager.Info[index].Data.DataValidFlag == VALID_FLAG) )
|
||||
{
|
||||
if(CheckDataStoreTime((u8*)&Temp_Time.year,&SJManager.Info[index].Data.TSec,read_maintain_time_ram()) == false)
|
||||
{
|
||||
SJManager.Info[index].Data.DataValidFlag = INVALID_FLAG;
|
||||
SJManager.Info[index].Data.FailCount = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
#ifndef WATERMETER_MANAGER_H__
|
||||
#define WATERMETER_MANAGER_H__
|
||||
|
||||
|
||||
#include "include.h"
|
||||
|
||||
#define SHUANGJIA_MANAGERUNIT_VALID (0x12345679)
|
||||
#define ADDRESS_LENGTH (7)
|
||||
#define METER_DATA_MAX_SIZE (4)
|
||||
#define ADDR_LIST_LENGTH (0xFF)
|
||||
|
||||
#define VALID_FLAG (0xAA)
|
||||
#define INVALID_FLAG (0x55)
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 AddrValidFlag;
|
||||
u8 Address[ADDRESS_LENGTH];
|
||||
}METER_ADDR_UNITTYPE,* LPMETER_ADDR_UNITTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//u8 Data[METER_DATA_MAX_SIZE];
|
||||
u8 DataValidFlag;
|
||||
u8 BCD_Decimal;
|
||||
u8 BCD_Integer_L;
|
||||
u8 BCD_Integer_M;
|
||||
u8 BCD_Integer_H;
|
||||
|
||||
|
||||
u8 FailCount;//抄表失败计数
|
||||
|
||||
u8 StateFlag0;
|
||||
u8 StateFlag1;
|
||||
|
||||
u8 TSec;
|
||||
u8 TMin;
|
||||
u8 THour;
|
||||
u8 TDay;
|
||||
u8 TMonth;
|
||||
u8 TYaer;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}METER_DATA_UNITTYPE,* LPMETER_DATA_UNITTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 Index;
|
||||
METER_ADDR_UNITTYPE Addr;
|
||||
METER_DATA_UNITTYPE Data;
|
||||
u16 CRCV;
|
||||
}METER_STRUCT_UNITTYPE, * LPMETER_STRUCT_UNITTYPE;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NKNOW = 0x00, //未知
|
||||
EXIST_ADDR_DATA_INVALID, //存在地址但是数据无效
|
||||
EXIST_ADDR_DATA_VALID, //存在地址但是数据有效
|
||||
EXIST_ADDR_CRC_ERROR, //存在地址但数据CRC校验错误
|
||||
|
||||
ADDR_OVERFLOW,
|
||||
NO_EXIST_ADDR, //不存在地址
|
||||
}RETURN_TYPE;
|
||||
//新天采集器地址档案数据管理单元
|
||||
typedef struct
|
||||
{
|
||||
u32 ValidFlag;
|
||||
u8 AddrSum; //地址总长度
|
||||
|
||||
METER_STRUCT_UNITTYPE Info[ADDR_LIST_LENGTH]; //当前数据存储信息
|
||||
|
||||
}SJ_ADDRLIST_MANUNIT_TYPE,* SP_SJ_ADDRLIST_MANUNIT_TYPE;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void SJMeterInfoInit( void );
|
||||
bool UpdateRFReceiveData(u8* addr,u8* data,u8* status);
|
||||
RETURN_TYPE ReadAddrListDataInfo( LPMETER_STRUCT_UNITTYPE Pload ,bool Save);
|
||||
void ClearMeterDataTimeOuttime( void );
|
||||
bool UpdataWMRMFailCounterProcess(u8* addr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //WATERMETER_MANAGER_H__
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
#include "addr.h"
|
||||
#include "Mem.h"
|
||||
#include "General.h"
|
||||
#include "Flash.h"
|
||||
|
||||
extern void addr_set(u8 * addr);
|
||||
|
||||
static u8 broadcast_addr[6] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
static u8 broadcast_addr_1[6] = {0x99, 0x99, 0x99, 0x99, 0x99, 0x99};
|
||||
|
||||
static u8 local_addr[6] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
|
||||
|
||||
u8 cmp_addr(u8 *addr)
|
||||
{
|
||||
if (cmp_datas(addr, local_addr, 6))
|
||||
{
|
||||
return ADDR_EQ;
|
||||
}
|
||||
else if (cmp_datas(addr, broadcast_addr, 6))
|
||||
{
|
||||
return BRODCAST_ADDRAA_EQ;
|
||||
}
|
||||
else if (cmp_datas(addr, broadcast_addr_1, 6))
|
||||
{
|
||||
return BRODCAST_ADDR99_EQ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ADDR_NEQ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
u8 * read_broadcast_addr(void)
|
||||
{
|
||||
return broadcast_addr;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : set_addr
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void set_addr(u8 *newaddr)
|
||||
{
|
||||
u8 local_temp[8];
|
||||
u16 crc;
|
||||
|
||||
//ÊäÈëÊÇÕýÐò£¬´æ´¢·´Ðò
|
||||
//memcpy(local_addr, newaddr, 6);
|
||||
//memcpy(local_temp, newaddr, 6);
|
||||
|
||||
memset(local_temp,0,sizeof(local_temp));
|
||||
memset(local_addr,0,sizeof(local_addr));
|
||||
|
||||
|
||||
for (u8 i = 0; i < 6; i++)
|
||||
{
|
||||
local_addr[i] = newaddr[5 - i];
|
||||
local_temp[i] = newaddr[5 - i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// memmove(local_addr,&newaddr[1],5);
|
||||
// memmove(local_temp,&newaddr[1],5);
|
||||
// addr_set(&newaddr[1]);
|
||||
|
||||
crc = GetCRC16(local_addr, 6);
|
||||
|
||||
local_temp[6] = crc & 0xFF;
|
||||
local_temp[7] = (u8)((crc >> 8) & 0xFF);
|
||||
|
||||
if (STM32_FlashPageErase(FLASH_LOCAL_ADDR_ADDRESS) == FLH_SUCCESS)
|
||||
{
|
||||
STM32_FlashWrite( FLASH_LOCAL_ADDR_ADDRESS, local_temp, 8);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : read_addr
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
bool read_addr(u8 *addrbuf )
|
||||
{
|
||||
u8 tempaddr[8];
|
||||
u16 crc;
|
||||
|
||||
memcpy(&tempaddr, (u8*)FLASH_LOCAL_ADDR_ADDRESS, sizeof(tempaddr));
|
||||
|
||||
crc = GetCRC16(tempaddr, 6);
|
||||
|
||||
if (crc == (tempaddr[6] + tempaddr[7]*256) )
|
||||
{
|
||||
memcpy(addrbuf, tempaddr, 6);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(addrbuf, local_addr, 6);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void init_local_addr(void)
|
||||
{
|
||||
u8 temp[6];
|
||||
if (read_addr(temp) )
|
||||
{
|
||||
memcpy(local_addr,temp, 6);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
u8 * addr_get()
|
||||
{
|
||||
return local_addr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#ifndef __ADDR_H__
|
||||
#define __ADDR_H__
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
#define FLASH_LOCAL_ADDR_ADDRESS 0x08004c00
|
||||
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
ADDR_NEQ = 0,
|
||||
ADDR_EQ,
|
||||
BRODCAST_ADDRAA_EQ,
|
||||
BRODCAST_ADDR99_EQ
|
||||
};
|
||||
|
||||
bool cmp_datas(u8 * buf1, u8* buf2, u8 length);
|
||||
u8 cmp_addr(u8 *addr);
|
||||
void set_addr(u8 *newaddr);
|
||||
bool read_addr(u8 *addrbuf);
|
||||
u8 * read_broadcast_addr(void);
|
||||
void init_local_addr(void);
|
||||
bool read_unique_id(u8 * id);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file apl.c
|
||||
* @author William Liang
|
||||
* @version V1.0.0
|
||||
* @date 07/26/2013
|
||||
* @brief This file contains application layer task and the initializtion of the variable.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "Basedefine.h"
|
||||
#include "apl.h"
|
||||
|
||||
//应用层版本
|
||||
// __root 保证没有使用的函数或者变量也能够包含在目标代码中
|
||||
__root const Manufacturer_Version aplVersion =
|
||||
{
|
||||
{'H', 'T',},//厂商代码
|
||||
{'T', 'X'},//芯片代码,表示全部所有共计8种转换器协议
|
||||
0x14, 0x12, 0x21,//日月年
|
||||
{0x09, 0x02}//版本
|
||||
};
|
||||
|
||||
|
||||
const Manufacturer_Version * get_apl_version_ptr(void)
|
||||
{
|
||||
return &aplVersion;
|
||||
}
|
||||
|
||||
|
||||
|
||||
u8 * get_veryw()
|
||||
{
|
||||
|
||||
return (u8 *)&aplVersion;
|
||||
}
|
||||
|
||||
void ReadVersion(void)
|
||||
{
|
||||
u8 buf[sizeof(Manufacturer_Version)];
|
||||
|
||||
buf[0] = aplVersion.venderID[0];
|
||||
buf[1] = aplVersion.venderID[1];
|
||||
buf[2] = aplVersion.chipID[0];
|
||||
buf[3] = aplVersion.chipID[1];
|
||||
buf[4] = aplVersion.date;
|
||||
buf[5] = aplVersion.month;
|
||||
buf[6] = aplVersion.year;
|
||||
buf[7] = aplVersion.version[0];
|
||||
buf[8] = aplVersion.version[1];
|
||||
|
||||
printf("APL Version=%c%c%c%c-%02x%02x%02x-V%02x.%02x\r\n", \
|
||||
buf[1], buf[0], buf[3], buf[2], buf[6], buf[5], buf[4], buf[8], buf[7]);
|
||||
|
||||
}
|
||||
|
||||
/************** (C) COPYRIGHT 2013 Robulink Technology Ltd.*****END OF FILE****/
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file apl.h
|
||||
* @author William Liang
|
||||
* @version V1.0.0
|
||||
* @date 07/26/2013
|
||||
* @brief This file contains the headers of the application layer.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __APL_H__
|
||||
#define __APL_H__
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 venderID[2];//const 厂商代码
|
||||
u8 chipID[2];//const 芯片代码
|
||||
u8 date;//const 日
|
||||
u8 month;//const 月
|
||||
u8 year;//const 年
|
||||
u8 version[2];//const 版本
|
||||
}Manufacturer_Version;
|
||||
|
||||
|
||||
const Manufacturer_Version * get_apl_version_ptr(void);
|
||||
void ReadVersion(void);
|
||||
|
||||
#endif /* __APL_H__ */
|
||||
|
||||
/******************* (C) COPYRIGHT 2013 Robulink Technology Ltd.*****END OF FILE****/
|
||||
+673
@@ -0,0 +1,673 @@
|
||||
#include "bl24c512.h"
|
||||
#include "include.h"
|
||||
|
||||
|
||||
|
||||
static u32 last_write_time;
|
||||
bool I2C_eeprom_write_byte( u16 addr, u8 data);
|
||||
bool I2C_eeprom_Read_byte(u16 addr, u8 *data);
|
||||
|
||||
void eeprom_da_mode(bool in_mode)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = SDA_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = (in_mode == TRUE) ? GPIO_Mode_IN_FLOATING : GPIO_Mode_Out_OD;
|
||||
GPIO_Init(SDA_PIN_PORT, &GPIO_InitStructure );
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = SCL_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init(SCL_PIN_PORT , &GPIO_InitStructure );
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
函数功能:延时连个指令周期
|
||||
函数名称:delayedus
|
||||
函数返回:无返回值。
|
||||
函数参数:延时时间
|
||||
**************************************************************/
|
||||
void delayed_ms(u8 n)
|
||||
{
|
||||
u32 dy;
|
||||
u8 i;
|
||||
for(i=0;i<n;i++)
|
||||
{
|
||||
dy=3200;
|
||||
while(dy!=0)
|
||||
{dy--;}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void delayedus(u8 n)
|
||||
{
|
||||
u8 i;
|
||||
for(i=0;i<n;i++);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:I2C总线复位。
|
||||
函数名称:I2C_Reset。
|
||||
函数返回:无返回值。
|
||||
函数参数:无参数
|
||||
**************************************************************/
|
||||
void I2C_Reset(void)
|
||||
{
|
||||
eeprom_da_mode(SDA_MODE_IN);
|
||||
|
||||
while(1)
|
||||
{
|
||||
SCL_LOW();
|
||||
delayedus(1);
|
||||
SCL_HIGH();
|
||||
if( GET_SDA() ==1 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
delayedus(1);
|
||||
}
|
||||
eeprom_da_mode(SDA_MODE_OUT);
|
||||
}
|
||||
|
||||
|
||||
void bl24c512_init(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
RCC_APB2PeriphClockCmd(SDA_PIN_CLK | SCL_PIN_CLK , ENABLE);
|
||||
|
||||
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = SDA_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
|
||||
GPIO_Init(SDA_PIN_PORT , &GPIO_InitStructure );
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = SCL_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init(SCL_PIN_PORT , &GPIO_InitStructure );
|
||||
|
||||
//I2C_Reset();
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
函数功能:产生起始位。
|
||||
函数名称:I2C_GenerateSTART。
|
||||
函数返回:无返回值。
|
||||
函数参数:无参数
|
||||
**************************************************************/
|
||||
void BL24C512I2C_GenerateSTART(void)
|
||||
{
|
||||
SDA_HIGH();//eeprom_da(1);
|
||||
SCL_HIGH();//eeprom_clk(1);
|
||||
delayedus(2);
|
||||
SDA_LOW();//eeprom_da(0);
|
||||
delayedus(2);
|
||||
SCL_LOW();//eeprom_clk(0);
|
||||
delayedus(2);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:产生停始位。
|
||||
函数名称:I2C_GenerateSTOP。
|
||||
函数返回:无返回值。
|
||||
函数参数:无参数
|
||||
**************************************************************/
|
||||
void BL24C512_I2C_GenerateSTOP(void)
|
||||
{
|
||||
SDA_LOW();//eeprom_da(0);
|
||||
delayedus(2);
|
||||
SCL_HIGH();//eeprom_clk(1);
|
||||
SDA_LOW();//eeprom_da(0);
|
||||
delayedus(2);
|
||||
SDA_HIGH();//eeprom_da(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void self_test_eeprom(void)
|
||||
{
|
||||
char testBuf[] = "test eeprom";
|
||||
char buf[15] = {0};
|
||||
|
||||
I2C_eeprom_write_buf(32896, (u8*)testBuf, sizeof(testBuf));
|
||||
I2C_eeprom_read_buf( 32896, (u8*)buf, sizeof(testBuf));
|
||||
|
||||
if (cmp_datas((u8*)buf, (u8*)testBuf, sizeof(testBuf)))
|
||||
{
|
||||
printf("OK\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ERROR\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:检测应答。
|
||||
函数名称:I2C_check_ack。
|
||||
函数返回:返回值是应答状态。
|
||||
函数参数:无参数。
|
||||
**************************************************************/
|
||||
unsigned char I2C_check_ack(void)
|
||||
{
|
||||
unsigned char ack=0;
|
||||
eeprom_da_mode(SDA_MODE_IN);
|
||||
SCL_HIGH();//eeprom_clk(1);
|
||||
delayedus(1);
|
||||
if(GET_SDA() ==1)
|
||||
{
|
||||
ack=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ack=1;
|
||||
}
|
||||
SCL_LOW();//eeprom_clk(0);
|
||||
delayedus(1);
|
||||
eeprom_da_mode(SDA_MODE_OUT);
|
||||
return ack;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:发送一个应答位。
|
||||
函数名称:I2c_send_ack。
|
||||
函数返回:无返回值。
|
||||
函数参数:无。
|
||||
**************************************************************/
|
||||
void I2c_send_ack(void)
|
||||
{
|
||||
SDA_LOW();//eeprom_da(0);
|
||||
delayedus(1);
|
||||
SCL_LOW();//eeprom_clk(0);
|
||||
delayedus(1);
|
||||
SCL_HIGH();//eeprom_clk(1);
|
||||
delayedus(1);
|
||||
SCL_LOW();//eeprom_clk(0);
|
||||
SDA_HIGH();//eeprom_da(1);
|
||||
}
|
||||
/*************************************************************
|
||||
函数功能:发送一个NO应答。
|
||||
函数名称:I2c_send_no_ack。
|
||||
函数返回:无返回值。
|
||||
函数参数:无。
|
||||
*************************************************************/
|
||||
void I2c_send_no_ack(void)
|
||||
{
|
||||
SDA_HIGH();//eeprom_da(1);
|
||||
delayedus(1);
|
||||
SCL_LOW();//eeprom_clk(0);
|
||||
delayedus(1);
|
||||
SCL_HIGH();//eeprom_clk(1);
|
||||
delayedus(1);
|
||||
SCL_LOW();//eeprom_clk(0);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:I2C发送一个字节。
|
||||
函数名称:I2c_send_byte。
|
||||
函数返回:无返回值。
|
||||
函数参数:无。
|
||||
*************************************************************/
|
||||
void I2c_send_byte(unsigned char data )
|
||||
{
|
||||
unsigned char i;
|
||||
SCL_LOW(); //eeprom_clk(0);//clk 0
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if((data&0x80)==0x80)
|
||||
{
|
||||
SDA_HIGH();//eeprom_da(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDA_LOW(); //eeprom_da(0);
|
||||
}
|
||||
SCL_HIGH(); //eeprom_clk(1);//clk 1
|
||||
delayedus(1);
|
||||
SCL_LOW(); //eeprom_clk(0);//clk 0
|
||||
delayedus(1);
|
||||
data<<=1;
|
||||
}
|
||||
delayedus(90);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:I2C接收一个字节。
|
||||
函数名称:I2c_receive_byte。
|
||||
函数返回:无返回值。
|
||||
函数参数:无。
|
||||
**************************************************************/
|
||||
unsigned char I2c_receive_byte(void)
|
||||
{
|
||||
unsigned char i;
|
||||
unsigned char rda=0;
|
||||
eeprom_da_mode(SDA_MODE_IN);
|
||||
|
||||
SCL_LOW(); //eeprom_clk(0);//clk 0
|
||||
delayedus(1);
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
rda<<=1;
|
||||
SCL_HIGH(); //eeprom_clk(1);//clk 1
|
||||
delayedus(1);
|
||||
if(GET_SDA() ==1 )
|
||||
{
|
||||
rda|=0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
rda&=0xFE;
|
||||
}
|
||||
|
||||
SCL_LOW(); //eeprom_clk(0);//clk 0
|
||||
delayedus(1);
|
||||
}
|
||||
eeprom_da_mode(SDA_MODE_OUT);
|
||||
|
||||
return rda;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:EEPROM检测EEPROM是否空闲,可以进行读写
|
||||
函数名称:poll_busy。
|
||||
函数返回:无返回值。
|
||||
函数参数:EEPROM的地址addr ,对应写入数据data。
|
||||
**************************************************************/
|
||||
bool poll_busy(void)
|
||||
{
|
||||
|
||||
BL24C512I2C_GenerateSTART();
|
||||
|
||||
I2c_send_byte(BL24C512ADDR);
|
||||
|
||||
if(I2C_check_ack()== 1)
|
||||
{
|
||||
BL24C512_I2C_GenerateSTOP();
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
BL24C512_I2C_GenerateSTOP();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void wait_eeprom_free(void)
|
||||
{
|
||||
while( last_write_time + 6/portTICK_RATE_MS > xTaskGetTickCount() );
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (poll_busy())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
函数功能:EEPROM任意地址写一字节。
|
||||
函数名称:I2C_eeprom_write_byte。
|
||||
函数返回:无返回值。
|
||||
函数参数:EEPROM的地址addr ,对应写入数据data。
|
||||
**************************************************************/
|
||||
bool I2C_eeprom_write_byte( u16 addr, u8 data)
|
||||
{
|
||||
unsigned char addrlow;
|
||||
unsigned char addrhigh;
|
||||
|
||||
|
||||
addrlow=(unsigned char)addr;
|
||||
addrhigh=(unsigned char)(addr>>8);
|
||||
|
||||
wait_eeprom_free();
|
||||
|
||||
BL24C512I2C_GenerateSTART();
|
||||
I2c_send_byte(BL24C512ADDR);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I2c_send_byte(addrhigh);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I2c_send_byte(addrlow);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I2c_send_byte(data);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BL24C512_I2C_GenerateSTOP();
|
||||
|
||||
last_write_time = xTaskGetTickCount();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:EEPROM任意地址读一字节。
|
||||
函数名称:I2C_eeprom_Read_byte。
|
||||
函数返回:无返回值。
|
||||
函数参数:EEPROM的地址addr。
|
||||
**************************************************************/
|
||||
bool I2C_eeprom_Read_byte(u16 addr, u8 *data)
|
||||
{
|
||||
unsigned char devaddr=0;
|
||||
unsigned char addrlow=0;
|
||||
unsigned char addrhigh=0;
|
||||
|
||||
addrlow=(unsigned char)addr;
|
||||
addrhigh=(unsigned char)(addr>>8);
|
||||
|
||||
wait_eeprom_free();
|
||||
|
||||
BL24C512I2C_GenerateSTART();
|
||||
I2c_send_byte(BL24C512ADDR);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I2c_send_byte(addrhigh);
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I2c_send_byte(addrlow);
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
devaddr=(BL24C512ADDR| 0X01);
|
||||
BL24C512I2C_GenerateSTART();
|
||||
|
||||
I2c_send_byte(devaddr);
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
*data=I2c_receive_byte();
|
||||
I2c_send_no_ack();
|
||||
delayedus(1);
|
||||
BL24C512_I2C_GenerateSTOP();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:EEPROM写入数组,只能写入小于128byte数据,并且不能超过页范围
|
||||
函数名称:I2C_eeprom_write_buf
|
||||
函数返回:无返回值。
|
||||
函数参数:EEPROM的地址addr。
|
||||
**************************************************************/
|
||||
bool I2C_eeprom_write_page(u16 addr, u8 * buf, u8 length)
|
||||
{
|
||||
unsigned char addrlow;
|
||||
unsigned char addrhigh;
|
||||
|
||||
|
||||
addrlow=(unsigned char)addr;
|
||||
addrhigh=(unsigned char)(addr>>8);
|
||||
|
||||
wait_eeprom_free();
|
||||
|
||||
BL24C512I2C_GenerateSTART();
|
||||
I2c_send_byte(BL24C512ADDR);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I2c_send_byte(addrhigh);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I2c_send_byte(addrlow);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (u8 i = 0; i < length; i++)
|
||||
{
|
||||
I2c_send_byte(buf[i]);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BL24C512_I2C_GenerateSTOP();
|
||||
|
||||
last_write_time = xTaskGetTickCount();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*************************************************************
|
||||
函数功能:EEPROM写入数组,只能写入小于128byte数据,并且不能超过页范围
|
||||
函数名称:I2C_eeprom_write_buf
|
||||
函数返回:无返回值。
|
||||
函数参数:EEPROM的地址addr。
|
||||
**************************************************************/
|
||||
bool I2C_eeprom_write_buf(u16 startAddr, u8 * buf, u16 length)
|
||||
{
|
||||
bl24c512_init();
|
||||
|
||||
u16 current_startAddr = startAddr;
|
||||
u8 first_page_byte = EEPROM_PAGE_SIZE - (startAddr % EEPROM_PAGE_SIZE);
|
||||
u8 * current_data_ptr = buf;
|
||||
u16 left_length = length;
|
||||
u16 integrated_Pages;
|
||||
u16 end_page_byte;
|
||||
|
||||
if (length > first_page_byte)
|
||||
{
|
||||
if (!I2C_eeprom_write_page(current_startAddr, current_data_ptr, first_page_byte))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
current_startAddr = current_startAddr + first_page_byte;
|
||||
current_data_ptr += first_page_byte;
|
||||
left_length = length - first_page_byte;
|
||||
integrated_Pages = left_length / EEPROM_PAGE_SIZE;
|
||||
end_page_byte = left_length % EEPROM_PAGE_SIZE;
|
||||
|
||||
|
||||
for (u16 i = 0; i < integrated_Pages; i++)
|
||||
{
|
||||
if (!I2C_eeprom_write_page(current_startAddr, current_data_ptr, EEPROM_PAGE_SIZE))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
current_startAddr += EEPROM_PAGE_SIZE;
|
||||
current_data_ptr += EEPROM_PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (end_page_byte > 0)
|
||||
{
|
||||
if (!I2C_eeprom_write_page(current_startAddr, current_data_ptr, end_page_byte))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!I2C_eeprom_write_page(startAddr, buf, length))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:EEPROM读出数组
|
||||
函数名称:I2C_eeprom_write_buf
|
||||
函数返回:无返回值。
|
||||
函数参数:EEPROM的地址addr。
|
||||
**************************************************************/
|
||||
bool I2C_eeprom_read_buf(u16 addr, u8 * buf, u16 length)
|
||||
{
|
||||
unsigned char devaddr;
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wait_eeprom_free();
|
||||
|
||||
bl24c512_init();
|
||||
|
||||
if (I2C_eeprom_Read_byte(addr, buf) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
devaddr=(BL24C512ADDR| 0X01);
|
||||
|
||||
BL24C512I2C_GenerateSTART();
|
||||
|
||||
I2c_send_byte(devaddr);
|
||||
|
||||
if(I2C_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (u16 i = 0; i < length; i++)
|
||||
{
|
||||
buf[i+ 1] = I2c_receive_byte();
|
||||
|
||||
if (i < length - 1)
|
||||
{
|
||||
I2c_send_ack();
|
||||
}
|
||||
}
|
||||
|
||||
I2c_send_no_ack();
|
||||
BL24C512_I2C_GenerateSTOP();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef _BL24C512_H_
|
||||
#define _BL24C512_H_
|
||||
|
||||
#include "stm32f10x.h"
|
||||
#include "Basedefine.h"
|
||||
|
||||
#define SDA_MODE_IN TRUE
|
||||
#define SDA_MODE_OUT FALSE
|
||||
|
||||
#define EEPROM_PAGE_SIZE 128
|
||||
|
||||
|
||||
#define BL24C512ADDR 0xA0
|
||||
#define ADDRMAX 65535
|
||||
|
||||
|
||||
#define SDA_PIN GPIO_Pin_7
|
||||
#define SDA_PIN_PORT GPIOB
|
||||
#define SDA_PIN_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define SCL_PIN GPIO_Pin_6
|
||||
#define SCL_PIN_PORT GPIOB
|
||||
#define SCL_PIN_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
|
||||
#define SDA_HIGH() GPIO_SetBits(SDA_PIN_PORT, SDA_PIN)
|
||||
#define SDA_LOW() GPIO_ResetBits(SDA_PIN_PORT, SDA_PIN)
|
||||
|
||||
#define SCL_HIGH() GPIO_SetBits(SCL_PIN_PORT, SCL_PIN)
|
||||
#define SCL_LOW() GPIO_ResetBits(SCL_PIN_PORT, SCL_PIN)
|
||||
|
||||
#define GET_SDA() GPIO_ReadInputDataBit(SDA_PIN_PORT, SDA_PIN)
|
||||
|
||||
|
||||
void delayedus(u8 n);
|
||||
void bl24c512_init(void);
|
||||
bool I2C_eeprom_write_byte(u16 addr, u8 data);
|
||||
bool I2C_eeprom_Read_byte(u16 addr, u8 *data);
|
||||
bool I2C_eeprom_write_buf(u16 addr, u8 * buf, u16 length);
|
||||
bool I2C_eeprom_read_buf(u16 addr, u8 * buf, u16 length);
|
||||
void I2C_test(void);
|
||||
void IIC_test_write(void);
|
||||
void IIC_test_read(void);
|
||||
void self_test_eeprom(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,894 @@
|
||||
#include "include.h"
|
||||
#include "uart.h"
|
||||
#include <math.h>
|
||||
#include "debug_printf.h"
|
||||
#include "Cmd.h"
|
||||
//信号量 队列 互斥信号量 定时器 进程同步 数据保护
|
||||
|
||||
void EdbugPrintProcess(u8* Pstr,u16 len);
|
||||
|
||||
|
||||
#define PEINTFBUFF_LENGTH (800)
|
||||
#define COM_DEBUG_BUF g_DebugRxBuffer
|
||||
u8 g_DebugRxBuffer[COM_DEBUG_RX_BUFFER_SIZE];
|
||||
struct st_uart_port COM_DEBUG_port = USART_PORT_PARAMS(COM_DEBUG, g_DebugRxBuffer,NULL);
|
||||
|
||||
//static QueueHandle_t printQueue;
|
||||
static SemaphoreHandle_t xSemaphore;
|
||||
static bool printf_switch_open = TRUE;
|
||||
TaskHandle_t print_task_handle;
|
||||
|
||||
|
||||
u16 head_index = 0;
|
||||
u16 tail_index = 0;
|
||||
u8 print_buf[Q_PRINT_LENGTH][Q_PRINT_SIZE + 1] = {0};
|
||||
|
||||
|
||||
bool SendRuning = false;
|
||||
u16 EdbugPrintBuffLength = 0x00;
|
||||
u16 EdbugPrintBuffIndex = 0x00;
|
||||
|
||||
u16 EdbugPrintBuffRxLength = 0x00;
|
||||
u16 EdbugPrintBuffRxIndex = 0x00;
|
||||
u8 EdbugPrintBuff[PEINTFBUFF_LENGTH];
|
||||
/*****************************************************************************
|
||||
* Function : close_printf
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void close_printf(void)
|
||||
{
|
||||
printf_switch_open = FALSE;
|
||||
head_index = 0;
|
||||
tail_index = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : open_printf
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void open_printf(void)
|
||||
{
|
||||
printf_switch_open = TRUE;
|
||||
head_index = 0;
|
||||
tail_index = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : debug_Tx
|
||||
* Description : none
|
||||
* Input : u8 *buf
|
||||
u8 len
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void debug_Tx(u8 *buf, u8 len)
|
||||
{
|
||||
//hal_UartDMATx(&COM_DEBUG_port, buf, len);
|
||||
EdbugPrintProcess(buf, len);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : reset_debug_buf
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void reset_debug_buf(void)
|
||||
{
|
||||
MemSet(COM_DEBUG_port.data.rxBuf, 0, sizeof(g_DebugRxBuffer));
|
||||
COM_DEBUG_port.data.rx_len = 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : get_debugBuf_len
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
u16 get_debugBuf_len(void)
|
||||
{
|
||||
return COM_DEBUG_port.data.rx_len;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : get_debugBuf
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return : u8
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
u8 * get_debugBuf(void)
|
||||
{
|
||||
return COM_DEBUG_port.data.rxBuf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void add_print_buf(u8*buf, u8 length)
|
||||
{
|
||||
u8 print_size;
|
||||
u8 index = 0;
|
||||
u8 valid_blockNum;
|
||||
u8 blockNum = (length % Q_PRINT_SIZE == 0)? (length / Q_PRINT_SIZE): (length/ Q_PRINT_SIZE + 1);
|
||||
|
||||
if (head_index >= tail_index)
|
||||
{
|
||||
if (head_index == tail_index)
|
||||
{
|
||||
head_index = 0;
|
||||
tail_index = 0;
|
||||
}
|
||||
|
||||
valid_blockNum = Q_PRINT_LENGTH - head_index + tail_index;
|
||||
blockNum = (blockNum >= valid_blockNum) ? valid_blockNum : blockNum;
|
||||
}
|
||||
else
|
||||
{
|
||||
valid_blockNum = tail_index - head_index;
|
||||
blockNum = (blockNum >= valid_blockNum) ? valid_blockNum : blockNum;
|
||||
}
|
||||
|
||||
|
||||
for (u8 i = 0; i < blockNum; i++)
|
||||
{
|
||||
if (i == blockNum - 1)
|
||||
{
|
||||
print_size = (length % Q_PRINT_SIZE == 0)? Q_PRINT_SIZE: (length % Q_PRINT_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
print_size = Q_PRINT_SIZE;
|
||||
}
|
||||
print_buf[head_index][0] = print_size;
|
||||
MemCpy(&print_buf[head_index][1], buf + index, print_size);
|
||||
index += print_size;
|
||||
head_index = (head_index + 1) % Q_PRINT_LENGTH;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UART5_IRQHandler(void)
|
||||
{
|
||||
if (USART_GetITStatus(COM_DEBUG_NO, USART_IT_TC) != RESET)
|
||||
{
|
||||
if( EdbugPrintBuffIndex >= EdbugPrintBuffLength)
|
||||
{
|
||||
USART_ITConfig(COM_DEBUG_NO, USART_IT_TC, DISABLE);
|
||||
EdbugPrintBuffIndex = 0;
|
||||
SendRuning = false;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
USART_SendData(COM_DEBUG_NO, EdbugPrintBuff[EdbugPrintBuffIndex]);
|
||||
EdbugPrintBuffIndex ++;
|
||||
|
||||
}
|
||||
}
|
||||
else if (USART_GetITStatus(COM_DEBUG_NO, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
|
||||
|
||||
u8 transparent_cmd[] = "transparent 00 ";
|
||||
|
||||
u16 len;
|
||||
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
if (USART_GetITStatus(COM_DEBUG_NO, USART_IT_RXNE) != RESET)
|
||||
{
|
||||
u8 receivedByte = USART_ReceiveData(COM_DEBUG_NO);
|
||||
|
||||
if ( COM_DEBUG_port.data.rx_index >= COM_DEBUG_RX_BUFFER_SIZE)
|
||||
{
|
||||
COM_DEBUG_port.data.rx_index = 0;
|
||||
}
|
||||
|
||||
if (receivedByte == '\b')//Backspace
|
||||
{
|
||||
if ( cmp_datas(transparent_cmd, COM_DEBUG_port.data.rxBuf, 11) )
|
||||
{
|
||||
COM_DEBUG_port.data.rxBuf[COM_DEBUG_port.data.rx_index++] = receivedByte;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (COM_DEBUG_port.data.rx_index > 0)
|
||||
{
|
||||
COM_DEBUG_port.data.rx_index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
COM_DEBUG_port.data.rxBuf[COM_DEBUG_port.data.rx_index ++] = receivedByte;
|
||||
|
||||
if ((receivedByte == '\r') || (receivedByte == '\n'))//Enter
|
||||
{
|
||||
if ( cmp_datas(transparent_cmd, COM_DEBUG_port.data.rxBuf, 11) )
|
||||
{
|
||||
len = COM_DEBUG_port.data.rxBuf[12] + COM_DEBUG_port.data.rxBuf[13]*256 + sizeof(transparent_cmd) - 1;
|
||||
|
||||
if (COM_DEBUG_port.data.rx_index < len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
COM_DEBUG_port.data.rx_len = COM_DEBUG_port.data.rx_index;
|
||||
COM_DEBUG_port.data.rx_index = 0;
|
||||
|
||||
xSemaphoreGiveFromISR( COM_DEBUG_port.xSemaphore, &xHigherPriorityTaskWoken );
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaitPrintfEnd( void )
|
||||
{
|
||||
if(SendRuning == true)
|
||||
{
|
||||
for(u8 tc = 0x0; ( tc < 20 ) & ( SendRuning == true) ; tc ++)
|
||||
{
|
||||
vTaskDelay(20 /portTICK_RATE_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void EdbugPrintProcess(u8* Pstr,u16 len)
|
||||
{
|
||||
if(len > PEINTFBUFF_LENGTH) return ;
|
||||
|
||||
WaitPrintfEnd();
|
||||
MemCpy(EdbugPrintBuff, Pstr, len);
|
||||
EdbugPrintBuffLength = len;
|
||||
|
||||
EdbugPrintBuffIndex = 0x00;
|
||||
|
||||
while(USART_GetITStatus(COM_DEBUG_NO, USART_IT_TC) != RESET);
|
||||
|
||||
USART_ITConfig(COM_DEBUG_NO, USART_IT_TC, ENABLE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retargets the C library printf function to the DEBUG_COM.
|
||||
* @param None.
|
||||
* @retval None.
|
||||
*/
|
||||
int printf(const char *format ,... )
|
||||
{
|
||||
u16 receData = 0;
|
||||
|
||||
// if (printf_switch_open)
|
||||
// {
|
||||
// va_list arg;
|
||||
// u16 receNum = 0;
|
||||
// static u8 buffer[100];
|
||||
//
|
||||
// va_start(arg, format);
|
||||
// receNum = (u16)vsnprintf((char *)(buffer), sizeof(buffer), format, arg);
|
||||
// va_end(arg);
|
||||
//
|
||||
// receData = receNum;
|
||||
// if ((receNum > 0) && (receNum <= sizeof(buffer)))
|
||||
// {
|
||||
// add_print_buf(buffer, receNum);
|
||||
//
|
||||
// if (COM_DEBUG_port.data.tx_timeout == 0)
|
||||
// {
|
||||
// COM_DEBUG_port.data.tx_timeout = 1;
|
||||
// hal_UartDMATx(&COM_DEBUG_port,&print_buf[tail_index][1], print_buf[tail_index][0]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
if (printf_switch_open)
|
||||
{
|
||||
va_list arg;
|
||||
u16 receNum = 0;
|
||||
//static u8 buffer[100];
|
||||
|
||||
WaitPrintfEnd();
|
||||
|
||||
va_start(arg, format);
|
||||
receNum = (u16)vsnprintf((char *)(EdbugPrintBuff), sizeof(EdbugPrintBuff), format, arg);
|
||||
va_end(arg);
|
||||
|
||||
SendRuning = true;
|
||||
|
||||
EdbugPrintBuffLength = receNum;
|
||||
|
||||
EdbugPrintBuffIndex = 0x00;
|
||||
|
||||
while(USART_GetITStatus(COM_DEBUG_NO, USART_IT_TC) != RESET);
|
||||
|
||||
USART_ITConfig(COM_DEBUG_NO, USART_IT_TC, ENABLE);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return receData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// memcpy(RS485_tx_buf, buf, length);
|
||||
// COM_noDMA_tx_index = 0;
|
||||
// COM_noDMA_len = length;
|
||||
// COM_485_port.data.tx_timeout = xTaskGetTickCount() + (RS485_BAUD_COFF*length + 100)/portTICK_RATE_MS;;
|
||||
// while(USART_GetITStatus(COM_RADIO_NO, USART_IT_TC) != RESET);
|
||||
// USART_ITConfig(COM_RADIO_NO, USART_IT_TC, ENABLE);
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : printf_buf
|
||||
* Description : none
|
||||
* Input : u8* buf
|
||||
u16 length
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170306
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void printf_buf(u8* buf, u16 length)
|
||||
{
|
||||
// static u8 temp_buf[Q_PRINT_SIZE];
|
||||
// u8 temp_count = 0;
|
||||
//
|
||||
// u8 max_pos = (sizeof(temp_buf) - 1) - (sizeof(temp_buf) - 1) % 3;
|
||||
//
|
||||
// if (Q_PRINT_SIZE < 4)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// MemSet(temp_buf, 0, Q_PRINT_SIZE);
|
||||
//
|
||||
// for (u8 i = 0; i < length; i++)
|
||||
// {
|
||||
// temp_buf[temp_count++] = ((buf[i] / 0x10) <= 9)? (buf[i] / 0x10) + '0': (buf[i] / 0x10) + 'A' - 10;
|
||||
// temp_buf[temp_count++] = ((buf[i] % 0x10) <= 9)? (buf[i] % 0x10) + '0': (buf[i] % 0x10) + 'A' - 10;
|
||||
// temp_buf[temp_count++] = ' ';
|
||||
//
|
||||
// if ( (temp_count >= max_pos ) || (i == length - 1))
|
||||
// {
|
||||
// add_print_buf(temp_buf, temp_count);
|
||||
// temp_count = 0;
|
||||
// MemSet(temp_buf, 0, Q_PRINT_SIZE);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (head_index != tail_index)
|
||||
// {
|
||||
// printf("\r\n");
|
||||
// }
|
||||
if(length >= 255 ) return ;
|
||||
|
||||
u16 index = 0x00;
|
||||
u16 Printflength = 0x00;
|
||||
|
||||
//printf("%s"," ");
|
||||
WaitPrintfEnd();
|
||||
for(index = 0x00; index < length; index ++)
|
||||
{
|
||||
Printflength += sprintf((char*)&EdbugPrintBuff[Printflength],"%02X ",buf[index]);
|
||||
}
|
||||
|
||||
Printflength += sprintf((char*)&EdbugPrintBuff[Printflength],"%s ","\r\n");
|
||||
|
||||
// EdbugPrintBuffLength = Printflength;
|
||||
//
|
||||
// EdbugPrintBuffIndex = 0x00;
|
||||
//
|
||||
// while(USART_GetITStatus(COM_DEBUG_NO, USART_IT_TC) != RESET);
|
||||
//
|
||||
// USART_ITConfig(COM_DEBUG_NO, USART_IT_TC, ENABLE);
|
||||
printf("%s",EdbugPrintBuff);
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : vPrintf_task
|
||||
* Description : none
|
||||
* Input : void * ptr
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void vPrintf_task(void * ptr)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
while (SendRuning == true)
|
||||
{
|
||||
if (xSemaphoreTake( xSemaphore, 1000 ) == pdFALSE)
|
||||
{
|
||||
hal_InitCOM(&COM_DEBUG_port);
|
||||
// COM_DEBUG_port.data.rx_index = 0;
|
||||
// COM_DEBUG_port.data.rx_len = 0;
|
||||
// COM_DEBUG_port.data.tx_timeout = 0;
|
||||
//
|
||||
SendRuning = false;
|
||||
EdbugPrintBuffLength = 0x00;
|
||||
EdbugPrintBuffIndex = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : vPrintf_rx_task
|
||||
* Description : none
|
||||
* Input : void * ptr
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void vPrintf_rx_task(void * ptr)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (xSemaphoreTake( COM_DEBUG_port.xSemaphore, portMAX_DELAY ) == pdPASS)
|
||||
{
|
||||
Cmd_Proc();
|
||||
reset_debug_buf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : task_print_start
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void task_print_start(void)
|
||||
{
|
||||
vSemaphoreCreateBinary( xSemaphore );
|
||||
xQueueReset( (QueueHandle_t)xSemaphore);
|
||||
|
||||
init_uart_port(&COM_DEBUG_port);
|
||||
xTaskCreate( vPrintf_task, "Task printf", 150, NULL, 4, &print_task_handle );
|
||||
xTaskCreate( vPrintf_rx_task, "Task rx printf", 150, NULL, 2, NULL );
|
||||
|
||||
printf("hb app start 2021-12-14\r\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
///*****************************************************************************
|
||||
// * Function : printf
|
||||
// * Description : none
|
||||
// * Input : const char *format
|
||||
// ...
|
||||
// * Output : None
|
||||
// * Return :
|
||||
// * Others :
|
||||
// * Record
|
||||
// * 1.Date : 20170314
|
||||
// * Author : barry
|
||||
// * Modification: Created function
|
||||
//
|
||||
//*****************************************************************************/
|
||||
//int printf(const char *format ,... )
|
||||
//{
|
||||
// static va_list arg;
|
||||
// static u16 receNum = 0;
|
||||
// static u16 receData = 0;
|
||||
// static u8 blockNum = 0;
|
||||
// static u8 buffer[PRINT_MAX_BUF];
|
||||
// static u8 print_buf[ Q_PRINT_SIZE + 1];
|
||||
// static u8 index = 0;
|
||||
// static u8 print_size;
|
||||
//
|
||||
// if (printf_switch_open)
|
||||
// {
|
||||
// MemSet(buffer, 0, sizeof(buffer));
|
||||
// va_start(arg, format);
|
||||
// receNum = (u16)vsnprintf((char *)(buffer), sizeof(buffer), format, arg);
|
||||
// va_end(arg);
|
||||
//
|
||||
// index = 0;
|
||||
//
|
||||
// if ((receNum > 0) && (receNum <= PRINT_MAX_BUF))
|
||||
// {
|
||||
// blockNum = (receNum % Q_PRINT_SIZE == 0)? (receNum / Q_PRINT_SIZE): (receNum / Q_PRINT_SIZE + 1);
|
||||
//
|
||||
// taskENTER_CRITICAL(); //保护临界区代码,不被其他的任务在数据打印过程中调用
|
||||
//
|
||||
// for (u8 i = 0; i < blockNum; i++)
|
||||
// {
|
||||
// if (i == blockNum - 1)
|
||||
// {
|
||||
// print_size = (receNum % Q_PRINT_SIZE == 0)? Q_PRINT_SIZE: receNum % Q_PRINT_SIZE;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// print_size = Q_PRINT_SIZE;
|
||||
// }
|
||||
// print_buf[0] = print_size;
|
||||
// MemCpy(print_buf + 1, buffer + index, Q_PRINT_SIZE);
|
||||
// index += print_size;
|
||||
// xQueueSendToBack( printQueue, print_buf, 0 );
|
||||
// }
|
||||
//
|
||||
// taskEXIT_CRITICAL();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return receData;
|
||||
// }
|
||||
//
|
||||
///*****************************************************************************
|
||||
// * Function : printf_buf
|
||||
// * Description : none
|
||||
// * Input : u8* buf
|
||||
// u16 length
|
||||
// * Output : None
|
||||
// * Return :
|
||||
// * Others :
|
||||
// * Record
|
||||
// * 1.Date : 20170314
|
||||
// * Author : barry
|
||||
// * Modification: Created function
|
||||
//
|
||||
//*****************************************************************************/
|
||||
//void printf_buf(u8* buf, u16 length)
|
||||
//{
|
||||
// static u8 temp_buf[Q_PRINT_SIZE];
|
||||
// u8 temp_count = 0;
|
||||
//
|
||||
// u8 max_pos = (sizeof(temp_buf) - 1) - (sizeof(temp_buf) - 1) % 3;
|
||||
//
|
||||
// if (Q_PRINT_SIZE < 4)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// MemSet(temp_buf, 0, Q_PRINT_SIZE);
|
||||
//
|
||||
// taskENTER_CRITICAL();
|
||||
//
|
||||
// for (u8 i = 0; i < length; i++)
|
||||
// {
|
||||
// temp_buf[temp_count++] = ((buf[i] / 0x10) <= 9)? (buf[i] / 0x10) + '0': (buf[i] / 0x10) + 'a' - 10;
|
||||
// temp_buf[temp_count++] = ((buf[i] % 0x10) <= 9)? (buf[i] % 0x10) + '0': (buf[i] % 0x10) + 'a' - 10;
|
||||
// temp_buf[temp_count++] = ' ';
|
||||
//
|
||||
// if ( (temp_count >= max_pos ) || (i == length - 1))
|
||||
// {
|
||||
// temp_count = 0;
|
||||
// printf("%s", temp_buf);
|
||||
// MemSet(temp_buf, 0, Q_PRINT_SIZE);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// printf("\r\n");
|
||||
//
|
||||
// taskEXIT_CRITICAL();
|
||||
//}
|
||||
//
|
||||
///*****************************************************************************
|
||||
// * Function : vPrintf_task
|
||||
// * Description : none
|
||||
// * Input : void * ptr
|
||||
// * Output : None
|
||||
// * Return :
|
||||
// * Others :
|
||||
// * Record
|
||||
// * 1.Date : 20170314
|
||||
// * Author : barry
|
||||
// * Modification: Created function
|
||||
//
|
||||
//*****************************************************************************/
|
||||
//void vPrintf_task(void * ptr)
|
||||
//{
|
||||
// u8 buf[Q_PRINT_SIZE+ 1];
|
||||
//
|
||||
// for (;;)
|
||||
// {
|
||||
// if( xQueueReceive( printQueue, buf, portMAX_DELAY ) == pdPASS )
|
||||
// {
|
||||
// hal_UartDMATx(&COM_DEBUG_port, buf + 1, buf[0]);
|
||||
// if (xSemaphoreTake( xSemaphore, 1000 ) == pdFALSE)
|
||||
// {
|
||||
// hal_InitCOM(&COM_DEBUG_port);
|
||||
// COM_DEBUG_port.data.rx_index = 0;
|
||||
// COM_DEBUG_port.data.rx_len = 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
// /*****************************************************************************
|
||||
// * Function : vPrintf_rx_task
|
||||
// * Description : none
|
||||
// * Input : void * ptr
|
||||
// * Output : None
|
||||
// * Return :
|
||||
// * Others :
|
||||
// * Record
|
||||
// * 1.Date : 20170314
|
||||
// * Author : barry
|
||||
// * Modification: Created function
|
||||
//
|
||||
//*****************************************************************************/
|
||||
//void vPrintf_rx_task(void * ptr)
|
||||
//{
|
||||
// for (;;)
|
||||
// {
|
||||
// if (xSemaphoreTake( COM_DEBUG_port.xSemaphore, portMAX_DELAY ) == pdPASS)
|
||||
// {
|
||||
// Cmd_Proc();
|
||||
// reset_debug_buf();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
// /*****************************************************************************
|
||||
// * Function : task_print_start
|
||||
// * Description : none
|
||||
// * Input : void
|
||||
// * Output : None
|
||||
// * Return :
|
||||
// * Others :
|
||||
// * Record
|
||||
// * 1.Date : 20170314
|
||||
// * Author : barry
|
||||
// * Modification: Created function
|
||||
//
|
||||
// *****************************************************************************/
|
||||
// void task_print_start(void)
|
||||
// {
|
||||
// hal_InitCOM(&COM_DEBUG_port);
|
||||
//
|
||||
// printQueue = xQueueCreate(Q_PRINT_LENGTH, Q_PRINT_SIZE + 1); // Q_PRINT_LENGTH 队列的条目数 Q_PRINT_SIZE 每个条目占多少字节
|
||||
// vSemaphoreCreateBinary( xSemaphore );
|
||||
// xQueueReset( (QueueHandle_t)xSemaphore);
|
||||
//
|
||||
// init_uart_port(&COM_DEBUG_port);
|
||||
// xTaskCreate( vPrintf_task, "Task printf", 150, NULL, 4, &print_task_handle );
|
||||
// xTaskCreate( vPrintf_rx_task, "Task rx printf", 150, NULL, 2, NULL );
|
||||
//
|
||||
// printf("app start\r\n");
|
||||
// }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : COM_DEBUG_TX_IRQHandler
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
//
|
||||
//void COM_DEBUG_TX_IRQHandler(void)
|
||||
//{
|
||||
// BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
//
|
||||
// if (DMA_GetITStatus(COM_DEBUG_TX_DMA_COMPLETE) != RESET)
|
||||
// {
|
||||
// DMA_ClearITPendingBit(COM_DEBUG_TX_DMA_COMPLETE);
|
||||
//
|
||||
// tail_index = (tail_index + 1) % Q_PRINT_LENGTH;
|
||||
// if (tail_index != head_index)
|
||||
// {
|
||||
// hal_UartDMATx(&COM_DEBUG_port,&print_buf[tail_index][1], print_buf[tail_index][0]);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// COM_DEBUG_port.data.tx_timeout = 0;
|
||||
// }
|
||||
// xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
|
||||
// portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
// }
|
||||
// else if (DMA_GetITStatus(COM_DEBUG_TX_DMA_ERROR) != RESET)
|
||||
// {
|
||||
// DMA_ClearITPendingBit(COM_DEBUG_TX_DMA_ERROR);
|
||||
// }
|
||||
//}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : COM_DEBUG_RX_IRQHandler
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
//void COM_DEBUG_RX_IRQHandler(void)
|
||||
//{
|
||||
// u8 transparent_cmd[] = "transparent 00 ";
|
||||
//
|
||||
// u16 len;
|
||||
//
|
||||
// BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
//
|
||||
// if (USART_GetITStatus(COM_DEBUG_NO, USART_IT_RXNE) != RESET)
|
||||
// {
|
||||
// u8 receivedByte = USART_ReceiveData(COM_DEBUG_NO);
|
||||
//
|
||||
// if ( COM_DEBUG_port.data.rx_index >= COM_DEBUG_RX_BUFFER_SIZE)
|
||||
// {
|
||||
// COM_DEBUG_port.data.rx_index = 0;
|
||||
// }
|
||||
//
|
||||
// if (receivedByte == '\b')//Backspace
|
||||
// {
|
||||
// if ( cmp_datas(transparent_cmd, COM_DEBUG_port.data.rxBuf, 11) )
|
||||
// {
|
||||
// COM_DEBUG_port.data.rxBuf[COM_DEBUG_port.data.rx_index++] = receivedByte;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (COM_DEBUG_port.data.rx_index > 0)
|
||||
// {
|
||||
// COM_DEBUG_port.data.rx_index--;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// COM_DEBUG_port.data.rxBuf[COM_DEBUG_port.data.rx_index ++] = receivedByte;
|
||||
//
|
||||
// if ((receivedByte == '\r') || (receivedByte == '\n'))//Enter
|
||||
// {
|
||||
// if ( cmp_datas(transparent_cmd, COM_DEBUG_port.data.rxBuf, 11) )
|
||||
// {
|
||||
// len = COM_DEBUG_port.data.rxBuf[12] + COM_DEBUG_port.data.rxBuf[13]*256 + sizeof(transparent_cmd) - 1;
|
||||
//
|
||||
// if (COM_DEBUG_port.data.rx_index < len)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// COM_DEBUG_port.data.rx_len = COM_DEBUG_port.data.rx_index;
|
||||
// COM_DEBUG_port.data.rx_index = 0;
|
||||
//
|
||||
// xSemaphoreGiveFromISR( COM_DEBUG_port.xSemaphore, &xHigherPriorityTaskWoken );
|
||||
// portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
#ifndef __DEBUG_PRINTF_H__
|
||||
#define __DEBUG_PRINTF_H__
|
||||
|
||||
#include "Basedefine.h"
|
||||
#include "Rtc.h"
|
||||
|
||||
//define COM_DEBUG infomation
|
||||
//#define COM_DEBUG_NO UART4 // DEBUG
|
||||
//#define COM_DEBUG_BAUD 9600
|
||||
//#define COM_DEBUG_CHECK USART_Parity_Even
|
||||
//#define COM_DEBUG_CLK RCC_APB1Periph_UART4
|
||||
//
|
||||
//#define COM_DEBUG_TX_PIN GPIO_Pin_10
|
||||
//#define COM_DEBUG_TX_PORT GPIOC
|
||||
//#define COM_DEBUG_TX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
//
|
||||
//#define COM_DEBUG_RX_PIN GPIO_Pin_11
|
||||
//#define COM_DEBUG_RX_PORT GPIOC
|
||||
//#define COM_DEBUG_RX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
//
|
||||
//#define COM_DEBUG_IRQn UART4_IRQn
|
||||
//
|
||||
//#define COM_DEBUG_DMA_CLK RCC_AHBPeriph_DMA2
|
||||
//#define COM_DEBUG_TX_DMA_CHANNEL DMA2_Channel5
|
||||
//#define COM_DEBUG_DR_BASE (UART4_BASE + 4)
|
||||
//#define COM_DEBUG_TX_IRQHandler DMA2_Channel4_5_IRQHandler
|
||||
//#define COM_DEBUG_RX_IRQHandler UART4_IRQHandler
|
||||
//#define COM_DEBUG_TX_DMA_COMPLETE DMA2_IT_TC5
|
||||
//#define COM_DEBUG_TX_DMA_ERROR DMA2_IT_TE5
|
||||
//#define COM_DEBUG_DMA_IRQn DMA2_Channel4_5_IRQn
|
||||
//#define COM_DEBUG_TX_BUFFER_SIZE 255
|
||||
//#define COM_DEBUG_RX_BUFFER_SIZE 255
|
||||
//#define COM_DEBUG_STR "DEBUG"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define COM_DEBUG_NO UART5 // DEBUG
|
||||
//#define COM_DEBUG_BAUD 115200
|
||||
//#define COM_DEBUG_CHECK USART_Parity_Even
|
||||
#define COM_DEBUG_BAUD 9600
|
||||
#define COM_DEBUG_CHECK USART_Parity_No
|
||||
#define COM_DEBUG_CLK RCC_APB1Periph_UART5
|
||||
|
||||
#define COM_DEBUG_TX_PIN GPIO_Pin_12
|
||||
#define COM_DEBUG_TX_PORT GPIOC
|
||||
#define COM_DEBUG_TX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define COM_DEBUG_RX_PIN GPIO_Pin_2
|
||||
#define COM_DEBUG_RX_PORT GPIOD
|
||||
#define COM_DEBUG_RX_PORT_CLK RCC_APB2Periph_GPIOD
|
||||
|
||||
#define COM_DEBUG_IRQn UART5_IRQn
|
||||
|
||||
#define COM_DEBUG_DMA_CLK 0
|
||||
#define COM_DEBUG_TX_DMA_CHANNEL 0
|
||||
#define COM_DEBUG_DR_BASE 0
|
||||
#define COM_DEBUG_TX_IRQHandler 0
|
||||
#define COM_DEBUG_RX_IRQHandler 0
|
||||
#define COM_DEBUG_TX_DMA_COMPLETE 0
|
||||
#define COM_DEBUG_TX_DMA_ERROR 0
|
||||
#define COM_DEBUG_DMA_IRQn 0
|
||||
#define COM_DEBUG_TX_BUFFER_SIZE 255
|
||||
#define COM_DEBUG_RX_BUFFER_SIZE 255
|
||||
#define COM_DEBUG_STR "DEBUG"
|
||||
|
||||
//define COM LORA moudule infomation
|
||||
//#define COM_RADIO_NO UART5
|
||||
//#define COM_RADIO_BAUD 9600 //8,e,1
|
||||
//#define COM_RADIO_CHECK USART_Parity_Even
|
||||
//#define COM_RADIO_CLK RCC_APB1Periph_UART5
|
||||
//
|
||||
//#define COM_RADIO_TX_PIN GPIO_Pin_12
|
||||
//#define COM_RADIO_TX_PORT GPIOC
|
||||
//#define COM_RADIO_TX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
//
|
||||
//#define COM_RADIO_RX_PIN GPIO_Pin_2
|
||||
//#define COM_RADIO_RX_PORT GPIOD
|
||||
//#define COM_RADIO_RX_PORT_CLK RCC_APB2Periph_GPIOD
|
||||
//
|
||||
//#define COM_RADIO_IRQn UART5_IRQn
|
||||
//
|
||||
//#define COM_RADIO_DMA_CLK 0
|
||||
//
|
||||
//#define COM_RADIO_TX_DMA_CHANNEL 0
|
||||
//#define COM_RADIO_DR_BASE 0
|
||||
//#define COM_RADIO_TX_IRQHandler 0
|
||||
//#define COM_RADIO_RX_IRQHandler 0
|
||||
//#define COM_RADIO_TX_DMA_COMPLETE 0
|
||||
//#define COM_RADIO_TX_DMA_ERROR 0
|
||||
//#define COM_RADIO_DMA_IRQn 0
|
||||
//
|
||||
//
|
||||
//#define COM_RADIO_TX_BUFFER_SIZE 255
|
||||
//#define COM_RADIO_RX_BUFFER_SIZE 255
|
||||
//#define COM_RADIO_STR "radio"
|
||||
|
||||
|
||||
/*
|
||||
#define COM_DEBUG_NO USART3 // DEBUG
|
||||
#define COM_DEBUG_BAUD 9600
|
||||
#define COM_DEBUG_CHECK USART_Parity_Even
|
||||
#define COM_DEBUG_CLK RCC_APB1Periph_USART3
|
||||
|
||||
#define COM_DEBUG_TX_PIN GPIO_Pin_10
|
||||
#define COM_DEBUG_TX_PORT GPIOB
|
||||
#define COM_DEBUG_TX_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define COM_DEBUG_RX_PIN GPIO_Pin_11
|
||||
#define COM_DEBUG_RX_PORT GPIOB
|
||||
#define COM_DEBUG_RX_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define COM_DEBUG_IRQn USART3_IRQn
|
||||
|
||||
#define COM_DEBUG_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
#define COM_DEBUG_TX_DMA_CHANNEL DMA1_Channel2
|
||||
#define COM_DEBUG_DR_BASE (USART3_BASE + 4)
|
||||
#define COM_DEBUG_TX_IRQHandler DMA1_Channel2_IRQHandler
|
||||
#define COM_DEBUG_RX_IRQHandler USART3_IRQHandler
|
||||
#define COM_DEBUG_TX_DMA_COMPLETE DMA1_IT_TC2
|
||||
#define COM_DEBUG_TX_DMA_ERROR DMA1_IT_TE2
|
||||
#define COM_DEBUG_DMA_IRQn DMA1_Channel2_IRQn
|
||||
#define COM_DEBUG_TX_BUFFER_SIZE 255
|
||||
#define COM_DEBUG_RX_BUFFER_SIZE 255
|
||||
|
||||
*/
|
||||
|
||||
#define PRINT_TIME_OUT(bytes) (((bytes * 11000) / COM_DEBUG_BAUD) + 100) //ms
|
||||
|
||||
#define Q_PRINT_LENGTH 128
|
||||
#define Q_PRINT_SIZE 16
|
||||
#define PRINT_BUFFER_SIZE (Q_PRINT_LENGTH * Q_PRINT_SIZE)
|
||||
#define PRINT_MAX_BUF 255
|
||||
|
||||
#define PRINT(CODE) do\
|
||||
{\
|
||||
sTime time;\
|
||||
time = TimetoBCD(RTC_GetCounter());\
|
||||
printf("%02d:%02d:%02d->", time.hour, time.minute, time.second);\
|
||||
CODE\
|
||||
} while (0)
|
||||
|
||||
#define __DISPLAY
|
||||
|
||||
#ifdef __DISPLAY
|
||||
#define DISP(CODE) PRINT(CODE)
|
||||
#define LIST(CODE) do{CODE}while(0)
|
||||
#else
|
||||
#define DISP(CODE)
|
||||
#define LIST(CODE)
|
||||
#endif
|
||||
|
||||
void debug_Tx(u8 *buf, u8 len);
|
||||
void task_print_start(void);
|
||||
void reset_debug_buf(void);
|
||||
void printf_buf(u8* buf, u16 length);
|
||||
u16 get_debugBuf_len(void);
|
||||
u8 * get_debugBuf(void);
|
||||
void close_printf(void);
|
||||
void open_printf(void);
|
||||
|
||||
#endif
|
||||
+885
@@ -0,0 +1,885 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hal_radio.c
|
||||
* @author William Liang
|
||||
* @version V1.0.0
|
||||
* @date 09/10/2013
|
||||
* @brief This file contains the initialization and handle of the radio frequency.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "hal_radio.h"
|
||||
#include "uart.h"
|
||||
#include "Rtc.h"
|
||||
#include "sx1276-LoRa.h"
|
||||
#include "sx1276-Fsk.h"
|
||||
#include "apl.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : spiReadWriteByte
|
||||
Description : spi basic function
|
||||
Input : u8 data
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
u8 spiReadWriteByte(u8 data)
|
||||
{
|
||||
while(SPI_I2S_GetFlagStatus(sRF_SPI,SPI_I2S_FLAG_TXE)==RESET);
|
||||
SPI_I2S_SendData(sRF_SPI, data);
|
||||
|
||||
while(SPI_I2S_GetFlagStatus(sRF_SPI,SPI_I2S_FLAG_RXNE)==RESET);
|
||||
return (u8)(SPI_I2S_ReceiveData(sRF_SPI));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276WriteBuffer
|
||||
Description : spi write buffer
|
||||
Input : uint8_t addr
|
||||
uint8_t *buffer
|
||||
uint8_t size
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276WriteBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
|
||||
{
|
||||
sRF_CS_LOW();
|
||||
spiReadWriteByte(addr|0x80);
|
||||
|
||||
for(u8 i = 0;i < size; i++)
|
||||
{
|
||||
spiReadWriteByte(buffer[i]);
|
||||
}
|
||||
sRF_CS_HIGH();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276ReadBuffer
|
||||
Description : none
|
||||
Input : uint8_t addr
|
||||
uint8_t *buffer
|
||||
uint8_t size
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276ReadBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
|
||||
{
|
||||
sRF_CS_LOW();
|
||||
|
||||
spiReadWriteByte(addr);
|
||||
|
||||
for(u8 i = 0;i < size; i++)
|
||||
{
|
||||
buffer[i] = spiReadWriteByte(0xFF);
|
||||
}
|
||||
sRF_CS_HIGH();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276Write
|
||||
Description : 1276 write Reg
|
||||
Input : uint8_t addr
|
||||
uint8_t data
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276Write( uint8_t addr, uint8_t data )
|
||||
{
|
||||
SX1276WriteBuffer( addr, &data, 1 );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276Read
|
||||
Description : 1276 read Reg
|
||||
Input : uint8_t addr
|
||||
uint8_t *data
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276Read( uint8_t addr, uint8_t *data )
|
||||
{
|
||||
SX1276ReadBuffer( addr, data, 1 );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276WriteFifo
|
||||
Description : none
|
||||
Input : uint8_t *buffer
|
||||
uint8_t size
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276WriteFifo( uint8_t *buffer, uint8_t size )
|
||||
{
|
||||
SX1276WriteBuffer( sRF_FIFO_ARRD, buffer, size );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276ReadFifo
|
||||
Description : none
|
||||
Input : uint8_t *buffer
|
||||
uint8_t size
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276ReadFifo( uint8_t *buffer, uint8_t size )
|
||||
{
|
||||
SX1276ReadBuffer( sRF_FIFO_ARRD, buffer, size );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : SX1276Reset
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170307
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
#define get_sys_time() xTaskGetTickCount()*portTICK_RATE_MS
|
||||
|
||||
void SX1276Reset(void)
|
||||
{
|
||||
u32 startTick;
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
hal_DIOx_ITConfig(all, DISABLE);
|
||||
RCC_APB2PeriphClockCmd(sRF_RESET_SCK, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_RESET_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init( sRF_RESET_PORT, &GPIO_InitStructure );
|
||||
|
||||
GPIO_ResetBits( sRF_RESET_PORT, sRF_RESET_PIN);
|
||||
|
||||
startTick = get_sys_time( );
|
||||
while( get_sys_time( ) < ( startTick + 2 ));
|
||||
|
||||
GPIO_SetBits( sRF_RESET_PORT, sRF_RESET_PIN );
|
||||
|
||||
startTick = get_sys_time( );
|
||||
while( get_sys_time( ) < ( startTick + 6 ));
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_RESET_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init( sRF_RESET_PORT, &GPIO_InitStructure );
|
||||
|
||||
hal_sRF_ClearAllRF_IT();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_ITConfig
|
||||
Description : none
|
||||
Input : en_GDOx_IrqLine irqLine
|
||||
FunctionalState NewState
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_ITConfig(uint32_t irqLine, FunctionalState NewState)
|
||||
{
|
||||
EXTI_InitTypeDef EXTI_InitStructure;
|
||||
|
||||
EXTI_InitStructure.EXTI_Line = irqLine;
|
||||
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
|
||||
EXTI_InitStructure.EXTI_LineCmd = NewState;
|
||||
EXTI_Init(&EXTI_InitStructure);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : hal_sRF_FSK_ITConfig
|
||||
* Description : none
|
||||
* Input : uint32_t irqLine
|
||||
FunctionalState NewState
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170418
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void hal_sRF_FSK_ITConfig( uint32_t irqLine, FunctionalState NewState)
|
||||
{
|
||||
EXTI_InitTypeDef EXTI_InitStructure;
|
||||
|
||||
if (NewState == ENABLE)
|
||||
{
|
||||
EXTI_ClearITPendingBit(irqLine);
|
||||
}
|
||||
|
||||
EXTI_InitStructure.EXTI_Line = irqLine;
|
||||
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
|
||||
EXTI_InitStructure.EXTI_LineCmd = NewState;
|
||||
EXTI_Init(&EXTI_InitStructure);
|
||||
|
||||
if (NewState == DISABLE)
|
||||
{
|
||||
EXTI_ClearITPendingBit(irqLine);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : hal_sRF_ClearAllRF_IT
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170418
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void hal_sRF_ClearAllRF_IT(void)
|
||||
{
|
||||
EXTI_ClearITPendingBit(DIO0_IRQ);
|
||||
EXTI_ClearITPendingBit(DIO1_IRQ);
|
||||
EXTI_ClearITPendingBit(DIO2_IRQ);
|
||||
EXTI_ClearITPendingBit(DIO3_IRQ);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : hal_Init_RF_pins
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_Init_RF_pins(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
|
||||
RCC_APB2PeriphClockCmd(sRF_CS_GPIO_CLK | sRF_SPI_MOSI_GPIO_CLK | sRF_SPI_MISO_GPIO_CLK |
|
||||
sRF_SPI_SCK_GPIO_CLK | sRF_DIOx_SCK | sRF_RESET_SCK | sRF_DIO4_SCK, ENABLE);
|
||||
|
||||
hal_DIOx_ITConfig(all,DISABLE);
|
||||
hal_sRF_ClearAllRF_IT();
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_RESET_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init( sRF_RESET_PORT, &GPIO_InitStructure );
|
||||
|
||||
/*!< Configure sRF_SPI pins: SCK */
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_SPI_SCK_PIN;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_Init(sRF_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
/*!< Configure sRF_SPI pins: MOSI */
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_SPI_MOSI_PIN;
|
||||
GPIO_Init(sRF_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
/*!< Configure sRF_SPI pins: MISO */
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_SPI_MISO_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_Init(sRF_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
/*!< Configure sRF_CS_PIN pin: sRF CS pin */
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_CS_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init(sRF_CS_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
/*!< Configure sRF_IRQ_PINs pin: DDO0~GDO5 */
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_DIO0_PIN | sRF_DIO1_PIN | sRF_DIO3_PIN;// | sRF_DIO2_PIN ;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
|
||||
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init(sRF_DIOx_PORT, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_DIO4_PIN;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
|
||||
GPIO_Init(sRF_DIO4_PORT, &GPIO_InitStructure);
|
||||
|
||||
/*TX LED pin*/
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = sRF_TX_CTRL_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init( sRF_TX_CTRL_PORT, &GPIO_InitStructure );
|
||||
}
|
||||
|
||||
|
||||
void hal_Init_RF_int(void)
|
||||
{
|
||||
NVIC_InitTypeDef NVIC_InitStructure;
|
||||
|
||||
/* Disable sRF_IRQ_EXTI clock */
|
||||
RCC_APB2PeriphResetCmd(RCC_APB2Periph_AFIO, DISABLE);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&NVIC_InitStructure);
|
||||
|
||||
|
||||
GPIO_EXTILineConfig(sRF_DIOx_PORT_SOURCE, sRF_DIO0_PIN_SOURCE);
|
||||
GPIO_EXTILineConfig(sRF_DIOx_PORT_SOURCE, sRF_DIO1_PIN_SOURCE);
|
||||
//GPIO_EXTILineConfig(sRF_DIOx_PORT_SOURCE, sRF_DIO2_PIN_SOURCE);
|
||||
GPIO_EXTILineConfig(sRF_DIOx_PORT_SOURCE, sRF_DIO3_PIN_SOURCE);
|
||||
GPIO_EXTILineConfig(sRF_DIO4_PORT_SOURCE, sRF_DIO4_PIN_SOURCE);
|
||||
|
||||
/* Enable AFIO clock */
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_SPI_Config
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_Init_RF_SPI(void)
|
||||
{
|
||||
SPI_InitTypeDef SPI_InitStructure;
|
||||
|
||||
if (sRF_SPI == SPI1)
|
||||
{
|
||||
RCC_APB2PeriphClockCmd(sRF_SPI_CLK, ENABLE);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
RCC_APB1PeriphClockCmd(sRF_SPI_CLK, ENABLE);
|
||||
}
|
||||
|
||||
/* Enable sRF SPI DMA clock */
|
||||
RCC_AHBPeriphClockCmd(sRF_SPI_DMA_CLK, ENABLE);
|
||||
|
||||
/*!< Deselect the RF: Chip Select high */
|
||||
sRF_CS_HIGH();
|
||||
|
||||
/* Disable sRF_SPI */
|
||||
SPI_Cmd(sRF_SPI, DISABLE);
|
||||
|
||||
/*!< SPI configuration */
|
||||
SPI_I2S_DeInit(sRF_SPI);
|
||||
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
||||
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
|
||||
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
|
||||
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
|
||||
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
|
||||
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
|
||||
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
|
||||
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
|
||||
SPI_InitStructure.SPI_CRCPolynomial = 7;
|
||||
SPI_Init(sRF_SPI, &SPI_InitStructure);
|
||||
|
||||
/*!< Enable the sRF_SPI */
|
||||
SPI_Cmd(sRF_SPI, ENABLE);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_InitSPI
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_InitSPI(void)
|
||||
{
|
||||
hal_Init_RF_pins();
|
||||
hal_Init_RF_int();
|
||||
hal_Init_RF_SPI();
|
||||
|
||||
#ifdef SPI_DMA_FIFO
|
||||
init_SPI_DMA();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : SX1276_lora_init
|
||||
* Description : none
|
||||
* Input : bool lora
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170320
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void SX1276_init(bool lora)
|
||||
{
|
||||
SX1276Reset();
|
||||
if (lora)
|
||||
{
|
||||
SX1276LoRaInit();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef USE_LORA_MODE
|
||||
SX1276FskInit();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : hal_InitRF
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_InitRF(void)
|
||||
{
|
||||
hal_sRF_InitSPI();
|
||||
#ifdef USE_LORA_MODE
|
||||
SX1276_init(true);
|
||||
#else
|
||||
SX1276_init(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
/*****************************************************************************
|
||||
Prototype : init_SPI_DMA
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void init_SPI_DMA(void)
|
||||
{
|
||||
DMA_InitTypeDef DMA_InitStructure;
|
||||
|
||||
/* Enable SPI Rx and Tx request */
|
||||
SPI_I2S_DMACmd(sRF_SPI, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);
|
||||
|
||||
/* sRF_SPI_DMA_RX_Channel configuration ---------------------------------------------*/
|
||||
DMA_DeInit(sRF_SPI_DMA_RX_Channel);
|
||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)sRF_SPI_DR_Base;
|
||||
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)0;
|
||||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
|
||||
DMA_InitStructure.DMA_BufferSize = 0;
|
||||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
||||
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
||||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||||
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
||||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||||
DMA_Init(sRF_SPI_DMA_RX_Channel, &DMA_InitStructure);
|
||||
|
||||
/* sRF_SPI_DMA_TX_Channel configuration ---------------------------------------------*/
|
||||
DMA_DeInit(sRF_SPI_DMA_TX_Channel);
|
||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)sRF_SPI_DR_Base;
|
||||
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)0;
|
||||
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
||||
DMA_InitStructure.DMA_BufferSize = 0;
|
||||
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
|
||||
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
|
||||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||||
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
||||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||||
DMA_Init(sRF_SPI_DMA_TX_Channel, &DMA_InitStructure);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_ReadRegister
|
||||
Description : none
|
||||
Input : u8 reg
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
u8 hal_sRF_ReadRegister(u8 reg)
|
||||
{
|
||||
if (reg > TOTAL_REGISTER_NUMBER)
|
||||
{
|
||||
printf("regsiter input error\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!< Deselect the Radio: Chip Select high */
|
||||
sRF_CS_HIGH();
|
||||
|
||||
/*!< Select the radio by pulling low the nSEL pin */
|
||||
sRF_CS_LOW();
|
||||
|
||||
/*!< Loop while DR register in not emplty */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
||||
|
||||
/*!< Send byte through the SPI1 peripheral */
|
||||
SPI_I2S_SendData(sRF_SPI, reg);
|
||||
|
||||
/*!< Wait to receive a byte */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
|
||||
/* read from the SPI bus */
|
||||
SPI_I2S_ReceiveData(sRF_SPI);
|
||||
|
||||
/*!< Loop while DR register in not emplty */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
||||
|
||||
/*!< Send byte through the SPI1 peripheral */
|
||||
SPI_I2S_SendData(sRF_SPI, sRF_DUMMY_BYTE);
|
||||
|
||||
/*!< Wait to receive a byte */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
|
||||
/*!< Return the byte read from the SPI bus */
|
||||
reg = SPI_I2S_ReceiveData(sRF_SPI);
|
||||
|
||||
/*!< Deselect the radio by pulling high the nSEL pin */
|
||||
sRF_CS_HIGH();
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_WriteRegister
|
||||
Description : none
|
||||
Input : u8 reg
|
||||
u8 val
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_WriteRegister(u8 reg, u8 val)
|
||||
{
|
||||
reg |= 0x80;
|
||||
|
||||
/*!< Deselect the Radio: Chip Select high */
|
||||
sRF_CS_HIGH();
|
||||
|
||||
/*!< Select the radio by pulling low the nSEL pin */
|
||||
sRF_CS_LOW();
|
||||
|
||||
/*!< Loop while DR register in not emplty */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
||||
|
||||
/*!< Send byte through the SPI1 peripheral */
|
||||
SPI_I2S_SendData(sRF_SPI, reg);
|
||||
|
||||
/*!< Wait to receive a byte */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
|
||||
/* read from the SPI bus */
|
||||
SPI_I2S_ReceiveData(sRF_SPI);
|
||||
|
||||
/*!< Loop while DR register in not emplty */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
||||
|
||||
/*!< Send byte through the SPI1 peripheral */
|
||||
SPI_I2S_SendData(sRF_SPI, val);
|
||||
|
||||
/*!< Wait to receive a byte */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
|
||||
/* read from the SPI bus */
|
||||
SPI_I2S_ReceiveData(sRF_SPI);
|
||||
|
||||
/*!< Deselect the radio by pulling high the nSEL pin */
|
||||
sRF_CS_HIGH();
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_DMA_Read
|
||||
Description : none
|
||||
Input : u8 startReg
|
||||
u8 *pBuffer
|
||||
u8 length
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_DMA_Read(u8 startReg, u8 *pBuffer, u8 length)
|
||||
{
|
||||
/* Allocate storage for CPU status register */
|
||||
#if OS_CRITICAL_METHOD == 3u
|
||||
OS_CPU_SR cpu_sr = 0u;
|
||||
#endif
|
||||
|
||||
if (startReg > TOTAL_REGISTER_NUMBER)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
/*!< Deselect the Radio: Chip Select high */
|
||||
sRF_CS_HIGH();
|
||||
|
||||
/*!< Select the radio by pulling low the nSEL pin */
|
||||
sRF_CS_LOW();
|
||||
|
||||
/*!< Loop while DR register in not emplty */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_TXE) == RESET);
|
||||
|
||||
/*!< Send byte through the SPI1 peripheral */
|
||||
SPI_I2S_SendData(sRF_SPI, startReg);
|
||||
|
||||
/*!< Wait to receive a byte */
|
||||
while (SPI_I2S_GetFlagStatus(sRF_SPI, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
|
||||
/* read from the SPI bus */
|
||||
SPI_I2S_ReceiveData(sRF_SPI);
|
||||
|
||||
OS_ENTER_CRITICAL();
|
||||
|
||||
sRF_SPI->CR1 |= SPI_Direction_2Lines_RxOnly;
|
||||
|
||||
/* sRF_SPI_DMA_RX_Channel configuration ---------------------------------------------*/
|
||||
sRF_SPI_DMA_RX_Channel->CMAR = (u32)pBuffer;
|
||||
sRF_SPI_DMA_RX_Channel->CNDTR = (u32)length;
|
||||
|
||||
/* Enable sRF_SPI_DMA_RX_Channel and TC interrupt*/
|
||||
sRF_SPI_DMA_RX_Channel->CCR |= DMA_CCR1_EN | DMA_CCR1_TCIE;
|
||||
|
||||
OS_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_DMA_Write
|
||||
Description : none
|
||||
Input : u8 *pBuffer
|
||||
u8 length
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_DMA_Write(u8 *pBuffer, u8 length)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
/*!< Deselect the Radio: Chip Select high */
|
||||
sRF_CS_HIGH();
|
||||
|
||||
/*!< Select the radio by pulling low the nSEL pin */
|
||||
sRF_CS_LOW();
|
||||
|
||||
/* sRF_SPI_DMA_TX_Channel configuration ---------------------------------------------*/
|
||||
sRF_SPI_DMA_TX_Channel->CMAR = (u32)pBuffer;
|
||||
sRF_SPI_DMA_TX_Channel->CNDTR = (u32)length;
|
||||
|
||||
/* Enable sRF_SPI_DMA_TX_Channel */
|
||||
sRF_SPI_DMA_TX_Channel->CCR |= DMA_CCR1_EN | DMA_CCR1_TCIE;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("length input error\r\n");
|
||||
}
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_Config
|
||||
Description : none
|
||||
Input : u8 startReg
|
||||
u8 *pBuffer
|
||||
u8 length
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_Config(u8 startReg, u8 *pBuffer, u8 length)
|
||||
{
|
||||
if (startReg >= TOTAL_REGISTER_NUMBER)
|
||||
{
|
||||
printf("startReg input error\r\n");
|
||||
return;
|
||||
}
|
||||
if (length > 0)
|
||||
{
|
||||
hal_sRF_InitSPI();
|
||||
*pBuffer = startReg | 0x80;
|
||||
hal_sRF_DMA_Write(pBuffer, length + 1);
|
||||
|
||||
}
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_Read
|
||||
Description : DMA read FIFO
|
||||
Input : u8 startReg
|
||||
u8 *pBuffer
|
||||
u8 length
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_Read(u8 startReg, u8 *pBuffer, u8 length)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
hal_sRF_InitSPI();
|
||||
hal_sRF_DMA_Read(startReg,pBuffer,length);
|
||||
}
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_readFIFO_DMA
|
||||
Description : none
|
||||
Input : u8 * pBuffer指向接收数组,数组的第一个字节为长度字节
|
||||
u8 length
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/21
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_readFIFO_DMA(u8 * pBuffer, u8 length)
|
||||
{
|
||||
|
||||
hal_sRF_DMA_Read(0,pBuffer+1,length);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_writeFIFO_DMA
|
||||
Description : none
|
||||
Input : u8 * pBuffer 指向开始发送的数组,数组的第一个字节为FIFO地址
|
||||
u8 length 实际发送的字节数
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/21
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void hal_sRF_writeFIFO_DMA(u8 * pBuffer, u8 length)
|
||||
{
|
||||
hal_sRF_Config(0,pBuffer,length);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* STM32F10x Peripherals Interrupt Handlers */
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : DMA1_Channel2_IRQHandler
|
||||
Description : This function handles SPI1 Rx Transfer Complete interrupt
|
||||
and Transfer Error interrupt.
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void DMA1_Channel2_IRQHandler(void)
|
||||
{
|
||||
if (DMA_GetITStatus(DMA1_IT_TC2) != RESET)
|
||||
{
|
||||
/* hal_sRF_InitSPI();初始化放在主循环中去 */
|
||||
RxEndProcess(TRUE);
|
||||
}
|
||||
|
||||
/*!< Deselect the RADIO: Chip Select high */
|
||||
//sRF_CS_HIGH();
|
||||
|
||||
/* Disable the selected SPI peripheral */
|
||||
//sRF_SPI->CR1 &= 0xFFBF;
|
||||
|
||||
/* Clear the DMA1 interrupt pending bits */
|
||||
DMA1->IFCR = DMA1_IT_TC2 | DMA1_IT_HT2 | DMA1_IT_TE2;
|
||||
|
||||
/* Disable the selected DMA1_Channel2 */
|
||||
DMA1_Channel2->CCR &= (u16)(~DMA_CCR1_EN);
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : DMA1_Channel3_IRQHandler
|
||||
Description : This function handles SPI1 Tx Transfer Complete interrupt
|
||||
and Transfer Error interrupt.
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void DMA1_Channel3_IRQHandler(void)
|
||||
{
|
||||
if (DMA_GetITStatus(DMA1_IT_TC3) != RESET)
|
||||
{
|
||||
SX1276LoRaStartTransmit();
|
||||
}
|
||||
|
||||
/* Clear the DMA1 interrupt pending bits */
|
||||
DMA1->IFCR = DMA1_IT_TC3 | DMA1_IT_HT3 | DMA1_IT_TE3;
|
||||
|
||||
/* Disable the selected DMA1_Channel3 */
|
||||
DMA1_Channel3->CCR &= (u16)(~DMA_CCR1_EN);
|
||||
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : hal_sRF_Transmit
|
||||
Description : PHY send
|
||||
Input : u8 *pBuffer
|
||||
u8 length
|
||||
u8 channel
|
||||
Output : None
|
||||
Return Value :
|
||||
Calls :
|
||||
Called By :
|
||||
|
||||
History :
|
||||
1.Date : 2014/10/29
|
||||
Author : liwei
|
||||
Modification : Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void hal_sRF_Transmit(u8 *pBuffer, u8 length, u8 channel)
|
||||
{
|
||||
SX1276LoRa_NormalTx(pBuffer,length);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/******************* (C) COPYRIGHT 2013 Robulink Technology Ltd.*****END OF FILE****/
|
||||
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hal_radio.h
|
||||
* @author William Liang
|
||||
* @version V1.0.0
|
||||
* @date 09/10/2013
|
||||
* @brief This file contains the headers of the radio frequency handlers.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __HAL_sRF_H__
|
||||
#define __HAL_sRF_H__
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "include.h"
|
||||
#include "stm32f10x.h"
|
||||
#include "sx1276-LoRa.h"
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief SPI sRF Frequency Chip Interface pins
|
||||
*/
|
||||
#define sRF_SPI SPI1
|
||||
#define sRF_SPI_CLK RCC_APB2Periph_SPI1
|
||||
#define sRF_CS_PIN GPIO_Pin_4 /* PA.4 */
|
||||
#define sRF_CS_GPIO_PORT GPIOA /* GPIOA */
|
||||
#define sRF_CS_GPIO_CLK RCC_APB2Periph_GPIOA
|
||||
#define sRF_SPI_SCK_PIN GPIO_Pin_5 /* PB.5 */
|
||||
#define sRF_SPI_SCK_GPIO_PORT GPIOA /* GPIOA */
|
||||
#define sRF_SPI_SCK_GPIO_CLK RCC_APB2Periph_GPIOA
|
||||
#define sRF_SPI_MISO_PIN GPIO_Pin_6 /* PB.6 */
|
||||
#define sRF_SPI_MISO_GPIO_PORT GPIOA /* GPIOA */
|
||||
#define sRF_SPI_MISO_GPIO_CLK RCC_APB2Periph_GPIOA
|
||||
#define sRF_SPI_MOSI_PIN GPIO_Pin_7 /* PB.7 */
|
||||
#define sRF_SPI_MOSI_GPIO_PORT GPIOA /* GPIOA */
|
||||
#define sRF_SPI_MOSI_GPIO_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define sRF_SPI_DR_Base (SPI1_BASE + 0x0C)
|
||||
#define sRF_SPI_DMA DMA1
|
||||
#define sRF_SPI_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
#define sRF_SPI_DMA_RX_Channel DMA1_Channel4
|
||||
#define sRF_SPI_DMA_TX_Channel DMA1_Channel5
|
||||
#define sRF_SPI_DMA_RX_FLAG DMA1_FLAG_TC4
|
||||
#define sRF_SPI_DMA_TX_FLAG DMA1_FLAG_TC5
|
||||
|
||||
|
||||
/* BEGIN: Added by Barry, 2014/3/4 */
|
||||
#define sRF_RESET_PORT GPIOA
|
||||
#define sRF_RESET_SCK RCC_APB2Periph_GPIOA
|
||||
#define sRF_RESET_PIN GPIO_Pin_1
|
||||
|
||||
|
||||
#define sRF_DIOx_PORT GPIOB
|
||||
#define sRF_DIOx_SCK RCC_APB2Periph_GPIOB
|
||||
#define sRF_DIO0_PIN GPIO_Pin_13
|
||||
#define sRF_DIO1_PIN GPIO_Pin_12
|
||||
//#define sRF_DIO2_PIN GPIO_Pin_1
|
||||
#define sRF_DIO3_PIN GPIO_Pin_0
|
||||
//#define sRF_DIO4_PIN GPIO_Pin_4
|
||||
//#define sRF_DIO5_PIN GPIO_Pin_5
|
||||
|
||||
#define sRF_DIO4_PORT GPIOC
|
||||
#define sRF_DIO4_PIN GPIO_Pin_5 //PC5
|
||||
#define sRF_DIO4_SCK RCC_APB2Periph_GPIOC
|
||||
#define sRF_DIO4_PORT_SOURCE GPIO_PortSourceGPIOC
|
||||
#define sRF_DIO4_PIN_SOURCE GPIO_PinSource5
|
||||
|
||||
#define sRF_DIOx_PORT_SOURCE GPIO_PortSourceGPIOB
|
||||
#define sRF_DIO0_PIN_SOURCE GPIO_PinSource13
|
||||
#define sRF_DIO1_PIN_SOURCE GPIO_PinSource12
|
||||
#define sRF_DIO2_PIN_SOURCE GPIO_PinSource1
|
||||
#define sRF_DIO3_PIN_SOURCE GPIO_PinSource0
|
||||
|
||||
|
||||
#define DIO0_IRQ EXTI_Line13
|
||||
#define DIO1_IRQ EXTI_Line12
|
||||
#define DIO2_IRQ EXTI_Line1
|
||||
#define DIO3_IRQ EXTI_Line0
|
||||
#define DIO4_IRQ EXTI_Line5
|
||||
#define DIOall_IRQ (DIO0_IRQ | DIO1_IRQ | DIO2_IRQ | DIO3_IRQ | DIO4_IRQ)
|
||||
#define hal_DIOx_ITConfig(n,NewState) hal_sRF_ITConfig(DIO##n##_IRQ,NewState)
|
||||
|
||||
#define sRF_TX_CTRL_PORT GPIOC
|
||||
#define sRF_TX_CTRL_PIN GPIO_Pin_4
|
||||
|
||||
#define sRF_FIFO_ARRD 0
|
||||
/* END: Added by Barry, 2014/3/4 */
|
||||
|
||||
/* Select sRF: Chip Select pin low */
|
||||
#define sRF_CS_LOW() GPIO_ResetBits(sRF_CS_GPIO_PORT, sRF_CS_PIN)
|
||||
/* Deselect sRF: Chip Select pin high */
|
||||
#define sRF_CS_HIGH() GPIO_SetBits(sRF_CS_GPIO_PORT, sRF_CS_PIN)
|
||||
|
||||
#define RFTX_ENABLE GPIO_SetBits(sRF_TX_CTRL_PORT, sRF_TX_CTRL_PIN)
|
||||
#define RFRX_ENABLE GPIO_ResetBits(sRF_TX_CTRL_PORT, sRF_TX_CTRL_PIN)
|
||||
|
||||
#define switch_Tx() GPIO_SetBits(sRF_TX_CTRL_PORT, sRF_TX_CTRL_PIN)
|
||||
#define switch_Rx() GPIO_ResetBits(sRF_TX_CTRL_PORT, sRF_TX_CTRL_PIN)
|
||||
|
||||
|
||||
|
||||
|
||||
/* Disable PA */
|
||||
#define sRF_PA_DISABLE() GPIO_ResetBits(sRF_PA_CTRL_PORT, sRF_PA_CTRL_PIN)
|
||||
/* Enable PA */
|
||||
#define sRF_PA_ENABLE() GPIO_SetBits(sRF_PA_CTRL_PORT, sRF_PA_CTRL_PIN)
|
||||
|
||||
|
||||
#define sRF_DUMMY_BYTE 0xAA
|
||||
#define sRF_CRYSTALCAP_EEPROM_ADDR 0xFFC1
|
||||
#define sRF_CHANNEL_NUMBER 66u
|
||||
#define sRF_PREAMBLE_LENGTH 80u //bytes
|
||||
#define sRF_SYNCWORD_LENGTH 2u //bytes
|
||||
#define sRF_FREQ_HOP_TIMEOUT 30u//ms
|
||||
#define sRF_CHECK_SYNCWORD_TIMEOUT 85u //(((sRF_PREAMBLE_LENGTH + sRF_SYNCWORD_LENGTH) * 8) / 10 + 20) //ms
|
||||
#define sRF_FIRST_TX_TIMEOUT 136u //(((sRF_PREAMBLE_LENGTH + sRF_SYNCWORD_LENGTH + FIFO_SIZE) * 8) / 10 + 20) //ms
|
||||
#define sRF_FIFO_TRX_TIMEOUT 71u //((FIFO_SIZE * 8) / 10 + 20) //ms
|
||||
#define sRF_FIFO_DMA_TIMEOUT 20u //ms
|
||||
#define sRF_PACKET_SIZE (aMaxPHYPayloadSize + 6) //258u
|
||||
#define sRF_RSSI_SAMPLE_NUMBER 9u
|
||||
#define sRF_RSSI_SAMPLE_INTERVAL 2u //ms
|
||||
#define sRF_TEST_INTERVAL 1000u //ms
|
||||
|
||||
#define TOTAL_REGISTER_NUMBER 0x70
|
||||
#define FIFO_SIZE 255u
|
||||
|
||||
#define RF_TIMEOUT 3000
|
||||
|
||||
#define RXTX( txEnable ) SX1276WriteRxTx( txEnable )
|
||||
#define TICK_RATE_MS( ms ) ( ms )
|
||||
|
||||
#define true TRUE
|
||||
#define false FALSE
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 version;
|
||||
u16 lastBytes;
|
||||
u16 total_packets;
|
||||
u16 current_packet_No;
|
||||
u16 total_bytes;
|
||||
u8 packet_length;
|
||||
}ST_update_slave_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 CadDetected:1;
|
||||
u8 FhssChangeChannel:1;
|
||||
u8 CadDone:1;
|
||||
u8 TxDone:1;
|
||||
u8 ValidHeader:1;
|
||||
u8 PayloadCrcError:1;
|
||||
u8 RxDone:1;
|
||||
u8 RxTimeout:1;
|
||||
}ST_irqFlag;
|
||||
|
||||
enum
|
||||
{
|
||||
RF_ERR = 0x0000,
|
||||
RF_CAD_DETECT = 0x0001,
|
||||
RF_TX_START = 0x0002,
|
||||
RF_TX_SUCCESS = 0x0004,
|
||||
RF_RX_SUCCESS = 0x0008,
|
||||
RF_RX_FAILED = 0x0010,
|
||||
RF_VALID_HEAD = 0x0020,
|
||||
RF_SET_PARAMS = 0x0040,
|
||||
RF_PREAMBLE_TIMEOUT = 0x0080,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
|
||||
void hal_InitRFVariable(void);
|
||||
void hal_InitRF(void);
|
||||
void hal_sRF_InitSPI(void);
|
||||
void hal_sRF_ITConfig(uint32_t irqLine, FunctionalState NewState);
|
||||
u8 hal_sRF_ReadRegister(u8 reg);
|
||||
void hal_sRF_WriteRegister(u8 reg, u8 val);
|
||||
void hal_sRF_DMA_Read(u8 startReg, u8 *pBuffer, u8 length);
|
||||
void hal_sRF_DMA_Write(u8 *pBuffer, u8 length);
|
||||
void hal_sRF_Config(u8 startReg, u8 *pBuffer, u8 length);
|
||||
void hal_sRF_Read(u8 startReg, u8 *pBuffer, u8 length);
|
||||
void hal_sRF_Receive(void);
|
||||
void hal_sRF_Transmit(u8 *pBuffer, u8 length, u8 channel);
|
||||
void hal_sRF_ReadRssi(void);
|
||||
u8 hal_sRF_GetLinkQuality(void);
|
||||
u8 hal_sRF_RssiToLinkQuality(u8 rssi);
|
||||
void hal_sRF_FrequencyHopping(void);
|
||||
void hal_sRF_WhiteningBuffer(u8 *pBuffer, u16 length);
|
||||
bool hal_sRF_CheckPacketValid(u8 *pBuffer, u16 length);
|
||||
void hal_sRF_Sync_Handle(void);
|
||||
void hal_sRF_TRX_Handle(void);
|
||||
|
||||
u8 spiReadWriteByte(u8 data);
|
||||
void SX1276WriteBuffer( uint8_t addr, uint8_t *buffer, uint8_t size );
|
||||
void SX1276ReadBuffer( uint8_t addr, uint8_t *buffer, uint8_t size );
|
||||
void SX1276Write( uint8_t addr, uint8_t data );
|
||||
void SX1276Read( uint8_t addr, uint8_t *data );
|
||||
void SX1276WriteFifo( uint8_t *buffer, uint8_t size );
|
||||
void SX1276ReadFifo( uint8_t *buffer, uint8_t size );
|
||||
void SX1276SetReset( uint8_t state );
|
||||
|
||||
u8 cmp(u8 * buf1, u8* buf2, u8 length);
|
||||
|
||||
void SX1276WriteRxTx( bool txEnable );
|
||||
void hal_sRF_SPI_Config(void);
|
||||
void sRFTransmitHandle(void);
|
||||
void TimeOutHandle(void);
|
||||
void hal_sRF_writeFIFO_DMA(u8 * pBuffer, u8 length);
|
||||
void hal_sRF_readFIFO_DMA(u8 * pBuffer, u8 length);
|
||||
void hal_sRF_Transmit(u8 *pBuffer, u8 length, u8 channel);
|
||||
void hal_sRF_FSK_ITConfig( uint32_t irqLine, FunctionalState NewState);
|
||||
void hal_sRF_ITConfig(uint32_t irqLine, FunctionalState NewState);
|
||||
void hal_sRF_ClearAllRF_IT();
|
||||
|
||||
|
||||
#define hal_fsk_eit_failing(n,NewState) hal_sRF_FSK_ITConfig(DIO##n##_IRQ,NewState)
|
||||
/*!
|
||||
* DIO state read functions mapping
|
||||
*/
|
||||
#define DIO(n) GPIO_ReadInputDataBit( sRF_DIOx_PORT, sRF_DIO##n##_PIN )
|
||||
|
||||
|
||||
#define DIO0 DIO(0)
|
||||
#define DIO1 DIO(1)
|
||||
#define DIO2 DIO(2)
|
||||
#define DIO3 DIO(3)
|
||||
#define DIO4 DIO(4)
|
||||
#define DIO5 DIO(5)
|
||||
#define DEBUG
|
||||
|
||||
/******************* (C) COPYRIGHT 2013 Robulink Technology Ltd.*****END OF FILE****/
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef _INCLUDE_H_
|
||||
#define _INCLUDE_H_
|
||||
|
||||
/************FreeRTOS include*********************/
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
#include "timers.h"
|
||||
#include "event_groups.h"
|
||||
/************standard include************************/
|
||||
#include "string.h"
|
||||
|
||||
/**************user include***********************/
|
||||
#include "Mem.h"
|
||||
#include "Basedefine.h"
|
||||
#include "General.h"
|
||||
|
||||
#include "debug_printf.h"
|
||||
#include "uart.h"
|
||||
#include "Init.h"
|
||||
|
||||
|
||||
#define METER_ADDR_LEN (7)
|
||||
#define METERTABLE_NUM_MAX (300)
|
||||
|
||||
|
||||
#define METER_CLOSE (1)
|
||||
#define METER_OPEN (2)
|
||||
|
||||
#define COMMON_VER
|
||||
#define ONE_UNIT_LEN (16) //一个单元的数据长度
|
||||
|
||||
|
||||
//#define AMT_VER
|
||||
|
||||
|
||||
//#define ONE_UNIT_LEN (17) //一个单元的数据长度
|
||||
|
||||
|
||||
#endif
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
#include "keywd.h"
|
||||
#include "MD5.h"
|
||||
#include "Flash.h"
|
||||
|
||||
|
||||
extern const u16 CRC16_Table[256];
|
||||
/*****************************************************************************
|
||||
* Function : create_keywd
|
||||
* Description : none
|
||||
* Input : u8* keyid
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
bool create_keywd(u8* keyid)
|
||||
{
|
||||
u8 un_id[12];
|
||||
u8 md5_id[16];
|
||||
u16 crc = 0;
|
||||
u8 index = 0;
|
||||
|
||||
if (!read_unique_id(un_id))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
MD5_code(un_id, md5_id, sizeof(un_id));
|
||||
|
||||
for (u16 i = 0; i < KEY_LEN; i++)
|
||||
{
|
||||
keyid[i] = rand()%255;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < KEY_LEN; i++)
|
||||
{
|
||||
if ((i % 32) == 0)
|
||||
{
|
||||
keyid[i] = md5_id[index++];
|
||||
|
||||
if (index >= 16)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crc = GetCRC16(keyid, KEY_LEN -2);
|
||||
|
||||
keyid[KEY_LEN -2] = (u8)(crc %256);
|
||||
keyid[KEY_LEN -1] = (u8)(crc /256);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : set_key_word
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
bool set_key_word(void)
|
||||
{
|
||||
u8 keyid[KEY_LEN];
|
||||
|
||||
for (u32 i = 0; i < KEY_LEN; i++)
|
||||
{
|
||||
if (*((u8*)(FLASH_KEY_ADDRESS + i)) != 0xFF)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( create_keywd(keyid))
|
||||
{
|
||||
if (STM32_FlashPageErase(FLASH_KEY_ADDRESS) == FLH_SUCCESS)
|
||||
{
|
||||
if (STM32_FlashWrite( FLASH_KEY_ADDRESS, keyid, KEY_LEN) == FLH_SUCCESS)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : check_passwd
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
bool check_passwd(void)
|
||||
{
|
||||
u8 unid[12];
|
||||
|
||||
u8 MD5_ID[16];
|
||||
u8 passwd[16];
|
||||
|
||||
u8 temp;
|
||||
|
||||
u8 index = 0;
|
||||
|
||||
u16 crc16 = 0xFFFF;
|
||||
u16 crc_read = 0;
|
||||
bool new_flash_area = TRUE;
|
||||
|
||||
if ( read_unique_id(unid))
|
||||
{
|
||||
MD5_code(unid, MD5_ID, sizeof(unid));
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (u16 i = 0; i < KEY_LEN -2; i++)
|
||||
{
|
||||
temp = *((u8*)(FLASH_KEY_ADDRESS + i));
|
||||
|
||||
if (temp != 0xFF)
|
||||
{
|
||||
new_flash_area = FALSE;
|
||||
}
|
||||
|
||||
crc16 = (crc16 >> 8 ) ^ CRC16_Table[(crc16 ^ temp) & 0xFF];
|
||||
|
||||
if ( (i % 32) == 0)
|
||||
{
|
||||
if (index < sizeof(passwd))
|
||||
{
|
||||
passwd[index++] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
crc16 ^= 0xFFFF;
|
||||
|
||||
crc_read = *((u8*)(FLASH_KEY_ADDRESS + KEY_LEN - 2)) + *((u8*)(FLASH_KEY_ADDRESS + KEY_LEN - 1))*256;
|
||||
|
||||
if (new_flash_area == TRUE)
|
||||
{
|
||||
return set_key_word();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (crc_read == crc16)
|
||||
{
|
||||
if (cmp_datas(passwd, MD5_ID, 16))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef _HEYWD_H_
|
||||
#define _HEYWD_H_
|
||||
|
||||
#include "include.h"
|
||||
|
||||
#define KEY_LEN 1024
|
||||
|
||||
|
||||
bool create_keywd(u8* keyid);
|
||||
bool set_key_word(void);
|
||||
bool check_passwd(void);
|
||||
|
||||
#endif
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* This project provides two demo applications. A low power project that
|
||||
* demonstrates the FreeRTOS tickless mode, and a more comprehensive test and
|
||||
* demo application. The configCREATE_LOW_POWER_DEMO setting (defined at the
|
||||
* top of FreeRTOSConfig.h) is used to select between the two. The low power
|
||||
* demo is implemented and described in main_low_power.c. The more
|
||||
* comprehensive test and demo application is implemented and described in
|
||||
* main_full.c.
|
||||
*
|
||||
* This file implements the code that is not demo specific, including the
|
||||
* hardware setup and FreeRTOS hook functions.
|
||||
*/
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
|
||||
/* ST library functions. */
|
||||
#include "stm32f10x.h"
|
||||
#include "Led.h"
|
||||
#include "debug_printf.h"
|
||||
#include "uart.h"
|
||||
#include "Init.h"
|
||||
#include "addr.h"
|
||||
#include "bl24c512.h"
|
||||
#include "update.h"
|
||||
#include "PHY.h"
|
||||
#include "IRDA.h"
|
||||
#include "rtc_ext.h"
|
||||
#include "file.h"
|
||||
|
||||
//#include "file.h"
|
||||
extern u32 time_cur;
|
||||
extern void dl_task();
|
||||
extern void rp_task();
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Set up the hardware ready to run this demo.
|
||||
*/
|
||||
static void prvSetupHardware( void );
|
||||
|
||||
/*
|
||||
* main_low_power() is used when configCREATE_LOW_POWER_DEMO is set to 1.
|
||||
* main_full() is used when configCREATE_LOW_POWER_DEMO is set to 0.
|
||||
* configCREATE_LOW_POWER_DEMO is defined at the top of main.c.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Prototypes for the standard FreeRTOS callback/hook functions implemented
|
||||
within this file. */
|
||||
void vApplicationMallocFailedHook( void );
|
||||
void vApplicationIdleHook( void );
|
||||
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName );
|
||||
void vApplicationTickHook( void );
|
||||
|
||||
extern void task_gprs(void *pParam);
|
||||
extern void frame3762_task(void *pParam);
|
||||
extern void GDflash_init(void);
|
||||
extern void sj_up_process();
|
||||
extern void ctl_task();
|
||||
extern void sj_ctl_process();
|
||||
extern void send_to_mbus(void *ptr);
|
||||
extern void upgrade_task();
|
||||
extern void send_to_485(void *ptr);
|
||||
|
||||
u8 tedtbuf[100];
|
||||
|
||||
void vTask_bilnk_led(void * led)
|
||||
{
|
||||
//test_led();
|
||||
|
||||
//if (self_test_eeprom())
|
||||
//{
|
||||
// printf("eeprom test OK\r\n");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// printf("eeprom test err\r\n");
|
||||
//}
|
||||
for(;;)
|
||||
{
|
||||
COM_led_on(0);
|
||||
vTaskDelay( 1000 / portTICK_RATE_MS );
|
||||
COM_led_off(0);
|
||||
vTaskDelay( 1000 / portTICK_RATE_MS );
|
||||
}
|
||||
}
|
||||
|
||||
void vTask_wtg(void *ptr)
|
||||
{
|
||||
Iwdg_Init(10);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
FEED_WDG;
|
||||
vTaskDelay( 2000 / portTICK_RATE_MS );
|
||||
time_cur = time_cur + 2;
|
||||
|
||||
//sj_ctl_process();
|
||||
}
|
||||
}
|
||||
|
||||
TaskHandle_t vTask_mac_handle;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void main( void )
|
||||
{
|
||||
for (u8 i = 0; i < 255; i++)
|
||||
{
|
||||
tedtbuf[i] = i+1;
|
||||
}
|
||||
|
||||
/* Prepare the hardware to run this demo. */
|
||||
prvSetupHardware();
|
||||
|
||||
GDflash_init();
|
||||
|
||||
file_read();
|
||||
|
||||
//test_crc();
|
||||
|
||||
xTaskCreate( vTask_bilnk_led, NULL, 100, NULL, 1, NULL);
|
||||
xTaskCreate( vTask_wtg, NULL, 70, NULL, 2, NULL);
|
||||
xTaskCreate( uarts_process_task, NULL, 400, NULL, 3, NULL);
|
||||
xTaskCreate( ExtRTC_Process_Task, "Extern RTC", 200, NULL, 4, NULL);
|
||||
xTaskCreate( task_gprs, NULL, 200, NULL, 5, NULL);
|
||||
xTaskCreate( send_to_485, NULL, 700, NULL, 6, NULL);
|
||||
xTaskCreate( rp_task, NULL, 400, NULL, 7, NULL);
|
||||
xTaskCreate( upgrade_task, NULL, 100, NULL, 10, NULL);
|
||||
|
||||
task_print_start();
|
||||
// create_update_task();
|
||||
vTaskStartScheduler();
|
||||
|
||||
/* The configCREATE_LOW_POWER_DEMO setting is described at the top of
|
||||
this file. */
|
||||
while(1){};
|
||||
|
||||
|
||||
/* This line will never be reached. */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSetupHardware( void )
|
||||
{
|
||||
void SystemCoreClockUpdate( void ); //在函数内部声明外部函数
|
||||
|
||||
RCC_Init();
|
||||
Nvic_Init();
|
||||
|
||||
/* System function that updates the SystemCoreClock variable. */
|
||||
SystemCoreClockUpdate();
|
||||
|
||||
/* Systick is fed from HCLK */
|
||||
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
|
||||
|
||||
/* Essential on STM32 Cortex-M devices. */
|
||||
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4);
|
||||
|
||||
init_all_led();
|
||||
init_local_addr();
|
||||
bl24c512_init();
|
||||
RTC_Init();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationMallocFailedHook( void )
|
||||
{
|
||||
/* vApplicationMallocFailedHook() will only be called if
|
||||
configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook
|
||||
function that will get called if a call to pvPortMalloc() fails.
|
||||
pvPortMalloc() is called internally by the kernel whenever a task, queue,
|
||||
timer or semaphore is created. It is also called by various parts of the
|
||||
demo application. If heap_1.c or heap_2.c are used, then the size of the
|
||||
heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
|
||||
FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
|
||||
to query the size of free heap space that remains (although it does not
|
||||
provide information on how the remaining heap might be fragmented). */
|
||||
taskDISABLE_INTERRUPTS();
|
||||
for( ;; );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationIdleHook( void )
|
||||
{
|
||||
/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
|
||||
to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
|
||||
task. It is essential that code added to this hook function never attempts
|
||||
to block in any way (for example, call xQueueReceive() with a block time
|
||||
specified, or call vTaskDelay()). If the application makes use of the
|
||||
vTaskDelete() API function (as this demo application does) then it is also
|
||||
important that vApplicationIdleHook() is permitted to return to its calling
|
||||
function, because it is the responsibility of the idle task to clean up
|
||||
memory allocated by the kernel to any task that has since been deleted. */
|
||||
//u32 free_byte = xPortGetFreeHeapSize();
|
||||
//free_byte += 1;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
|
||||
{
|
||||
( void ) pcTaskName;
|
||||
( void ) pxTask;
|
||||
|
||||
/* Run time stack overflow checking is performed if
|
||||
configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook
|
||||
function is called if a stack overflow is detected. */
|
||||
taskDISABLE_INTERRUPTS();
|
||||
for( ;; );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vApplicationTickHook( void )
|
||||
{
|
||||
/* This function will be called by each tick interrupt if
|
||||
configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h. User code can be
|
||||
added here, but the tick hook is called from an interrupt context, so
|
||||
code must not attempt to block, and only the interrupt safe FreeRTOS API
|
||||
functions can be used (those that end in FromISR()). */
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vAssertCalled( unsigned long ulLine, const char * const pcFileName )
|
||||
{
|
||||
volatile unsigned long ulSetToNonZeroInDebuggerToContinue = 0;
|
||||
|
||||
/* Parameters are not used. */
|
||||
( void ) ulLine;
|
||||
( void ) pcFileName;
|
||||
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
while( ulSetToNonZeroInDebuggerToContinue == 0 )
|
||||
{
|
||||
/* Use the debugger to set ulSetToNonZeroInDebuggerToContinue to a
|
||||
non zero value to step out of this function to the point that raised
|
||||
this assert(). */
|
||||
__asm volatile( "NOP" );
|
||||
__asm volatile( "NOP" );
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
+2209
File diff suppressed because it is too large
Load Diff
+693
@@ -0,0 +1,693 @@
|
||||
#ifndef __PROTOCOL_H__
|
||||
#define __PROTOCOL_H__
|
||||
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
J188 read meter struct
|
||||
************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 type;
|
||||
u8 id[7];
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[2];
|
||||
}ST_J188_head;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ST_J188_head head;
|
||||
u8 SER;
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_J188_read,* PLST_J188_read;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 current_sum[5];
|
||||
u8 day_sum[5];
|
||||
u8 current_time[7];
|
||||
u8 status[2];
|
||||
}ST_woter_data_block;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ST_J188_head head;
|
||||
u8 SER;
|
||||
ST_woter_data_block data_block;
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_J188_read_woter_ack,* PLST_J188_read_woter_ack;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ST_J188_head head;
|
||||
u8 SER;
|
||||
u8 Data[4];
|
||||
u8 ST0;
|
||||
u8 ST1;
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_XYJ188_read_woter_ack,* PLST_XYJ188_read_woter_ack;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 type;
|
||||
u8 id[7];
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 SER;
|
||||
u8 status[2];
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_J188_err_ack;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ST_J188_head head;
|
||||
u8 SER;
|
||||
u8 status[2];
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_J188_ctrl_ack;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ST_J188_head head;
|
||||
u8 cmd;
|
||||
u8 SER;
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_J188_ctrl;
|
||||
|
||||
/************************************************************************
|
||||
yzsj read meter struct
|
||||
************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI0;
|
||||
u8 DI1;
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_yzsj_read;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 data[3];
|
||||
u8 sum;
|
||||
}ST_yzsj_ack;
|
||||
|
||||
/************************************************************************
|
||||
HHCQ read meter struct
|
||||
************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 MSA;
|
||||
u8 SSA;
|
||||
u8 WMA;
|
||||
u8 type;
|
||||
u8 key;
|
||||
u8 ctrl;
|
||||
u8 lenH;
|
||||
u8 lenL;
|
||||
}ST_HHCQ_head;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 MSA;
|
||||
u8 SSA;
|
||||
u8 WMA;
|
||||
u8 type;
|
||||
u8 key;
|
||||
u8 ctrl;
|
||||
u8 lenH;
|
||||
u8 lenL;
|
||||
u8 data[4];
|
||||
u8 crc8;
|
||||
u8 end16;
|
||||
}ST_HHCQ_read;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 MSA;
|
||||
u8 SSA;
|
||||
u8 WMA;
|
||||
u8 type;
|
||||
u8 key;
|
||||
u8 ctrl;
|
||||
u8 lenH;
|
||||
u8 lenL;
|
||||
u8 id[4];
|
||||
u8 status;
|
||||
u8 data[4];
|
||||
u8 crc8;
|
||||
u8 end16;
|
||||
}ST_HHCQ_read_woter_ack;
|
||||
|
||||
/************************************************************************
|
||||
CS485 read meter struct
|
||||
************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 default80;
|
||||
u8 center_addr[6];
|
||||
u8 ctrl;
|
||||
u8 dataLen[2];
|
||||
u8 default70;
|
||||
u8 DI[2];
|
||||
}st_CS485_head;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
st_CS485_head head;
|
||||
u8 meterCount;
|
||||
u8 meterID[5];
|
||||
u8 day;
|
||||
u8 month;
|
||||
u8 year;
|
||||
u8 crc16[2];
|
||||
u8 end16;
|
||||
}st_CS485_read;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
st_CS485_head head;
|
||||
u8 meterCount;
|
||||
u8 meterID[5];
|
||||
u8 min;
|
||||
u8 hour;
|
||||
u8 day;
|
||||
u8 month;
|
||||
u8 year;
|
||||
u8 meter_data[4];
|
||||
u8 status[2];
|
||||
u8 reserved[2];
|
||||
u8 crc16[2];
|
||||
u8 end16;
|
||||
}st_CS485_ack_ok;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
st_CS485_head head;
|
||||
u8 data[3];
|
||||
u8 crc16[2];
|
||||
u8 endi6;
|
||||
}st_CS485_ack_err;
|
||||
/************************************************************************
|
||||
NJSM read meter struct
|
||||
************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
u8 startEB;
|
||||
u8 cmd80;
|
||||
u8 id[4];
|
||||
u8 len;
|
||||
u8 cs;
|
||||
}st_NJSM485_read;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 startEB;
|
||||
u8 cmd90;
|
||||
u8 id[4];
|
||||
u8 len0F;
|
||||
u8 data[4];
|
||||
u8 period[2];
|
||||
u8 stop[2];
|
||||
u8 status;
|
||||
u8 saved[2];
|
||||
u8 volt[2];
|
||||
u8 temp[2];
|
||||
u8 cs;
|
||||
}st_NJSM485_ack;
|
||||
|
||||
/************************************************************************
|
||||
HZJD read meter struct
|
||||
************************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[2];
|
||||
u8 cs;
|
||||
u8 end16;
|
||||
}st_HZJD_read;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[2];
|
||||
u8 data[4];
|
||||
u8 cs;
|
||||
u8 end16;
|
||||
}st_HZJD_ack;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 addr[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[4];
|
||||
}ST_645_head;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 addr[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 id[6];
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_645_read_ADDR;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 addr[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 defaultAF;
|
||||
u8 defoult02;
|
||||
u8 id[6];
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_645_read_ADDR99;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 addr[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[4];
|
||||
u8 type;
|
||||
u8 meter_id[7];
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_645_read_meter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 saved5[5];
|
||||
u8 type_data;
|
||||
u8 current_sum[5];
|
||||
u8 day_sum[5];
|
||||
u8 kpa[2];
|
||||
u8 current[3];
|
||||
u8 saved16[16];
|
||||
u8 time_sum[3];
|
||||
u8 current_time[7];
|
||||
u8 status[2];
|
||||
}ST_645_woter_data_block;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 frozen_time_flag[3];
|
||||
u8 teminal_read_time[5];
|
||||
u8 meter_type;
|
||||
u8 current_sum[5];
|
||||
u8 check_day_sum[5];
|
||||
u8 saved[21];
|
||||
u8 time_sum[3];
|
||||
u8 current_time[7];
|
||||
u8 status[2];
|
||||
}ST_day_frozen_data_block;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[4];
|
||||
ST_645_woter_data_block data_block;
|
||||
u8 type;
|
||||
u8 meter_id[7];
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_645_read_worter_ack;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[4];
|
||||
ST_day_frozen_data_block data_block;
|
||||
u8 type;
|
||||
u8 meter_id[7];
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_645_read_frozen_woter_ack;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 addr[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[2];
|
||||
u8 MSB;
|
||||
u8 type;
|
||||
u8 saved[2];
|
||||
}ST_645_SFDX_read_meter;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 addr[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[2];
|
||||
u8 MSB;
|
||||
u8 type;
|
||||
u8 current_sum[5];
|
||||
u8 day_sum[5];
|
||||
u8 current_time[7];
|
||||
u8 status[2];
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}ST_645_SFDX_read_ack;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 com_databits:2;
|
||||
u8 com_checkbit:1;
|
||||
u8 com_checkbit_mask:1;
|
||||
u8 com_stopbit:1;
|
||||
u8 com_baud:3;
|
||||
}ST_comConf;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[4];
|
||||
u8 port;
|
||||
u8 meter_config;
|
||||
u8 meter_type;
|
||||
u8 meter_id[7];
|
||||
}ST_E5E50000_packet;//E5E50000 E5E50001
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[4];
|
||||
}ST_E5E50000_ack;//E5E50000 ack
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[4];
|
||||
u8 port;
|
||||
u8 port_config;
|
||||
u8 meter_type;
|
||||
u8 meter_id[7];
|
||||
ST_J188_read packet188;
|
||||
u8 cs;
|
||||
u8 end16;
|
||||
}ST_E5E50001_packet;//E5E50001
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start68;
|
||||
u8 id[6];
|
||||
u8 end68;
|
||||
u8 ctrl;
|
||||
u8 len;
|
||||
u8 DI[4];
|
||||
ST_J188_read_woter_ack packet188;
|
||||
u8 cs;
|
||||
u8 end16;
|
||||
}ST_E5E50001_ack; //E5E50001 ack
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
ST_645_read_meter * com_upPacket_ptr;
|
||||
ST_645_SFDX_read_meter * whsf_upPacket_ptr;
|
||||
ST_E5E50000_packet * e5e50000_upPacket_ptr;
|
||||
ST_E5E50001_packet * e5e50001_upPacket_ptr;
|
||||
}un_upPaket;
|
||||
|
||||
/*********************************************/
|
||||
typedef union
|
||||
{
|
||||
ST_J188_read * J188_read_ptr;
|
||||
ST_yzsj_read * yzsj_read_ptr;
|
||||
ST_HHCQ_read * hhcq_read_ptr;
|
||||
st_CS485_read * CS485_read_ptr;
|
||||
st_NJSM485_read * NJSM485_read_ptr;
|
||||
st_HZJD_read * HZJD_read_ptr;
|
||||
}un_down_read_Packet;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 up_protol;
|
||||
u8 meter_type;
|
||||
u8 meter_protl;
|
||||
u8 meter_port;
|
||||
u8 meter_config;
|
||||
u8 meter_addr[7];
|
||||
u8 plc_DI[4];
|
||||
u8 data[5];
|
||||
u8 status[2];
|
||||
u8 j188DI[2];
|
||||
u8 j188SER;
|
||||
u8 e5e5dat[200];
|
||||
u8 e5e5datLen;
|
||||
}st_params;
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
//福建赛达水表集中器抄表协议
|
||||
typedef struct
|
||||
{
|
||||
u8 FIXED_FE1;
|
||||
u8 FIXED_FE2;
|
||||
u8 FIXED_FE3;
|
||||
u8 StartSymbol; //0x68
|
||||
u8 MeterType;
|
||||
u8 GPRSAddr[7];
|
||||
u8 ControlWord;
|
||||
u8 FrameSum;
|
||||
u8 FrameSn;
|
||||
u16 FrameLength;
|
||||
//Data Area
|
||||
u8 DataFlag[3];
|
||||
//u8 DataSn;
|
||||
u8 MAddr[7];
|
||||
u8 CS;
|
||||
u8 ENDSymbol;
|
||||
|
||||
}ST_FUJIAN_SDPROTOCOL_READWGDATA,*LPST_FUJIAN_SDPROTOCOL_READWGDATA;
|
||||
|
||||
//福建赛达水表集中器抄表返回帧协议
|
||||
typedef struct
|
||||
{
|
||||
u8 StartSymbol; //0x68
|
||||
u8 MeterType;
|
||||
u8 GPRSAddr[7];
|
||||
u8 ControlWord;
|
||||
u8 FrameSum;
|
||||
u8 FrameSn;
|
||||
u16 FrameLength;
|
||||
//Data Area
|
||||
u8 DataFlag[3];
|
||||
//u8 DataSn;
|
||||
u8 MAddr[7];
|
||||
u8 DataBuff[6];
|
||||
u8 CS;
|
||||
u8 ENDSymbol;
|
||||
|
||||
}ST_FUJIAN_SDPROTOCOL_READWGACKDATA,*LPST_FUJIAN_SDPROTOCOL_READWGACKDATA;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 StartSymbol; //0x68
|
||||
u8 CAddr[6];
|
||||
u8 StartaSymbol; //0x68
|
||||
u8 ControlWord;
|
||||
u8 DataLength;
|
||||
//Data Area
|
||||
u8 MAddr[7];
|
||||
u8 Data[4];
|
||||
u8 Status[2];
|
||||
u8 CS;
|
||||
u8 ENDSymbol;
|
||||
}ST_RADIO_MONITOR_DATA_TYPE,*PLST_RADIO_MONITOR_DATA_TYPE;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct _readmf
|
||||
{
|
||||
u8 frameh; //0xAA
|
||||
u8 companyflag[2];//00 00
|
||||
u8 ctrl[2];// 06 01
|
||||
u8 addr[4];// hex => dec
|
||||
u8 rm_year;//dec
|
||||
u8 rm_month;//dec
|
||||
u8 rm_day;//dec
|
||||
u8 standy[6];//00
|
||||
u8 cs;//
|
||||
u8 frameend;//16
|
||||
}ST_CDRS232_READ_MONTH_DATA_FRAME_TYPE,*PLST_CDRS232_READ_MONTH_DATA_FRAME_TYPE;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern u8 calcrc_1byte(u8 abyte);
|
||||
extern u8 calcrc_bytes(u8 *p, u16 len);
|
||||
extern bool check_645_protocol(u8 *buf, u8 length);
|
||||
extern u8 check_HHQQ_protocol(u8 *buf, u8 length);
|
||||
extern bool check_j188_protocol(u8 *buf, u8 length);
|
||||
extern bool check_yzsj_ack_protocol(u8 *buf, u16 len);
|
||||
extern void code_HHCQ_buf(u8 *buf, u8 len);
|
||||
extern void create_read_CS485_Meter(u8* id, u8 *outBuf, u16 *outLen);
|
||||
extern void create_read_HHCQ_Meter(u8 *id, u8 *outBuf, u16 *outLen);
|
||||
extern void create_read_HYgas_Meter(u8 *id, u8 *outBuf, u16 *outLen);
|
||||
extern void create_read_HZJD_Meter(u8 *id, u8 *outBuf, u16 *outLen);
|
||||
extern void create_read_J188_Meter(u8 type, u8 *id, bool j901f, u8 *outBuf, u16 *outLen);
|
||||
extern void create_read_NJSM485_Meter( u8 *id, u8 *outBuf, u16 *outLen);
|
||||
extern void create_read_YZSJ_Meter( u8 *id, u8 *outBuf, u16 *outLen);
|
||||
extern bool CS485_ackPacket_analyse(u8 *inbuf, u16 len, u8 *inID, u8 *out_datas, u8 *out_status);
|
||||
extern void decode_HHCQ_buf(u8* buf);
|
||||
extern u8 get_645_packet_length(u8* buf);
|
||||
extern u8 get_HHCQ_length(u8* buf);
|
||||
extern u8 get_j188_length(u8 *buf);
|
||||
extern bool HHCQ_ackPacket_analyse(u8 *inbuf, u16 len, u8 *inID, u8 *out_datas, u8 *out_status);
|
||||
extern bool HZJD_ackPacket_analyse(u8 *inbuf, u16 len, u8 *inID, u8 *out_datas, u8 *out_status);
|
||||
extern bool J188_ackPacket_analyse(u8 *inbuf, u16 len, u8 *inID, u8 *out_datas, u8 *out_status);
|
||||
extern bool NJSM485_ackPacket_analyse(u8 *inbuf, u16 len, u8 *inID, u8 *out_datas, u8 *out_status);
|
||||
extern u8 * search_645_packet(u8 *buf, u16 length);
|
||||
extern u8 * search_HHCQ_packet(u8* buf, u8 length);
|
||||
extern u8 * search_j188_packet(u8 *buf, u16 length);
|
||||
extern u8 * search_yzsj_packet(u8 *buf, u16 length);
|
||||
extern u8 transparent_tx(u8 *buf, u8 inlen);
|
||||
extern bool YZSJ_ackPacket_analyse(u8 *inbuf, u16 len, u8 *inID, u8 *out_datas, u8 *out_status);
|
||||
extern struct st_meter_temp_value * process_recevied_id(u8 *id);
|
||||
extern bool check_188_read_meter_packet(u8 *buf, u16 length, u8 *type, u8 *id, u8 *j188DI, u8 *j188SER);
|
||||
extern void E5E50001_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern void E5E50000_uplinkPacket_create(st_params * ptr, u8 *inbuf, u8 inLen, u8* outBuf);
|
||||
void CreatFuJian_Protocol_ReadWaterGasMeterDataBlockFrame( u8* str,u8* len,u8* Addr);
|
||||
u8* CheckFuJian_Protocol_ReadWaterGasMeterDataBlockAckFrame( u8* str,u8 len,u8* Addr);
|
||||
void CreatFuJian_Protocol_WaterGasMeter645DataACKFrame( u8* Pstr,u8* len,u8* Addr,u8* Data,u8* Ftime);
|
||||
void CreatFuJian_Protocol_WaterGasMeter645DataERRORACKFrame( u8* Pstr,u8* len,u8* Addr);
|
||||
u8* CheckFuJian_Protocol_ReadXYWaterMeterDataBlockAckFrame( u8* str,u8 len,u8* Addr);
|
||||
void CreatFuJian_Protocol_ReadXYWaterMeterDataBlockFrame( u8* str,u8* len,u8* Addr);
|
||||
void CreatHubei_Protocol_ReadXYWaterMeterDataFrame( u8* str,u16* len,u8* Addr);
|
||||
u8* CheckHubei_Protocol_ReadXYWaterMeterAckDataFrame( u8* str,u8 len,u8* Addr,u8* outaddr);
|
||||
void AnalyzeXYDXAckDataFrameProcess(u8* pData,st_params * pstr);
|
||||
void DLT645_07_watermetertype_ack(u8 *buf);
|
||||
void CreatXinTian_Protocol_ControlONOFFKey(u8* Pstr,u8* Len,u8* Addr,u8 key);
|
||||
void CreatChenDianGuoJi_Protocol_ControlWaterGasMeterKeyAckFrame( u8* Pstr,u8* len,st_params * pstr,u16 key);
|
||||
void CreatChenDianGuoJI_Protocol_WaterGasMeter645DataERRORACKFrame( u8* Pstr,u8* len,st_params * pstr);
|
||||
void CreatReadChangDeConcentratorData(u8* meter_id,u8* outBuf, u16* outLen);
|
||||
void CreatReadChangDeConcentratorDate(u8* outBuf, u16* outLen);
|
||||
//void CreatReadChangDeConcentratorDate(u8* outBuf, u16* outLen);
|
||||
#endif
|
||||
|
||||
+506
@@ -0,0 +1,506 @@
|
||||
#include "rtc_ext.h"
|
||||
#include "bl24c512.h"
|
||||
#include "include.h"
|
||||
|
||||
|
||||
extern void dl_start();
|
||||
extern void rp_start();
|
||||
extern bool is_report_time();
|
||||
extern bool is_dl_time();
|
||||
extern void hb_timeproc();
|
||||
|
||||
st_rtc_ext ERtctime;
|
||||
|
||||
|
||||
void RTC_EXT_da_mode(bool in_mode)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = RTC_SDA_PIN;
|
||||
if (in_mode)
|
||||
{
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
}
|
||||
|
||||
GPIO_Init(RTC_SDA_PIN_PORT, &GPIO_InitStructure );
|
||||
}
|
||||
/*************************************************************
|
||||
函数功能:I2C总线复位。
|
||||
函数名称:I2C_Reset。
|
||||
函数返回:无返回值。
|
||||
函数参数:无参数
|
||||
**************************************************************/
|
||||
void RTC_EXT_Reset(void)
|
||||
{
|
||||
RTC_EXT_da_mode(SDA_MODE_IN);
|
||||
|
||||
while(1)
|
||||
{
|
||||
RTC_SCL_LOW();
|
||||
delayedus(1);
|
||||
RTC_SCL_HIGH();
|
||||
if( RTC_GET_SDA() ==1 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
delayedus(1);
|
||||
}
|
||||
|
||||
RTC_EXT_da_mode(SDA_MODE_OUT);
|
||||
}
|
||||
|
||||
void RTC_EXT_init(void)
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
RCC_APB2PeriphClockCmd(RTC_SDA_PIN_CLK | RTC_SCL_PIN_CLK , ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = RTC_SDA_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init(RTC_SDA_PIN_PORT , &GPIO_InitStructure );
|
||||
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Pin = RTC_SCL_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init(RTC_SCL_PIN_PORT , &GPIO_InitStructure );
|
||||
|
||||
RTC_EXT_Reset();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:产生起始位。
|
||||
函数名称:I2C_GenerateSTART。
|
||||
函数返回:无返回值。
|
||||
函数参数:无参数
|
||||
**************************************************************/
|
||||
void RTC_EXT_GenerateSTART(void)
|
||||
{
|
||||
RTC_SDA_HIGH();//eeprom_da(1);
|
||||
RTC_SCL_HIGH();//eeprom_clk(1);
|
||||
delayedus(2);
|
||||
RTC_SDA_LOW();//eeprom_da(0);
|
||||
delayedus(2);
|
||||
RTC_SCL_LOW();//eeprom_clk(0);
|
||||
delayedus(2);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:产生停始位。
|
||||
函数名称:I2C_GenerateSTOP。
|
||||
函数返回:无返回值。
|
||||
函数参数:无参数
|
||||
**************************************************************/
|
||||
void RTC_EXT_I2C_GenerateSTOP(void)
|
||||
{
|
||||
RTC_SDA_LOW();//eeprom_da(0);
|
||||
delayedus(2);
|
||||
RTC_SCL_HIGH();//eeprom_clk(1);
|
||||
RTC_SDA_LOW();//eeprom_da(0);
|
||||
delayedus(2);
|
||||
RTC_SDA_HIGH();//eeprom_da(1);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:检测应答。
|
||||
函数名称:I2C_check_ack。
|
||||
函数返回:返回值是应答状态。
|
||||
函数参数:无参数。
|
||||
**************************************************************/
|
||||
unsigned char RTC_EXT_check_ack(void)
|
||||
{
|
||||
unsigned char ack=0;
|
||||
RTC_EXT_da_mode(SDA_MODE_IN);
|
||||
RTC_SCL_HIGH();//eeprom_clk(1);
|
||||
//delayedus(1);
|
||||
if(RTC_GET_SDA() ==1)
|
||||
{
|
||||
ack=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ack=1;
|
||||
}
|
||||
RTC_SCL_LOW();//eeprom_clk(0);
|
||||
//delayedus(1);
|
||||
RTC_EXT_da_mode(SDA_MODE_OUT);
|
||||
return ack;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:发送一个应答位。
|
||||
函数名称:I2c_send_ack。
|
||||
函数返回:无返回值。
|
||||
函数参数:无。
|
||||
**************************************************************/
|
||||
void RTC_EXT_send_ack(void)
|
||||
{
|
||||
RTC_SDA_LOW();//eeprom_da(0);
|
||||
//delayedus(1);
|
||||
RTC_SCL_LOW();//eeprom_clk(0);
|
||||
//delayedus(1);
|
||||
RTC_SCL_HIGH();//eeprom_clk(1);
|
||||
//delayedus(1);
|
||||
RTC_SCL_LOW();//eeprom_clk(0);
|
||||
RTC_SDA_HIGH();//eeprom_da(1);
|
||||
}
|
||||
/*************************************************************
|
||||
函数功能:发送一个NO应答。
|
||||
函数名称:I2c_send_no_ack。
|
||||
函数返回:无返回值。
|
||||
函数参数:无。
|
||||
**************************************************************/
|
||||
void RTC_EXT_send_no_ack(void)
|
||||
{
|
||||
RTC_SDA_HIGH();//eeprom_da(1);
|
||||
//delayedus(1);
|
||||
RTC_SCL_LOW();//eeprom_clk(0);
|
||||
//delayedus(1);
|
||||
RTC_SCL_HIGH();//eeprom_clk(1);
|
||||
//delayedus(1);
|
||||
RTC_SCL_LOW();//eeprom_clk(0);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:I2C发送一个字节。
|
||||
函数名称:I2c_send_byte。
|
||||
函数返回:无返回值。
|
||||
函数参数:无。
|
||||
**************************************************************/
|
||||
void RTC_EXT_send_byte(unsigned char data )
|
||||
{
|
||||
unsigned char i;
|
||||
RTC_SCL_LOW(); //eeprom_clk(0);//clk 0
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
if((data&0x80)==0x80)
|
||||
{
|
||||
RTC_SDA_HIGH();//eeprom_da(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RTC_SDA_LOW(); //eeprom_da(0);
|
||||
}
|
||||
RTC_SCL_HIGH(); //eeprom_clk(1);//clk 1
|
||||
//delayedus(1);
|
||||
RTC_SCL_LOW(); //eeprom_clk(0);//clk 0
|
||||
//delayedus(1);
|
||||
data<<=1;
|
||||
}
|
||||
delayedus(90);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:I2C接收一个字节。
|
||||
函数名称:I2c_receive_byte。
|
||||
函数返回:无返回值。
|
||||
函数参数:无。
|
||||
**************************************************************/
|
||||
unsigned char RTC_EXT_receive_byte(void)
|
||||
{
|
||||
unsigned char i;
|
||||
unsigned char rda=0;
|
||||
RTC_EXT_da_mode(SDA_MODE_IN);
|
||||
|
||||
RTC_SCL_LOW(); //eeprom_clk(0);//clk 0
|
||||
//delayedus(1);
|
||||
for(i=0;i<8;i++)
|
||||
{
|
||||
rda<<=1;
|
||||
RTC_SCL_HIGH(); //eeprom_clk(1);//clk 1
|
||||
//delayedus(1);
|
||||
if(RTC_GET_SDA() ==1 )
|
||||
{
|
||||
rda|=0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
rda&=0xFE;
|
||||
}
|
||||
|
||||
RTC_SCL_LOW(); //eeprom_clk(0);//clk
|
||||
//delayedus(1);
|
||||
}
|
||||
RTC_EXT_da_mode(SDA_MODE_OUT);
|
||||
|
||||
return rda;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:RTC8025T读reg
|
||||
函数名称:RTC_read_reg。
|
||||
函数返回:
|
||||
函数参数:
|
||||
**************************************************************/
|
||||
bool RTC_read_reg(u8 reg, u8 *dat)
|
||||
{
|
||||
RTC_EXT_GenerateSTART();
|
||||
RTC_EXT_send_byte(RTC_WRIT_ADDR);
|
||||
|
||||
if(RTC_EXT_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RTC_EXT_send_byte(reg);
|
||||
if(RTC_EXT_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RTC_EXT_GenerateSTART();
|
||||
RTC_EXT_send_byte(RTC_READ_ADDR);
|
||||
if(RTC_EXT_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*dat = RTC_EXT_receive_byte();
|
||||
RTC_EXT_send_no_ack();
|
||||
|
||||
delayedus(1);
|
||||
RTC_EXT_I2C_GenerateSTOP();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:RTC8025T写reg
|
||||
函数名称:RTC_write_reg。
|
||||
函数返回:
|
||||
函数参数:
|
||||
**************************************************************/
|
||||
bool RTC_write_reg(u8 reg, u8 dat)
|
||||
{
|
||||
RTC_EXT_GenerateSTART();
|
||||
RTC_EXT_send_byte(RTC_WRIT_ADDR);
|
||||
|
||||
if(RTC_EXT_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RTC_EXT_send_byte(reg);
|
||||
if(RTC_EXT_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RTC_EXT_send_byte(dat);
|
||||
if(RTC_EXT_check_ack()==0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
RTC_EXT_I2C_GenerateSTOP();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
函数功能:EEPROM任意地址读一字节。
|
||||
函数名称:RTC_test
|
||||
函数返回:
|
||||
函数参数:
|
||||
**************************************************************/
|
||||
void RTC_test(void)
|
||||
{
|
||||
u8 dat_year;
|
||||
u8 dat_mon;
|
||||
u8 dat_day;
|
||||
|
||||
RTC_EXT_init();
|
||||
|
||||
RTC_read_reg(RTC_REG_MONTH, &dat_mon);
|
||||
RTC_read_reg(RTC_REG_YEAR, &dat_year);
|
||||
|
||||
RTC_read_reg(RTC_REG_DAY , &dat_day);
|
||||
|
||||
RTC_write_reg(RTC_REG_YEAR, 16);
|
||||
RTC_write_reg(RTC_REG_MONTH, 6);
|
||||
RTC_write_reg(RTC_REG_DAY, 14);
|
||||
|
||||
RTC_read_reg(RTC_REG_YEAR, &dat_year);
|
||||
RTC_read_reg(RTC_REG_MONTH, &dat_mon);
|
||||
RTC_read_reg(RTC_REG_DAY , &dat_day);
|
||||
|
||||
printf("%d/%d/%d\r\n", dat_year, dat_mon, dat_day);
|
||||
}
|
||||
|
||||
void set_rtc_time(st_rtc_ext rtc_dat)
|
||||
{
|
||||
RTC_EXT_init();
|
||||
|
||||
RTC_write_reg(RTC_REG_SEC, rtc_dat.sec);
|
||||
RTC_write_reg(RTC_REG_MIN, rtc_dat.min);
|
||||
RTC_write_reg(RTC_REG_HOUR, rtc_dat.hour);
|
||||
RTC_write_reg(RTC_REG_WEEK, rtc_dat.week);
|
||||
RTC_write_reg(RTC_REG_DAY, rtc_dat.day);
|
||||
RTC_write_reg(RTC_REG_MONTH, rtc_dat.month);
|
||||
RTC_write_reg(RTC_REG_YEAR, rtc_dat.year);
|
||||
}
|
||||
|
||||
void read_rtc_time(st_rtc_ext * rtc_dat)
|
||||
{
|
||||
RTC_EXT_init();
|
||||
|
||||
st_rtc_ext TempTime1,TempTime2;
|
||||
/*
|
||||
RTC_read_reg(RTC_REG_SEC, &rtc_dat->sec);
|
||||
RTC_read_reg(RTC_REG_MIN, &rtc_dat->min);
|
||||
RTC_read_reg(RTC_REG_HOUR, &rtc_dat->hour);
|
||||
RTC_read_reg(RTC_REG_WEEK, &rtc_dat->week);
|
||||
RTC_read_reg(RTC_REG_DAY, &rtc_dat->day);
|
||||
RTC_read_reg(RTC_REG_MONTH, &rtc_dat->month);
|
||||
RTC_read_reg(RTC_REG_YEAR, &rtc_dat->year);
|
||||
*/
|
||||
|
||||
for(u8 n=0 ;n<3; n++)
|
||||
{
|
||||
|
||||
|
||||
|
||||
RTC_read_reg(RTC_REG_SEC, &TempTime1.sec);
|
||||
RTC_read_reg(RTC_REG_MIN, &TempTime1.min);
|
||||
RTC_read_reg(RTC_REG_HOUR, &TempTime1.hour);
|
||||
RTC_read_reg(RTC_REG_WEEK, &TempTime1.week);
|
||||
RTC_read_reg(RTC_REG_DAY, &TempTime1.day);
|
||||
RTC_read_reg(RTC_REG_MONTH, &TempTime1.month);
|
||||
RTC_read_reg(RTC_REG_YEAR, &TempTime1.year);
|
||||
|
||||
RTC_read_reg(RTC_REG_SEC, &TempTime2.sec);
|
||||
RTC_read_reg(RTC_REG_MIN, &TempTime2.min);
|
||||
RTC_read_reg(RTC_REG_HOUR, &TempTime2.hour);
|
||||
RTC_read_reg(RTC_REG_WEEK, &TempTime2.week);
|
||||
RTC_read_reg(RTC_REG_DAY, &TempTime2.day);
|
||||
RTC_read_reg(RTC_REG_MONTH, &TempTime2.month);
|
||||
RTC_read_reg(RTC_REG_YEAR, &TempTime2.year);
|
||||
|
||||
if((TempTime1.sec == TempTime2.sec) &&
|
||||
(TempTime1.min == TempTime2.min) &&
|
||||
(TempTime1.hour == TempTime2.hour) &&
|
||||
(TempTime1.week == TempTime2.week) &&
|
||||
(TempTime1.day == TempTime2.day) &&
|
||||
(TempTime1.month == TempTime2.month) &&
|
||||
(TempTime1.year == TempTime2.year)
|
||||
)
|
||||
{
|
||||
rtc_dat->sec = TempTime1.sec;
|
||||
rtc_dat->min = TempTime1.min;
|
||||
rtc_dat->hour = TempTime1.hour;
|
||||
rtc_dat->week = TempTime1.week;
|
||||
rtc_dat->day = TempTime1.day;
|
||||
rtc_dat->month = TempTime1.month;
|
||||
rtc_dat->year = TempTime1.year;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RTC_read_reg(RTC_REG_SEC, &rtc_dat->sec);
|
||||
RTC_read_reg(RTC_REG_MIN, &rtc_dat->min);
|
||||
RTC_read_reg(RTC_REG_HOUR, &rtc_dat->hour);
|
||||
RTC_read_reg(RTC_REG_WEEK, &rtc_dat->week);
|
||||
RTC_read_reg(RTC_REG_DAY, &rtc_dat->day);
|
||||
RTC_read_reg(RTC_REG_MONTH, &rtc_dat->month);
|
||||
RTC_read_reg(RTC_REG_YEAR, &rtc_dat->year);
|
||||
|
||||
}
|
||||
|
||||
void read_rtc_stime(sTime *time_dat)
|
||||
{
|
||||
RTC_EXT_init();
|
||||
|
||||
RTC_read_reg(RTC_REG_SEC, &time_dat->second);
|
||||
RTC_read_reg(RTC_REG_MIN, &time_dat->minute);
|
||||
RTC_read_reg(RTC_REG_HOUR, &time_dat->hour);
|
||||
RTC_read_reg(RTC_REG_DAY, &time_dat->day);
|
||||
RTC_read_reg(RTC_REG_MONTH, &time_dat->month);
|
||||
RTC_read_reg(RTC_REG_YEAR, &time_dat->year);
|
||||
}
|
||||
|
||||
u8* GetCurrentTime( void )
|
||||
{
|
||||
return (u8*)&ERtctime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GetExternClockTime(st_rtc_ext * rtc_dat)
|
||||
{
|
||||
MemCpy((u8*)rtc_dat,(u8*)&ERtctime,sizeof(st_rtc_ext));
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CheckTimeDate( st_rtc_ext * rtc_dat )
|
||||
{
|
||||
if(rtc_dat->year < 0x17) return FALSE;
|
||||
if((rtc_dat->month > 0x12) || (rtc_dat->month == 0x00) )return FALSE;
|
||||
if((rtc_dat->day > 0x31) || (rtc_dat->day == 0x00) ) return FALSE;
|
||||
if(rtc_dat->hour > 0x24) return FALSE;
|
||||
if(rtc_dat->min > 0x60) return FALSE;
|
||||
if(rtc_dat->sec > 0x60) return FALSE;
|
||||
if(rtc_dat->week > 0x06) return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static bool is_reset = false;
|
||||
static u32 reset_count = 0;
|
||||
|
||||
|
||||
void ExtRTC_Process_Task(void *ptr)
|
||||
{
|
||||
RTC_EXT_init();
|
||||
read_rtc_time(&ERtctime);
|
||||
|
||||
// if( ( CheckBCDFormat( (u8*)&ERtctime, sizeof(&ERtctime) ) == FALSE ) || (CheckTimeDate(&ERtctime) == FALSE) )
|
||||
// {
|
||||
// ERtctime.year = 0x17;
|
||||
// ERtctime.month = 0x07;
|
||||
// ERtctime.day = 0x01;
|
||||
// ERtctime.hour = 0x10;
|
||||
// ERtctime.min = 0x23;
|
||||
// ERtctime.sec = 0x45;
|
||||
// ERtctime.week = 0x06;
|
||||
//
|
||||
// set_rtc_time(ERtctime);
|
||||
// }
|
||||
|
||||
for (;;)
|
||||
{
|
||||
read_rtc_time(&ERtctime);
|
||||
vTaskDelay( 2000 / portTICK_RATE_MS );
|
||||
|
||||
hb_timeproc();
|
||||
|
||||
if(ERtctime.hour==0x09 && ERtctime.min == 0x30)
|
||||
{
|
||||
is_reset = true;
|
||||
|
||||
}
|
||||
|
||||
if(is_reset)
|
||||
{
|
||||
reset_count ++ ;
|
||||
if(reset_count>60)
|
||||
{
|
||||
SysReset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef _RTC_EXT_H_
|
||||
#define _RTC_EXT_H_
|
||||
|
||||
#include "Basedefine.h"
|
||||
#include "stm32f10x.h"
|
||||
#include "Rtc.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 sec;
|
||||
u8 min;
|
||||
u8 hour;
|
||||
|
||||
u8 day;
|
||||
u8 month;
|
||||
u8 year;
|
||||
|
||||
u8 week;
|
||||
}st_rtc_ext,*PLst_rtc_ext;
|
||||
|
||||
#define RTC_WRIT_ADDR 0x64
|
||||
#define RTC_READ_ADDR 0x65
|
||||
|
||||
#define RTC_REG_SEC 0x00
|
||||
#define RTC_REG_MIN 0x01
|
||||
#define RTC_REG_HOUR 0x02
|
||||
#define RTC_REG_WEEK 0x03
|
||||
#define RTC_REG_DAY 0x04
|
||||
#define RTC_REG_MONTH 0x05
|
||||
#define RTC_REG_YEAR 0x06
|
||||
#define RTC_REG_RAM 0x07
|
||||
#define RTC_REG_MIN_Alarm 0x08
|
||||
#define RTC_REG_WEEK_Alarm 0x09
|
||||
#define RTC_REG_DAY_Alarm 0x0A
|
||||
#define RTC_REG_COUNT0 0x0B
|
||||
#define RTC_REG_COUNT1 0x0C
|
||||
#define RTC_REG_EXT 0x0D
|
||||
#define RTC_REG_FLAG 0x0E
|
||||
#define RTC_REG_CTRL 0x0F
|
||||
|
||||
|
||||
#define RTC_SDA_PIN GPIO_Pin_9
|
||||
#define RTC_SDA_PIN_PORT GPIOB
|
||||
#define RTC_SDA_PIN_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define RTC_SCL_PIN GPIO_Pin_8
|
||||
#define RTC_SCL_PIN_PORT GPIOB
|
||||
#define RTC_SCL_PIN_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
|
||||
|
||||
#define RTC_SDA_HIGH() GPIO_SetBits(RTC_SDA_PIN_PORT, RTC_SDA_PIN)
|
||||
#define RTC_SDA_LOW() GPIO_ResetBits(RTC_SDA_PIN_PORT, RTC_SDA_PIN)
|
||||
|
||||
#define RTC_SCL_HIGH() GPIO_SetBits(RTC_SCL_PIN_PORT, RTC_SCL_PIN)
|
||||
#define RTC_SCL_LOW() GPIO_ResetBits(RTC_SCL_PIN_PORT, RTC_SCL_PIN)
|
||||
|
||||
#define RTC_GET_SDA() GPIO_ReadInputDataBit( RTC_SDA_PIN_PORT, RTC_SDA_PIN)
|
||||
|
||||
|
||||
|
||||
|
||||
void set_rtc_time(st_rtc_ext rtc_dat);
|
||||
void read_rtc_time(st_rtc_ext * rtc_dat);
|
||||
void read_rtc_stime(sTime *time_dat);
|
||||
void read_rtc_stime(sTime *time_dat);
|
||||
void RTC_test(void);
|
||||
void ExtRTC_Process_Task(void *ptr);
|
||||
void GetExternClockTime(st_rtc_ext * rtc_dat);
|
||||
void set_rtc_time(st_rtc_ext rtc_dat);
|
||||
u8* GetCurrentTime( void );
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
/********************************************************************************
|
||||
|
||||
**** Copyright (C), 2017, xx xx xx xx info&tech Co., Ltd. ****
|
||||
|
||||
********************************************************************************
|
||||
* File Name : storage.c
|
||||
* Author : barry
|
||||
* Date : 2017-02-21
|
||||
* Description : .C file function description
|
||||
* Version : 1.0
|
||||
* Function List :
|
||||
*
|
||||
* Record :
|
||||
* 1.Date : 2017-02-21
|
||||
* Author : barry
|
||||
* Modification: Created file
|
||||
|
||||
*************************************************************************************************************/
|
||||
#include "storage.h"
|
||||
#include "protocol.h"
|
||||
#include "General.h"
|
||||
#include "debug_printf.h"
|
||||
#include "bl24c512.h"
|
||||
#include "Mem.h"
|
||||
#include "update.h"
|
||||
#include "Flash.h"
|
||||
#include "uart.h"
|
||||
|
||||
|
||||
// I2C_eeprom_write_buf(WM_ADDR_MANAGER_UNIT_ADDR +5 + (Pload->Index * sizeof(METER_STRUCT_UNITTYPE)), (u8*)Pload, sizeof(METER_STRUCT_UNITTYPE));
|
||||
// I2C_eeprom_read_buf(WM_ADDR_MANAGER_UNIT_ADDR +5 , (u8*)&SJManager.Info[0].Index, sizeof(METER_STRUCT_UNITTYPE)*SJManager.AddrSum);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef _STORAGE_H_
|
||||
#define _STORAGE_H_
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
#define SLAVE_NODE_SIZE 64
|
||||
#define SLAVE_NODE_MAX 10
|
||||
#define INVALID_POS_FLAG 0xFFFF
|
||||
|
||||
#define VALID_NODE_FLAG 0x8899
|
||||
#define INVALID_NODE_FLAG 0xAABB
|
||||
|
||||
#define EEPROM_METER_CONFIG 0
|
||||
|
||||
|
||||
|
||||
|
||||
#define SLAVE_NODE_LEN_ADDR EEPROM_PAGE_SIZE*2 //档案长度存储位置
|
||||
#define SLAVE_NODE_DOC_ADDR EEPROM_PAGE_SIZE*3 //档案数据存储位置
|
||||
|
||||
#define WM_ADDR_MANAGER_UNIT_ADDR (EEPROM_PAGE_SIZE*5) //存储水表地址数据以及管理单元
|
||||
|
||||
#define XYDX_WATERMETER_MONITOR EEPROM_PAGE_SIZE*165 //档案数据存储位置
|
||||
|
||||
|
||||
#define DEFAULT_MAINTAIN_TIME 1
|
||||
|
||||
#define FRALED_COUNT 3
|
||||
|
||||
#define INNER_FLASH_PAGE_SIZE 2048
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) SEMTECH S.A.
|
||||
*/
|
||||
/*!
|
||||
* \file sx1276.c
|
||||
* \brief SX1276 RF chip driver
|
||||
*
|
||||
* \version 2.0.0
|
||||
* \date May 6 2013
|
||||
* \author Gregory Cristian
|
||||
*
|
||||
* Last modified by Miguel Luis on Jun 19 2013
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "include.h"
|
||||
#include "sx1276-Fsk.h"
|
||||
#include "sx1276-FskMisc.h"
|
||||
#include "hal_radio.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// Default settings
|
||||
tFskSettings FskSettings =
|
||||
{
|
||||
492000000, // RFFrequency
|
||||
10000, // Bitrate
|
||||
20000, // Fdev
|
||||
0, // Power
|
||||
40000, // RxBw
|
||||
150000, // RxBwAfc
|
||||
true, // CrcOn
|
||||
true, // AfcOn
|
||||
255 // PayloadLength (set payload size to the maximum for variable mode, else set the exact payload length)
|
||||
};
|
||||
|
||||
extern struct etimer timer_rf;
|
||||
|
||||
sRF_FSK g_fsk = {
|
||||
.states = RF_STATE_IDLE,
|
||||
.index = 0,
|
||||
.packetLenth = 0,
|
||||
.rssi = 0.0,
|
||||
.sync_timeout = 1000,
|
||||
.plyloadtimeout = 1000
|
||||
};
|
||||
|
||||
void SX1276Fsk_recrive_Packet(void);
|
||||
|
||||
/*!
|
||||
* SX1276 FSK registers variable
|
||||
*/
|
||||
extern uint8_t SX1276Regs[];
|
||||
|
||||
tSX1276* SX1276 = ( tSX1276* )SX1276Regs;;
|
||||
|
||||
/*!
|
||||
* Local RF buffer for communication support
|
||||
*/
|
||||
static uint8_t RFBuffer[RF_BUFFER_SIZE];
|
||||
|
||||
/*!
|
||||
* Chunk size of data write in buffer
|
||||
*/
|
||||
//static uint8_t DataChunkSize = 32;
|
||||
|
||||
|
||||
/*!
|
||||
* RF state machine variable
|
||||
*/
|
||||
static uint8_t RFState = RF_STATE_IDLE;
|
||||
|
||||
/*!
|
||||
* Rx management support variables
|
||||
*/
|
||||
|
||||
/*!
|
||||
* PacketTimeout holds the RF packet timeout
|
||||
* SyncSize = [0..8]
|
||||
* VariableSize = [0;1]
|
||||
* AddressSize = [0;1]
|
||||
* PayloadSize = [0..RF_BUFFER_SIZE]
|
||||
* CrcSize = [0;2]
|
||||
* PacketTimeout = ( ( 8 * ( VariableSize + AddressSize + PayloadSize + CrcSize ) / BR ) * 1000.0 ) + 1
|
||||
* Computed timeout is in miliseconds
|
||||
*/
|
||||
//static uint32_t PacketTimeout;
|
||||
|
||||
/*!
|
||||
* Preamble2SyncTimeout
|
||||
* Preamble2SyncTimeout = ( ( 8 * ( PremableSize + SyncSize ) / RFBitrate ) * 1000.0 ) + 1
|
||||
* Computed timeout is in miliseconds
|
||||
*/
|
||||
//static uint32_t Preamble2SyncTimeout;
|
||||
|
||||
//static bool PreambleDetected = false;
|
||||
//static bool SyncWordDetected = false;
|
||||
//static bool PacketDetected = false;
|
||||
static uint16_t RxPacketSize = 0;
|
||||
//static uint8_t RxBytesRead = 0;
|
||||
//static uint8_t TxBytesSent = 0;
|
||||
static double RxPacketRssiValue;
|
||||
static uint32_t RxPacketAfcValue;
|
||||
static uint8_t RxGain = 1;
|
||||
//static uint32_t RxTimeoutTimer = 0;
|
||||
//static uint32_t Preamble2SyncTimer = 0;
|
||||
|
||||
|
||||
//static bool firstReceiveByte = true;
|
||||
|
||||
/*!
|
||||
* Tx management support variables
|
||||
*/
|
||||
static uint16_t TxPacketSize = 0;
|
||||
//static uint32_t TxTimeoutTimer = 0;
|
||||
|
||||
void SX1276FskInit( void )
|
||||
{
|
||||
SX1276FskSetOpMode( RF_OPMODE_SLEEP );
|
||||
SX1276->RegOpMode = ( SX1276->RegOpMode & 0x7F ) | 0x00;
|
||||
SX1276Write( REG_OPMODE, SX1276->RegOpMode );
|
||||
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
|
||||
|
||||
SX1276FskSetDefaults( );
|
||||
SX1276ReadBuffer( REG_OPMODE, SX1276Regs + 1, 0x70 - 1 );
|
||||
|
||||
// Set the device in FSK mode and Sleep Mode
|
||||
SX1276->RegOpMode = RF_OPMODE_MODULATIONTYPE_FSK | RF_OPMODE_SLEEP;
|
||||
SX1276Write( REG_OPMODE, SX1276->RegOpMode );
|
||||
|
||||
SX1276->RegPaRamp = RF_PARAMP_MODULATIONSHAPING_01;
|
||||
SX1276Write( REG_PARAMP, SX1276->RegPaRamp );
|
||||
|
||||
SX1276->RegLna = RF_LNA_GAIN_G1;
|
||||
SX1276Write( REG_LNA, SX1276->RegLna );
|
||||
|
||||
SX1276->RegRxConfig = ( FskSettings.AfcOn == true ) ? RF_RXCONFIG_AFCAUTO_ON: RF_RXCONFIG_AFCAUTO_OFF;
|
||||
SX1276->RegRxConfig |= RF_RXCONFIG_RESTARTRXONCOLLISION_OFF | RF_RXCONFIG_AGCAUTO_ON;// |RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT;
|
||||
|
||||
if( FskSettings.AfcOn == true )
|
||||
{
|
||||
SX1276->RegRxConfig = RF_RXCONFIG_RESTARTRXONCOLLISION_OFF | RF_RXCONFIG_AFCAUTO_ON |
|
||||
RF_RXCONFIG_AGCAUTO_ON;// |RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT;
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276->RegRxConfig = RF_RXCONFIG_RESTARTRXONCOLLISION_OFF | RF_RXCONFIG_AFCAUTO_OFF |
|
||||
RF_RXCONFIG_AGCAUTO_ON;// | RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT;
|
||||
}
|
||||
|
||||
SX1276->RegPreambleLsb = 30;
|
||||
|
||||
SX1276->RegPreambleDetect = RF_PREAMBLEDETECT_DETECTOR_ON | RF_PREAMBLEDETECT_DETECTORSIZE_3 |
|
||||
RF_PREAMBLEDETECT_DETECTORTOL_10;
|
||||
|
||||
SX1276->RegRssiThresh = 0xFF;
|
||||
|
||||
SX1276->RegSyncConfig = RF_SYNCCONFIG_AUTORESTARTRXMODE_OFF | RF_SYNCCONFIG_PREAMBLEPOLARITY_AA |
|
||||
RF_SYNCCONFIG_SYNC_ON |
|
||||
RF_SYNCCONFIG_SYNCSIZE_4;
|
||||
|
||||
SX1276->RegSyncValue1 = 0x69;
|
||||
SX1276->RegSyncValue2 = 0x81;
|
||||
SX1276->RegSyncValue3 = 0x7E;
|
||||
SX1276->RegSyncValue4 = 0x96;
|
||||
|
||||
SX1276->RegPacketConfig1 = RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE | RF_PACKETCONFIG1_DCFREE_OFF |
|
||||
( FskSettings.CrcOn << 4 ) | RF_PACKETCONFIG1_CRCAUTOCLEAR_OFF |
|
||||
RF_PACKETCONFIG1_ADDRSFILTERING_OFF | RF_PACKETCONFIG1_CRCWHITENINGTYPE_CCITT;
|
||||
SX1276FskGetPacketCrcOn( ); // Update CrcOn on FskSettings
|
||||
|
||||
SX1276->RegPayloadLength = FskSettings.PayloadLength;
|
||||
|
||||
// we can now update the registers with our configuration
|
||||
SX1276WriteBuffer( REG_OPMODE, SX1276Regs + 1, 0x70 - 1 );
|
||||
|
||||
// then we need to set the RF settings
|
||||
SX1276FskSetRFFrequency( FskSettings.RFFrequency );
|
||||
SX1276FskSetBitrate( FskSettings.Bitrate );
|
||||
SX1276FskSetFdev( FskSettings.Fdev );
|
||||
|
||||
SX1276FskSetDccBw( &SX1276->RegRxBw, 0, FskSettings.RxBw );
|
||||
SX1276FskSetDccBw( &SX1276->RegAfcBw, 0, FskSettings.RxBwAfc );
|
||||
SX1276FskSetRssiOffset( 0 );
|
||||
|
||||
SX1276FskSetPAOutput( RF_PACONFIG_PASELECT_RFO );
|
||||
//SX1276FskSetPAOutput( RF_PACONFIG_PASELECT_PABOOST );
|
||||
SX1276FskSetPa20dBm( false );
|
||||
SX1276FskSetRFPower( FskSettings.Power );
|
||||
|
||||
|
||||
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
|
||||
|
||||
// Calibrate the HF
|
||||
SX1276FskRxCalibrate( );
|
||||
|
||||
g_fsk.sync_timeout = (u16)(8*8*1000/FskSettings.Bitrate) + 5;
|
||||
g_fsk.plyloadtimeout = (u16)(255*2*8*1000/FskSettings.Bitrate) + 5;
|
||||
|
||||
SX1276Fsk_recrive_Packet();
|
||||
}
|
||||
|
||||
|
||||
void SX1276FskSetDefaults( void )
|
||||
{
|
||||
// REMARK: See SX1276 datasheet for modified default values.
|
||||
|
||||
SX1276Read( REG_VERSION, &SX1276->RegVersion );
|
||||
}
|
||||
|
||||
void SX1276FskSetOpMode( uint8_t opMode )
|
||||
{
|
||||
static uint8_t opModePrev = RF_OPMODE_STANDBY;
|
||||
static bool antennaSwitchTxOnPrev = true;
|
||||
bool antennaSwitchTxOn = false;
|
||||
|
||||
opModePrev = SX1276->RegOpMode & ~RF_OPMODE_MASK;
|
||||
|
||||
if( opMode != opModePrev )
|
||||
{
|
||||
if( opMode == RF_OPMODE_TRANSMITTER )
|
||||
{
|
||||
antennaSwitchTxOn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
antennaSwitchTxOn = false;
|
||||
}
|
||||
if( antennaSwitchTxOn != antennaSwitchTxOnPrev )
|
||||
{
|
||||
antennaSwitchTxOnPrev = antennaSwitchTxOn;
|
||||
//RXTX( antennaSwitchTxOn ); // Antenna switch control
|
||||
}
|
||||
SX1276->RegOpMode = ( SX1276->RegOpMode & RF_OPMODE_MASK ) | opMode;
|
||||
|
||||
SX1276Write( REG_OPMODE, SX1276->RegOpMode );
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t SX1276FskGetOpMode( void )
|
||||
{
|
||||
SX1276Read( REG_OPMODE, &SX1276->RegOpMode );
|
||||
|
||||
return SX1276->RegOpMode & ~RF_OPMODE_MASK;
|
||||
}
|
||||
|
||||
int32_t SX1276FskReadFei( void )
|
||||
{
|
||||
SX1276ReadBuffer( REG_FEIMSB, &SX1276->RegFeiMsb, 2 ); // Reads the FEI value
|
||||
|
||||
return ( int32_t )(( double )( ( ( uint16_t )SX1276->RegFeiMsb << 8 ) | ( uint16_t )SX1276->RegFeiLsb ) * ( double )FREQ_STEP);
|
||||
}
|
||||
|
||||
int32_t SX1276FskReadAfc( void )
|
||||
{
|
||||
SX1276ReadBuffer( REG_AFCMSB, &SX1276->RegAfcMsb, 2 ); // Reads the AFC value
|
||||
return ( int32_t )(( double )( ( ( uint16_t )SX1276->RegAfcMsb << 8 ) | ( uint16_t )SX1276->RegAfcLsb ) * ( double )FREQ_STEP);
|
||||
}
|
||||
|
||||
uint8_t SX1276FskReadRxGain( void )
|
||||
{
|
||||
SX1276Read( REG_LNA, &SX1276->RegLna );
|
||||
return( SX1276->RegLna >> 5 ) & 0x07;
|
||||
}
|
||||
|
||||
double SX1276FskReadRssi( void )
|
||||
{
|
||||
SX1276Read( REG_RSSIVALUE, &SX1276->RegRssiValue ); // Reads the RSSI value
|
||||
|
||||
return -( double )( ( double )SX1276->RegRssiValue / 2.0 );
|
||||
}
|
||||
|
||||
uint8_t SX1276FskGetPacketRxGain( void )
|
||||
{
|
||||
return RxGain;
|
||||
}
|
||||
|
||||
double SX1276FskGetPacketRssi( void )
|
||||
{
|
||||
return RxPacketRssiValue;
|
||||
}
|
||||
|
||||
uint32_t SX1276FskGetPacketAfc( void )
|
||||
{
|
||||
return RxPacketAfcValue;
|
||||
}
|
||||
/*
|
||||
void SX1276FskStartRx( void )
|
||||
{
|
||||
SX1276FskSetRFState( RF_STATE_RX_INIT );
|
||||
}
|
||||
*/
|
||||
void SX1276FskGetRxPacket( void *buffer, uint16_t *size )
|
||||
{
|
||||
*size = RxPacketSize;
|
||||
RxPacketSize = 0;
|
||||
memcpy( ( void * )buffer, ( void * )RFBuffer, ( size_t )*size );
|
||||
}
|
||||
|
||||
void SX1276FskSetTxPacket( const void *buffer, uint16_t size )
|
||||
{
|
||||
TxPacketSize = size;
|
||||
memcpy( ( void * )RFBuffer, buffer, ( size_t )TxPacketSize );
|
||||
|
||||
RFState = RF_STATE_TX_INIT;
|
||||
}
|
||||
|
||||
// Remark: SX1276 must be fully initialized before calling this function
|
||||
uint16_t SX1276FskGetPacketPayloadSize( void )
|
||||
{
|
||||
uint16_t syncSize;
|
||||
uint16_t variableSize;
|
||||
uint16_t addressSize;
|
||||
uint16_t payloadSize;
|
||||
uint16_t crcSize;
|
||||
|
||||
syncSize = ( SX1276->RegSyncConfig & 0x07 ) + 1;
|
||||
variableSize = ( ( SX1276->RegPacketConfig1 & 0x80 ) == 0x80 ) ? 1 : 0;
|
||||
addressSize = ( ( SX1276->RegPacketConfig1 & 0x06 ) != 0x00 ) ? 1 : 0;
|
||||
payloadSize = SX1276->RegPayloadLength;
|
||||
crcSize = ( ( SX1276->RegPacketConfig1 & 0x10 ) == 0x10 ) ? 2 : 0;
|
||||
|
||||
return syncSize + variableSize + addressSize + payloadSize + crcSize;
|
||||
}
|
||||
|
||||
// Remark: SX1276 must be fully initialized before calling this function
|
||||
uint16_t SX1276FskGetPacketHeaderSize( void )
|
||||
{
|
||||
uint16_t preambleSize;
|
||||
uint16_t syncSize;
|
||||
|
||||
preambleSize = ( ( uint16_t )SX1276->RegPreambleMsb << 8 ) | ( uint16_t )SX1276->RegPreambleLsb;
|
||||
syncSize = ( SX1276->RegSyncConfig & 0x07 ) + 1;
|
||||
|
||||
return preambleSize + syncSize;
|
||||
}
|
||||
|
||||
uint8_t SX1276FskGetRFState( void )
|
||||
{
|
||||
return RFState;
|
||||
}
|
||||
|
||||
void SX1276FskSetRFState( uint8_t state )
|
||||
{
|
||||
RFState = state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void start_continuous_mode(void)
|
||||
{
|
||||
//4、BitSyncOn
|
||||
//5、continuous mode
|
||||
//6、RX
|
||||
u8 RegDioMapping[2];
|
||||
u8 temp = 0;;
|
||||
|
||||
SX1276FskSetOpMode(RF_OPMODE_STANDBY);
|
||||
|
||||
switch_Rx();
|
||||
|
||||
RegDioMapping[0] = RF_DIOMAPPING1_DIO0_11 | RF_DIOMAPPING1_DIO1_00 | RF_DIOMAPPING1_DIO2_11 | RF_DIOMAPPING1_DIO3_10;
|
||||
RegDioMapping[1] = RF_DIOMAPPING2_DIO4_00 | RF_DIOMAPPING2_DIO5_11 | RF_DIOMAPPING2_MAP_PREAMBLEDETECT;
|
||||
SX1276WriteBuffer( REG_DIOMAPPING1, RegDioMapping, 2 );
|
||||
|
||||
SX1276Read(REG_OOKPEAK, &temp);
|
||||
temp |= (0x20);
|
||||
SX1276Write(REG_OOKPEAK, temp);
|
||||
|
||||
SX1276Read(REG_PACKETCONFIG2, &temp);
|
||||
temp &= (~0x40);
|
||||
SX1276Write(REG_PACKETCONFIG2, temp);
|
||||
|
||||
SX1276FskSetOpMode(RF_OPMODE_RECEIVER);
|
||||
}
|
||||
|
||||
void packet_tx_data(u8 *PBuffer,u8 length)
|
||||
{
|
||||
g_fsk.buffer[0] = length;
|
||||
|
||||
memcpy( ( void * )(g_fsk.buffer+1), PBuffer, length);
|
||||
|
||||
g_fsk.packetLenth = length + 1;
|
||||
|
||||
g_fsk.index = 0;
|
||||
}
|
||||
|
||||
void fill_fifo(void)
|
||||
{
|
||||
u8 sendLenth;
|
||||
|
||||
u8 leftlength = g_fsk.packetLenth - g_fsk.index;
|
||||
|
||||
if (g_fsk.index == 0)
|
||||
{
|
||||
if (leftlength <= 64)
|
||||
{
|
||||
SX1276WriteFifo(g_fsk.buffer, leftlength);
|
||||
g_fsk.index += leftlength;
|
||||
hal_DIOx_ITConfig(1,DISABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276WriteFifo(g_fsk.buffer, 64);
|
||||
g_fsk.index += 64;
|
||||
}
|
||||
}
|
||||
else if (g_fsk.index < g_fsk.packetLenth)
|
||||
{
|
||||
sendLenth = ( leftlength > (FIFO_LENGTH - TX_FIFO_THRESHOLD) ? (FIFO_LENGTH - TX_FIFO_THRESHOLD) : leftlength);
|
||||
SX1276WriteFifo(g_fsk.buffer+g_fsk.index, sendLenth);
|
||||
g_fsk.index += sendLenth;
|
||||
}
|
||||
}
|
||||
|
||||
void contious_tx(void)
|
||||
{
|
||||
SX1276->RegFifoThresh = RF_FIFOTHRESH_TXSTARTCONDITION_FIFOTHRESH | TX_FIFO_THRESHOLD; // 24 bytes of data
|
||||
SX1276Write( REG_FIFOTHRESH, SX1276->RegFifoThresh );
|
||||
switch_Tx();
|
||||
SX1276FskSetOpMode( RF_OPMODE_TRANSMITTER );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void read_fifo(bool rxdone)
|
||||
{
|
||||
u8 leftlength;
|
||||
|
||||
if (g_fsk.index == 0)
|
||||
{
|
||||
SX1276ReadFifo(&g_fsk.packetLenth , 1);
|
||||
}
|
||||
|
||||
leftlength = g_fsk.packetLenth - g_fsk.index;
|
||||
|
||||
if (rxdone)
|
||||
{
|
||||
if (leftlength <= FIFO_LENGTH)
|
||||
{
|
||||
//hal_DIOx_ITConfig(all,DISABLE);
|
||||
SX1276ReadFifo(g_fsk.buffer+g_fsk.index, leftlength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g_fsk.index < (g_fsk.packetLenth -1) )
|
||||
{
|
||||
SX1276ReadFifo(g_fsk.buffer+g_fsk.index, RX_FIFO_THRESHOLD);
|
||||
g_fsk.index += RX_FIFO_THRESHOLD;
|
||||
}
|
||||
|
||||
leftlength = g_fsk.packetLenth - g_fsk.index;
|
||||
|
||||
if (leftlength <= FIFO_LENGTH)
|
||||
{
|
||||
hal_DIOx_ITConfig(1,DISABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SX1276Fsk_Send_Packet(u8 *PBuffer,u8 length)
|
||||
{
|
||||
hal_DIOx_ITConfig(all, DISABLE);
|
||||
|
||||
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
|
||||
// PacketSent, FifoLevel, FifoFull, TxReady
|
||||
SX1276->RegDioMapping1 = packet_DIO0_packetSend | packet_DIO1_fifoLevel | packet_DIO2_fifoFull | packet_DIO3_TxReady;
|
||||
// LowBat, Data
|
||||
SX1276->RegDioMapping2 = packet_DIO4_TimeOut | packet_DIO5_Data ;
|
||||
|
||||
SX1276WriteBuffer( REG_DIOMAPPING1, &SX1276->RegDioMapping1, 2 );
|
||||
|
||||
SX1276->RegFifoThresh = RF_FIFOTHRESH_TXSTARTCONDITION_FIFONOTEMPTY | TX_FIFO_THRESHOLD; // 24 bytes of data
|
||||
SX1276Write( REG_FIFOTHRESH, SX1276->RegFifoThresh );
|
||||
|
||||
packet_tx_data(PBuffer, length);
|
||||
|
||||
hal_DIOx_ITConfig(0,ENABLE);
|
||||
hal_DIOx_ITConfig(1,ENABLE);
|
||||
|
||||
fill_fifo();
|
||||
|
||||
switch_Tx();
|
||||
g_fsk.states = RF_STATE_TX_RUNNING;
|
||||
|
||||
SX1276FskSetOpMode( RF_OPMODE_TRANSMITTER );
|
||||
}
|
||||
|
||||
|
||||
void SX1276Fsk_recrive_Packet(void)
|
||||
{
|
||||
|
||||
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
|
||||
|
||||
hal_DIOx_ITConfig(all, DISABLE);
|
||||
|
||||
SX1276->RegDioMapping1 = packet_DIO0_RxpayloadReady | packet_DIO1_fifoLevel | packet_DIO2_SyncAddress | packet_DIO3_fifoEmpty;
|
||||
// LowBat, Data
|
||||
SX1276->RegDioMapping2 = packet_DIO4_Rssi_PreambleDetect | packet_DIO5_Data | RF_DIOMAPPING2_MAP_PREAMBLEDETECT;
|
||||
|
||||
SX1276WriteBuffer( REG_DIOMAPPING1, &SX1276->RegDioMapping1, 2 );
|
||||
|
||||
SX1276->RegFifoThresh = RF_FIFOTHRESH_TXSTARTCONDITION_FIFONOTEMPTY | RX_FIFO_THRESHOLD; // 24 bytes of data
|
||||
SX1276Write( REG_FIFOTHRESH, SX1276->RegFifoThresh );
|
||||
|
||||
g_fsk.states = RF_STATE_RX_INIT;
|
||||
|
||||
g_fsk.index = 0;
|
||||
|
||||
hal_DIOx_ITConfig(4,ENABLE);
|
||||
hal_DIOx_ITConfig(0,ENABLE);
|
||||
hal_DIOx_ITConfig(1,ENABLE);
|
||||
hal_DIOx_ITConfig(2,ENABLE);
|
||||
hal_DIOx_ITConfig(3,ENABLE);
|
||||
|
||||
switch_Rx();
|
||||
|
||||
SX1276FskSetOpMode( RF_OPMODE_RECEIVER );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*****************************************************************************
|
||||
Prototype : GPIO_EVEN_IRQHandler
|
||||
Description :
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2016/08/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void GPIO_EVEN_IRQHandler(void)
|
||||
{
|
||||
u32 flags = GPIO->IF;
|
||||
GPIO->IFC = flags;
|
||||
|
||||
if(flags & (1 << sRF_DIO0_PIN) )
|
||||
{
|
||||
hal_DIOx_ITConfig(all, DISABLE);
|
||||
hal_sRF_ClearAllRF_IT();
|
||||
|
||||
if(g_fsk.states == RF_STATE_TX_RUNNING)
|
||||
{
|
||||
// Tx done
|
||||
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
|
||||
g_fsk.states = RF_STATE_TX_DONE;
|
||||
process_post(&hal_RF_process, PROCESS_EVENT_MSG, (void *)(&g_fsk.states));
|
||||
}
|
||||
|
||||
if(g_fsk.states == RF_STATE_RX_SYNC)
|
||||
{
|
||||
// Rx done
|
||||
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
|
||||
read_fifo(true);
|
||||
etimer_stop(&timer_rf);
|
||||
g_fsk.states = RF_STATE_RX_DONE;
|
||||
process_post(&hal_RF_process, PROCESS_EVENT_MSG, (void *)(&g_fsk.states));
|
||||
}
|
||||
}
|
||||
else if (flags & (1 << sRF_DIO2_PIN) )
|
||||
{
|
||||
if(g_fsk.states == RF_STATE_TX_RUNNING)
|
||||
{
|
||||
hal_DIOx_ITConfig(all,DISABLE);
|
||||
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
|
||||
}
|
||||
//sync detect
|
||||
if(g_fsk.states == RF_STATE_RX_PREAMBLE)
|
||||
{
|
||||
hal_DIOx_ITConfig(2,DISABLE);
|
||||
etimer_remodify(&timer_rf, g_fsk.plyloadtimeout);
|
||||
printf("sync det\r\n");
|
||||
g_fsk.states = RF_STATE_RX_SYNC;
|
||||
g_fsk.rssi = SX1276FskReadRssi( );
|
||||
}
|
||||
}
|
||||
else if (flags & (1 << sRF_DIO3_PIN) )
|
||||
{
|
||||
hal_DIOx_ITConfig(all,DISABLE);
|
||||
SX1276FskSetOpMode( RF_OPMODE_STANDBY );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GPIO_ODD_IRQHandler(void)
|
||||
{
|
||||
u32 flags = GPIO->IF;
|
||||
GPIO->IFC = flags;
|
||||
|
||||
if (flags & (1 << sRF_DIO1_PIN) )
|
||||
{
|
||||
if(g_fsk.states == RF_STATE_TX_RUNNING)
|
||||
{
|
||||
fill_fifo();
|
||||
}
|
||||
|
||||
if(g_fsk.states == RF_STATE_RX_SYNC)
|
||||
{
|
||||
read_fifo(false);
|
||||
}
|
||||
}
|
||||
else if (flags & (1 << sRF_DIO4_PIN) )
|
||||
{
|
||||
if(g_fsk.states == RF_STATE_RX_INIT)
|
||||
{
|
||||
hal_DIOx_ITConfig(4,DISABLE);
|
||||
etimer_remodify(&timer_rf, g_fsk.sync_timeout); //不执行这个的话,中断函数少点时间,执行的话,可快速判断超时
|
||||
printf("preamble det\r\n");
|
||||
g_fsk.states = RF_STATE_RX_PREAMBLE;
|
||||
process_post(&hal_RF_process, PROCESS_EVENT_MSG, (void *)(&g_fsk.states));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+1500
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) SEMTECH S.A.
|
||||
*/
|
||||
/*!
|
||||
* \file sx1276-FskMisc.c
|
||||
* \brief SX1276 RF chip high level functions driver
|
||||
*
|
||||
* \remark Optional support functions.
|
||||
* These functions are defined only to easy the change of the
|
||||
* parameters.
|
||||
* For a final firmware the radio parameters will be known so
|
||||
* there is no need to support all possible parameters.
|
||||
* Removing these functions will greatly reduce the final firmware
|
||||
* size.
|
||||
*
|
||||
* \version 2.0.0
|
||||
* \date May 6 2013
|
||||
* \author Gregory Cristian
|
||||
*
|
||||
* Last modified by Miguel Luis on Jun 19 2013
|
||||
*/
|
||||
#include <math.h>
|
||||
|
||||
#include "hal_radio.h"
|
||||
#include "sx1276-Fsk.h"
|
||||
#include "sx1276-FskMisc.h"
|
||||
|
||||
|
||||
extern tFskSettings FskSettings;
|
||||
|
||||
void SX1276FskSetRFFrequency( uint32_t freq )
|
||||
{
|
||||
FskSettings.RFFrequency = freq;
|
||||
|
||||
freq = ( uint32_t )( ( double )freq / ( double )FREQ_STEP );
|
||||
SX1276->RegFrfMsb = ( uint8_t )( ( freq >> 16 ) & 0xFF );
|
||||
SX1276->RegFrfMid = ( uint8_t )( ( freq >> 8 ) & 0xFF );
|
||||
SX1276->RegFrfLsb = ( uint8_t )( freq & 0xFF );
|
||||
SX1276WriteBuffer( REG_FRFMSB, &SX1276->RegFrfMsb, 3 );
|
||||
}
|
||||
|
||||
uint32_t SX1276FskGetRFFrequency( void )
|
||||
{
|
||||
SX1276ReadBuffer( REG_FRFMSB, &SX1276->RegFrfMsb, 3 );
|
||||
FskSettings.RFFrequency = ( ( uint32_t )SX1276->RegFrfMsb << 16 ) | ( ( uint32_t )SX1276->RegFrfMid << 8 ) | ( ( uint32_t )SX1276->RegFrfLsb );
|
||||
FskSettings.RFFrequency = ( uint32_t )( ( double )FskSettings.RFFrequency * ( double )FREQ_STEP );
|
||||
|
||||
return FskSettings.RFFrequency;
|
||||
}
|
||||
|
||||
void SX1276FskRxCalibrate( void )
|
||||
{
|
||||
// the function RadioRxCalibrate is called just after the reset so all register are at their default values
|
||||
uint8_t regPaConfigInitVal;
|
||||
uint32_t initialFreq;
|
||||
|
||||
// save register values;
|
||||
SX1276Read( REG_PACONFIG, ®PaConfigInitVal );
|
||||
initialFreq = SX1276FskGetRFFrequency( );
|
||||
|
||||
// Cut the PA just in case
|
||||
SX1276->RegPaConfig = 0x00; // RFO output, power = -1 dBm
|
||||
SX1276Write( REG_PACONFIG, SX1276->RegPaConfig );
|
||||
|
||||
// Set Frequency in HF band
|
||||
SX1276FskSetRFFrequency( 860000000 );
|
||||
|
||||
// Rx chain re-calibration workaround
|
||||
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
|
||||
SX1276->RegImageCal = ( SX1276->RegImageCal & RF_IMAGECAL_IMAGECAL_MASK ) | RF_IMAGECAL_IMAGECAL_START;
|
||||
SX1276Write( REG_IMAGECAL, SX1276->RegImageCal );
|
||||
|
||||
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
|
||||
// rx_cal_run goes low when calibration in finished
|
||||
while( ( SX1276->RegImageCal & RF_IMAGECAL_IMAGECAL_RUNNING ) == RF_IMAGECAL_IMAGECAL_RUNNING )
|
||||
{
|
||||
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
|
||||
}
|
||||
|
||||
// reload saved values into the registers
|
||||
SX1276->RegPaConfig = regPaConfigInitVal;
|
||||
SX1276Write( REG_PACONFIG, SX1276->RegPaConfig );
|
||||
|
||||
SX1276FskSetRFFrequency( initialFreq );
|
||||
|
||||
}
|
||||
|
||||
void SX1276FskSetBitrate( uint32_t bitrate )
|
||||
{
|
||||
FskSettings.Bitrate = bitrate;
|
||||
|
||||
bitrate = ( uint16_t )( ( double )XTAL_FREQ / ( double )bitrate );
|
||||
SX1276->RegBitrateMsb = ( uint8_t )( bitrate >> 8 );
|
||||
SX1276->RegBitrateLsb = ( uint8_t )( bitrate & 0xFF );
|
||||
SX1276WriteBuffer( REG_BITRATEMSB, &SX1276->RegBitrateMsb, 2 );
|
||||
}
|
||||
|
||||
uint32_t SX1276FskGetBitrate( void )
|
||||
{
|
||||
SX1276ReadBuffer( REG_BITRATEMSB, &SX1276->RegBitrateMsb, 2 );
|
||||
FskSettings.Bitrate = ( ( ( uint32_t )SX1276->RegBitrateMsb << 8 ) | ( ( uint32_t )SX1276->RegBitrateLsb ) );
|
||||
FskSettings.Bitrate = ( uint16_t )( ( double )XTAL_FREQ / ( double )FskSettings.Bitrate );
|
||||
|
||||
return FskSettings.Bitrate;
|
||||
}
|
||||
|
||||
void SX1276FskSetFdev( uint32_t fdev )
|
||||
{
|
||||
FskSettings.Fdev = fdev;
|
||||
|
||||
SX1276Read( REG_FDEVMSB, &SX1276->RegFdevMsb );
|
||||
|
||||
fdev = ( uint16_t )( ( double )fdev / ( double )FREQ_STEP );
|
||||
SX1276->RegFdevMsb = ( ( SX1276->RegFdevMsb & RF_FDEVMSB_FDEV_MASK ) | ( ( ( uint8_t )( fdev >> 8 ) ) & ~RF_FDEVMSB_FDEV_MASK ) );
|
||||
SX1276->RegFdevLsb = ( uint8_t )( fdev & 0xFF );
|
||||
SX1276WriteBuffer( REG_FDEVMSB, &SX1276->RegFdevMsb, 2 );
|
||||
}
|
||||
|
||||
uint32_t SX1276FskGetFdev( void )
|
||||
{
|
||||
SX1276ReadBuffer( REG_FDEVMSB, &SX1276->RegFdevMsb, 2 );
|
||||
FskSettings.Fdev = ( ( ( uint32_t )( ( SX1276->RegFdevMsb << 8 ) & ~RF_FDEVMSB_FDEV_MASK ) ) | ( ( uint32_t )SX1276->RegFdevLsb ) );
|
||||
FskSettings.Fdev = ( uint16_t )( ( double )FskSettings.Fdev * ( double )FREQ_STEP );
|
||||
|
||||
return FskSettings.Fdev;
|
||||
}
|
||||
|
||||
void SX1276FskSetRFPower( int8_t power )
|
||||
{
|
||||
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
|
||||
SX1276Read( REG_PADAC, &SX1276->RegPaDac );
|
||||
|
||||
if( ( SX1276->RegPaConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
|
||||
{
|
||||
if( ( SX1276->RegPaDac & 0x87 ) == 0x87 )
|
||||
{
|
||||
if( power < 5 )
|
||||
{
|
||||
power = 5;
|
||||
}
|
||||
if( power > 20 )
|
||||
{
|
||||
power = 20;
|
||||
}
|
||||
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_MAX_POWER_MASK ) | 0x70;
|
||||
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( power < 2 )
|
||||
{
|
||||
power = 2;
|
||||
}
|
||||
if( power > 17 )
|
||||
{
|
||||
power = 17;
|
||||
}
|
||||
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_MAX_POWER_MASK ) | 0x70;
|
||||
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( power < -1 )
|
||||
{
|
||||
power = -1;
|
||||
}
|
||||
if( power > 14 )
|
||||
{
|
||||
power = 14;
|
||||
}
|
||||
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_MAX_POWER_MASK ) | 0x70;
|
||||
SX1276->RegPaConfig = ( SX1276->RegPaConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power + 1 ) & 0x0F );
|
||||
}
|
||||
SX1276Write( REG_PACONFIG, SX1276->RegPaConfig );
|
||||
FskSettings.Power = power;
|
||||
}
|
||||
|
||||
int8_t SX1276FskGetRFPower( void )
|
||||
{
|
||||
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
|
||||
SX1276Read( REG_PADAC, &SX1276->RegPaDac );
|
||||
|
||||
if( ( SX1276->RegPaConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
|
||||
{
|
||||
if( ( SX1276->RegPaDac & 0x07 ) == 0x07 )
|
||||
{
|
||||
FskSettings.Power = 5 + ( SX1276->RegPaConfig & ~RF_PACONFIG_OUTPUTPOWER_MASK );
|
||||
}
|
||||
else
|
||||
{
|
||||
FskSettings.Power = 2 + ( SX1276->RegPaConfig & ~RF_PACONFIG_OUTPUTPOWER_MASK );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FskSettings.Power = -1 + ( SX1276->RegPaConfig & ~RF_PACONFIG_OUTPUTPOWER_MASK );
|
||||
}
|
||||
return FskSettings.Power;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Computes the Rx bandwidth with the mantisse and exponent
|
||||
*
|
||||
* \param [IN] mantisse Mantisse of the bandwidth value
|
||||
* \param [IN] exponent Exponent of the bandwidth value
|
||||
* \retval bandwidth Computed bandwidth
|
||||
*/
|
||||
static uint32_t SX1276FskComputeRxBw( uint8_t mantisse, uint8_t exponent )
|
||||
{
|
||||
// rxBw
|
||||
if( ( SX1276->RegOpMode & RF_OPMODE_MODULATIONTYPE_FSK ) == RF_OPMODE_MODULATIONTYPE_FSK )
|
||||
{
|
||||
return ( uint32_t )( ( double )XTAL_FREQ / ( mantisse * ( double )pow( 2, exponent + 2 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( uint32_t )( ( double )XTAL_FREQ / ( mantisse * ( double )pow( 2, exponent + 3 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Computes the mantisse and exponent from the bandwitdh value
|
||||
*
|
||||
* \param [IN] rxBwValue Bandwidth value
|
||||
* \param [OUT] mantisse Mantisse of the bandwidth value
|
||||
* \param [OUT] exponent Exponent of the bandwidth value
|
||||
*/
|
||||
static void SX1276FskComputeRxBwMantExp( uint32_t rxBwValue, uint8_t* mantisse, uint8_t* exponent )
|
||||
{
|
||||
uint8_t tmpExp = 0;
|
||||
uint8_t tmpMant = 0;
|
||||
|
||||
double tmpRxBw = 0;
|
||||
double rxBwMin = 10e6;
|
||||
|
||||
for( tmpExp = 0; tmpExp < 8; tmpExp++ )
|
||||
{
|
||||
for( tmpMant = 16; tmpMant <= 24; tmpMant += 4 )
|
||||
{
|
||||
if( ( SX1276->RegOpMode & RF_OPMODE_MODULATIONTYPE_FSK ) == RF_OPMODE_MODULATIONTYPE_FSK )
|
||||
{
|
||||
tmpRxBw = ( double )XTAL_FREQ / ( tmpMant * ( double )pow( 2, tmpExp + 2 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpRxBw = ( double )XTAL_FREQ / ( tmpMant * ( double )pow( 2, tmpExp + 3 ) );
|
||||
}
|
||||
if( fabs( tmpRxBw - rxBwValue ) < rxBwMin )
|
||||
{
|
||||
rxBwMin = fabs( tmpRxBw - rxBwValue );
|
||||
*mantisse = tmpMant;
|
||||
*exponent = tmpExp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SX1276FskSetDccBw( uint8_t* reg, uint32_t dccValue, uint32_t rxBwValue )
|
||||
{
|
||||
uint8_t mantisse = 0;
|
||||
uint8_t exponent = 0;
|
||||
|
||||
if( reg == &SX1276->RegRxBw )
|
||||
{
|
||||
*reg = ( uint8_t )dccValue & 0x60;
|
||||
}
|
||||
else
|
||||
{
|
||||
*reg = 0;
|
||||
}
|
||||
|
||||
SX1276FskComputeRxBwMantExp( rxBwValue, &mantisse, &exponent );
|
||||
|
||||
switch( mantisse )
|
||||
{
|
||||
case 16:
|
||||
*reg |= ( uint8_t )( 0x00 | ( exponent & 0x07 ) );
|
||||
break;
|
||||
case 20:
|
||||
*reg |= ( uint8_t )( 0x08 | ( exponent & 0x07 ) );
|
||||
break;
|
||||
case 24:
|
||||
*reg |= ( uint8_t )( 0x10 | ( exponent & 0x07 ) );
|
||||
break;
|
||||
default:
|
||||
// Something went terribely wrong
|
||||
break;
|
||||
}
|
||||
|
||||
if( reg == &SX1276->RegRxBw )
|
||||
{
|
||||
SX1276Write( REG_RXBW, *reg );
|
||||
FskSettings.RxBw = rxBwValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276Write( REG_AFCBW, *reg );
|
||||
FskSettings.RxBwAfc = rxBwValue;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t SX1276FskGetBw( uint8_t* reg )
|
||||
{
|
||||
uint32_t rxBwValue = 0;
|
||||
uint8_t mantisse = 0;
|
||||
switch( ( *reg & 0x18 ) >> 3 )
|
||||
{
|
||||
case 0:
|
||||
mantisse = 16;
|
||||
break;
|
||||
case 1:
|
||||
mantisse = 20;
|
||||
break;
|
||||
case 2:
|
||||
mantisse = 24;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
rxBwValue = SX1276FskComputeRxBw( mantisse, ( uint8_t )*reg & 0x07 );
|
||||
if( reg == &SX1276->RegRxBw )
|
||||
{
|
||||
return FskSettings.RxBw = rxBwValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FskSettings.RxBwAfc = rxBwValue;
|
||||
}
|
||||
}
|
||||
|
||||
void SX1276FskSetPacketCrcOn( bool enable )
|
||||
{
|
||||
SX1276Read( REG_PACKETCONFIG1, &SX1276->RegPacketConfig1 );
|
||||
SX1276->RegPacketConfig1 = ( SX1276->RegPacketConfig1 & RF_PACKETCONFIG1_CRC_MASK ) | ( enable << 4 );
|
||||
SX1276Write( REG_PACKETCONFIG1, SX1276->RegPacketConfig1 );
|
||||
FskSettings.CrcOn = enable;
|
||||
}
|
||||
|
||||
bool SX1276FskGetPacketCrcOn( void )
|
||||
{
|
||||
SX1276Read( REG_PACKETCONFIG1, &SX1276->RegPacketConfig1 );
|
||||
FskSettings.CrcOn = (bool)(( SX1276->RegPacketConfig1 & RF_PACKETCONFIG1_CRC_ON ) >> 4);
|
||||
return FskSettings.CrcOn;
|
||||
}
|
||||
|
||||
void SX1276FskSetAfcOn( bool enable )
|
||||
{
|
||||
SX1276Read( REG_RXCONFIG, &SX1276->RegRxConfig );
|
||||
SX1276->RegRxConfig = ( SX1276->RegRxConfig & RF_RXCONFIG_AFCAUTO_MASK ) | ( enable << 4 );
|
||||
SX1276Write( REG_RXCONFIG, SX1276->RegRxConfig );
|
||||
FskSettings.AfcOn = enable;
|
||||
}
|
||||
|
||||
bool SX1276FskGetAfcOn( void )
|
||||
{
|
||||
SX1276Read( REG_RXCONFIG, &SX1276->RegRxConfig );
|
||||
FskSettings.AfcOn = (bool)(( SX1276->RegRxConfig & RF_RXCONFIG_AFCAUTO_ON ) >> 4);
|
||||
return FskSettings.AfcOn;
|
||||
}
|
||||
|
||||
void SX1276FskSetPayloadLength( uint8_t value )
|
||||
{
|
||||
SX1276->RegPayloadLength = value;
|
||||
SX1276Write( REG_PAYLOADLENGTH, SX1276->RegPayloadLength );
|
||||
FskSettings.PayloadLength = value;
|
||||
}
|
||||
|
||||
uint8_t SX1276FskGetPayloadLength( void )
|
||||
{
|
||||
SX1276Read( REG_PAYLOADLENGTH, &SX1276->RegPayloadLength );
|
||||
FskSettings.PayloadLength = SX1276->RegPayloadLength;
|
||||
return FskSettings.PayloadLength;
|
||||
}
|
||||
|
||||
void SX1276FskSetPa20dBm( bool enale )
|
||||
{
|
||||
SX1276Read( REG_PADAC, &SX1276->RegPaDac );
|
||||
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
|
||||
|
||||
if( ( SX1276->RegPaConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
|
||||
{
|
||||
if( enale == true )
|
||||
{
|
||||
SX1276->RegPaDac = 0x87;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276->RegPaDac = 0x84;
|
||||
}
|
||||
SX1276Write( REG_PADAC, SX1276->RegPaDac );
|
||||
}
|
||||
|
||||
bool SX1276FskGetPa20dBm( void )
|
||||
{
|
||||
SX1276Read( REG_PADAC, &SX1276->RegPaDac );
|
||||
|
||||
return ( ( SX1276->RegPaDac & 0x07 ) == 0x07 ) ? true : false;
|
||||
}
|
||||
|
||||
void SX1276FskSetPAOutput( uint8_t outputPin )
|
||||
{
|
||||
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
|
||||
SX1276->RegPaConfig = (SX1276->RegPaConfig & RF_PACONFIG_PASELECT_MASK ) | outputPin;
|
||||
SX1276Write( REG_PACONFIG, SX1276->RegPaConfig );
|
||||
}
|
||||
|
||||
uint8_t SX1276FskGetPAOutput( void )
|
||||
{
|
||||
SX1276Read( REG_PACONFIG, &SX1276->RegPaConfig );
|
||||
return SX1276->RegPaConfig & ~RF_PACONFIG_PASELECT_MASK;
|
||||
}
|
||||
|
||||
|
||||
void SX1276FskSetPaRamp( uint8_t value )
|
||||
{
|
||||
SX1276Read( REG_PARAMP, &SX1276->RegPaRamp );
|
||||
SX1276->RegPaRamp = ( SX1276->RegPaRamp & RF_PARAMP_MASK ) | ( value & ~RF_PARAMP_MASK );
|
||||
SX1276Write( REG_PARAMP, SX1276->RegPaRamp );
|
||||
}
|
||||
|
||||
uint8_t SX1276FskGetPaRamp( void )
|
||||
{
|
||||
SX1276Read( REG_PARAMP, &SX1276->RegPaRamp );
|
||||
return SX1276->RegPaRamp & ~RF_PARAMP_MASK;
|
||||
}
|
||||
|
||||
void SX1276FskSetRssiOffset( int8_t offset )
|
||||
{
|
||||
SX1276Read( REG_RSSICONFIG, &SX1276->RegRssiConfig );
|
||||
if( offset < 0 )
|
||||
{
|
||||
offset = ( ~offset & 0x1F );
|
||||
offset += 1;
|
||||
offset = -offset;
|
||||
}
|
||||
SX1276->RegRssiConfig |= ( uint8_t )( ( offset & 0x1F ) << 3 );
|
||||
SX1276Write( REG_RSSICONFIG, SX1276->RegRssiConfig );
|
||||
}
|
||||
|
||||
int8_t SX1276FskGetRssiOffset( void )
|
||||
{
|
||||
SX1276Read( REG_RSSICONFIG, &SX1276->RegRssiConfig );
|
||||
int8_t offset = SX1276->RegRssiConfig >> 3;
|
||||
if( ( offset & 0x10 ) == 0x10 )
|
||||
{
|
||||
offset = ( ~offset & 0x1F );
|
||||
offset += 1;
|
||||
offset = -offset;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
int8_t SX1276FskGetRawTemp( void )
|
||||
{
|
||||
int8_t temp = 0;
|
||||
uint8_t previousOpMode;
|
||||
//uint32_t startTick;
|
||||
|
||||
// Enable Temperature reading
|
||||
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
|
||||
SX1276->RegImageCal = ( SX1276->RegImageCal & RF_IMAGECAL_TEMPMONITOR_MASK ) | RF_IMAGECAL_TEMPMONITOR_ON;
|
||||
SX1276Write( REG_IMAGECAL, SX1276->RegImageCal );
|
||||
|
||||
// save current Op Mode
|
||||
SX1276Read( REG_OPMODE, &SX1276->RegOpMode );
|
||||
previousOpMode = SX1276->RegOpMode;
|
||||
|
||||
// put device in FSK RxSynth
|
||||
SX1276->RegOpMode = RF_OPMODE_SYNTHESIZER_RX;
|
||||
SX1276Write( REG_OPMODE, SX1276->RegOpMode );
|
||||
|
||||
// Wait 1ms
|
||||
//startTick = GET_TICK_COUNT( );
|
||||
//while( ( GET_TICK_COUNT( ) - startTick ) < TICK_RATE_MS( 1 ) );
|
||||
|
||||
// Disable Temperature reading
|
||||
SX1276Read( REG_IMAGECAL, &SX1276->RegImageCal );
|
||||
SX1276->RegImageCal = ( SX1276->RegImageCal & RF_IMAGECAL_TEMPMONITOR_MASK ) | RF_IMAGECAL_TEMPMONITOR_OFF;
|
||||
SX1276Write( REG_IMAGECAL, SX1276->RegImageCal );
|
||||
|
||||
// Read temperature
|
||||
SX1276Read( REG_TEMP, &SX1276->RegTemp );
|
||||
|
||||
temp = SX1276->RegTemp & 0x7F;
|
||||
|
||||
if( ( SX1276->RegTemp & 0x80 ) == 0x80 )
|
||||
{
|
||||
temp *= -1;
|
||||
}
|
||||
|
||||
// Reload previous Op Mode
|
||||
SX1276Write( REG_OPMODE, previousOpMode );
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
int8_t SX1276FskCalibreateTemp( int8_t actualTemp )
|
||||
{
|
||||
return actualTemp - SX1276FskGetRawTemp( );
|
||||
}
|
||||
|
||||
int8_t SX1276FskGetTemp( int8_t compensationFactor )
|
||||
{
|
||||
return SX1276FskGetRawTemp( ) + compensationFactor;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) SEMTECH S.A.
|
||||
*/
|
||||
/*!
|
||||
* \file sx1276-FskMisc.h
|
||||
* \brief SX1276 RF chip high level functions driver
|
||||
*
|
||||
* \remark Optional support functions.
|
||||
* These functions are defined only to easy the change of the
|
||||
* parameters.
|
||||
* For a final firmware the radio parameters will be known so
|
||||
* there is no need to support all possible parameters.
|
||||
* Removing these functions will greatly reduce the final firmware
|
||||
* size.
|
||||
*
|
||||
* \version 2.0.B2
|
||||
* \date May 6 2013
|
||||
* \author Gregory Cristian
|
||||
*
|
||||
* Last modified by Miguel Luis on Jun 19 2013
|
||||
*/
|
||||
#ifndef __SX1276_FSK_MISC_H__
|
||||
#define __SX1276_FSK_MISC_H__
|
||||
|
||||
/*!
|
||||
* \brief Writes the new RF frequency value
|
||||
*
|
||||
* \param [IN] freq New RF frequency value in [Hz]
|
||||
*/
|
||||
void SX1276FskSetRFFrequency( uint32_t freq );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current RF frequency value
|
||||
*
|
||||
* \retval freq Current RF frequency value in [Hz]
|
||||
*/
|
||||
uint32_t SX1276FskGetRFFrequency( void );
|
||||
|
||||
/*!
|
||||
* \brief Calibrate RSSI and I/Q mismatch for HF
|
||||
*
|
||||
* \retval none
|
||||
*/
|
||||
void SX1276FskRxCalibrate( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new bitrate value
|
||||
*
|
||||
* \param [IN] bitrate New bitrate value in [bps]
|
||||
*/
|
||||
void SX1276FskSetBitrate( uint32_t bitrate );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current bitrate value
|
||||
*
|
||||
* \retval bitrate Current bitrate value in [bps]
|
||||
*/
|
||||
uint32_t SX1276FskGetBitrate( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new frequency deviation value
|
||||
*
|
||||
* \param [IN] fdev New frequency deviation value in [Hz]
|
||||
*/
|
||||
void SX1276FskSetFdev( uint32_t fdev );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current frequency deviation value
|
||||
*
|
||||
* \retval fdev Current frequency deviation value in [Hz]
|
||||
*/
|
||||
uint32_t SX1276FskGetFdev( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new RF output power value
|
||||
*
|
||||
* \param [IN] power New output power value in [dBm]
|
||||
*/
|
||||
void SX1276FskSetRFPower( int8_t power );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current RF output power value
|
||||
*
|
||||
* \retval power Current output power value in [dBm]
|
||||
*/
|
||||
int8_t SX1276FskGetRFPower( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the DC offset canceller and Rx bandwidth values
|
||||
*
|
||||
* \remark For SX1276 there is no DCC setting. dccValue should be 0
|
||||
* ie: SX1276SetDccBw( &SX1276.RegRxBw, 0, 62500 );
|
||||
*
|
||||
* \param [IN] reg Register pointer to either SX1231.RegRxBw or SX1231.RegAfcBw
|
||||
* \param [IN] dccValue New DC offset canceller value in [Hz] ( SX1231 only )
|
||||
* \param [IN] rxBwValue New Rx bandwidth value in [Hz]
|
||||
*/
|
||||
void SX1276FskSetDccBw( uint8_t* reg, uint32_t dccValue, uint32_t rxBwValue );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current bandwidth setting
|
||||
*
|
||||
* \param [IN] reg Register pointer to either SX1231.RegRxBw or SX1231.RegAfcBw
|
||||
*
|
||||
* \retval bandwidth Bandwidth value
|
||||
*/
|
||||
uint32_t SX1276FskGetBw( uint8_t* reg );
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables CRC
|
||||
*
|
||||
* \param [IN] enable CRC enable/disable
|
||||
*/
|
||||
void SX1276FskSetPacketCrcOn( bool enable );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current CRC Enable/Disbale value
|
||||
*
|
||||
* \retval enable Current CRC Enable/Disbale value
|
||||
*/
|
||||
bool SX1276FskGetPacketCrcOn( void );
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables AFC
|
||||
*
|
||||
* \param [IN] enable AFC enable/disable
|
||||
*/
|
||||
void SX1276FskSetAfcOn( bool enable );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current AFC Enable/Disbale value
|
||||
*
|
||||
* \retval enable Current AFC Enable/Disbale value
|
||||
*/
|
||||
bool SX1276FskGetAfcOn( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new payload length value
|
||||
*
|
||||
* \param [IN] value New payload length value
|
||||
*/
|
||||
void SX1276FskSetPayloadLength( uint8_t value );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current payload length value
|
||||
*
|
||||
* \retval value Current payload length value
|
||||
*/
|
||||
uint8_t SX1276FskGetPayloadLength( void );
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables the 20 dBm PA
|
||||
*
|
||||
* \param [IN] enable [true, false]
|
||||
*/
|
||||
void SX1276FskSetPa20dBm( bool enale );
|
||||
|
||||
/*!
|
||||
* \brief Gets the current 20 dBm PA status
|
||||
*
|
||||
* \retval enable [true, false]
|
||||
*/
|
||||
bool SX1276FskGetPa20dBm( void );
|
||||
|
||||
/*!
|
||||
* \brief Set the RF Output pin
|
||||
*
|
||||
* \param [IN] RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
|
||||
*/
|
||||
void SX1276FskSetPAOutput( uint8_t outputPin );
|
||||
|
||||
/*!
|
||||
* \brief Gets the used RF Ouptu pin
|
||||
*
|
||||
* \retval RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
|
||||
*/
|
||||
uint8_t SX1276FskGetPAOutput( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new PA rise/fall time of ramp up/down value
|
||||
*
|
||||
* \param [IN] value New PaRamp value
|
||||
*/
|
||||
void SX1276FskSetPaRamp( uint8_t value );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current PA rise/fall time of ramp up/down value
|
||||
*
|
||||
* \retval value Current PaRamp value
|
||||
*/
|
||||
uint8_t SX1276FskGetPaRamp( void );
|
||||
|
||||
/*!
|
||||
* \brief Applies an offset to the RSSI. Compensates board components
|
||||
*
|
||||
* \param [IN] offset Offset to be applied (+/-)
|
||||
*/
|
||||
void SX1276FskSetRssiOffset( int8_t offset );
|
||||
|
||||
/*!
|
||||
* \brief Gets the current RSSI offset.
|
||||
*
|
||||
* \retval offset Current offset (+/-)
|
||||
*/
|
||||
int8_t SX1276FskGetRssiOffset( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new value for the preamble size
|
||||
*
|
||||
* \param [IN] size New value of pramble size
|
||||
*/
|
||||
void SX1276FskSetPreambleSize( uint16_t size );
|
||||
|
||||
/*!
|
||||
* Reads the raw temperature
|
||||
* \retval temperature New raw temperature reading in 2's complement format
|
||||
*/
|
||||
int8_t SX1276FskGetRawTemp( void );
|
||||
|
||||
/*!
|
||||
* Computes the temperature compensation factor
|
||||
* \param [IN] actualTemp Actual temperature measured by an external device
|
||||
* \retval compensationFactor Computed compensation factor
|
||||
*/
|
||||
int8_t SX1276FskCalibreateTemp( int8_t actualTemp );
|
||||
|
||||
/*!
|
||||
* Gets the actual compensated temperature
|
||||
* \param [IN] compensationFactor Return value of the calibration function
|
||||
* \retval New compensated temperature value
|
||||
*/
|
||||
int8_t SX1276FskGetTemp( int8_t compensationFactor );
|
||||
|
||||
#endif //__SX1276_FSK_MISC_H__
|
||||
@@ -0,0 +1,832 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) SEMTECH S.A.
|
||||
*/
|
||||
/*!
|
||||
* \file sx1276-LoRa.c
|
||||
* \brief SX1276 RF chip driver mode LoRa
|
||||
*
|
||||
* \version 2.0.0
|
||||
* \date May 6 2013
|
||||
* \author Gregory Cristian
|
||||
*
|
||||
* Last modified by Miguel Luis on Jun 19 2013
|
||||
*/
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include "hal_radio.h"
|
||||
#include "sx1276-Fsk.h"
|
||||
#include "sx1276-LoRaMisc.h"
|
||||
#include "sx1276-LoRa.h"
|
||||
|
||||
/*!
|
||||
* Frequency hopping frequencies table
|
||||
*/
|
||||
#if defined (HIGH_FREQUENCY)
|
||||
const int32_t HoppingFrequencies[] =
|
||||
{
|
||||
916500000,
|
||||
923500000,
|
||||
906500000,
|
||||
917500000,
|
||||
917500000,
|
||||
909000000,
|
||||
903000000,
|
||||
916000000,
|
||||
912500000,
|
||||
926000000,
|
||||
925000000,
|
||||
909500000,
|
||||
913000000,
|
||||
918500000,
|
||||
918500000,
|
||||
902500000,
|
||||
911500000,
|
||||
926500000,
|
||||
902500000,
|
||||
922000000,
|
||||
924000000,
|
||||
903500000,
|
||||
913000000,
|
||||
922000000,
|
||||
926000000,
|
||||
910000000,
|
||||
920000000,
|
||||
922500000,
|
||||
911000000,
|
||||
922000000,
|
||||
909500000,
|
||||
926000000,
|
||||
922000000,
|
||||
918000000,
|
||||
925500000,
|
||||
908000000,
|
||||
917500000,
|
||||
926500000,
|
||||
908500000,
|
||||
916000000,
|
||||
905500000,
|
||||
916000000,
|
||||
903000000,
|
||||
905000000,
|
||||
915000000,
|
||||
913000000,
|
||||
907000000,
|
||||
910000000,
|
||||
926500000,
|
||||
925500000,
|
||||
911000000,
|
||||
};
|
||||
#else
|
||||
const int32_t HoppingFrequencies[] =
|
||||
{
|
||||
#if 0
|
||||
479000000,
|
||||
484700000,
|
||||
471500000,
|
||||
479300000,
|
||||
471700000,
|
||||
479500000,
|
||||
471900000,
|
||||
479700000,
|
||||
472100000,
|
||||
479900000,
|
||||
472300000,
|
||||
480100000,
|
||||
472500000,
|
||||
480300000,
|
||||
472700000,
|
||||
480500000,
|
||||
472900000,
|
||||
480700000,
|
||||
473100000,
|
||||
480900000,
|
||||
473300000,
|
||||
481100000,
|
||||
473500000,
|
||||
481300000,
|
||||
473700000,
|
||||
481500000,
|
||||
473900000,
|
||||
481700000,
|
||||
474100000,
|
||||
481900000,
|
||||
474300000,
|
||||
482100000,
|
||||
474500000,
|
||||
482300000,
|
||||
474700000,
|
||||
482500000,
|
||||
474900000,
|
||||
482700000,
|
||||
475100000,
|
||||
482900000,
|
||||
475300000,
|
||||
483100000,
|
||||
475500000,
|
||||
483300000,
|
||||
475700000,
|
||||
483500000,
|
||||
475900000,
|
||||
483700000,
|
||||
476100000,
|
||||
483900000,
|
||||
476500000,
|
||||
484100000,
|
||||
476700000,
|
||||
484300000,
|
||||
476900000,
|
||||
484500000,
|
||||
477100000,
|
||||
484900000,
|
||||
477300000,
|
||||
485100000,
|
||||
477500000,
|
||||
485300000,
|
||||
477700000,
|
||||
485500000,
|
||||
477900000,
|
||||
485700000,
|
||||
#endif
|
||||
492000000,
|
||||
492100000,
|
||||
492200000,
|
||||
492300000,
|
||||
492400000,
|
||||
492500000,
|
||||
492600000,
|
||||
492700000,
|
||||
492800000,
|
||||
492900000,
|
||||
493000000,
|
||||
493100000,
|
||||
493200000,
|
||||
493300000,
|
||||
493400000,
|
||||
493500000,
|
||||
493600000,
|
||||
493700000,
|
||||
493800000,
|
||||
493900000,
|
||||
494000000,
|
||||
494100000,
|
||||
494200000,
|
||||
494300000,
|
||||
494400000,
|
||||
494500000,
|
||||
494600000,
|
||||
494700000,
|
||||
494800000,
|
||||
494900000,
|
||||
495000000,
|
||||
495100000,
|
||||
495200000,
|
||||
495300000,
|
||||
495400000,
|
||||
495500000,
|
||||
495600000,
|
||||
495700000,
|
||||
495800000,
|
||||
495900000,
|
||||
496000000,
|
||||
496100000,
|
||||
496200000,
|
||||
496300000,
|
||||
496400000,
|
||||
496500000,
|
||||
496600000,
|
||||
496700000,
|
||||
496800000,
|
||||
496900000,
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
#define NO_HOP_LOW_FREQUENCY 479000000
|
||||
|
||||
#ifdef HOP_CHSS
|
||||
#define HOP_CHANNELS 50
|
||||
#endif
|
||||
|
||||
static u8 g_hopChannel = 0;
|
||||
static u32 LoraSymbolTs;
|
||||
static u32 loraWokePreambleLenth;
|
||||
|
||||
u8 SX1276Regs[0x70];
|
||||
tSX1276LR* SX1276LR = (tSX1276LR*)SX1276Regs;
|
||||
|
||||
u32 g_SignalBw[10] = {7800, 10400, 15600, 20800, 31200, 41600, 62500, 125000, 250000, 500000};
|
||||
|
||||
tLoRaSettings LoRaSettings =
|
||||
{
|
||||
#ifdef HIGH_FREQUENCY
|
||||
.RFFrequency = 920000000, // RFFrequency
|
||||
#else
|
||||
.RFFrequency = NO_HOP_LOW_FREQUENCY,
|
||||
#endif
|
||||
.Power = 0, // Power
|
||||
.SignalBw = 6, // SignalBw [0: 7.8kHz, 1: 10.4 kHz, 2: 15.6 kHz, 3: 20.8 kHz, 4: 31.2 kHz,
|
||||
// 5: 41.6 kHz, 6: 62.5 kHz, 7: 125 kHz, 8: 250 kHz, 9: 500 kHz, other: Reserved]
|
||||
.SpreadingFactor = 7, // SpreadingFactor [6: 64, 7: 128, 8: 256, 9: 512, 10: 1024, 11: 2048, 12: 4096 chips]
|
||||
.ErrorCoding = 2, // ErrorCoding [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
|
||||
.CrcOn = true, // CrcOn [0: OFF, 1: ON]
|
||||
.ImplicitHeaderOn = false, // ImplicitHeaderOn [0: OFF, 1: ON]
|
||||
.RxSingleOn = false, // RxSingleOn [0: Continuous, 1 Single]
|
||||
.FreqHopOn = false, // FreqHopOn [0: OFF, 1: ON]
|
||||
.HopPeriod = 7, // HopPeriod Hops every frequency hopping period symbols
|
||||
.TxPacketTimeout = 800, // TxPacketTimeout
|
||||
.RxPacketTimeout = 800, // RxPacketTimeout
|
||||
.PayloadLength = 254, // PayloadLength (used for implicit header mode)
|
||||
.LowDatarateOptimize = false, // LowDatarateOptimize option
|
||||
.PreambleLen = NORMALSYMBOLSLENGTH, // Preamble length
|
||||
};
|
||||
|
||||
|
||||
st_RF_LoRa_DypeDef g_RF_LoRa =
|
||||
{
|
||||
.rf_DataBufferValid = false,
|
||||
.rf_state = RFLR_STATE_IDLE,
|
||||
.rf_RxPacketSize = 0,
|
||||
.rf_TxPacketSize = 0,
|
||||
.rf_HeaderValid = false,
|
||||
};
|
||||
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
u32 loraWokePreambleLenth;
|
||||
uint8_t LoraChl;
|
||||
st_RF_LoRa_DypeDef data;
|
||||
|
||||
u32 (*readLoraSymbolTs)(void);
|
||||
int8_t (*getPacketSnr)(void);
|
||||
u8 (*getRxPacketRssi)();
|
||||
void (*LoRa_NormalTx)(u8 channel, u8 *PBuffer, u8 length);
|
||||
void (*LoRa_WakeUpTx)(u8 channel, u8 *PBuffer, u8 length);
|
||||
void (*LoRa_Receive_Packet)(u8 channel, bool wakeUp);
|
||||
}st_Lora_port;
|
||||
|
||||
u32 readLoraSymbolTs(void)
|
||||
{
|
||||
return set_LoraSymbolTs(LoRaSettings.SignalBw, LoRaSettings.SpreadingFactor);
|
||||
}
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : set_LoraSymbolTs
|
||||
* Description : none
|
||||
* Input : uint8_t BwFlag
|
||||
uint8_t SF
|
||||
* Output : None
|
||||
* Return : unit ms
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170320
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
u32 set_LoraSymbolTs(uint8_t BwFlag ,uint8_t SF)
|
||||
{
|
||||
return (1 << SF)*1000/g_SignalBw[BwFlag];
|
||||
}
|
||||
|
||||
u32 get_LoraSymbolTs(void)
|
||||
{
|
||||
return LoraSymbolTs;
|
||||
}
|
||||
/*****************************************************************************
|
||||
* Function : set_LoRaWokeUpPreambleLenth
|
||||
* Description : none
|
||||
* Input : u32 period
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170320
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
u32 set_LoRaWokeUpPreambleLenth(u32 period, uint8_t BwFlag ,uint8_t SF)
|
||||
{
|
||||
return (u32)(period * g_SignalBw[BwFlag] / ((1 << SF) *1000)) + 6;
|
||||
}
|
||||
|
||||
u32 get_LoRaWokeUpPreambleLenth(void)
|
||||
{
|
||||
return loraWokePreambleLenth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276LoRaSetDefaults
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276LoRaSetDefaults( void )
|
||||
{
|
||||
/* REMARK: See SX1276 datasheet for modified default values */
|
||||
SX1276Read( REG_LR_VERSION, &SX1276LR->RegVersion );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276LoRaSetOpMode
|
||||
Description : none
|
||||
Input : uint8_t opMode
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276LoRaSetOpMode( uint8_t opMode )
|
||||
{
|
||||
SX1276LR->RegOpMode = ( SX1276LR->RegOpMode & RFLR_OPMODE_MASK ) | opMode;
|
||||
|
||||
/* BEGIN: Added by Barry, 2014/3/14 */
|
||||
#ifdef HIGH_FREQUENCY
|
||||
SX1276LR->RegOpMode = ( SX1276LR->RegOpMode & RFLR_OPMODE_FREQMODE_ACCESS_MASK ) | RFLR_OPMODE_FREQMODE_ACCESS_HF; //Elvis
|
||||
#endif
|
||||
/* END: Added by Barry, 2014/3/14 */
|
||||
|
||||
SX1276Write( REG_LR_OPMODE, SX1276LR->RegOpMode );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276LoRaGetOpMode
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
uint8_t SX1276LoRaGetOpMode( void )
|
||||
{
|
||||
SX1276Read( REG_LR_OPMODE, &SX1276LR->RegOpMode );
|
||||
return SX1276LR->RegOpMode & ~RFLR_OPMODE_MASK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276LoRaReadRxGain
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
uint8_t SX1276LoRaReadRxGain( void )
|
||||
{
|
||||
SX1276Read( REG_LR_LNA, &SX1276LR->RegLna );
|
||||
return( SX1276LR->RegLna >> 5 ) & 0x07;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : config_GDOx_Map
|
||||
Description : none
|
||||
Input : st_GDOx_Config GDOx_Map
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void config_GDOx_Map(st_GDOx_Config GDOx_Map)
|
||||
{
|
||||
SX1276LR->RegDioMapping1 = GDOx_Map.GDO0Config|
|
||||
GDOx_Map.GDO1Config|
|
||||
GDOx_Map.GDO2Config|
|
||||
GDOx_Map.GDO3Config;
|
||||
|
||||
SX1276LR->RegDioMapping2 = GDOx_Map.GDO4Config|
|
||||
GDOx_Map.GDO5Config;
|
||||
|
||||
SX1276WriteBuffer( REG_LR_DIOMAPPING1, &SX1276LR->RegDioMapping1, 2 );
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : getPacketSnr
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
int8_t getPacketSnr(void)
|
||||
{
|
||||
uint8_t rxSnrEstimate;
|
||||
int8_t RxPacketSnrEstimate;
|
||||
|
||||
SX1276Read( REG_LR_PKTSNRVALUE, &rxSnrEstimate );
|
||||
|
||||
/* The SNR sign bit is 1 */
|
||||
if( rxSnrEstimate & 0x80 )
|
||||
{
|
||||
/* Invert and divide by 4 */
|
||||
RxPacketSnrEstimate = ( ( ~rxSnrEstimate + 1 ) & 0xFF ) >> 2;
|
||||
RxPacketSnrEstimate = -RxPacketSnrEstimate;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Divide by 4 */
|
||||
RxPacketSnrEstimate = ( rxSnrEstimate & 0xFF ) >> 2;
|
||||
}
|
||||
return RxPacketSnrEstimate;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : get_RxPacketRssi
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
double get_RxPacketRssi(int8_t RxPacketSnr)
|
||||
{
|
||||
#define RSSI_OFFSET_LF -164.0
|
||||
#define RSSI_OFFSET_HF -157.0
|
||||
|
||||
double RxPacketRssi;
|
||||
|
||||
SX1276Read( REG_LR_PKTRSSIVALUE, &SX1276LR->RegPktRssiValue );
|
||||
|
||||
if( LoRaSettings.RFFrequency < 860000000 ) // LF
|
||||
{
|
||||
if( RxPacketSnr < 0 )
|
||||
{
|
||||
RxPacketRssi = RSSI_OFFSET_LF + ((double)SX1276LR->RegPktRssiValue) + RxPacketSnr;
|
||||
}
|
||||
else
|
||||
{
|
||||
RxPacketRssi = RSSI_OFFSET_LF + ( 1.0666 * ((double)SX1276LR->RegPktRssiValue) );
|
||||
}
|
||||
}
|
||||
else // HF
|
||||
{
|
||||
if( RxPacketSnr < 0 )
|
||||
{
|
||||
RxPacketRssi = RSSI_OFFSET_HF + ( ( double )SX1276LR->RegPktRssiValue ) + RxPacketSnr;
|
||||
}
|
||||
else
|
||||
{
|
||||
RxPacketRssi = RSSI_OFFSET_HF + ( 1.0666 * ((double)SX1276LR->RegPktRssiValue) );
|
||||
}
|
||||
}
|
||||
|
||||
return RxPacketRssi;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : read_Lora_Rssi
|
||||
Description : none
|
||||
Input : tRFLRStates state
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
u8 read_Lora_Rssi(void)
|
||||
{
|
||||
int8_t pSnr = getPacketSnr();
|
||||
u8 rssi = (u8)get_RxPacketRssi(pSnr);
|
||||
|
||||
if (rssi & 0x80)
|
||||
{
|
||||
rssi = (~rssi + 1);
|
||||
}
|
||||
return rssi;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276LoRaInit
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276LoRaInit( void )
|
||||
{
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_SLEEP );
|
||||
SX1276LR->RegOpMode = ( SX1276LR->RegOpMode & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_ON;
|
||||
SX1276Write( REG_LR_OPMODE, SX1276LR->RegOpMode );
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
|
||||
|
||||
SX1276LoRaSetDefaults( );
|
||||
|
||||
SX1276ReadBuffer( REG_LR_OPMODE, SX1276Regs + 1, 0x70 - 1 );
|
||||
|
||||
SX1276LR->RegLna = RFLR_LNA_GAIN_G1;
|
||||
|
||||
SX1276Write( REG_LR_LNA, SX1276LR->RegLna );
|
||||
|
||||
/* Set the device in Sleep Mode */
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_SLEEP );
|
||||
|
||||
SX1276LoRaSetRFFrequency( LoRaSettings.RFFrequency );
|
||||
SX1276LoRaSetSpreadingFactor( LoRaSettings.SpreadingFactor ); // SF6 only operates in implicit header mode.
|
||||
SX1276LoRaSetErrorCoding( LoRaSettings.ErrorCoding );
|
||||
SX1276LoRaSetPacketCrcOn( LoRaSettings.CrcOn );
|
||||
SX1276LoRaSetSignalBandwidth( LoRaSettings.SignalBw );
|
||||
|
||||
SX1276LoRaSetImplicitHeaderOn( LoRaSettings.ImplicitHeaderOn );
|
||||
SX1276LoRaSetSymbTimeout( 0x3FF );
|
||||
SX1276LoRaSetPayloadLength( LoRaSettings.PayloadLength );
|
||||
SX1276LoRaSetPreambleLength(LoRaSettings.PreambleLen);
|
||||
|
||||
/* seted true when a symble time over 16ms */
|
||||
if (get_LoraSymbolTs() >= 16)
|
||||
{
|
||||
SX1276LoRaSetLowDatarateOptimize(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276LoRaSetLowDatarateOptimize(false);
|
||||
}
|
||||
|
||||
SX1276LoRaSetPAOutput( RFLR_PACONFIG_PASELECT_RFO );
|
||||
//SX1276LoRaSetPAOutput( RFLR_PACONFIG_PASELECT_PABOOST );
|
||||
/* set max power 17DBm */
|
||||
SX1276LoRaSetPa20dBm( false );
|
||||
|
||||
/* set power */
|
||||
SX1276LoRaSetRFPower( LoRaSettings.Power );
|
||||
|
||||
SX1276StartSleep();
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : Lora_lowPower_Init
|
||||
* Description : none
|
||||
* Input : u32 period
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170526
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void Lora_lowPower_Init(u32 period)
|
||||
{
|
||||
LoraSymbolTs = set_LoraSymbolTs(LoRaSettings.SignalBw, LoRaSettings.SpreadingFactor);
|
||||
loraWokePreambleLenth = set_LoRaWokeUpPreambleLenth(period, LoRaSettings.SignalBw, LoRaSettings.SpreadingFactor);
|
||||
}
|
||||
|
||||
u32 get_LoraWokeUpPreambleT(void)
|
||||
{
|
||||
return LoraSymbolTs*loraWokePreambleLenth;
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : receiveRxData
|
||||
Description : none
|
||||
Input : bool spiDMA
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void receiveRxData(u8 *buf, u8 *length)
|
||||
{
|
||||
if( LoRaSettings.RxSingleOn == true )
|
||||
{
|
||||
SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxBaseAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276Read( REG_LR_FIFORXCURRENTADDR, &SX1276LR->RegFifoRxCurrentAddr );
|
||||
SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoRxCurrentAddr;
|
||||
}
|
||||
|
||||
if( LoRaSettings.ImplicitHeaderOn == true )
|
||||
{
|
||||
*length = SX1276LR->RegPayloadLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276Read( REG_LR_NBRXBYTES, &SX1276LR->RegNbRxBytes );
|
||||
*length = SX1276LR->RegNbRxBytes;
|
||||
}
|
||||
|
||||
SX1276Write( REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr );
|
||||
SX1276ReadFifo(buf, *length);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : SX1276LoRa_hopTx_config
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170320
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void SX1276LoRa_hopTx_config(st_GDOx_Config *DIO_map_ptr)
|
||||
{
|
||||
SX1276LR->RegIrqFlagsMask &= (~RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL);
|
||||
SX1276LR->RegHopPeriod = LoRaSettings.HopPeriod;
|
||||
DIO_map_ptr->GDO1Config = DIO1_FhssCC;
|
||||
hal_DIOx_ITConfig(1,ENABLE);
|
||||
}
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276LoRa_Send_Packet
|
||||
Description : none
|
||||
Input : u8 *PBuffer
|
||||
u8 length
|
||||
bool FreqHop
|
||||
bool spiDMA
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276LoRa_Send_Packet(u8 channel, bool wakeUp, u8 *PBuffer,u8 length)
|
||||
{
|
||||
st_GDOx_Config DIO_map_conf = DEFAULT_DIO_config;
|
||||
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
|
||||
hal_DIOx_ITConfig(all, DISABLE);
|
||||
switch_Tx();
|
||||
|
||||
DIO_map_conf.GDO0Config = DIO0_TxDone;
|
||||
SX1276LR->RegIrqFlagsMask = RFLR_IRQFLAGS_ALL_MASK & (~RFLR_IRQFLAGS_TXDONE);
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_SYNTHESIZER_TX );
|
||||
SX1276LR->RegHopPeriod = 0;
|
||||
|
||||
#ifdef HOP_CHSS
|
||||
SX1276LoRa_hopTx_config(DIO_map_conf);
|
||||
#endif
|
||||
|
||||
LoRaSettings.PreambleLen = wakeUp? get_LoRaWokeUpPreambleLenth():NORMALSYMBOLSLENGTH;
|
||||
SX1276LoRaSetPreambleLength(LoRaSettings.PreambleLen);
|
||||
|
||||
config_GDOx_Map(DIO_map_conf);
|
||||
SX1276Write( REG_LR_HOPPERIOD, SX1276LR->RegHopPeriod );
|
||||
SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );
|
||||
SX1276LoRaSetRFFrequency(HoppingFrequencies[channel]);
|
||||
|
||||
SX1276LR->RegPayloadLength = length;
|
||||
SX1276Write( REG_LR_PAYLOADLENGTH, SX1276LR->RegPayloadLength);
|
||||
|
||||
SX1276LR->RegFifoTxBaseAddr = 0x00;
|
||||
SX1276Write( REG_LR_FIFOTXBASEADDR, SX1276LR->RegFifoTxBaseAddr );
|
||||
|
||||
SX1276LR->RegFifoAddrPtr = SX1276LR->RegFifoTxBaseAddr;
|
||||
SX1276Write(REG_LR_FIFOADDRPTR, SX1276LR->RegFifoAddrPtr);
|
||||
|
||||
g_RF_LoRa.rf_state = RFLR_STATE_TX_RUNNING;
|
||||
|
||||
MemCpy(g_RF_LoRa.rf_DataBuffer, PBuffer, length);
|
||||
g_RF_LoRa.rf_TxPacketSize = length;
|
||||
|
||||
SX1276WriteFifo(g_RF_LoRa.rf_DataBuffer,length);
|
||||
SX1276LoRaSetOpMode(RFLR_OPMODE_TRANSMITTER);
|
||||
hal_DIOx_ITConfig(0,ENABLE);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276LoRa_Receive_Packet
|
||||
Description : none
|
||||
Input : bool FreqHop
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276LoRa_Receive_Packet(u8 channel, bool wakeUp)
|
||||
{
|
||||
st_GDOx_Config DIO_map_conf = DEFAULT_DIO_config;
|
||||
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
|
||||
|
||||
SX1276LR->RegIrqFlagsMask = RFLR_IRQFLAGS_ALL_MASK;
|
||||
|
||||
SX1276LR->RegIrqFlagsMask &= (~(RFLR_IRQFLAGS_RXDONE |
|
||||
RFLR_IRQFLAGS_PAYLOADCRCERROR|
|
||||
RFLR_IRQFLAGS_VALIDHEADER
|
||||
/*|RFLR_IRQFLAGS_RXTIMEOUT*/
|
||||
));
|
||||
|
||||
DIO_map_conf.GDO0Config = DIO0_RxDone;
|
||||
DIO_map_conf.GDO3Config = DIO3_ValidHeader;
|
||||
SX1276LR->RegHopPeriod = 0;
|
||||
|
||||
switch_Rx();
|
||||
|
||||
#ifdef HOP_CHSS
|
||||
SX1276LoRa_hopTx_config(DIO_map_conf);
|
||||
#endif
|
||||
|
||||
LoRaSettings.PreambleLen = wakeUp? get_LoRaWokeUpPreambleLenth():NORMALSYMBOLSLENGTH;
|
||||
SX1276LoRaSetPreambleLength(LoRaSettings.PreambleLen);
|
||||
SX1276LoRaSetSymbTimeout(0x3FF);
|
||||
|
||||
config_GDOx_Map(DIO_map_conf);
|
||||
SX1276Write( REG_LR_HOPPERIOD, SX1276LR->RegHopPeriod );
|
||||
SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );
|
||||
SX1276LoRaSetRFFrequency(HoppingFrequencies[channel]);
|
||||
|
||||
if (wakeUp)
|
||||
{
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_RECEIVER_SINGLE );
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_RECEIVER );
|
||||
}
|
||||
|
||||
g_RF_LoRa.rf_state = RFLR_STATE_RX_RUNNING;
|
||||
|
||||
hal_DIOx_ITConfig(0,ENABLE);
|
||||
hal_DIOx_ITConfig(3,ENABLE);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276StartSleep
|
||||
Description : none
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276StartSleep(void)
|
||||
{
|
||||
switch_Rx();
|
||||
hal_DIOx_ITConfig(all, DISABLE);
|
||||
hal_sRF_ClearAllRF_IT();
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_SLEEP );
|
||||
g_RF_LoRa.rf_state = RFLR_STATE_SLEEP;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Prototype : SX1276LoRa_CAD_Scan
|
||||
Description : none
|
||||
Input : void
|
||||
Output : None
|
||||
Return Value :
|
||||
Date : 2014/3/15
|
||||
Author : Barry
|
||||
*****************************************************************************/
|
||||
void SX1276LoRa_CAD_Scan(u8 channel)
|
||||
{
|
||||
st_GDOx_Config DIO_map_conf = DEFAULT_DIO_config;
|
||||
|
||||
switch_Rx();
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_STANDBY );
|
||||
|
||||
SX1276LR->RegIrqFlagsMask |= RFLR_IRQFLAGS_ALL_MASK;
|
||||
SX1276LR->RegIrqFlagsMask &= (~(RFLR_IRQFLAGS_CADDETECTED | RFLR_IRQFLAGS_CADDONE));
|
||||
SX1276Write( REG_LR_IRQFLAGSMASK, SX1276LR->RegIrqFlagsMask );
|
||||
|
||||
SX1276LoRaSetRFFrequency(HoppingFrequencies[channel]);
|
||||
|
||||
DIO_map_conf.GDO0Config = DIO0_CadDone;
|
||||
DIO_map_conf.GDO1Config = DIO1_CadDetected;
|
||||
config_GDOx_Map(DIO_map_conf);
|
||||
|
||||
hal_DIOx_ITConfig(0,ENABLE);
|
||||
|
||||
SX1276LoRaSetOpMode( RFLR_OPMODE_CAD );
|
||||
g_RF_LoRa.rf_state = RFLR_STATE_CAD_RUNNING;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : set_hop_Channel
|
||||
* Description : none
|
||||
* Input : u8 channel
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170320
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void set_hop_Channel(u8 channel)
|
||||
{
|
||||
SX1276LoRaSetRFFrequency( HoppingFrequencies[ (g_hopChannel + channel&RFLR_HOPCHANNEL_CHANNEL_MASK)%HOP_CHANNELS] );
|
||||
}
|
||||
|
||||
|
||||
+1071
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) SEMTECH S.A.
|
||||
*/
|
||||
/*!
|
||||
* \file sx1276-LoRaMisc.c
|
||||
* \brief SX1276 RF chip high level functions driver
|
||||
*
|
||||
* \remark Optional support functions.
|
||||
* These functions are defined only to easy the change of the
|
||||
* parameters.
|
||||
* For a final firmware the radio parameters will be known so
|
||||
* there is no need to support all possible parameters.
|
||||
* Removing these functions will greatly reduce the final firmware
|
||||
* size.
|
||||
*
|
||||
* \version 2.0.0
|
||||
* \date May 6 2013
|
||||
* \author Gregory Cristian
|
||||
*
|
||||
* Last modified by Miguel Luis on Jun 19 2013
|
||||
*/
|
||||
//#include "platform.h"
|
||||
|
||||
//#if defined( USE_SX1276_RADIO )
|
||||
//#if defined(SX1276_LORA)
|
||||
|
||||
|
||||
#include "hal_radio.h"
|
||||
//#include "sx1276.h"
|
||||
|
||||
#include "sx1276-LoRa.h"
|
||||
|
||||
|
||||
/*!
|
||||
* SX1276 definitions
|
||||
*/
|
||||
#define XTAL_FREQ 32000000
|
||||
#define FREQ_STEP 61.03515625
|
||||
|
||||
extern tLoRaSettings LoRaSettings;
|
||||
|
||||
void SX1276LoRaSetRFFrequency( uint32_t freq )
|
||||
{
|
||||
LoRaSettings.RFFrequency = freq;
|
||||
|
||||
freq = ( uint32_t )( ( double )freq / ( double )FREQ_STEP );
|
||||
SX1276LR->RegFrfMsb = ( uint8_t )( ( freq >> 16 ) & 0xFF );
|
||||
SX1276LR->RegFrfMid = ( uint8_t )( ( freq >> 8 ) & 0xFF );
|
||||
SX1276LR->RegFrfLsb = ( uint8_t )( freq & 0xFF );
|
||||
SX1276WriteBuffer( REG_LR_FRFMSB, &SX1276LR->RegFrfMsb, 3 );
|
||||
}
|
||||
|
||||
uint32_t SX1276LoRaGetRFFrequency( void )
|
||||
{
|
||||
SX1276ReadBuffer( REG_LR_FRFMSB, &SX1276LR->RegFrfMsb, 3 );
|
||||
LoRaSettings.RFFrequency = ( ( uint32_t )SX1276LR->RegFrfMsb << 16 ) | ( ( uint32_t )SX1276LR->RegFrfMid << 8 ) | ( ( uint32_t )SX1276LR->RegFrfLsb );
|
||||
LoRaSettings.RFFrequency = ( uint32_t )( ( double )LoRaSettings.RFFrequency * ( double )FREQ_STEP );
|
||||
|
||||
return LoRaSettings.RFFrequency;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetRFPower( int8_t power )
|
||||
{
|
||||
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
|
||||
SX1276Read( REG_LR_PADAC, &SX1276LR->RegPaDac );
|
||||
/* is used PA boost pin*/
|
||||
if( ( SX1276LR->RegPaConfig & RFLR_PACONFIG_PASELECT_PABOOST ) == RFLR_PACONFIG_PASELECT_PABOOST )
|
||||
{ /* is max 20dbm output enable */
|
||||
if( ( SX1276LR->RegPaDac & 0x87 ) == 0x87 )
|
||||
{
|
||||
if( power < 5 )
|
||||
{
|
||||
power = 5;
|
||||
}
|
||||
if( power > 20 )
|
||||
{
|
||||
power = 20;
|
||||
}
|
||||
/* set RegPaConfig MaxPower x111xxxx MaxPower over 14dbm */
|
||||
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_MAX_POWER_MASK ) | 0x70;
|
||||
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F );
|
||||
}
|
||||
/* max PA 17 dbm */
|
||||
else
|
||||
{
|
||||
if( power < 2 )
|
||||
{
|
||||
power = 2;
|
||||
}
|
||||
if( power > 17 )
|
||||
{
|
||||
power = 17;
|
||||
}
|
||||
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_MAX_POWER_MASK ) | 0x70;
|
||||
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( power < -1 )
|
||||
{
|
||||
power = -1;
|
||||
}
|
||||
if( power > 14 )
|
||||
{
|
||||
power = 14;
|
||||
}
|
||||
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_MAX_POWER_MASK ) | 0x70;
|
||||
SX1276LR->RegPaConfig = ( SX1276LR->RegPaConfig & RFLR_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power + 1 ) & 0x0F );
|
||||
}
|
||||
SX1276Write( REG_LR_PACONFIG, SX1276LR->RegPaConfig );
|
||||
LoRaSettings.Power = power;
|
||||
}
|
||||
|
||||
int8_t SX1276LoRaGetRFPower( void )
|
||||
{
|
||||
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
|
||||
SX1276Read( REG_LR_PADAC, &SX1276LR->RegPaDac );
|
||||
|
||||
if( ( SX1276LR->RegPaConfig & RFLR_PACONFIG_PASELECT_PABOOST ) == RFLR_PACONFIG_PASELECT_PABOOST )
|
||||
{
|
||||
if( ( SX1276LR->RegPaDac & 0x07 ) == 0x07 )
|
||||
{
|
||||
LoRaSettings.Power = 5 + ( SX1276LR->RegPaConfig & ~RFLR_PACONFIG_OUTPUTPOWER_MASK );
|
||||
}
|
||||
else
|
||||
{
|
||||
LoRaSettings.Power = 2 + ( SX1276LR->RegPaConfig & ~RFLR_PACONFIG_OUTPUTPOWER_MASK );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LoRaSettings.Power = -1 + ( SX1276LR->RegPaConfig & ~RFLR_PACONFIG_OUTPUTPOWER_MASK );
|
||||
}
|
||||
return LoRaSettings.Power;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetSignalBandwidth( uint8_t bw )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
|
||||
SX1276LR->RegModemConfig1 = ( SX1276LR->RegModemConfig1 & RFLR_MODEMCONFIG1_BW_MASK ) | ( bw << 4 );
|
||||
SX1276Write( REG_LR_MODEMCONFIG1, SX1276LR->RegModemConfig1 );
|
||||
LoRaSettings.SignalBw = bw;
|
||||
}
|
||||
|
||||
uint8_t SX1276LoRaGetSignalBandwidth( void )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
|
||||
LoRaSettings.SignalBw = ( SX1276LR->RegModemConfig1 & ~RFLR_MODEMCONFIG1_BW_MASK ) >> 4;
|
||||
return LoRaSettings.SignalBw;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetSpreadingFactor( uint8_t factor )
|
||||
{
|
||||
if( factor > 12 )
|
||||
{
|
||||
factor = 12;
|
||||
}
|
||||
else if( factor < 6 )
|
||||
{
|
||||
factor = 6;
|
||||
}
|
||||
|
||||
if( factor == 6 )
|
||||
{
|
||||
SX1276LoRaSetNbTrigPeaks( 5 );
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276LoRaSetNbTrigPeaks( 3 );
|
||||
}
|
||||
|
||||
SX1276Read( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2 );
|
||||
SX1276LR->RegModemConfig2 = ( SX1276LR->RegModemConfig2 & RFLR_MODEMCONFIG2_SF_MASK ) | ( factor << 4 );
|
||||
SX1276Write( REG_LR_MODEMCONFIG2, SX1276LR->RegModemConfig2 );
|
||||
LoRaSettings.SpreadingFactor = factor;
|
||||
}
|
||||
|
||||
uint8_t SX1276LoRaGetSpreadingFactor( void )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2 );
|
||||
LoRaSettings.SpreadingFactor = ( SX1276LR->RegModemConfig2 & ~RFLR_MODEMCONFIG2_SF_MASK ) >> 4;
|
||||
return LoRaSettings.SpreadingFactor;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetErrorCoding( uint8_t value )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
|
||||
SX1276LR->RegModemConfig1 = ( SX1276LR->RegModemConfig1 & RFLR_MODEMCONFIG1_CODINGRATE_MASK ) | ( value << 1 );
|
||||
SX1276Write( REG_LR_MODEMCONFIG1, SX1276LR->RegModemConfig1 );
|
||||
LoRaSettings.ErrorCoding = value;
|
||||
}
|
||||
|
||||
uint8_t SX1276LoRaGetErrorCoding( void )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
|
||||
LoRaSettings.ErrorCoding = ( SX1276LR->RegModemConfig1 & ~RFLR_MODEMCONFIG1_CODINGRATE_MASK ) >> 1;
|
||||
return LoRaSettings.ErrorCoding;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetPacketCrcOn( bool enable )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2 );
|
||||
SX1276LR->RegModemConfig2 = ( SX1276LR->RegModemConfig2 & RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK ) | ( enable << 2 );
|
||||
SX1276Write( REG_LR_MODEMCONFIG2, SX1276LR->RegModemConfig2 );
|
||||
LoRaSettings.CrcOn = enable;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetPreambleLength( uint16_t value )
|
||||
{
|
||||
SX1276ReadBuffer( REG_LR_PREAMBLEMSB, &SX1276LR->RegPreambleMsb, 2 );
|
||||
|
||||
SX1276LR->RegPreambleMsb = ( value >> 8 ) & 0x00FF;
|
||||
SX1276LR->RegPreambleLsb = value & 0xFF;
|
||||
SX1276WriteBuffer( REG_LR_PREAMBLEMSB, &SX1276LR->RegPreambleMsb, 2 );
|
||||
}
|
||||
|
||||
uint16_t SX1276LoRaGetPreambleLength( void )
|
||||
{
|
||||
SX1276ReadBuffer( REG_LR_PREAMBLEMSB, &SX1276LR->RegPreambleMsb, 2 );
|
||||
return ( ( SX1276LR->RegPreambleMsb & 0x00FF ) << 8 ) | SX1276LR->RegPreambleLsb;
|
||||
}
|
||||
|
||||
bool SX1276LoRaGetPacketCrcOn( void )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2 );
|
||||
LoRaSettings.CrcOn =(bool) (( SX1276LR->RegModemConfig2 & RFLR_MODEMCONFIG2_RXPAYLOADCRC_ON ) >> 1);
|
||||
return LoRaSettings.CrcOn;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetImplicitHeaderOn( bool enable )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
|
||||
SX1276LR->RegModemConfig1 = ( SX1276LR->RegModemConfig1 & RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK ) | ( enable );
|
||||
SX1276Write( REG_LR_MODEMCONFIG1, SX1276LR->RegModemConfig1 );
|
||||
LoRaSettings.ImplicitHeaderOn = enable;
|
||||
}
|
||||
|
||||
bool SX1276LoRaGetImplicitHeaderOn( void )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG1, &SX1276LR->RegModemConfig1 );
|
||||
LoRaSettings.ImplicitHeaderOn =(bool) (( SX1276LR->RegModemConfig1 & RFLR_MODEMCONFIG1_IMPLICITHEADER_ON ));
|
||||
return LoRaSettings.ImplicitHeaderOn;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetRxSingleOn( bool enable )
|
||||
{
|
||||
LoRaSettings.RxSingleOn = enable;
|
||||
}
|
||||
|
||||
bool SX1276LoRaGetRxSingleOn( void )
|
||||
{
|
||||
return LoRaSettings.RxSingleOn;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetFreqHopOn( bool enable )
|
||||
{
|
||||
LoRaSettings.FreqHopOn = enable;
|
||||
}
|
||||
|
||||
bool SX1276LoRaGetFreqHopOn( void )
|
||||
{
|
||||
return LoRaSettings.FreqHopOn;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetHopPeriod( uint8_t value )
|
||||
{
|
||||
SX1276LR->RegHopPeriod = value;
|
||||
SX1276Write( REG_LR_HOPPERIOD, SX1276LR->RegHopPeriod );
|
||||
LoRaSettings.HopPeriod = value;
|
||||
}
|
||||
|
||||
uint8_t SX1276LoRaGetHopPeriod( void )
|
||||
{
|
||||
SX1276Read( REG_LR_HOPPERIOD, &SX1276LR->RegHopPeriod );
|
||||
LoRaSettings.HopPeriod = SX1276LR->RegHopPeriod;
|
||||
return LoRaSettings.HopPeriod;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetTxPacketTimeout( uint32_t value )
|
||||
{
|
||||
LoRaSettings.TxPacketTimeout = value;
|
||||
}
|
||||
|
||||
uint32_t SX1276LoRaGetTxPacketTimeout( void )
|
||||
{
|
||||
return LoRaSettings.TxPacketTimeout;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetRxPacketTimeout( uint32_t value )
|
||||
{
|
||||
LoRaSettings.RxPacketTimeout = value;
|
||||
}
|
||||
|
||||
uint32_t SX1276LoRaGetRxPacketTimeout( void )
|
||||
{
|
||||
return LoRaSettings.RxPacketTimeout;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetPayloadLength( uint8_t value )
|
||||
{
|
||||
SX1276LR->RegPayloadLength = value;
|
||||
SX1276Write( REG_LR_PAYLOADLENGTH, SX1276LR->RegPayloadLength );
|
||||
LoRaSettings.PayloadLength = value;
|
||||
}
|
||||
|
||||
uint8_t SX1276LoRaGetPayloadLength( void )
|
||||
{
|
||||
SX1276Read( REG_LR_PAYLOADLENGTH, &SX1276LR->RegPayloadLength );
|
||||
LoRaSettings.PayloadLength = SX1276LR->RegPayloadLength;
|
||||
return LoRaSettings.PayloadLength;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetPa20dBm( bool enale )
|
||||
{
|
||||
SX1276Read( REG_LR_PADAC, &SX1276LR->RegPaDac );
|
||||
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
|
||||
|
||||
if( ( SX1276LR->RegPaConfig & RFLR_PACONFIG_PASELECT_PABOOST ) == RFLR_PACONFIG_PASELECT_PABOOST )
|
||||
{
|
||||
if( enale == true )
|
||||
{
|
||||
SX1276LR->RegPaDac = 0x87;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SX1276LR->RegPaDac = 0x84;
|
||||
}
|
||||
SX1276Write( REG_LR_PADAC, SX1276LR->RegPaDac );
|
||||
}
|
||||
|
||||
bool SX1276LoRaGetPa20dBm( void )
|
||||
{
|
||||
SX1276Read( REG_LR_PADAC, &SX1276LR->RegPaDac );
|
||||
|
||||
return ( ( SX1276LR->RegPaDac & 0x07 ) == 0x07 ) ? true : false;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetPAOutput( uint8_t outputPin )
|
||||
{
|
||||
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
|
||||
SX1276LR->RegPaConfig = (SX1276LR->RegPaConfig & RFLR_PACONFIG_PASELECT_MASK ) | outputPin;
|
||||
SX1276Write( REG_LR_PACONFIG, SX1276LR->RegPaConfig );
|
||||
}
|
||||
|
||||
uint8_t SX1276LoRaGetPAOutput( void )
|
||||
{
|
||||
SX1276Read( REG_LR_PACONFIG, &SX1276LR->RegPaConfig );
|
||||
return SX1276LR->RegPaConfig & ~RFLR_PACONFIG_PASELECT_MASK;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetPaRamp( uint8_t value )
|
||||
{
|
||||
SX1276Read( REG_LR_PARAMP, &SX1276LR->RegPaRamp );
|
||||
SX1276LR->RegPaRamp = ( SX1276LR->RegPaRamp & RFLR_PARAMP_MASK ) | ( value & ~RFLR_PARAMP_MASK );
|
||||
SX1276Write( REG_LR_PARAMP, SX1276LR->RegPaRamp );
|
||||
}
|
||||
|
||||
uint8_t SX1276LoRaGetPaRamp( void )
|
||||
{
|
||||
SX1276Read( REG_LR_PARAMP, &SX1276LR->RegPaRamp );
|
||||
return SX1276LR->RegPaRamp & ~RFLR_PARAMP_MASK;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetSymbTimeout( uint16_t value )
|
||||
{
|
||||
SX1276ReadBuffer( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2, 2 );
|
||||
|
||||
SX1276LR->RegModemConfig2 = ( SX1276LR->RegModemConfig2 & RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) | ( ( value >> 8 ) & ~RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK );
|
||||
SX1276LR->RegSymbTimeoutLsb = value & 0xFF;
|
||||
SX1276WriteBuffer( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2, 2 );
|
||||
}
|
||||
|
||||
uint16_t SX1276LoRaGetSymbTimeout( void )
|
||||
{
|
||||
SX1276ReadBuffer( REG_LR_MODEMCONFIG2, &SX1276LR->RegModemConfig2, 2 );
|
||||
return ( ( SX1276LR->RegModemConfig2 & ~RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) << 8 ) | SX1276LR->RegSymbTimeoutLsb;
|
||||
}
|
||||
|
||||
void SX1276LoRaSetLowDatarateOptimize( bool enable )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG3, &SX1276LR->RegModemConfig3 );
|
||||
SX1276LR->RegModemConfig3 = ( SX1276LR->RegModemConfig3 & RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK ) | ( enable << 3 );
|
||||
SX1276Write( REG_LR_MODEMCONFIG3, SX1276LR->RegModemConfig3 );
|
||||
}
|
||||
|
||||
bool SX1276LoRaGetLowDatarateOptimize( void )
|
||||
{
|
||||
SX1276Read( REG_LR_MODEMCONFIG3, &SX1276LR->RegModemConfig3 );
|
||||
return (bool)(( ( SX1276LR->RegModemConfig3 & RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_ON ) >> 3 ));
|
||||
}
|
||||
|
||||
void SX1276LoRaSetNbTrigPeaks( uint8_t value )
|
||||
{
|
||||
SX1276Read( 0x31, &SX1276LR->RegTestReserved31 );
|
||||
SX1276LR->RegTestReserved31 = ( SX1276LR->RegTestReserved31 & 0xF8 ) | value;
|
||||
SX1276Write( 0x31, SX1276LR->RegTestReserved31 );
|
||||
}
|
||||
|
||||
uint8_t SX1276LoRaGetNbTrigPeaks( void )
|
||||
{
|
||||
SX1276Read( 0x31, &SX1276LR->RegTestReserved31 );
|
||||
return ( SX1276LR->RegTestReserved31 & 0x07 );
|
||||
}
|
||||
//#endif // (SX1276_LORA)
|
||||
//#endif // USE_SX1276_RADIO
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
|
||||
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
|
||||
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
|
||||
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
|
||||
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* Copyright (C) SEMTECH S.A.
|
||||
*/
|
||||
/*!
|
||||
* \file sx1276-LoRaMisc.h
|
||||
* \brief SX1276 RF chip high level functions driver
|
||||
*
|
||||
* \remark Optional support functions.
|
||||
* These functions are defined only to easy the change of the
|
||||
* parameters.
|
||||
* For a final firmware the radio parameters will be known so
|
||||
* there is no need to support all possible parameters.
|
||||
* Removing these functions will greatly reduce the final firmware
|
||||
* size.
|
||||
*
|
||||
* \version 2.0.B2
|
||||
* \date May 6 2013
|
||||
* \author Gregory Cristian
|
||||
*
|
||||
* Last modified by Miguel Luis on Jun 19 2013
|
||||
*/
|
||||
#ifndef __SX1276_LORA_MISC_H__
|
||||
#define __SX1276_LORA_MISC_H__
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Writes the new RF frequency value
|
||||
*
|
||||
* \param [IN] freq New RF frequency value in [Hz]
|
||||
*/
|
||||
void SX1276LoRaSetRFFrequency( uint32_t freq );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current RF frequency value
|
||||
*
|
||||
* \retval freq Current RF frequency value in [Hz]
|
||||
*/
|
||||
uint32_t SX1276LoRaGetRFFrequency( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new RF output power value
|
||||
*
|
||||
* \param [IN] power New output power value in [dBm]
|
||||
*/
|
||||
void SX1276LoRaSetRFPower( int8_t power );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current RF output power value
|
||||
*
|
||||
* \retval power Current output power value in [dBm]
|
||||
*/
|
||||
int8_t SX1276LoRaGetRFPower( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new Signal Bandwidth value
|
||||
*
|
||||
* \remark This function sets the IF frequency according to the datasheet
|
||||
*
|
||||
* \param [IN] factor New Signal Bandwidth value [0: 125 kHz, 1: 250 kHz, 2: 500 kHz]
|
||||
*/
|
||||
void SX1276LoRaSetSignalBandwidth( uint8_t bw );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current Signal Bandwidth value
|
||||
*
|
||||
* \retval factor Current Signal Bandwidth value [0: 125 kHz, 1: 250 kHz, 2: 500 kHz]
|
||||
*/
|
||||
uint8_t SX1276LoRaGetSignalBandwidth( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new Spreading Factor value
|
||||
*
|
||||
* \param [IN] factor New Spreading Factor value [7, 8, 9, 10, 11, 12]
|
||||
*/
|
||||
void SX1276LoRaSetSpreadingFactor( uint8_t factor );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current Spreading Factor value
|
||||
*
|
||||
* \retval factor Current Spreading Factor value [7, 8, 9, 10, 11, 12]
|
||||
*/
|
||||
uint8_t SX1276LoRaGetSpreadingFactor( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new Error Coding value
|
||||
*
|
||||
* \param [IN] value New Error Coding value [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
|
||||
*/
|
||||
void SX1276LoRaSetErrorCoding( uint8_t value );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current Error Coding value
|
||||
*
|
||||
* \retval value Current Error Coding value [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
|
||||
*/
|
||||
uint8_t SX1276LoRaGetErrorCoding( void );
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables the packet CRC generation
|
||||
*
|
||||
* \param [IN] enaable [true, false]
|
||||
*/
|
||||
void SX1276LoRaSetPacketCrcOn( bool enable );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current packet CRC generation status
|
||||
*
|
||||
* \retval enable [true, false]
|
||||
*/
|
||||
bool SX1276LoRaGetPacketCrcOn( void );
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables the Implicit Header mode in LoRa
|
||||
*
|
||||
* \param [IN] enable [true, false]
|
||||
*/
|
||||
void SX1276LoRaSetImplicitHeaderOn( bool enable );
|
||||
|
||||
/*!
|
||||
* \brief Check if implicit header mode in LoRa in enabled or disabled
|
||||
*
|
||||
* \retval enable [true, false]
|
||||
*/
|
||||
bool SX1276LoRaGetImplicitHeaderOn( void );
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables Rx single instead of Rx continuous
|
||||
*
|
||||
* \param [IN] enable [true, false]
|
||||
*/
|
||||
void SX1276LoRaSetRxSingleOn( bool enable );
|
||||
|
||||
/*!
|
||||
* \brief Check if LoRa is in Rx Single mode
|
||||
*
|
||||
* \retval enable [true, false]
|
||||
*/
|
||||
bool SX1276LoRaGetRxSingleOn( void );
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables the frequency hopping
|
||||
*
|
||||
* \param [IN] enable [true, false]
|
||||
*/
|
||||
|
||||
void SX1276LoRaSetFreqHopOn( bool enable );
|
||||
|
||||
/*!
|
||||
* \brief Get the frequency hopping status
|
||||
*
|
||||
* \param [IN] enable [true, false]
|
||||
*/
|
||||
bool SX1276LoRaGetFreqHopOn( void );
|
||||
|
||||
/*!
|
||||
* \brief Set symbol period between frequency hops
|
||||
*
|
||||
* \param [IN] value
|
||||
*/
|
||||
void SX1276LoRaSetHopPeriod( uint8_t value );
|
||||
|
||||
/*!
|
||||
* \brief Get symbol period between frequency hops
|
||||
*
|
||||
* \retval value symbol period between frequency hops
|
||||
*/
|
||||
uint8_t SX1276LoRaGetHopPeriod( void );
|
||||
|
||||
/*!
|
||||
* \brief Set timeout Tx packet (based on MCU timer, timeout between Tx Mode entry Tx Done IRQ)
|
||||
*
|
||||
* \param [IN] value timeout (ms)
|
||||
*/
|
||||
void SX1276LoRaSetTxPacketTimeout( uint32_t value );
|
||||
|
||||
/*!
|
||||
* \brief Get timeout between Tx packet (based on MCU timer, timeout between Tx Mode entry Tx Done IRQ)
|
||||
*
|
||||
* \retval value timeout (ms)
|
||||
*/
|
||||
uint32_t SX1276LoRaGetTxPacketTimeout( void );
|
||||
|
||||
/*!
|
||||
* \brief Set timeout Rx packet (based on MCU timer, timeout between Rx Mode entry and Rx Done IRQ)
|
||||
*
|
||||
* \param [IN] value timeout (ms)
|
||||
*/
|
||||
void SX1276LoRaSetRxPacketTimeout( uint32_t value );
|
||||
|
||||
/*!
|
||||
* \brief Get timeout Rx packet (based on MCU timer, timeout between Rx Mode entry and Rx Done IRQ)
|
||||
*
|
||||
* \retval value timeout (ms)
|
||||
*/
|
||||
uint32_t SX1276LoRaGetRxPacketTimeout( void );
|
||||
|
||||
/*!
|
||||
* \brief Set payload length
|
||||
*
|
||||
* \param [IN] value payload length
|
||||
*/
|
||||
void SX1276LoRaSetPayloadLength( uint8_t value );
|
||||
|
||||
/*!
|
||||
* \brief Get payload length
|
||||
*
|
||||
* \retval value payload length
|
||||
*/
|
||||
uint8_t SX1276LoRaGetPayloadLength( void );
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables the 20 dBm PA
|
||||
*
|
||||
* \param [IN] enable [true, false]
|
||||
*/
|
||||
void SX1276LoRaSetPa20dBm( bool enale );
|
||||
|
||||
/*!
|
||||
* \brief Gets the current 20 dBm PA status
|
||||
*
|
||||
* \retval enable [true, false]
|
||||
*/
|
||||
bool SX1276LoRaGetPa20dBm( void );
|
||||
|
||||
/*!
|
||||
* \brief Set the RF Output pin
|
||||
*
|
||||
* \param [IN] RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
|
||||
*/
|
||||
void SX1276LoRaSetPAOutput( uint8_t outputPin );
|
||||
|
||||
/*!
|
||||
* \brief Gets the used RF Ouptut pin
|
||||
*
|
||||
* \retval RF_PACONFIG_PASELECT_PABOOST or RF_PACONFIG_PASELECT_RFO
|
||||
*/
|
||||
uint8_t SX1276LoRaGetPAOutput( void );
|
||||
|
||||
/*!
|
||||
* \brief Writes the new PA rise/fall time of ramp up/down value
|
||||
*
|
||||
* \param [IN] value New PaRamp value
|
||||
*/
|
||||
void SX1276LoRaSetPaRamp( uint8_t value );
|
||||
|
||||
/*!
|
||||
* \brief Reads the current PA rise/fall time of ramp up/down value
|
||||
*
|
||||
* \retval freq Current PaRamp value
|
||||
*/
|
||||
uint8_t SX1276LoRaGetPaRamp( void );
|
||||
|
||||
/*!
|
||||
* \brief Set Symbol Timeout based on symbol length
|
||||
*
|
||||
* \param [IN] value number of symbol
|
||||
*/
|
||||
void SX1276LoRaSetSymbTimeout( uint16_t value );
|
||||
|
||||
/*!
|
||||
* \brief Get Symbol Timeout based on symbol length
|
||||
*
|
||||
* \retval value number of symbol
|
||||
*/
|
||||
uint16_t SX1276LoRaGetSymbTimeout( void );
|
||||
|
||||
/*!
|
||||
* \brief Configure the device to optimize low datarate transfers
|
||||
*
|
||||
* \param [IN] enable Enables/Disables the low datarate optimization
|
||||
*/
|
||||
void SX1276LoRaSetLowDatarateOptimize( bool enable );
|
||||
|
||||
/*!
|
||||
* \brief Get the status of optimize low datarate transfers
|
||||
*
|
||||
* \retval LowDatarateOptimize enable or disable
|
||||
*/
|
||||
bool SX1276LoRaGetLowDatarateOptimize( void );
|
||||
|
||||
/*!
|
||||
* \brief Get the preamble length
|
||||
*
|
||||
* \retval value preamble length
|
||||
*/
|
||||
uint16_t SX1276LoRaGetPreambleLength( void );
|
||||
|
||||
/*!
|
||||
* \brief Set the preamble length
|
||||
*
|
||||
* \param [IN] value preamble length
|
||||
*/
|
||||
void SX1276LoRaSetPreambleLength( uint16_t value );
|
||||
|
||||
/*!
|
||||
* \brief Set the number or rolling preamble symbol needed for detection
|
||||
*
|
||||
* \param [IN] value number of preamble symbol
|
||||
*/
|
||||
void SX1276LoRaSetNbTrigPeaks( uint8_t value );
|
||||
|
||||
/*!
|
||||
* \brief Get the number or rolling preamble symbol needed for detection
|
||||
*
|
||||
* \retval value number of preamble symbol
|
||||
*/
|
||||
uint8_t SX1276LoRaGetNbTrigPeaks( void );
|
||||
#endif //__SX1276_LORA_MISC_H__
|
||||
+3089
File diff suppressed because it is too large
Load Diff
+751
@@ -0,0 +1,751 @@
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hal_uart.h
|
||||
* @author William Liang
|
||||
* @version V1.0.0
|
||||
* @date 07/22/2013
|
||||
* @brief This file contains the headers of the uart handlers.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef _UART_H_
|
||||
#define _UART_H_
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include "include.h"
|
||||
#include "protocol.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define USART_BUF_SIXE 255
|
||||
|
||||
//define COM MBUS master infomation
|
||||
#define COM_MBUS_MASTER_NO USART1
|
||||
|
||||
#ifdef COMMON_VER
|
||||
#define COM_MBUS_MASTER_BAUD 2400
|
||||
#endif
|
||||
|
||||
#ifdef AMT_VER
|
||||
#define COM_MBUS_MASTER_BAUD 1200
|
||||
#endif
|
||||
|
||||
#define COM_MBUS_MASTER_CHECK USART_Parity_Even
|
||||
#define COM_MBUS_MASTER_CLK RCC_APB2Periph_USART1
|
||||
|
||||
#define COM_MBUS_MASTER_TX_PIN GPIO_Pin_9
|
||||
#define COM_MBUS_MASTER_TX_PORT GPIOA
|
||||
#define COM_MBUS_MASTER_TX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_MBUS_MASTER_RX_PIN GPIO_Pin_10
|
||||
#define COM_MBUS_MASTER_RX_PORT GPIOA
|
||||
#define COM_MBUS_MASTER_RX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_MBUS_MASTER_IRQn USART1_IRQn
|
||||
|
||||
#define COM_MBUS_MASTER_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
#define COM_MBUS_MASTER_TX_DMA_CHANNEL DMA1_Channel4
|
||||
#define COM_MBUS_MASTER_DR_BASE (USART1_BASE + 4)
|
||||
#define COM_MBUS_MASTER_TX_IRQHandler DMA1_Channel4_IRQHandler
|
||||
#define COM_MBUS_MASTER_RX_IRQHandler USART1_IRQHandler
|
||||
#define COM_MBUS_MASTER_TX_DMA_COMPLETE DMA1_IT_TC4
|
||||
#define COM_MBUS_MASTER_TX_DMA_ERROR DMA1_IT_TE4
|
||||
#define COM_MBUS_MASTER_DMA_IRQn DMA1_Channel4_IRQn
|
||||
|
||||
#define COM_MBUS_MASTER_TX_BUFFER_SIZE 200
|
||||
#define COM_MBUS_MASTER_RX_BUFFER_SIZE 512
|
||||
#define COM_MBUS_MASTER_STR "MBUS master"
|
||||
|
||||
|
||||
//define COM LORA moudule infomation
|
||||
//#define COM_RADIO_NO UART5
|
||||
//#define COM_RADIO_BAUD 9600 //8,e,1
|
||||
//#define COM_RADIO_CHECK USART_Parity_Even
|
||||
//#define COM_RADIO_CLK RCC_APB1Periph_UART5
|
||||
//
|
||||
//#define COM_RADIO_TX_PIN GPIO_Pin_12
|
||||
//#define COM_RADIO_TX_PORT GPIOC
|
||||
//#define COM_RADIO_TX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
//
|
||||
//#define COM_RADIO_RX_PIN GPIO_Pin_2
|
||||
//#define COM_RADIO_RX_PORT GPIOD
|
||||
//#define COM_RADIO_RX_PORT_CLK RCC_APB2Periph_GPIOD
|
||||
//
|
||||
//#define COM_RADIO_IRQn UART5_IRQn
|
||||
//
|
||||
//#define COM_RADIO_DMA_CLK 0
|
||||
//
|
||||
//#define COM_RADIO_TX_DMA_CHANNEL 0
|
||||
//#define COM_RADIO_DR_BASE 0
|
||||
//#define COM_RADIO_TX_IRQHandler 0
|
||||
//#define COM_RADIO_RX_IRQHandler 0
|
||||
//#define COM_RADIO_TX_DMA_COMPLETE 0
|
||||
//#define COM_RADIO_TX_DMA_ERROR 0
|
||||
//#define COM_RADIO_DMA_IRQn 0
|
||||
//
|
||||
//
|
||||
//#define COM_RADIO_TX_BUFFER_SIZE 255
|
||||
//#define COM_RADIO_RX_BUFFER_SIZE 255
|
||||
//#define COM_RADIO_STR "radio"
|
||||
|
||||
|
||||
#define COM_RADIO_NO UART4
|
||||
#define COM_RADIO_BAUD 2400 //8,e,1
|
||||
#define COM_RADIO_CHECK USART_Parity_Even
|
||||
#define COM_RADIO_CLK RCC_APB1Periph_UART4
|
||||
|
||||
#define COM_RADIO_TX_PIN GPIO_Pin_10
|
||||
#define COM_RADIO_TX_PORT GPIOC
|
||||
#define COM_RADIO_TX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define COM_RADIO_RX_PIN GPIO_Pin_11
|
||||
#define COM_RADIO_RX_PORT GPIOC
|
||||
#define COM_RADIO_RX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define COM_RADIO_IRQn UART4_IRQn
|
||||
|
||||
#define COM_RADIO_DMA_CLK RCC_AHBPeriph_DMA2
|
||||
|
||||
#define COM_RADIO_TX_DMA_CHANNEL DMA2_Channel5
|
||||
#define COM_RADIO_DR_BASE (UART4_BASE + 4)
|
||||
#define COM_RADIO_TX_IRQHandler DMA2_Channel4_5_IRQHandler
|
||||
#define COM_RADIO_RX_IRQHandler UART4_IRQHandler
|
||||
#define COM_RADIO_TX_DMA_COMPLETE DMA2_IT_TC5
|
||||
#define COM_RADIO_TX_DMA_ERROR DMA2_IT_TE5
|
||||
#define COM_RADIO_DMA_IRQn DMA2_Channel4_5_IRQn
|
||||
|
||||
|
||||
//#define COM_RADIO_TX_BUFFER_SIZE 255
|
||||
//#define COM_RADIO_RX_BUFFER_SIZE 255
|
||||
#define COM_RADIO_TX_BUFFER_SIZE 10
|
||||
#define COM_RADIO_RX_BUFFER_SIZE 10
|
||||
#define COM_RADIO_STR "radio"
|
||||
|
||||
|
||||
//
|
||||
//#define COM_DEBUG_NO UART4 // DEBUG
|
||||
//#define COM_DEBUG_BAUD 9600
|
||||
//#define COM_DEBUG_CHECK USART_Parity_Even
|
||||
//#define COM_DEBUG_CLK RCC_APB1Periph_UART4
|
||||
//
|
||||
//#define COM_DEBUG_TX_PIN GPIO_Pin_10
|
||||
//#define COM_DEBUG_TX_PORT GPIOC
|
||||
//#define COM_DEBUG_TX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
//
|
||||
//#define COM_DEBUG_RX_PIN GPIO_Pin_11
|
||||
//#define COM_DEBUG_RX_PORT GPIOC
|
||||
//#define COM_DEBUG_RX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
//
|
||||
//#define COM_DEBUG_IRQn UART4_IRQn
|
||||
//
|
||||
//#define COM_DEBUG_DMA_CLK RCC_AHBPeriph_DMA2
|
||||
//#define COM_DEBUG_TX_DMA_CHANNEL DMA2_Channel5
|
||||
//#define COM_DEBUG_DR_BASE (UART4_BASE + 4)
|
||||
//#define COM_DEBUG_TX_IRQHandler DMA2_Channel4_5_IRQHandler
|
||||
//#define COM_DEBUG_RX_IRQHandler UART4_IRQHandler
|
||||
//#define COM_DEBUG_TX_DMA_COMPLETE DMA2_IT_TC5
|
||||
//#define COM_DEBUG_TX_DMA_ERROR DMA2_IT_TE5
|
||||
//#define COM_DEBUG_DMA_IRQn DMA2_Channel4_5_IRQn
|
||||
//#define COM_DEBUG_TX_BUFFER_SIZE 255
|
||||
//#define COM_DEBUG_RX_BUFFER_SIZE 255
|
||||
//#define COM_DEBUG_STR "DEBUG"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//define COM PLC module infomation
|
||||
#define COM_PLC_NO USART3
|
||||
#define COM_PLC_BAUD 115200
|
||||
#define COM_PLC_CHECK USART_Parity_No
|
||||
//#define COM_PLC_BAUD 2400
|
||||
//#define COM_PLC_CHECK USART_Parity_Even
|
||||
#define COM_PLC_CLK RCC_APB1Periph_USART3
|
||||
|
||||
#define COM_PLC_TX_PIN GPIO_Pin_10
|
||||
#define COM_PLC_TX_PORT GPIOB
|
||||
#define COM_PLC_TX_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define COM_PLC_RX_PIN GPIO_Pin_11
|
||||
#define COM_PLC_RX_PORT GPIOB
|
||||
#define COM_PLC_RX_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define COM_PLC_IRQn USART3_IRQn
|
||||
|
||||
#define COM_PLC_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
#define COM_PLC_TX_DMA_CHANNEL DMA1_Channel2
|
||||
#define COM_PLC_DR_BASE (USART3_BASE + 4)
|
||||
#define COM_PLC_TX_IRQHandler DMA1_Channel2_IRQHandler
|
||||
#define COM_PLC_RX_IRQHandler USART3_IRQHandler
|
||||
#define COM_PLC_TX_DMA_COMPLETE DMA1_IT_TC2
|
||||
#define COM_PLC_TX_DMA_ERROR DMA1_IT_TE2
|
||||
#define COM_PLC_DMA_IRQn DMA1_Channel2_IRQn
|
||||
|
||||
#define COM_PLC_TX_BUFFER_SIZE 512
|
||||
#define COM_PLC_RX_BUFFER_SIZE 512
|
||||
#define COM_PLC_STR "PLC"
|
||||
|
||||
|
||||
//define COM LORA moudule infomation
|
||||
#define COM_485_NO USART2
|
||||
#define COM_485_BAUD 2400 //8,e,1
|
||||
#define COM_485_CHECK USART_Parity_Even//USART_Parity_No
|
||||
#define COM_485_CLK RCC_APB1Periph_USART2
|
||||
|
||||
#define COM_485_TX_PIN GPIO_Pin_2
|
||||
#define COM_485_TX_PORT GPIOA
|
||||
#define COM_485_TX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_485_RX_PIN GPIO_Pin_3
|
||||
#define COM_485_RX_PORT GPIOA
|
||||
#define COM_485_RX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_485_IRQn USART2_IRQn
|
||||
|
||||
#define COM_485_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
#define COM_485_TX_DMA_CHANNEL DMA1_Channel7
|
||||
#define COM_485_DR_BASE (USART2_BASE + 4)
|
||||
#define COM_485_TX_IRQHandler DMA1_Channel7_IRQHandler
|
||||
#define COM_485_RX_IRQHandler USART2_IRQHandler
|
||||
#define COM_485_TX_DMA_COMPLETE DMA1_IT_TC7
|
||||
#define COM_485_TX_DMA_ERROR DMA1_IT_TE7
|
||||
#define COM_485_DMA_IRQn DMA1_Channel7_IRQn
|
||||
|
||||
#define COM_485_TX_BUFFER_SIZE 255
|
||||
#define COM_485_RX_BUFFER_SIZE 255
|
||||
//#define COM_485_TX_BUFFER_SIZE 20
|
||||
//#define COM_485_RX_BUFFER_SIZE 10
|
||||
#define COM_485_STR "485"
|
||||
|
||||
|
||||
|
||||
#define COM_4852_NO NULL//USART2
|
||||
#define COM_4852_BAUD 600 //8,e,1
|
||||
#define COM_4852_CHECK USART_Parity_Even
|
||||
#define COM_4852_CLK NULL//RCC_APB1Periph_USART2
|
||||
|
||||
#define COM_4852_TX_PIN GPIO_Pin_4
|
||||
#define COM_4852_TX_PORT GPIOA
|
||||
#define COM_4852_TX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_4852_RX_PIN GPIO_Pin_5
|
||||
#define COM_4852_RX_PORT GPIOA
|
||||
#define COM_4852_RX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
|
||||
#define COM_4852_TX_BIT0 GPIO_ResetBits(COM_4852_TX_PORT, COM_4852_TX_PIN);
|
||||
#define COM_4852_TX_BIT1 GPIO_SetBits(COM_4852_TX_PORT, COM_4852_TX_PIN);
|
||||
#define COM_4852_RX_BIT GPIO_ReadInputDataBit(COM_4852_RX_PORT, COM_4852_RX_PIN)
|
||||
//接收管脚中断
|
||||
#define COM_4852_RX_LINE EXTI_Line5
|
||||
#define COM_4852_RX_PORT_SOURCE GPIO_PortSourceGPIOA
|
||||
#define COM_4852_RX_PIN_SOURCE GPIO_PinSource5
|
||||
#define COM_4852_IRQn EXTI9_5_IRQn//USART2_IRQn
|
||||
//数据波特率定时器
|
||||
#define COM_4852_BAUD_TIMER TIM4
|
||||
#define COM_4852_BAUD_TIMER_CLK RCC_APB1Periph_TIM4
|
||||
#define COM_4852_BAUD_PRESC 100
|
||||
#define COM_4852_BAUD_TIMER_PERIOD (SystemCoreClock/COM_4852_BAUD_PRESC/COM_4852_BAUD)
|
||||
#define COM_4852_BAUD_IRQn TIM4_IRQn
|
||||
#define COM_4852_BAUD_IRQHandler TIM4_IRQHandler
|
||||
|
||||
|
||||
|
||||
|
||||
#define COM_4852_DMA_CLK 0//RCC_AHBPeriph_DMA1
|
||||
#define COM_4852_TX_DMA_CHANNEL 0//DMA1_Channel7
|
||||
#define COM_4852_DR_BASE 0//(USART2_BASE + 4)
|
||||
#define COM_4852_TX_IRQHandler 0//DMA1_Channel7_IRQHandler
|
||||
#define COM_4852_RX_IRQHandler EXTI9_5_IRQHandler//USART2_IRQHandler
|
||||
#define COM_4852_TX_DMA_COMPLETE 0//DMA1_IT_TC7
|
||||
#define COM_4852_TX_DMA_ERROR 0//DMA1_IT_TE7
|
||||
#define COM_4852_DMA_IRQn 0//DMA1_Channel7_IRQn
|
||||
|
||||
#define COM_4852_TX_BUFFER_SIZE 255
|
||||
#define COM_4852_RX_BUFFER_SIZE 255
|
||||
#define COM_4852_STR "4852"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
//define COM module end
|
||||
#define MBUS_OVERLOAD_FLAG_PIN GPIO_Pin_3
|
||||
#define MBUS_OVERLOAD_FLAG_PIN_PORT GPIOC
|
||||
#define MBUS_OVERLOAD_FLAG_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define MBUS_OVERLOAD_FLAG_PORT_SOURCE GPIO_PortSourceGPIOC
|
||||
#define MBUS_OVERLOAD_FLAG_PIN_SOURCE GPIO_PinSource3
|
||||
#define MBUS_OVERLOAD_FLAG_LINE EXTI_Line3
|
||||
#define MBUS_OVERLOAD_FLAG_IRQHandler EXTI3_IRQHandler
|
||||
*/
|
||||
|
||||
|
||||
#define MBUSM_BAUD_COFF (11 * 1000 / COM_MBUS_MASTER_BAUD)
|
||||
#define PLC_BAUD_COFF (11 * 1000 / COM_PLC_BAUD)
|
||||
#define RS485_BAUD_COFF (11 * 1000 / COM_485_BAUD)
|
||||
#define PRINT_BAUD_COFF (11 * 1000 / COM_DEBUG_BAUD)
|
||||
|
||||
|
||||
//#define MBUS_SWITCH_TIMEOUT (10000 /portTICK_RATE_MS)
|
||||
#define MBUS_SWITCH_TIMEOUT (60000 /portTICK_RATE_MS)
|
||||
|
||||
|
||||
#define PORT_RX_TIMEOUT (70 /portTICK_RATE_MS)//设置串口的超时接收时间,此值需设置为最低波特率的最少两个字节时间
|
||||
#define SCAN_PORT_RERIOD (5 /portTICK_RATE_MS)//扫描串口超时的周期
|
||||
|
||||
#define MBUS_TIMEOUT (1200 /portTICK_RATE_MS)
|
||||
#define CS485_TIMEOUT (2000 /portTICK_RATE_MS)
|
||||
#define PLC_TIMEOUT (2500 /portTICK_RATE_MS)
|
||||
#define XIMEI_TIMEOUT (10000 /portTICK_RATE_MS)
|
||||
#define MUT_TIMEOUT (2000 /portTICK_RATE_MS)
|
||||
|
||||
#define OPEN_SWITCN_DELAY (2000 /portTICK_RATE_MS)
|
||||
#define DELAY_HOUR_TIME (3600000 /portTICK_RATE_MS)
|
||||
#define DELAY_MIN_TIME (60000 /portTICK_RATE_MS)
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USART_TypeDef * com;
|
||||
USART_InitTypeDef uart_param;
|
||||
uint32_t com_clk;
|
||||
uint16_t com_tx_pin;
|
||||
GPIO_TypeDef * com_tx_port;
|
||||
uint32_t com_tx_port_clk;
|
||||
uint16_t com_rx_pin;
|
||||
GPIO_TypeDef * com_rx_port;
|
||||
uint32_t xom_rx_port_clk;
|
||||
uint32_t com_DMA_CLK;
|
||||
uint8_t com_IRQn;
|
||||
uint8_t com_DMA_IRQn;
|
||||
}st_uart_int;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USART_TypeDef * com;
|
||||
DMA_Channel_TypeDef * com_TX_DMA_CHANNEL;
|
||||
uint32_t com_DR_BASE;
|
||||
u16 txbufLength;
|
||||
}st_uart_channel_cfg;
|
||||
|
||||
#define COMM_BUF_SIZE 512
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 *rxBuf;
|
||||
u8 *txBuf;
|
||||
u16 tx_index;
|
||||
u16 rx_index;
|
||||
u16 rx_len;
|
||||
u16 tx_len;
|
||||
u32 rx_timeout;
|
||||
u32 tx_timeout;
|
||||
}st_uart_buf_cfg;
|
||||
|
||||
|
||||
struct st_uart_port
|
||||
{
|
||||
EventBits_t port_No;
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
st_uart_int init;
|
||||
st_uart_channel_cfg chl;
|
||||
st_uart_buf_cfg data;
|
||||
char * string;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#define DEFAULT_USART_CFG(baud, check) { baud,USART_WordLength_9b,USART_StopBits_1,\
|
||||
check, (USART_Mode_Rx | USART_Mode_Tx),\
|
||||
USART_HardwareFlowControl_None\
|
||||
}
|
||||
|
||||
|
||||
#define USART_INIT(name) { name##_NO,\
|
||||
DEFAULT_USART_CFG(name##_BAUD, name##_CHECK),\
|
||||
name##_CLK,name##_TX_PIN,\
|
||||
name##_TX_PORT,name##_TX_PORT_CLK,\
|
||||
name##_RX_PIN,\
|
||||
name##_RX_PORT,\
|
||||
name##_RX_PORT_CLK,\
|
||||
name##_DMA_CLK,\
|
||||
name##_IRQn,\
|
||||
name##_DMA_IRQn\
|
||||
}
|
||||
|
||||
#define USART_DMA_config(name) {name##_NO, name##_TX_DMA_CHANNEL, (uint32_t)name##_DR_BASE, name##_TX_BUFFER_SIZE}
|
||||
|
||||
#define USART_PORT_PARAMS(name, rxbuf, txbuf) {name##_PORT_NO, NULL, USART_INIT(name),USART_DMA_config(name),{rxbuf,txbuf,0,0,0,0,0,0}, name##_STR}
|
||||
|
||||
|
||||
#define USART_RX_INT_HANDLE(name) void name##_RX_IRQHandler(void) \
|
||||
{ \
|
||||
if (USART_GetITStatus(name##_NO, USART_IT_RXNE) != RESET) \
|
||||
{ \
|
||||
uart_int_rx_frame(&(name##_port)); \
|
||||
} \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
#define USART_TX_INT_HANDLE(name) void name##_TX_IRQHandler(void) \
|
||||
{ \
|
||||
if (DMA_GetITStatus(name##_TX_DMA_COMPLETE) != RESET) \
|
||||
{ \
|
||||
DMA_ClearITPendingBit(name##_TX_DMA_COMPLETE); \
|
||||
uart_dma_tx_callback(&(name##_port)); \
|
||||
} \
|
||||
if (DMA_GetITStatus(name##_TX_DMA_ERROR) != RESET) \
|
||||
{ \
|
||||
DMA_ClearITPendingBit(name##_TX_DMA_ERROR); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define create_uart_port(name, rxbuf, txbuf) struct st_uart_port name##_port = USART_PORT_PARAMS(name, rxbuf, txbuf);\
|
||||
USART_TX_INT_HANDLE(name) \
|
||||
USART_RX_INT_HANDLE(name) \
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
UP_VER_OF_COMMON = 0,
|
||||
UP_VER_OF_ON_KEY,
|
||||
UP_VER_OF_OFF_KEY,
|
||||
UP_VER_OF_WHSF,
|
||||
UP_VER_OF_E5E50000,
|
||||
UP_VER_OF_E5E50001,
|
||||
UP_VER_OF_FJWGDATA,
|
||||
UP_VER_OF_standard,
|
||||
UP_VER_OF_MAX
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PORT_NONE = 0,
|
||||
PORT_MBUS_MASTER,
|
||||
PORT_RADIO,
|
||||
PORT_PLC,
|
||||
PORT_485,
|
||||
PORT_MUT,
|
||||
POET_DEBUG,
|
||||
POET_4852,
|
||||
PORT_MAX,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
COM_MBUS_MASTER_PORT_NO = (1UL << PORT_MBUS_MASTER),
|
||||
COM_RADIO_PORT_NO = (1UL << PORT_RADIO),
|
||||
COM_PLC_PORT_NO = (1UL << PORT_PLC),
|
||||
COM_485_PORT_NO = (1UL << PORT_485),
|
||||
COM_MUT_PORT_NO = (1UL << PORT_MUT),
|
||||
COM_DEBUG_PORT_NO = (1UL << POET_DEBUG),
|
||||
COM_4852_PORT_NO = (1UL << POET_4852),
|
||||
PORT_AUTO = (COM_MBUS_MASTER_PORT_NO | COM_485_PORT_NO | COM_MUT_PORT_NO)
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROTCL_AUTO = 0,
|
||||
PROTCL_E5E50000,
|
||||
|
||||
MBUS_METER_START,
|
||||
MBUS_901F_2400_E,
|
||||
MBUS_1F90_2400_E,
|
||||
MBUS_HHCQ_2400_N,
|
||||
MBUS_YZSJ_1200_E,
|
||||
MBUS_HZJD_1200_E,
|
||||
MBUS_METER_MAX,
|
||||
|
||||
RS485_METER_START,
|
||||
RS485_NJSM_1200_N,
|
||||
RS485_CS485_2400_E,
|
||||
RS485_XYDX_2400_8N2,
|
||||
RS485_METER_MAX,
|
||||
|
||||
MUT_METER_START,
|
||||
MUT_RS232_CD_115200_N,
|
||||
//MUT_CQXM_LORA,
|
||||
MUT_SPI_LORA,
|
||||
MUT_METER_MAX,
|
||||
};
|
||||
|
||||
/* Baud( bps): 0~7 依次表示:
|
||||
自适应, 1200, 2400, 4800, 9600, 19200,
|
||||
38400, 57600 */
|
||||
enum
|
||||
{
|
||||
BAUD_auto = 0,
|
||||
BAUD_1200,
|
||||
BAUD_2400,
|
||||
BAUD_4800,
|
||||
BAUD_9600,
|
||||
BAUD_19200,
|
||||
BAUD_38400,
|
||||
BAUD_57600,
|
||||
};
|
||||
|
||||
|
||||
/* 0/1:
|
||||
1/2 停止位 */
|
||||
enum
|
||||
{
|
||||
STOP_1bits = 0,
|
||||
STOP_2bits,
|
||||
};
|
||||
|
||||
|
||||
/* 0/1:
|
||||
无/有校验 */
|
||||
|
||||
enum
|
||||
{
|
||||
PARITY_NONE = 0,
|
||||
PARITY_TRUE,
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* 0/1:
|
||||
偶/奇校验 */
|
||||
enum
|
||||
{
|
||||
PARITY_EVEN = 0,
|
||||
PARITY_ODD,
|
||||
};
|
||||
|
||||
/* 0~3:
|
||||
5-8 位数 */
|
||||
enum
|
||||
{
|
||||
DATABITS_5 = 0,
|
||||
DATABITS_6,
|
||||
DATABITS_7,
|
||||
DATABITS_8,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
UP_PORT_PLC,
|
||||
UP_PORT_485,
|
||||
UP_PORT_MAX,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
|
||||
MBUS_MODE_MASTER = 0,
|
||||
MBUS_MODE_SLAVE,
|
||||
};
|
||||
|
||||
/********************define MBUS power contrl pin******************************/
|
||||
//MBUS继电器控制
|
||||
#define MBUS_POWER_CTRL_PIN GPIO_Pin_1
|
||||
#define MBUS_POWER_CTRL_PIN_PORT GPIOB
|
||||
#define MBUS_POWER_CTRL_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
#define open_mbus_switch() GPIO_ResetBits(MBUS_POWER_CTRL_PIN_PORT, MBUS_POWER_CTRL_PIN)
|
||||
//#define close_mbus_switch() GPIO_SetBits(MBUS_POWER_CTRL_PIN_PORT, MBUS_POWER_CTRL_PIN)
|
||||
#define mbus_switch_state() GPIO_ReadOutputDataBit(MBUS_POWER_CTRL_PIN_PORT, MBUS_POWER_CTRL_PIN)
|
||||
|
||||
/********************define MBUS in pin*******************************/
|
||||
#define MBUS_EXTIN_PIN GPIO_Pin_4
|
||||
#define MBUS_EXTIN_PORT GPIOC
|
||||
#define MBUS_EXTIN_CLK RCC_APB2Periph_GPIOC
|
||||
#define MBUS_in_state() GPIO_ReadInputDataBit(MBUS_EXTIN_PORT, MBUS_EXTIN_PIN)
|
||||
|
||||
#define MBUS_EXT_FLAG_PORT_SOURCE GPIO_PortSourceGPIOC
|
||||
#define MBUS_EXT_FLAG_PIN_SOURCE GPIO_PinSource4
|
||||
#define MBUS_EXT_FLAG_LINE EXTI_Line4
|
||||
#define MBUS_EXT_IRQHandler EXTI4_IRQHandler
|
||||
|
||||
|
||||
/********************define MBUS overload *******************************/
|
||||
#define MBUS_OVERLOAD_PIN GPIO_Pin_12
|
||||
#define MBUS_OVERLOAD_PORT GPIOB
|
||||
#define MBUS_OVERLOAD_CLK RCC_APB2Periph_GPIOB
|
||||
#define MBUS_OVERLOAD_in_state() GPIO_ReadInputDataBit(MBUS_OVERLOAD_PORT, MBUS_OVERLOAD_PIN)
|
||||
|
||||
#define MBUS_OVERLOAD_FLAG_PORT_SOURCE GPIO_PortSourceGPIOB
|
||||
#define MBUS_OVERLOAD_FLAG_PIN_SOURCE GPIO_PinSource12
|
||||
#define MBUS_OVERLOAD_FLAG_LINE EXTI_Line12
|
||||
#define MBUS_OVERLOAD_FLAG_IRQHandler EXTI15_10_IRQHandler
|
||||
|
||||
|
||||
/********************define power level pin*******************************/
|
||||
#define POWER_LEVEL_PIN GPIO_Pin_13
|
||||
#define POWER_LEVEL_PORT GPIOB
|
||||
#define POWER_LEVEL_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define SET_POWER_LEVEL_HIGH() GPIO_SetBits(POWER_LEVEL_PORT, POWER_LEVEL_PIN);
|
||||
#define SET_POWER_LEVEL_LOW() GPIO_ResetBits(POWER_LEVEL_PORT, POWER_LEVEL_PIN);
|
||||
#define power_level_state() GPIO_ReadOutputDataBit(POWER_LEVEL_PORT, POWER_LEVEL_PIN)
|
||||
|
||||
|
||||
|
||||
/********************define 485 power contrl pin******************************/
|
||||
#define RS485_CTRL_PIN GPIO_Pin_5
|
||||
#define RS485_CTRL_PIN_PORT GPIOC
|
||||
#define RS485_CTRL_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
#define open_RS485_switch() GPIO_ResetBits(RS485_CTRL_PIN_PORT, RS485_CTRL_PIN);hal_sRF_ITConfig(RS485_OVERLOAD_FLAG_LINE, ENABLE)
|
||||
|
||||
|
||||
#define close_RS485_switch() GPIO_SetBits(RS485_CTRL_PIN_PORT, RS485_CTRL_PIN); hal_sRF_ITConfig(RS485_OVERLOAD_FLAG_LINE, DISABLE)
|
||||
|
||||
|
||||
|
||||
#define RS485_switch_state() GPIO_ReadOutputDataBit(RS485_CTRL_PIN_PORT, RS485_CTRL_PIN)
|
||||
|
||||
/********************define 485 in pin*******************************/
|
||||
#define RS485_EXTIN_PIN GPIO_Pin_6
|
||||
#define RS485_EXTIN_PORT GPIOA
|
||||
#define RS485_EXTIN_CLK RCC_APB2Periph_GPIOA
|
||||
#define RS485_in_state() GPIO_ReadInputDataBit(RS485_EXTIN_PORT, RS485_EXTIN_PIN)
|
||||
|
||||
/********************define MBUS overload *******************************/
|
||||
#define RS485_OVERLOAD_PIN GPIO_Pin_7
|
||||
#define RS485_OVERLOAD_PORT GPIOA
|
||||
#define RS485_OVERLOAD_CLK RCC_APB2Periph_GPIOA
|
||||
#define RS485_OVERLOAD_in_state() GPIO_ReadInputDataBit(RS485_OVERLOAD_PORT, RS485_OVERLOAD_PIN)
|
||||
|
||||
|
||||
|
||||
#define RS485_OVERLOAD_FLAG_PORT_SOURCE GPIO_PortSourceGPIOA
|
||||
#define RS485_OVERLOAD_FLAG_PIN_SOURCE GPIO_PinSource7
|
||||
#define RS485_OVERLOAD_FLAG_LINE EXTI_Line7
|
||||
#define RS485_OVERLOAD_IRQn EXTI9_5_IRQn
|
||||
|
||||
#define RS485_OVERLOAD_FLAG_IRQHandler EXTI9_5_IRQHandler
|
||||
|
||||
|
||||
/********************define PLC reset pin*******************************/
|
||||
#define PLC_RESET_PIN GPIO_Pin_0
|
||||
#define PLC_RESET_PIN_PORT GPIOB
|
||||
#define PLC_RESET_PIN_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define PLC_RESET_HIGH() GPIO_SetBits(PLC_RESET_PIN_PORT, PLC_RESET_PIN)
|
||||
#define PLC_RESET_LOW() GPIO_ResetBits(PLC_RESET_PIN_PORT, PLC_RESET_PIN)
|
||||
|
||||
/********************define overload current pin*******************************/
|
||||
#define MUT_RESET_PIN GPIO_Pin_14
|
||||
#define MUT_RESET_PIN_PORT GPIOB
|
||||
#define MUT_RESET_PIN_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define MUT_RESET_HIGH() GPIO_SetBits(PLC_RESET_PIN_PORT, PLC_RESET_PIN)
|
||||
#define MUT_RESET_LOW() GPIO_ResetBits(PLC_RESET_PIN_PORT, PLC_RESET_PIN)
|
||||
|
||||
|
||||
//#define IRDA_TPIN_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_0, GPIO_Mode_AF_OD} //PA0
|
||||
//#define IRDA_RPIN_CFG {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_1, GPIO_Mode_IPU} //PC1
|
||||
//#define RF_DOWN_TPIN_CFG {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_12, GPIO_Mode_IN_FLOATING} //PC12
|
||||
//#define RF_DOWN_RPIN_CFG {GPIOD, RCC_APB2Periph_GPIOD, GPIO_Pin_2, GPIO_Mode_IN_FLOATING} //PD2
|
||||
//#define RS485_UP_TPIN_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_4, GPIO_Mode_IN_FLOATING} //PA4
|
||||
//#define RS485_UP_RPIN_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_5, GPIO_Mode_IN_FLOATING} //PA5
|
||||
|
||||
|
||||
#define PLC_RESET_CFG {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_0, GPIO_Mode_Out_OD} //PB0
|
||||
|
||||
#define MBUS_SWITCH_CFG {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_1, GPIO_Mode_IN_FLOATING} //PB1
|
||||
#define MBUS_EXT_CFG {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_4, GPIO_Mode_IN_FLOATING} //PC4
|
||||
#define MBUS_OVERLOAD_CFG {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_12, GPIO_Mode_IN_FLOATING} //PB12
|
||||
|
||||
#define RS485_CTRL_CFG {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_5, GPIO_Mode_IN_FLOATING} //PC5
|
||||
#define RS485_OVERLOAD_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_7, GPIO_Mode_IN_FLOATING} //PA7
|
||||
#define RS485_EXT_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_6, GPIO_Mode_IN_FLOATING} //PA6
|
||||
|
||||
#define MBUS_POW_LEVEL_CFG {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_13, GPIO_Mode_IN_FLOATING} //PB13
|
||||
|
||||
|
||||
#define OFF_KEY 0xAA
|
||||
#define ON_KEY 0x55
|
||||
|
||||
|
||||
|
||||
extern void add_one_list_node(st_params* params);
|
||||
extern void COM_frozen_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern void COM_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern u16 create_queue_send_packet(u8 * buf, u16 length);
|
||||
extern void DLT645_07_addr_ack(u8 *buf);
|
||||
extern void DLT645_97_1F_addr_ack(u8 *buf);
|
||||
extern void E5E5_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern u8 get_protocl_inRAM(void);
|
||||
extern bool get_readMeter_params(u8 *buf, st_params * ptr);
|
||||
extern bool get_read_meter_packet(u16 meter_protcl, u8 type, u8 *meter_id, u8 *outBuf, u16 *outLen);
|
||||
extern void hal_InitCOM(struct st_uart_port * port);
|
||||
extern void hal_UartDMATx(struct st_uart_port* uart_port, u8 *pBuf, u16 length);
|
||||
//extern void hal_UartIntTx(u8 *pBuf, u16 length);
|
||||
extern void init_uart_port(struct st_uart_port * port);
|
||||
extern void init_uart_tasks(void);
|
||||
extern void led_process_task(void * ptr);
|
||||
extern void mbus_gpio_init(void);
|
||||
extern void MBUS_master_process_task(void * ptr);
|
||||
extern void MBUS_mater_Tx(u8 *pBuf, u16 length);
|
||||
extern void MBUS_OVERLOAD_FLAG_IRQHandler(void);
|
||||
extern void MBUS_slave_process_task(void *ptr);
|
||||
extern void mbus_switch_timeOut_callback_function(TimerHandle_t xTimer);
|
||||
extern bool meter_ack_packet_process(u16 meter_protl, u8 *inbuf, u16 inLen, st_params * ptr, u8* outBuf);
|
||||
extern void PLC_process_task(void *ptr);
|
||||
extern void plc_uart_Tx(u8 *buf, u16 length);
|
||||
extern void port_send(struct st_uart_port* port, u8 *buf, u16 length);
|
||||
extern bool read_meter_process(u8 meter_protcl);
|
||||
extern bool read_power_level(void);
|
||||
extern void read_standard_elcMeter(u8 *buf, u8 length);
|
||||
extern void saved_meter_process(bool success, struct st_meter_temp_value *saved_ptr, st_params * ptr);
|
||||
extern void set_curent_protocl(u8 config,u8 MBUSpower);
|
||||
extern void set_mbus_master_params(u32 baud, u16 check);
|
||||
extern void set_PLC_UART_baud(u32 baud);
|
||||
extern void set_port_prams(u16 meter_protcl);
|
||||
extern void set_power_level(bool high);
|
||||
extern void simulate_mbus_plc_rx(u8 *buf, u16 len);
|
||||
extern void temp_saved_task(void *ptr);
|
||||
extern void UART5_IRQHandler(void);
|
||||
extern void uarts_process_task(void * ptr);
|
||||
extern void uart_dma_tx_callback(struct st_uart_port* uartPort);
|
||||
extern void uart_int_rx_frame(struct st_uart_port* uartPort);
|
||||
extern void uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern void uplink_ack_send(u8 uplink, u8 *buf, u16 length);
|
||||
extern void WHSF_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern void auto_sync_list_meters(void);
|
||||
extern void RS485_gpio_init(void);
|
||||
void RS4852_SendDataPacket(u8 *buf, u16 length);
|
||||
void up_485_Tx(u8 *buf, u16 length);
|
||||
void AnalogUartInit(struct st_uart_port * port);
|
||||
void RS485DataRequenstReady( void );
|
||||
bool ReadRS232ConcentratorDate(u8* year,u8* month);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,588 @@
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hal_uart.h
|
||||
* @author William Liang
|
||||
* @version V1.0.0
|
||||
* @date 07/22/2013
|
||||
* @brief This file contains the headers of the uart handlers.
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef _UART_H_
|
||||
#define _UART_H_
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include "include.h"
|
||||
#include "protocol.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define USART_BUF_SIXE 255
|
||||
|
||||
//define COM MBUS master infomation
|
||||
#define COM_MBUS_MASTER_NO USART1
|
||||
#define COM_MBUS_MASTER_BAUD 2400
|
||||
#define COM_MBUS_MASTER_CHECK USART_Parity_Even
|
||||
#define COM_MBUS_MASTER_CLK RCC_APB2Periph_USART1
|
||||
|
||||
#define COM_MBUS_MASTER_TX_PIN GPIO_Pin_9
|
||||
#define COM_MBUS_MASTER_TX_PORT GPIOA
|
||||
#define COM_MBUS_MASTER_TX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_MBUS_MASTER_RX_PIN GPIO_Pin_10
|
||||
#define COM_MBUS_MASTER_RX_PORT GPIOA
|
||||
#define COM_MBUS_MASTER_RX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_MBUS_MASTER_IRQn USART1_IRQn
|
||||
|
||||
#define COM_MBUS_MASTER_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
#define COM_MBUS_MASTER_TX_DMA_CHANNEL DMA1_Channel4
|
||||
#define COM_MBUS_MASTER_DR_BASE (USART1_BASE + 4)
|
||||
#define COM_MBUS_MASTER_TX_IRQHandler DMA1_Channel4_IRQHandler
|
||||
#define COM_MBUS_MASTER_RX_IRQHandler USART1_IRQHandler
|
||||
#define COM_MBUS_MASTER_TX_DMA_COMPLETE DMA1_IT_TC4
|
||||
#define COM_MBUS_MASTER_TX_DMA_ERROR DMA1_IT_TE4
|
||||
#define COM_MBUS_MASTER_DMA_IRQn DMA1_Channel4_IRQn
|
||||
|
||||
#define COM_MBUS_MASTER_TX_BUFFER_SIZE 200
|
||||
#define COM_MBUS_MASTER_RX_BUFFER_SIZE 255
|
||||
#define COM_MBUS_MASTER_STR "MBUS master"
|
||||
|
||||
|
||||
//define COM LORA moudule infomation
|
||||
#define COM_RADIO_NO UART5
|
||||
#define COM_RADIO_BAUD 9600 //8,e,1
|
||||
#define COM_RADIO_CHECK USART_Parity_Even
|
||||
#define COM_RADIO_CLK RCC_APB1Periph_UART5
|
||||
|
||||
#define COM_RADIO_TX_PIN GPIO_Pin_12
|
||||
#define COM_RADIO_TX_PORT GPIOC
|
||||
#define COM_RADIO_TX_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define COM_RADIO_RX_PIN GPIO_Pin_2
|
||||
#define COM_RADIO_RX_PORT GPIOD
|
||||
#define COM_RADIO_RX_PORT_CLK RCC_APB2Periph_GPIOD
|
||||
|
||||
#define COM_RADIO_IRQn UART5_IRQn
|
||||
|
||||
#define COM_RADIO_DMA_CLK 0
|
||||
|
||||
#define COM_RADIO_TX_DMA_CHANNEL 0
|
||||
#define COM_RADIO_DR_BASE 0
|
||||
#define COM_RADIO_TX_IRQHandler 0
|
||||
#define COM_RADIO_RX_IRQHandler 0
|
||||
#define COM_RADIO_TX_DMA_COMPLETE 0
|
||||
#define COM_RADIO_TX_DMA_ERROR 0
|
||||
#define COM_RADIO_DMA_IRQn 0
|
||||
|
||||
|
||||
#define COM_RADIO_TX_BUFFER_SIZE 255
|
||||
#define COM_RADIO_RX_BUFFER_SIZE 255
|
||||
#define COM_RADIO_STR "radio"
|
||||
|
||||
|
||||
|
||||
//define COM PLC module infomation
|
||||
#define COM_PLC_NO USART3
|
||||
#define COM_PLC_BAUD 2400
|
||||
#define COM_PLC_CHECK USART_Parity_Even
|
||||
#define COM_PLC_CLK RCC_APB1Periph_USART3
|
||||
|
||||
#define COM_PLC_TX_PIN GPIO_Pin_10
|
||||
#define COM_PLC_TX_PORT GPIOB
|
||||
#define COM_PLC_TX_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define COM_PLC_RX_PIN GPIO_Pin_11
|
||||
#define COM_PLC_RX_PORT GPIOA
|
||||
#define COM_PLC_RX_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define COM_PLC_IRQn USART3_IRQn
|
||||
|
||||
#define COM_PLC_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
#define COM_PLC_TX_DMA_CHANNEL DMA1_Channel2
|
||||
#define COM_PLC_DR_BASE (USART3_BASE + 4)
|
||||
#define COM_PLC_TX_IRQHandler DMA1_Channel2_IRQHandler
|
||||
#define COM_PLC_RX_IRQHandler USART3_IRQHandler
|
||||
#define COM_PLC_TX_DMA_COMPLETE DMA1_IT_TC2
|
||||
#define COM_PLC_TX_DMA_ERROR DMA1_IT_TE2
|
||||
#define COM_PLC_DMA_IRQn DMA1_Channel2_IRQn
|
||||
|
||||
#define COM_PLC_TX_BUFFER_SIZE 255
|
||||
#define COM_PLC_RX_BUFFER_SIZE 255
|
||||
#define COM_PLC_STR "PLC"
|
||||
|
||||
|
||||
//define COM LORA moudule infomation
|
||||
#define COM_485_NO USART2
|
||||
#define COM_485_BAUD 2400 //8,e,1
|
||||
#define COM_485_CHECK USART_Parity_Even
|
||||
#define COM_485_CLK RCC_APB1Periph_USART2
|
||||
|
||||
#define COM_485_TX_PIN GPIO_Pin_2
|
||||
#define COM_485_TX_PORT GPIOA
|
||||
#define COM_485_TX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_485_RX_PIN GPIO_Pin_3
|
||||
#define COM_485_RX_PORT GPIOA
|
||||
#define COM_485_RX_PORT_CLK RCC_APB2Periph_GPIOA
|
||||
|
||||
#define COM_485_IRQn USART2_IRQn
|
||||
|
||||
#define COM_485_DMA_CLK RCC_AHBPeriph_DMA1
|
||||
#define COM_485_TX_DMA_CHANNEL DMA1_Channel7
|
||||
#define COM_485_DR_BASE (USART2_BASE + 4)
|
||||
#define COM_485_TX_IRQHandler DMA1_Channel7_IRQHandler
|
||||
#define COM_485_RX_IRQHandler USART2_IRQHandler
|
||||
#define COM_485_TX_DMA_COMPLETE DMA1_IT_TC7
|
||||
#define COM_485_TX_DMA_ERROR DMA1_IT_TE7
|
||||
#define COM_485_DMA_IRQn DMA1_Channel7_IRQn
|
||||
|
||||
#define COM_485_TX_BUFFER_SIZE 255
|
||||
#define COM_485_RX_BUFFER_SIZE 255
|
||||
#define COM_485_STR "485"
|
||||
|
||||
/*
|
||||
//define COM module end
|
||||
#define MBUS_OVERLOAD_FLAG_PIN GPIO_Pin_3
|
||||
#define MBUS_OVERLOAD_FLAG_PIN_PORT GPIOC
|
||||
#define MBUS_OVERLOAD_FLAG_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
|
||||
#define MBUS_OVERLOAD_FLAG_PORT_SOURCE GPIO_PortSourceGPIOC
|
||||
#define MBUS_OVERLOAD_FLAG_PIN_SOURCE GPIO_PinSource3
|
||||
#define MBUS_OVERLOAD_FLAG_LINE EXTI_Line3
|
||||
#define MBUS_OVERLOAD_FLAG_IRQHandler EXTI3_IRQHandler
|
||||
*/
|
||||
|
||||
|
||||
#define MBUSM_BAUD_COFF (11 * 1000 / COM_MBUS_MASTER_BAUD)
|
||||
#define PLC_BAUD_COFF (11 * 1000 / COM_PLC_BAUD)
|
||||
#define RS485_BAUD_COFF (11 * 1000 / COM_485_BAUD)
|
||||
#define PRINT_BAUD_COFF (11 * 1000 / COM_DEBUG_BAUD)
|
||||
|
||||
|
||||
#define MBUS_SWITCH_TIMEOUT (10000 /portTICK_RATE_MS)
|
||||
#define PORT_RX_TIMEOUT (15 /portTICK_RATE_MS)//设置串口的超时接收时间,此值需设置为最低波特率的最少两个字节时间
|
||||
#define SCAN_PORT_RERIOD (5 /portTICK_RATE_MS)//扫描串口超时的周期
|
||||
|
||||
#define MBUS_TIMEOUT (1200 /portTICK_RATE_MS)
|
||||
#define CS485_TIMEOUT (2000 /portTICK_RATE_MS)
|
||||
#define PLC_TIMEOUT (2500 /portTICK_RATE_MS)
|
||||
#define XIMEI_TIMEOUT (10000 /portTICK_RATE_MS)
|
||||
#define MUT_TIMEOUT (2000 /portTICK_RATE_MS)
|
||||
|
||||
#define OPEN_SWITCN_DELAY (2000 /portTICK_RATE_MS)
|
||||
#define DELAY_HOUR_TIME (3600000 /portTICK_RATE_MS)
|
||||
#define DELAY_MIN_TIME (60000 /portTICK_RATE_MS)
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USART_TypeDef * com;
|
||||
USART_InitTypeDef uart_param;
|
||||
uint32_t com_clk;
|
||||
uint16_t com_tx_pin;
|
||||
GPIO_TypeDef * com_tx_port;
|
||||
uint32_t com_tx_port_clk;
|
||||
uint16_t com_rx_pin;
|
||||
GPIO_TypeDef * com_rx_port;
|
||||
uint32_t xom_rx_port_clk;
|
||||
uint32_t com_DMA_CLK;
|
||||
uint8_t com_IRQn;
|
||||
uint8_t com_DMA_IRQn;
|
||||
}st_uart_int;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USART_TypeDef * com;
|
||||
DMA_Channel_TypeDef * com_TX_DMA_CHANNEL;
|
||||
uint32_t com_DR_BASE;
|
||||
u16 txbufLength;
|
||||
}st_uart_channel_cfg;
|
||||
|
||||
#define COMM_BUF_SIZE 300
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 *rxBuf;
|
||||
u8 *txBuf;
|
||||
u16 rx_index;
|
||||
u16 rx_len;
|
||||
u32 rx_timeout;
|
||||
u32 tx_timeout;
|
||||
}st_uart_buf_cfg;
|
||||
|
||||
|
||||
struct st_uart_port
|
||||
{
|
||||
EventBits_t port_No;
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
st_uart_int init;
|
||||
st_uart_channel_cfg chl;
|
||||
st_uart_buf_cfg data;
|
||||
char * string;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#define DEFAULT_USART_CFG(baud, check) { baud,USART_WordLength_9b,USART_StopBits_1,\
|
||||
check, (USART_Mode_Rx | USART_Mode_Tx),\
|
||||
USART_HardwareFlowControl_None\
|
||||
}
|
||||
|
||||
|
||||
#define USART_INIT(name) { name##_NO,\
|
||||
DEFAULT_USART_CFG(name##_BAUD, name##_CHECK),\
|
||||
name##_CLK,name##_TX_PIN,\
|
||||
name##_TX_PORT,name##_TX_PORT_CLK,\
|
||||
name##_RX_PIN,\
|
||||
name##_RX_PORT,\
|
||||
name##_RX_PORT_CLK,\
|
||||
name##_DMA_CLK,\
|
||||
name##_IRQn,\
|
||||
name##_DMA_IRQn\
|
||||
}
|
||||
|
||||
#define USART_DMA_config(name) {name##_NO, name##_TX_DMA_CHANNEL, (uint32_t)name##_DR_BASE, name##_TX_BUFFER_SIZE}
|
||||
|
||||
#define USART_PORT_PARAMS(name, rxbuf, txbuf) {name##_PORT_NO, NULL, USART_INIT(name),USART_DMA_config(name),{rxbuf,txbuf,0,0,0,0}, name##_STR}
|
||||
|
||||
|
||||
#define USART_RX_INT_HANDLE(name) void name##_RX_IRQHandler(void) \
|
||||
{ \
|
||||
if (USART_GetITStatus(name##_NO, USART_IT_RXNE) != RESET) \
|
||||
{ \
|
||||
uart_int_rx_frame(&(name##_port)); \
|
||||
} \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
#define USART_TX_INT_HANDLE(name) void name##_TX_IRQHandler(void) \
|
||||
{ \
|
||||
if (DMA_GetITStatus(name##_TX_DMA_COMPLETE) != RESET) \
|
||||
{ \
|
||||
DMA_ClearITPendingBit(name##_TX_DMA_COMPLETE); \
|
||||
uart_dma_tx_callback(&(name##_port)); \
|
||||
} \
|
||||
if (DMA_GetITStatus(name##_TX_DMA_ERROR) != RESET) \
|
||||
{ \
|
||||
DMA_ClearITPendingBit(name##_TX_DMA_ERROR); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define create_uart_port(name, rxbuf, txbuf) struct st_uart_port name##_port = USART_PORT_PARAMS(name, rxbuf, txbuf);\
|
||||
USART_TX_INT_HANDLE(name) \
|
||||
USART_RX_INT_HANDLE(name) \
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
UP_VER_OF_COMMON = 0,
|
||||
UP_VER_OF_WHSF,
|
||||
UP_VER_OF_E5E50000,
|
||||
UP_VER_OF_E5E50001,
|
||||
UP_VER_OF_FJWGDATA,
|
||||
UP_VER_OF_standard,
|
||||
UP_VER_OF_MAX
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PORT_NONE = 0,
|
||||
PORT_MBUS_MASTER,
|
||||
PORT_RADIO,
|
||||
PORT_PLC,
|
||||
PORT_485,
|
||||
PORT_MUT,
|
||||
POET_DEBUG,
|
||||
PORT_MAX,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
COM_MBUS_MASTER_PORT_NO = (1UL << PORT_MBUS_MASTER),
|
||||
COM_RADIO_PORT_NO = (1UL << PORT_RADIO),
|
||||
COM_PLC_PORT_NO = (1UL << PORT_PLC),
|
||||
COM_485_PORT_NO = (1UL << PORT_485),
|
||||
COM_MUT_PORT_NO = (1UL << PORT_MUT),
|
||||
COM_DEBUG_PORT_NO = (1UL << POET_DEBUG),
|
||||
PORT_AUTO = (COM_MBUS_MASTER_PORT_NO | COM_485_PORT_NO | COM_MUT_PORT_NO)
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROTCL_AUTO = 0,
|
||||
PROTCL_E5E50000,
|
||||
MBUS_METER_START,
|
||||
MBUS_901F_2400_E,
|
||||
MBUS_1F90_2400_E,
|
||||
MBUS_HHCQ_2400_N,
|
||||
MBUS_YZSJ_1200_E,
|
||||
MBUS_HZJD_1200_E,
|
||||
MBUS_METER_MAX,
|
||||
RS485_METER_START,
|
||||
RS485_NJSM_1200_N,
|
||||
RS485_CS485_2400_E,
|
||||
RS485_METER_MAX,
|
||||
MUT_METER_START,
|
||||
//MUT_CQXM_LORA,
|
||||
MUT_SPI_LORA,
|
||||
MUT_METER_MAX,
|
||||
};
|
||||
|
||||
/* Baud( bps): 0~7 依次表示:
|
||||
自适应, 1200, 2400, 4800, 9600, 19200,
|
||||
38400, 57600 */
|
||||
enum
|
||||
{
|
||||
BAUD_auto = 0,
|
||||
BAUD_1200,
|
||||
BAUD_2400,
|
||||
BAUD_4800,
|
||||
BAUD_9600,
|
||||
BAUD_19200,
|
||||
BAUD_38400,
|
||||
BAUD_57600,
|
||||
};
|
||||
|
||||
|
||||
/* 0/1:
|
||||
1/2 停止位 */
|
||||
enum
|
||||
{
|
||||
STOP_1bits = 0,
|
||||
STOP_2bits,
|
||||
};
|
||||
|
||||
|
||||
/* 0/1:
|
||||
无/有校验 */
|
||||
|
||||
enum
|
||||
{
|
||||
PARITY_NONE = 0,
|
||||
PARITY_TRUE,
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* 0/1:
|
||||
偶/奇校验 */
|
||||
enum
|
||||
{
|
||||
PARITY_EVEN = 0,
|
||||
PARITY_ODD,
|
||||
};
|
||||
|
||||
/* 0~3:
|
||||
5-8 位数 */
|
||||
enum
|
||||
{
|
||||
DATABITS_5 = 0,
|
||||
DATABITS_6,
|
||||
DATABITS_7,
|
||||
DATABITS_8,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
UP_PORT_PLC,
|
||||
UP_PORT_485,
|
||||
UP_PORT_MAX,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
|
||||
MBUS_MODE_MASTER = 0,
|
||||
MBUS_MODE_SLAVE,
|
||||
};
|
||||
|
||||
/********************define MBUS power contrl pin******************************/
|
||||
#define MBUS_POWER_CTRL_PIN GPIO_Pin_1
|
||||
#define MBUS_POWER_CTRL_PIN_PORT GPIOB
|
||||
#define MBUS_POWER_CTRL_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
#define open_mbus_switch() GPIO_ResetBits(MBUS_POWER_CTRL_PIN_PORT, MBUS_POWER_CTRL_PIN)
|
||||
#define close_mbus_switch() GPIO_SetBits(MBUS_POWER_CTRL_PIN_PORT, MBUS_POWER_CTRL_PIN)
|
||||
#define mbus_switch_state() GPIO_ReadOutputDataBit(MBUS_POWER_CTRL_PIN_PORT, MBUS_POWER_CTRL_PIN)
|
||||
|
||||
/********************define MBUS in pin*******************************/
|
||||
#define MBUS_EXTIN_PIN GPIO_Pin_4
|
||||
#define MBUS_EXTIN_PORT GPIOC
|
||||
#define MBUS_EXTIN_CLK RCC_APB2Periph_GPIOC
|
||||
#define MBUS_in_state() GPIO_ReadInputDataBit(MBUS_EXTIN_PORT, MBUS_EXTIN_PIN)
|
||||
|
||||
#define MBUS_EXT_FLAG_PORT_SOURCE GPIO_PortSourceGPIOC
|
||||
#define MBUS_EXT_FLAG_PIN_SOURCE GPIO_PinSource4
|
||||
#define MBUS_EXT_FLAG_LINE EXTI_Line4
|
||||
#define MBUS_EXT_IRQHandler EXTI4_IRQHandler
|
||||
|
||||
|
||||
/********************define MBUS overload *******************************/
|
||||
#define MBUS_OVERLOAD_PIN GPIO_Pin_12
|
||||
#define MBUS_OVERLOAD_PORT GPIOB
|
||||
#define MBUS_OVERLOAD_CLK RCC_APB2Periph_GPIOB
|
||||
#define MBUS_OVERLOAD_in_state() GPIO_ReadInputDataBit(MBUS_OVERLOAD_PORT, MBUS_OVERLOAD_PIN)
|
||||
|
||||
#define MBUS_OVERLOAD_FLAG_PORT_SOURCE GPIO_PortSourceGPIOB
|
||||
#define MBUS_OVERLOAD_FLAG_PIN_SOURCE GPIO_PinSource12
|
||||
#define MBUS_OVERLOAD_FLAG_LINE EXTI_Line12
|
||||
#define MBUS_OVERLOAD_FLAG_IRQHandler EXTI15_10_IRQHandler
|
||||
|
||||
|
||||
/********************define power level pin*******************************/
|
||||
#define POWER_LEVEL_PIN GPIO_Pin_13
|
||||
#define POWER_LEVEL_PORT GPIOB
|
||||
#define POWER_LEVEL_PORT_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define SET_POWER_LEVEL_HIGH() GPIO_SetBits(POWER_LEVEL_PORT, POWER_LEVEL_PIN);
|
||||
#define SET_POWER_LEVEL_LOW() GPIO_ResetBits(POWER_LEVEL_PORT, POWER_LEVEL_PIN);
|
||||
#define power_level_state() GPIO_ReadOutputDataBit(POWER_LEVEL_PORT, POWER_LEVEL_PIN)
|
||||
|
||||
|
||||
|
||||
/********************define 485 power contrl pin******************************/
|
||||
#define RS485_CTRL_PIN GPIO_Pin_5
|
||||
#define RS485_CTRL_PIN_PORT GPIOC
|
||||
#define RS485_CTRL_PORT_CLK RCC_APB2Periph_GPIOC
|
||||
#define open_RS485_switch() GPIO_ResetBits(RS485_CTRL_PIN_PORT, RS485_CTRL_PIN);hal_sRF_ITConfig(RS485_OVERLOAD_FLAG_LINE, ENABLE)
|
||||
|
||||
|
||||
#define close_RS485_switch() GPIO_SetBits(RS485_CTRL_PIN_PORT, RS485_CTRL_PIN); hal_sRF_ITConfig(RS485_OVERLOAD_FLAG_LINE, DISABLE)
|
||||
|
||||
|
||||
|
||||
#define RS485_switch_state() GPIO_ReadOutputDataBit(RS485_CTRL_PIN_PORT, RS485_CTRL_PIN)
|
||||
|
||||
/********************define 485 in pin*******************************/
|
||||
#define RS485_EXTIN_PIN GPIO_Pin_6
|
||||
#define RS485_EXTIN_PORT GPIOA
|
||||
#define RS485_EXTIN_CLK RCC_APB2Periph_GPIOA
|
||||
#define RS485_in_state() GPIO_ReadOutputDataBit(RS485_EXTIN_PORT, RS485_EXTIN_PIN)
|
||||
|
||||
/********************define MBUS overload *******************************/
|
||||
#define RS485_OVERLOAD_PIN GPIO_Pin_7
|
||||
#define RS485_OVERLOAD_PORT GPIOA
|
||||
#define RS485_OVERLOAD_CLK RCC_APB2Periph_GPIOA
|
||||
#define RS485_OVERLOAD_in_state() GPIO_ReadOutputDataBit(RS485_OVERLOAD_PORT, RS485_OVERLOAD_PIN)
|
||||
|
||||
|
||||
|
||||
#define RS485_OVERLOAD_FLAG_PORT_SOURCE GPIO_PortSourceGPIOA
|
||||
#define RS485_OVERLOAD_FLAG_PIN_SOURCE GPIO_PinSource7
|
||||
#define RS485_OVERLOAD_FLAG_LINE EXTI_Line7
|
||||
#define RS485_OVERLOAD_IRQn EXTI9_5_IRQn
|
||||
|
||||
#define RS485_OVERLOAD_FLAG_IRQHandler EXTI9_5_IRQHandler
|
||||
|
||||
|
||||
/********************define PLC reset pin*******************************/
|
||||
#define PLC_RESET_PIN GPIO_Pin_0
|
||||
#define PLC_RESET_PIN_PORT GPIOB
|
||||
#define PLC_RESET_PIN_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define PLC_RESET_HIGH() GPIO_SetBits(PLC_RESET_PIN_PORT, PLC_RESET_PIN)
|
||||
#define PLC_RESET_LOW() GPIO_ResetBits(PLC_RESET_PIN_PORT, PLC_RESET_PIN)
|
||||
|
||||
/********************define overload current pin*******************************/
|
||||
#define MUT_RESET_PIN GPIO_Pin_14
|
||||
#define MUT_RESET_PIN_PORT GPIOB
|
||||
#define MUT_RESET_PIN_CLK RCC_APB2Periph_GPIOB
|
||||
|
||||
#define MUT_RESET_HIGH() GPIO_SetBits(PLC_RESET_PIN_PORT, PLC_RESET_PIN)
|
||||
#define MUT_RESET_LOW() GPIO_ResetBits(PLC_RESET_PIN_PORT, PLC_RESET_PIN)
|
||||
|
||||
|
||||
#define IRDA_TPIN_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_0, GPIO_Mode_IN_FLOATING} //PA0
|
||||
#define IRDA_RPIN_CFG {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_1, GPIO_Mode_IN_FLOATING} //PC1
|
||||
#define RF_DOWN_TPIN_CFG {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_12, GPIO_Mode_IN_FLOATING} //PC12
|
||||
#define RF_DOWN_RPIN_CFG {GPIOD, RCC_APB2Periph_GPIOD, GPIO_Pin_2, GPIO_Mode_IN_FLOATING} //PD2
|
||||
#define RS485_UP_TPIN_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_4, GPIO_Mode_IN_FLOATING} //PA4
|
||||
#define RS485_UP_RPIN_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_5, GPIO_Mode_IN_FLOATING} //PA5
|
||||
|
||||
|
||||
#define PLC_RESET_CFG {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_0, GPIO_Mode_IPU} //PB0
|
||||
|
||||
#define MBUS_SWITCH_CFG {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_1, GPIO_Mode_IN_FLOATING} //PB1
|
||||
#define MBUS_EXT_CFG {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_4, GPIO_Mode_IN_FLOATING} //PC4
|
||||
#define MBUS_OVERLOAD_CFG {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_12, GPIO_Mode_IN_FLOATING} //PB12
|
||||
|
||||
#define RS485_CTRL_CFG {GPIOC, RCC_APB2Periph_GPIOC, GPIO_Pin_5, GPIO_Mode_IN_FLOATING} //PC5
|
||||
#define RS485_OVERLOAD_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_7, GPIO_Mode_IN_FLOATING} //PA7
|
||||
#define RS485_EXT_CFG {GPIOA, RCC_APB2Periph_GPIOA, GPIO_Pin_6, GPIO_Mode_IN_FLOATING} //PA6
|
||||
|
||||
#define MBUS_POW_LEVEL_CFG {GPIOB, RCC_APB2Periph_GPIOB, GPIO_Pin_13, GPIO_Mode_IN_FLOATING} //PB13
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern void add_one_list_node(st_params* params);
|
||||
extern void COM_frozen_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern void COM_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern u16 create_queue_send_packet(u8 * buf, u16 length);
|
||||
extern void DLT645_07_addr_ack(u8 *buf);
|
||||
extern void DLT645_97_1F_addr_ack(u8 *buf);
|
||||
extern void E5E5_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern u8 get_protocl_inRAM(void);
|
||||
extern bool get_readMeter_params(u8 *buf, st_params * ptr);
|
||||
extern bool get_read_meter_packet(u16 meter_protcl, u8 type, u8 *meter_id, u8 *outBuf, u16 *outLen);
|
||||
extern void hal_InitCOM(struct st_uart_port * port);
|
||||
extern void hal_UartDMATx(struct st_uart_port* uart_port, u8 *pBuf, u16 length);
|
||||
//extern void hal_UartIntTx(u8 *pBuf, u16 length);
|
||||
extern void init_uart_port(struct st_uart_port * port);
|
||||
extern void init_uart_tasks(void);
|
||||
extern void led_process_task(void * ptr);
|
||||
extern void mbus_gpio_init(void);
|
||||
extern void MBUS_master_process_task(void * ptr);
|
||||
extern void MBUS_mater_Tx(u8 *pBuf, u16 length);
|
||||
extern void MBUS_OVERLOAD_FLAG_IRQHandler(void);
|
||||
extern void MBUS_slave_process_task(void *ptr);
|
||||
extern void mbus_switch_timeOut_callback_function(TimerHandle_t xTimer);
|
||||
extern bool meter_ack_packet_process(u16 meter_protl, u8 *inbuf, u8 inLen, st_params * ptr, u8* outBuf);
|
||||
extern void PLC_process_task(void *ptr);
|
||||
extern void plc_uart_Tx(u8 *buf, u16 length);
|
||||
extern void port_send(struct st_uart_port* port, u8 *buf, u16 length);
|
||||
extern bool read_meter_process(u8 meter_protcl, st_params *read_params, u8 *outbuf);
|
||||
extern bool read_power_level(void);
|
||||
extern void read_standard_elcMeter(u8 *buf, u8 length);
|
||||
extern void saved_meter_process(bool success, struct st_meter_temp_value *saved_ptr, st_params * ptr);
|
||||
extern void set_curent_protocl(u8 config);
|
||||
extern void set_mbus_master_params(u32 baud, u16 check);
|
||||
extern void set_PLC_UART_baud(u32 baud);
|
||||
extern void set_port_prams(u16 meter_protcl);
|
||||
extern void set_power_level(bool high);
|
||||
extern void simulate_mbus_plc_rx(u8 *buf, u8 len);
|
||||
extern void temp_saved_task(void *ptr);
|
||||
extern void UART5_IRQHandler(void);
|
||||
extern void uarts_process_task(void * ptr);
|
||||
extern void uart_dma_tx_callback(struct st_uart_port* uartPort);
|
||||
extern void uart_int_rx_frame(struct st_uart_port* uartPort);
|
||||
extern void uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern void uplink_ack_send(u8 uplink, u8 *buf, u16 length);
|
||||
extern void WHSF_uplinkPacket_create(st_params * ptr, u8* outBuf);
|
||||
extern void auto_sync_list_meters(void);
|
||||
extern void RS485_gpio_init(void);
|
||||
void RS4852_SendDataPacket(u8 *buf, u16 length);
|
||||
void up_485_Tx(u8 *buf, u16 length);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+916
@@ -0,0 +1,916 @@
|
||||
|
||||
/******************************************************************************************
|
||||
update Function
|
||||
STM32F103RCT6 256K flash 48K RAM
|
||||
flash : 0-15k API API : 0x0800,0000-0x0800,3FFF
|
||||
: 16-17, params : 0x0800,4000-0x0800,47FF
|
||||
: 18-19k key : 0x0800,4800-0x0800,4FFF
|
||||
: 20K - 137K app : 0x0800,5000-0x0802,27FF
|
||||
: 138K- 255K update app: 0x0802,2800-0x0803,FFFF
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 file_indication;
|
||||
u8 file_property;
|
||||
u8 file_instr;
|
||||
u16 total_packets;
|
||||
u32 current_packet_No;
|
||||
u16 packet_length;
|
||||
u8 * data;
|
||||
}st_update_packet;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UPDATE_END = 0,
|
||||
UPDATE_RUNNING,
|
||||
UPDATE_FINISH,
|
||||
UPDATE_SUCCESS,
|
||||
UPDATE_FAILED,
|
||||
UPDATE_SALVE,
|
||||
}EM_UPDATE_STATUS;
|
||||
|
||||
******************************************************************************/
|
||||
#include "apl.h"
|
||||
#include "update.h"
|
||||
#include "Flash.h"
|
||||
#include "uart.h"
|
||||
#include "Mem.h"
|
||||
#include "addr.h"
|
||||
#include "General.h"
|
||||
#include "MD5.h"
|
||||
#include "Led.h"
|
||||
|
||||
st_update_params st_update;
|
||||
static u8 packet_nnmber;
|
||||
extern const u16 CRC16_Table[];
|
||||
|
||||
static u8 g_update_ctrl = UPDATE_NONE;
|
||||
|
||||
static QueueHandle_t updateQueue;
|
||||
|
||||
#define UPDATE_BUF_LEN 255
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : write_update_ctrlner
|
||||
* Description : none
|
||||
* Input : u8 ctrlner
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void write_update_ctrlner(u8 ctrlner)
|
||||
{
|
||||
if (ctrlner < UPDATE_MAX)
|
||||
{
|
||||
g_update_ctrl = ctrlner;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : read_update_ctrlner
|
||||
* Description : none
|
||||
* Input : void
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
u8 read_update_ctrlner(void)
|
||||
{
|
||||
return g_update_ctrl;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : set_update_packetState
|
||||
* Description : none
|
||||
* Input : u16 packetNo
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void set_update_packetState(u16 packetNo)
|
||||
{
|
||||
st_update.packetsState[packetNo/8] |= (1<<(packetNo%8));
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : check_update_packect_state
|
||||
* Description : none
|
||||
* Input : u16 packetNo
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170314
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
bool check_update_packect_state(u16 packetNo)
|
||||
{
|
||||
if (st_update.packetsState[packetNo/8] & (1<<(packetNo%8)) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
check if all packet reserved
|
||||
*
|
||||
*****************************************************************************/
|
||||
bool check_update_state(u16 total_packets)
|
||||
{
|
||||
for (u16 j = 0; j < total_packets; j++)
|
||||
{
|
||||
if (check_update_packect_state(j) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
check if update data reserved right
|
||||
*
|
||||
*****************************************************************************/
|
||||
bool update_software_check(u32 totalBytes)
|
||||
{
|
||||
u16 temp;
|
||||
u16 crc16 = 0xFFFF;
|
||||
u32 count = totalBytes -2;
|
||||
u8 flash_temp;
|
||||
u32 current_flash_addr = FLASH_APP_BACK_ADDRESS;
|
||||
|
||||
if (totalBytes <= 2)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
//GDflash_read(current_flash_addr, &flash_temp, 1);
|
||||
flash_temp = *((u8*)current_flash_addr);
|
||||
|
||||
current_flash_addr++;
|
||||
crc16 = (crc16 >> 8 ) ^ CRC16_Table[(crc16 ^ flash_temp) & 0xFF];
|
||||
}
|
||||
crc16 ^= 0xFFFF;
|
||||
|
||||
|
||||
//GDflash_read(current_flash_addr, &flash_temp, 1);
|
||||
flash_temp = *((u8*)current_flash_addr);
|
||||
|
||||
current_flash_addr++;
|
||||
temp = (u16)flash_temp*256;
|
||||
|
||||
//GDflash_read(current_flash_addr, &flash_temp, 1);
|
||||
flash_temp = *((u8*)current_flash_addr);
|
||||
|
||||
current_flash_addr++;
|
||||
temp += flash_temp;
|
||||
|
||||
if (crc16 == temp)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
write update packet in flash
|
||||
*
|
||||
*****************************************************************************/
|
||||
void FLASH_Write_update_page(u16 packetNo, u8 * Data, u8 length)
|
||||
{
|
||||
u32 packet_start_addr = FLASH_APP_BACK_ADDRESS + packetNo * UPDATE_DEFAULT_PACKET_SIZE;
|
||||
u8 buf[128];
|
||||
MemCpy(buf, Data, length);
|
||||
|
||||
__disable_irq();
|
||||
STM32_FlashWrite(packet_start_addr, Data, length);
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
*
|
||||
read update params from flash
|
||||
*
|
||||
*********************************************************************************/
|
||||
bool read_update_flash(st_update_params *st_update_Structure)
|
||||
{
|
||||
memcpy(st_update_Structure, (u8*)FLASH_UPDATE_PARAMS_ADDRESS,sizeof(st_update_params));
|
||||
|
||||
if ( GetCRC16((u8*)st_update_Structure, sizeof(st_update_params) -2) == (st_update_Structure->crc) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
*
|
||||
write update params in flash
|
||||
*
|
||||
*********************************************************************************/
|
||||
void write_update_flash(st_update_params *st_update_Structure )
|
||||
{
|
||||
st_update_Structure->crc = GetCRC16((u8*)st_update_Structure, sizeof(st_update_params) - 2);
|
||||
|
||||
if (STM32_FlashPageErase(FLASH_UPDATE_PARAMS_ADDRESS) == FLH_SUCCESS)
|
||||
{
|
||||
STM32_FlashWrite( FLASH_UPDATE_PARAMS_ADDRESS, (u8*)st_update_Structure, sizeof(st_update_params));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
*
|
||||
*****************************************************************************/
|
||||
void reset_update_params(void)
|
||||
{
|
||||
memset(&st_update, 0 , sizeof(st_update));
|
||||
write_update_flash(&st_update);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void update_ack(u8 number, u32 current_packet_No, u8 ctrl, u8 ctrlner)
|
||||
{
|
||||
static st_AFN15_ack afn15ack;
|
||||
|
||||
afn15ack.head.start = 0x68;
|
||||
afn15ack.head.len = 0x13;
|
||||
afn15ack.head.ctrl = ctrl | 0xc0;
|
||||
|
||||
afn15ack.head.info_route = 0;
|
||||
afn15ack.head.info_slave = 0;
|
||||
afn15ack.head.info_com_module = 0;
|
||||
afn15ack.head.info_conflict = 0;
|
||||
afn15ack.head.info_relay = 0;
|
||||
|
||||
afn15ack.head.info[0] = 0;
|
||||
afn15ack.head.info[1] = 0;
|
||||
afn15ack.head.info[2] = 0;
|
||||
afn15ack.head.info[3] = 0;
|
||||
afn15ack.head.number = number;
|
||||
|
||||
afn15ack.afn = 0x15;
|
||||
afn15ack.dt1 = 0x01;
|
||||
afn15ack.dt2 = 0x00;
|
||||
|
||||
afn15ack.current_packet_No = current_packet_No;
|
||||
afn15ack.cs = GetSum((u8*)(&afn15ack)+ 3, 14);
|
||||
afn15ack.end = 0x16;
|
||||
|
||||
if (ctrlner == UPDATE_485)
|
||||
{
|
||||
debug_Tx( (u8*)&afn15ack, sizeof(st_AFN15_ack));
|
||||
}
|
||||
else
|
||||
{
|
||||
plc_uart_Tx( (u8*)&afn15ack, sizeof(st_AFN15_ack));
|
||||
}
|
||||
}
|
||||
|
||||
u16 get_DT(u8 DT1, u8 DT2)
|
||||
{
|
||||
u16 temp = 0;
|
||||
|
||||
for (u8 i = 0; i < 8; i++)
|
||||
{
|
||||
temp += ((DT1 >> i) & 0x01);
|
||||
}
|
||||
|
||||
if (temp != 1)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
temp = 0;
|
||||
|
||||
do{
|
||||
DT1 = DT1 >> 1;
|
||||
|
||||
if (DT1 == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
temp++;
|
||||
}while(1);
|
||||
|
||||
return (0xF1 + DT2*8 + temp);
|
||||
}
|
||||
|
||||
void decode_dt(u16 DT, u8 *dt1, u8 *dt2)
|
||||
{
|
||||
*dt2 = (DT - 0xF1)/ 8;
|
||||
*dt1 = (1 << (DT - 0xF1) % 8);
|
||||
}
|
||||
|
||||
void defaut_13762head_ack_write(st_13762_head * head, u8 length, bool com_module_exist, u8 ctrl)
|
||||
{
|
||||
head->start = 0x68;
|
||||
head->len = length;
|
||||
head->ctrl = ctrl | 0x80;
|
||||
head->info_route = 0;
|
||||
head->info_slave = 0;
|
||||
head->info_com_module = (u8)com_module_exist;
|
||||
head->info_conflict = 0;
|
||||
head->info_relay = 0;
|
||||
MemSet(head->info, 0, 4);
|
||||
head->number = packet_nnmber;
|
||||
}
|
||||
|
||||
|
||||
void apl_process_1372(u8 * ptr1372, u8 ctrlner)
|
||||
{
|
||||
static st_13762 temp_1372_frame;
|
||||
|
||||
static st_13762 *ptr_1372 = &temp_1372_frame;
|
||||
|
||||
static st_13762_03F1_ack ack_ptr_13762_03f1;
|
||||
|
||||
u8 *current_ptr = NULL;
|
||||
|
||||
u16 DT;
|
||||
|
||||
memcpy(ptr_1372, ptr1372, 10);
|
||||
|
||||
u16 length = temp_1372_frame.lenL + temp_1372_frame.lenH *256;
|
||||
|
||||
ptr_1372->cs = ptr1372[length - 2];
|
||||
ptr_1372->end = ptr1372[length - 1];
|
||||
|
||||
if ((ptr_1372->ctrl & 0x08) == 1)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
current_ptr = &ptr1372[10];
|
||||
|
||||
packet_nnmber = ptr_1372->number;
|
||||
|
||||
if (ptr_1372->info_com_module)
|
||||
{
|
||||
|
||||
ptr_1372->source_addr = current_ptr;
|
||||
|
||||
current_ptr += 6;
|
||||
|
||||
if (cmp_addr(ptr_1372->source_addr) == ADDR_NEQ)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptr_1372->info_relay)
|
||||
{
|
||||
ptr_1372->relay_addr = current_ptr;
|
||||
|
||||
current_ptr += ptr_1372->info_relay*6;
|
||||
}
|
||||
|
||||
ptr_1372->desc_addr = current_ptr;
|
||||
current_ptr += 6;
|
||||
}
|
||||
|
||||
ptr_1372->AFN = *current_ptr;
|
||||
ptr_1372->DT1 = *(current_ptr + 1);
|
||||
ptr_1372->DT2 = *(current_ptr + 2);
|
||||
current_ptr += 3;
|
||||
|
||||
DT = get_DT(ptr_1372->DT1, ptr_1372->DT2);
|
||||
|
||||
ptr_1372->data = current_ptr;
|
||||
|
||||
if (!(ptr_1372->info_com_module))
|
||||
{
|
||||
switch (ptr_1372->AFN)
|
||||
{
|
||||
case 0x03:
|
||||
if (DT == 0xF1)
|
||||
{
|
||||
if (ctrlner == UPDATE_PLC)
|
||||
{
|
||||
defaut_13762head_ack_write(&ack_ptr_13762_03f1.head, sizeof(st_13762_03F1_ack), FALSE, ptr_1372->ctrl);
|
||||
ack_ptr_13762_03f1.AFN = 0x03;
|
||||
ack_ptr_13762_03f1.DT1 = 0x01;
|
||||
ack_ptr_13762_03f1.DT2 = 0x00;
|
||||
MemCpy(ack_ptr_13762_03f1.Manu_code, (u8*)get_apl_version_ptr(), sizeof(Manufacturer_Version));
|
||||
ack_ptr_13762_03f1.cs = GetSum( (u8*)&ack_ptr_13762_03f1 + 3, sizeof(st_13762_03F1_ack) - 5);
|
||||
ack_ptr_13762_03f1.end = 0x16;
|
||||
plc_uart_Tx((u8*)&ack_ptr_13762_03f1, sizeof(st_13762_03F1_ack));
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 0x15:
|
||||
if (DT == 0xF1)
|
||||
{
|
||||
if (read_update_ctrlner() == UPDATE_NONE)
|
||||
{
|
||||
write_update_ctrlner(ctrlner);
|
||||
xQueueSendToBack( updateQueue, (u8*)ptr_1372->data, 10);
|
||||
}
|
||||
else if (read_update_ctrlner() == ctrlner)
|
||||
{
|
||||
xQueueSendToBack( updateQueue, (u8*)ptr_1372->data, 10);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool check_13762_packet(u8 *buf)
|
||||
{
|
||||
u8 len = buf[1] + buf[2]*256;
|
||||
|
||||
if ( (buf[0] == 0x68) && (buf[len -1] == 0x16) )
|
||||
{
|
||||
if (buf[len -2] == GetSum(buf + 3, len - 5))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void transparent_Proc(void)
|
||||
{
|
||||
//transparent xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
u8 *start_pos = NULL;
|
||||
// u8 transparent_cmd[] = "transparent 00 ";
|
||||
|
||||
start_pos = get_debugBuf() + sizeof("transparent 00 ") - 1;
|
||||
|
||||
if (check_13762_packet(start_pos))
|
||||
{
|
||||
apl_process_1372(start_pos, UPDATE_485);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t get_packets(uint32_t totalBytes )
|
||||
{
|
||||
uint16_t packet;
|
||||
|
||||
packet = totalBytes /FLASH_PAGE_SIZE;
|
||||
|
||||
if (totalBytes % FLASH_PAGE_SIZE )
|
||||
{
|
||||
packet += 1;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Function : update_iap
|
||||
* Description : none
|
||||
* Input : u32 totalBytes
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170425
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
此处还需要修改,不要使用1页的内存来存储,用小内存,或者直接用半字的方式来处理
|
||||
*****************************************************************************/
|
||||
bool update_iap(u32 totalBytes)
|
||||
{
|
||||
//static u8 updateBuf[FLASH_PAGE_SIZE];
|
||||
u16 iap_flash_pages = get_packets(totalBytes);
|
||||
|
||||
for (u32 j = 0; j < iap_flash_pages; j++)
|
||||
{
|
||||
// memcpy(updateBuf, (u8*)(FLASH_APP_BACK_ADDRESS + j*FLASH_PAGE_SIZE), FLASH_PAGE_SIZE);
|
||||
if (STM32_FlashPageErase(FLASH_API_ADDRESS + FLASH_PAGE_SIZE*j) == FLH_SUCCESS)
|
||||
{
|
||||
if (STM32_FlashWrite(FLASH_API_ADDRESS + FLASH_PAGE_SIZE*j, (u8*)(FLASH_APP_BACK_ADDRESS + j*FLASH_PAGE_SIZE) , FLASH_PAGE_SIZE) != FLH_SUCCESS)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool proceess_packet(st_update_packet * current_ptr, st_update_params * flash_ptr)
|
||||
{
|
||||
if (check_update_packect_state( current_ptr->current_packet_No))
|
||||
{
|
||||
printf("the same packet\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
printf("write packet %d in flash\r\n", current_ptr->current_packet_No);
|
||||
|
||||
FLASH_Write_update_page(current_ptr->current_packet_No, current_ptr->data, current_ptr->packet_length);
|
||||
|
||||
set_update_packetState(current_ptr->current_packet_No);
|
||||
|
||||
flash_ptr->received_packets++;
|
||||
|
||||
flash_ptr->current_packets = current_ptr->current_packet_No;
|
||||
|
||||
if (current_ptr->current_packet_No >= (current_ptr->total_packets - 1))
|
||||
{
|
||||
if (check_update_state(flash_ptr->total_packets) == TRUE)
|
||||
{
|
||||
printf("all packet received\r\n");
|
||||
|
||||
printf("total updte bytes = %d\r\n", flash_ptr->totalBytes );
|
||||
|
||||
flash_ptr->totalBytes = (current_ptr->total_packets - 1)*UPDATE_DEFAULT_PACKET_SIZE + current_ptr->packet_length;
|
||||
|
||||
if (current_ptr->file_indication == 0x03)
|
||||
{
|
||||
flash_ptr->status = UPDATE_FINISH;
|
||||
write_update_flash(flash_ptr);
|
||||
return TRUE;
|
||||
}
|
||||
else if (current_ptr->file_indication == 0xFD )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_update_params();
|
||||
printf("update file indication err\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_update_params();
|
||||
printf("update file err\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void erase_128k(void)
|
||||
{
|
||||
for (u32 i = 0; i < FLASH_APPL_BACK_PAGES; i++)
|
||||
{
|
||||
STM32_FlashPageErase(FLASH_APP_BACK_ADDRESS + i*2048);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool is_update_process = false;
|
||||
|
||||
bool get_update_process()
|
||||
{
|
||||
return is_update_process;
|
||||
}
|
||||
|
||||
void set_update_process()
|
||||
{
|
||||
is_update_process = true;
|
||||
}
|
||||
|
||||
|
||||
void update_process_task(void *ptr)
|
||||
{
|
||||
static st_update_packet update_packet;
|
||||
static bool update_finish_state = FALSE;
|
||||
static u8 tempBuf[UPDATE_BUF_LEN];
|
||||
static u32 last_packet_No = 0;
|
||||
|
||||
updateQueue = xQueueCreate(1, UPDATE_BUF_LEN);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
xQueueReceive(updateQueue, tempBuf, portMAX_DELAY );
|
||||
|
||||
memcpy(&update_packet, tempBuf, sizeof(st_update_packet) - 4);
|
||||
update_packet.data = tempBuf + sizeof(st_update_packet) -4;
|
||||
|
||||
if (update_packet.current_packet_No != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("update start\r\n");
|
||||
set_update_process();
|
||||
|
||||
|
||||
vTaskDelay(1000/portTICK_RATE_MS);
|
||||
close_printf();
|
||||
memset(&st_update, 0 , sizeof(st_update));
|
||||
|
||||
erase_128k();
|
||||
vTaskDelay(1000/portTICK_RATE_MS);
|
||||
|
||||
st_update.status = UPDATE_RUNNING;
|
||||
st_update.total_packets = update_packet.total_packets;
|
||||
printf("update_totalPackets = %d\r\n", st_update.total_packets);
|
||||
last_packet_No = 0;
|
||||
|
||||
update_finish_state = proceess_packet(&update_packet, &st_update);
|
||||
update_ack(packet_nnmber, update_packet.current_packet_No, 0x0A, g_update_ctrl);
|
||||
|
||||
if ( g_update_ctrl == UPDATE_PLC)
|
||||
{
|
||||
vTaskDelay(100/portTICK_RATE_MS);
|
||||
set_PLC_UART_baud(57600);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
if( xQueueReceive(updateQueue, tempBuf, 3000/portTICK_RATE_MS ) == pdPASS)
|
||||
{
|
||||
memcpy(&update_packet, tempBuf, sizeof(st_update_packet) - 4);
|
||||
update_packet.data = tempBuf + sizeof(st_update_packet) -4;
|
||||
|
||||
if (update_packet.current_packet_No != (last_packet_No + 1))
|
||||
{
|
||||
reset_update_params();
|
||||
open_printf();
|
||||
|
||||
if ( g_update_ctrl == UPDATE_PLC)
|
||||
{
|
||||
set_PLC_UART_baud(COM_PLC_BAUD);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_packet_No += 1;
|
||||
update_finish_state = proceess_packet(&update_packet, &st_update);
|
||||
update_ack(packet_nnmber, update_packet.current_packet_No, 0x0A, g_update_ctrl);
|
||||
if (update_finish_state)
|
||||
{
|
||||
update_finish_state = FALSE;
|
||||
|
||||
if (update_packet.file_indication == 0x03 ) //升级自身
|
||||
{
|
||||
vTaskDelay(300/portTICK_RATE_MS);
|
||||
SysReset();
|
||||
}
|
||||
else if (update_packet.file_indication == 0xFD ) //升级IAP
|
||||
{
|
||||
if (update_software_check(st_update.totalBytes))
|
||||
{
|
||||
bool iap_result = update_iap(st_update.totalBytes);
|
||||
if (iap_result)
|
||||
{
|
||||
SysReset();
|
||||
}
|
||||
}
|
||||
|
||||
set_PLC_UART_baud(COM_PLC_BAUD);
|
||||
reset_update_params();
|
||||
}
|
||||
else //升级标志错误
|
||||
{
|
||||
set_PLC_UART_baud(COM_PLC_BAUD);
|
||||
reset_update_params();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( g_update_ctrl == UPDATE_PLC)
|
||||
{
|
||||
set_PLC_UART_baud(COM_PLC_BAUD);
|
||||
}
|
||||
memset(&st_update, 0 , sizeof(st_update));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void create_update_task(void)
|
||||
{
|
||||
xTaskCreate( update_process_task, NULL, 200, NULL, 3, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void updata_finish(u32 total_packets)
|
||||
{
|
||||
|
||||
|
||||
reset_update_params();
|
||||
|
||||
|
||||
st_update.status = UPDATE_FINISH;
|
||||
st_update.totalBytes = total_packets;
|
||||
|
||||
|
||||
write_update_flash(&st_update);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
#define ONE_HOUR_TIME 3600000
|
||||
#define HALF_HOUR_TIME 1800000
|
||||
PROCESS(apl_update_process, "update_process ");
|
||||
PROCESS_THREAD(apl_update_process, ev, data)
|
||||
{
|
||||
|
||||
static st_update_packet update_packet;
|
||||
static bool update_finish_state = FALSE;
|
||||
static struct etimer update_timer;
|
||||
static struct etimer timeout_timer;
|
||||
static u8 tempBuf[255];
|
||||
static u8 buf[12];
|
||||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
if (ev == PROCESS_EVENT_INIT)
|
||||
{
|
||||
read_update_flash(&st_update);
|
||||
if (st_update.status == UPDATE_SUCCESS)
|
||||
{
|
||||
all_light_delay();
|
||||
reset_update_params();
|
||||
}
|
||||
memset(&st_update, 0 , sizeof(st_update));
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
PROCESS_WAIT_EVENT();
|
||||
|
||||
if (ev == PROCESS_EVENT_MSG)
|
||||
{
|
||||
memcpy(tempBuf, (u8*)data, COM_PLC_RX_BUFFER_SIZE);
|
||||
memcpy(&update_packet, tempBuf, sizeof(st_update_packet) - 4);
|
||||
|
||||
update_packet.data = tempBuf + sizeof(st_update_packet) -4;
|
||||
|
||||
if (update_packet.current_packet_No >= update_packet.total_packets )
|
||||
{
|
||||
printf("packet no error\r\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update_packet.current_packet_No == 0)
|
||||
{
|
||||
close_printf();
|
||||
printf("update start\r\n");
|
||||
memset(&st_update, 0 , sizeof(st_update));
|
||||
|
||||
erase_128k();
|
||||
etimer_set(&update_timer, 1000);
|
||||
PROCESS_WAIT_EVENT_UNTIL((ev == PROCESS_EVENT_TIMER) && ((struct etimer *)data == &update_timer));
|
||||
|
||||
etimer_set(&update_timer, HALF_HOUR_TIME);
|
||||
st_update.status = UPDATE_RUNNING;
|
||||
st_update.total_packets = update_packet.total_packets;
|
||||
printf("update_totalPackets = %d\r\n", st_update.total_packets);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (st_update.status != UPDATE_RUNNING)
|
||||
{
|
||||
reset_update_params();
|
||||
open_printf();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
update_finish_state = proceess_packet(&update_packet, &st_update);
|
||||
|
||||
update_ack(packet_nnmber, update_packet.current_packet_No, 0x0A, g_update_ctrl);
|
||||
|
||||
|
||||
if ((update_packet.current_packet_No == 0) && (g_update_ctrl == UPDATE_PLC))
|
||||
{
|
||||
etimer_set(&update_timer, 100);
|
||||
PROCESS_WAIT_EVENT_UNTIL((ev == PROCESS_EVENT_TIMER) && ((struct etimer *)data == &update_timer));
|
||||
set_PLC_UART_baud(57600);
|
||||
}
|
||||
|
||||
if (update_packet.current_packet_No == update_packet.total_packets -1)
|
||||
{
|
||||
etimer_stop(&timeout_timer);
|
||||
}
|
||||
|
||||
if (update_finish_state)
|
||||
{
|
||||
update_finish_state = FALSE;
|
||||
|
||||
if (update_packet.file_indication == 0x03 )
|
||||
{
|
||||
etimer_set(&update_timer, 300);
|
||||
PROCESS_WAIT_EVENT_UNTIL((ev == PROCESS_EVENT_TIMER) && ((struct etimer *)data == &update_timer));
|
||||
SysReset();
|
||||
}
|
||||
else if (update_packet.file_indication == 0xFD )
|
||||
{
|
||||
if (update_software_check(st_update.totalBytes))
|
||||
{
|
||||
if (!update_iap(st_update.totalBytes))
|
||||
{
|
||||
SysReset();
|
||||
}
|
||||
|
||||
set_PLC_UART_baud(9600);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_update_params();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((ev == PROCESS_EVENT_TIMER) && ((struct etimer *)data == &timeout_timer))
|
||||
{
|
||||
reset_update_params();
|
||||
set_PLC_UART_baud(9600);
|
||||
open_printf();
|
||||
}
|
||||
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
*/
|
||||
/******************* (C) COPYRIGHT 2013 Robulink Technology Ltd.*****END OF FILE****/
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
#ifndef _UPDATE_H_
|
||||
#define _UPDATE_H_
|
||||
|
||||
#include "Basedefine.h"
|
||||
|
||||
|
||||
#define FLASH_API_ADDRESS 0x08000000
|
||||
|
||||
#define FLASH_MAINTAINTIME_ADDRESS 0x08003000
|
||||
#define FLASH_KEY_ADDRESS 0x08003800
|
||||
#define FLASH_UPDATE_PARAMS_ADDRESS 0x08004000
|
||||
#define FLASH_LOCAL_ADDR_ADDRESS 0x08004c00 // ÔÚAPPµÄÇ°ÃæÒ»¸ö1KλÖÃ
|
||||
|
||||
#define FLASH_APP_ADDRESS 0x08005000
|
||||
#define FLASH_APP_BACK_ADDRESS 0x08022800
|
||||
|
||||
|
||||
#define FLASH_SLAVE_NODE_COUNT_ADDRESS 0x0803F800
|
||||
|
||||
|
||||
|
||||
#define FLASH_API_PAGES 8
|
||||
#define FLASH_PARAMS_PAGES 2
|
||||
#define FLASH_APP_PAGES 59
|
||||
#define FLASH_APPL_BACK_PAGES 59
|
||||
#define UPDATE_DEFAULT_PACKET_SIZE 128
|
||||
#define FLASH_PAGE_SIZE 2048
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UPDATE_END = 0,
|
||||
UPDATE_RUNNING,
|
||||
UPDATE_FINISH,
|
||||
UPDATE_SUCCESS,
|
||||
UPDATE_FAILED,
|
||||
UPDATE_SALVE,
|
||||
}EM_UPDATE_STATUS;
|
||||
|
||||
enum
|
||||
{
|
||||
UPDATE_NONE,
|
||||
UPDATE_PLC,
|
||||
UPDATE_485,
|
||||
UPDATE_MAX,
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 totalBytes;
|
||||
u16 version;
|
||||
u16 total_packets;
|
||||
u16 current_packets;
|
||||
u16 received_packets;
|
||||
u8 status;
|
||||
u8 packetsState[127];
|
||||
u16 crc;
|
||||
}st_update_params;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 file_indication;
|
||||
u8 file_property;
|
||||
u8 file_instr;
|
||||
u16 total_packets;
|
||||
u32 current_packet_No;
|
||||
u16 packet_length;
|
||||
u8 * data;
|
||||
}st_update_packet;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start;
|
||||
u16 len;
|
||||
u8 ctrl;
|
||||
u8 info_route:1;
|
||||
u8 info_slave:1;
|
||||
u8 info_com_module:1;
|
||||
u8 info_conflict:1;
|
||||
u8 info_relay:4;
|
||||
u8 info[4];
|
||||
u8 number;
|
||||
}st_13762_head;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
st_13762_head head;
|
||||
u8 afn;
|
||||
u8 dt1;
|
||||
u8 dt2;
|
||||
u32 current_packet_No;
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}st_AFN15_ack;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 start;
|
||||
u8 lenL;
|
||||
u8 lenH;
|
||||
u8 ctrl;
|
||||
u8 info_route:1;
|
||||
u8 info_slave:1;
|
||||
u8 info_com_module:1;
|
||||
u8 info_conflict:1;
|
||||
u8 info_relay:4;
|
||||
u8 info[4];
|
||||
u8 number;
|
||||
u8 *source_addr;
|
||||
u8 *relay_addr;
|
||||
u8 *desc_addr;
|
||||
u8 AFN;
|
||||
u8 DT1;
|
||||
u8 DT2;
|
||||
u8 *data;
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}st_13762;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
st_13762_head head;
|
||||
u8 AFN;
|
||||
u8 DT1;
|
||||
u8 DT2;
|
||||
u8 Manu_code[2];
|
||||
u8 chip_code[2];
|
||||
u8 day;
|
||||
u8 month;
|
||||
u8 year;
|
||||
u8 version;
|
||||
u8 cs;
|
||||
u8 end;
|
||||
}st_13762_03F1_ack;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
void transparent_Proc(void);
|
||||
void write_update_contrlner(u8 ctrlner);
|
||||
void apl_process_1372(u8 * ptr1372, u8 ctrlner);
|
||||
bool check_13762_packet(u8 *buf);
|
||||
void create_update_task(void);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "wdg.h"
|
||||
/*****************************************************************************
|
||||
* Function : Iwdg_Init
|
||||
* Description : none
|
||||
* Input : u8 timeout 为以秒为单位的看门狗超时时间,不得低于1s,看门狗定时器的数据不能超过u16的大小65536
|
||||
* Output : None
|
||||
* Return :
|
||||
* Others :
|
||||
* Record
|
||||
* 1.Date : 20170412
|
||||
* Author : barry
|
||||
* Modification: Created function
|
||||
|
||||
*****************************************************************************/
|
||||
void Iwdg_Init(u8 timeout)
|
||||
{
|
||||
#define WDG_PRE 256
|
||||
#define WDG_PER_COUNT (40000/WDG_PRE)
|
||||
#define IWDG_Prescaler IWDG_Prescaler_256
|
||||
|
||||
|
||||
u8 max_timeout = 0xFFF / WDG_PER_COUNT;
|
||||
|
||||
u16 reloadCount = 0;
|
||||
|
||||
timeout = (timeout == 0)? 1:timeout;
|
||||
timeout = (timeout >= max_timeout)? max_timeout: timeout;
|
||||
|
||||
reloadCount = timeout* WDG_PER_COUNT;
|
||||
|
||||
/* Check if the system has resumed from IWDG reset */
|
||||
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
|
||||
{
|
||||
RCC_ClearFlag();
|
||||
}
|
||||
|
||||
/* IWDG timeout equal to 280 ms (the timeout may varies due to LSI frequency
|
||||
dispersion) */
|
||||
/* Enable write access to IWDG_PR and IWDG_RLR registers */
|
||||
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
|
||||
|
||||
/* IWDG counter clock: 40KHz(LSI) / 32 = 1.25 KHz */
|
||||
IWDG_SetPrescaler(IWDG_Prescaler);
|
||||
|
||||
/* Set counter reload value to 1250, 1s timeout */
|
||||
IWDG_SetReload(reloadCount);
|
||||
|
||||
/* Reload IWDG counter */
|
||||
IWDG_ReloadCounter();
|
||||
|
||||
/* Enable IWDG (the LSI oscillator will be enabled by hardware) */
|
||||
IWDG_Enable();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/********************************************************************************
|
||||
|
||||
**** Copyright (C), 2017, xx xx xx xx info&tech Co., Ltd. ****
|
||||
|
||||
********************************************************************************
|
||||
* File Name : wdg.h
|
||||
* Author : barry
|
||||
* Date : 2017-04-12
|
||||
* Description : wdg.c header file
|
||||
* Version : 1.0
|
||||
* Function List :
|
||||
*
|
||||
* Record :
|
||||
* 1.Date : 2017-04-12
|
||||
* Author : barry
|
||||
* Modification: Created file
|
||||
|
||||
*************************************************************************************************************/
|
||||
|
||||
#ifndef __WDG_H__
|
||||
#define __WDG_H__
|
||||
|
||||
#include "include.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define FEED_WDG do{IWDG_ReloadCounter();}while(0)
|
||||
|
||||
extern void Iwdg_Init(uint8_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* __WDG_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,936 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project>
|
||||
<fileVersion>5</fileVersion>
|
||||
<fileChecksum>1226562857</fileChecksum>
|
||||
<configuration>
|
||||
<name>Debug</name>
|
||||
<outputs>
|
||||
<file>$PROJ_DIR$\shuangjia\addryw.c</file>
|
||||
<file>$PROJ_DIR$\filedata\hbfile.c</file>
|
||||
<file>$PROJ_DIR$\shuangjia\FRAM.c</file>
|
||||
<file>$PROJ_DIR$\hb\hbtimeproc.c</file>
|
||||
<file>$PROJ_DIR$\filedata\filedatadebug.c</file>
|
||||
<file>$PROJ_DIR$\shuangjia\filesave.c</file>
|
||||
<file>$PROJ_DIR$\hb\hbframe.c</file>
|
||||
<file>$PROJ_DIR$\hb\hbdatapro.c</file>
|
||||
<file>$PROJ_DIR$\hb\dl485.c</file>
|
||||
<file>$PROJ_DIR$\hb\hbheartpro .c</file>
|
||||
<file>$PROJ_DIR$\hb\hbdatacount.c</file>
|
||||
<file>$PROJ_DIR$\shuangjia\load.c</file>
|
||||
<file>$PROJ_DIR$\rp\rpprocess.c</file>
|
||||
<file>$PROJ_DIR$\APP\storage.c</file>
|
||||
<file>$PROJ_DIR$\APP\bl24c512.c</file>
|
||||
<file>$PROJ_DIR$\shuangjia\file.c</file>
|
||||
<file>$PROJ_DIR$\hb\dl485pro.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_i2c.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\FreeRTOS Source\tasks.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\PHY.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_pwr.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\misc.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\CSMIS\system_stm32f10x.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_rcc.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\hal_radio.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\keywd.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\MD5.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\sx1276-FskMisc.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\wdg.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\Cmd.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_exti.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_rtc.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\addr.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\Led.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\Flash.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\FreeRTOS Source\Portable\IAR\ARM_CM3\port.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\IrDA.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\FreeRTOS Source\list.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_dma.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\FreeRTOS Source\timers.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\protocol.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\yw\generalyw.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\debug_printf.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\apl.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\Init.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\rtc_ext.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\uart.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\update.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\FreeRTOS Source\queue.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\Mem.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\sx1276-LoRaMisc.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\sx1276-LoRa.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_flash.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\main.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\Rtc.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_gpio.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_iwdg.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\General.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\FreeRTOS Source\event_groups.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_bkp.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\FreeRTOS Source\Portable\IAR\heap_4.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\Standard Demo Tasks\PollQ.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_tim.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_spi.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\Standard Demo Tasks\BlockQ.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_usart.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\FreeRTOS Source\Portable\IAR\ARM_CM3\portasm.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\Standard Demo Tasks\blocktim.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\Standard Demo Tasks\semtest.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\Standard Demo Tasks\countsem.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\CSMIS\startup_stm32f10x_hd.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Exe\amt20201123.hex</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\Standard Demo Tasks\recmutex.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\ST_Code\STM32F10x_StdPeriph_Driver\stm32f10x_wwdg.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\Standard Demo Tasks\dynamic.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Exe\RTOSDemo.out</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\Standard Demo Tasks\GenQTest.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\yw\frame.o</file>
|
||||
<file>$PROJ_DIR$\APP\Led.c</file>
|
||||
<file>$PROJ_DIR$\APP\Rtc.c</file>
|
||||
<file>$PROJ_DIR$\APP\General.c</file>
|
||||
<file>$PROJ_DIR$\shuangjia\gprs.c</file>
|
||||
<file>$PROJ_DIR$\APP\keywd.c</file>
|
||||
<file>$PROJ_DIR$\APP\Mem.c</file>
|
||||
<file>$PROJ_DIR$\APP\update.c</file>
|
||||
<file>$PROJ_DIR$\upgrade\upgrade.c</file>
|
||||
<file>$PROJ_DIR$\APP\debug_printf.c</file>
|
||||
<file>$PROJ_DIR$\yw\frame.c</file>
|
||||
<file>$PROJ_DIR$\APP\wdg.c</file>
|
||||
<file>$PROJ_DIR$\Source\portable\IAR\ARM_CM3\port.c</file>
|
||||
<file>$PROJ_DIR$\Source\list.c</file>
|
||||
<file>$PROJ_DIR$\shuangjia\hal_GDflash.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup_stm32f10x_hd.s</file>
|
||||
<file>$PROJ_DIR$\APP\sx1276-FskMisc.c</file>
|
||||
<file>$PROJ_DIR$\APP\IrDA.c</file>
|
||||
<file>$PROJ_DIR$\yw\crc.c</file>
|
||||
<file>$PROJ_DIR$\APP\Init.c</file>
|
||||
<file>$PROJ_DIR$\APP\protocol.c</file>
|
||||
<file>$PROJ_DIR$\Source\queue.c</file>
|
||||
<file>$PROJ_DIR$\shuangjia\poweroffon.c</file>
|
||||
<file>$PROJ_DIR$\Source\timers.c</file>
|
||||
<file>$PROJ_DIR$\APP\MD5.c</file>
|
||||
<file>$PROJ_DIR$\APP\Flash.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c</file>
|
||||
<file>$PROJ_DIR$\APP\rtc_ext.c</file>
|
||||
<file>$PROJ_DIR$\APP\sx1276-LoRa.c</file>
|
||||
<file>$PROJ_DIR$\Source\portable\MemMang\heap_4.c</file>
|
||||
<file>$PROJ_DIR$\Source\event_groups.c</file>
|
||||
<file>$PROJ_DIR$\APP\addr.c</file>
|
||||
<file>$PROJ_DIR$\APP\sx1276-LoRaMisc.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\yw\crc.o</file>
|
||||
<file>$PROJ_DIR$\APP\hal_radio.c</file>
|
||||
<file>$PROJ_DIR$\APP\Cmd.c</file>
|
||||
<file>$PROJ_DIR$\Source\portable\IAR\ARM_CM3\portasm.s</file>
|
||||
<file>$PROJ_DIR$\yw\generalyw.c</file>
|
||||
<file>$PROJ_DIR$\APP\uart.c</file>
|
||||
<file>$PROJ_DIR$\Source\tasks.c</file>
|
||||
<file>$PROJ_DIR$\yw\comp.c</file>
|
||||
<file>$PROJ_DIR$\APP\apl.c</file>
|
||||
<file>$PROJ_DIR$\APP\main.c</file>
|
||||
<file>$PROJ_DIR$\APP\PHY.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_pwr.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_spi.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\misc.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rtc.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\filesave.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\hbdatapro.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\hbheartpro .o</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_iwdg.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\load.o</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_bkp.c</file>
|
||||
<file>$PROJ_DIR$\Common\Minimal\semtest.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\dl485.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\hbdatacount.o</file>
|
||||
<file>$PROJ_DIR$\Common\Minimal\PollQ.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\storage.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\filedata\filedatadebug.o</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\filedata\hbfile.o</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\filedata\hbtimeproc.o</file>
|
||||
<file>$PROJ_DIR$\Common\Minimal\countsem.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\shuangjia\addryw.o</file>
|
||||
<file>$PROJ_DIR$\Common\Minimal\blocktim.c</file>
|
||||
<file>$PROJ_DIR$\Common\Minimal\recmutex.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\shuangjia\gprs.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\shuangjia\FRAM.o</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_tim.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rcc.c</file>
|
||||
<file>$PROJ_DIR$\Common\Minimal\dynamic.c</file>
|
||||
<file>$PROJ_DIR$\Common\Minimal\GenQTest.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\rpprocess.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\shuangjia\hal_GDflash.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\shuangjia\poweroffon.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\upgrade\upgrade.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\yw\comp.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\dl485pro.o</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\file.o</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_exti.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\hbframe.o</file>
|
||||
<file>$PROJ_DIR$\Common\Minimal\BlockQ.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dma.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_i2c.c</file>
|
||||
<file>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_flash.c</file>
|
||||
<file>$PROJ_DIR$\Debug\Obj\APP\ahb\bl24c512.o</file>
|
||||
</outputs>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\shuangjia\addryw.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 143</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\filedata\hbfile.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 139</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\shuangjia\FRAM.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 147</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\hb\hbtimeproc.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 141</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\filedata\filedatadebug.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 137</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\shuangjia\filesave.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 125</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\hb\hbframe.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 160</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\hb\hbdatapro.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 126</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\hb\dl485.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 133</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\hb\hbheartpro .c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 127</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\hb\hbdatacount.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 134</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\shuangjia\load.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 129</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\rp\rpprocess.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 152</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\storage.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 136</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\bl24c512.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 165</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\shuangjia\file.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 158</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\hb\dl485pro.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 157</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>[ROOT_NODE]</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ILINK</name>
|
||||
<file> 75</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Debug\Exe\RTOSDemo.out</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>OBJCOPY</name>
|
||||
<file> 71</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\Led.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 33</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\Rtc.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 54</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\General.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 57</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\shuangjia\gprs.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 146</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\keywd.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 25</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\Mem.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 49</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\update.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 47</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\upgrade\upgrade.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 155</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\debug_printf.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 42</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\yw\frame.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 77</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\wdg.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 28</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Source\portable\IAR\ARM_CM3\port.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 35</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Source\list.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 37</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\shuangjia\hal_GDflash.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 153</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup_stm32f10x_hd.s</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>AARM</name>
|
||||
<file> 70</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\sx1276-FskMisc.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 27</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\IrDA.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 36</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\yw\crc.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 110</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\Init.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 44</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\protocol.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 40</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Source\queue.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 48</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\shuangjia\poweroffon.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 154</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Source\timers.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 39</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\MD5.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 26</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\Flash.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 34</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 22</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\rtc_ext.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 45</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\sx1276-LoRa.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 51</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Source\portable\MemMang\heap_4.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 60</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Source\event_groups.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 58</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\addr.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 32</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\sx1276-LoRaMisc.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 50</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\hal_radio.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 24</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\Cmd.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 29</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Source\portable\IAR\ARM_CM3\portasm.s</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>AARM</name>
|
||||
<file> 66</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\yw\generalyw.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 41</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\uart.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 46</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Source\tasks.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 18</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\yw\comp.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 156</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\apl.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 43</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\main.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 53</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\APP\PHY.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 19</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_pwr.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 20</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_spi.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 63</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\misc.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 21</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rtc.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 31</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_iwdg.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 56</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 55</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_bkp.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 59</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Common\Minimal\semtest.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 68</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Common\Minimal\PollQ.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 61</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 73</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 65</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Common\Minimal\countsem.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 69</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Common\Minimal\blocktim.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 67</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Common\Minimal\recmutex.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 72</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_tim.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 62</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rcc.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 23</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Common\Minimal\dynamic.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 74</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Common\Minimal\GenQTest.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 76</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_exti.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 30</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\Common\Minimal\BlockQ.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 64</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dma.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 38</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_i2c.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 17</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<file>
|
||||
<name>$PROJ_DIR$\ST_Code\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_flash.c</name>
|
||||
<outputs>
|
||||
<tool>
|
||||
<name>ICCARM</name>
|
||||
<file> 52</file>
|
||||
</tool>
|
||||
</outputs>
|
||||
</file>
|
||||
<forcedrebuild>
|
||||
<name>[MULTI_TOOL]</name>
|
||||
<tool>ILINK</tool>
|
||||
</forcedrebuild>
|
||||
</configuration>
|
||||
</project>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates six tasks that operate on three queues as follows:
|
||||
*
|
||||
* The first two tasks send and receive an incrementing number to/from a queue.
|
||||
* One task acts as a producer and the other as the consumer. The consumer is a
|
||||
* higher priority than the producer and is set to block on queue reads. The queue
|
||||
* only has space for one item - as soon as the producer posts a message on the
|
||||
* queue the consumer will unblock, pre-empt the producer, and remove the item.
|
||||
*
|
||||
* The second two tasks work the other way around. Again the queue used only has
|
||||
* enough space for one item. This time the consumer has a lower priority than the
|
||||
* producer. The producer will try to post on the queue blocking when the queue is
|
||||
* full. When the consumer wakes it will remove the item from the queue, causing
|
||||
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
|
||||
* queue.
|
||||
*
|
||||
* The last two tasks use the same queue producer and consumer functions. This time the queue has
|
||||
* enough space for lots of items and the tasks operate at the same priority. The
|
||||
* producer will execute, placing items into the queue. The consumer will start
|
||||
* executing when either the queue becomes full (causing the producer to block) or
|
||||
* a context switch occurs (tasks of the same priority will time slice).
|
||||
*
|
||||
* \page BlockQC blockQ.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.00:
|
||||
|
||||
+ Reversed the priority and block times of the second two demo tasks so
|
||||
they operate as per the description above.
|
||||
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than unsigned long.
|
||||
|
||||
Changes from V4.0.2
|
||||
|
||||
+ The second set of tasks were created the wrong way around. This has been
|
||||
corrected.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "BlockQ.h"
|
||||
#include "print.h"
|
||||
|
||||
#define blckqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
|
||||
#define blckqNUM_TASK_SETS ( 3 )
|
||||
|
||||
/* Structure used to pass parameters to the blocking queue tasks. */
|
||||
typedef struct BLOCKING_QUEUE_PARAMETERS
|
||||
{
|
||||
QueueHandle_t xQueue; /*< The queue to be used by the task. */
|
||||
TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */
|
||||
volatile short *psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
|
||||
} xBlockingQueueParameters;
|
||||
|
||||
/* Task function that creates an incrementing number and posts it on a queue. */
|
||||
static void vBlockingQueueProducer( void *pvParameters );
|
||||
|
||||
/* Task function that removes the incrementing number from a queue and checks that
|
||||
it is the expected number. */
|
||||
static void vBlockingQueueConsumer( void *pvParameters );
|
||||
|
||||
/* Variables which are incremented each time an item is removed from a queue, and
|
||||
found to be the expected value.
|
||||
These are used to check that the tasks are still running. */
|
||||
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
|
||||
|
||||
/* Variable which are incremented each time an item is posted on a queue. These
|
||||
are used to check that the tasks are still running. */
|
||||
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2;
|
||||
xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4;
|
||||
xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6;
|
||||
const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
|
||||
const TickType_t xBlockTime = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
|
||||
const TickType_t xDontBlock = ( TickType_t ) 0;
|
||||
|
||||
/* Create the first two tasks as described at the top of the file. */
|
||||
|
||||
/* First create the structure used to pass parameters to the consumer tasks. */
|
||||
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Create the queue used by the first two tasks to pass the incrementing number.
|
||||
Pass a pointer to the queue in the parameter structure. */
|
||||
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
|
||||
|
||||
/* The consumer is created first so gets a block time as described above. */
|
||||
pxQueueParameters1->xBlockTime = xBlockTime;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check it
|
||||
is still running. */
|
||||
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
|
||||
|
||||
/* Create the structure used to pass parameters to the producer task. */
|
||||
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Pass the queue to this task also, using the parameter structure. */
|
||||
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
|
||||
|
||||
/* The producer is not going to block - as soon as it posts the consumer will
|
||||
wake and remove the item so the producer should always have room to post. */
|
||||
pxQueueParameters2->xBlockTime = xDontBlock;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check
|
||||
it is still running. */
|
||||
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
|
||||
|
||||
|
||||
/* Note the producer has a lower priority than the consumer when the tasks are
|
||||
spawned. */
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the second two tasks as described at the top of the file. This uses
|
||||
the same mechanism but reverses the task priorities. */
|
||||
|
||||
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
|
||||
pxQueueParameters3->xBlockTime = xDontBlock;
|
||||
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
|
||||
|
||||
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
|
||||
pxQueueParameters4->xBlockTime = xBlockTime;
|
||||
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the last two tasks as described above. The mechanism is again just
|
||||
the same. This time both parameter structures are given a block time. */
|
||||
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
|
||||
pxQueueParameters5->xBlockTime = xBlockTime;
|
||||
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
|
||||
|
||||
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
|
||||
pxQueueParameters6->xBlockTime = xBlockTime;
|
||||
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vBlockingQueueProducer( void *pvParameters )
|
||||
{
|
||||
unsigned short usValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
const char * const pcTaskStartMsg = "Blocking queue producer started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "Could not post on blocking queue\r\n";
|
||||
short sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully posted a message, so increment the variable
|
||||
used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the variable we are going to post next time round. The
|
||||
consumer will expect the numbers to follow in numerical order. */
|
||||
++usValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vBlockingQueueConsumer( void *pvParameters )
|
||||
{
|
||||
unsigned short usData, usExpectedValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
const char * const pcTaskStartMsg = "Blocking queue consumer started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "Incorrect value received on blocking queue.\r\n";
|
||||
short sErrorEverOccurred = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
|
||||
/* Catch-up. */
|
||||
usExpectedValue = usData;
|
||||
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully received a message, so increment the
|
||||
variable used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the value we expect to remove from the queue next time
|
||||
round. */
|
||||
++usExpectedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreBlockingQueuesStillRunning( void )
|
||||
{
|
||||
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
|
||||
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
|
||||
portBASE_TYPE xReturn = pdPASS, xTasks;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
bits and we are only reading them. We also only care to see if they have
|
||||
changed or not.
|
||||
|
||||
Loop through each check variable and return pdFALSE if any are found not
|
||||
to have changed since the last call. */
|
||||
|
||||
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
|
||||
{
|
||||
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
|
||||
|
||||
|
||||
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* This is a very simple queue test. See the BlockQ. c documentation for a more
|
||||
* comprehensive version.
|
||||
*
|
||||
* Creates two tasks that communicate over a single queue. One task acts as a
|
||||
* producer, the other a consumer.
|
||||
*
|
||||
* The producer loops for three iteration, posting an incrementing number onto the
|
||||
* queue each cycle. It then delays for a fixed period before doing exactly the
|
||||
* same again.
|
||||
*
|
||||
* The consumer loops emptying the queue. Each item removed from the queue is
|
||||
* checked to ensure it contains the expected value. When the queue is empty it
|
||||
* blocks for a fixed period, then does the same again.
|
||||
*
|
||||
* All queue access is performed without blocking. The consumer completely empties
|
||||
* the queue each time it runs so the producer should never find the queue full.
|
||||
*
|
||||
* An error is flagged if the consumer obtains an unexpected value or the producer
|
||||
* find the queue is full.
|
||||
*
|
||||
* \page PollQC pollQ.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than unsigned long.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "PollQ.h"
|
||||
|
||||
#define pollqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
|
||||
|
||||
/* The task that posts the incrementing number onto the queue. */
|
||||
static void vPolledQueueProducer( void *pvParameters );
|
||||
|
||||
/* The task that empties the queue. */
|
||||
static void vPolledQueueConsumer( void *pvParameters );
|
||||
|
||||
/* Variables that are used to check that the tasks are still running with no errors. */
|
||||
static volatile short sPollingConsumerCount = 0, sPollingProducerCount = 0;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
static QueueHandle_t xPolledQueue;
|
||||
const unsigned portBASE_TYPE uxQueueSize = 10;
|
||||
|
||||
/* Create the queue used by the producer and consumer. */
|
||||
xPolledQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
|
||||
|
||||
/* Spawn the producer and consumer. */
|
||||
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
|
||||
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPolledQueueProducer( void *pvParameters )
|
||||
{
|
||||
unsigned short usValue = 0, usLoop;
|
||||
QueueHandle_t *pxQueue;
|
||||
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
|
||||
const unsigned short usNumToProduce = 3;
|
||||
const char * const pcTaskStartMsg = "Polled queue producer started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "Could not post on polled queue.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The queue being used is passed in as the parameter. */
|
||||
pxQueue = ( QueueHandle_t * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
for( usLoop = 0; usLoop < usNumToProduce; ++usLoop )
|
||||
{
|
||||
/* Send an incrementing number on the queue without blocking. */
|
||||
if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( TickType_t ) 0 ) != pdPASS )
|
||||
{
|
||||
/* We should never find the queue full - this is an error. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If an error has ever been recorded we stop incrementing the
|
||||
check variable. */
|
||||
++sPollingProducerCount;
|
||||
}
|
||||
|
||||
/* Update the value we are going to post next time around. */
|
||||
++usValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait before we start posting again to ensure the consumer runs and
|
||||
empties the queue. */
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPolledQueueConsumer( void *pvParameters )
|
||||
{
|
||||
unsigned short usData, usExpectedValue = 0;
|
||||
QueueHandle_t *pxQueue;
|
||||
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
|
||||
const char * const pcTaskStartMsg = "Polled queue consumer started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "Incorrect value received on polled queue.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The queue being used is passed in as the parameter. */
|
||||
pxQueue = ( QueueHandle_t * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Loop until the queue is empty. */
|
||||
while( uxQueueMessagesWaiting( *pxQueue ) )
|
||||
{
|
||||
if( xQueueReceive( *pxQueue, &usData, ( TickType_t ) 0 ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* This is not what we expected to receive so an error has
|
||||
occurred. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sError = pdTRUE;
|
||||
/* Catch-up to the value we received so our next expected value
|
||||
should again be correct. */
|
||||
usExpectedValue = usData;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* Only increment the check variable if no errors have
|
||||
occurred. */
|
||||
++sPollingConsumerCount;
|
||||
}
|
||||
}
|
||||
++usExpectedValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the queue is empty we block, allowing the producer to place more
|
||||
items in the queue. */
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running with no errors. */
|
||||
portBASE_TYPE xArePollingQueuesStillRunning( void )
|
||||
{
|
||||
static short sLastPollingConsumerCount = 0, sLastPollingProducerCount = 0;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
if( ( sLastPollingConsumerCount == sPollingConsumerCount ) ||
|
||||
( sLastPollingProducerCount == sPollingProducerCount )
|
||||
)
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
sLastPollingConsumerCount = sPollingConsumerCount;
|
||||
sLastPollingProducerCount = sPollingProducerCount;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates two tasks that operate on an interrupt driven serial port. A loopback
|
||||
* connector should be used so that everything that is transmitted is also received.
|
||||
* The serial port does not use any flow control. On a standard 9way 'D' connector
|
||||
* pins two and three should be connected together.
|
||||
*
|
||||
* The first task repeatedly sends a string to a queue, character at a time. The
|
||||
* serial port interrupt will empty the queue and transmit the characters. The
|
||||
* task blocks for a pseudo random period before resending the string.
|
||||
*
|
||||
* The second task blocks on a queue waiting for a character to be received.
|
||||
* Characters received by the serial port interrupt routine are posted onto the
|
||||
* queue - unblocking the task making it ready to execute. If this is then the
|
||||
* highest priority task ready to run it will run immediately - with a context
|
||||
* switch occurring at the end of the interrupt service routine. The task
|
||||
* receiving characters is spawned with a higher priority than the task
|
||||
* transmitting the characters.
|
||||
*
|
||||
* With the loop back connector in place, one task will transmit a string and the
|
||||
* other will immediately receive it. The receiving task knows the string it
|
||||
* expects to receive so can detect an error.
|
||||
*
|
||||
* This also creates a third task. This is used to test semaphore usage from an
|
||||
* ISR and does nothing interesting.
|
||||
*
|
||||
* \page ComTestC comtest.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.00:
|
||||
|
||||
+ The priority of the Rx task has been lowered. Received characters are
|
||||
now processed (read from the queue) at the idle priority, allowing low
|
||||
priority tasks to run evenly at times of a high communications overhead.
|
||||
|
||||
Changes from V1.01:
|
||||
|
||||
+ The Tx task now waits a pseudo random time between transissions.
|
||||
Previously a fixed period was used but this was not such a good test as
|
||||
interrupts fired at regular intervals.
|
||||
|
||||
Changes From V1.2.0:
|
||||
|
||||
+ Use vSerialPutString() instead of single character puts.
|
||||
+ Only stop the check variable incrementing after two consecutive errors.
|
||||
|
||||
Changed from V1.2.5
|
||||
|
||||
+ Made the Rx task 2 priorities higher than the Tx task. Previously it was
|
||||
only 1. This is done to tie in better with the other demo application
|
||||
tasks.
|
||||
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than unsigned long.
|
||||
+ Slight modification to task priorities.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "serial.h"
|
||||
#include "comtest.h"
|
||||
#include "print.h"
|
||||
|
||||
/* The Tx task will transmit the sequence of characters at a pseudo random
|
||||
interval. This is the maximum and minimum block time between sends. */
|
||||
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x15e )
|
||||
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0xc8 )
|
||||
|
||||
#define comMAX_CONSECUTIVE_ERRORS ( 2 )
|
||||
|
||||
#define comSTACK_SIZE ( ( unsigned short ) 256 )
|
||||
|
||||
#define comRX_RELATIVE_PRIORITY ( 1 )
|
||||
|
||||
/* Handle to the com port used by both tasks. */
|
||||
static xComPortHandle xPort;
|
||||
|
||||
/* The transmit function as described at the top of the file. */
|
||||
static void vComTxTask( void *pvParameters );
|
||||
|
||||
/* The receive function as described at the top of the file. */
|
||||
static void vComRxTask( void *pvParameters );
|
||||
|
||||
/* The semaphore test function as described at the top of the file. */
|
||||
static void vSemTestTask( void * pvParameters );
|
||||
|
||||
/* The string that is repeatedly transmitted. */
|
||||
const char * const pcMessageToExchange = "Send this message over and over again to check communications interrupts. "
|
||||
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
|
||||
|
||||
/* Variables that are incremented on each cycle of each task. These are used to
|
||||
check that both tasks are still executing. */
|
||||
volatile short sTxCount = 0, sRxCount = 0, sSemCount = 0;
|
||||
|
||||
/* The handle to the semaphore test task. */
|
||||
static TaskHandle_t xSemTestTaskHandle = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartComTestTasks( unsigned portBASE_TYPE uxPriority, eCOMPort ePort, eBaud eBaudRate )
|
||||
{
|
||||
const unsigned portBASE_TYPE uxBufferLength = 255;
|
||||
|
||||
/* Initialise the com port then spawn both tasks. */
|
||||
xPort = xSerialPortInit( ePort, eBaudRate, serNO_PARITY, serBITS_8, serSTOP_1, uxBufferLength );
|
||||
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority, NULL );
|
||||
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority + comRX_RELATIVE_PRIORITY, NULL );
|
||||
xTaskCreate( vSemTestTask, "ISRSem", comSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xSemTestTaskHandle );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vComTxTask( void *pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "COM Tx task started.\r\n";
|
||||
TickType_t xTimeToWait;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Send the string to the serial port. */
|
||||
vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) );
|
||||
|
||||
/* We have posted all the characters in the string - increment the variable
|
||||
used to check that this task is still running, then wait before re-sending
|
||||
the string. */
|
||||
sTxCount++;
|
||||
|
||||
xTimeToWait = xTaskGetTickCount();
|
||||
|
||||
/* Make sure we don't wait too long... */
|
||||
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
||||
|
||||
/* ...but we do want to wait. */
|
||||
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
||||
{
|
||||
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
||||
}
|
||||
|
||||
vTaskDelay( xTimeToWait );
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vComRxTask( void *pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "COM Rx task started.\r\n";
|
||||
const char * const pcTaskErrorMsg = "COM read error\r\n";
|
||||
const char * const pcTaskRestartMsg = "COM resynced\r\n";
|
||||
const char * const pcTaskTimeoutMsg = "COM Rx timed out\r\n";
|
||||
const TickType_t xBlockTime = ( TickType_t ) 0xffff / portTICK_PERIOD_MS;
|
||||
const char *pcExpectedChar;
|
||||
portBASE_TYPE xGotChar;
|
||||
char cRxedChar;
|
||||
short sResyncRequired, sConsecutiveErrors, sLatchedError;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The first expected character is the first character in the string. */
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
sResyncRequired = pdFALSE;
|
||||
sConsecutiveErrors = 0;
|
||||
sLatchedError = pdFALSE;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Receive a message from the com port interrupt routine. If a message is
|
||||
not yet available the call will block the task. */
|
||||
xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime );
|
||||
if( xGotChar == pdTRUE )
|
||||
{
|
||||
if( sResyncRequired == pdTRUE )
|
||||
{
|
||||
/* We got out of sequence and are waiting for the start of the next
|
||||
transmission of the string. */
|
||||
if( cRxedChar == '\n' )
|
||||
{
|
||||
/* This is the end of the message so we can start again - with
|
||||
the first character in the string being the next thing we expect
|
||||
to receive. */
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
sResyncRequired = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say that we are going to try
|
||||
again. */
|
||||
vPrintDisplayMessage( &pcTaskRestartMsg );
|
||||
|
||||
/* Stop incrementing the check variable, if consecutive errors occur. */
|
||||
sConsecutiveErrors++;
|
||||
if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS )
|
||||
{
|
||||
sLatchedError = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have received a character, but is it the expected character? */
|
||||
if( cRxedChar != *pcExpectedChar )
|
||||
{
|
||||
/* This was not the expected character so post a message for
|
||||
printing to say that an error has occurred. We will then wait
|
||||
to resynchronise. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sResyncRequired = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This was the expected character so next time we will expect
|
||||
the next character in the string. Wrap back to the beginning
|
||||
of the string when the null terminator has been reached. */
|
||||
pcExpectedChar++;
|
||||
if( *pcExpectedChar == '\0' )
|
||||
{
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
|
||||
/* We have got through the entire string without error. */
|
||||
sConsecutiveErrors = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the count that is used to check that this task is still
|
||||
running. This is only done if an error has never occurred. */
|
||||
if( sLatchedError == pdFALSE )
|
||||
{
|
||||
sRxCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskTimeoutMsg );
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSemTestTask( void * pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "ISR Semaphore test started.\r\n";
|
||||
portBASE_TYPE xError = pdFALSE;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xSerialWaitForSemaphore( xPort ) )
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
sSemCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xError = pdTRUE;
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e830 !e818 pvParameters not used but function prototype must be standard for task function. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreComTestTasksStillRunning( void )
|
||||
{
|
||||
static short sLastTxCount = 0, sLastRxCount = 0, sLastSemCount = 0;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
bits and we are only reading them. We also only care to see if they have
|
||||
changed or not. */
|
||||
|
||||
if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
sLastTxCount = sTxCount;
|
||||
sLastRxCount = sRxCount;
|
||||
sLastSemCount = sSemCount;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vComTestUnsuspendTask( void )
|
||||
{
|
||||
/* The task that is suspended on the semaphore will be referenced from the
|
||||
Suspended list as it is blocking indefinitely. This call just checks that
|
||||
the kernel correctly detects this and does not attempt to unsuspend the
|
||||
task. */
|
||||
xTaskResumeFromISR( xSemTestTaskHandle );
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a single persistent task which periodically dynamically creates another
|
||||
* four tasks. The original task is called the creator task, the four tasks it
|
||||
* creates are called suicidal tasks.
|
||||
*
|
||||
* Two of the created suicidal tasks kill one other suicidal task before killing
|
||||
* themselves - leaving just the original task remaining.
|
||||
*
|
||||
* The creator task must be spawned after all of the other demo application tasks
|
||||
* as it keeps a check on the number of tasks under the scheduler control. The
|
||||
* number of tasks it expects to see running should never be greater than the
|
||||
* number of tasks that were in existence when the creator task was spawned, plus
|
||||
* one set of four suicidal tasks. If this number is exceeded an error is flagged.
|
||||
*
|
||||
* \page DeathC death.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than unsigned long.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "death.h"
|
||||
#include "print.h"
|
||||
|
||||
#define deathSTACK_SIZE ( ( unsigned short ) 512 )
|
||||
|
||||
/* The task originally created which is responsible for periodically dynamically
|
||||
creating another four tasks. */
|
||||
static void vCreateTasks( void *pvParameters );
|
||||
|
||||
/* The task function of the dynamically created tasks. */
|
||||
static void vSuicidalTask( void *pvParameters );
|
||||
|
||||
/* A variable which is incremented every time the dynamic tasks are created. This
|
||||
is used to check that the task is still running. */
|
||||
static volatile short sCreationCount = 0;
|
||||
|
||||
/* Used to store the number of tasks that were originally running so the creator
|
||||
task can tell if any of the suicidal tasks have failed to die. */
|
||||
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
|
||||
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5;
|
||||
|
||||
/* Used to store a handle to the tasks that should be killed by a suicidal task,
|
||||
before it kills itself. */
|
||||
TaskHandle_t xCreatedTask1, xCreatedTask2;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
unsigned portBASE_TYPE *puxPriority;
|
||||
|
||||
/* Create the Creator tasks - passing in as a parameter the priority at which
|
||||
the suicidal tasks should be created. */
|
||||
puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
|
||||
*puxPriority = uxPriority;
|
||||
|
||||
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );
|
||||
|
||||
/* Record the number of tasks that are running now so we know if any of the
|
||||
suicidal tasks have failed to be killed. */
|
||||
uxTasksRunningAtStart = uxTaskGetNumberOfTasks();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSuicidalTask( void *pvParameters )
|
||||
{
|
||||
portDOUBLE d1, d2;
|
||||
TaskHandle_t xTaskToKill;
|
||||
const TickType_t xDelay = ( TickType_t ) 500 / portTICK_PERIOD_MS;
|
||||
|
||||
if( pvParameters != NULL )
|
||||
{
|
||||
/* This task is periodically created four times. Tow created tasks are
|
||||
passed a handle to the other task so it can kill it before killing itself.
|
||||
The other task is passed in null. */
|
||||
xTaskToKill = *( TaskHandle_t* )pvParameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTaskToKill = NULL;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Do something random just to use some stack and registers. */
|
||||
d1 = 2.4;
|
||||
d2 = 89.2;
|
||||
d2 *= d1;
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
if( xTaskToKill != NULL )
|
||||
{
|
||||
/* Make sure the other task has a go before we delete it. */
|
||||
vTaskDelay( ( TickType_t ) 0 );
|
||||
/* Kill the other task that was created by vCreateTasks(). */
|
||||
vTaskDelete( xTaskToKill );
|
||||
/* Kill ourselves. */
|
||||
vTaskDelete( NULL );
|
||||
}
|
||||
}
|
||||
}/*lint !e818 !e550 Function prototype must be as per standard for task functions. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCreateTasks( void *pvParameters )
|
||||
{
|
||||
const TickType_t xDelay = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
|
||||
unsigned portBASE_TYPE uxPriority;
|
||||
const char * const pcTaskStartMsg = "Create task started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;
|
||||
vPortFree( pvParameters );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Just loop round, delaying then creating the four suicidal tasks. */
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask1 );
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask1, uxPriority, NULL );
|
||||
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask2 );
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask2, uxPriority, NULL );
|
||||
|
||||
++sCreationCount;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that the creator task is still running and that there
|
||||
are not any more than four extra tasks. */
|
||||
portBASE_TYPE xIsCreateTaskStillRunning( void )
|
||||
{
|
||||
static short sLastCreationCount = 0;
|
||||
short sReturn = pdTRUE;
|
||||
unsigned portBASE_TYPE uxTasksRunningNow;
|
||||
|
||||
if( sLastCreationCount == sCreationCount )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
|
||||
uxTasksRunningNow = uxTaskGetNumberOfTasks();
|
||||
|
||||
if( uxTasksRunningNow < uxTasksRunningAtStart )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Everything is okay. */
|
||||
}
|
||||
|
||||
return sReturn;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,620 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* The first test creates three tasks - two counter tasks (one continuous count
|
||||
* and one limited count) and one controller. A "count" variable is shared
|
||||
* between all three tasks. The two counter tasks should never be in a "ready"
|
||||
* state at the same time. The controller task runs at the same priority as
|
||||
* the continuous count task, and at a lower priority than the limited count
|
||||
* task.
|
||||
*
|
||||
* One counter task loops indefinitely, incrementing the shared count variable
|
||||
* on each iteration. To ensure it has exclusive access to the variable it
|
||||
* raises it's priority above that of the controller task before each
|
||||
* increment, lowering it again to it's original priority before starting the
|
||||
* next iteration.
|
||||
*
|
||||
* The other counter task increments the shared count variable on each
|
||||
* iteration of it's loop until the count has reached a limit of 0xff - at
|
||||
* which point it suspends itself. It will not start a new loop until the
|
||||
* controller task has made it "ready" again by calling vTaskResume ().
|
||||
* This second counter task operates at a higher priority than controller
|
||||
* task so does not need to worry about mutual exclusion of the counter
|
||||
* variable.
|
||||
*
|
||||
* The controller task is in two sections. The first section controls and
|
||||
* monitors the continuous count task. When this section is operational the
|
||||
* limited count task is suspended. Likewise, the second section controls
|
||||
* and monitors the limited count task. When this section is operational the
|
||||
* continuous count task is suspended.
|
||||
*
|
||||
* In the first section the controller task first takes a copy of the shared
|
||||
* count variable. To ensure mutual exclusion on the count variable it
|
||||
* suspends the continuous count task, resuming it again when the copy has been
|
||||
* taken. The controller task then sleeps for a fixed period - during which
|
||||
* the continuous count task will execute and increment the shared variable.
|
||||
* When the controller task wakes it checks that the continuous count task
|
||||
* has executed by comparing the copy of the shared variable with its current
|
||||
* value. This time, to ensure mutual exclusion, the scheduler itself is
|
||||
* suspended with a call to vTaskSuspendAll (). This is for demonstration
|
||||
* purposes only and is not a recommended technique due to its inefficiency.
|
||||
*
|
||||
* After a fixed number of iterations the controller task suspends the
|
||||
* continuous count task, and moves on to its second section.
|
||||
*
|
||||
* At the start of the second section the shared variable is cleared to zero.
|
||||
* The limited count task is then woken from it's suspension by a call to
|
||||
* vTaskResume (). As this counter task operates at a higher priority than
|
||||
* the controller task the controller task should not run again until the
|
||||
* shared variable has been counted up to the limited value causing the counter
|
||||
* task to suspend itself. The next line after vTaskResume () is therefore
|
||||
* a check on the shared variable to ensure everything is as expected.
|
||||
*
|
||||
*
|
||||
* The second test consists of a couple of very simple tasks that post onto a
|
||||
* queue while the scheduler is suspended. This test was added to test parts
|
||||
* of the scheduler not exercised by the first test.
|
||||
*
|
||||
*
|
||||
* The final set of two tasks implements a third test. This simply raises the
|
||||
* priority of a task while the scheduler is suspended. Again this test was
|
||||
* added to exercise parts of the code not covered by the first test.
|
||||
*
|
||||
* \page Priorities dynamic.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than unsigned long.
|
||||
+ Added a second, simple test that uses the functions
|
||||
vQueueReceiveWhenSuspendedTask() and vQueueSendWhenSuspendedTask().
|
||||
|
||||
Changes from V3.1.1
|
||||
|
||||
+ Added a third simple test that uses the vTaskPrioritySet() function
|
||||
while the scheduler is suspended.
|
||||
+ Modified the controller task slightly to test the calling of
|
||||
vTaskResumeAll() while the scheduler is suspended.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "dynamic.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Function that implements the "limited count" task as described above. */
|
||||
static void vLimitedIncrementTask( void * pvParameters );
|
||||
|
||||
/* Function that implements the "continuous count" task as described above. */
|
||||
static void vContinuousIncrementTask( void * pvParameters );
|
||||
|
||||
/* Function that implements the controller task as described above. */
|
||||
static void vCounterControlTask( void * pvParameters );
|
||||
|
||||
/* The simple test functions that check sending and receiving while the
|
||||
scheduler is suspended. */
|
||||
static void vQueueReceiveWhenSuspendedTask( void *pvParameters );
|
||||
static void vQueueSendWhenSuspendedTask( void *pvParameters );
|
||||
|
||||
/* The simple test functions that check raising and lowering of task priorities
|
||||
while the scheduler is suspended. */
|
||||
static void prvChangePriorityWhenSuspendedTask( void *pvParameters );
|
||||
static void prvChangePriorityHelperTask( void *pvParameters );
|
||||
|
||||
|
||||
/* Demo task specific constants. */
|
||||
#define priSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
|
||||
#define priSLEEP_TIME ( ( TickType_t ) 50 )
|
||||
#define priLOOPS ( 5 )
|
||||
#define priMAX_COUNT ( ( unsigned long ) 0xff )
|
||||
#define priNO_BLOCK ( ( TickType_t ) 0 )
|
||||
#define priSUSPENDED_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Handles to the two counter tasks. These could be passed in as parameters
|
||||
to the controller task to prevent them having to be file scope. */
|
||||
static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle, xChangePriorityWhenSuspendedHandle;
|
||||
|
||||
/* The shared counter variable. This is passed in as a parameter to the two
|
||||
counter variables for demonstration purposes. */
|
||||
static unsigned long ulCounter;
|
||||
|
||||
/* Variable used in a similar way by the test that checks the raising and
|
||||
lowering of task priorities while the scheduler is suspended. */
|
||||
static unsigned long ulPrioritySetCounter;
|
||||
|
||||
/* Variables used to check that the tasks are still operating without error.
|
||||
Each complete iteration of the controller task increments this variable
|
||||
provided no errors have been found. The variable maintaining the same value
|
||||
is therefore indication of an error. */
|
||||
static unsigned short usCheckVariable = ( unsigned short ) 0;
|
||||
static portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
|
||||
static portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
|
||||
static portBASE_TYPE xPriorityRaiseWhenSuspendedError = pdFALSE;
|
||||
|
||||
/* Queue used by the second test. */
|
||||
QueueHandle_t xSuspendedTestQueue;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
/*
|
||||
* Start the seven tasks as described at the top of the file.
|
||||
* Note that the limited count task is given a higher priority.
|
||||
*/
|
||||
void vStartDynamicPriorityTasks( void )
|
||||
{
|
||||
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned long ) );
|
||||
xTaskCreate( vContinuousIncrementTask, "CONT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
|
||||
xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
|
||||
xTaskCreate( vCounterControlTask, "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_SEND", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RECV", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvChangePriorityWhenSuspendedTask, "1st_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
|
||||
xTaskCreate( prvChangePriorityHelperTask, "2nd_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xChangePriorityWhenSuspendedHandle );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just loops around incrementing the shared variable until the limit has been
|
||||
* reached. Once the limit has been reached it suspends itself.
|
||||
*/
|
||||
static void vLimitedIncrementTask( void * pvParameters )
|
||||
{
|
||||
unsigned long *pulCounter;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
the task. */
|
||||
pulCounter = ( unsigned long * ) pvParameters;
|
||||
|
||||
/* This will run before the control task, so the first thing it does is
|
||||
suspend - the control task will resume it when ready. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Just count up to a value then suspend. */
|
||||
( *pulCounter )++;
|
||||
|
||||
if( *pulCounter >= priMAX_COUNT )
|
||||
{
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just keep counting the shared variable up. The control task will suspend
|
||||
* this task when it wants.
|
||||
*/
|
||||
static void vContinuousIncrementTask( void * pvParameters )
|
||||
{
|
||||
unsigned long *pulCounter;
|
||||
unsigned portBASE_TYPE uxOurPriority;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
the task. */
|
||||
pulCounter = ( unsigned long * ) pvParameters;
|
||||
|
||||
/* Query our priority so we can raise it when exclusive access to the
|
||||
shared variable is required. */
|
||||
uxOurPriority = uxTaskPriorityGet( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Raise our priority above the controller task to ensure a context
|
||||
switch does not occur while we are accessing this variable. */
|
||||
vTaskPrioritySet( NULL, uxOurPriority + 1 );
|
||||
( *pulCounter )++;
|
||||
vTaskPrioritySet( NULL, uxOurPriority );
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Controller task as described above.
|
||||
*/
|
||||
static void vCounterControlTask( void * pvParameters )
|
||||
{
|
||||
unsigned long ulLastCounter;
|
||||
short sLoops;
|
||||
short sError = pdFALSE;
|
||||
const char * const pcTaskStartMsg = "Priority manipulation tasks started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Start with the counter at zero. */
|
||||
ulCounter = ( unsigned long ) 0;
|
||||
|
||||
/* First section : */
|
||||
|
||||
/* Check the continuous count task is running. */
|
||||
for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
|
||||
{
|
||||
/* Suspend the continuous count task so we can take a mirror of the
|
||||
shared variable without risk of corruption. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
ulLastCounter = ulCounter;
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
|
||||
/* Now delay to ensure the other task has processor time. */
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
/* Check the shared variable again. This time to ensure mutual
|
||||
exclusion the whole scheduler will be locked. This is just for
|
||||
demo purposes! */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
if( ulLastCounter == ulCounter )
|
||||
{
|
||||
/* The shared variable has not changed. There is a problem
|
||||
with the continuous count task so flag an error. */
|
||||
sError = pdTRUE;
|
||||
xTaskResumeAll();
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
|
||||
/* Second section: */
|
||||
|
||||
/* Suspend the continuous counter task so it stops accessing the shared variable. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
|
||||
/* Reset the variable. */
|
||||
ulCounter = ( unsigned long ) 0;
|
||||
|
||||
/* Resume the limited count task which has a higher priority than us.
|
||||
We should therefore not return from this call until the limited count
|
||||
task has suspended itself with a known value in the counter variable.
|
||||
The scheduler suspension is not necessary but is included for test
|
||||
purposes. */
|
||||
vTaskSuspendAll();
|
||||
vTaskResume( xLimitedIncrementHandle );
|
||||
xTaskResumeAll();
|
||||
|
||||
/* Does the counter variable have the expected value? */
|
||||
if( ulCounter != priMAX_COUNT )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If no errors have occurred then increment the check variable. */
|
||||
portENTER_CRITICAL();
|
||||
usCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Resume the continuous count task and do it all again. */
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vQueueSendWhenSuspendedTask( void *pvParameters )
|
||||
{
|
||||
static unsigned long ulValueToSend = ( unsigned long ) 0;
|
||||
const char * const pcTaskStartMsg = "Queue send while suspended task started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Queue send while suspended failed.\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* We must not block while the scheduler is suspended! */
|
||||
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
|
||||
{
|
||||
if( xSuspendedQueueSendError == pdFALSE )
|
||||
{
|
||||
xTaskResumeAll();
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
|
||||
xSuspendedQueueSendError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
++ulValueToSend;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vQueueReceiveWhenSuspendedTask( void *pvParameters )
|
||||
{
|
||||
static unsigned long ulExpectedValue = ( unsigned long ) 0, ulReceivedValue;
|
||||
const char * const pcTaskStartMsg = "Queue receive while suspended task started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Queue receive while suspended failed.\r\n";
|
||||
portBASE_TYPE xGotValue;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Suspending the scheduler here is fairly pointless and
|
||||
undesirable for a normal application. It is done here purely
|
||||
to test the scheduler. The inner xTaskResumeAll() should
|
||||
never return pdTRUE as the scheduler is still locked by the
|
||||
outer call. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
|
||||
}
|
||||
if( xTaskResumeAll() )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
} while( xGotValue == pdFALSE );
|
||||
|
||||
if( ulReceivedValue != ulExpectedValue )
|
||||
{
|
||||
if( xSuspendedQueueReceiveError == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
|
||||
++ulExpectedValue;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvChangePriorityWhenSuspendedTask( void *pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "Priority change when suspended task started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Priority change when suspended task failed.\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Start with the counter at 0 so we know what the counter should be
|
||||
when we check it next. */
|
||||
ulPrioritySetCounter = ( unsigned long ) 0;
|
||||
|
||||
/* Resume the helper task. At this time it has a priority lower than
|
||||
ours so no context switch should occur. */
|
||||
vTaskResume( xChangePriorityWhenSuspendedHandle );
|
||||
|
||||
/* Check to ensure the task just resumed has not executed. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned long ) 0 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Now try raising the priority while the scheduler is suspended. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, ( configMAX_PRIORITIES - 1 ) );
|
||||
|
||||
/* Again, even though the helper task has a priority greater than
|
||||
ours, it should not have executed yet because the scheduler is
|
||||
suspended. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned long ) 0 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
/* Now the scheduler has been resumed the helper task should
|
||||
immediately preempt us and execute. When it executes it will increment
|
||||
the ulPrioritySetCounter exactly once before suspending itself.
|
||||
|
||||
We should now always find the counter set to 1. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned long ) 1 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Delay until we try this again. */
|
||||
vTaskDelay( priSLEEP_TIME * 2 );
|
||||
|
||||
/* Set the priority of the helper task back ready for the next
|
||||
execution of this task. */
|
||||
vTaskSuspendAll();
|
||||
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, tskIDLE_PRIORITY );
|
||||
xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvChangePriorityHelperTask( void *pvParameters )
|
||||
{
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* This is the helper task for prvChangePriorityWhenSuspendedTask().
|
||||
It has it's priority raised and lowered. When it runs it simply
|
||||
increments the counter then suspends itself again. This allows
|
||||
prvChangePriorityWhenSuspendedTask() to know how many times it has
|
||||
executed. */
|
||||
ulPrioritySetCounter++;
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Called to check that all the created tasks are still running without error. */
|
||||
portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if it has been incremented
|
||||
since the last call. */
|
||||
static unsigned short usLastTaskCheck = ( unsigned short ) 0;
|
||||
portBASE_TYPE xReturn = pdTRUE;
|
||||
|
||||
/* Check the tasks are still running by ensuring the check variable
|
||||
is still incrementing. */
|
||||
|
||||
if( usCheckVariable == usLastTaskCheck )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueSendError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueReceiveError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xPriorityRaiseWhenSuspendedError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck = usCheckVariable;
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file exercises the event mechanism whereby more than one task is
|
||||
* blocked waiting for the same event.
|
||||
*
|
||||
* The demo creates five tasks - four 'event' tasks, and a controlling task.
|
||||
* The event tasks have various different priorities and all block on reading
|
||||
* the same queue. The controlling task writes data to the queue, then checks
|
||||
* to see which of the event tasks read the data from the queue. The
|
||||
* controlling task has the lowest priority of all the tasks so is guaranteed
|
||||
* to always get preempted immediately upon writing to the queue.
|
||||
*
|
||||
* By selectively suspending and resuming the event tasks the controlling task
|
||||
* can check that the highest priority task that is blocked on the queue is the
|
||||
* task that reads the posted data from the queue.
|
||||
*
|
||||
* Two of the event tasks share the same priority. When neither of these tasks
|
||||
* are suspended they should alternate - one reading one message from the queue,
|
||||
* the other the next message, etc.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "mevents.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo specific constants. */
|
||||
#define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )
|
||||
#define evtNUM_TASKS ( 4 )
|
||||
#define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 )
|
||||
#define evtNO_DELAY 0
|
||||
|
||||
/* Just indexes used to uniquely identify the tasks. Note that two tasks are
|
||||
'highest' priority. */
|
||||
#define evtHIGHEST_PRIORITY_INDEX_2 3
|
||||
#define evtHIGHEST_PRIORITY_INDEX_1 2
|
||||
#define evtMEDIUM_PRIORITY_INDEX 1
|
||||
#define evtLOWEST_PRIORITY_INDEX 0
|
||||
|
||||
/* Each event task increments one of these counters each time it reads data
|
||||
from the queue. */
|
||||
static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
|
||||
|
||||
/* Each time the controlling task posts onto the queue it increments the
|
||||
expected count of the task that it expected to read the data from the queue
|
||||
(i.e. the task with the highest priority that should be blocked on the queue).
|
||||
|
||||
xExpectedTaskCounters are incremented from the controlling task, and
|
||||
xTaskCounters are incremented from the individual event tasks - therefore
|
||||
comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
|
||||
correct task was unblocked by the post. */
|
||||
static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
|
||||
|
||||
/* Handles to the four event tasks. These are required to suspend and resume
|
||||
the tasks. */
|
||||
static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ];
|
||||
|
||||
/* The single queue onto which the controlling task posts, and the four event
|
||||
tasks block. */
|
||||
static QueueHandle_t xQueue;
|
||||
|
||||
/* Flag used to indicate whether or not an error has occurred at any time.
|
||||
An error is either the queue being full when not expected, or an unexpected
|
||||
task reading data from the queue. */
|
||||
static portBASE_TYPE xHealthStatus = pdPASS;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Function that implements the event task. This is created four times. */
|
||||
static void prvMultiEventTask( void *pvParameters );
|
||||
|
||||
/* Function that implements the controlling task. */
|
||||
static void prvEventControllerTask( void *pvParameters );
|
||||
|
||||
/* This is a utility function that posts data to the queue, then compares
|
||||
xExpectedTaskCounters with xTaskCounters to ensure everything worked as
|
||||
expected.
|
||||
|
||||
The event tasks all have higher priorities the controlling task. Therefore
|
||||
the controlling task will always get preempted between writhing to the queue
|
||||
and checking the task counters.
|
||||
|
||||
@param xExpectedTask The index to the task that the controlling task thinks
|
||||
should be the highest priority task waiting for data, and
|
||||
therefore the task that will unblock.
|
||||
|
||||
@param xIncrement The number of items that should be written to the queue.
|
||||
*/
|
||||
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement );
|
||||
|
||||
/* This is just incremented each cycle of the controlling tasks function so
|
||||
the main application can ensure the test is still running. */
|
||||
static portBASE_TYPE xCheckVariable = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMultiEventTasks( void )
|
||||
{
|
||||
/* Create the queue to be used for all the communications. */
|
||||
xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
|
||||
|
||||
/* Start the controlling task. This has the idle priority to ensure it is
|
||||
always preempted by the event tasks. */
|
||||
xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
/* Start the four event tasks. Note that two have priority 3, one
|
||||
priority 2 and the other priority 1. */
|
||||
xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMultiEventTask( void *pvParameters )
|
||||
{
|
||||
portBASE_TYPE *pxCounter;
|
||||
unsigned portBASE_TYPE uxDummy;
|
||||
const char * const pcTaskStartMsg = "Multi event task started.\r\n";
|
||||
|
||||
/* The variable this task will increment is passed in as a parameter. */
|
||||
pxCounter = ( portBASE_TYPE * ) pvParameters;
|
||||
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Block on the queue. */
|
||||
if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
|
||||
{
|
||||
/* We unblocked by reading the queue - so simply increment
|
||||
the counter specific to this task instance. */
|
||||
( *pxCounter )++;
|
||||
}
|
||||
else
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEventControllerTask( void *pvParameters )
|
||||
{
|
||||
const char * const pcTaskStartMsg = "Multi event controller task started.\r\n";
|
||||
portBASE_TYPE xDummy = 0;
|
||||
|
||||
/* Just to stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* All tasks are blocked on the queue. When a message is posted one of
|
||||
the two tasks that share the highest priority should unblock to read
|
||||
the queue. The next message written should unblock the other task with
|
||||
the same high priority, and so on in order. No other task should
|
||||
unblock to read data as they have lower priorities. */
|
||||
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* For the rest of these tests we don't need the second 'highest'
|
||||
priority task - so it is suspended. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
|
||||
|
||||
|
||||
|
||||
/* Now suspend the other highest priority task. The medium priority
|
||||
task will then be the task with the highest priority that remains
|
||||
blocked on the queue. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
|
||||
/* This time, when we post onto the queue we will expect the medium
|
||||
priority task to unblock and preempt us. */
|
||||
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
|
||||
|
||||
/* Now try resuming the highest priority task while the scheduler is
|
||||
suspended. The task should start executing as soon as the scheduler
|
||||
is resumed - therefore when we post to the queue again, the highest
|
||||
priority task should again preempt us. */
|
||||
vTaskSuspendAll();
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* Now we are going to suspend the high and medium priority tasks. The
|
||||
low priority task should then preempt us. Again the task suspension is
|
||||
done with the whole scheduler suspended just for test purposes. */
|
||||
vTaskSuspendAll();
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
|
||||
|
||||
/* Do the same basic test another few times - selectively suspending
|
||||
and resuming tasks and each time calling prvCheckTaskCounters() passing
|
||||
to the function the number of the task we expected to be unblocked by
|
||||
the post. */
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
vTaskSuspendAll(); /* Just for test. */
|
||||
vTaskSuspendAll(); /* Just for test. */
|
||||
vTaskSuspendAll(); /* Just for even more test. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
xTaskResumeAll();
|
||||
xTaskResumeAll();
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* Now a slight change, first suspend all tasks. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
|
||||
/* Now when we resume the low priority task and write to the queue 3
|
||||
times. We expect the low priority task to service the queue three
|
||||
times. */
|
||||
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
|
||||
|
||||
/* Again suspend all tasks (only the low priority task is not suspended
|
||||
already). */
|
||||
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
|
||||
/* This time we are going to suspend the scheduler, resume the low
|
||||
priority task, then resume the high priority task. In this state we
|
||||
will write to the queue three times. When the scheduler is resumed
|
||||
we expect the high priority task to service all three messages. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
|
||||
for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
|
||||
{
|
||||
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* The queue should not have been serviced yet!. The scheduler
|
||||
is still suspended. */
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
/* We should have been preempted by resuming the scheduler - so by the
|
||||
time we are running again we expect the high priority task to have
|
||||
removed three items from the queue. */
|
||||
xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* The medium priority and second high priority tasks are still
|
||||
suspended. Make sure to resume them before starting again. */
|
||||
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
|
||||
|
||||
/* Just keep incrementing to show the task is still executing. */
|
||||
xCheckVariable++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement )
|
||||
{
|
||||
portBASE_TYPE xDummy = 0;
|
||||
|
||||
/* Write to the queue the requested number of times. The data written is
|
||||
not important. */
|
||||
for( xDummy = 0; xDummy < xIncrement; xDummy++ )
|
||||
{
|
||||
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
|
||||
{
|
||||
/* Did not expect to ever find the queue full. */
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* All the tasks blocked on the queue have a priority higher than the
|
||||
controlling task. Writing to the queue will therefore have caused this
|
||||
task to be preempted. By the time this line executes the event task will
|
||||
have executed and incremented its counter. Increment the expected counter
|
||||
to the same value. */
|
||||
( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
|
||||
|
||||
/* Check the actual counts and expected counts really are the same. */
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
/* The counters were not the same. This means a task we did not expect
|
||||
to unblock actually did unblock. */
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreMultiEventTasksStillRunning( void )
|
||||
{
|
||||
static portBASE_TYPE xPreviousCheckVariable = 0;
|
||||
|
||||
/* Called externally to periodically check that this test is still
|
||||
operational. */
|
||||
|
||||
if( xPreviousCheckVariable == xCheckVariable )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
|
||||
xPreviousCheckVariable = xCheckVariable;
|
||||
|
||||
return xHealthStatus;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Creates eight tasks, each of which flash an LED at a different rate. The first
|
||||
* LED flashes every 125ms, the second every 250ms, the third every 375ms, etc.
|
||||
*
|
||||
* The LED flash tasks provide instant visual feedback. They show that the scheduler
|
||||
* is still operational.
|
||||
*
|
||||
* The PC port uses the standard parallel port for outputs, the Flashlite 186 port
|
||||
* uses IO port F.
|
||||
*
|
||||
* \page flashC flash.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than unsigned long.
|
||||
|
||||
Changes from V2.1.1
|
||||
|
||||
+ The stack size now uses configMINIMAL_STACK_SIZE.
|
||||
+ String constants made file scope to decrease stack depth on 8051 port.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "partest.h"
|
||||
#include "flash.h"
|
||||
#include "print.h"
|
||||
|
||||
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/* Structure used to pass parameters to the LED tasks. */
|
||||
typedef struct LED_PARAMETERS
|
||||
{
|
||||
unsigned portBASE_TYPE uxLED; /*< The output the task should use. */
|
||||
TickType_t xFlashRate; /*< The rate at which the LED should flash. */
|
||||
} xLEDParameters;
|
||||
|
||||
/* The task that is created eight times - each time with a different xLEDParaemtes
|
||||
structure passed in as the parameter. */
|
||||
static void vLEDFlashTask( void *pvParameters );
|
||||
|
||||
/* String to print if USE_STDIO is defined. */
|
||||
const char * const pcTaskStartMsg = "LED flash task started.\r\n";
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
unsigned portBASE_TYPE uxLEDTask;
|
||||
xLEDParameters *pxLEDParameters;
|
||||
const unsigned portBASE_TYPE uxNumOfLEDs = 8;
|
||||
const TickType_t xFlashRate = 125;
|
||||
|
||||
/* Create the eight tasks. */
|
||||
for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask )
|
||||
{
|
||||
/* Create and complete the structure used to pass parameters to the next
|
||||
created task. */
|
||||
pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) );
|
||||
pxLEDParameters->uxLED = uxLEDTask;
|
||||
pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( TickType_t ) uxLEDTask ) );
|
||||
pxLEDParameters->xFlashRate /= portTICK_PERIOD_MS;
|
||||
|
||||
/* Spawn the task. */
|
||||
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, ( void * ) pxLEDParameters, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vLEDFlashTask( void *pvParameters )
|
||||
{
|
||||
xLEDParameters *pxParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
pxParameters = ( xLEDParameters * ) pvParameters;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
/* Delay for half the flash period then turn the LED on. */
|
||||
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
|
||||
vParTestToggleLED( pxParameters->uxLED );
|
||||
|
||||
/* Delay for half the flash period then turn the LED off. */
|
||||
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
|
||||
vParTestToggleLED( pxParameters->uxLED );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.3
|
||||
|
||||
+ The created tasks now include calls to tskYIELD(), allowing them to be used
|
||||
with the cooperative scheduler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates eight tasks, each of which loops continuously performing an (emulated)
|
||||
* floating point calculation.
|
||||
*
|
||||
* All the tasks run at the idle priority and never block or yield. This causes
|
||||
* all eight tasks to time slice with the idle task. Running at the idle priority
|
||||
* means that these tasks will get pre-empted any time another task is ready to run
|
||||
* or a time slice occurs. More often than not the pre-emption will occur mid
|
||||
* calculation, creating a good test of the schedulers context switch mechanism - a
|
||||
* calculation producing an unexpected result could be a symptom of a corruption in
|
||||
* the context of a task.
|
||||
*
|
||||
* \page FlopC flop.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "flop.h"
|
||||
|
||||
#define mathSTACK_SIZE ( ( unsigned short ) 512 )
|
||||
#define mathNUMBER_OF_TASKS ( 8 )
|
||||
|
||||
/* Four tasks, each of which performs a different floating point calculation.
|
||||
Each of the four is created twice. */
|
||||
static void vCompetingMathTask1( void *pvParameters );
|
||||
static void vCompetingMathTask2( void *pvParameters );
|
||||
static void vCompetingMathTask3( void *pvParameters );
|
||||
static void vCompetingMathTask4( void *pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
task gets a calculation wrong it will
|
||||
stop incrementing its check variable. */
|
||||
static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask1( void *pvParameters )
|
||||
{
|
||||
portDOUBLE d1, d2, d3, d4;
|
||||
volatile unsigned short *pusTaskCheckVariable;
|
||||
const portDOUBLE dAnswer = ( 123.4567 + 2345.6789 ) * -918.222;
|
||||
const char * const pcTaskStartMsg = "Math task 1 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Math task 1 failed.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for(;;)
|
||||
{
|
||||
d1 = 123.4567;
|
||||
d2 = 2345.6789;
|
||||
d3 = -918.222;
|
||||
|
||||
d4 = ( d1 + d2 ) * d3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask2( void *pvParameters )
|
||||
{
|
||||
portDOUBLE d1, d2, d3, d4;
|
||||
volatile unsigned short *pusTaskCheckVariable;
|
||||
const portDOUBLE dAnswer = ( -389.38 / 32498.2 ) * -2.0001;
|
||||
const char * const pcTaskStartMsg = "Math task 2 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Math task 2 failed.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ;; )
|
||||
{
|
||||
d1 = -389.38;
|
||||
d2 = 32498.2;
|
||||
d3 = -2.0001;
|
||||
|
||||
d4 = ( d1 / d2 ) * d3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know
|
||||
this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask3( void *pvParameters )
|
||||
{
|
||||
portDOUBLE *pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile unsigned short *pusTaskCheckVariable;
|
||||
const unsigned short usArraySize = 250;
|
||||
unsigned short usPosition;
|
||||
const char * const pcTaskStartMsg = "Math task 3 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Math task 3 failed.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
pdArray[ usPosition ] = ( portDOUBLE ) usPosition + 5.5;
|
||||
dTotal1 += ( portDOUBLE ) usPosition + 5.5;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ usPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask4( void *pvParameters )
|
||||
{
|
||||
portDOUBLE *pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile unsigned short *pusTaskCheckVariable;
|
||||
const unsigned short usArraySize = 250;
|
||||
unsigned short usPosition;
|
||||
const char * const pcTaskStartMsg = "Math task 4 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Math task 4 failed.\r\n";
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
pdArray[ usPosition ] = ( portDOUBLE ) usPosition * 12.123;
|
||||
dTotal1 += ( portDOUBLE ) usPosition * 12.123;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ usPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreMathsTaskStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if they have been incremented
|
||||
since the last call. */
|
||||
static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
|
||||
portBASE_TYPE xReturn = pdTRUE, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
are still incrementing. */
|
||||
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.3
|
||||
|
||||
+ The created tasks now include calls to tskYIELD(), allowing them to be used
|
||||
with the cooperative scheduler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This does the same as flop. c, but uses variables of type long instead of
|
||||
* type double.
|
||||
*
|
||||
* As with flop. c, the tasks created in this file are a good test of the
|
||||
* scheduler context switch mechanism. The processor has to access 32bit
|
||||
* variables in two or four chunks (depending on the processor). The low
|
||||
* priority of these tasks means there is a high probability that a context
|
||||
* switch will occur mid calculation. See the flop. c documentation for
|
||||
* more information.
|
||||
*
|
||||
* \page IntegerC integer.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.1
|
||||
|
||||
+ The constants used in the calculations are larger to ensure the
|
||||
optimiser does not truncate them to 16 bits.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "integer.h"
|
||||
|
||||
#define intgSTACK_SIZE ( ( unsigned short ) 256 )
|
||||
#define intgNUMBER_OF_TASKS ( 8 )
|
||||
|
||||
/* Four tasks, each of which performs a different calculation on four byte
|
||||
variables. Each of the four is created twice. */
|
||||
static void vCompeteingIntMathTask1( void *pvParameters );
|
||||
static void vCompeteingIntMathTask2( void *pvParameters );
|
||||
static void vCompeteingIntMathTask3( void *pvParameters );
|
||||
static void vCompeteingIntMathTask4( void *pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
task gets a calculation wrong it will stop incrementing its check variable. */
|
||||
static volatile unsigned short usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompeteingIntMathTask1, "IntMath1", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask2, "IntMath2", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask3, "IntMath3", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask4, "IntMath4", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask1, "IntMath5", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask2, "IntMath6", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask3, "IntMath7", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask4, "IntMath8", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask1( void *pvParameters )
|
||||
{
|
||||
long l1, l2, l3, l4;
|
||||
short sError = pdFALSE;
|
||||
volatile unsigned short *pusTaskCheckVariable;
|
||||
const long lAnswer = ( ( long ) 74565L + ( long ) 1234567L ) * ( long ) -918L;
|
||||
const char * const pcTaskStartMsg = "Integer math task 1 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for(;;)
|
||||
{
|
||||
l1 = ( long ) 74565L;
|
||||
l2 = ( long ) 1234567L;
|
||||
l3 = ( long ) -918L;
|
||||
|
||||
l4 = ( l1 + l2 ) * l3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( l4 != lAnswer )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask2( void *pvParameters )
|
||||
{
|
||||
long l1, l2, l3, l4;
|
||||
short sError = pdFALSE;
|
||||
volatile unsigned short *pusTaskCheckVariable;
|
||||
const long lAnswer = ( ( long ) -389000L / ( long ) 329999L ) * ( long ) -89L;
|
||||
const char * const pcTaskStartMsg = "Integer math task 2 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ;; )
|
||||
{
|
||||
l1 = -389000L;
|
||||
l2 = 329999L;
|
||||
l3 = -89L;
|
||||
|
||||
l4 = ( l1 / l2 ) * l3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( l4 != lAnswer )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask3( void *pvParameters )
|
||||
{
|
||||
long *plArray, lTotal1, lTotal2;
|
||||
short sError = pdFALSE;
|
||||
volatile unsigned short *pusTaskCheckVariable;
|
||||
const unsigned short usArraySize = ( unsigned short ) 250;
|
||||
unsigned short usPosition;
|
||||
const char * const pcTaskStartMsg = "Integer math task 3 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Integer math task 3 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Create the array we are going to use for our check calculation. */
|
||||
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
|
||||
|
||||
/* Keep filling the array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
lTotal1 = ( long ) 0;
|
||||
lTotal2 = ( long ) 0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
plArray[ usPosition ] = ( long ) usPosition + ( long ) 5;
|
||||
lTotal1 += ( long ) usPosition + ( long ) 5;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
lTotal2 += plArray[ usPosition ];
|
||||
}
|
||||
|
||||
if( lTotal1 != lTotal2 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask4( void *pvParameters )
|
||||
{
|
||||
long *plArray, lTotal1, lTotal2;
|
||||
short sError = pdFALSE;
|
||||
volatile unsigned short *pusTaskCheckVariable;
|
||||
const unsigned short usArraySize = 250;
|
||||
unsigned short usPosition;
|
||||
const char * const pcTaskStartMsg = "Integer math task 4 started.\r\n";
|
||||
const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
|
||||
|
||||
/* Create the array we are going to use for our check calculation. */
|
||||
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
|
||||
|
||||
/* Keep filling the array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
lTotal1 = ( long ) 0;
|
||||
lTotal2 = ( long ) 0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
plArray[ usPosition ] = ( long ) usPosition * ( long ) 12;
|
||||
lTotal1 += ( long ) usPosition * ( long ) 12;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
lTotal2 += plArray[ usPosition ];
|
||||
}
|
||||
|
||||
|
||||
if( lTotal1 != lTotal2 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if they have been incremented
|
||||
since the last call. */
|
||||
static unsigned short usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
|
||||
portBASE_TYPE xReturn = pdTRUE, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
are still incrementing. */
|
||||
for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Manages a queue of strings that are waiting to be displayed. This is used to
|
||||
* ensure mutual exclusion of console output.
|
||||
*
|
||||
* A task wishing to display a message will call vPrintDisplayMessage (), with a
|
||||
* pointer to the string as the parameter. The pointer is posted onto the
|
||||
* xPrintQueue queue.
|
||||
*
|
||||
* The task spawned in main. c blocks on xPrintQueue. When a message becomes
|
||||
* available it calls pcPrintGetNextMessage () to obtain a pointer to the next
|
||||
* string, then uses the functions defined in the portable layer FileIO. c to
|
||||
* display the message.
|
||||
*
|
||||
* <b>NOTE:</b>
|
||||
* Using console IO can disrupt real time performance - depending on the port.
|
||||
* Standard C IO routines are not designed for real time applications. While
|
||||
* standard IO is useful for demonstration and debugging an alternative method
|
||||
* should be used if you actually require console IO as part of your application.
|
||||
*
|
||||
* \page PrintC print.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than unsigned long.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "print.h"
|
||||
|
||||
static QueueHandle_t xPrintQueue;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPrintInitialise( void )
|
||||
{
|
||||
const unsigned portBASE_TYPE uxQueueSize = 20;
|
||||
|
||||
/* Create the queue on which errors will be reported. */
|
||||
xPrintQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( char * ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPrintDisplayMessage( const char * const * ppcMessageToSend )
|
||||
{
|
||||
#ifdef USE_STDIO
|
||||
xQueueSend( xPrintQueue, ( void * ) ppcMessageToSend, ( TickType_t ) 0 );
|
||||
#else
|
||||
/* Stop warnings. */
|
||||
( void ) ppcMessageToSend;
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
const char *pcPrintGetNextMessage( TickType_t xPrintRate )
|
||||
{
|
||||
char *pcMessage;
|
||||
|
||||
if( xQueueReceive( xPrintQueue, &pcMessage, xPrintRate ) == pdPASS )
|
||||
{
|
||||
return pcMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates two sets of two tasks. The tasks within a set share a variable, access
|
||||
* to which is guarded by a semaphore.
|
||||
*
|
||||
* Each task starts by attempting to obtain the semaphore. On obtaining a
|
||||
* semaphore a task checks to ensure that the guarded variable has an expected
|
||||
* value. It then clears the variable to zero before counting it back up to the
|
||||
* expected value in increments of 1. After each increment the variable is checked
|
||||
* to ensure it contains the value to which it was just set. When the starting
|
||||
* value is again reached the task releases the semaphore giving the other task in
|
||||
* the set a chance to do exactly the same thing. The starting value is high
|
||||
* enough to ensure that a tick is likely to occur during the incrementing loop.
|
||||
*
|
||||
* An error is flagged if at any time during the process a shared variable is
|
||||
* found to have a value other than that expected. Such an occurrence would
|
||||
* suggest an error in the mutual exclusion mechanism by which access to the
|
||||
* variable is restricted.
|
||||
*
|
||||
* The first set of two tasks poll their semaphore. The second set use blocking
|
||||
* calls.
|
||||
*
|
||||
* \page SemTestC semtest.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.0:
|
||||
|
||||
+ The tasks that operate at the idle priority now use a lower expected
|
||||
count than those running at a higher priority. This prevents the low
|
||||
priority tasks from signaling an error because they have not been
|
||||
scheduled enough time for each of them to count the shared variable to
|
||||
the high value.
|
||||
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than unsigned long.
|
||||
|
||||
Changes from V2.1.1
|
||||
|
||||
+ The stack size now uses configMINIMAL_STACK_SIZE.
|
||||
+ String constants made file scope to decrease stack depth on 8051 port.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "semtest.h"
|
||||
#include "print.h"
|
||||
|
||||
/* The value to which the shared variables are counted. */
|
||||
#define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xfff )
|
||||
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xff )
|
||||
|
||||
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
#define semtstNUM_TASKS ( 4 )
|
||||
|
||||
#define semtstDELAY_FACTOR ( ( TickType_t ) 10 )
|
||||
|
||||
/* The task function as described at the top of the file. */
|
||||
static void prvSemaphoreTest( void *pvParameters );
|
||||
|
||||
/* Structure used to pass parameters to each task. */
|
||||
typedef struct SEMAPHORE_PARAMETERS
|
||||
{
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
volatile unsigned long *pulSharedVariable;
|
||||
TickType_t xBlockTime;
|
||||
} xSemaphoreParameters;
|
||||
|
||||
/* Variables used to check that all the tasks are still running without errors. */
|
||||
static volatile short sCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
static volatile short sNextCheckVariable = 0;
|
||||
|
||||
/* Strings to print if USE_STDIO is defined. */
|
||||
const char * const pcPollingSemaphoreTaskError = "Guarded shared variable in unexpected state.\r\n";
|
||||
const char * const pcSemaphoreTaskStart = "Guarded shared variable task started.\r\n";
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters;
|
||||
const TickType_t xBlockTime = ( TickType_t ) 100;
|
||||
|
||||
/* Create the structure used to pass parameters to the first two tasks. */
|
||||
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
|
||||
if( pxFirstSemaphoreParameters != NULL )
|
||||
{
|
||||
/* Create the semaphore used by the first two tasks. */
|
||||
vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );
|
||||
|
||||
if( pxFirstSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
/* Create the variable which is to be shared by the first two tasks. */
|
||||
pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
|
||||
|
||||
/* Initialise the share variable to the value the tasks expect. */
|
||||
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
|
||||
/* The first two tasks do not block on semaphore calls. */
|
||||
pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0;
|
||||
|
||||
/* Spawn the first two tasks. As they poll they operate at the idle priority. */
|
||||
xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* Do exactly the same to create the second set of tasks, only this time
|
||||
provide a block time for the semaphore calls. */
|
||||
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
if( pxSecondSemaphoreParameters != NULL )
|
||||
{
|
||||
vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
|
||||
|
||||
if( pxSecondSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
|
||||
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
|
||||
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS;
|
||||
|
||||
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSemaphoreTest( void *pvParameters )
|
||||
{
|
||||
xSemaphoreParameters *pxParameters;
|
||||
volatile unsigned long *pulSharedVariable, ulExpectedValue;
|
||||
unsigned long ulCounter;
|
||||
short sError = pdFALSE, sCheckVariableToUse;
|
||||
|
||||
/* See which check variable to use. sNextCheckVariable is not semaphore
|
||||
protected! */
|
||||
portENTER_CRITICAL();
|
||||
sCheckVariableToUse = sNextCheckVariable;
|
||||
sNextCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcSemaphoreTaskStart );
|
||||
|
||||
/* A structure is passed in as the parameter. This contains the shared
|
||||
variable being guarded. */
|
||||
pxParameters = ( xSemaphoreParameters * ) pvParameters;
|
||||
pulSharedVariable = pxParameters->pulSharedVariable;
|
||||
|
||||
/* If we are blocking we use a much higher count to ensure loads of context
|
||||
switches occur during the count. */
|
||||
if( pxParameters->xBlockTime > ( TickType_t ) 0 )
|
||||
{
|
||||
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try to obtain the semaphore. */
|
||||
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
/* We have the semaphore and so expect any other tasks using the
|
||||
shared variable to have left it in the state we expect to find
|
||||
it. */
|
||||
if( *pulSharedVariable != ulExpectedValue )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
/* Clear the variable, then count it back up to the expected value
|
||||
before releasing the semaphore. Would expect a context switch or
|
||||
two during this time. */
|
||||
for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
|
||||
{
|
||||
*pulSharedVariable = ulCounter;
|
||||
if( *pulSharedVariable != ulCounter )
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
}
|
||||
sError = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the semaphore, and if no errors have occurred increment the check
|
||||
variable. */
|
||||
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
if( sCheckVariableToUse < semtstNUM_TASKS )
|
||||
{
|
||||
( sCheckVariables[ sCheckVariableToUse ] )++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a block time then we are running at a priority higher
|
||||
than the idle priority. This task takes a long time to complete
|
||||
a cycle (deliberately so to test the guarding) so will be starving
|
||||
out lower priority tasks. Block for some time to allow give lower
|
||||
priority tasks some processor time. */
|
||||
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pxParameters->xBlockTime == ( TickType_t ) 0 )
|
||||
{
|
||||
/* We have not got the semaphore yet, so no point using the
|
||||
processor. We are not blocking when attempting to obtain the
|
||||
semaphore. */
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
portBASE_TYPE xTask, xReturn = pdTRUE;
|
||||
|
||||
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
|
||||
{
|
||||
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,681 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some test scenarios that ensure tasks respond correctly
|
||||
* to xTaskAbortDelay() calls.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include "limits.h"
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
#include "event_groups.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "AbortDelay.h"
|
||||
|
||||
/* This file can only be used if the functionality it tests is included in the
|
||||
build. Remove the whole file if this is not the case. */
|
||||
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||
|
||||
#if( INCLUDE_xTaskGetHandle != 1 )
|
||||
#error This test file uses the xTaskGetHandle() API function so INCLUDE_xTaskGetHandle must be set to 1 in FreeRTOSConfig.h.
|
||||
#endif
|
||||
|
||||
/* Task priorities. Allow these to be overridden. */
|
||||
#ifndef abtCONTROLLING_PRIORITY
|
||||
#define abtCONTROLLING_PRIORITY ( configMAX_PRIORITIES - 3 )
|
||||
#endif
|
||||
|
||||
#ifndef abtBLOCKING_PRIORITY
|
||||
#define abtBLOCKING_PRIORITY ( configMAX_PRIORITIES - 2 )
|
||||
#endif
|
||||
|
||||
/* The tests that are performed. */
|
||||
#define abtNOTIFY_WAIT_ABORTS 0
|
||||
#define abtNOTIFY_TAKE_ABORTS 1
|
||||
#define abtDELAY_ABORTS 2
|
||||
#define abtDELAY_UNTIL_ABORTS 3
|
||||
#define abtSEMAPHORE_TAKE_ABORTS 4
|
||||
#define abtEVENT_GROUP_ABORTS 5
|
||||
#define abtQUEUE_SEND_ABORTS 6
|
||||
#define abtMAX_TESTS 7
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The two test tasks. The controlling task specifies which test to executed.
|
||||
* More information is provided in the comments within the tasks.
|
||||
*/
|
||||
static void prvControllingTask( void *pvParameters );
|
||||
static void prvBlockingTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Test functions called by the blocking task. Each function follows the same
|
||||
* pattern, but the way the task blocks is different in each case.
|
||||
*
|
||||
* In each function three blocking calls are made. The first and third
|
||||
* blocking call is expected to time out, while the middle blocking call is
|
||||
* expected to be aborted by the controlling task half way through the block
|
||||
* time.
|
||||
*/
|
||||
static void prvTestAbortingTaskNotifyWait( void );
|
||||
static void prvTestAbortingTaskNotifyTake( void );
|
||||
static void prvTestAbortingTaskDelay( void );
|
||||
static void prvTestAbortingTaskDelayUntil( void );
|
||||
static void prvTestAbortingSemaphoreTake( void );
|
||||
static void prvTestAbortingEventGroupWait( void );
|
||||
static void prvTestAbortingQueueSend( void );
|
||||
|
||||
/*
|
||||
* Checks the amount of time a task spent in the Blocked state is within the
|
||||
* expected bounds.
|
||||
*/
|
||||
static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime, TickType_t xExpectedBlockTime );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Used to ensure that tasks are still executing without error. */
|
||||
static volatile BaseType_t xControllingCycles = 0, xBlockingCycles = 0;
|
||||
static volatile BaseType_t xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Each task needs to know the other tasks handle so they can send signals to
|
||||
each other. The handle is obtained from the task's name. */
|
||||
static const char *pcControllingTaskName = "AbtCtrl", *pcBlockingTaskName = "AbtBlk";
|
||||
|
||||
/* The maximum amount of time a task will block for. */
|
||||
const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 100 );
|
||||
const TickType_t xHalfMaxBlockTime = pdMS_TO_TICKS( 50 );
|
||||
|
||||
/* The actual block time is dependent on the priority of other tasks in the
|
||||
system so the actual block time might be greater than that expected, but it
|
||||
should be within an acceptable upper bound. */
|
||||
const TickType_t xAllowableMargin = pdMS_TO_TICKS( 7 );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateAbortDelayTasks( void )
|
||||
{
|
||||
/* Create the two test tasks described above. */
|
||||
xTaskCreate( prvControllingTask, pcControllingTaskName, configMINIMAL_STACK_SIZE, NULL, abtCONTROLLING_PRIORITY, NULL );
|
||||
xTaskCreate( prvBlockingTask, pcBlockingTaskName, configMINIMAL_STACK_SIZE, NULL, abtBLOCKING_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvControllingTask( void *pvParameters )
|
||||
{
|
||||
TaskHandle_t xBlockingTask;
|
||||
uint32_t ulTestToPerform = abtNOTIFY_WAIT_ABORTS;
|
||||
TickType_t xTimeAtStart;
|
||||
const TickType_t xStartMargin = 2UL;
|
||||
|
||||
/* Just to remove compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
xBlockingTask = xTaskGetHandle( pcBlockingTaskName );
|
||||
configASSERT( xBlockingTask );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Tell the secondary task to perform the next test. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
xTaskNotify( xBlockingTask, ulTestToPerform, eSetValueWithOverwrite );
|
||||
|
||||
/* The secondary task has a higher priority, so will now be in the
|
||||
Blocked state to wait for a maximum of xMaxBlockTime. It expects that
|
||||
period to complete with a timeout. It will then block for
|
||||
xMaxBlockTimeAgain, but this time it expects to the block time to abort
|
||||
half way through. Block until it is time to send the abort to the
|
||||
secondary task. xStartMargin is used because this task takes timing
|
||||
from the beginning of the test, whereas the blocking task takes timing
|
||||
from the entry into the Blocked state - and as the tasks run at
|
||||
different priorities, there may be some discrepancy. Also, temporarily
|
||||
raise the priority of the controlling task to that of the blocking
|
||||
task to minimise discrepancies. */
|
||||
vTaskPrioritySet( NULL, abtBLOCKING_PRIORITY );
|
||||
vTaskDelay( xMaxBlockTime + xHalfMaxBlockTime + xStartMargin );
|
||||
xTaskAbortDelay( xBlockingTask );
|
||||
|
||||
/* Reset the priority to the normal controlling priority. */
|
||||
vTaskPrioritySet( NULL, abtCONTROLLING_PRIORITY );
|
||||
|
||||
/* Now wait to be notified that the secondary task has completed its
|
||||
test. */
|
||||
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||
|
||||
/* Did the entire test run for the expected time, which is two full
|
||||
block times plus the half block time caused by calling
|
||||
xTaskAbortDelay()? */
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, ( xMaxBlockTime + xMaxBlockTime + xHalfMaxBlockTime ) );
|
||||
|
||||
/* Move onto the next test. */
|
||||
ulTestToPerform++;
|
||||
|
||||
if( ulTestToPerform >= abtMAX_TESTS )
|
||||
{
|
||||
ulTestToPerform = 0;
|
||||
}
|
||||
|
||||
/* To indicate this task is still executing. */
|
||||
xControllingCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvBlockingTask( void *pvParameters )
|
||||
{
|
||||
TaskHandle_t xControllingTask;
|
||||
uint32_t ulNotificationValue;
|
||||
const uint32_t ulMax = 0xffffffffUL;
|
||||
|
||||
/* Just to remove compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
xControllingTask = xTaskGetHandle( pcControllingTaskName );
|
||||
configASSERT( xControllingTask );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait to be notified of the test that is to be performed next. */
|
||||
xTaskNotifyWait( 0, ulMax, &ulNotificationValue, portMAX_DELAY );
|
||||
|
||||
switch( ulNotificationValue )
|
||||
{
|
||||
case abtNOTIFY_WAIT_ABORTS:
|
||||
prvTestAbortingTaskNotifyWait();
|
||||
break;
|
||||
|
||||
case abtNOTIFY_TAKE_ABORTS:
|
||||
prvTestAbortingTaskNotifyTake();
|
||||
break;
|
||||
|
||||
case abtDELAY_ABORTS:
|
||||
prvTestAbortingTaskDelay();
|
||||
break;
|
||||
|
||||
case abtDELAY_UNTIL_ABORTS:
|
||||
prvTestAbortingTaskDelayUntil();
|
||||
break;
|
||||
|
||||
case abtSEMAPHORE_TAKE_ABORTS:
|
||||
prvTestAbortingSemaphoreTake();
|
||||
break;
|
||||
|
||||
case abtEVENT_GROUP_ABORTS:
|
||||
prvTestAbortingEventGroupWait();
|
||||
break;
|
||||
|
||||
case abtQUEUE_SEND_ABORTS:
|
||||
prvTestAbortingQueueSend();
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Should not get here. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Let the primary task know the test is complete. */
|
||||
xTaskNotifyGive( xControllingTask );
|
||||
|
||||
/* To indicate this task is still executing. */
|
||||
xBlockingCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingTaskDelayUntil( void )
|
||||
{
|
||||
TickType_t xTimeAtStart, xLastBlockTime;
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* Take a copy of the time as it is updated in the call to
|
||||
vTaskDelayUntil() but its original value is needed to determine the actual
|
||||
time spend in the Blocked state. */
|
||||
xLastBlockTime = xTimeAtStart;
|
||||
|
||||
/* This first delay should just time out. */
|
||||
vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
through. Again take a copy of the time as it is updated in the call to
|
||||
vTaskDelayUntil() buts its original value is needed to determine the amount
|
||||
of time actually spent in the Blocked state. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
xLastBlockTime = xTimeAtStart;
|
||||
vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* As with the other tests, the third block period should not time out. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
xLastBlockTime = xTimeAtStart;
|
||||
vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingTaskDelay( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
vTaskDelay( xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
through. */
|
||||
vTaskDelay( xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
vTaskDelay( xMaxBlockTime );
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingTaskNotifyTake( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
uint32_t ulReturn;
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
|
||||
if( ulReturn != 0 )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
through. */
|
||||
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
|
||||
if( ulReturn != 0 )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
|
||||
if( ulReturn != 0 )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingEventGroupWait( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
EventGroupHandle_t xEventGroup;
|
||||
EventBits_t xBitsToWaitFor = ( EventBits_t ) 0x01, xReturn;
|
||||
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
static StaticEventGroup_t xEventGroupBuffer;
|
||||
|
||||
/* Create the event group. Statically allocated memory is used so the
|
||||
creation cannot fail. */
|
||||
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
|
||||
}
|
||||
#else
|
||||
{
|
||||
xEventGroup = xEventGroupCreate();
|
||||
configASSERT( xEventGroup );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
through. */
|
||||
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
|
||||
if( xReturn != 0x00 )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Not really necessary in this case, but for completeness. */
|
||||
vEventGroupDelete( xEventGroup );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingQueueSend( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
BaseType_t xReturn;
|
||||
const UBaseType_t xQueueLength = ( UBaseType_t ) 1;
|
||||
QueueHandle_t xQueue;
|
||||
uint8_t ucItemToQueue;
|
||||
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
static StaticQueue_t xQueueBuffer;
|
||||
static uint8_t ucQueueStorage[ sizeof( uint8_t ) ];
|
||||
|
||||
/* Create the queue. Statically allocated memory is used so the
|
||||
creation cannot fail. */
|
||||
xQueue = xQueueCreateStatic( xQueueLength, sizeof( uint8_t ), ucQueueStorage, &xQueueBuffer );
|
||||
}
|
||||
#else
|
||||
{
|
||||
xQueue = xQueueCreate( xQueueLength, sizeof( uint8_t ) );
|
||||
configASSERT( xQueue );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This function tests aborting when in the blocked state waiting to send,
|
||||
so the queue must be full. There is only one space in the queue. */
|
||||
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
|
||||
if( xReturn != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
through. */
|
||||
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Not really necessary in this case, but for completeness. */
|
||||
vQueueDelete( xQueue );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingSemaphoreTake( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
BaseType_t xReturn;
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
static StaticSemaphore_t xSemaphoreBuffer;
|
||||
|
||||
/* Create the semaphore. Statically allocated memory is used so the
|
||||
creation cannot fail. */
|
||||
xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
|
||||
}
|
||||
#else
|
||||
{
|
||||
xSemaphore = xSemaphoreCreateBinary();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
through. */
|
||||
xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Not really necessary in this case, but for completeness. */
|
||||
vSemaphoreDelete( xSemaphore );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTestAbortingTaskNotifyWait( void )
|
||||
{
|
||||
TickType_t xTimeAtStart;
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This first delay should just time out. */
|
||||
xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This second delay should be aborted by the primary task half way
|
||||
through. */
|
||||
xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
|
||||
|
||||
/* Note the time before the delay so the length of the delay is known. */
|
||||
xTimeAtStart = xTaskGetTickCount();
|
||||
|
||||
/* This third delay should just time out again. */
|
||||
xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );
|
||||
if( xReturn != pdFALSE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime, TickType_t xExpectedBlockTime )
|
||||
{
|
||||
TickType_t xTimeNow, xActualBlockTime;
|
||||
|
||||
xTimeNow = xTaskGetTickCount();
|
||||
xActualBlockTime = xTimeNow - xStartTime;
|
||||
|
||||
/* The actual block time should not be less than the expected block time. */
|
||||
if( xActualBlockTime < xExpectedBlockTime )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* The actual block time can be greater than the expected block time, as it
|
||||
depends on the priority of the other tasks, but it should be within an
|
||||
acceptable margin. */
|
||||
if( xActualBlockTime > ( xExpectedBlockTime + xAllowableMargin ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreAbortDelayTestTasksStillRunning( void )
|
||||
{
|
||||
static BaseType_t xLastControllingCycleCount = 0, xLastBlockingCycleCount = 0;
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
/* Have both tasks performed at least one cycle since this function was
|
||||
last called? */
|
||||
if( xControllingCycles == xLastControllingCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xBlockingCycles == xLastBlockingCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xErrorOccurred == pdTRUE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
xLastBlockingCycleCount = xBlockingCycles;
|
||||
xLastControllingCycleCount = xControllingCycles;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif /* INCLUDE_xTaskAbortDelay == 1 */
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates six tasks that operate on three queues as follows:
|
||||
*
|
||||
* The first two tasks send and receive an incrementing number to/from a queue.
|
||||
* One task acts as a producer and the other as the consumer. The consumer is a
|
||||
* higher priority than the producer and is set to block on queue reads. The queue
|
||||
* only has space for one item - as soon as the producer posts a message on the
|
||||
* queue the consumer will unblock, pre-empt the producer, and remove the item.
|
||||
*
|
||||
* The second two tasks work the other way around. Again the queue used only has
|
||||
* enough space for one item. This time the consumer has a lower priority than the
|
||||
* producer. The producer will try to post on the queue blocking when the queue is
|
||||
* full. When the consumer wakes it will remove the item from the queue, causing
|
||||
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
|
||||
* queue.
|
||||
*
|
||||
* The last two tasks use the same queue producer and consumer functions. This time the queue has
|
||||
* enough space for lots of items and the tasks operate at the same priority. The
|
||||
* producer will execute, placing items into the queue. The consumer will start
|
||||
* executing when either the queue becomes full (causing the producer to block) or
|
||||
* a context switch occurs (tasks of the same priority will time slice).
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "BlockQ.h"
|
||||
|
||||
#define blckqSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define blckqNUM_TASK_SETS ( 3 )
|
||||
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
|
||||
#error This example cannot be used if dynamic allocation is not allowed.
|
||||
#endif
|
||||
|
||||
/* Structure used to pass parameters to the blocking queue tasks. */
|
||||
typedef struct BLOCKING_QUEUE_PARAMETERS
|
||||
{
|
||||
QueueHandle_t xQueue; /*< The queue to be used by the task. */
|
||||
TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */
|
||||
volatile short *psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
|
||||
} xBlockingQueueParameters;
|
||||
|
||||
/* Task function that creates an incrementing number and posts it on a queue. */
|
||||
static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
|
||||
|
||||
/* Task function that removes the incrementing number from a queue and checks that
|
||||
it is the expected number. */
|
||||
static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters );
|
||||
|
||||
/* Variables which are incremented each time an item is removed from a queue, and
|
||||
found to be the expected value.
|
||||
These are used to check that the tasks are still running. */
|
||||
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
|
||||
|
||||
/* Variable which are incremented each time an item is posted on a queue. These
|
||||
are used to check that the tasks are still running. */
|
||||
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartBlockingQueueTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2;
|
||||
xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4;
|
||||
xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6;
|
||||
const UBaseType_t uxQueueSize1 = 1, uxQueueSize5 = 5;
|
||||
const TickType_t xBlockTime = pdMS_TO_TICKS( ( TickType_t ) 1000 );
|
||||
const TickType_t xDontBlock = ( TickType_t ) 0;
|
||||
|
||||
/* Create the first two tasks as described at the top of the file. */
|
||||
|
||||
/* First create the structure used to pass parameters to the consumer tasks. */
|
||||
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Create the queue used by the first two tasks to pass the incrementing number.
|
||||
Pass a pointer to the queue in the parameter structure. */
|
||||
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) );
|
||||
|
||||
/* The consumer is created first so gets a block time as described above. */
|
||||
pxQueueParameters1->xBlockTime = xBlockTime;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check it
|
||||
is still running. */
|
||||
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
|
||||
|
||||
/* Create the structure used to pass parameters to the producer task. */
|
||||
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Pass the queue to this task also, using the parameter structure. */
|
||||
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
|
||||
|
||||
/* The producer is not going to block - as soon as it posts the consumer will
|
||||
wake and remove the item so the producer should always have room to post. */
|
||||
pxQueueParameters2->xBlockTime = xDontBlock;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check
|
||||
it is still running. */
|
||||
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
|
||||
|
||||
|
||||
/* Note the producer has a lower priority than the consumer when the tasks are
|
||||
spawned. */
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the second two tasks as described at the top of the file. This uses
|
||||
the same mechanism but reverses the task priorities. */
|
||||
|
||||
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) );
|
||||
pxQueueParameters3->xBlockTime = xDontBlock;
|
||||
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
|
||||
|
||||
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
|
||||
pxQueueParameters4->xBlockTime = xBlockTime;
|
||||
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the last two tasks as described above. The mechanism is again just
|
||||
the same. This time both parameter structures are given a block time. */
|
||||
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( UBaseType_t ) sizeof( uint16_t ) );
|
||||
pxQueueParameters5->xBlockTime = xBlockTime;
|
||||
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
|
||||
|
||||
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
|
||||
pxQueueParameters6->xBlockTime = xBlockTime;
|
||||
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )
|
||||
{
|
||||
uint16_t usValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
short sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
|
||||
{
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully posted a message, so increment the variable
|
||||
used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the variable we are going to post next time round. The
|
||||
consumer will expect the numbers to follow in numerical order. */
|
||||
++usValue;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
|
||||
{
|
||||
uint16_t usData, usExpectedValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
short sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* Catch-up. */
|
||||
usExpectedValue = usData;
|
||||
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully received a message, so increment the
|
||||
variable used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the value we expect to remove from the queue next time
|
||||
round. */
|
||||
++usExpectedValue;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
if( pxQueueParameters->xBlockTime == 0 )
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreBlockingQueuesStillRunning( void )
|
||||
{
|
||||
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
|
||||
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
|
||||
BaseType_t xReturn = pdPASS, xTasks;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
bits and we are only reading them. We also only care to see if they have
|
||||
changed or not.
|
||||
|
||||
Loop through each check variable to and return pdFALSE if any are found not
|
||||
to have changed since the last call. */
|
||||
|
||||
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
|
||||
{
|
||||
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
|
||||
|
||||
|
||||
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,788 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
|
||||
* including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
|
||||
* mutex behaviour.
|
||||
*
|
||||
* See the comments above the prvSendFrontAndBackTest() and
|
||||
* prvLowPriorityMutexTask() prototypes below for more information.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "GenQTest.h"
|
||||
|
||||
#define genqQUEUE_LENGTH ( 5 )
|
||||
#define intsemNO_BLOCK ( 0 )
|
||||
|
||||
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
|
||||
* macros by using both to fill a queue, then reading from the queue to
|
||||
* check the resultant queue order is as expected. Queue data is also
|
||||
* peeked.
|
||||
*/
|
||||
static void prvSendFrontAndBackTest( void *pvParameters );
|
||||
|
||||
/*
|
||||
* The following three tasks are used to demonstrate the mutex behaviour.
|
||||
* Each task is given a different priority to demonstrate the priority
|
||||
* inheritance mechanism.
|
||||
*
|
||||
* The low priority task obtains a mutex. After this a high priority task
|
||||
* attempts to obtain the same mutex, causing its priority to be inherited
|
||||
* by the low priority task. The task with the inherited high priority then
|
||||
* resumes a medium priority task to ensure it is not blocked by the medium
|
||||
* priority task while it holds the inherited high priority. Once the mutex
|
||||
* is returned the task with the inherited priority returns to its original
|
||||
* low priority, and is therefore immediately preempted by first the high
|
||||
* priority task and then the medium priority task before it can continue.
|
||||
*/
|
||||
static void prvLowPriorityMutexTask( void *pvParameters );
|
||||
static void prvMediumPriorityMutexTask( void *pvParameters );
|
||||
static void prvHighPriorityMutexTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
detected in any of the tasks. */
|
||||
static volatile BaseType_t xErrorDetected = pdFALSE;
|
||||
|
||||
/* Counters that are incremented on each cycle of a test. This is used to
|
||||
detect a stalled task - a test that is no longer running. */
|
||||
static volatile uint32_t ulLoopCounter = 0;
|
||||
static volatile uint32_t ulLoopCounter2 = 0;
|
||||
|
||||
/* The variable that is guarded by the mutex in the mutex demo tasks. */
|
||||
static volatile uint32_t ulGuardedVariable = 0;
|
||||
|
||||
/* Handles used in the mutex test to suspend and resume the high and medium
|
||||
priority mutex test tasks. */
|
||||
static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartGenericQueueTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
QueueHandle_t xQueue;
|
||||
SemaphoreHandle_t xMutex;
|
||||
|
||||
/* Create the queue that we are going to use for the
|
||||
prvSendFrontAndBackTest demo. */
|
||||
xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) );
|
||||
|
||||
if( xQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one
|
||||
is in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xQueue, "Gen_Queue_Test" );
|
||||
|
||||
/* Create the demo task and pass it the queue just created. We are
|
||||
passing the queue handle by value so it does not matter that it is
|
||||
declared on the stack here. */
|
||||
xTaskCreate( prvSendFrontAndBackTest, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
|
||||
}
|
||||
|
||||
/* Create the mutex used by the prvMutexTest task. */
|
||||
xMutex = xSemaphoreCreateMutex();
|
||||
|
||||
if( xMutex != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the mutex to the registry, if one is
|
||||
in use. The registry is provided as a means for kernel aware
|
||||
debuggers to locate mutexes and has no purpose if a kernel aware
|
||||
debugger is not being used. The call to vQueueAddToRegistry() will be
|
||||
removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
|
||||
defined or is defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Gen_Queue_Mutex" );
|
||||
|
||||
/* Create the mutex demo tasks and pass it the mutex just created. We
|
||||
are passing the mutex handle by value so it does not matter that it is
|
||||
declared on the stack here. */
|
||||
xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
|
||||
xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
|
||||
xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSendFrontAndBackTest( void *pvParameters )
|
||||
{
|
||||
uint32_t ulData, ulData2;
|
||||
QueueHandle_t xQueue;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const char * const * ppcMessageToSend );
|
||||
|
||||
const char * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
xQueue = ( QueueHandle_t ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The queue is empty, so sending an item to the back of the queue
|
||||
should have the same efect as sending it to the front of the queue.
|
||||
|
||||
First send to the front and check everything is as expected. */
|
||||
xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* The data we sent to the queue should equal the data we just received
|
||||
from the queue. */
|
||||
if( ulLoopCounter != ulData )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Then do the same, sending the data to the back, checking everything
|
||||
is as expected. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* The data we sent to the queue should equal the data we just received
|
||||
from the queue. */
|
||||
if( ulLoopCounter != ulData )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
|
||||
for( ulData = 2; ulData < 5; ulData++ )
|
||||
{
|
||||
xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
|
||||
}
|
||||
|
||||
/* Now the order in the queue should be 2, 3, 4, with 2 being the first
|
||||
thing to be read out. Now add 1 then 0 to the front of the queue. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 3 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
ulData = 1;
|
||||
xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
|
||||
ulData = 0;
|
||||
xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
|
||||
|
||||
/* Now the queue should be full, and when we read the data out we
|
||||
should receive 0, 1, 2, 3, 4. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 5 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Check the data we read out is in the expected order. */
|
||||
for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
|
||||
{
|
||||
/* Try peeking the data first. */
|
||||
if( xQueuePeek( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Now try receiving the data for real. The value should be the
|
||||
same. Clobber the value first so we know we really received it. */
|
||||
ulData2 = ~ulData2;
|
||||
if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* The queue should now be empty again. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
|
||||
/* Our queue is empty once more, add 10, 11 to the back. */
|
||||
ulData = 10;
|
||||
if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
ulData = 11;
|
||||
if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
|
||||
front. */
|
||||
for( ulData = 9; ulData >= 7; ulData-- )
|
||||
{
|
||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now check that the queue is full, and that receiving data provides
|
||||
the expected sequence of 7, 8, 9, 10, 11. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 5 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Check the data we read out is in the expected order. */
|
||||
for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
|
||||
{
|
||||
if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLoopCounter++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
|
||||
{
|
||||
/* Take the mutex. It should be available now. */
|
||||
if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the guarded variable to a known start value. */
|
||||
ulGuardedVariable = 0;
|
||||
|
||||
/* This task's priority should be as per that assigned when the task was
|
||||
created. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now unsuspend the high priority task. This will attempt to take the
|
||||
mutex, and block when it finds it cannot obtain it. */
|
||||
vTaskResume( xHighPriorityMutexTask );
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Ensure the task is reporting its priority as blocked and not
|
||||
suspended (as it would have done in versions up to V7.5.3). */
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* The priority of the high priority task should now have been inherited
|
||||
as by now it will have attempted to get the mutex. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Attempt to set the priority of this task to the test priority -
|
||||
between the idle priority and the medium/high test priorities, but the
|
||||
actual priority should remain at the high priority. */
|
||||
vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now unsuspend the medium priority task. This should not run as the
|
||||
inherited priority of this task is above that of the medium priority
|
||||
task. */
|
||||
vTaskResume( xMediumPriorityMutexTask );
|
||||
|
||||
/* If the medium priority task did run then it will have incremented the
|
||||
guarded variable. */
|
||||
if( ulGuardedVariable != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Take the local mutex too, so two mutexes are now held. */
|
||||
if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When the semaphore is given back the priority of this task should not
|
||||
yet be disinherited because the local mutex is still held. This is a
|
||||
simplification to allow FreeRTOS to be integrated with middleware that
|
||||
attempts to hold multiple mutexes without bloating the code with complex
|
||||
algorithms. It is possible that the high priority mutex task will
|
||||
execute as it shares a priority with this task. */
|
||||
if( xSemaphoreGive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* The guarded variable is only incremented by the medium priority task,
|
||||
which still should not have executed as this task should remain at the
|
||||
higher priority, ensure this is the case. */
|
||||
if( ulGuardedVariable != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now also give back the local mutex, taking the held count back to 0.
|
||||
This time the priority of this task should be disinherited back to the
|
||||
priority to which it was set while the mutex was held. This means
|
||||
the medium priority task should execute and increment the guarded
|
||||
variable. When this task next runs both the high and medium priority
|
||||
tasks will have been suspended again. */
|
||||
if( xSemaphoreGive( xLocalMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Check the guarded variable did indeed increment... */
|
||||
if( ulGuardedVariable != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* ... and that the priority of this task has been disinherited to
|
||||
genqMUTEX_TEST_PRIORITY. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the priority of this task back to its original value, ready for
|
||||
the next loop around this test. */
|
||||
vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
|
||||
{
|
||||
/* Take the mutex. It should be available now. */
|
||||
if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the guarded variable to a known start value. */
|
||||
ulGuardedVariable = 0;
|
||||
|
||||
/* This task's priority should be as per that assigned when the task was
|
||||
created. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now unsuspend the high priority task. This will attempt to take the
|
||||
mutex, and block when it finds it cannot obtain it. */
|
||||
vTaskResume( xHighPriorityMutexTask );
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Ensure the task is reporting its priority as blocked and not
|
||||
suspended (as it would have done in versions up to V7.5.3). */
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* The priority of the high priority task should now have been inherited
|
||||
as by now it will have attempted to get the mutex. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now unsuspend the medium priority task. This should not run as the
|
||||
inherited priority of this task is above that of the medium priority
|
||||
task. */
|
||||
vTaskResume( xMediumPriorityMutexTask );
|
||||
|
||||
/* If the medium priority task did run then it will have incremented the
|
||||
guarded variable. */
|
||||
if( ulGuardedVariable != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Take the local mutex too, so two mutexes are now held. */
|
||||
if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When the local semaphore is given back the priority of this task should
|
||||
not yet be disinherited because the shared mutex is still held. This is a
|
||||
simplification to allow FreeRTOS to be integrated with middleware that
|
||||
attempts to hold multiple mutexes without bloating the code with complex
|
||||
algorithms. It is possible that the high priority mutex task will
|
||||
execute as it shares a priority with this task. */
|
||||
if( xSemaphoreGive( xLocalMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* The guarded variable is only incremented by the medium priority task,
|
||||
which still should not have executed as this task should remain at the
|
||||
higher priority, ensure this is the case. */
|
||||
if( ulGuardedVariable != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now also give back the shared mutex, taking the held count back to 0.
|
||||
This time the priority of this task should be disinherited back to the
|
||||
priority at which it was created. This means the medium priority task
|
||||
should execute and increment the guarded variable. When this task next runs
|
||||
both the high and medium priority tasks will have been suspended again. */
|
||||
if( xSemaphoreGive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Check the guarded variable did indeed increment... */
|
||||
if( ulGuardedVariable != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* ... and that the priority of this task has been disinherited to
|
||||
genqMUTEX_LOW_PRIORITY. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const char * const * ppcMessageToSend );
|
||||
|
||||
const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
/* The local mutex is used to check the 'mutexs held' count. */
|
||||
xLocalMutex = xSemaphoreCreateMutex();
|
||||
configASSERT( xLocalMutex );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The first tests exercise the priority inheritance when two mutexes
|
||||
are taken then returned in a different order to which they were
|
||||
taken. */
|
||||
prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex );
|
||||
|
||||
/* Just to show this task is still running. */
|
||||
ulLoopCounter2++;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* The second tests exercise the priority inheritance when two mutexes
|
||||
are taken then returned in the same order in which they were taken. */
|
||||
prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex );
|
||||
|
||||
/* Just to show this task is still running. */
|
||||
ulLoopCounter2++;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMediumPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The medium priority task starts by suspending itself. The low
|
||||
priority task will unsuspend this task when required. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* When this task unsuspends all it does is increment the guarded
|
||||
variable, this is so the low priority task knows that it has
|
||||
executed. */
|
||||
ulGuardedVariable++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The high priority task starts by suspending itself. The low
|
||||
priority task will unsuspend this task when required. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* When this task unsuspends all it does is attempt to obtain
|
||||
the mutex. It should find the mutex is not available so a
|
||||
block time is specified. */
|
||||
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When the mutex is eventually obtained it is just given back before
|
||||
returning to suspend ready for the next cycle. */
|
||||
if( xSemaphoreGive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreGenericQueueTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
|
||||
|
||||
/* If the demo task is still running then we expect the loop counters to
|
||||
have incremented since this function was last called. */
|
||||
if( ulLastLoopCounter == ulLoopCounter )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulLastLoopCounter2 == ulLoopCounter2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLastLoopCounter = ulLoopCounter;
|
||||
ulLastLoopCounter2 = ulLoopCounter2;
|
||||
|
||||
/* Errors detected in the task itself will have latched xErrorDetected
|
||||
to true. */
|
||||
|
||||
return ( BaseType_t ) !xErrorDetected;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,769 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines one of the more complex set of demo/test tasks. They are
|
||||
* designed to stress test the queue implementation though pseudo simultaneous
|
||||
* multiple reads and multiple writes from both tasks of varying priority and
|
||||
* interrupts. The interrupts are prioritised such to ensure that nesting
|
||||
* occurs (for those ports that support it).
|
||||
*
|
||||
* The test ensures that, while being accessed from three tasks and two
|
||||
* interrupts, all the data sent to the queues is also received from
|
||||
* the same queue, and that no duplicate items are either sent or received.
|
||||
* The tests also ensure that a low priority task is never able to successfully
|
||||
* read from or write to a queue when a task of higher priority is attempting
|
||||
* the same operation.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
|
||||
/* SafeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo app includes. */
|
||||
#include "IntQueue.h"
|
||||
#include "IntQueueTimer.h"
|
||||
|
||||
#if( INCLUDE_eTaskGetState != 1 )
|
||||
#error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file.
|
||||
#endif
|
||||
|
||||
/* Priorities used by test tasks. */
|
||||
#ifndef intqHIGHER_PRIORITY
|
||||
#define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )
|
||||
#endif
|
||||
#define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
|
||||
|
||||
/* The number of values to send/receive before checking that all values were
|
||||
processed as expected. */
|
||||
#define intqNUM_VALUES_TO_LOG ( 200 )
|
||||
#define intqSHORT_DELAY ( 140 )
|
||||
|
||||
/* The value by which the value being sent to or received from a queue should
|
||||
increment past intqNUM_VALUES_TO_LOG before we check that all values have been
|
||||
sent/received correctly. This is done to ensure that all tasks and interrupts
|
||||
accessing the queue have completed their accesses with the
|
||||
intqNUM_VALUES_TO_LOG range. */
|
||||
#define intqVALUE_OVERRUN ( 50 )
|
||||
|
||||
/* The delay used by the polling task. A short delay is used for code
|
||||
coverage. */
|
||||
#define intqONE_TICK_DELAY ( 1 )
|
||||
|
||||
/* Each task and interrupt is given a unique identifier. This value is used to
|
||||
identify which task sent or received each value. The identifier is also used
|
||||
to distinguish between two tasks that are running the same task function. */
|
||||
#define intqHIGH_PRIORITY_TASK1 ( ( UBaseType_t ) 1 )
|
||||
#define intqHIGH_PRIORITY_TASK2 ( ( UBaseType_t ) 2 )
|
||||
#define intqLOW_PRIORITY_TASK ( ( UBaseType_t ) 3 )
|
||||
#define intqFIRST_INTERRUPT ( ( UBaseType_t ) 4 )
|
||||
#define intqSECOND_INTERRUPT ( ( UBaseType_t ) 5 )
|
||||
#define intqQUEUE_LENGTH ( ( UBaseType_t ) 10 )
|
||||
|
||||
/* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
|
||||
from each queue by each task, otherwise an error is detected. */
|
||||
#define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
|
||||
|
||||
/* Send the next value to the queue that is normally empty. This is called
|
||||
from within the interrupts. */
|
||||
#define timerNORMALLY_EMPTY_TX() \
|
||||
if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
|
||||
{ \
|
||||
UBaseType_t uxSavedInterruptStatus; \
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
|
||||
{ \
|
||||
uxValueForNormallyEmptyQueue++; \
|
||||
if( xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \
|
||||
{ \
|
||||
uxValueForNormallyEmptyQueue--; \
|
||||
} \
|
||||
} \
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
|
||||
} \
|
||||
|
||||
/* Send the next value to the queue that is normally full. This is called
|
||||
from within the interrupts. */
|
||||
#define timerNORMALLY_FULL_TX() \
|
||||
if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
|
||||
{ \
|
||||
UBaseType_t uxSavedInterruptStatus; \
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
|
||||
{ \
|
||||
uxValueForNormallyFullQueue++; \
|
||||
if( xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \
|
||||
{ \
|
||||
uxValueForNormallyFullQueue--; \
|
||||
} \
|
||||
} \
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
|
||||
} \
|
||||
|
||||
/* Receive a value from the normally empty queue. This is called from within
|
||||
an interrupt. */
|
||||
#define timerNORMALLY_EMPTY_RX() \
|
||||
if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
|
||||
{ \
|
||||
prvQueueAccessLogError( __LINE__ ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \
|
||||
}
|
||||
|
||||
/* Receive a value from the normally full queue. This is called from within
|
||||
an interrupt. */
|
||||
#define timerNORMALLY_FULL_RX() \
|
||||
if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
|
||||
{ \
|
||||
prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \
|
||||
} \
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The two queues used by the test. */
|
||||
static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue;
|
||||
|
||||
/* Variables used to detect a stall in one of the tasks. */
|
||||
static volatile UBaseType_t uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
|
||||
|
||||
/* Any unexpected behaviour sets xErrorStatus to fail and log the line that
|
||||
caused the error in xErrorLine. */
|
||||
static BaseType_t xErrorStatus = pdPASS;
|
||||
static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0;
|
||||
|
||||
/* Used for sequencing between tasks. */
|
||||
static BaseType_t xWasSuspended = pdFALSE;
|
||||
|
||||
/* The values that are sent to the queues. An incremented value is sent each
|
||||
time to each queue. */
|
||||
static volatile UBaseType_t uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
|
||||
|
||||
/* A handle to some of the tasks is required so they can be suspended/resumed. */
|
||||
TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
|
||||
|
||||
/* When a value is received in a queue the value is ticked off in the array
|
||||
the array position of the value is set to a the identifier of the task or
|
||||
interrupt that accessed the queue. This way missing or duplicate values can be
|
||||
detected. */
|
||||
static uint8_t ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
|
||||
static uint8_t ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
|
||||
|
||||
/* The test tasks themselves. */
|
||||
static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );
|
||||
static void prvLowerPriorityNormallyFullTask( void *pvParameters );
|
||||
static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );
|
||||
static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
|
||||
static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );
|
||||
|
||||
/* Used to mark the positions within the ucNormallyEmptyReceivedValues and
|
||||
ucNormallyFullReceivedValues arrays, while checking for duplicates. */
|
||||
static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource );
|
||||
static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource );
|
||||
|
||||
/* Logs the line on which an error occurred. */
|
||||
static void prvQueueAccessLogError( UBaseType_t uxLine );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartInterruptQueueTasks( void )
|
||||
{
|
||||
/* Start the test tasks. */
|
||||
xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
|
||||
xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
|
||||
xTaskCreate( prvLowerPriorityNormallyEmptyTask, "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
|
||||
xTaskCreate( prv1stHigherPriorityNormallyFullTask, "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
|
||||
xTaskCreate( prv2ndHigherPriorityNormallyFullTask, "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
|
||||
xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
|
||||
|
||||
/* Create the queues that are accessed by multiple tasks and multiple
|
||||
interrupts. */
|
||||
xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
|
||||
xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" );
|
||||
vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource )
|
||||
{
|
||||
if( uxValue < intqNUM_VALUES_TO_LOG )
|
||||
{
|
||||
/* We don't expect to receive the same value twice, so if the value
|
||||
has already been marked as received an error has occurred. */
|
||||
if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Log that this value has been received. */
|
||||
ucNormallyFullReceivedValues[ uxValue ] = ( uint8_t ) uxSource;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource )
|
||||
{
|
||||
if( uxValue < intqNUM_VALUES_TO_LOG )
|
||||
{
|
||||
/* We don't expect to receive the same value twice, so if the value
|
||||
has already been marked as received an error has occurred. */
|
||||
if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Log that this value has been received. */
|
||||
ucNormallyEmptyReceivedValues[ uxValue ] = ( uint8_t ) uxSource;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueAccessLogError( UBaseType_t uxLine )
|
||||
{
|
||||
/* Latch the line number that caused the error. */
|
||||
xErrorLine = uxLine;
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
|
||||
{
|
||||
UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
|
||||
|
||||
/* The timer should not be started until after the scheduler has started.
|
||||
More than one task is running this code so we check the parameter value
|
||||
to determine which task should start the timer. */
|
||||
if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
vInitialiseTimerForIntQueueTest();
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Block waiting to receive a value from the normally empty queue.
|
||||
Interrupts will write to the queue so we should receive a value. */
|
||||
if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Note which value was received so we can check all expected
|
||||
values are received and no values are duplicated. */
|
||||
prvRecordValue_NormallyEmpty( uxRxed, ( UBaseType_t ) pvParameters );
|
||||
}
|
||||
|
||||
/* Ensure the other task running this code gets a chance to execute. */
|
||||
taskYIELD();
|
||||
|
||||
if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
/* Have we received all the expected values? */
|
||||
if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
|
||||
{
|
||||
vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
|
||||
|
||||
uxTask1 = 0;
|
||||
uxTask2 = 0;
|
||||
uxInterrupts = 0;
|
||||
|
||||
/* Loop through the array, checking that both tasks have
|
||||
placed values into the array, and that no values are missing.
|
||||
Start at 1 as we expect position 0 to be unused. */
|
||||
for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
|
||||
{
|
||||
if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
|
||||
{
|
||||
/* A value is missing. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
/* Value was placed into the array by task 1. */
|
||||
uxTask1++;
|
||||
}
|
||||
else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
|
||||
{
|
||||
/* Value was placed into the array by task 2. */
|
||||
uxTask2++;
|
||||
}
|
||||
else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )
|
||||
{
|
||||
uxInterrupts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
|
||||
{
|
||||
/* Only task 2 seemed to log any values. */
|
||||
uxErrorCount1++;
|
||||
if( uxErrorCount1 > 2 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uxErrorCount1 = 0;
|
||||
}
|
||||
|
||||
if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )
|
||||
{
|
||||
/* Only task 1 seemed to log any values. */
|
||||
uxErrorCount2++;
|
||||
if( uxErrorCount2 > 2 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uxErrorCount2 = 0;
|
||||
}
|
||||
|
||||
if( uxInterrupts == 0 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Clear the array again, ready to start a new cycle. */
|
||||
memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
|
||||
|
||||
uxHighPriorityLoops1++;
|
||||
uxValueForNormallyEmptyQueue = 0;
|
||||
|
||||
/* Suspend ourselves, allowing the lower priority task to
|
||||
actually receive something from the queue. Until now it
|
||||
will have been prevented from doing so by the higher
|
||||
priority tasks. The lower priority task will resume us
|
||||
if it receives something. We will then resume the other
|
||||
higher priority task. */
|
||||
vTaskSuspend( NULL );
|
||||
vTaskResume( xHighPriorityNormallyEmptyTask2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )
|
||||
{
|
||||
UBaseType_t uxValue, uxRxed;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
|
||||
{
|
||||
/* A value should only be obtained when the high priority task is
|
||||
suspended. */
|
||||
if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
|
||||
|
||||
/* Wake the higher priority task again. */
|
||||
vTaskResume( xHighPriorityNormallyEmptyTask1 );
|
||||
uxLowPriorityLoops1++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raise our priority while we send so we can preempt the higher
|
||||
priority task, and ensure we get the Tx value into the queue. */
|
||||
vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyEmptyQueue++;
|
||||
uxValue = uxValueForNormallyEmptyQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )
|
||||
{
|
||||
UBaseType_t uxValueToTx, ux, uxInterrupts;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Make sure the queue starts full or near full. >> 1 as there are two
|
||||
high priority tasks. */
|
||||
for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
|
||||
{
|
||||
/* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
|
||||
expect it to ever time out. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Allow the other task running this code to run. */
|
||||
taskYIELD();
|
||||
|
||||
/* Have all the expected values been sent to the queue? */
|
||||
if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
|
||||
{
|
||||
/* Make sure the other high priority task completes its send of
|
||||
any values below intqNUM_VALUE_TO_LOG. */
|
||||
vTaskDelay( intqSHORT_DELAY );
|
||||
|
||||
vTaskSuspend( xHighPriorityNormallyFullTask2 );
|
||||
|
||||
if( xWasSuspended == pdTRUE )
|
||||
{
|
||||
/* We would have expected the other high priority task to have
|
||||
set this back to false by now. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Set the suspended flag so an error is not logged if the other
|
||||
task recognises a time out when it is unsuspended. */
|
||||
xWasSuspended = pdTRUE;
|
||||
|
||||
/* Check interrupts are also sending. */
|
||||
uxInterrupts = 0U;
|
||||
|
||||
/* Start at 1 as we expect position 0 to be unused. */
|
||||
for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
|
||||
{
|
||||
if( ucNormallyFullReceivedValues[ ux ] == 0 )
|
||||
{
|
||||
/* A value was missing. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )
|
||||
{
|
||||
uxInterrupts++;
|
||||
}
|
||||
}
|
||||
|
||||
if( uxInterrupts == 0 )
|
||||
{
|
||||
/* No writes from interrupts were found. Are interrupts
|
||||
actually running? */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Reset the array ready for the next cycle. */
|
||||
memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
|
||||
|
||||
uxHighPriorityLoops2++;
|
||||
uxValueForNormallyFullQueue = 0;
|
||||
|
||||
/* Suspend ourselves, allowing the lower priority task to
|
||||
actually receive something from the queue. Until now it
|
||||
will have been prevented from doing so by the higher
|
||||
priority tasks. The lower priority task will resume us
|
||||
if it receives something. We will then resume the other
|
||||
higher priority task. */
|
||||
vTaskSuspend( NULL );
|
||||
vTaskResume( xHighPriorityNormallyFullTask2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )
|
||||
{
|
||||
UBaseType_t uxValueToTx, ux;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Make sure the queue starts full or near full. >> 1 as there are two
|
||||
high priority tasks. */
|
||||
for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
|
||||
{
|
||||
if( xWasSuspended != pdTRUE )
|
||||
{
|
||||
/* It is ok to time out if the task has been suspended. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
|
||||
xWasSuspended = pdFALSE;
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowerPriorityNormallyFullTask( void *pvParameters )
|
||||
{
|
||||
UBaseType_t uxValue, uxTxed = 9999;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )
|
||||
{
|
||||
/* Should only succeed when the higher priority task is suspended */
|
||||
if( eTaskGetState( xHighPriorityNormallyFullTask1 ) != eSuspended )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
vTaskResume( xHighPriorityNormallyFullTask1 );
|
||||
uxLowPriorityLoops2++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raise our priority while we receive so we can preempt the higher
|
||||
priority task, and ensure we get the value from the queue. */
|
||||
vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
|
||||
|
||||
if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
|
||||
}
|
||||
|
||||
vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xFirstTimerHandler( void )
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
UBaseType_t uxRxedValue;
|
||||
static UBaseType_t uxNextOperation = 0;
|
||||
|
||||
/* Called from a timer interrupt. Perform various read and write
|
||||
accesses on the queues. */
|
||||
|
||||
uxNextOperation++;
|
||||
|
||||
if( uxNextOperation & ( UBaseType_t ) 0x01 )
|
||||
{
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
}
|
||||
else
|
||||
{
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_RX();
|
||||
}
|
||||
|
||||
return xHigherPriorityTaskWoken;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xSecondTimerHandler( void )
|
||||
{
|
||||
UBaseType_t uxRxedValue;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
static UBaseType_t uxNextOperation = 0;
|
||||
|
||||
/* Called from a timer interrupt. Perform various read and write
|
||||
accesses on the queues. */
|
||||
|
||||
uxNextOperation++;
|
||||
|
||||
if( uxNextOperation & ( UBaseType_t ) 0x01 )
|
||||
{
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
|
||||
timerNORMALLY_EMPTY_RX();
|
||||
timerNORMALLY_EMPTY_RX();
|
||||
}
|
||||
else
|
||||
{
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
}
|
||||
|
||||
return xHigherPriorityTaskWoken;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
BaseType_t xAreIntQueueTasksStillRunning( void )
|
||||
{
|
||||
static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
|
||||
|
||||
/* xErrorStatus can be set outside of this function. This function just
|
||||
checks that all the tasks are still cycling. */
|
||||
|
||||
if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
|
||||
{
|
||||
/* The high priority 1 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
|
||||
|
||||
if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
|
||||
{
|
||||
/* The high priority 2 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
|
||||
|
||||
if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
|
||||
{
|
||||
/* The low priority 1 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
|
||||
|
||||
if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
|
||||
{
|
||||
/* The low priority 2 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
|
||||
|
||||
return xErrorStatus;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,567 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Demonstrates and tests mutexes being used from an interrupt.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "IntSemTest.h"
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The priorities of the test tasks. */
|
||||
#define intsemMASTER_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define intsemSLAVE_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
|
||||
/* The rate at which the tick hook will give the mutex. */
|
||||
#define intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ( 100 )
|
||||
|
||||
/* A block time of 0 means 'don't block'. */
|
||||
#define intsemNO_BLOCK 0
|
||||
|
||||
/* The maximum count value for the counting semaphore given from an
|
||||
interrupt. */
|
||||
#define intsemMAX_COUNT 3
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The master is a task that receives a mutex that is given from an interrupt -
|
||||
* although generally mutexes should not be used given in interrupts (and
|
||||
* definitely never taken in an interrupt) there are some circumstances when it
|
||||
* may be desirable.
|
||||
*
|
||||
* The slave task is just used by the master task to force priority inheritance
|
||||
* on a mutex that is shared between the master and the slave - which is a
|
||||
* separate mutex to that given by the interrupt.
|
||||
*/
|
||||
static void vInterruptMutexSlaveTask( void *pvParameters );
|
||||
static void vInterruptMutexMasterTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* A test whereby the master takes the shared and interrupt mutexes in that
|
||||
* order, then gives them back in the same order, ensuring the priority
|
||||
* inheritance is behaving as expected at each step.
|
||||
*/
|
||||
static void prvTakeAndGiveInTheSameOrder( void );
|
||||
|
||||
/*
|
||||
* A test whereby the master takes the shared and interrupt mutexes in that
|
||||
* order, then gives them back in the opposite order to which they were taken,
|
||||
* ensuring the priority inheritance is behaving as expected at each step.
|
||||
*/
|
||||
static void prvTakeAndGiveInTheOppositeOrder( void );
|
||||
|
||||
/*
|
||||
* A simple task that interacts with an interrupt using a counting semaphore,
|
||||
* primarily for code coverage purposes.
|
||||
*/
|
||||
static void vInterruptCountingSemaphoreTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
detected in any of the tasks. */
|
||||
static volatile BaseType_t xErrorDetected = pdFALSE;
|
||||
|
||||
/* Counters that are incremented on each cycle of a test. This is used to
|
||||
detect a stalled task - a test that is no longer running. */
|
||||
static volatile uint32_t ulMasterLoops = 0, ulCountingSemaphoreLoops = 0;
|
||||
|
||||
/* Handles of the test tasks that must be accessed from other test tasks. */
|
||||
static TaskHandle_t xSlaveHandle;
|
||||
|
||||
/* A mutex which is given from an interrupt - although generally mutexes should
|
||||
not be used given in interrupts (and definitely never taken in an interrupt)
|
||||
there are some circumstances when it may be desirable. */
|
||||
static SemaphoreHandle_t xISRMutex = NULL;
|
||||
|
||||
/* A counting semaphore which is given from an interrupt. */
|
||||
static SemaphoreHandle_t xISRCountingSemaphore = NULL;
|
||||
|
||||
/* A mutex which is shared between the master and slave tasks - the master
|
||||
does both sharing of this mutex with the slave and receiving a mutex from the
|
||||
interrupt. */
|
||||
static SemaphoreHandle_t xMasterSlaveMutex = NULL;
|
||||
|
||||
/* Flag that allows the master task to control when the interrupt gives or does
|
||||
not give the mutex. There is no mutual exclusion on this variable, but this is
|
||||
only test code and it should be fine in the 32=bit test environment. */
|
||||
static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE;
|
||||
|
||||
/* Used to coordinate timing between tasks and the interrupt. */
|
||||
const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartInterruptSemaphoreTasks( void )
|
||||
{
|
||||
/* Create the semaphores that are given from an interrupt. */
|
||||
xISRMutex = xSemaphoreCreateMutex();
|
||||
configASSERT( xISRMutex );
|
||||
xISRCountingSemaphore = xSemaphoreCreateCounting( intsemMAX_COUNT, 0 );
|
||||
configASSERT( xISRCountingSemaphore );
|
||||
|
||||
/* Create the mutex that is shared between the master and slave tasks (the
|
||||
master receives a mutex from an interrupt and shares a mutex with the
|
||||
slave. */
|
||||
xMasterSlaveMutex = xSemaphoreCreateMutex();
|
||||
configASSERT( xMasterSlaveMutex );
|
||||
|
||||
/* Create the tasks that share mutexes between then and with interrupts. */
|
||||
xTaskCreate( vInterruptMutexSlaveTask, "IntMuS", configMINIMAL_STACK_SIZE, NULL, intsemSLAVE_PRIORITY, &xSlaveHandle );
|
||||
xTaskCreate( vInterruptMutexMasterTask, "IntMuM", configMINIMAL_STACK_SIZE, NULL, intsemMASTER_PRIORITY, NULL );
|
||||
|
||||
/* Create the task that blocks on the counting semaphore. */
|
||||
xTaskCreate( vInterruptCountingSemaphoreTask, "IntCnt", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vInterruptMutexMasterTask( void *pvParameters )
|
||||
{
|
||||
/* Just to avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
prvTakeAndGiveInTheSameOrder();
|
||||
|
||||
/* Ensure not to starve out other tests. */
|
||||
ulMasterLoops++;
|
||||
vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
|
||||
|
||||
prvTakeAndGiveInTheOppositeOrder();
|
||||
|
||||
/* Ensure not to starve out other tests. */
|
||||
ulMasterLoops++;
|
||||
vTaskDelay( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTakeAndGiveInTheSameOrder( void )
|
||||
{
|
||||
/* Ensure the slave is suspended, and that this task is running at the
|
||||
lower priority as expected as the start conditions. */
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Take the semaphore that is shared with the slave. */
|
||||
if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* This task now has the mutex. Unsuspend the slave so it too
|
||||
attempts to take the mutex. */
|
||||
vTaskResume( xSlaveHandle );
|
||||
|
||||
/* The slave has the higher priority so should now have executed and
|
||||
blocked on the semaphore. */
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* This task should now have inherited the priority of the slave
|
||||
task. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now wait a little longer than the time between ISR gives to also
|
||||
obtain the ISR mutex. */
|
||||
xOkToGiveMutex = pdTRUE;
|
||||
if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
xOkToGiveMutex = pdFALSE;
|
||||
|
||||
/* Attempting to take again immediately should fail as the mutex is
|
||||
already held. */
|
||||
if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Should still be at the priority of the slave task. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Give back the ISR semaphore to ensure the priority is not
|
||||
disinherited as the shared mutex (which the higher priority task is
|
||||
attempting to obtain) is still held. */
|
||||
if( xSemaphoreGive( xISRMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Finally give back the shared mutex. This time the higher priority
|
||||
task should run before this task runs again - so this task should have
|
||||
disinherited the priority and the higher priority task should be in the
|
||||
suspended state again. */
|
||||
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Reset the mutex ready for the next round. */
|
||||
xQueueReset( xISRMutex );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTakeAndGiveInTheOppositeOrder( void )
|
||||
{
|
||||
/* Ensure the slave is suspended, and that this task is running at the
|
||||
lower priority as expected as the start conditions. */
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Take the semaphore that is shared with the slave. */
|
||||
if( xSemaphoreTake( xMasterSlaveMutex, intsemNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* This task now has the mutex. Unsuspend the slave so it too
|
||||
attempts to take the mutex. */
|
||||
vTaskResume( xSlaveHandle );
|
||||
|
||||
/* The slave has the higher priority so should now have executed and
|
||||
blocked on the semaphore. */
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* This task should now have inherited the priority of the slave
|
||||
task. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now wait a little longer than the time between ISR gives to also
|
||||
obtain the ISR mutex. */
|
||||
xOkToGiveMutex = pdTRUE;
|
||||
if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
xOkToGiveMutex = pdFALSE;
|
||||
|
||||
/* Attempting to take again immediately should fail as the mutex is
|
||||
already held. */
|
||||
if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Should still be at the priority of the slave task. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Give back the shared semaphore to ensure the priority is not disinherited
|
||||
as the ISR mutex is still held. The higher priority slave task should run
|
||||
before this task runs again. */
|
||||
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Should still be at the priority of the slave task as this task still
|
||||
holds one semaphore (this is a simplification in the priority inheritance
|
||||
mechanism. */
|
||||
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Give back the ISR semaphore, which should result in the priority being
|
||||
disinherited as it was the last mutex held. */
|
||||
if( xSemaphoreGive( xISRMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Reset the mutex ready for the next round. */
|
||||
xQueueReset( xISRMutex );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vInterruptMutexSlaveTask( void *pvParameters )
|
||||
{
|
||||
/* Just to avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* This task starts by suspending itself so when it executes can be
|
||||
controlled by the master task. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* This task will execute when the master task already holds the mutex.
|
||||
Attempting to take the mutex will place this task in the Blocked
|
||||
state. */
|
||||
if( xSemaphoreTake( xMasterSlaveMutex, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vInterruptCountingSemaphoreTask( void *pvParameters )
|
||||
{
|
||||
BaseType_t xCount;
|
||||
const TickType_t xDelay = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) * ( intsemMAX_COUNT + 1 );
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Expect to start with the counting semaphore empty. */
|
||||
if( uxQueueMessagesWaiting( ( QueueHandle_t ) xISRCountingSemaphore ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Wait until it is expected that the interrupt will have filled the
|
||||
counting semaphore. */
|
||||
xOkToGiveCountingSemaphore = pdTRUE;
|
||||
vTaskDelay( xDelay );
|
||||
xOkToGiveCountingSemaphore = pdFALSE;
|
||||
|
||||
/* Now it is expected that the counting semaphore is full. */
|
||||
if( uxQueueMessagesWaiting( ( QueueHandle_t ) xISRCountingSemaphore ) != intsemMAX_COUNT )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueSpacesAvailable( ( QueueHandle_t ) xISRCountingSemaphore ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulCountingSemaphoreLoops++;
|
||||
|
||||
/* Expect to be able to take the counting semaphore intsemMAX_COUNT
|
||||
times. A block time of 0 is used as the semaphore should already be
|
||||
there. */
|
||||
xCount = 0;
|
||||
while( xSemaphoreTake( xISRCountingSemaphore, 0 ) == pdPASS )
|
||||
{
|
||||
xCount++;
|
||||
}
|
||||
|
||||
if( xCount != intsemMAX_COUNT )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now raise the priority of this task so it runs immediately that the
|
||||
semaphore is given from the interrupt. */
|
||||
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
||||
|
||||
/* Block to wait for the semaphore to be given from the interrupt. */
|
||||
xOkToGiveCountingSemaphore = pdTRUE;
|
||||
xSemaphoreTake( xISRCountingSemaphore, portMAX_DELAY );
|
||||
xSemaphoreTake( xISRCountingSemaphore, portMAX_DELAY );
|
||||
xOkToGiveCountingSemaphore = pdFALSE;
|
||||
|
||||
/* Reset the priority so as not to disturbe other tests too much. */
|
||||
vTaskPrioritySet( NULL, tskIDLE_PRIORITY );
|
||||
|
||||
ulCountingSemaphoreLoops++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vInterruptSemaphorePeriodicTest( void )
|
||||
{
|
||||
static TickType_t xLastGiveTime = 0;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
TickType_t xTimeNow;
|
||||
|
||||
/* No mutual exclusion on xOkToGiveMutex, but this is only test code (and
|
||||
only executed on a 32-bit architecture) so ignore that in this case. */
|
||||
xTimeNow = xTaskGetTickCountFromISR();
|
||||
if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )
|
||||
{
|
||||
configASSERT( xISRMutex );
|
||||
if( xOkToGiveMutex != pdFALSE )
|
||||
{
|
||||
/* Null is used as the second parameter in this give, and non-NULL
|
||||
in the other gives for code coverage reasons. */
|
||||
xSemaphoreGiveFromISR( xISRMutex, NULL );
|
||||
|
||||
/* Second give attempt should fail. */
|
||||
configASSERT( xSemaphoreGiveFromISR( xISRMutex, &xHigherPriorityTaskWoken ) == pdFAIL );
|
||||
}
|
||||
|
||||
if( xOkToGiveCountingSemaphore != pdFALSE )
|
||||
{
|
||||
xSemaphoreGiveFromISR( xISRCountingSemaphore, &xHigherPriorityTaskWoken );
|
||||
}
|
||||
xLastGiveTime = xTimeNow;
|
||||
}
|
||||
|
||||
/* Remove compiler warnings about the value being set but not used. */
|
||||
( void ) xHigherPriorityTaskWoken;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreInterruptSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastMasterLoopCounter = 0, ulLastCountingSemaphoreLoops = 0;
|
||||
|
||||
/* If the demo tasks are running then it is expected that the loop counters
|
||||
will have changed since this function was last called. */
|
||||
if( ulLastMasterLoopCounter == ulMasterLoops )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLastMasterLoopCounter = ulMasterLoops;
|
||||
|
||||
if( ulLastCountingSemaphoreLoops == ulCountingSemaphoreLoops )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLastCountingSemaphoreLoops = ulCountingSemaphoreLoops++;
|
||||
|
||||
/* Errors detected in the task itself will have latched xErrorDetected
|
||||
to true. */
|
||||
|
||||
return ( BaseType_t ) !xErrorDetected;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This version of PollQ. c is for use on systems that have limited stack
|
||||
* space and no display facilities. The complete version can be found in
|
||||
* the Demo/Common/Full directory.
|
||||
*
|
||||
* Creates two tasks that communicate over a single queue. One task acts as a
|
||||
* producer, the other a consumer.
|
||||
*
|
||||
* The producer loops for three iteration, posting an incrementing number onto the
|
||||
* queue each cycle. It then delays for a fixed period before doing exactly the
|
||||
* same again.
|
||||
*
|
||||
* The consumer loops emptying the queue. Each item removed from the queue is
|
||||
* checked to ensure it contains the expected value. When the queue is empty it
|
||||
* blocks for a fixed period, then does the same again.
|
||||
*
|
||||
* All queue access is performed without blocking. The consumer completely empties
|
||||
* the queue each time it runs so the producer should never find the queue full.
|
||||
*
|
||||
* An error is flagged if the consumer obtains an unexpected value or the producer
|
||||
* find the queue is full.
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
TickType_t rather than uint32_t.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "PollQ.h"
|
||||
|
||||
#define pollqSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define pollqQUEUE_SIZE ( 10 )
|
||||
#define pollqPRODUCER_DELAY ( pdMS_TO_TICKS( ( TickType_t ) 200 ) )
|
||||
#define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( TickType_t ) ( 20 / portTICK_PERIOD_MS ) )
|
||||
#define pollqNO_DELAY ( ( TickType_t ) 0 )
|
||||
#define pollqVALUES_TO_PRODUCE ( ( BaseType_t ) 3 )
|
||||
#define pollqINITIAL_VALUE ( ( BaseType_t ) 0 )
|
||||
|
||||
/* The task that posts the incrementing number onto the queue. */
|
||||
static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
|
||||
|
||||
/* The task that empties the queue. */
|
||||
static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );
|
||||
|
||||
/* Variables that are used to check that the tasks are still running with no
|
||||
errors. */
|
||||
static volatile BaseType_t xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartPolledQueueTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
static QueueHandle_t xPolledQueue;
|
||||
|
||||
/* Create the queue used by the producer and consumer. */
|
||||
xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( UBaseType_t ) sizeof( uint16_t ) );
|
||||
|
||||
if( xPolledQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xPolledQueue, "Poll_Test_Queue" );
|
||||
|
||||
/* Spawn the producer and consumer. */
|
||||
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vPolledQueueProducer, pvParameters )
|
||||
{
|
||||
uint16_t usValue = ( uint16_t ) 0;
|
||||
BaseType_t xError = pdFALSE, xLoop;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ )
|
||||
{
|
||||
/* Send an incrementing number on the queue without blocking. */
|
||||
if( xQueueSend( *( ( QueueHandle_t * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We should never find the queue full so if we get here there
|
||||
has been an error. */
|
||||
xError = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
/* If an error has ever been recorded we stop incrementing the
|
||||
check variable. */
|
||||
portENTER_CRITICAL();
|
||||
xPollingProducerCount++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Update the value we are going to post next time around. */
|
||||
usValue++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait before we start posting again to ensure the consumer runs and
|
||||
empties the queue. */
|
||||
vTaskDelay( pollqPRODUCER_DELAY );
|
||||
}
|
||||
} /*lint !e818 Function prototype must conform to API. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters )
|
||||
{
|
||||
uint16_t usData, usExpectedValue = ( uint16_t ) 0;
|
||||
BaseType_t xError = pdFALSE;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Loop until the queue is empty. */
|
||||
while( uxQueueMessagesWaiting( *( ( QueueHandle_t * ) pvParameters ) ) )
|
||||
{
|
||||
if( xQueueReceive( *( ( QueueHandle_t * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* This is not what we expected to receive so an error has
|
||||
occurred. */
|
||||
xError = pdTRUE;
|
||||
|
||||
/* Catch-up to the value we received so our next expected
|
||||
value should again be correct. */
|
||||
usExpectedValue = usData;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
/* Only increment the check variable if no errors have
|
||||
occurred. */
|
||||
portENTER_CRITICAL();
|
||||
xPollingConsumerCount++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
/* Next time round we would expect the number to be one higher. */
|
||||
usExpectedValue++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the queue is empty we block, allowing the producer to place more
|
||||
items in the queue. */
|
||||
vTaskDelay( pollqCONSUMER_DELAY );
|
||||
}
|
||||
} /*lint !e818 Function prototype must conform to API. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running with no errors. */
|
||||
BaseType_t xArePollingQueuesStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* Check both the consumer and producer poll count to check they have both
|
||||
been changed since out last trip round. We do not need a critical section
|
||||
around the check variables as this is called from a higher priority than
|
||||
the other tasks that access the same variables. */
|
||||
if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||
|
||||
( xPollingProducerCount == pollqINITIAL_VALUE )
|
||||
)
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the check variables back down so we know if they have been
|
||||
incremented the next time around. */
|
||||
xPollingConsumerCount = pollqINITIAL_VALUE;
|
||||
xPollingProducerCount = pollqINITIAL_VALUE;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
@@ -0,0 +1,481 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Tests the behaviour when data is peeked from a queue when there are
|
||||
* multiple tasks blocked on the queue.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "QPeek.h"
|
||||
|
||||
#define qpeekQUEUE_LENGTH ( 5 )
|
||||
#define qpeekNO_BLOCK ( 0 )
|
||||
#define qpeekSHORT_DELAY ( 10 )
|
||||
|
||||
#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 )
|
||||
#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The following three tasks are used to demonstrate the peeking behaviour.
|
||||
* Each task is given a different priority to demonstrate the order in which
|
||||
* tasks are woken as data is peeked from a queue.
|
||||
*/
|
||||
static void prvLowPriorityPeekTask( void *pvParameters );
|
||||
static void prvMediumPriorityPeekTask( void *pvParameters );
|
||||
static void prvHighPriorityPeekTask( void *pvParameters );
|
||||
static void prvHighestPriorityPeekTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
detected in any of the tasks. */
|
||||
static volatile BaseType_t xErrorDetected = pdFALSE;
|
||||
|
||||
/* Counter that is incremented on each cycle of a test. This is used to
|
||||
detect a stalled task - a test that is no longer running. */
|
||||
static volatile uint32_t ulLoopCounter = 0;
|
||||
|
||||
/* Handles to the test tasks. */
|
||||
TaskHandle_t xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueuePeekTasks( void )
|
||||
{
|
||||
QueueHandle_t xQueue;
|
||||
|
||||
/* Create the queue that we are going to use for the test/demo. */
|
||||
xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( uint32_t ) );
|
||||
|
||||
if( xQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xQueue, "QPeek_Test_Queue" );
|
||||
|
||||
/* Create the demo tasks and pass it the queue just created. We are
|
||||
passing the queue handle by value so it does not matter that it is declared
|
||||
on the stack here. */
|
||||
xTaskCreate( prvLowPriorityPeekTask, "PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );
|
||||
xTaskCreate( prvMediumPriorityPeekTask, "PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );
|
||||
xTaskCreate( prvHighPriorityPeekTask, "PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );
|
||||
xTaskCreate( prvHighestPriorityPeekTask, "PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighestPriorityPeekTask( void *pvParameters )
|
||||
{
|
||||
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
|
||||
uint32_t ulValue;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
{
|
||||
void vPrintDisplayMessage( const char * const * ppcMessageToSend );
|
||||
|
||||
const char * const pcTaskStartMsg = "Queue peek test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
}
|
||||
#endif
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
block, allowing the high priority task to execute. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we reach here the high and medium priority tasks should still
|
||||
be blocked on the queue. We unblocked because the low priority task
|
||||
wrote a value to the queue, which we should have peeked. Peeking the
|
||||
data (rather than receiving it) will leave the data on the queue, so
|
||||
the high priority task should then have also been unblocked, but not
|
||||
yet executed. */
|
||||
if( ulValue != 0x11223344 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we are going to actually receive the data, so when the high
|
||||
priority task runs it will find the queue empty and return to the
|
||||
blocked state. */
|
||||
ulValue = 0;
|
||||
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to receive the value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0x11223344 )
|
||||
{
|
||||
/* We did not receive the expected value - which should have been
|
||||
the same value as was peeked. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we will block again as the queue is once more empty. The low
|
||||
priority task can then execute again. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the low priority task should have again written to the
|
||||
queue. */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We only peeked the data, so suspending ourselves now should enable
|
||||
the high priority task to also peek the data. The high priority task
|
||||
will have been unblocked when we peeked the data as we left the data
|
||||
in the queue. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
|
||||
|
||||
/* This time we are going to do the same as the above test, but the
|
||||
high priority task is going to receive the data, rather than peek it.
|
||||
This means that the medium priority task should never peek the value. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0xaabbaabb )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighPriorityPeekTask( void *pvParameters )
|
||||
{
|
||||
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
|
||||
uint32_t ulValue;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
block, allowing the medium priority task to execute. Both the high
|
||||
and highest priority tasks will then be blocked on the queue. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the highest priority task should have peeked the data
|
||||
(unblocking this task) then suspended (allowing this task to also peek
|
||||
the data). */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We only peeked the data, so suspending ourselves now should enable
|
||||
the medium priority task to also peek the data. The medium priority task
|
||||
will have been unblocked when we peeked the data as we left the data
|
||||
in the queue. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
|
||||
/* This time we are going actually receive the value, so the medium
|
||||
priority task will never peek the data - we removed it from the queue. */
|
||||
if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0xaabbaabb )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMediumPriorityPeekTask( void *pvParameters )
|
||||
{
|
||||
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
|
||||
uint32_t ulValue;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
block, allowing the low priority task to execute. The highest, high
|
||||
and medium priority tasks will then all be blocked on the queue. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the high priority task should have peeked the data
|
||||
(unblocking this task) then suspended (allowing this task to also peek
|
||||
the data). */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Just so we know the test is still running. */
|
||||
ulLoopCounter++;
|
||||
|
||||
/* Now we can suspend ourselves so the low priority task can execute
|
||||
again. */
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowPriorityPeekTask( void *pvParameters )
|
||||
{
|
||||
QueueHandle_t xQueue = ( QueueHandle_t ) pvParameters;
|
||||
uint32_t ulValue;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Write some data to the queue. This should unblock the highest
|
||||
priority task that is waiting to peek data from the queue. */
|
||||
ulValue = 0x11223344;
|
||||
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* By the time we get here the data should have been removed from
|
||||
the queue. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Write another value to the queue, again waking the highest priority
|
||||
task that is blocked on the queue. */
|
||||
ulValue = 0x01234567;
|
||||
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* All the other tasks should now have successfully peeked the data.
|
||||
The data is still in the queue so we should be able to receive it. */
|
||||
ulValue = 0;
|
||||
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to receive the data. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
}
|
||||
|
||||
/* Lets just delay a while as this is an intensive test as we don't
|
||||
want to starve other tests of processing time. */
|
||||
vTaskDelay( qpeekSHORT_DELAY );
|
||||
|
||||
/* Unsuspend the other tasks so we can repeat the test - this time
|
||||
however not all the other tasks will peek the data as the high
|
||||
priority task is actually going to remove it from the queue. Send
|
||||
to front is used just to be different. As the queue is empty it
|
||||
makes no difference to the result. */
|
||||
vTaskResume( xMediumPriorityTask );
|
||||
vTaskResume( xHighPriorityTask );
|
||||
vTaskResume( xHighestPriorityTask );
|
||||
|
||||
#if( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
ulValue = 0xaabbaabb;
|
||||
if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* This time we should find that the queue is empty. The high priority
|
||||
task actually removed the data rather than just peeking it. */
|
||||
if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )
|
||||
{
|
||||
/* We expected to receive the data. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Unsuspend the highest and high priority tasks so we can go back
|
||||
and repeat the whole thing. The medium priority task should not be
|
||||
suspended as it was not able to peek the data in this last case. */
|
||||
vTaskResume( xHighPriorityTask );
|
||||
vTaskResume( xHighestPriorityTask );
|
||||
|
||||
/* Lets just delay a while as this is an intensive test as we don't
|
||||
want to starve other tests of processing time. */
|
||||
vTaskDelay( qpeekSHORT_DELAY );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
BaseType_t xAreQueuePeekTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastLoopCounter = 0;
|
||||
|
||||
/* If the demo task is still running then we expect the loopcounter to
|
||||
have incremented since this function was last called. */
|
||||
if( ulLastLoopCounter == ulLoopCounter )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLastLoopCounter = ulLoopCounter;
|
||||
|
||||
/* Errors detected in the task itself will have latched xErrorDetected
|
||||
to true. */
|
||||
|
||||
return ( BaseType_t ) !xErrorDetected;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Basic task to demonstrate the xQueueOverwrite() function. See the comments
|
||||
* in the function itself.
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "QueueOverwrite.h"
|
||||
|
||||
/* A block time of 0 just means "don't block". */
|
||||
#define qoDONT_BLOCK 0
|
||||
|
||||
/* Number of times to overwrite the value in the queue. */
|
||||
#define qoLOOPS 5
|
||||
|
||||
/* The task that uses the queue. */
|
||||
static void prvQueueOverwriteTask( void *pvParameters );
|
||||
|
||||
/* Variable that is incremented on each loop of prvQueueOverwriteTask() provided
|
||||
prvQueueOverwriteTask() has not found any errors. */
|
||||
static uint32_t ulLoopCounter = 0;
|
||||
|
||||
/* Set to pdFALSE if an error is discovered by the
|
||||
vQueueOverwritePeriodicISRDemo() function. */
|
||||
static BaseType_t xISRTestStatus = pdPASS;
|
||||
|
||||
/* The queue that is accessed from the ISR. The queue accessed by the task is
|
||||
created inside the task itself. */
|
||||
static QueueHandle_t xISRQueue = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueueOverwriteTask( UBaseType_t uxPriority )
|
||||
{
|
||||
const UBaseType_t uxQueueLength = 1;
|
||||
|
||||
/* Create the queue used by the ISR. xQueueOverwriteFromISR() should only
|
||||
be used on queues that have a length of 1. */
|
||||
xISRQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) );
|
||||
|
||||
/* Create the test task. The queue used by the test task is created inside
|
||||
the task itself. */
|
||||
xTaskCreate( prvQueueOverwriteTask, "QOver", configMINIMAL_STACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueOverwriteTask( void *pvParameters )
|
||||
{
|
||||
QueueHandle_t xTaskQueue;
|
||||
const UBaseType_t uxQueueLength = 1;
|
||||
uint32_t ulValue, ulStatus = pdPASS, x;
|
||||
|
||||
/* The parameter is not used. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Create the queue. xQueueOverwrite() should only be used on queues that
|
||||
have a length of 1. */
|
||||
xTaskQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) );
|
||||
configASSERT( xTaskQueue );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The queue is empty. Writing to the queue then reading from the queue
|
||||
should return the item written. */
|
||||
ulValue = 10;
|
||||
xQueueOverwrite( xTaskQueue, &ulValue );
|
||||
|
||||
ulValue = 0;
|
||||
xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK );
|
||||
|
||||
if( ulValue != 10 )
|
||||
{
|
||||
ulStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Now try writing to the queue several times. Each time the value
|
||||
in the queue should get overwritten. */
|
||||
for( x = 0; x < qoLOOPS; x++ )
|
||||
{
|
||||
/* Write to the queue. */
|
||||
xQueueOverwrite( xTaskQueue, &x );
|
||||
|
||||
/* Check the value in the queue is that written, even though the
|
||||
queue was not necessarily empty. */
|
||||
xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK );
|
||||
if( ulValue != x )
|
||||
{
|
||||
ulStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* There should always be one item in the queue. */
|
||||
if( uxQueueMessagesWaiting( xTaskQueue ) != uxQueueLength )
|
||||
{
|
||||
ulStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Empty the queue again. */
|
||||
xQueueReceive( xTaskQueue, &ulValue, qoDONT_BLOCK );
|
||||
|
||||
if( uxQueueMessagesWaiting( xTaskQueue ) != 0 )
|
||||
{
|
||||
ulStatus = pdFAIL;
|
||||
}
|
||||
|
||||
if( ulStatus != pdFAIL )
|
||||
{
|
||||
/* Increment a counter to show this task is still running without
|
||||
error. */
|
||||
ulLoopCounter++;
|
||||
}
|
||||
|
||||
#if( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xIsQueueOverwriteTaskStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
if( xISRTestStatus != pdPASS )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else if( ulLoopCounter > 0 )
|
||||
{
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The task has either stalled of discovered an error. */
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
ulLoopCounter = 0;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vQueueOverwritePeriodicISRDemo( void )
|
||||
{
|
||||
static uint32_t ulCallCount = 0;
|
||||
const uint32_t ulTx1 = 10UL, ulTx2 = 20UL, ulNumberOfSwitchCases = 3UL;
|
||||
uint32_t ulRx;
|
||||
|
||||
/* This function should be called from an interrupt, such as the tick hook
|
||||
function vApplicationTickHook(). */
|
||||
|
||||
configASSERT( xISRQueue );
|
||||
|
||||
switch( ulCallCount )
|
||||
{
|
||||
case 0:
|
||||
/* The queue is empty. Write ulTx1 to the queue. In this demo the
|
||||
last parameter is not used because there are no tasks blocked on
|
||||
this queue. */
|
||||
xQueueOverwriteFromISR( xISRQueue, &ulTx1, NULL );
|
||||
|
||||
/* Peek the queue to check it holds the expected value. */
|
||||
xQueuePeekFromISR( xISRQueue, &ulRx );
|
||||
if( ulRx != ulTx1 )
|
||||
{
|
||||
xISRTestStatus = pdFAIL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* The queue already holds ulTx1. Overwrite the value in the queue
|
||||
with ulTx2. */
|
||||
xQueueOverwriteFromISR( xISRQueue, &ulTx2, NULL );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Read from the queue to empty the queue again. The value read
|
||||
should be ulTx2. */
|
||||
xQueueReceiveFromISR( xISRQueue, &ulRx, NULL );
|
||||
|
||||
if( ulRx != ulTx2 )
|
||||
{
|
||||
xISRTestStatus = pdFAIL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Run the next case in the switch statement above next time this function
|
||||
is called. */
|
||||
ulCallCount++;
|
||||
|
||||
if( ulCallCount >= ulNumberOfSwitchCases )
|
||||
{
|
||||
/* Go back to the start. */
|
||||
ulCallCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,738 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tests the use of queue sets.
|
||||
*
|
||||
* A receive task creates a number of queues and adds them to a queue set before
|
||||
* blocking on the queue set receive. A transmit task and (optionally) an
|
||||
* interrupt repeatedly unblocks the receive task by sending messages to the
|
||||
* queues in a pseudo random order. The receive task removes the messages from
|
||||
* the queues and flags an error if the received message does not match that
|
||||
* expected. The task sends values in the range 0 to
|
||||
* queuesetINITIAL_ISR_TX_VALUE, and the ISR sends value in the range
|
||||
* queuesetINITIAL_ISR_TX_VALUE to ULONG_MAX.
|
||||
*/
|
||||
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "QueueSet.h"
|
||||
|
||||
/* The number of queues that are created and added to the queue set. */
|
||||
#define queuesetNUM_QUEUES_IN_SET 3
|
||||
|
||||
/* The length of each created queue. */
|
||||
#define queuesetQUEUE_LENGTH 3
|
||||
|
||||
/* Block times used in this demo. A block time or 0 means "don't block". */
|
||||
#define queuesetSHORT_DELAY 200
|
||||
#define queuesetDONT_BLOCK 0
|
||||
|
||||
/* Messages are sent in incrementing order from both a task and an interrupt.
|
||||
The task sends values in the range 0 to 0xfffe, and the interrupt sends values
|
||||
in the range of 0xffff to ULONG_MAX. */
|
||||
#define queuesetINITIAL_ISR_TX_VALUE 0xffffUL
|
||||
|
||||
/* The priorities used in this demo. */
|
||||
#define queuesetLOW_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define queuesetMEDIUM_PRIORITY ( queuesetLOW_PRIORITY + 1 )
|
||||
|
||||
/* For test purposes the priority of the sending task is changed after every
|
||||
queuesetPRIORITY_CHANGE_LOOPS number of values are sent to a queue. */
|
||||
#define queuesetPRIORITY_CHANGE_LOOPS ( ( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ) * 2 )
|
||||
|
||||
/* The ISR sends to the queue every queuesetISR_TX_PERIOD ticks. */
|
||||
#define queuesetISR_TX_PERIOD ( 100UL )
|
||||
|
||||
/* A delay inserted when the Tx task changes its priority to be above the idle
|
||||
task priority to ensure the idle priority tasks get some CPU time before the
|
||||
next iteration of the queue set Tx task. */
|
||||
#define queuesetTX_LOOP_DELAY pdMS_TO_TICKS( ( TickType_t ) 200 )
|
||||
|
||||
/* The allowable maximum deviation between a received value and the expected
|
||||
received value. A deviation will occur when data is received from a queue
|
||||
inside an ISR in between a task receiving from a queue and the task checking
|
||||
the received value. */
|
||||
#define queuesetALLOWABLE_RX_DEVIATION 3
|
||||
|
||||
/* Ignore values that are at the boundaries of allowable values to make the
|
||||
testing of limits easier (don't have to deal with wrapping values). */
|
||||
#define queuesetIGNORED_BOUNDARY ( queuesetALLOWABLE_RX_DEVIATION * 2 )
|
||||
|
||||
typedef enum
|
||||
{
|
||||
eEqualPriority = 0, /* Tx and Rx tasks have the same priority. */
|
||||
eTxHigherPriority, /* The priority of the Tx task is above that of the Rx task. */
|
||||
eTxLowerPriority /* The priority of the Tx task is below that of the Rx task. */
|
||||
} eRelativePriorities;
|
||||
|
||||
/*
|
||||
* The task that periodically sends to the queue set.
|
||||
*/
|
||||
static void prvQueueSetSendingTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* The task that reads from the queue set.
|
||||
*/
|
||||
static void prvQueueSetReceivingTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Check the value received from a queue is the expected value. Some values
|
||||
* originate from the send task, some values originate from the ISR, with the
|
||||
* range of the value being used to distinguish between the two message
|
||||
* sources.
|
||||
*/
|
||||
static void prvCheckReceivedValue( uint32_t ulReceived );
|
||||
|
||||
/*
|
||||
* For purposes of test coverage, functions that read from and write to a
|
||||
* queue set from an ISR respectively.
|
||||
*/
|
||||
static void prvReceiveFromQueueInSetFromISR( void );
|
||||
static void prvSendToQueueInSetFromISR( void );
|
||||
|
||||
/*
|
||||
* Create the queues and add them to a queue set before resuming the Tx
|
||||
* task.
|
||||
*/
|
||||
static void prvSetupTest( void );
|
||||
|
||||
/*
|
||||
* Checks a value received from a queue falls within the range of expected
|
||||
* values.
|
||||
*/
|
||||
static BaseType_t prvCheckReceivedValueWithinExpectedRange( uint32_t ulReceived, uint32_t ulExpectedReceived );
|
||||
|
||||
/*
|
||||
* Increase test coverage by occasionally change the priorities of the two tasks
|
||||
* relative to each other. */
|
||||
static void prvChangeRelativePriorities( void );
|
||||
|
||||
/*
|
||||
* Local pseudo random number seed and return functions. Used to avoid calls
|
||||
* to the standard library.
|
||||
*/
|
||||
static size_t prvRand( void );
|
||||
static void prvSRand( size_t uxSeed );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queues that are added to the set. */
|
||||
static QueueHandle_t xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 };
|
||||
|
||||
/* Counts how many times each queue in the set is used to ensure all the
|
||||
queues are used. */
|
||||
static uint32_t ulQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 };
|
||||
|
||||
/* The handle of the queue set to which the queues are added. */
|
||||
static QueueSetHandle_t xQueueSet;
|
||||
|
||||
/* If the prvQueueSetReceivingTask() task has not detected any errors then
|
||||
it increments ulCycleCounter on each iteration.
|
||||
xAreQueueSetTasksStillRunning() returns pdPASS if the value of
|
||||
ulCycleCounter has changed between consecutive calls, and pdFALSE if
|
||||
ulCycleCounter has stopped incrementing (indicating an error condition). */
|
||||
static volatile uint32_t ulCycleCounter = 0UL;
|
||||
|
||||
/* Set to pdFAIL if an error is detected by any queue set task.
|
||||
ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */
|
||||
static volatile BaseType_t xQueueSetTasksStatus = pdPASS;
|
||||
|
||||
/* Just a flag to let the function that writes to a queue from an ISR know that
|
||||
the queues are setup and can be used. */
|
||||
static volatile BaseType_t xSetupComplete = pdFALSE;
|
||||
|
||||
/* The value sent to the queue from the ISR is file scope so the
|
||||
xAreQueeuSetTasksStillRunning() function can check it is incrementing as
|
||||
expected. */
|
||||
static volatile uint32_t ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE;
|
||||
|
||||
/* Used by the pseudo random number generator. */
|
||||
static size_t uxNextRand = 0;
|
||||
|
||||
/* The task handles are stored so their priorities can be changed. */
|
||||
TaskHandle_t xQueueSetSendingTask, xQueueSetReceivingTask;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueueSetTasks( void )
|
||||
{
|
||||
/* Create the tasks. */
|
||||
xTaskCreate( prvQueueSetSendingTask, "SetTx", configMINIMAL_STACK_SIZE, NULL, queuesetMEDIUM_PRIORITY, &xQueueSetSendingTask );
|
||||
|
||||
if( xQueueSetSendingTask != NULL )
|
||||
{
|
||||
xTaskCreate( prvQueueSetReceivingTask, "SetRx", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, &xQueueSetReceivingTask );
|
||||
|
||||
/* It is important that the sending task does not attempt to write to a
|
||||
queue before the queue has been created. It is therefore placed into
|
||||
the suspended state before the scheduler has started. It is resumed by
|
||||
the receiving task after the receiving task has created the queues and
|
||||
added the queues to the queue set. */
|
||||
vTaskSuspend( xQueueSetSendingTask );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreQueueSetTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastCycleCounter, ulLastISRTxValue = 0;
|
||||
static uint32_t ulLastQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 };
|
||||
BaseType_t xReturn = pdPASS, x;
|
||||
|
||||
if( ulLastCycleCounter == ulCycleCounter )
|
||||
{
|
||||
/* The cycle counter is no longer being incremented. Either one of the
|
||||
tasks is stalled or an error has been detected. */
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
ulLastCycleCounter = ulCycleCounter;
|
||||
|
||||
/* Ensure that all the queues in the set have been used. This ensures the
|
||||
test is working as intended and guards against the rand() in the Tx task
|
||||
missing some values. */
|
||||
for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )
|
||||
{
|
||||
if( ulLastQueueUsedCounter[ x ] == ulQueueUsedCounter[ x ] )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
ulLastQueueUsedCounter[ x ] = ulQueueUsedCounter[ x ];
|
||||
}
|
||||
|
||||
/* Check the global status flag. */
|
||||
if( xQueueSetTasksStatus != pdPASS )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
/* Check that the ISR is still sending values to the queues too. */
|
||||
if( ulISRTxValue == ulLastISRTxValue )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastISRTxValue = ulISRTxValue;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueSetSendingTask( void *pvParameters )
|
||||
{
|
||||
uint32_t ulTaskTxValue = 0;
|
||||
size_t uxQueueToWriteTo;
|
||||
QueueHandle_t xQueueInUse;
|
||||
|
||||
/* Remove compiler warning about the unused parameter. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Seed mini pseudo random number generator. */
|
||||
prvSRand( ( size_t ) &ulTaskTxValue );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Generate the index for the queue to which a value is to be sent. */
|
||||
uxQueueToWriteTo = prvRand() % queuesetNUM_QUEUES_IN_SET;
|
||||
xQueueInUse = xQueues[ uxQueueToWriteTo ];
|
||||
|
||||
/* Note which index is being written to to ensure all the queues are
|
||||
used. */
|
||||
( ulQueueUsedCounter[ uxQueueToWriteTo ] )++;
|
||||
|
||||
/* Send to the queue to unblock the task that is waiting for data to
|
||||
arrive on a queue within the queue set to which this queue belongs. */
|
||||
if( xQueueSendToBack( xQueueInUse, &ulTaskTxValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* The send should always pass as an infinite block time was
|
||||
used. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
#if( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
ulTaskTxValue++;
|
||||
|
||||
/* If the Tx value has reached the range used by the ISR then set it
|
||||
back to 0. */
|
||||
if( ulTaskTxValue == queuesetINITIAL_ISR_TX_VALUE )
|
||||
{
|
||||
ulTaskTxValue = 0;
|
||||
}
|
||||
|
||||
/* Increase test coverage by occasionally change the priorities of the
|
||||
two tasks relative to each other. */
|
||||
prvChangeRelativePriorities();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvChangeRelativePriorities( void )
|
||||
{
|
||||
static UBaseType_t ulLoops = 0;
|
||||
static eRelativePriorities ePriorities = eEqualPriority;
|
||||
|
||||
/* Occasionally change the task priority relative to the priority of
|
||||
the receiving task. */
|
||||
ulLoops++;
|
||||
if( ulLoops >= queuesetPRIORITY_CHANGE_LOOPS )
|
||||
{
|
||||
ulLoops = 0;
|
||||
|
||||
switch( ePriorities )
|
||||
{
|
||||
case eEqualPriority:
|
||||
/* Both tasks are running with medium priority. Now lower the
|
||||
priority of the receiving task so the Tx task has the higher
|
||||
relative priority. */
|
||||
vTaskPrioritySet( xQueueSetReceivingTask, queuesetLOW_PRIORITY );
|
||||
ePriorities = eTxHigherPriority;
|
||||
break;
|
||||
|
||||
case eTxHigherPriority:
|
||||
/* The Tx task is running with a higher priority than the Rx
|
||||
task. Switch the priorities around so the Rx task has the
|
||||
higher relative priority. */
|
||||
vTaskPrioritySet( xQueueSetReceivingTask, queuesetMEDIUM_PRIORITY );
|
||||
vTaskPrioritySet( xQueueSetSendingTask, queuesetLOW_PRIORITY );
|
||||
ePriorities = eTxLowerPriority;
|
||||
break;
|
||||
|
||||
case eTxLowerPriority:
|
||||
/* The Tx task is running with a lower priority than the Rx
|
||||
task. Make the priorities equal again. */
|
||||
vTaskPrioritySet( xQueueSetSendingTask, queuesetMEDIUM_PRIORITY );
|
||||
ePriorities = eEqualPriority;
|
||||
|
||||
/* When both tasks are using a non-idle priority the queue set
|
||||
tasks will starve idle priority tasks of execution time - so
|
||||
relax a bit before the next iteration to minimise the impact. */
|
||||
vTaskDelay( queuesetTX_LOOP_DELAY );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueSetReceivingTask( void *pvParameters )
|
||||
{
|
||||
uint32_t ulReceived;
|
||||
QueueHandle_t xActivatedQueue;
|
||||
TickType_t xBlockTime;
|
||||
|
||||
/* Remove compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Create the queues and add them to the queue set before resuming the Tx
|
||||
task. */
|
||||
prvSetupTest();
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* For test coverage reasons, the block time is dependent on the
|
||||
priority of this task - which changes during the test. When the task
|
||||
is at the idle priority it polls the queue set. */
|
||||
if( uxTaskPriorityGet( NULL ) == tskIDLE_PRIORITY )
|
||||
{
|
||||
xBlockTime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xBlockTime = portMAX_DELAY;
|
||||
}
|
||||
|
||||
/* Wait for a message to arrive on one of the queues in the set. */
|
||||
xActivatedQueue = xQueueSelectFromSet( xQueueSet, portMAX_DELAY );
|
||||
|
||||
if( xActivatedQueue == NULL )
|
||||
{
|
||||
if( xBlockTime != 0 )
|
||||
{
|
||||
/* This should not happen as an infinite delay was used. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reading from the queue should pass with a zero block time as
|
||||
this task will only run when something has been posted to a task
|
||||
in the queue set. */
|
||||
if( xQueueReceive( xActivatedQueue, &ulReceived, queuesetDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Ensure the value received was the value expected. This function
|
||||
manipulates file scope data and is also called from an ISR, hence
|
||||
the critical section. */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
prvCheckReceivedValue( ulReceived );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
if( xQueueSetTasksStatus == pdPASS )
|
||||
{
|
||||
ulCycleCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vQueueSetAccessQueueSetFromISR( void )
|
||||
{
|
||||
static uint32_t ulCallCount = 0;
|
||||
|
||||
/* xSetupComplete is set to pdTRUE when the queues have been created and
|
||||
are available for use. */
|
||||
if( xSetupComplete == pdTRUE )
|
||||
{
|
||||
/* It is intended that this function is called from the tick hook
|
||||
function, so each call is one tick period apart. */
|
||||
ulCallCount++;
|
||||
if( ulCallCount > queuesetISR_TX_PERIOD )
|
||||
{
|
||||
ulCallCount = 0;
|
||||
|
||||
/* First attempt to read from the queue set. */
|
||||
prvReceiveFromQueueInSetFromISR();
|
||||
|
||||
/* Then write to the queue set. */
|
||||
prvSendToQueueInSetFromISR();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckReceivedValue( uint32_t ulReceived )
|
||||
{
|
||||
static uint32_t ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;
|
||||
|
||||
/* Values are received in tasks and interrupts. It is likely that the
|
||||
receiving task will sometimes get preempted by the receiving interrupt
|
||||
between reading a value from the queue and calling this function. When
|
||||
that happens, if the receiving interrupt calls this function the values
|
||||
will get passed into this function slightly out of order. For that
|
||||
reason the value passed in is tested against a small range of expected
|
||||
values, rather than a single absolute value. To make the range testing
|
||||
easier values in the range limits are ignored. */
|
||||
|
||||
/* If the received value is equal to or greater than
|
||||
queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */
|
||||
if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE )
|
||||
{
|
||||
/* The value was sent from the ISR. */
|
||||
if( ( ulReceived - queuesetINITIAL_ISR_TX_VALUE ) < queuesetIGNORED_BOUNDARY )
|
||||
{
|
||||
/* The value received is at the lower limit of the expected range.
|
||||
Don't test it and expect to receive one higher next time. */
|
||||
}
|
||||
else if( ( ULONG_MAX - ulReceived ) <= queuesetIGNORED_BOUNDARY )
|
||||
{
|
||||
/* The value received is at the higher limit of the expected range.
|
||||
Don't test it and expect to wrap soon. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check the value against its expected value range. */
|
||||
if( prvCheckReceivedValueWithinExpectedRange( ulReceived, ulExpectedReceivedFromISR ) != pdPASS )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
configASSERT( xQueueSetTasksStatus );
|
||||
|
||||
/* It is expected to receive an incrementing number. */
|
||||
ulExpectedReceivedFromISR++;
|
||||
if( ulExpectedReceivedFromISR == 0 )
|
||||
{
|
||||
ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The value was sent from the Tx task. */
|
||||
if( ulReceived < queuesetIGNORED_BOUNDARY )
|
||||
{
|
||||
/* The value received is at the lower limit of the expected range.
|
||||
Don't test it, and expect to receive one higher next time. */
|
||||
}
|
||||
else if( ( ( queuesetINITIAL_ISR_TX_VALUE - 1 ) - ulReceived ) <= queuesetIGNORED_BOUNDARY )
|
||||
{
|
||||
/* The value received is at the higher limit of the expected range.
|
||||
Don't test it and expect to wrap soon. */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check the value against its expected value range. */
|
||||
if( prvCheckReceivedValueWithinExpectedRange( ulReceived, ulExpectedReceivedFromTask ) != pdPASS )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
configASSERT( xQueueSetTasksStatus );
|
||||
|
||||
/* It is expected to receive an incrementing number. */
|
||||
ulExpectedReceivedFromTask++;
|
||||
if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE )
|
||||
{
|
||||
ulExpectedReceivedFromTask = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t prvCheckReceivedValueWithinExpectedRange( uint32_t ulReceived, uint32_t ulExpectedReceived )
|
||||
{
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
if( ulReceived > ulExpectedReceived )
|
||||
{
|
||||
configASSERT( ( ulReceived - ulExpectedReceived ) <= queuesetALLOWABLE_RX_DEVIATION );
|
||||
if( ( ulReceived - ulExpectedReceived ) > queuesetALLOWABLE_RX_DEVIATION )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
configASSERT( ( ulExpectedReceived - ulReceived ) <= queuesetALLOWABLE_RX_DEVIATION );
|
||||
if( ( ulExpectedReceived - ulReceived ) > queuesetALLOWABLE_RX_DEVIATION )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvReceiveFromQueueInSetFromISR( void )
|
||||
{
|
||||
QueueSetMemberHandle_t xActivatedQueue;
|
||||
uint32_t ulReceived;
|
||||
|
||||
/* See if any of the queues in the set contain data. */
|
||||
xActivatedQueue = xQueueSelectFromSetFromISR( xQueueSet );
|
||||
|
||||
if( xActivatedQueue != NULL )
|
||||
{
|
||||
/* Reading from the queue for test purposes only. */
|
||||
if( xQueueReceiveFromISR( xActivatedQueue, &ulReceived, NULL ) != pdPASS )
|
||||
{
|
||||
/* Data should have been available as the handle was returned from
|
||||
xQueueSelectFromSetFromISR(). */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Ensure the value received was the value expected. */
|
||||
prvCheckReceivedValue( ulReceived );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSendToQueueInSetFromISR( void )
|
||||
{
|
||||
static BaseType_t xQueueToWriteTo = 0;
|
||||
|
||||
if( xQueueSendFromISR( xQueues[ xQueueToWriteTo ], ( void * ) &ulISRTxValue, NULL ) == pdPASS )
|
||||
{
|
||||
ulISRTxValue++;
|
||||
|
||||
/* If the Tx value has wrapped then set it back to its initial value. */
|
||||
if( ulISRTxValue == 0UL )
|
||||
{
|
||||
ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE;
|
||||
}
|
||||
|
||||
/* Use a different queue next time. */
|
||||
xQueueToWriteTo++;
|
||||
if( xQueueToWriteTo >= queuesetNUM_QUEUES_IN_SET )
|
||||
{
|
||||
xQueueToWriteTo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSetupTest( void )
|
||||
{
|
||||
BaseType_t x;
|
||||
uint32_t ulValueToSend = 0;
|
||||
|
||||
/* Ensure the queues are created and the queue set configured before the
|
||||
sending task is unsuspended.
|
||||
|
||||
First Create the queue set such that it will be able to hold a message for
|
||||
every space in every queue in the set. */
|
||||
xQueueSet = xQueueCreateSet( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH );
|
||||
|
||||
for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )
|
||||
{
|
||||
/* Create the queue and add it to the set. The queue is just holding
|
||||
uint32_t value. */
|
||||
xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( uint32_t ) );
|
||||
configASSERT( xQueues[ x ] );
|
||||
if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdPASS )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The queue has now been added to the queue set and cannot be added to
|
||||
another. */
|
||||
if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdFAIL )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to remove a queue from a queue set it does not belong
|
||||
to (NULL being passed as the queue set in this case). */
|
||||
if( xQueueRemoveFromSet( xQueues[ 0 ], NULL ) != pdFAIL )
|
||||
{
|
||||
/* It is not possible to successfully remove a queue from a queue
|
||||
set it does not belong to. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Attempt to remove a queue from the queue set it does belong to. */
|
||||
if( xQueueRemoveFromSet( xQueues[ 0 ], xQueueSet ) != pdPASS )
|
||||
{
|
||||
/* It should be possible to remove the queue from the queue set it
|
||||
does belong to. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Add an item to the queue before attempting to add it back into the
|
||||
set. */
|
||||
xQueueSend( xQueues[ 0 ], ( void * ) &ulValueToSend, 0 );
|
||||
if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdFAIL )
|
||||
{
|
||||
/* Should not be able to add a non-empty queue to a set. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Remove the item from the queue before adding the queue back into the
|
||||
set so the dynamic tests can begin. */
|
||||
xQueueReceive( xQueues[ 0 ], &ulValueToSend, 0 );
|
||||
if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdPASS )
|
||||
{
|
||||
/* If the queue was successfully removed from the queue set then it
|
||||
should be possible to add it back in again. */
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* The task that sends to the queues is not running yet, so attempting to
|
||||
read from the queue set should fail. */
|
||||
if( xQueueSelectFromSet( xQueueSet, queuesetSHORT_DELAY ) != NULL )
|
||||
{
|
||||
xQueueSetTasksStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* Resume the task that writes to the queues. */
|
||||
vTaskResume( xQueueSetSendingTask );
|
||||
|
||||
/* Let the ISR access the queues also. */
|
||||
xSetupComplete = pdTRUE;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static size_t prvRand( void )
|
||||
{
|
||||
uxNextRand = ( uxNextRand * ( size_t ) 1103515245 ) + ( size_t ) 12345;
|
||||
return ( uxNextRand / ( size_t ) 65536 ) % ( size_t ) 32768;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSRand( size_t uxSeed )
|
||||
{
|
||||
uxNextRand = uxSeed;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tests the use of queue sets.
|
||||
*
|
||||
* A receive task creates a number of queues and adds them to a queue set before
|
||||
* blocking on the queue set receive. A transmit task and (optionally) an
|
||||
* interrupt repeatedly unblocks the receive task by sending messages to the
|
||||
* queues in a pseudo random order. The receive task removes the messages from
|
||||
* the queues and flags an error if the received message does not match that
|
||||
* expected. The task sends values in the range 0 to
|
||||
* queuesetINITIAL_ISR_TX_VALUE, and the ISR sends value in the range
|
||||
* queuesetINITIAL_ISR_TX_VALUE to ULONG_MAX.
|
||||
*/
|
||||
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "QueueSetPolling.h"
|
||||
|
||||
/* The length of each created queue. */
|
||||
#define setpollQUEUE_LENGTH 10
|
||||
|
||||
/* Block times used in this demo. A block time or 0 means "don't block". */
|
||||
#define setpollDONT_BLOCK 0
|
||||
|
||||
/* The ISR sends to the queue every setpollISR_TX_PERIOD ticks. */
|
||||
#define queuesetISR_TX_PERIOD ( 50UL )
|
||||
|
||||
/*
|
||||
* The task that reads from the queue set.
|
||||
*/
|
||||
static void prvQueueSetReceivingTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue that is added to the set. */
|
||||
static QueueHandle_t xQueue = NULL;
|
||||
|
||||
/* The handle of the queue set to which the queue is added. */
|
||||
static QueueSetHandle_t xQueueSet = NULL;
|
||||
|
||||
/* Set to pdFAIL if an error is detected by any queue set task.
|
||||
ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */
|
||||
static volatile BaseType_t xQueueSetPollStatus = pdPASS;
|
||||
|
||||
/* Counter used to ensure the task is still running. */
|
||||
static uint32_t ulCycleCounter = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueueSetPollingTask( void )
|
||||
{
|
||||
/* Create the queue that is added to the set, the set, and add the queue to
|
||||
the set. */
|
||||
xQueue = xQueueCreate( setpollQUEUE_LENGTH, sizeof( uint32_t ) );
|
||||
xQueueSet = xQueueCreateSet( setpollQUEUE_LENGTH );
|
||||
|
||||
if( ( xQueue != NULL ) && ( xQueueSet != NULL ) )
|
||||
{
|
||||
xQueueAddToSet( xQueue, xQueueSet );
|
||||
|
||||
/* Create the task. */
|
||||
xTaskCreate( prvQueueSetReceivingTask, "SetPoll", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueSetReceivingTask( void *pvParameters )
|
||||
{
|
||||
uint32_t ulReceived, ulExpected = 0;
|
||||
QueueHandle_t xActivatedQueue;
|
||||
|
||||
/* Remove compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Is a message waiting? A block time is not used to ensure the queue
|
||||
set is polled while it is being written to from an interrupt. */
|
||||
xActivatedQueue = xQueueSelectFromSet( xQueueSet, setpollDONT_BLOCK );
|
||||
|
||||
if( xActivatedQueue != NULL )
|
||||
{
|
||||
/* Reading from the queue should pass with a zero block time as
|
||||
this task will only run when something has been posted to a task
|
||||
in the queue set. */
|
||||
if( xQueueReceive( xActivatedQueue, &ulReceived, setpollDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xQueueSetPollStatus = pdFAIL;
|
||||
}
|
||||
|
||||
if( ulReceived == ulExpected )
|
||||
{
|
||||
ulExpected++;
|
||||
}
|
||||
else
|
||||
{
|
||||
xQueueSetPollStatus = pdFAIL;
|
||||
}
|
||||
|
||||
if( xQueueSetPollStatus == pdPASS )
|
||||
{
|
||||
ulCycleCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vQueueSetPollingInterruptAccess( void )
|
||||
{
|
||||
static uint32_t ulCallCount = 0, ulValueToSend = 0;
|
||||
|
||||
/* It is intended that this function is called from the tick hook
|
||||
function, so each call is one tick period apart. */
|
||||
ulCallCount++;
|
||||
if( ulCallCount > queuesetISR_TX_PERIOD )
|
||||
{
|
||||
ulCallCount = 0;
|
||||
|
||||
if( xQueueSendFromISR( xQueue, ( void * ) &ulValueToSend, NULL ) == pdPASS )
|
||||
{
|
||||
/* Send the next value next time. */
|
||||
ulValueToSend++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreQueueSetPollTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastCycleCounter = 0;
|
||||
|
||||
if( ulLastCycleCounter == ulCycleCounter )
|
||||
{
|
||||
xQueueSetPollStatus = pdFAIL;
|
||||
}
|
||||
|
||||
ulLastCycleCounter = ulCycleCounter;
|
||||
|
||||
return xQueueSetPollStatus;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Tests the behaviour of direct task notifications.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <limits.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "TaskNotify.h"
|
||||
|
||||
#define notifyTASK_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define notifyUINT32_MAX ( ( uint32_t ) 0xffffffff )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Implementation of the task that gets notified.
|
||||
*/
|
||||
static void prvNotifiedTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Performs a few initial tests that can be done prior to creating the second
|
||||
* task.
|
||||
*/
|
||||
static void prvSingleTaskTests( void );
|
||||
|
||||
/*
|
||||
* Software timer callback function from which xTaskNotify() is called.
|
||||
*/
|
||||
static void prvNotifyingTimer( TimerHandle_t xTimer );
|
||||
|
||||
/*
|
||||
* Utility function to create pseudo random numbers.
|
||||
*/
|
||||
static UBaseType_t prvRand( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Used to latch errors during the test's execution. */
|
||||
static BaseType_t xErrorStatus = pdPASS;
|
||||
|
||||
/* Used to ensure the task has not stalled. */
|
||||
static volatile uint32_t ulNotifyCycleCount = 0;
|
||||
|
||||
/* The handle of the task that receives the notifications. */
|
||||
static TaskHandle_t xTaskToNotify = NULL;
|
||||
|
||||
/* Used to count the notifications sent to the task from a software timer and
|
||||
the number of notifications received by the task from the software timer. The
|
||||
two should stay synchronised. */
|
||||
static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL;
|
||||
|
||||
/* The timer used to notify the task. */
|
||||
static TimerHandle_t xTimer = NULL;
|
||||
|
||||
/* Used by the pseudo random number generating function. */
|
||||
static size_t uxNextRand = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartTaskNotifyTask( void )
|
||||
{
|
||||
/* Create the task that performs some tests by itself, then loops around
|
||||
being notified by both a software timer and an interrupt. */
|
||||
xTaskCreate( prvNotifiedTask, "Notified", configMINIMAL_STACK_SIZE, NULL, notifyTASK_PRIORITY, &xTaskToNotify );
|
||||
|
||||
/* Pseudo seed the random number generator. */
|
||||
uxNextRand = ( size_t ) prvRand;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSingleTaskTests( void )
|
||||
{
|
||||
const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
|
||||
BaseType_t xReturned;
|
||||
uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue, ulPreviousValue, ulExpectedValue;
|
||||
TickType_t xTimeOnEntering;
|
||||
const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;
|
||||
const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Check blocking when there are no notifications. */
|
||||
xTimeOnEntering = xTaskGetTickCount();
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
|
||||
|
||||
/* Should have blocked for the entire block time. */
|
||||
if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )
|
||||
{
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
configASSERT( ulNotifiedValue == 0UL );
|
||||
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Check no blocking when notifications are pending. First notify itself -
|
||||
this would not be a normal thing to do and is done here for test purposes
|
||||
only. */
|
||||
xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
|
||||
|
||||
/* Even through the 'without overwrite' action was used the update should
|
||||
have been successful. */
|
||||
configASSERT( xReturned == pdPASS );
|
||||
|
||||
/* No bits should have been pending previously. */
|
||||
configASSERT( ulPreviousValue == 0 );
|
||||
|
||||
/* The task should now have a notification pending, and so not time out. */
|
||||
xTimeOnEntering = xTaskGetTickCount();
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
|
||||
|
||||
if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )
|
||||
{
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* The task should have been notified, and the notified value should
|
||||
be equal to ulFirstNotifiedConst. */
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
|
||||
|
||||
/* Incremented to show the task is still running. */
|
||||
ulNotifyCycleCount++;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Check the non-overwriting functionality. The notification is done twice
|
||||
using two different notification values. The action says don't overwrite so
|
||||
only the first notification should pass and the value read back should also
|
||||
be that used with the first notification. */
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
|
||||
/* Waiting for the notification should now return immediately so a block
|
||||
time of zero is used. */
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Do the same again, only this time use the overwriting version. This time
|
||||
both notifications should pass, and the value written the second time should
|
||||
overwrite the value written the first time, and so be the value that is read
|
||||
back. */
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Check notifications with no action pass without updating the value. Even
|
||||
though ulFirstNotifiedConst is used as the value the value read back should
|
||||
remain at ulSecondNotifiedConst. */
|
||||
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Check incrementing values. Send ulMaxLoop increment notifications, then
|
||||
ensure the received value is as expected - which should be
|
||||
ulSecondNotificationValueConst plus how ever many times to loop iterated. */
|
||||
for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
|
||||
{
|
||||
xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
}
|
||||
|
||||
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
|
||||
|
||||
/* Should not be any notifications pending now. */
|
||||
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Check all bits can be set by notifying the task with one additional bit set
|
||||
on each notification, and exiting the loop when all the bits are found to be
|
||||
set. As there are 32-bits the loop should execute 32 times before all the
|
||||
bits are found to be set. */
|
||||
ulNotifyingValue = 0x01;
|
||||
ulLoop = 0;
|
||||
|
||||
/* Start with all bits clear. */
|
||||
xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
|
||||
do
|
||||
{
|
||||
/* Set the next bit in the task's notified value. */
|
||||
xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );
|
||||
|
||||
/* Wait for the notified value - which of course will already be
|
||||
available. Don't clear the bits on entry or exit as this loop is exited
|
||||
when all the bits are set. */
|
||||
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
|
||||
ulLoop++;
|
||||
|
||||
/* Use the next bit on the next iteration around this loop. */
|
||||
ulNotifyingValue <<= 1UL;
|
||||
|
||||
} while ( ulNotifiedValue != notifyUINT32_MAX );
|
||||
|
||||
/* As a 32-bit value was used the loop should have executed 32 times before
|
||||
all the bits were set. */
|
||||
configASSERT( ulLoop == 32 );
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Check bits are cleared on entry but not on exit when a notification fails
|
||||
to arrive before timing out - both with and without a timeout value. Wait
|
||||
for the notification again - but this time it is not given by anything and
|
||||
should return pdFAIL. The parameters are set to clear bit zero on entry and
|
||||
bit one on exit. As no notification was received only the bit cleared on
|
||||
entry should actually get cleared. */
|
||||
xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
|
||||
/* Notify the task with no action so as not to update the bits even though
|
||||
notifyUINT32_MAX is used as the notification value. */
|
||||
xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eNoAction );
|
||||
|
||||
/* Reading back the value should should find bit 0 is clear, as this was
|
||||
cleared on entry, but bit 1 is not clear as it will not have been cleared on
|
||||
exit as no notification was received. */
|
||||
xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdPASS );
|
||||
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Now try clearing the bit on exit. For that to happen a notification must be
|
||||
received, so the task is notified first. */
|
||||
xTaskNotify( xTaskToNotify, 0, eNoAction );
|
||||
xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 );
|
||||
|
||||
/* However as the bit is cleared on exit, after the returned notification
|
||||
value is set, the returned notification value should not have the bit
|
||||
cleared... */
|
||||
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
|
||||
|
||||
/* ...but reading the value back again should find that the bit was indeed
|
||||
cleared internally. The returned value should be pdFAIL however as nothing
|
||||
has notified the task in the mean time. */
|
||||
xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );
|
||||
configASSERT( xReturned == pdFAIL );
|
||||
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
Now try querying the previus value while notifying a task. */
|
||||
xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
|
||||
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
|
||||
|
||||
/* Clear all bits. */
|
||||
xTaskNotifyWait( 0x00, notifyUINT32_MAX, &ulNotifiedValue, 0 );
|
||||
xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
|
||||
configASSERT( ulPreviousValue == 0 );
|
||||
|
||||
ulExpectedValue = 0;
|
||||
for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )
|
||||
{
|
||||
/* Set the next bit up, and expect to receive the last bits set (so
|
||||
the previous value will not yet have the bit being set this time
|
||||
around). */
|
||||
xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );
|
||||
configASSERT( ulExpectedValue == ulPreviousValue );
|
||||
ulExpectedValue |= ulLoop;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Clear the previous notifications. */
|
||||
xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||||
|
||||
/* The task should not have any notifications pending, so an attempt to clear
|
||||
the notification state should fail. */
|
||||
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
|
||||
|
||||
/* Get the task to notify itself. This is not a normal thing to do, and is
|
||||
only done here for test purposes. */
|
||||
xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
|
||||
|
||||
/* Now the notification state should be eNotified, so it should now be
|
||||
possible to clear the notification state. */
|
||||
configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
|
||||
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
|
||||
|
||||
|
||||
|
||||
|
||||
/* Incremented to show the task is still running. */
|
||||
ulNotifyCycleCount++;
|
||||
|
||||
/* Leave all bits cleared. */
|
||||
xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvNotifyingTimer( TimerHandle_t xNotUsed )
|
||||
{
|
||||
( void ) xNotUsed;
|
||||
|
||||
xTaskNotifyGive( xTaskToNotify );
|
||||
|
||||
/* This value is also incremented from an interrupt. */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
ulTimerNotificationsSent++;
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvNotifiedTask( void *pvParameters )
|
||||
{
|
||||
const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0;
|
||||
TickType_t xPeriod;
|
||||
const uint32_t ulCyclesToRaisePriority = 50UL;
|
||||
|
||||
/* Remove compiler warnings about unused parameters. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Run a few tests that can be done from a single task before entering the
|
||||
main loop. */
|
||||
prvSingleTaskTests();
|
||||
|
||||
/* Create the software timer that is used to send notifications to this
|
||||
task. Notifications are also received from an interrupt. */
|
||||
xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Start the timer again with a different period. Sometimes the period
|
||||
will be higher than the tasks block time, sometimes it will be lower
|
||||
than the tasks block time. */
|
||||
xPeriod = prvRand() % xMaxPeriod;
|
||||
if( xPeriod < xMinPeriod )
|
||||
{
|
||||
xPeriod = xMinPeriod;
|
||||
}
|
||||
|
||||
/* Change the timer period and start the timer. */
|
||||
xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );
|
||||
|
||||
/* Block waiting for the notification again with a different period.
|
||||
Sometimes the period will be higher than the tasks block time, sometimes
|
||||
it will be lower than the tasks block time. */
|
||||
xPeriod = prvRand() % xMaxPeriod;
|
||||
if( xPeriod < xMinPeriod )
|
||||
{
|
||||
xPeriod = xMinPeriod;
|
||||
}
|
||||
|
||||
/* Block to wait for a notification but without clearing the
|
||||
notification count, so only add one to the count of received
|
||||
notifications as any other notifications will remain pending. */
|
||||
if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )
|
||||
{
|
||||
ulTimerNotificationsReceived++;
|
||||
}
|
||||
|
||||
|
||||
/* Take a notification without clearing again, but this time without a
|
||||
block time specified. */
|
||||
if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )
|
||||
{
|
||||
ulTimerNotificationsReceived++;
|
||||
}
|
||||
|
||||
/* Wait for the next notification from the timer, clearing all
|
||||
notifications if one is received, so this time adding the total number
|
||||
of notifications that were pending as none will be left pending after
|
||||
the function call. */
|
||||
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );
|
||||
|
||||
/* Occasionally raise the priority of the task being notified to test
|
||||
the path where the task is notified from an ISR and becomes the highest
|
||||
priority ready state task, but the pxHigherPriorityTaskWoken parameter
|
||||
is NULL (which it is in the tick hook that sends notifications to this
|
||||
task. */
|
||||
if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )
|
||||
{
|
||||
vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );
|
||||
|
||||
/* Wait for the next notification again, clearing all notifications if
|
||||
one is received, but this time blocking indefinitely. */
|
||||
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||
|
||||
/* Reset the priority. */
|
||||
vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for the next notification again, clearing all notifications if
|
||||
one is received, but this time blocking indefinitely. */
|
||||
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
|
||||
}
|
||||
|
||||
/* Incremented to show the task is still running. */
|
||||
ulNotifyCycleCount++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void xNotifyTaskFromISR( void )
|
||||
{
|
||||
static BaseType_t xCallCount = 0, xAPIToUse = 0;
|
||||
const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
|
||||
uint32_t ulPreviousValue;
|
||||
const uint32_t ulUnexpectedValue = 0xff;
|
||||
|
||||
/* The task performs some tests before starting the timer that gives the
|
||||
notification from this interrupt. If the timer has not been created yet
|
||||
then the initial tests have not yet completed and the notification should
|
||||
not be sent. */
|
||||
if( xTimer != NULL )
|
||||
{
|
||||
xCallCount++;
|
||||
|
||||
if( xCallCount >= xCallInterval )
|
||||
{
|
||||
/* It is time to 'give' the notification again. */
|
||||
xCallCount = 0;
|
||||
|
||||
/* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
|
||||
and xTaskNotifyAndQueryFromISR(). */
|
||||
switch( xAPIToUse )
|
||||
{
|
||||
case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL );
|
||||
xAPIToUse++;
|
||||
break;
|
||||
|
||||
case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );
|
||||
xAPIToUse++;
|
||||
break;
|
||||
|
||||
case 2: ulPreviousValue = ulUnexpectedValue;
|
||||
xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );
|
||||
configASSERT( ulPreviousValue != ulUnexpectedValue );
|
||||
xAPIToUse = 0;
|
||||
break;
|
||||
|
||||
default:/* Should never get here!. */
|
||||
break;
|
||||
}
|
||||
|
||||
ulTimerNotificationsSent++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check the created tasks are still running and have not
|
||||
detected any errors. */
|
||||
BaseType_t xAreTaskNotificationTasksStillRunning( void )
|
||||
{
|
||||
static uint32_t ulLastNotifyCycleCount = 0;
|
||||
const uint32_t ulMaxSendReceiveDeviation = 5UL;
|
||||
|
||||
/* Check the cycle count is still incrementing to ensure the task is still
|
||||
actually running. */
|
||||
if( ulLastNotifyCycleCount == ulNotifyCycleCount )
|
||||
{
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulLastNotifyCycleCount = ulNotifyCycleCount;
|
||||
}
|
||||
|
||||
/* Check the count of 'takes' from the software timer is keeping track with
|
||||
the amount of 'gives'. */
|
||||
if( ulTimerNotificationsSent > ulTimerNotificationsReceived )
|
||||
{
|
||||
if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )
|
||||
{
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return xErrorStatus;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static UBaseType_t prvRand( void )
|
||||
{
|
||||
const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1;
|
||||
|
||||
/* Utility function to generate a pseudo random number. */
|
||||
uxNextRand = ( uxMultiplier * uxNextRand ) + uxIncrement;
|
||||
return( ( uxNextRand >> 16 ) & ( ( size_t ) 0x7fff ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,582 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some test scenarios that ensure tasks do not exit queue
|
||||
* send or receive functions prematurely. A description of the tests is
|
||||
* included within the code.
|
||||
*/
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "blocktim.h"
|
||||
|
||||
/* Task priorities. Allow these to be overridden. */
|
||||
#ifndef bktPRIMARY_PRIORITY
|
||||
#define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
|
||||
#endif
|
||||
|
||||
#ifndef bktSECONDARY_PRIORITY
|
||||
#define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
|
||||
#endif
|
||||
|
||||
/* Task behaviour. */
|
||||
#define bktQUEUE_LENGTH ( 5 )
|
||||
#define bktSHORT_WAIT pdMS_TO_TICKS( ( TickType_t ) 20 )
|
||||
#define bktPRIMARY_BLOCK_TIME ( 10 )
|
||||
#define bktALLOWABLE_MARGIN ( 15 )
|
||||
#define bktTIME_TO_BLOCK ( 175 )
|
||||
#define bktDONT_BLOCK ( ( TickType_t ) 0 )
|
||||
#define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 )
|
||||
|
||||
/* In case the demo does not have software timers enabled, as this file uses
|
||||
the configTIMER_TASK_PRIORITY setting. */
|
||||
#ifndef configTIMER_TASK_PRIORITY
|
||||
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The two test tasks. Their behaviour is commented within the functions.
|
||||
*/
|
||||
static void vPrimaryBlockTimeTestTask( void *pvParameters );
|
||||
static void vSecondaryBlockTimeTestTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Very basic tests to verify the block times are as expected.
|
||||
*/
|
||||
static void prvBasicDelayTests( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The queue on which the tasks block. */
|
||||
static QueueHandle_t xTestQueue;
|
||||
|
||||
/* Handle to the secondary task is required by the primary task for calls
|
||||
to vTaskSuspend/Resume(). */
|
||||
static TaskHandle_t xSecondary;
|
||||
|
||||
/* Used to ensure that tasks are still executing without error. */
|
||||
static volatile BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;
|
||||
static volatile BaseType_t xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Provides a simple mechanism for the primary task to know when the
|
||||
secondary task has executed. */
|
||||
static volatile UBaseType_t xRunIndicator;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateBlockTimeTasks( void )
|
||||
{
|
||||
/* Create the queue on which the two tasks block. */
|
||||
xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) );
|
||||
|
||||
if( xTestQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one
|
||||
is in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware
|
||||
debugger is not being used. The call to vQueueAddToRegistry() will be
|
||||
removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
|
||||
defined or is defined to be less than 1. */
|
||||
vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" );
|
||||
|
||||
/* Create the two test tasks. */
|
||||
xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
|
||||
xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPrimaryBlockTimeTestTask( void *pvParameters )
|
||||
{
|
||||
BaseType_t xItem, xData;
|
||||
TickType_t xTimeWhenBlocking;
|
||||
TickType_t xTimeToBlock, xBlockedTime;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/*********************************************************************
|
||||
Test 0
|
||||
|
||||
Basic vTaskDelay() and vTaskDelayUntil() tests. */
|
||||
prvBasicDelayTests();
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
Test 1
|
||||
|
||||
Simple block time wakeup test on queue receives. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* The queue is empty. Attempt to read from the queue using a block
|
||||
time. When we wake, ensure the delta in time is as expected. */
|
||||
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
|
||||
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after xTimeToBlock having not received
|
||||
anything on the queue. */
|
||||
if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we blocked for? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
if( xBlockedTime < xTimeToBlock )
|
||||
{
|
||||
/* Should not have blocked for less than we requested. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
/* Should not have blocked for longer than we requested,
|
||||
although we would not necessarily run as soon as we were
|
||||
unblocked so a margin is allowed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Test 2
|
||||
|
||||
Simple block time wakeup test on queue sends.
|
||||
|
||||
First fill the queue. It should be empty so all sends should pass. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* The queue is full. Attempt to write to the queue using a block
|
||||
time. When we wake, ensure the delta in time is as expected. */
|
||||
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
|
||||
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after xTimeToBlock having not received
|
||||
anything on the queue. */
|
||||
if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we blocked for? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
if( xBlockedTime < xTimeToBlock )
|
||||
{
|
||||
/* Should not have blocked for less than we requested. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
/* Should not have blocked for longer than we requested,
|
||||
although we would not necessarily run as soon as we were
|
||||
unblocked so a margin is allowed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Test 3
|
||||
|
||||
Wake the other task, it will block attempting to post to the queue.
|
||||
When we read from the queue the other task will wake, but before it
|
||||
can run we will post to the queue again. When the other task runs it
|
||||
will find the queue still full, even though it was woken. It should
|
||||
recognise that its block time has not expired and return to block for
|
||||
the remains of its block time.
|
||||
|
||||
Wake the other task so it blocks attempting to post to the already
|
||||
full queue. */
|
||||
xRunIndicator = 0;
|
||||
vTaskResume( xSecondary );
|
||||
|
||||
/* We need to wait a little to ensure the other task executes. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task has not yet executed. */
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
/* Make sure the other task is blocked on the queue. */
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* Now when we make space on the queue the other task should wake
|
||||
but not execute as this task has higher priority. */
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now fill the queue again before the other task gets a chance to
|
||||
execute. If the other task had executed we would find the queue
|
||||
full ourselves, and the other task have set xRunIndicator. */
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Raise the priority of the other task so it executes and blocks
|
||||
on the queue again. */
|
||||
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
|
||||
|
||||
/* The other task should now have re-blocked without exiting the
|
||||
queue function. */
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed outside of the
|
||||
queue function. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the priority back down. */
|
||||
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
|
||||
}
|
||||
|
||||
/* Let the other task timeout. When it unblockes it will check that it
|
||||
unblocked at the correct time, then suspend itself. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
Test 4
|
||||
|
||||
As per test 3 - but with the send and receive the other way around.
|
||||
The other task blocks attempting to read from the queue.
|
||||
|
||||
Empty the queue. We should find that it is full. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wake the other task so it blocks attempting to read from the
|
||||
already empty queue. */
|
||||
vTaskResume( xSecondary );
|
||||
|
||||
/* We need to wait a little to ensure the other task executes. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* Now when we place an item on the queue the other task should
|
||||
wake but not execute as this task has higher priority. */
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now empty the queue again before the other task gets a chance to
|
||||
execute. If the other task had executed we would find the queue
|
||||
empty ourselves, and the other task would be suspended. */
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Raise the priority of the other task so it executes and blocks
|
||||
on the queue again. */
|
||||
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
|
||||
|
||||
/* The other task should now have re-blocked without exiting the
|
||||
queue function. */
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed outside of the
|
||||
queue function. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
|
||||
}
|
||||
|
||||
/* Let the other task timeout. When it unblockes it will check that it
|
||||
unblocked at the correct time, then suspend itself. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
|
||||
xPrimaryCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSecondaryBlockTimeTestTask( void *pvParameters )
|
||||
{
|
||||
TickType_t xTimeWhenBlocking, xBlockedTime;
|
||||
BaseType_t xData;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/*********************************************************************
|
||||
Test 0, 1 and 2
|
||||
|
||||
This task does not participate in these tests. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/*********************************************************************
|
||||
Test 3
|
||||
|
||||
The first thing we do is attempt to read from the queue. It should be
|
||||
full so we block. Note the time before we block so we can check the
|
||||
wake time is as per that expected. */
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after bktTIME_TO_BLOCK having not sent anything to
|
||||
the queue. */
|
||||
xData = 0;
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we inside the send function? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */
|
||||
if( xBlockedTime < bktTIME_TO_BLOCK )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN
|
||||
either. A margin is permitted as we would not necessarily run as
|
||||
soon as we unblocked. */
|
||||
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Suspend ready for test 3. */
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/*********************************************************************
|
||||
Test 4
|
||||
|
||||
As per test three, but with the send and receive reversed. */
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after bktTIME_TO_BLOCK having not received
|
||||
anything on the queue. */
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */
|
||||
if( xBlockedTime < bktTIME_TO_BLOCK )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN
|
||||
either. A margin is permitted as we would not necessarily run as soon
|
||||
as we unblocked. */
|
||||
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
|
||||
xSecondaryCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvBasicDelayTests( void )
|
||||
{
|
||||
TickType_t xPreTime, xPostTime, x, xLastUnblockTime, xExpectedUnblockTime;
|
||||
const TickType_t xPeriod = 75, xCycles = 5, xAllowableMargin = ( bktALLOWABLE_MARGIN >> 1 );
|
||||
|
||||
/* Temporarily increase priority so the timing is more accurate, but not so
|
||||
high as to disrupt the timer tests. */
|
||||
vTaskPrioritySet( NULL, configTIMER_TASK_PRIORITY - 1 );
|
||||
|
||||
/* Crude check to too that vTaskDelay() blocks for the expected period. */
|
||||
xPreTime = xTaskGetTickCount();
|
||||
vTaskDelay( bktTIME_TO_BLOCK );
|
||||
xPostTime = xTaskGetTickCount();
|
||||
|
||||
/* The priority is higher, so the allowable margin is halved when compared
|
||||
to the other tests in this file. */
|
||||
if( ( xPostTime - xPreTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now crude tests to check the vTaskDelayUntil() functionality. */
|
||||
xPostTime = xTaskGetTickCount();
|
||||
xLastUnblockTime = xPostTime;
|
||||
|
||||
for( x = 0; x < xCycles; x++ )
|
||||
{
|
||||
/* Calculate the next expected unblock time from the time taken before
|
||||
this loop was entered. */
|
||||
xExpectedUnblockTime = xPostTime + ( x * xPeriod );
|
||||
|
||||
vTaskDelayUntil( &xLastUnblockTime, xPeriod );
|
||||
|
||||
if( ( xTaskGetTickCount() - xExpectedUnblockTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
xPrimaryCycles++;
|
||||
}
|
||||
|
||||
/* Reset to the original task priority ready for the other tests. */
|
||||
vTaskPrioritySet( NULL, bktPRIMARY_PRIORITY );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreBlockTimeTestTasksStillRunning( void )
|
||||
{
|
||||
static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
/* Have both tasks performed at least one cycle since this function was
|
||||
last called? */
|
||||
if( xPrimaryCycles == xLastPrimaryCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xSecondaryCycles == xLastSecondaryCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xErrorOccurred == pdTRUE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
xLastSecondaryCycleCount = xSecondaryCycles;
|
||||
xLastPrimaryCycleCount = xPrimaryCycles;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This version of comtest. c is for use on systems that have limited stack
|
||||
* space and no display facilities. The complete version can be found in
|
||||
* the Demo/Common/Full directory.
|
||||
*
|
||||
* Creates two tasks that operate on an interrupt driven serial port. A
|
||||
* loopback connector should be used so that everything that is transmitted is
|
||||
* also received. The serial port does not use any flow control. On a
|
||||
* standard 9way 'D' connector pins two and three should be connected together.
|
||||
*
|
||||
* The first task posts a sequence of characters to the Tx queue, toggling an
|
||||
* LED on each successful post. At the end of the sequence it sleeps for a
|
||||
* pseudo-random period before resending the same sequence.
|
||||
*
|
||||
* The UART Tx end interrupt is enabled whenever data is available in the Tx
|
||||
* queue. The Tx end ISR removes a single character from the Tx queue and
|
||||
* passes it to the UART for transmission.
|
||||
*
|
||||
* The second task blocks on the Rx queue waiting for a character to become
|
||||
* available. When the UART Rx end interrupt receives a character it places
|
||||
* it in the Rx queue, waking the second task. The second task checks that the
|
||||
* characters removed from the Rx queue form the same sequence as those posted
|
||||
* to the Tx queue, and toggles an LED for each correct character.
|
||||
*
|
||||
* The receiving task is spawned with a higher priority than the transmitting
|
||||
* task. The receiver will therefore wake every time a character is
|
||||
* transmitted so neither the Tx or Rx queue should ever hold more than a few
|
||||
* characters.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include <stdlib.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "serial.h"
|
||||
#include "comtest.h"
|
||||
#include "partest.h"
|
||||
|
||||
#define comSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define comTX_LED_OFFSET ( 0 )
|
||||
#define comRX_LED_OFFSET ( 1 )
|
||||
#define comTOTAL_PERMISSIBLE_ERRORS ( 2 )
|
||||
|
||||
/* The Tx task will transmit the sequence of characters at a pseudo random
|
||||
interval. This is the maximum and minimum block time between sends. */
|
||||
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 )
|
||||
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 )
|
||||
#define comOFFSET_TIME ( ( TickType_t ) 3 )
|
||||
|
||||
/* We should find that each character can be queued for Tx immediately and we
|
||||
don't have to block to send. */
|
||||
#define comNO_BLOCK ( ( TickType_t ) 0 )
|
||||
|
||||
/* The Rx task will block on the Rx queue for a long period. */
|
||||
#define comRX_BLOCK_TIME ( ( TickType_t ) 0xffff )
|
||||
|
||||
/* The sequence transmitted is from comFIRST_BYTE to and including comLAST_BYTE. */
|
||||
#define comFIRST_BYTE ( 'A' )
|
||||
#define comLAST_BYTE ( 'X' )
|
||||
|
||||
#define comBUFFER_LEN ( ( UBaseType_t ) ( comLAST_BYTE - comFIRST_BYTE ) + ( UBaseType_t ) 1 )
|
||||
#define comINITIAL_RX_COUNT_VALUE ( 0 )
|
||||
|
||||
/* Handle to the com port used by both tasks. */
|
||||
static xComPortHandle xPort = NULL;
|
||||
|
||||
/* The transmit task as described at the top of the file. */
|
||||
static portTASK_FUNCTION_PROTO( vComTxTask, pvParameters );
|
||||
|
||||
/* The receive task as described at the top of the file. */
|
||||
static portTASK_FUNCTION_PROTO( vComRxTask, pvParameters );
|
||||
|
||||
/* The LED that should be toggled by the Rx and Tx tasks. The Rx task will
|
||||
toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task will toggle LED
|
||||
( uxBaseLED + comTX_LED_OFFSET ). */
|
||||
static UBaseType_t uxBaseLED = 0;
|
||||
|
||||
/* Check variable used to ensure no error have occurred. The Rx task will
|
||||
increment this variable after every successfully received sequence. If at any
|
||||
time the sequence is incorrect the the variable will stop being incremented. */
|
||||
static volatile UBaseType_t uxRxLoops = comINITIAL_RX_COUNT_VALUE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vAltStartComTestTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED )
|
||||
{
|
||||
/* Initialise the com port then spawn the Rx and Tx tasks. */
|
||||
uxBaseLED = uxLED;
|
||||
xSerialPortInitMinimal( ulBaudRate, comBUFFER_LEN );
|
||||
|
||||
/* The Tx task is spawned with a lower priority than the Rx task. */
|
||||
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority - 1, ( TaskHandle_t * ) NULL );
|
||||
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vComTxTask, pvParameters )
|
||||
{
|
||||
char cByteToSend;
|
||||
TickType_t xTimeToWait;
|
||||
|
||||
/* Just to stop compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Simply transmit a sequence of characters from comFIRST_BYTE to
|
||||
comLAST_BYTE. */
|
||||
for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ )
|
||||
{
|
||||
if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS )
|
||||
{
|
||||
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn the LED off while we are not doing anything. */
|
||||
vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE );
|
||||
|
||||
/* We have posted all the characters in the string - wait before
|
||||
re-sending. Wait a pseudo-random time as this will provide a better
|
||||
test. */
|
||||
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
|
||||
|
||||
/* Make sure we don't wait too long... */
|
||||
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
||||
|
||||
/* ...but we do want to wait. */
|
||||
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
||||
{
|
||||
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
||||
}
|
||||
|
||||
vTaskDelay( xTimeToWait );
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vComRxTask, pvParameters )
|
||||
{
|
||||
signed char cExpectedByte, cByteRxed;
|
||||
BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Just to stop compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* We expect to receive the characters from comFIRST_BYTE to
|
||||
comLAST_BYTE in an incrementing order. Loop to receive each byte. */
|
||||
for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ )
|
||||
{
|
||||
/* Block on the queue that contains received bytes until a byte is
|
||||
available. */
|
||||
if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) )
|
||||
{
|
||||
/* Was this the byte we were expecting? If so, toggle the LED,
|
||||
otherwise we are out on sync and should break out of the loop
|
||||
until the expected character sequence is about to restart. */
|
||||
if( cByteRxed == cExpectedByte )
|
||||
{
|
||||
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
|
||||
}
|
||||
else
|
||||
{
|
||||
xResyncRequired = pdTRUE;
|
||||
break; /*lint !e960 Non-switch break allowed. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn the LED off while we are not doing anything. */
|
||||
vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE );
|
||||
|
||||
/* Did we break out of the loop because the characters were received in
|
||||
an unexpected order? If so wait here until the character sequence is
|
||||
about to restart. */
|
||||
if( xResyncRequired == pdTRUE )
|
||||
{
|
||||
while( cByteRxed != comLAST_BYTE )
|
||||
{
|
||||
/* Block until the next char is available. */
|
||||
xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME );
|
||||
}
|
||||
|
||||
/* Note that an error occurred which caused us to have to resync.
|
||||
We use this to stop incrementing the loop counter so
|
||||
sAreComTestTasksStillRunning() will return false - indicating an
|
||||
error. */
|
||||
xErrorOccurred++;
|
||||
|
||||
/* We have now resynced with the Tx task and can continue. */
|
||||
xResyncRequired = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS )
|
||||
{
|
||||
/* Increment the count of successful loops. As error
|
||||
occurring (i.e. an unexpected character being received) will
|
||||
prevent this counter being incremented for the rest of the
|
||||
execution. Don't worry about mutual exclusion on this
|
||||
variable - it doesn't really matter as we just want it
|
||||
to change. */
|
||||
uxRxLoops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreComTestTasksStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* If the count of successful reception loops has not changed than at
|
||||
some time an error occurred (i.e. a character was received out of sequence)
|
||||
and we will return false. */
|
||||
if( uxRxLoops == comINITIAL_RX_COUNT_VALUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Reset the count of successful Rx loops. When this function is called
|
||||
again we expect this to have been incremented. */
|
||||
uxRxLoops = comINITIAL_RX_COUNT_VALUE;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Creates a task and a timer that operate on an interrupt driven serial port.
|
||||
* This demo assumes that the characters transmitted on a port will also be
|
||||
* received on the same port. Therefore, the UART must either be connected to
|
||||
* an echo server, or the uart connector must have a loopback connector fitted.
|
||||
* See http://www.serialporttool.com/CommEcho.htm for a suitable echo server
|
||||
* for Windows hosts.
|
||||
*
|
||||
* The timer sends a string to the UART, toggles an LED, then resets itself by
|
||||
* changing its own period. The period is calculated as a pseudo random number
|
||||
* between comTX_MAX_BLOCK_TIME and comTX_MIN_BLOCK_TIME.
|
||||
*
|
||||
* The task blocks on an Rx queue waiting for a character to become available.
|
||||
* Received characters are checked to ensure they match those transmitted by the
|
||||
* Tx timer. An error is latched if characters are missing, incorrect, or
|
||||
* arrive too slowly.
|
||||
*
|
||||
* How characters are actually transmitted and received is port specific. Demos
|
||||
* that include this test/demo file will provide example drivers. The Tx timer
|
||||
* executes in the context of the timer service (daemon) task, and must
|
||||
* therefore never attempt to block.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
|
||||
#ifndef configUSE_TIMERS
|
||||
#error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
|
||||
#endif
|
||||
|
||||
#if configUSE_TIMERS != 1
|
||||
#error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
|
||||
#endif
|
||||
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "serial.h"
|
||||
#include "comtest_strings.h"
|
||||
#include "partest.h"
|
||||
|
||||
/* The size of the stack given to the Rx task. */
|
||||
#define comSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/* See the comment above the declaraction of the uxBaseLED variable. */
|
||||
#define comTX_LED_OFFSET ( 0 )
|
||||
#define comRX_LED_OFFSET ( 1 )
|
||||
|
||||
/* The Tx timer transmits the sequence of characters at a pseudo random
|
||||
interval that is capped between comTX_MAX_BLOCK_TIME and
|
||||
comTX_MIN_BLOCK_TIME. */
|
||||
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 )
|
||||
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 )
|
||||
#define comOFFSET_TIME ( ( TickType_t ) 3 )
|
||||
|
||||
/* States for the simple state machine implemented in the Rx task. */
|
||||
#define comtstWAITING_START_OF_STRING 0
|
||||
#define comtstWAITING_END_OF_STRING 1
|
||||
|
||||
/* A short delay in ticks - this delay is used to allow the Rx queue to fill up
|
||||
a bit so more than one character can be processed at a time. This is relative
|
||||
to comTX_MIN_BLOCK_TIME to ensure it is never longer than the shortest gap
|
||||
between transmissions. It could be worked out more scientifically from the
|
||||
baud rate being used. */
|
||||
#define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( TickType_t ) 2 )
|
||||
|
||||
/* The string that is transmitted and received. */
|
||||
#define comTRANSACTED_STRING "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||
|
||||
/* A block time of 0 simply means "don't block". */
|
||||
#define comtstDONT_BLOCK ( TickType_t ) 0
|
||||
|
||||
/* Handle to the com port used by both tasks. */
|
||||
static xComPortHandle xPort = NULL;
|
||||
|
||||
/* The callback function allocated to the transmit timer, as described in the
|
||||
comments at the top of this file. */
|
||||
static void prvComTxTimerCallback( TimerHandle_t xTimer );
|
||||
|
||||
/* The receive task as described in the comments at the top of this file. */
|
||||
static void vComRxTask( void *pvParameters );
|
||||
|
||||
/* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task
|
||||
will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */
|
||||
static UBaseType_t uxBaseLED = 0;
|
||||
|
||||
/* The Rx task toggles uxRxLoops on each successful iteration of its defined
|
||||
function - provided no errors have ever been latched. If this variable stops
|
||||
incrementing, then an error has occurred. */
|
||||
static volatile UBaseType_t uxRxLoops = 0UL;
|
||||
|
||||
/* The timer used to periodically transmit the string. This is the timer that
|
||||
has prvComTxTimerCallback allocated to it as its callback function. */
|
||||
static TimerHandle_t xTxTimer = NULL;
|
||||
|
||||
/* The string length is held at file scope so the Tx timer does not need to
|
||||
calculate it each time it executes. */
|
||||
static size_t xStringLength = 0U;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartComTestStringsTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED )
|
||||
{
|
||||
/* Store values that are used at run time. */
|
||||
uxBaseLED = uxLED;
|
||||
|
||||
/* Calculate the string length here, rather than each time the Tx timer
|
||||
executes. */
|
||||
xStringLength = strlen( comTRANSACTED_STRING );
|
||||
|
||||
/* Include the null terminator in the string length as this is used to
|
||||
detect the end of the string in the Rx task. */
|
||||
xStringLength++;
|
||||
|
||||
/* Initialise the com port, then spawn the Rx task and create the Tx
|
||||
timer. */
|
||||
xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) );
|
||||
|
||||
/* Create the Rx task and the Tx timer. The timer is started from the
|
||||
Rx task. */
|
||||
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
xTxTimer = xTimerCreate( "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback );
|
||||
configASSERT( xTxTimer );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvComTxTimerCallback( TimerHandle_t xTimer )
|
||||
{
|
||||
TickType_t xTimeToWait;
|
||||
|
||||
/* The parameter is not used in this case. */
|
||||
( void ) xTimer;
|
||||
|
||||
/* Send the string. How this is actually performed depends on the
|
||||
sample driver provided with this demo. However - as this is a timer,
|
||||
it executes in the context of the timer task and therefore must not
|
||||
block. */
|
||||
vSerialPutString( xPort, comTRANSACTED_STRING, xStringLength );
|
||||
|
||||
/* Toggle an LED to give a visible indication that another transmission
|
||||
has been performed. */
|
||||
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
|
||||
|
||||
/* Wait a pseudo random time before sending the string again. */
|
||||
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
|
||||
|
||||
/* Ensure the time to wait is not greater than comTX_MAX_BLOCK_TIME. */
|
||||
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
||||
|
||||
/* Ensure the time to wait is not less than comTX_MIN_BLOCK_TIME. */
|
||||
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
||||
{
|
||||
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
||||
}
|
||||
|
||||
/* Reset the timer to run again xTimeToWait ticks from now. This function
|
||||
is called from the context of the timer task, so the block time must not
|
||||
be anything other than zero. */
|
||||
xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vComRxTask( void *pvParameters )
|
||||
{
|
||||
BaseType_t xState = comtstWAITING_START_OF_STRING, xErrorOccurred = pdFALSE;
|
||||
char *pcExpectedByte, cRxedChar;
|
||||
const xComPortHandle xPort = NULL;
|
||||
|
||||
/* The parameter is not used in this example. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Start the Tx timer. This only needs to be started once, as it will
|
||||
reset itself thereafter. */
|
||||
xTimerStart( xTxTimer, portMAX_DELAY );
|
||||
|
||||
/* The first expected Rx character is the first in the string that is
|
||||
transmitted. */
|
||||
pcExpectedByte = comTRANSACTED_STRING;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait for the next character. */
|
||||
if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE )
|
||||
{
|
||||
/* A character definitely should have been received by now. As a
|
||||
character was not received an error must have occurred (which might
|
||||
just be that the loopback connector is not fitted). */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
switch( xState )
|
||||
{
|
||||
case comtstWAITING_START_OF_STRING:
|
||||
if( cRxedChar == *pcExpectedByte )
|
||||
{
|
||||
/* The received character was the first character of the
|
||||
string. Move to the next state to check each character
|
||||
as it comes in until the entire string has been received. */
|
||||
xState = comtstWAITING_END_OF_STRING;
|
||||
pcExpectedByte++;
|
||||
|
||||
/* Block for a short period. This just allows the Rx queue
|
||||
to contain more than one character, and therefore prevent
|
||||
thrashing reads to the queue, and repetitive context
|
||||
switches as each character is received. */
|
||||
vTaskDelay( comSHORT_DELAY );
|
||||
}
|
||||
break;
|
||||
|
||||
case comtstWAITING_END_OF_STRING:
|
||||
if( cRxedChar == *pcExpectedByte )
|
||||
{
|
||||
/* The received character was the expected character. Was
|
||||
it the last character in the string - i.e. the null
|
||||
terminator? */
|
||||
if( cRxedChar == 0x00 )
|
||||
{
|
||||
/* The entire string has been received. If no errors
|
||||
have been latched, then increment the loop counter to
|
||||
show this task is still healthy. */
|
||||
if( xErrorOccurred == pdFALSE )
|
||||
{
|
||||
uxRxLoops++;
|
||||
|
||||
/* Toggle an LED to give a visible sign that a
|
||||
complete string has been received. */
|
||||
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
|
||||
}
|
||||
|
||||
/* Go back to wait for the start of the next string. */
|
||||
pcExpectedByte = comTRANSACTED_STRING;
|
||||
xState = comtstWAITING_START_OF_STRING;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wait for the next character in the string. */
|
||||
pcExpectedByte++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The character received was not that expected. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Should not get here. Stop the Rx loop counter from
|
||||
incrementing to latch the error. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreComTestTasksStillRunning( void )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* If the count of successful reception loops has not changed than at
|
||||
some time an error occurred (i.e. a character was received out of sequence)
|
||||
and false is returned. */
|
||||
if( uxRxLoops == 0UL )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Reset the count of successful Rx loops. When this function is called
|
||||
again it should have been incremented again. */
|
||||
uxRxLoops = 0UL;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Simple demonstration of the usage of counting semaphore.
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "countsem.h"
|
||||
|
||||
/* The maximum count value that the semaphore used for the demo can hold. */
|
||||
#define countMAX_COUNT_VALUE ( 200 )
|
||||
|
||||
/* Constants used to indicate whether or not the semaphore should have been
|
||||
created with its maximum count value, or its minimum count value. These
|
||||
numbers are used to ensure that the pointers passed in as the task parameters
|
||||
are valid. */
|
||||
#define countSTART_AT_MAX_COUNT ( 0xaa )
|
||||
#define countSTART_AT_ZERO ( 0x55 )
|
||||
|
||||
/* Two tasks are created for the test. One uses a semaphore created with its
|
||||
count value set to the maximum, and one with the count value set to zero. */
|
||||
#define countNUM_TEST_TASKS ( 2 )
|
||||
#define countDONT_BLOCK ( 0 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
detected in any of the tasks. */
|
||||
static volatile BaseType_t xErrorDetected = pdFALSE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The demo task. This simply counts the semaphore up to its maximum value,
|
||||
* the counts it back down again. The result of each semaphore 'give' and
|
||||
* 'take' is inspected, with an error being flagged if it is found not to be
|
||||
* the expected result.
|
||||
*/
|
||||
static void prvCountingSemaphoreTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Utility function to increment the semaphore count value up from zero to
|
||||
* countMAX_COUNT_VALUE.
|
||||
*/
|
||||
static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore, UBaseType_t *puxLoopCounter );
|
||||
|
||||
/*
|
||||
* Utility function to decrement the semaphore count value up from
|
||||
* countMAX_COUNT_VALUE to zero.
|
||||
*/
|
||||
static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore, UBaseType_t *puxLoopCounter );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The structure that is passed into the task as the task parameter. */
|
||||
typedef struct COUNT_SEM_STRUCT
|
||||
{
|
||||
/* The semaphore to be used for the demo. */
|
||||
SemaphoreHandle_t xSemaphore;
|
||||
|
||||
/* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with
|
||||
its count value set to its max count value, or countSTART_AT_ZERO if it
|
||||
should have been created with its count value set to 0. */
|
||||
UBaseType_t uxExpectedStartCount;
|
||||
|
||||
/* Incremented on each cycle of the demo task. Used to detect a stalled
|
||||
task. */
|
||||
UBaseType_t uxLoopCounter;
|
||||
} xCountSemStruct;
|
||||
|
||||
/* Two structures are defined, one is passed to each test task. */
|
||||
static volatile xCountSemStruct xParameters[ countNUM_TEST_TASKS ];
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartCountingSemaphoreTasks( void )
|
||||
{
|
||||
/* Create the semaphores that we are going to use for the test/demo. The
|
||||
first should be created such that it starts at its maximum count value,
|
||||
the second should be created such that it starts with a count value of zero. */
|
||||
xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE );
|
||||
xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT;
|
||||
xParameters[ 0 ].uxLoopCounter = 0;
|
||||
|
||||
xParameters[ 1 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, 0 );
|
||||
xParameters[ 1 ].uxExpectedStartCount = 0;
|
||||
xParameters[ 1 ].uxLoopCounter = 0;
|
||||
|
||||
/* Were the semaphores created? */
|
||||
if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the semaphore to the registry, if one is
|
||||
in use. The registry is provided as a means for kernel aware
|
||||
debuggers to locate semaphores and has no purpose if a kernel aware
|
||||
debugger is not being used. The call to vQueueAddToRegistry() will be
|
||||
removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
|
||||
defined or is defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 0 ].xSemaphore, "Counting_Sem_1" );
|
||||
vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 1 ].xSemaphore, "Counting_Sem_2" );
|
||||
|
||||
/* Create the demo tasks, passing in the semaphore to use as the parameter. */
|
||||
xTaskCreate( prvCountingSemaphoreTask, "CNT1", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 0 ] ), tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvCountingSemaphoreTask, "CNT2", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 1 ] ), tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore, UBaseType_t *puxLoopCounter )
|
||||
{
|
||||
UBaseType_t ux;
|
||||
|
||||
/* If the semaphore count is at its maximum then we should not be able to
|
||||
'give' the semaphore. */
|
||||
if( xSemaphoreGive( xSemaphore ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */
|
||||
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
|
||||
{
|
||||
configASSERT( uxSemaphoreGetCount( xSemaphore ) == ( countMAX_COUNT_VALUE - ux ) );
|
||||
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to be able to take the semaphore. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
( *puxLoopCounter )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the semaphore count is zero then we should not be able to 'take'
|
||||
the semaphore. */
|
||||
configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore, UBaseType_t *puxLoopCounter )
|
||||
{
|
||||
UBaseType_t ux;
|
||||
|
||||
/* If the semaphore count is zero then we should not be able to 'take'
|
||||
the semaphore. */
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */
|
||||
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
|
||||
{
|
||||
configASSERT( uxSemaphoreGetCount( xSemaphore ) == ux );
|
||||
|
||||
if( xSemaphoreGive( xSemaphore ) != pdPASS )
|
||||
{
|
||||
/* We expected to be able to take the semaphore. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
( *puxLoopCounter )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the semaphore count is at its maximum then we should not be able to
|
||||
'give' the semaphore. */
|
||||
if( xSemaphoreGive( xSemaphore ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCountingSemaphoreTask( void *pvParameters )
|
||||
{
|
||||
xCountSemStruct *pxParameter;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const char * const * ppcMessageToSend );
|
||||
|
||||
const char * const pcTaskStartMsg = "Counting semaphore demo started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
/* The semaphore to be used was passed as the parameter. */
|
||||
pxParameter = ( xCountSemStruct * ) pvParameters;
|
||||
|
||||
/* Did we expect to find the semaphore already at its max count value, or
|
||||
at zero? */
|
||||
if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT )
|
||||
{
|
||||
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
}
|
||||
|
||||
/* Now we expect the semaphore count to be 0, so this time there is an
|
||||
error if we can take the semaphore. */
|
||||
if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
prvIncrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreCountingSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static UBaseType_t uxLastCount0 = 0, uxLastCount1 = 0;
|
||||
BaseType_t xReturn = pdPASS;
|
||||
|
||||
/* Return fail if any 'give' or 'take' did not result in the expected
|
||||
behaviour. */
|
||||
if( xErrorDetected != pdFALSE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
/* Return fail if either task is not still incrementing its loop counter. */
|
||||
if( uxLastCount0 == xParameters[ 0 ].uxLoopCounter )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastCount0 = xParameters[ 0 ].uxLoopCounter;
|
||||
}
|
||||
|
||||
if( uxLastCount1 == xParameters[ 1 ].uxLoopCounter )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastCount1 = xParameters[ 1 ].uxLoopCounter;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This demo application file demonstrates the use of queues to pass data
|
||||
* between co-routines.
|
||||
*
|
||||
* N represents the number of 'fixed delay' co-routines that are created and
|
||||
* is set during initialisation.
|
||||
*
|
||||
* N 'fixed delay' co-routines are created that just block for a fixed
|
||||
* period then post the number of an LED onto a queue. Each such co-routine
|
||||
* uses a different block period. A single 'flash' co-routine is also created
|
||||
* that blocks on the same queue, waiting for the number of the next LED it
|
||||
* should flash. Upon receiving a number it simply toggle the instructed LED
|
||||
* then blocks on the queue once more. In this manner each LED from LED 0 to
|
||||
* LED N-1 is caused to flash at a different rate.
|
||||
*
|
||||
* The 'fixed delay' co-routines are created with co-routine priority 0. The
|
||||
* flash co-routine is created with co-routine priority 1. This means that
|
||||
* the queue should never contain more than a single item. This is because
|
||||
* posting to the queue will unblock the 'flash' co-routine, and as this has
|
||||
* a priority greater than the tasks posting to the queue it is guaranteed to
|
||||
* have emptied the queue and blocked once again before the queue can contain
|
||||
* any more date. An error is indicated if an attempt to post data to the
|
||||
* queue fails - indicating that the queue is already full.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "croutine.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo application includes. */
|
||||
#include "partest.h"
|
||||
#include "crflash.h"
|
||||
|
||||
/* The queue should only need to be of length 1. See the description at the
|
||||
top of the file. */
|
||||
#define crfQUEUE_LENGTH 1
|
||||
|
||||
#define crfFIXED_DELAY_PRIORITY 0
|
||||
#define crfFLASH_PRIORITY 1
|
||||
|
||||
/* Only one flash co-routine is created so the index is not significant. */
|
||||
#define crfFLASH_INDEX 0
|
||||
|
||||
/* Don't allow more than crfMAX_FLASH_TASKS 'fixed delay' co-routines to be
|
||||
created. */
|
||||
#define crfMAX_FLASH_TASKS 8
|
||||
|
||||
/* We don't want to block when posting to the queue. */
|
||||
#define crfPOSTING_BLOCK_TIME 0
|
||||
|
||||
/*
|
||||
* The 'fixed delay' co-routine as described at the top of the file.
|
||||
*/
|
||||
static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex );
|
||||
|
||||
/*
|
||||
* The 'flash' co-routine as described at the top of the file.
|
||||
*/
|
||||
static void prvFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex );
|
||||
|
||||
/* The queue used to pass data between the 'fixed delay' co-routines and the
|
||||
'flash' co-routine. */
|
||||
static QueueHandle_t xFlashQueue;
|
||||
|
||||
/* This will be set to pdFALSE if we detect an error. */
|
||||
static BaseType_t xCoRoutineFlashStatus = pdPASS;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* See the header file for details.
|
||||
*/
|
||||
void vStartFlashCoRoutines( UBaseType_t uxNumberToCreate )
|
||||
{
|
||||
UBaseType_t uxIndex;
|
||||
|
||||
if( uxNumberToCreate > crfMAX_FLASH_TASKS )
|
||||
{
|
||||
uxNumberToCreate = crfMAX_FLASH_TASKS;
|
||||
}
|
||||
|
||||
/* Create the queue used to pass data between the co-routines. */
|
||||
xFlashQueue = xQueueCreate( crfQUEUE_LENGTH, sizeof( UBaseType_t ) );
|
||||
|
||||
if( xFlashQueue )
|
||||
{
|
||||
/* Create uxNumberToCreate 'fixed delay' co-routines. */
|
||||
for( uxIndex = 0; uxIndex < uxNumberToCreate; uxIndex++ )
|
||||
{
|
||||
xCoRoutineCreate( prvFixedDelayCoRoutine, crfFIXED_DELAY_PRIORITY, uxIndex );
|
||||
}
|
||||
|
||||
/* Create the 'flash' co-routine. */
|
||||
xCoRoutineCreate( prvFlashCoRoutine, crfFLASH_PRIORITY, crfFLASH_INDEX );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
/* Even though this is a co-routine the xResult variable does not need to be
|
||||
static as we do not need it to maintain its state between blocks. */
|
||||
BaseType_t xResult;
|
||||
/* The uxIndex parameter of the co-routine function is used as an index into
|
||||
the xFlashRates array to obtain the delay period to use. */
|
||||
static const TickType_t xFlashRates[ crfMAX_FLASH_TASKS ] = { 150 / portTICK_PERIOD_MS,
|
||||
200 / portTICK_PERIOD_MS,
|
||||
250 / portTICK_PERIOD_MS,
|
||||
300 / portTICK_PERIOD_MS,
|
||||
350 / portTICK_PERIOD_MS,
|
||||
400 / portTICK_PERIOD_MS,
|
||||
450 / portTICK_PERIOD_MS,
|
||||
500 / portTICK_PERIOD_MS };
|
||||
|
||||
/* Co-routines MUST start with a call to crSTART. */
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Post our uxIndex value onto the queue. This is used as the LED to
|
||||
flash. */
|
||||
crQUEUE_SEND( xHandle, xFlashQueue, ( void * ) &uxIndex, crfPOSTING_BLOCK_TIME, &xResult );
|
||||
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* For the reasons stated at the top of the file we should always
|
||||
find that we can post to the queue. If we could not then an error
|
||||
has occurred. */
|
||||
xCoRoutineFlashStatus = pdFAIL;
|
||||
}
|
||||
|
||||
crDELAY( xHandle, xFlashRates[ uxIndex ] );
|
||||
}
|
||||
|
||||
/* Co-routines MUST end with a call to crEND. */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
/* Even though this is a co-routine the variable do not need to be
|
||||
static as we do not need it to maintain their state between blocks. */
|
||||
BaseType_t xResult;
|
||||
UBaseType_t uxLEDToFlash;
|
||||
|
||||
/* Co-routines MUST start with a call to crSTART. */
|
||||
crSTART( xHandle );
|
||||
( void ) uxIndex;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Block to wait for the number of the LED to flash. */
|
||||
crQUEUE_RECEIVE( xHandle, xFlashQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
|
||||
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* We would not expect to wake unless we received something. */
|
||||
xCoRoutineFlashStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We received the number of an LED to flash - flash it! */
|
||||
vParTestToggleLED( uxLEDToFlash );
|
||||
}
|
||||
}
|
||||
|
||||
/* Co-routines MUST end with a call to crEND. */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreFlashCoRoutinesStillRunning( void )
|
||||
{
|
||||
/* Return pdPASS or pdFAIL depending on whether an error has been detected
|
||||
or not. */
|
||||
return xCoRoutineFlashStatus;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This demo file demonstrates how to send data between an ISR and a
|
||||
* co-routine. A tick hook function is used to periodically pass data between
|
||||
* the RTOS tick and a set of 'hook' co-routines.
|
||||
*
|
||||
* hookNUM_HOOK_CO_ROUTINES co-routines are created. Each co-routine blocks
|
||||
* to wait for a character to be received on a queue from the tick ISR, checks
|
||||
* to ensure the character received was that expected, then sends the number
|
||||
* back to the tick ISR on a different queue.
|
||||
*
|
||||
* The tick ISR checks the numbers received back from the 'hook' co-routines
|
||||
* matches the number previously sent.
|
||||
*
|
||||
* If at any time a queue function returns unexpectedly, or an incorrect value
|
||||
* is received either by the tick hook or a co-routine then an error is
|
||||
* latched.
|
||||
*
|
||||
* This demo relies on each 'hook' co-routine to execute between each
|
||||
* hookTICK_CALLS_BEFORE_POST tick interrupts. This and the heavy use of
|
||||
* queues from within an interrupt may result in an error being detected on
|
||||
* slower targets simply due to timing.
|
||||
*/
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "croutine.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo application includes. */
|
||||
#include "crhook.h"
|
||||
|
||||
/* The number of 'hook' co-routines that are to be created. */
|
||||
#define hookNUM_HOOK_CO_ROUTINES ( 4 )
|
||||
|
||||
/* The number of times the tick hook should be called before a character is
|
||||
posted to the 'hook' co-routines. */
|
||||
#define hookTICK_CALLS_BEFORE_POST ( 500 )
|
||||
|
||||
/* There should never be more than one item in any queue at any time. */
|
||||
#define hookHOOK_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/* Don't block when initially posting to the queue. */
|
||||
#define hookNO_BLOCK_TIME ( 0 )
|
||||
|
||||
/* The priority relative to other co-routines (rather than tasks) that the
|
||||
'hook' co-routines should take. */
|
||||
#define mainHOOK_CR_PRIORITY ( 1 )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The co-routine function itself.
|
||||
*/
|
||||
static void prvHookCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex );
|
||||
|
||||
|
||||
/*
|
||||
* The tick hook function. This receives a number from each 'hook' co-routine
|
||||
* then sends a number to each co-routine. An error is flagged if a send or
|
||||
* receive fails, or an unexpected number is received.
|
||||
*/
|
||||
void vApplicationTickHook( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Queues used to send data FROM a co-routine TO the tick hook function.
|
||||
The hook functions received (Rx's) on these queues. One queue per
|
||||
'hook' co-routine. */
|
||||
static QueueHandle_t xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
|
||||
/* Queues used to send data FROM the tick hook TO a co-routine function.
|
||||
The hood function transmits (Tx's) on these queues. One queue per
|
||||
'hook' co-routine. */
|
||||
static QueueHandle_t xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
|
||||
/* Set to true if an error is detected at any time. */
|
||||
static BaseType_t xCoRoutineErrorDetected = pdFALSE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartHookCoRoutines( void )
|
||||
{
|
||||
UBaseType_t uxIndex, uxValueToPost = 0;
|
||||
|
||||
for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ )
|
||||
{
|
||||
/* Create a queue to transmit to and receive from each 'hook'
|
||||
co-routine. */
|
||||
xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) );
|
||||
xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) );
|
||||
|
||||
/* To start things off the tick hook function expects the queue it
|
||||
uses to receive data to contain a value. */
|
||||
xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME );
|
||||
|
||||
/* Create the 'hook' co-routine itself. */
|
||||
xCoRoutineCreate( prvHookCoRoutine, mainHOOK_CR_PRIORITY, uxIndex );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static UBaseType_t uxCallCounter = 0, uxNumberToPost = 0;
|
||||
void vApplicationTickHook( void )
|
||||
{
|
||||
UBaseType_t uxReceivedNumber;
|
||||
BaseType_t xIndex, xCoRoutineWoken;
|
||||
|
||||
/* Is it time to talk to the 'hook' co-routines again? */
|
||||
uxCallCounter++;
|
||||
if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST )
|
||||
{
|
||||
uxCallCounter = 0;
|
||||
|
||||
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
|
||||
{
|
||||
xCoRoutineWoken = pdFALSE;
|
||||
if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS )
|
||||
{
|
||||
/* There is no reason why we would not expect the queue to
|
||||
contain a value. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Each queue used to receive data from the 'hook' co-routines
|
||||
should contain the number we last posted to the same co-routine. */
|
||||
if( uxReceivedNumber != uxNumberToPost )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Nothing should be blocked waiting to post to the queue. */
|
||||
if( xCoRoutineWoken != pdFALSE )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the next cycle by posting the next number onto each Tx queue. */
|
||||
uxNumberToPost++;
|
||||
|
||||
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
|
||||
{
|
||||
if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE )
|
||||
{
|
||||
/* Posting to the queue should have woken the co-routine that
|
||||
was blocked on the queue. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHookCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
static UBaseType_t uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
BaseType_t xResult;
|
||||
|
||||
/* Each co-routine MUST start with a call to crSTART(); */
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait to receive a value from the tick hook. */
|
||||
xResult = pdFAIL;
|
||||
crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult );
|
||||
|
||||
/* There is no reason why we should not have received something on
|
||||
the queue. */
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Send the same number back to the idle hook so it can verify it. */
|
||||
xResult = pdFAIL;
|
||||
crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult );
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* There is no reason why we should not have been able to post to
|
||||
the queue. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Each co-routine MUST end with a call to crEND(). */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xAreHookCoRoutinesStillRunning( void )
|
||||
{
|
||||
if( xCoRoutineErrorDetected )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a single persistent task which periodically dynamically creates another
|
||||
* two tasks. The original task is called the creator task, the two tasks it
|
||||
* creates are called suicidal tasks.
|
||||
*
|
||||
* One of the created suicidal tasks kill one other suicidal task before killing
|
||||
* itself - leaving just the original task remaining.
|
||||
*
|
||||
* The creator task must be spawned after all of the other demo application tasks
|
||||
* as it keeps a check on the number of tasks under the scheduler control. The
|
||||
* number of tasks it expects to see running should never be greater than the
|
||||
* number of tasks that were in existence when the creator task was spawned, plus
|
||||
* one set of four suicidal tasks. If this number is exceeded an error is flagged.
|
||||
*
|
||||
* \page DeathC death.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "death.h"
|
||||
|
||||
#define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 )
|
||||
|
||||
/* The task originally created which is responsible for periodically dynamically
|
||||
creating another four tasks. */
|
||||
static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters );
|
||||
|
||||
/* The task function of the dynamically created tasks. */
|
||||
static portTASK_FUNCTION_PROTO( vSuicidalTask, pvParameters );
|
||||
|
||||
/* A variable which is incremented every time the dynamic tasks are created. This
|
||||
is used to check that the task is still running. */
|
||||
static volatile uint16_t usCreationCount = 0;
|
||||
|
||||
/* Used to store the number of tasks that were originally running so the creator
|
||||
task can tell if any of the suicidal tasks have failed to die.
|
||||
*/
|
||||
static volatile UBaseType_t uxTasksRunningAtStart = 0;
|
||||
|
||||
/* When a task deletes itself, it stack and TCB are cleaned up by the Idle task.
|
||||
Under heavy load the idle task might not get much processing time, so it would
|
||||
be legitimate for several tasks to remain undeleted for a short period. There
|
||||
may also be a few other unexpected tasks if, for example, the tasks that test
|
||||
static allocation are also being used. */
|
||||
static const UBaseType_t uxMaxNumberOfExtraTasksRunning = 3;
|
||||
|
||||
/* Used to store a handle to the task that should be killed by a suicidal task,
|
||||
before it kills itself. */
|
||||
TaskHandle_t xCreatedTask;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateSuicidalTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) NULL, uxPriority, NULL );
|
||||
|
||||
/* Record the number of tasks that are running now so we know if any of the
|
||||
suicidal tasks have failed to be killed. */
|
||||
uxTasksRunningAtStart = ( UBaseType_t ) uxTaskGetNumberOfTasks();
|
||||
|
||||
/* FreeRTOS.org versions before V3.0 started the idle-task as the very
|
||||
first task. The idle task was then already included in uxTasksRunningAtStart.
|
||||
From FreeRTOS V3.0 on, the idle task is started when the scheduler is
|
||||
started. Therefore the idle task is not yet accounted for. We correct
|
||||
this by increasing uxTasksRunningAtStart by 1. */
|
||||
uxTasksRunningAtStart++;
|
||||
|
||||
/* From FreeRTOS version 7.0.0 can optionally create a timer service task.
|
||||
If this is done, then uxTasksRunningAtStart needs incrementing again as that
|
||||
too is created when the scheduler is started. */
|
||||
#if configUSE_TIMERS == 1
|
||||
{
|
||||
uxTasksRunningAtStart++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vSuicidalTask, pvParameters )
|
||||
{
|
||||
volatile long l1, l2;
|
||||
TaskHandle_t xTaskToKill;
|
||||
const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 200 );
|
||||
|
||||
if( pvParameters != NULL )
|
||||
{
|
||||
/* This task is periodically created four times. Two created tasks are
|
||||
passed a handle to the other task so it can kill it before killing itself.
|
||||
The other task is passed in null. */
|
||||
xTaskToKill = *( TaskHandle_t* )pvParameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTaskToKill = NULL;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Do something random just to use some stack and registers. */
|
||||
l1 = 2;
|
||||
l2 = 89;
|
||||
l2 *= l1;
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
if( xTaskToKill != NULL )
|
||||
{
|
||||
/* Make sure the other task has a go before we delete it. */
|
||||
vTaskDelay( ( TickType_t ) 0 );
|
||||
|
||||
/* Kill the other task that was created by vCreateTasks(). */
|
||||
vTaskDelete( xTaskToKill );
|
||||
|
||||
/* Kill ourselves. */
|
||||
vTaskDelete( NULL );
|
||||
}
|
||||
}
|
||||
}/*lint !e818 !e550 Function prototype must be as per standard for task functions. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCreateTasks, pvParameters )
|
||||
{
|
||||
const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 1000 );
|
||||
UBaseType_t uxPriority;
|
||||
|
||||
/* Remove compiler warning about unused parameter. */
|
||||
( void ) pvParameters;
|
||||
|
||||
uxPriority = uxTaskPriorityGet( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Just loop round, delaying then creating the four suicidal tasks. */
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
xCreatedTask = NULL;
|
||||
|
||||
xTaskCreate( vSuicidalTask, "SUICID1", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xCreatedTask );
|
||||
xTaskCreate( vSuicidalTask, "SUICID2", configMINIMAL_STACK_SIZE, &xCreatedTask, uxPriority, NULL );
|
||||
|
||||
++usCreationCount;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that the creator task is still running and that there
|
||||
are not any more than four extra tasks. */
|
||||
BaseType_t xIsCreateTaskStillRunning( void )
|
||||
{
|
||||
static uint16_t usLastCreationCount = 0xfff;
|
||||
BaseType_t xReturn = pdTRUE;
|
||||
static UBaseType_t uxTasksRunningNow;
|
||||
|
||||
if( usLastCreationCount == usCreationCount )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
usLastCreationCount = usCreationCount;
|
||||
}
|
||||
|
||||
uxTasksRunningNow = ( UBaseType_t ) uxTaskGetNumberOfTasks();
|
||||
|
||||
if( uxTasksRunningNow < uxTasksRunningAtStart )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Everything is okay. */
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* The first test creates three tasks - two counter tasks (one continuous count
|
||||
* and one limited count) and one controller. A "count" variable is shared
|
||||
* between all three tasks. The two counter tasks should never be in a "ready"
|
||||
* state at the same time. The controller task runs at the same priority as
|
||||
* the continuous count task, and at a lower priority than the limited count
|
||||
* task.
|
||||
*
|
||||
* One counter task loops indefinitely, incrementing the shared count variable
|
||||
* on each iteration. To ensure it has exclusive access to the variable it
|
||||
* raises its priority above that of the controller task before each
|
||||
* increment, lowering it again to its original priority before starting the
|
||||
* next iteration.
|
||||
*
|
||||
* The other counter task increments the shared count variable on each
|
||||
* iteration of its loop until the count has reached a limit of 0xff - at
|
||||
* which point it suspends itself. It will not start a new loop until the
|
||||
* controller task has made it "ready" again by calling vTaskResume().
|
||||
* This second counter task operates at a higher priority than controller
|
||||
* task so does not need to worry about mutual exclusion of the counter
|
||||
* variable.
|
||||
*
|
||||
* The controller task is in two sections. The first section controls and
|
||||
* monitors the continuous count task. When this section is operational the
|
||||
* limited count task is suspended. Likewise, the second section controls
|
||||
* and monitors the limited count task. When this section is operational the
|
||||
* continuous count task is suspended.
|
||||
*
|
||||
* In the first section the controller task first takes a copy of the shared
|
||||
* count variable. To ensure mutual exclusion on the count variable it
|
||||
* suspends the continuous count task, resuming it again when the copy has been
|
||||
* taken. The controller task then sleeps for a fixed period - during which
|
||||
* the continuous count task will execute and increment the shared variable.
|
||||
* When the controller task wakes it checks that the continuous count task
|
||||
* has executed by comparing the copy of the shared variable with its current
|
||||
* value. This time, to ensure mutual exclusion, the scheduler itself is
|
||||
* suspended with a call to vTaskSuspendAll (). This is for demonstration
|
||||
* purposes only and is not a recommended technique due to its inefficiency.
|
||||
*
|
||||
* After a fixed number of iterations the controller task suspends the
|
||||
* continuous count task, and moves on to its second section.
|
||||
*
|
||||
* At the start of the second section the shared variable is cleared to zero.
|
||||
* The limited count task is then woken from its suspension by a call to
|
||||
* vTaskResume (). As this counter task operates at a higher priority than
|
||||
* the controller task the controller task should not run again until the
|
||||
* shared variable has been counted up to the limited value causing the counter
|
||||
* task to suspend itself. The next line after vTaskResume () is therefore
|
||||
* a check on the shared variable to ensure everything is as expected.
|
||||
*
|
||||
*
|
||||
* The second test consists of a couple of very simple tasks that post onto a
|
||||
* queue while the scheduler is suspended. This test was added to test parts
|
||||
* of the scheduler not exercised by the first test.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "dynamic.h"
|
||||
|
||||
/* Function that implements the "limited count" task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vLimitedIncrementTask, pvParameters );
|
||||
|
||||
/* Function that implements the "continuous count" task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vContinuousIncrementTask, pvParameters );
|
||||
|
||||
/* Function that implements the controller task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vCounterControlTask, pvParameters );
|
||||
|
||||
static portTASK_FUNCTION_PROTO( vQueueReceiveWhenSuspendedTask, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );
|
||||
|
||||
/* Demo task specific constants. */
|
||||
#define priSTACK_SIZE ( configMINIMAL_STACK_SIZE )
|
||||
#define priSLEEP_TIME pdMS_TO_TICKS( 128 )
|
||||
#define priLOOPS ( 5 )
|
||||
#define priMAX_COUNT ( ( uint32_t ) 0xff )
|
||||
#define priNO_BLOCK ( ( TickType_t ) 0 )
|
||||
#define priSUSPENDED_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Handles to the two counter tasks. These could be passed in as parameters
|
||||
to the controller task to prevent them having to be file scope. */
|
||||
static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle;
|
||||
|
||||
/* The shared counter variable. This is passed in as a parameter to the two
|
||||
counter variables for demonstration purposes. */
|
||||
static volatile uint32_t ulCounter;
|
||||
|
||||
/* Variables used to check that the tasks are still operating without error.
|
||||
Each complete iteration of the controller task increments this variable
|
||||
provided no errors have been found. The variable maintaining the same value
|
||||
is therefore indication of an error. */
|
||||
static volatile uint16_t usCheckVariable = ( uint16_t ) 0;
|
||||
static volatile BaseType_t xSuspendedQueueSendError = pdFALSE;
|
||||
static volatile BaseType_t xSuspendedQueueReceiveError = pdFALSE;
|
||||
|
||||
/* Queue used by the second test. */
|
||||
QueueHandle_t xSuspendedTestQueue;
|
||||
|
||||
/* The value the queue receive task expects to receive next. This is file
|
||||
scope so xAreDynamicPriorityTasksStillRunning() can ensure it is still
|
||||
incrementing. */
|
||||
static uint32_t ulExpectedValue = ( uint32_t ) 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
/*
|
||||
* Start the three tasks as described at the top of the file.
|
||||
* Note that the limited count task is given a higher priority.
|
||||
*/
|
||||
void vStartDynamicPriorityTasks( void )
|
||||
{
|
||||
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( uint32_t ) );
|
||||
|
||||
if( xSuspendedTestQueue != NULL )
|
||||
{
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xSuspendedTestQueue, "Suspended_Test_Queue" );
|
||||
|
||||
xTaskCreate( vContinuousIncrementTask, "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
|
||||
xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
|
||||
xTaskCreate( vCounterControlTask, "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just loops around incrementing the shared variable until the limit has been
|
||||
* reached. Once the limit has been reached it suspends itself.
|
||||
*/
|
||||
static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )
|
||||
{
|
||||
uint32_t *pulCounter;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
the task. */
|
||||
pulCounter = ( uint32_t * ) pvParameters;
|
||||
|
||||
/* This will run before the control task, so the first thing it does is
|
||||
suspend - the control task will resume it when ready. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Just count up to a value then suspend. */
|
||||
( *pulCounter )++;
|
||||
|
||||
if( *pulCounter >= priMAX_COUNT )
|
||||
{
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just keep counting the shared variable up. The control task will suspend
|
||||
* this task when it wants.
|
||||
*/
|
||||
static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters )
|
||||
{
|
||||
volatile uint32_t *pulCounter;
|
||||
UBaseType_t uxOurPriority;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
the task. */
|
||||
pulCounter = ( uint32_t * ) pvParameters;
|
||||
|
||||
/* Query our priority so we can raise it when exclusive access to the
|
||||
shared variable is required. */
|
||||
uxOurPriority = uxTaskPriorityGet( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Raise the priority above the controller task to ensure a context
|
||||
switch does not occur while the variable is being accessed. */
|
||||
vTaskPrioritySet( NULL, uxOurPriority + 1 );
|
||||
{
|
||||
configASSERT( ( uxTaskPriorityGet( NULL ) == ( uxOurPriority + 1 ) ) );
|
||||
( *pulCounter )++;
|
||||
}
|
||||
vTaskPrioritySet( NULL, uxOurPriority );
|
||||
|
||||
#if( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
configASSERT( ( uxTaskPriorityGet( NULL ) == uxOurPriority ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Controller task as described above.
|
||||
*/
|
||||
static portTASK_FUNCTION( vCounterControlTask, pvParameters )
|
||||
{
|
||||
uint32_t ulLastCounter;
|
||||
short sLoops;
|
||||
short sError = pdFALSE;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Start with the counter at zero. */
|
||||
ulCounter = ( uint32_t ) 0;
|
||||
|
||||
/* First section : */
|
||||
|
||||
/* Check the continuous count task is running. */
|
||||
for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
|
||||
{
|
||||
/* Suspend the continuous count task so we can take a mirror of the
|
||||
shared variable without risk of corruption. This is not really
|
||||
needed as the other task raises its priority above this task's
|
||||
priority. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
{
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
ulLastCounter = ulCounter;
|
||||
}
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
|
||||
#if( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eReady );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Now delay to ensure the other task has processor time. */
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
/* Check the shared variable again. This time to ensure mutual
|
||||
exclusion the whole scheduler will be locked. This is just for
|
||||
demo purposes! */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
if( ulLastCounter == ulCounter )
|
||||
{
|
||||
/* The shared variable has not changed. There is a problem
|
||||
with the continuous count task so flag an error. */
|
||||
sError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
/* Second section: */
|
||||
|
||||
/* Suspend the continuous counter task so it stops accessing the shared
|
||||
variable. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
|
||||
/* Reset the variable. */
|
||||
ulCounter = ( uint32_t ) 0;
|
||||
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Resume the limited count task which has a higher priority than us.
|
||||
We should therefore not return from this call until the limited count
|
||||
task has suspended itself with a known value in the counter variable. */
|
||||
vTaskResume( xLimitedIncrementHandle );
|
||||
|
||||
#if( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* This task should not run again until xLimitedIncrementHandle has
|
||||
suspended itself. */
|
||||
#if( INCLUDE_eTaskGetState == 1 )
|
||||
{
|
||||
configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
|
||||
}
|
||||
#endif /* INCLUDE_eTaskGetState */
|
||||
|
||||
/* Does the counter variable have the expected value? */
|
||||
if( ulCounter != priMAX_COUNT )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If no errors have occurred then increment the check variable. */
|
||||
portENTER_CRITICAL();
|
||||
usCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Resume the continuous count task and do it all again. */
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
|
||||
#if( configUSE_PREEMPTION == 0 )
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters )
|
||||
{
|
||||
static uint32_t ulValueToSend = ( uint32_t ) 0;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* We must not block while the scheduler is suspended! */
|
||||
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
|
||||
{
|
||||
xSuspendedQueueSendError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
++ulValueToSend;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters )
|
||||
{
|
||||
uint32_t ulReceivedValue;
|
||||
BaseType_t xGotValue;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Suspending the scheduler here is fairly pointless and
|
||||
undesirable for a normal application. It is done here purely
|
||||
to test the scheduler. The inner xTaskResumeAll() should
|
||||
never return pdTRUE as the scheduler is still locked by the
|
||||
outer call. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
|
||||
}
|
||||
if( xTaskResumeAll() != pdFALSE )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
|
||||
} while( xGotValue == pdFALSE );
|
||||
|
||||
if( ulReceivedValue != ulExpectedValue )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueReceiveError != pdTRUE )
|
||||
{
|
||||
/* Only increment the variable if an error has not occurred. This
|
||||
allows xAreDynamicPriorityTasksStillRunning() to check for stalled
|
||||
tasks as well as explicit errors. */
|
||||
++ulExpectedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Called to check that all the created tasks are still running without error. */
|
||||
BaseType_t xAreDynamicPriorityTasksStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if it has been incremented
|
||||
since the last call. */
|
||||
static uint16_t usLastTaskCheck = ( uint16_t ) 0;
|
||||
static uint32_t ulLastExpectedValue = ( uint32_t ) 0U;
|
||||
BaseType_t xReturn = pdTRUE;
|
||||
|
||||
/* Check the tasks are still running by ensuring the check variable
|
||||
is still incrementing. */
|
||||
|
||||
if( usCheckVariable == usLastTaskCheck )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( ulExpectedValue == ulLastExpectedValue )
|
||||
{
|
||||
/* The value being received by the queue receive task has not
|
||||
incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueSendError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueReceiveError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck = usCheckVariable;
|
||||
ulLastExpectedValue = ulExpectedValue;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
All rights reserved
|
||||
|
||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
***************************************************************************
|
||||
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
>>! obliged to provide the source code for proprietary components !<<
|
||||
>>! outside of the FreeRTOS kernel. !<<
|
||||
***************************************************************************
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
link: http://www.freertos.org/a00114.html
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS provides completely free yet professionally developed, *
|
||||
* robust, strictly quality controlled, supported, and cross *
|
||||
* platform software that is more than just the market leader, it *
|
||||
* is the industry's de facto standard. *
|
||||
* *
|
||||
* Help yourself get started quickly while simultaneously helping *
|
||||
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
* tutorial book, reference manual, or both: *
|
||||
* http://www.FreeRTOS.org/Documentation *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
defined configASSERT()?
|
||||
|
||||
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
embedded software for free we request you assist our global community by
|
||||
participating in the support forum.
|
||||
|
||||
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
be as productive as possible as early as possible. Now you can receive
|
||||
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
engineered and independently SIL3 certified version for use in safety and
|
||||
mission critical applications that require provable dependability.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/**
|
||||
* This version of flash .c is for use on systems that have limited stack space
|
||||
* and no display facilities. The complete version can be found in the
|
||||
* Demo/Common/Full directory.
|
||||
*
|
||||
* Three tasks are created, each of which flash an LED at a different rate. The first
|
||||
* LED flashes every 200ms, the second every 400ms, the third every 600ms.
|
||||
*
|
||||
* The LED flash tasks provide instant visual feedback. They show that the scheduler
|
||||
* is still operational.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "partest.h"
|
||||
#include "flash.h"
|
||||
|
||||
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define ledNUMBER_OF_LEDS ( 3 )
|
||||
#define ledFLASH_RATE_BASE ( ( TickType_t ) 333 )
|
||||
|
||||
/* Variable used by the created tasks to calculate the LED number to use, and
|
||||
the rate at which they should flash the LED. */
|
||||
static volatile UBaseType_t uxFlashTaskNumber = 0;
|
||||
|
||||
/* The task that is created three times. */
|
||||
static portTASK_FUNCTION_PROTO( vLEDFlashTask, pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartLEDFlashTasks( UBaseType_t uxPriority )
|
||||
{
|
||||
BaseType_t xLEDTask;
|
||||
|
||||
/* Create the three tasks. */
|
||||
for( xLEDTask = 0; xLEDTask < ledNUMBER_OF_LEDS; ++xLEDTask )
|
||||
{
|
||||
/* Spawn the task. */
|
||||
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vLEDFlashTask, pvParameters )
|
||||
{
|
||||
TickType_t xFlashRate, xLastFlashTime;
|
||||
UBaseType_t uxLED;
|
||||
|
||||
/* The parameters are not used. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Calculate the LED and flash rate. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* See which of the eight LED's we should use. */
|
||||
uxLED = uxFlashTaskNumber;
|
||||
|
||||
/* Update so the next task uses the next LED. */
|
||||
uxFlashTaskNumber++;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( TickType_t ) uxLED );
|
||||
xFlashRate /= portTICK_PERIOD_MS;
|
||||
|
||||
/* We will turn the LED on and off again in the delay period, so each
|
||||
delay is only half the total period. */
|
||||
xFlashRate /= ( TickType_t ) 2;
|
||||
|
||||
/* We need to initialise xLastFlashTime prior to the first call to
|
||||
vTaskDelayUntil(). */
|
||||
xLastFlashTime = xTaskGetTickCount();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
/* Delay for half the flash period then turn the LED on. */
|
||||
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
|
||||
vParTestToggleLED( uxLED );
|
||||
|
||||
/* Delay for half the flash period then turn the LED off. */
|
||||
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
|
||||
vParTestToggleLED( uxLED );
|
||||
}
|
||||
} /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user