1. 程式人生 > >一個簡單的接收快取設計——C語言實現

一個簡單的接收快取設計——C語言實現

#include "string.h"
#include "stdlib.h"
#include "stdio.h"
/************************/
#include "SYS_ENUM.h"
#include "LoopRecBuff.h"

/*******************************************************
MIT License

Copyright (c) 2018 w64228013

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*******************************************************/

//LoopBuff uartbuff = 
//{
//		NULL, //ucBuff address
//		MaxBuffLength,//usBuffLength
//		LimitedBuffHead,//usRecPos
//		LimitedBuffHead,//usReadPos
//		MaxReTryCount,//usRetryCount
//		0,//ucIsReadBusy
//};

unsigned char ucBuffArray[MaxBuffLength] = {0};

/**
  * @brief  內部使用,當重試次數超過MaxReTryCount後呼叫
  * @note   
  * @param  *t_AimLoopBuffPtr:快取塊結構體的指標;RecPos:接收的快取位置
  * @retval None
*/
void Syn_Loop_Buff_Pos(LoopBuff *t_AimLoopBuffPtr,unsigned short RecPos)
{
	t_AimLoopBuffPtr->usReadPos = RecPos;
	t_AimLoopBuffPtr->usRetryCount = MaxReTryCount;
}
/**
  * @brief  未使用,重置讀取位置和接收位置
  * @note   
  * @param  *t_AimLoopBuffPtr:快取塊結構體的指標;
  * @retval None
*/
void Reset_Loop_Buff(LoopBuff *t_AimLoopBuffPtr)
{
	/*前面需要增加響應的中斷停止函式,防止Reset的瞬間觸發中斷*/
	
	t_AimLoopBuffPtr->usReadPos = t_AimLoopBuffPtr->usRecPos = 0;
}
/**
  * @brief  內部呼叫,確認快取長度是否有效
  * @note   
  * @param  *t_AimLoopBuffPtr:快取塊結構體的指標;curLength:新增快取的長度;AimLength:目標需要的長度;RecPos:接收的快取位置,IsCheckAddtionalLength:是否需要檢測超出的長度;
  * @retval RET_OK:長度正確;RET_ERR:長度錯誤
*/
__inline return_value Check_RetryCount_IsOver(LoopBuff *t_AimLoopBuffPtr,unsigned short curLength,unsigned short AimLength,unsigned short RecPos,unsigned char IsRetainAddtionalLength)
{
	/*如果新增長度 >= 目標長度 說明正常返回true*/
	if(curLength == AimLength)
		{
			t_AimLoopBuffPtr->usRetryCount = MaxReTryCount;
			return RET_OK;
		}
	else if(curLength > AimLength)
		{
			/*如果新增長度 > 目標長度 並且需要檢測額外長度*/	
		 if(IsRetainAddtionalLength != NotCheckAddtionalLength)
			{
				/*執行同步並且返回StatusErr*/
				Syn_Loop_Buff_Pos(t_AimLoopBuffPtr,RecPos);
				return RET_ERR;
			}
			t_AimLoopBuffPtr->usRetryCount = MaxReTryCount;
			return RET_OK;
		}	
	else
	{
		/*如果重試次數到了則執行同步*/
		if( --t_AimLoopBuffPtr->usRetryCount == 0 )
		{
//			printf("%d\r\n",t_AimLoopBuffPtr->usRetryCount);
			Syn_Loop_Buff_Pos(t_AimLoopBuffPtr,RecPos);
		}
//		else {printf("%d\r\n",t_AimLoopBuffPtr->usRetryCount);}
		return RET_ERR;
	}
}
/**
  * @brief  外部呼叫,讀取響應長度的
  * @note   
  * @param  *t_AimLoopBuffPtr:快取塊結構體的指標;*Buffdst:彈出資料的拷貝地址;AimLength:目標需要的長度,IsCheckAddtionalLength:是否需要檢測超出的長度;
  * @retval *Buffdst:正確的話返回拷貝地址;NULL:錯誤的話返回空指標地址
*/	
unsigned char* Takeout_Buff(LoopBuff *t_AimLoopBuffPtr,unsigned char *Buffdst,unsigned short AimLength,BuffConsType IsCheckAddtionalLength)
{
	const unsigned short constRecPos = t_AimLoopBuffPtr->usRecPos;
	int offset = constRecPos - t_AimLoopBuffPtr->usReadPos; 
	unsigned short tempoffset = {0}; 
	/*沒有新資料,或者AimLength為0*/
	if((offset == 0)||(AimLength==0))
		return NULL;
	/*offset>0,Pos正序,新增長度是 = offset*/
	else if(offset > 0)
	{	
		if(Check_RetryCount_IsOver(t_AimLoopBuffPtr,offset,AimLength,constRecPos,IsCheckAddtionalLength) != RET_OK)
			return NULL;
		/*Pos正序方式讀取*/
		/*儲存初始ReadPos*/		
		tempoffset = t_AimLoopBuffPtr->usReadPos;
		
		#if BuffMode == PreciseMode
			t_AimLoopBuffPtr->usReadPos += AimLength;
		#elif	BuffMode == RoughMode
			t_AimLoopBuffPtr->usReadPos = constRecPos;
		#endif /*BuffMode == RoughMode*/
		
		/*資料搬到dst地址所指的區域,並返回dst地址*/
		return memcpy(Buffdst,&t_AimLoopBuffPtr->ucBuff[tempoffset],AimLength);
	}
	/*offset<0,Pos倒序,新增長度 = offset+t_AimLoopBuffPtr->usBuffLength */
	else if(offset < 0)
	{		
		/*如果目標長度 > 新增長度,返回NULL,不對Buff做讀取*/
		/*
			發生這種情況的原因有:
		  1,讀取的瞬間資料片段還在傳送,解決:等待或再多呼叫幾次本函式,超過次數同步
		  2,讀取的可能是被破壞的碎片資料,解決:超過次數同步
		*/
		/*先計算出當前 這裡:offset 是負數 + 整個buff長度 = 實際新增buff長度*/
		/*返回 NULL 說明資料有問題 return NULL*/
		if (Check_RetryCount_IsOver(t_AimLoopBuffPtr,offset+t_AimLoopBuffPtr->usBuffLength,AimLength,constRecPos,IsCheckAddtionalLength) != RET_OK)
			return NULL;
		/*Pos倒序,先讀取尾部剩餘長度tempoffset*/
		tempoffset = t_AimLoopBuffPtr->usBuffLength - t_AimLoopBuffPtr->usReadPos;
		/*如果目標長度 <= 尾部剩餘長度,則按照Pos正序方式讀取*/
		if(AimLength <= tempoffset)
		{
			tempoffset = t_AimLoopBuffPtr->usReadPos;
			
			#if BuffMode == PreciseMode
				t_AimLoopBuffPtr->usReadPos += AimLength;
			#elif	BuffMode == RoughMode
				t_AimLoopBuffPtr->usReadPos = constRecPos;
			#endif /*BuffMode == RoughMode*/		
			
			return memcpy(Buffdst,&t_AimLoopBuffPtr->ucBuff[tempoffset],AimLength);
		}
		/*Pos倒序方式讀取*/
		/*1:讀取尾部剩餘*/
		memcpy(Buffdst,&t_AimLoopBuffPtr->ucBuff[t_AimLoopBuffPtr->usReadPos],tempoffset);		
		/*2::讀取頭部 目標長度 - 尾部長度 */
		memcpy(Buffdst + tempoffset,&t_AimLoopBuffPtr->ucBuff[0],AimLength - tempoffset);
		
		#if BuffMode == PreciseMode
			t_AimLoopBuffPtr->usReadPos = AimLength - tempoffset;
		#elif	BuffMode == RoughMode
			t_AimLoopBuffPtr->usReadPos = constRecPos;
		#endif /*BuffMode == RoughMode*/
		
		/*資料搬到dst地址所指的區域,並返回dst地址*/
		return Buffdst;		
	}
	return NULL;
}
/**
  * @brief  外部呼叫,接收資料
  * @note   
  * @param  *t_AimLoopBuffPtr:快取塊結構體的指標;data:接收到的每一個位元組
  * @retval 
*/
void Putin_Buff(LoopBuff *t_AimLoopBuffPtr,unsigned char data)
{	
	t_AimLoopBuffPtr->ucBuff[t_AimLoopBuffPtr->usRecPos++] = data;
	if( t_AimLoopBuffPtr->usRecPos >= t_AimLoopBuffPtr->usBuffLength )
	{
		t_AimLoopBuffPtr->usRecPos = LimitedBuffHead;
	}
}
/**
  * @brief  外部呼叫,初始化接收塊
  * @note   
  * @param  *t_AimLoopBuffPtr:快取塊結構體的指標;*ucBuffArrayPtr:塊的記憶體地址;usBuffLength:塊的長度
  * @retval RET_OK:成功;RET_ERR:失敗
*/
return_value Initializaion_Loop_Buff(LoopBuff *t_AimLoopBuffPtr,unsigned char *ucBuffArrayPtr,unsigned short usBuffLength)
{
	if((usBuffLength > MaxBuffLength)||(ucBuffArrayPtr == NULL))
		return RET_ERR;
	t_AimLoopBuffPtr->ucBuff = ucBuffArrayPtr;/*地址賦值*/
	t_AimLoopBuffPtr->usBuffLength = usBuffLength;/*長度賦值*/	
	t_AimLoopBuffPtr->usRecPos = LimitedBuffHead;
	t_AimLoopBuffPtr->usReadPos = LimitedBuffHead;
	t_AimLoopBuffPtr->usRetryCount = MaxReTryCount;
	t_AimLoopBuffPtr->ucIsReadBusy = 0;
	return RET_OK;	
}

