本文大多内容来自这位大佬,写博客只是为了做笔记 QNX中以pulse方式处理中断
首先,在中断处理线程中,先要获取io权限:
ThreadCtl(_NTO_TCTL_IO, 0)
其次,创建私有channel,并得到一个connection id: 然后,初始化sigevent,将coid与sigevent绑定,中断产生执行中断处理函数返回sigevent时内核就会在对应的channel产生一个pulse,通过解析coid执行不同的处理
chid = ChannelCreate(0);
coid = ConnectAttach(ND_LOCAL_NODE, 0, chid, _NTO_SIDE_CHANNEL, 0);
在QNX中提供了三个不同的绑定函数,用来绑定coid与sigevent
SIGEV_PULSE_INIT( &event, coid, priority , code, value );
// store the value in sigev_value.sival_ptr
SIGEV_PULSE_INT_INIT( &event, coid, priority , code, value );
// (QNX Neutrino 7.0 or later) Store the value in sigev_value.sival_int and
// set the hidden SIGEV_FLAG_SIVAL_INT bit in sigev_notify
SIGEV_PULSE_PTR_INIT( &event, coid, priority , code, value );
// (QNX Neutrino 7.0 or later) Store the value in sigev_value.sival_ptr
- event:sigevent结构体变量
- coid:通过ConnectAttach()获取
- priority是优先级,可通过SIGEV_PULSE_PRIO_INHERIT宏来获取继承的优先级或自己来设定
- code就是pulse的类型,可自行设定,可以直接在函数设定,也可以在中断服务函数中设定
- value值一般为0
将中断号与中断服务函数进行绑定
InterruptAttach(intr, handler, area, size, flags);
- intr:中断号
- hander:中断服务函数,原型为
const struct sigevent *handler(void *arg, int32_t id);
- area:传递给handler的参数
- size:传递参数的大小
- flags一般设置为:_NTO_INTR_FLAGS_TRK_MSK。
最后,线程一直调用MsgReceive()等待pulse就行了,对pulse解析处理。
const struct sigevent *handler(void *arg,int32_t id)
{
//关闭中断
InterruptMask(irq_num, id);
//do your work
event.sigev_value.sival_ptr = xxx; // pulse中可以接收的数据
event.sigev_code = XXX; // pulse的code
InterruptUnmask(irq_num,id);
return (&intrevent)
}
//中断服务线程
void *irqs(void *arg)
{
int32_t chid, coid;
int32_t rcvid;
//获取IO权限
ThreadCtl(_NTO_TCTL_IO, 0);
chid = ChannelCreate(0);
coid = ConnectAttach(ND_LOCAL_NODE, 0, chid, _NTO_SIDE_CHANNEL, 0);
intId = InterruptAttach(irq,
handler,
(void *)(arg),
sizeof(arg),
_NTO_INTR_FLAGS_TRK_MSK);
while (1) {
static struct _pulse pulse = { 0 };
rcvid = MsgReceive(chid, &pulse, sizeof(pulse), NULL);
if (rcvid == 0) {
int8_t code_data = pulse.code;
data = pulse.value.sival_ptr; // 注意类型转换
// do your work
}
}
}
一个具体例子:
#define PULSE_PRIORITY 21
#define PULSE_CODE _PULSE_CODE_MINAVAIL
typedef struct dev {
int coid;
int chid;
pthread_t irq_thread;
unsigned thread_priority;
unsigned intr;
int id;
struct sigevent intrevent;
} dev;
#pragma pack()
static const struct sigevent *tp_intr(void *area, int id)
{
dev_t *dev = area;
return &dev->intrevent;
}
int intr_attach(dev *dev)
{
SIGEV_PULSE_INIT(&dev->intrevent, dev->coid, PULSE_PRIORITY, APULSE_CODE, 0);
dev->id = InterruptAttach(dev->intr, intr, dev, sizeof(*dev), _NTO_INTR_FLAGS_TRK_MSK | _NTO_INTR_FLAGS_PROCESS);
if(dev->id == -1)
{
error("InterruptAttach: %s", strerror(errno));
goto fai;
}
return 0;
fai:
return -1;
}
static void *rq_thread(void *arg)
{
int rcvid;
int err;
struct _pulse pulse;
struct dev *dev = (struct dev *)arg;
while (1)
{
rcvid = MsgReceive(dev->chid, &pulse, sizeof(pulse), NULL);
if (rcvid < 0)
{
if ((EINTR == errno) || (ETIMEDOUT == errno))
{
continue;
}
break;
}
else if (rcvid == 0)
{
if (pulse.code == PULSE_CODE)
{
//do your work
irq_process();
}
}
}
err = InterruptDetach(dev->id)
if (err == -1)
{
LOGERR("InterrupDetach: %s", strerror(errno));
return -1;
}
dev->id = 0;
return NULL;
}
int irq_init(dev *dev, uint32_t gpio_number)
{
int ret = -1;
if (dev == NULL)
{
LOGERR("dev is NULL");
return -1;
}
if (-1 == ThreadCtl(_NTO_TCTL_IO, 0))
{
LOGERR("Failed to get IO privileges!");
goto failChannelCreate;
}
// irq_gpio_init(dev, gpio_number);
if (dev->intr <= 0)
{
LOGERR("Failed to register interrupt");
goto failChannelCreate;
}
/* Connect to device */
dev->chid = ChannelCreate(0);
if (dev->chid == -1)
{
LOGERR("ChannelCreate: %s", strerror(errno));
goto failChannelCreate;
}
dev->coid = ConnectAttach(0, 0, dev->chid, _NTO_SIDE_CHANNEL, 0);
if (dev->coid == -1)
{
LOGERR("ConnectAttach: %s", strerror(errno));
goto failConnectAttach;
}
if (intr_attach(dev) != 0)
{
LOGERR("irq fail");
goto failConnectAttach;
}
ret = pthread_create(&dev->irq_thread, NULL, irq_thread, dev);
if (EOK != ret)
{
LOGERR("Failed to create the intr thread (%s - %i)", strerror(errno), ret);
goto failCreateThread;
}
pthread_setname_np(dev->irq_thread, "irq");
return 0;
failCreateThread:
failConnectAttach:
ConnectDetach(dev->chid);
dev->chid = -1;
failChannelCreate:
return -1;
}