河北水利局项目
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Debug/
|
||||||
|
settings/
|
||||||
|
Source Insight/
|
||||||
18
.vscode/iar-vsc.json
vendored
Normal file
18
.vscode/iar-vsc.json
vendored
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
114
APP/Basedefine.h
Normal file
114
APP/Basedefine.h
Normal file
@@ -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
APP/Cmd.c.bak
Normal file
1913
APP/Cmd.c.bak
Normal file
File diff suppressed because it is too large
Load Diff
57
APP/Cmd.h
Normal file
57
APP/Cmd.h
Normal file
@@ -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
APP/Flash.c
Normal file
166
APP/Flash.c
Normal file
@@ -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
APP/Flash.h
Normal file
43
APP/Flash.h
Normal file
@@ -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
APP/General.c
Normal file
309
APP/General.c
Normal file
@@ -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();// 复位
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
97
APP/General.h
Normal file
97
APP/General.h
Normal file
@@ -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
APP/Init.c
Normal file
165
APP/Init.c
Normal file
@@ -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
APP/Init.h
Normal file
44
APP/Init.h
Normal file
@@ -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
APP/IrDA.c
Normal file
724
APP/IrDA.c
Normal file
@@ -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
APP/IrDA.h
Normal file
59
APP/IrDA.h
Normal file
@@ -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
|
||||||
248
APP/Led.c
Normal file
248
APP/Led.c
Normal file
@@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
115
APP/Led.h
Normal file
115
APP/Led.h
Normal file
@@ -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****/
|
||||||
189
APP/MD5.c
Normal file
189
APP/MD5.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
53
APP/MD5.h
Normal file
53
APP/MD5.h
Normal file
@@ -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
|
||||||
129
APP/Mem.c
Normal file
129
APP/Mem.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
66
APP/Mem.h
Normal file
66
APP/Mem.h
Normal file
@@ -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
|
||||||
|
|
||||||
416
APP/PHY.c
Normal file
416
APP/PHY.c
Normal file
@@ -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
|
||||||
8
APP/PHY.h
Normal file
8
APP/PHY.h
Normal file
@@ -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);
|
||||||
223
APP/Rtc.c
Normal file
223
APP/Rtc.c
Normal file
@@ -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****/
|
||||||
47
APP/Rtc.h
Normal file
47
APP/Rtc.h
Normal 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****/
|
||||||
415
APP/WaterMeterManager.c
Normal file
415
APP/WaterMeterManager.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
125
APP/WaterMetermanager.h
Normal file
125
APP/WaterMetermanager.h
Normal file
@@ -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
APP/addr.c
Normal file
135
APP/addr.c
Normal file
@@ -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
APP/addr.h
Normal file
27
APP/addr.h
Normal file
@@ -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
|
||||||
59
APP/apl.c
Normal file
59
APP/apl.c
Normal file
@@ -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****/
|
||||||
33
APP/apl.h
Normal file
33
APP/apl.h
Normal 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
APP/bl24c512.c
Normal file
673
APP/bl24c512.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
46
APP/bl24c512.h
Normal file
46
APP/bl24c512.h
Normal file
@@ -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
|
||||||
894
APP/debug_printf.c
Normal file
894
APP/debug_printf.c
Normal file
@@ -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 );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
163
APP/debug_printf.h
Normal file
163
APP/debug_printf.h
Normal file
@@ -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
APP/hal_radio.c
Normal file
885
APP/hal_radio.c
Normal file
@@ -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
APP/hal_radio.h
Normal file
240
APP/hal_radio.h
Normal file
@@ -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****/
|
||||||
41
APP/include.h
Normal file
41
APP/include.h
Normal 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
APP/keywd.c
Normal file
181
APP/keywd.c
Normal file
@@ -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
APP/keywd.h
Normal file
13
APP/keywd.h
Normal file
@@ -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
APP/main.c
Normal file
319
APP/main.c
Normal file
@@ -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
APP/protocol.c
Normal file
2209
APP/protocol.c
Normal file
File diff suppressed because it is too large
Load Diff
693
APP/protocol.h
Normal file
693
APP/protocol.h
Normal file
@@ -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
APP/rtc_ext.c
Normal file
506
APP/rtc_ext.c
Normal file
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
72
APP/rtc_ext.h
Normal file
72
APP/rtc_ext.h
Normal file
@@ -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
|
||||||
32
APP/storage.c
Normal file
32
APP/storage.c
Normal file
@@ -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);
|
||||||
|
|
||||||
32
APP/storage.h
Normal file
32
APP/storage.h
Normal file
@@ -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
|
||||||
638
APP/sx1276-Fsk.c
Normal file
638
APP/sx1276-Fsk.c
Normal file
@@ -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
APP/sx1276-Fsk.h
Normal file
1500
APP/sx1276-Fsk.h
Normal file
File diff suppressed because it is too large
Load Diff
515
APP/sx1276-FskMisc.c
Normal file
515
APP/sx1276-FskMisc.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
241
APP/sx1276-FskMisc.h
Normal file
241
APP/sx1276-FskMisc.h
Normal file
@@ -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__
|
||||||
832
APP/sx1276-LoRa.c
Normal file
832
APP/sx1276-LoRa.c
Normal file
@@ -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
APP/sx1276-LoRa.h
Normal file
1071
APP/sx1276-LoRa.h
Normal file
File diff suppressed because it is too large
Load Diff
414
APP/sx1276-LoRaMisc.c
Normal file
414
APP/sx1276-LoRaMisc.c
Normal file
@@ -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
|
||||||
315
APP/sx1276-LoRaMisc.h
Normal file
315
APP/sx1276-LoRaMisc.h
Normal file
@@ -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
APP/uart.c
Normal file
3089
APP/uart.c
Normal file
File diff suppressed because it is too large
Load Diff
751
APP/uart.h
Normal file
751
APP/uart.h
Normal file
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
588
APP/uart.h~RF183f36a.TMP
Normal file
588
APP/uart.h~RF183f36a.TMP
Normal file
@@ -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
APP/update.c
Normal file
916
APP/update.c
Normal file
@@ -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
APP/update.h
Normal file
147
APP/update.h
Normal file
@@ -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
|
||||||
|
|
||||||
53
APP/wdg.c
Normal file
53
APP/wdg.c
Normal file
@@ -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();
|
||||||
|
}
|
||||||
42
APP/wdg.h
Normal file
42
APP/wdg.h
Normal file
@@ -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__ */
|
||||||
1182
Backup of Backup of Backup of RTOSDemo.ewp
Normal file
1182
Backup of Backup of Backup of RTOSDemo.ewp
Normal file
File diff suppressed because it is too large
Load Diff
936
Backup of Backup of RTOSDemo.dep
Normal file
936
Backup of Backup of RTOSDemo.dep
Normal file
@@ -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>
|
||||||
1419
Backup of Backup of RTOSDemo.ewd
Normal file
1419
Backup of Backup of RTOSDemo.ewd
Normal file
File diff suppressed because it is too large
Load Diff
1335
Backup of Backup of RTOSDemo.ewp
Normal file
1335
Backup of Backup of RTOSDemo.ewp
Normal file
File diff suppressed because it is too large
Load Diff
1487
Backup of Backup of RTOSDemo.ewt
Normal file
1487
Backup of Backup of RTOSDemo.ewt
Normal file
File diff suppressed because it is too large
Load Diff
350
Common/Full/BlockQ.c
Normal file
350
Common/Full/BlockQ.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
262
Common/Full/PollQ.c
Normal file
262
Common/Full/PollQ.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
388
Common/Full/comtest.c
Normal file
388
Common/Full/comtest.c
Normal file
@@ -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 );
|
||||||
|
}
|
||||||
245
Common/Full/death.c
Normal file
245
Common/Full/death.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
620
Common/Full/dynamic.c
Normal file
620
Common/Full/dynamic.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
410
Common/Full/events.c
Normal file
410
Common/Full/events.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
170
Common/Full/flash.c
Normal file
170
Common/Full/flash.c
Normal file
@@ -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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
373
Common/Full/flop.c
Normal file
373
Common/Full/flop.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
369
Common/Full/integer.c
Normal file
369
Common/Full/integer.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
148
Common/Full/print.c
Normal file
148
Common/Full/print.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
327
Common/Full/semtest.c
Normal file
327
Common/Full/semtest.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
681
Common/Minimal/AbortDelay.c
Normal file
681
Common/Minimal/AbortDelay.c
Normal file
@@ -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 */
|
||||||
332
Common/Minimal/BlockQ.c
Normal file
332
Common/Minimal/BlockQ.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
1078
Common/Minimal/EventGroupsDemo.c
Normal file
1078
Common/Minimal/EventGroupsDemo.c
Normal file
File diff suppressed because it is too large
Load Diff
788
Common/Minimal/GenQTest.c
Normal file
788
Common/Minimal/GenQTest.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
769
Common/Minimal/IntQueue.c
Normal file
769
Common/Minimal/IntQueue.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
567
Common/Minimal/IntSemTest.c
Normal file
567
Common/Minimal/IntSemTest.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
265
Common/Minimal/PollQ.c
Normal file
265
Common/Minimal/PollQ.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
481
Common/Minimal/QPeek.c
Normal file
481
Common/Minimal/QPeek.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
272
Common/Minimal/QueueOverwrite.c
Normal file
272
Common/Minimal/QueueOverwrite.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
738
Common/Minimal/QueueSet.c
Normal file
738
Common/Minimal/QueueSet.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
221
Common/Minimal/QueueSetPolling.c
Normal file
221
Common/Minimal/QueueSetPolling.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
1148
Common/Minimal/StaticAllocation.c
Normal file
1148
Common/Minimal/StaticAllocation.c
Normal file
File diff suppressed because it is too large
Load Diff
603
Common/Minimal/TaskNotify.c
Normal file
603
Common/Minimal/TaskNotify.c
Normal file
@@ -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 ) );
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
1108
Common/Minimal/TimerDemo.c
Normal file
1108
Common/Minimal/TimerDemo.c
Normal file
File diff suppressed because it is too large
Load Diff
582
Common/Minimal/blocktim.c
Normal file
582
Common/Minimal/blocktim.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
307
Common/Minimal/comtest.c
Normal file
307
Common/Minimal/comtest.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
353
Common/Minimal/comtest_strings.c
Normal file
353
Common/Minimal/comtest_strings.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
330
Common/Minimal/countsem.c
Normal file
330
Common/Minimal/countsem.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
250
Common/Minimal/crflash.c
Normal file
250
Common/Minimal/crflash.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
274
Common/Minimal/crhook.c
Normal file
274
Common/Minimal/crhook.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
257
Common/Minimal/death.c
Normal file
257
Common/Minimal/death.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
518
Common/Minimal/dynamic.c
Normal file
518
Common/Minimal/dynamic.c
Normal file
@@ -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;
|
||||||
|
}
|
||||||
161
Common/Minimal/flash.c
Normal file
161
Common/Minimal/flash.c
Normal file
@@ -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