/*receive example*/
//void USART1_IRQHandler(void)                	
//{
//	if(USART_GetITStatus(USART1,USART_IT_RXNE)== SET)
//	{
//		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
//		Putin_Buff(&uartbuff,USART_ReceiveData(USART1));
//	}
//}

/*read example*/
//void Read_Buff(void)
//{ 
//	unsigned char tempbuff[10];	
//	printf("the data is %02x",Takeout_Buff(&uartbuff,tempbuff,4));
//}
/*
*********************2018.1.23*****************************

LoopRecBuff,接收環形緩衝



****2018.1.23 V0.01****
Pos正序:表示RecPos>ReadPos 
Pos倒序:表示RecPos<ReadPos

模式區別:主要是完成讀取後ReadPos的位置選擇。

PreciseMode:ReadPos 按照 AimLength 長度偏移,常用於資料幀分段接收。
RoughMode:ReadPos 按照 RecPos 的位置偏移。此模式可能需要再修改,使得功能更加明確。

錯誤處理:
1,新增資料長度 小於 AimLength,每次Pop_Buff(),內部usRetryCount倒計數,返回NULL,
當usRetryCount計數結束,同步ReadPos和RecPos。

****2018.1.26 V0.02****
新增: enum BuffConsType;

修改:
	 Check_RetryCount_IsOver(),新增BuffConsType IsCheckAddtionalLength形參,內部相應改動,對額外長度也做檢測
	 Pop_Buff(),新增BuffConsType IsCheckAddtionalLength形參,內部相應改動,呼叫時可以選擇是否檢測額外長度

	 函式名改變:functions' names have changed
	 Pop_Buff() 改為-> Takeout_Buff()
	 Push_Buff() 改為-> Putin_Buff()

****2018.2.2 V0.03****
刪除:enum BuffStatus;

新增:
	"SYS_ENUM.h"檔案,
	Initializaion_Loop_Buff(),實現接收塊的初始化;

修改:
	啟用unsigned short usBuffLength,	
	Putin_Buff(),中長度改變,
	unsigned char   ucBuff[MaxBuffLength] 改為-> unsigned char*  ucBuff;

********************Usage********************************

  
LoopBuff *t_loopBuffPtr = NULL;
unsigned char *ucbuffaddressPtr = NULL;
unsigned short usBuffLength = "you need the size of the buff";
t_loopBuffPtr 		  = malloc(sizeof(LoopBuff));
ucbuffaddressPtr	  = malloc(usBuffLength);


if(Initializaion_Loop_Buff(t_loopBuffPtr,ucbuffaddressPtr,usBuffLength) == RET_OK)
	return "you can use this buff";
else 
	return "the initialization is failing";


******************Usage_End******************************

*/ 
#ifndef __LOOPRECBUFF_h
#define __LOOPRECBUFF_h

