单链表 源码C程序源文件:DataRetrans.c
/**
* @file :
* @date :20191118
* @author :zhoumin
*/
#include "DataRetrans.h"
#include "server.h"
#include "rtc.h"
#include <stdbool.h>
#if MALLOC_SWITCH
void *pmalloc(uint32_t size) { return calloc(size, sizeof(uint8_t));}
malloc_fn Retrans_malloc = (malloc_fn)pmalloc;
free_fn Retrans_free = (free_fn)free;
#else
void* (*Retrans_malloc)(size_t sz) = pvPortMalloc;//malloc;
void (*Retrans_free)(void *ptr) = vPortFree;//free;
#endif
#define QUEUE_SIZE 20
/*初始化单链表*/
void InitList(LNode **HL)
{
*HL = NULL; //置单链表为空
}
/*删除单链表中所有节点,使其成为空表*/
void ClearList(LNode **HL)
{
LNode *cp; //cp(current pointer)指向当前待处理节点
LNode *np; //np(next pointer)指向cp的后继节点
cp = *HL; //表头指针赋给cp
while(cp != NULL){
np = cp->next;
Retrans_free(cp);//释放该节点内存
cp =np; //使下一个节点成为当前节点
}
*HL = NULL;
}
/*得到单链表的长度*/
uint16_t LengthList(LNode *HL)
{
uint16_t i=0;
while(HL != NULL){
i++;
HL = HL->next;
}
return i;
}
/*检查单链表是否为空*/
bool EmptyList(LNode *HL)
{
return HL==NULL;
}
/*得到单链表中第pos个节点中的元素*/ //节点序号从表头的序号1开始
ElemType GetList(LNode *HL, uint16_t pos) //pos>=1
{
if(pos < 1){
LOG_L("pos is Wrongful!");
return NULL;
}
uint16_t i= 0;
while(HL != NULL){
i++;
if(i == pos)
break;
HL = HL->next;
}
if(HL != NULL){ //不为空,说明已找到该节点
return HL->data;
}
else{
LOG_L("pos is out range!");//没找到
return NULL;
}
}
/*遍历一个链表*/
void TraverseList(LNode *HL)
{
while(HL != NULL){
//LOG_L(fmt, args...);
HL = HL->next;
}
}
/*从链表中查找出给定值的第一个元素,并由item带回该值*/
bool FindList(LNode *HL, ElemType *item)
{
while(HL != NULL){
if(*item == HL->data){ //根据具体比对项,修改此处代码
*item = HL->data; //根据具体比对项,修改此处代码
return true;
}
else{
HL = HL->next;
}
}
return false;
}
/*更新链表中等于给定值的第一个元素*/
bool UpdateList(LNode *HL, const ElemType *item)
{
while(HL != NULL){
if(HL->data == *item)
break;
else
HL = HL->next;
}
if(HL == NULL) //没有找到给定值的元素,无法更新
return false;
else{
HL->data = *item;
return true;
}
}
/*向单链表中按给定条件插入一个元素*/ //表头节点的序号指定为1,pos==1,表示插入到表头
bool InsertList(LNode **HL, ElemType item, int pos) //pos必须大于等于-1;pos:0 按值寻找插入位置 pos:-1插入到表尾 pos:>0 插入到pos指定序号位置
{
if(pos < -1){
LOG_L("pos is Wrongful!");
return false;
}
//为item元素建立新节点
LNode *newptr;
newptr = (LNode *)Retrans_malloc(sizeof(LNode));
newptr->data = item;
//寻找新节点的插入位置
LNode *cp = *HL; //cp指向当前节点,即待查节点,初始为指向表头
LNode *ap = NULL; //ahead pointer 指向cp的前驱节点,初始化空
if(pos == 0){ //pos:0 按值寻找插入位置
while(cp != NULL){
if(item < cp->data) //根据具体比对内容,修改此处代码
break; //找到新元素的插入位置,退出循环
else{
ap = cp;
cp = cp->next;
}
}
}
else if(pos == -1){ //pos:-1插入到表尾
while(cp != NULL){
ap =cp;
cp = cp->next;
}
}
else{ //pos:>0 插入到pos指定序号位置
int i = 0;
while(cp != NULL){
i++;
if(i == pos){ //pos==1,表示插入到表头
break;
}
else{
ap = cp;
cp = cp->next;
}
}
if(cp == NULL && i <pos){ //ypl-教材应该有误,教材源码: (cp == NULL && i+1 <pos)
LOG_L("pos is not exist!");
return false;
}
}
//完成新节点的插入操作
if(ap == NULL){ //ap为空,表示,将要插入的节点位置就是表头--表头的前驱节点就是空
newptr->next = *HL;
*HL = newptr;
}
else{ //把新节点插入到非表头位置,即插入到ap和cp之间
newptr->next = cp; //cp如果为空,则表示插入到表尾
ap->next = newptr;
}
return true;
}
/*从单链表中删除符合给定条件的第一个元素*/
bool DeleteList(LNode **HL, ElemType *item, int pos) //pos必须大于等于-1;pos:0 按值寻找待删节点 pos:-1待删节点是表尾 pos:>0 插入到pos指定序号位置
{
//单链表为空,无法删除,返回假
if(*HL == NULL){
LOG_L("LIST is empty!");
return false;
}
//pos值小于-1,返回假
if(pos < -1){
LOG_L("pos's value is invalid!");
return false;
}
//寻找需要被删除的元素的节点
LNode *cp = *HL; //cp指向当前节点,即待查节点,初始为指向表头
LNode *ap = NULL; //ahead pointer 指向cp的前驱节点,初始化空
if(pos == 0){ //按值查找被删除节点
while(cp != NULL){
if(*item == cp->data)
break;
else{
ap = cp;
cp = cp->next;
}
}
if(cp == NULL){
LOG_L("pos's value can't find!");
return false;
}
}
else if(pos == -1){ //查找表尾节点
while(cp->next != NULL){
ap = cp;
cp = cp->next;
}
}
else{ //查找给定序号的节点
int i = 0;
while(cp != NULL){
i++;
if(i == pos){
break;
}
else{
ap = cp;
cp = cp->next;
}
}
if(cp == NULL){
LOG_L("pos is over lenth!");//指定序号越界超过链表实际长度
return false;
}
}
//删除cp指向的节点
if(ap == NULL){ //删除表头节点
#if 1
LNode *temp = *HL; //ypl-语法可能出错的备用方案
*HL = temp->next;
#else
*HL = (*HL)->next;//ypl-语法不标准,但仍旧能够编译过
#endif
}
else{ //删除非表头节点,也可能是表尾节点
ap->next = cp->next;
}
//回收被删除节点的存储空间
Retrans_free(cp);//ypl-实际上,要回收的数据还不止节点占用的空间,还有
return true;
}
/*对单链表进行数据排序
*假定待排序的单链表由表头指针HL所指向,对节点值按照从小到大进行排序链接时,首先建立一个空的单链表,
*然后把HL中的每个节点取出来并按值依次插入到新建立的单链表中,最后由HL带回新建链表的表头指针
*/
void SortList(LNode **HL)
{
//建立一个反映排序结果的新单链表,并初始化为空
LNode *SL;
InitList(&SL);
//从待排序的HL单链表中依次取出每个节点,并按值由小到大插入到新单链表中
LNode *r=*HL; //r指向待取出排序的一个节点,初始化为HL表头节点
LNode *t; //t指向r的后继节点
LNode *cp; //指向已排序的新链表,初始化为表头SL
LNode *ap; //ap指向cp的前驱节点,初始化为空
while(r != NULL)
{
//为新插入的r节点在SL中顺序查找出插入位置
t = r->next; //t指向原链表r节点的后继节点
cp = SL; //指向已排序的新链表,初始化为表头SL
ap = NULL; //ap指向cp的前驱节点,初始化为空
while(cp != NULL)
{
if(r->data < cp->data)
break; //找到被插入点,退出循环
else{
ap = cp; //ap和cp均后移,实现有序链表中的每个节点依次顺序和原链表中r节点比较
cp = cp->next;
}
}
//实现插入操作
if(ap == NULL){ //把r节点插入到表头
r->next = SL;
SL = r;
}
else{ //把r节点插入到ap和cp之间
r->next = cp;
ap->next = r;
}
//使r指向原链表的下一个节点
r = t;
}
//返回链表排序结果
*HL = SL;
}
QueueHandle_t xQueue;
//osSemaphoreId xComRxSem;
struct Repeat_Qmsg *reMsgHead = NULL;
LNode *reMSGHead;
/**
* 数据单元内存释放
*/
void FreeQMsg(QMsg *pmsg)
{
if(pmsg != NULL)
{
if(pmsg->message.data != NULL)
{
Retrans_free(pmsg->message.data);
pmsg->message.data = NULL;
}
Retrans_free(pmsg);
pmsg = NULL;
}
}
int PutToRepeatQmsg(QMsg *data)
{
struct Repeat_Qmsg *p = (struct Repeat_Qmsg *)Retrans_malloc(sizeof(struct Repeat_Qmsg));
if(p == NULL)
{
LOG_E("malloc error.\r\n");
return CL_FAIL;
}
p->data = data;
if(reMsgHead == NULL)
{
p->next = NULL;
reMsgHead = p;
}
else
{
p->next = reMsgHead;
reMsgHead = p;
}
return CL_OK;
}
void RepeatQmsgLoop(void)
{
struct Repeat_Qmsg *p = reMsgHead;
struct Repeat_Qmsg *last = NULL ,*temp;
QMsg *data = NULL;
while (p != NULL)
{
if(GetTimeStamp() >= p->data->timestamp+3000)
{
data = p->data;
//将节点数据添加到发送队列
if(xQueueSendToBack(xQueue,(void*)&data,0) != pdTRUE)
{
LOG_E("send to queue error.\r\n");
FreeQMsg(data);//添加队列失败,释放数据单元内存
}
/* 删除节点p */
temp = p; //记录节点
if(p == reMsgHead)//p指向头节点
{
reMsgHead = p->next;
}
else
{
last->next = p->next;
}
last = p;
p = p->next;
Retrans_free(temp);//释放该节点内存
temp = NULL;
}
else
{
last = p;
p = p->next;
}
}
}
int DataRetrans_SendMsg(Message_Unit message,timeout_callback callback)
{
BaseType_t ret ;
if(message.data == NULL)
return CL_FAIL;
QMsg *pmsg = (QMsg *)Retrans_malloc(sizeof(QMsg));
if(pmsg == NULL)
{
LOG_E("malloc queue msg failed.\r\n");
return CL_FAIL;
}
pmsg->message = message;
pmsg->flag = 1;
pmsg->callback = callback;
pmsg->timers = 1;
ret = xQueueSendToBack(xQueue,&pmsg,0);
//ret = xQueueSendToFront(xQueue,&pmsg,0);
if(ret != pdTRUE)
{
LOG_E("send msg to queue error.\r\n");
Retrans_free(pmsg);
return CL_FAIL;
}
return CL_OK;
}
void BswSrv_485SendTask(void *argc)
{
uint32_t values = 0;
QMsg *pmsg = NULL;
BaseType_t ret;
//UNUSED(argc);
while (1)
{
vTaskDelay(300);
Feed_WDT();
ret = xQueueReceive(xQueue,(void*)&pmsg, 5/*portMAX_DELAY*/);
if(ret == pdTRUE && pmsg != NULL)
{
//发送消息
//LOG_I("-->msg:%s \r\n",pmsg->message.data);
//PrintfData(">>msg:",pmsg->message.data,pmsg->message.len);
//BswDrv_UsartSend(CHG_UART_INDEX, pmsg->message.data,pmsg->message.len);
pmsg->timers++;
pmsg->timestamp = GetTimeStamp();
//等待消息ACK 最多等待200ms
values = ulTaskNotifyTake(pdTRUE,200);
if(values == 1)//收到ack
{
FreeQMsg(pmsg);
}
else if(pmsg->flag == 1)//超时
{
if(pmsg->timers >= 3)
{
FreeQMsg(pmsg);
if(pmsg->callback) pmsg->callback();
//LOG_I("send data timeout.\r\n");
}
else
{
//添加到重发队列
PutToRepeatQmsg(pmsg);
LOG_E("PutToRepeatQmsg. \r\n");
}
}
else
{
FreeQMsg(pmsg);
//LOG_I("wait ack timeout.\r\n");
}
}
//轮询重发队列
RepeatQmsgLoop();
}
}
/**
* 485总线任务初始化
*/
void BswSrv_485TaskInit(void)
{
xQueue = xQueueCreate(QUEUE_SIZE, sizeof(QMsg *));
//xComRxSem = osSemaphoreCreate(NULL,10);
reMsgHead = NULL;
}
单链表 源码C程序头文件:DataRetrans.h
#ifndef __DATA_RESTRANS_H_
#define __DATA_RESTRANS_H_
#include "includes.h"
//typedef enum {FALSE = 0, TRUE = !FALSE } Bool;
typedef void (*timeout_callback) (void);
/**
* 消息单元
*/ /*重发数据区*/
typedef struct
{
uint16_t len; //数据长度
void * data; //数据缓存区
uint16_t msgId; //流水号
uint8_t cmd; //指令
}Message_Unit;
/**
* 队列数据单元
*/
typedef struct
{
/*重发数据区*/
Message_Unit message;
/*重发控制器*/
uint8_t flag; //未收到应答的重发标志 1:正在重发 0:结束重发
uint8_t timers; //当前发送次数
uint32_t timestamp; //上次发送时间戳
timeout_callback callback; //超时回调函数
}QMsg;
typedef QMsg* ElemType;
struct _LNode{
ElemType data;
struct _LNode *next;
};
typedef struct _LNode LNode;
/**
* 重传消息链表
*/
struct Repeat_Qmsg
{
QMsg *data;
struct Repeat_Qmsg *next;
};
#define MALLOC_SWITCH 1 //0
#if MALLOC_SWITCH
typedef void *(*malloc_fn)(size_t sz);
typedef void (*free_fn)(void *ptr);
extern malloc_fn Retrans_malloc;//malloc;
extern free_fn Retrans_free;//free;
#else
extern void *(*Retrans_malloc)(size_t sz);//malloc;
extern void (*Retrans_free)(void *ptr);//free;
#endif
int DataRetrans_SendMsg(Message_Unit message,timeout_callback callback);
void BswSrv_485TaskInit(void);
#endif