qnx中断处理

790 阅读2分钟

本文大多内容来自这位大佬,写博客只是为了做笔记 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;
}