在使用信号量时,一个线程release一个线程take,在某些特定时候,take线程永远不执行了,release线程确认一直有释放,sem下面的Value一直在增加,
详细追踪,发现在take的某个时候,sem信号量下的semxx->parent.suspend_thread->next的值发生了改变,本来应该指向take线程的地址,变成了指向release线程地址,导致sem下的supend_thread列表在release时恢复take线程.
代码如下
#include "outunit.h"
#include "app.h"
#include "uhp.h"
//ALIGN(RT_ALIGN_SIZE)
#define OUTUNIT_UART_NAME "uart2"
#define PARSE_DATA_HEAD 0
#define PARSE_DATA_BODY 1
#define PARSE_DATA_TAIL 2
#define PARSE_DATA_CHECK 3
#define DATA_LEN 19
rt_uint8_t frame_buf[20];
rt_uint8_t state = 0;
rt_uint8_t frame_buf_offset = 0;
rt_uint8_t outUnitConnectErr;
rt_uint8_t *shiyuan_setHandler;
typedef struct _shiyuan_format{
uint8_t head;
uint8_t addr;
uint8_t func
tion;
uint8_t len;
uint8_t data[13];
uint8_t tail;
uint8_t verify;
}shiyuan_format, *shiyuan_format_t;
struct rx_msg{
rt_device_t dev; // 设备句柄
rt_size_t receiveSize; // 接收数据尺寸
};
const char *uart_name; // 设备名字
struct rt_semaphore outUnitTxSem; //发送信号量
struct rt_messagequeue outUnitRxMq; // 消息队列
rt_device_t outUnitdev;
typedef struct {
SHIYUAN_OUTINFO sy_data;
SHIYUAN_OUTSET sy_set;
} OUT_UNIT;
OUT_UNIT outUnit;
/*
* 函数名称: SUM_Check()
*/
rt_uint8_t SUM_Check(rt_uint8_t *buf, rt_uint8_t len)
{
rt_uint8_t temp_result = 0, cnt = 0;
for (cnt = 0; cnt < len; cnt++)
{
temp_result += buf[cnt];
}
temp_result = ~temp_result;
return temp_result;
}
// 发送编码
static void OutUnit_ReplyCode(rt_uint8_t *tx_buf , rt_uint8_t com_len )
{
rt_device_write(outUnitdev,0, tx_buf, com_len);
}
void shiyuan_send(void )
{
static shiyuan_format sy_dev;
sy_dev.head = 0xAA;
sy_dev.addr =frame_buf[1];
sy_dev.len =13;
sy_dev.function =frame_buf[2]+0x30;
switch(frame_buf[2])
{
case 0x11:
rt_memcpy(sy_dev.data, (uint8_t*)&outUnit.sy_set.curIndoorMode,sy_dev.len); // 如果是41信息回复
sy_dev.data[sy_dev.len-1]= 0x06; // 湿度设置 50 // 最后一个字节是设置湿度
break;
case 0x12:
rt_memcpy(sy_dev.data,(uint8_t*)&outUnit.sy_set.curIndoorMode,sy_dev.len);
break;
case 0x13:
case 0x14:
rt_memset((uint8_t*)sy_dev.data,0,sy_dev.len);
break;
}
sy_dev.tail =0xBB;
sy_dev.verify = SUM_Check(&sy_dev.addr, DATA_LEN- 2);
OutUnit_ReplyCode((uint8_t*)&sy_dev.head,DATA_LEN); // 发送数据
}
//发送处理线程
static void OutUnit_TxThreadEntry(void *parameter)
{
(void ) *parameter;
while(1)
{
if( RT_EOK == rt_sem_take(&outUnitTxSem,RT_WAITING_FOREVER))// 等待信号量释放
{
shiyuan_send();
}
else
{
rt_kprintf("out tx sem take Error!\n");
}
}
}
/********************************************************************************/
// 接收回调函数
rt_err_t OutUnit_ReceiveCb(rt_device_t dev, rt_size_t size)
{
rt_err_t ret =0;
struct rx_msg msg;
msg.dev = dev;
msg.receiveSize = size>DATA_LEN ? DATA_LEN : size;
ret = rt_mq_send(&outUnitRxMq,&msg, sizeof(struct rx_msg)); //发送消息队列
return ret;
}
// 字节解析
static void OutUnit_ReceiveDecodeChar(rt_uint8_t ch )
{
rt_uint8_t *temp_ptr = 0;
switch(state)
{
case PARSE_DATA_HEAD:
if (frame_buf_offset ==0)// 刚解析第一个
{
if(ch == 0xAA)
{
frame_buf[0] = ch;
frame_buf_offset =1;
}
}
else if(frame_buf_offset == 1) // 解析第二个
{
if (ch ==0x01)
{
frame_buf[1] = ch;
frame_buf_offset =2;
}
}
else if (frame_buf_offset ==2) // 第三字节
{
if ((ch<=0x14)&&(ch>=0x11))
{
frame_buf[2] = ch;
frame_buf_offset =3;
}
}
else if (frame_buf_offset ==3) // 第三字节
{
if (ch==13)
{
frame_buf[3] = ch;
frame_buf_offset =4;
state = PARSE_DATA_BODY;
}
}
else
{
frame_buf_offset =0;
state = PARSE_DATA_HEAD;
}
break;
case PARSE_DATA_BODY:
frame_buf[frame_buf_offset] =ch; // 存储每个数据
frame_buf_offset++;
if (frame_buf_offset > DATA_LEN-3)
{
state = PARSE_DATA_TAIL;
}
break;
case PARSE_DATA_TAIL:
if (ch == 0xBB)
{
frame_buf[frame_buf_offset++]=ch;
state = PARSE_DATA_CHECK;
}
break;
case PARSE_DATA_CHECK:
if (SUM_Check(&frame_buf[1], DATA_LEN- 2) ==ch)
{
timeCnt.oduConnectCnt=0;
frame_buf[frame_buf_offset]=ch;
if (frame_buf[2]== 0x11)
temp_ptr = &outUnit.sy_data.r0x11_curOutRunMode;
else if (frame_buf[2]== 0x12)
temp_ptr = &outUnit.sy_data.r0x12_acCurrent_H;
else if (frame_buf[2]== 0x13)
temp_ptr = &outUnit.sy_data.r0x13_codeIndex_HH;
else if (frame_buf[2]== 0x14)
temp_ptr = &outUnit.sy_data.r0x14_ctrlIndoorEnable1;
rt_memcpy(temp_ptr,(rt_uint8_t*)(frame_buf +4),DATA_LEN- 6);
rt_sem_release(&outUnitTxSem); // 释放一个发送信号量 ,怀疑释
}
frame_buf_offset=0;
state = PARSE_DATA_HEAD;
break;
}
}
#endif /* 1 */
//接收处理线程
static void OutUnit_RxThreadEntry(void *parameter)
{
struct rx_msg msg;
rt_size_t len=0;
rt_uint8_t rx_buf[RT_SERIAL_RB_BUFSZ ]={0};
(void ) *parameter;
while(1)
{
rt_memset(&msg, 0, sizeof(msg));
if ( RT_EOK == rt_mq_recv(&outUnitRxMq, &msg, sizeof(msg), RT_WAITING_FOREVER)) //获取 消息队列 移植等待
{
len = rt_device_read(msg.dev,0, &rx_buf,msg.receiveSize); //
for(uint8_t cnt=0; cnt< len ;cnt++)
{
OutUnit_ReceiveDecodeChar(rx_buf[cnt]);
}
}
}
}
// 初始化函数
static int OutUnit_Init(void)
{
static char msg_pool[256];
rt_memset(&outUnit.sy_data,0,sizeof(SHIYUAN_OUTINFO));
rt_memset(&outUnit.sy_set,0,sizeof(SHIYUAN_OUTSET));
rt_sem_init(&outUnitTxSem,"outtx",0,RT_IPC_FLAG_FIFO); // 创建发送信号量
rt_mq_init(&outUnitRxMq,"outrx",msg_pool,sizeof(struct rx_msg),sizeof(msg_pool),RT_IPC_FLAG_FIFO); //
uart_name = OUTUNIT_UART_NAME ;
static struct serial_configure cfg = {
.baud_rate = 600,
.data_bits = DATA_BITS_8,
.stop_bits = STOP_BITS_2,
.bit_order=BIT_ORDER_LSB,
.bufsz = 256,
.parity = PARITY_EVEN, // 偶校验
};
outUnitdev = rt_device_find(uart_name);// 获取设备
if (outUnitdev != RT_NULL)
rt_device_control(outUnitdev,RT_DEVICE_CTRL_CONFIG,&cfg); // 初始化串口
rt_device_open(outUnitdev,RT_DEVICE_FLAG_DMA_RX|RT_DEVICE_FLAG_DMA_TX); // DMA读写打开
rt_device_set_rx_indicate(outUnitdev, OutUnit_ReceiveCb); // 设置接收回到函数
rt_thread_t rx_thread = rt_thread_create("rx", OutUnit_RxThreadEntry, RT_NULL, 1024, 12, 10);
RT_ASSERT(rx_thread != RT_NULL);
rt_thread_startup(rx_thread);
rt_thread_t tx_thread = rt_thread_create("tx", OutUnit_TxThreadEntry, RT_NULL, 1024, 9,20);
RT_ASSERT(tx_thread != RT_NULL);
rt_thread_startup(tx_thread);
return 0;
}
INIT_APP_EXPORT(OutUnit_Init);
/***************************************************************************************/
// 读数据
void* OutUnit_GetOutUnitData(void)
{
return (SHIYUAN_OUTINFO*)&outUnit.sy_data;
}
// 写入更新数据
int OutUnit_WriteOutUnitData(rt_uint8_t *rData , rt_uint16_t offset, rt_uint16_t num)
{
if(offset +num >sizeof(SHIYUAN_OUTSET)) //超出范围
return -1;
rt_memcpy((rt_uint8_t*)(&outUnit.sy_set.curIndoorMode+offset), rData , num);
return num;
}