#include "SYS_ENUM.h"

/*******************************************************
MIT License

Copyright (c) 2018 w64228013

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*******************************************************/


#define MaxBuffLength 							256
#define MaxTempBuffLength 						128
#define MaxReTryCount  							15+1
#define LimitedBuffTail  						(MaxBuffLength - 1)
#define LimitedBuffHead   						0	

#define PreciseMode  							0
#define RoughMode		 							1
#define BuffMode  	 							PreciseMode	 

#define HAS_MALLOC								0
/************************************************************************************/
typedef struct 
{
	//unsigned char   ucBuff[MaxBuffLength];
	unsigned char*  ucBuff;								/*快取指標*/
	unsigned short  usBuffLength;						/*快取區域長度*/
	unsigned short  usRecPos;							/*接收位置*/
	unsigned short  usReadPos;							/*讀取位置*/
	unsigned short  usRetryCount;						/*資料塊重試次數*/
	unsigned char   ucIsReadBusy;						/*快取塊是否讀取繁忙,為可能的多執行緒預留位元組*/
}LoopBuff;

/*
typedef enum 
{
	StatusErr = 0,
	StatusOk = 1,
	
}BuffStatus;
*/

typedef enum 
{
	CheckAddtionalLength = 0,
	NotCheckAddtionalLength = 1,
	
}BuffConsType;

/*if you dont use malloc or others ,you should extern first*/
extern unsigned char ucBuffArray[MaxBuffLength];

extern LoopBuff uartbuff;
extern unsigned char* Takeout_Buff(LoopBuff *AimLoopBuff,unsigned char *Buffdst,unsigned short AimLength,BuffConsType IsCheckAddtionalLength);
extern void Putin_Buff(LoopBuff *AimLoopBuff,unsigned char data);
extern return_value Initializaion_Loop_Buff(LoopBuff *t_AimLoopBuffPtr,unsigned char *ucBuffArrayPtr,unsigned short usBuffLength);

#endif

/*
*********************2018.1.31*****************************
	所有程式通用的列舉變數

****2018.1.31 V0.01****

	應用檔案:LoopRecBuff,
			 DeviceManger,
*/




typedef enum return_enum
{
	RET_OK = 0,
	RET_ERR,
}return_value;
如果使用有問題或者不足的地方,望有高手能夠指點留言,感謝!