Example #1
0
File: int.c Project: djyos/djyos
//----设定中断同步-------------------------------------------------------------
//功能: 阻塞正在处理的事件的线程,直到指定的中断线的中断发生、响应并返回,然后才
//      激活线程。调用前确保该中断线被禁止,调用本函数将导致中断线被使能(是直接
//      使能,不是调用int_save_asyn_line),并在返回后恢复禁止状态。
//参数: ufl_line,等待的目标中断线
//返回: false = 该中断已经被其他线程等待,直接返回。
//      true = 成功同步,并在该中断发生后返回。
//备注: 1.中断是一种临界资源,不宜在中断函数中太多的事情,故中断同步的功能比较简
//      单,每条中断线同一时刻只能有一个线程等待,也不允许设置超时等待
//      2.秉承djyos一贯风格,中断同步函数只能把自己置入等待状态,而不能控制别的
//      线程,故函数原型不能是 bool_t int_sync(ufast_t line,uint16_t event_id)
//      3.实时中断设置等待无效,调用本函数时,如果line已经被设置为实时中断,则
//      直接返回false,如果调用本函数后,line不能被设置为实时中断。
//      4.为正确实现功能,须在调用前确保该中断线是被禁止的。
//-----------------------------------------------------------------------------
bool_t Int_AsynSignalSync(ufast_t ufl_line)
{
    if( (ufl_line > CN_INT_LINE_LAST)
            || (tg_pIntLineTable[ufl_line] == NULL) )
        return false;
    if( !Djy_QuerySch())
    {   //禁止调度,不能进入异步信号同步状态。
        Djy_SaveLastError(EN_KNL_CANT_SCHED);
        return false;
    }
    Int_SaveAsynSignal();   //在操作就绪队列期间不能发生中断
    //实时中断不能设置同步,一个中断只接受一个同步事件
    if((tg_pIntLineTable[ufl_line]->int_type == CN_REAL)
            || (tg_pIntLineTable[ufl_line]->sync_event != NULL))
    {
        Int_RestoreAsynSignal();
        return false; //实时中断或已经有同步事件
    }else
    {
        if(Int_QueryLine(ufl_line) == true)    //中断已经发生,同步条件达到
        {
            Int_ClearLine(ufl_line);
            Int_RestoreAsynSignal();
            return true;
        }
        //以下三行从就绪链表中取出running事件
        __Djy_CutReadyEvent(g_ptEventRunning);
        g_ptEventRunning->next = NULL;
        g_ptEventRunning->previous = NULL;
        g_ptEventRunning->event_status = CN_STS_WAIT_ASYN_SIGNAL;
        tg_pIntLineTable[ufl_line]->sync_event = g_ptEventRunning;
    }
    Int_EnableAsynLine(ufl_line);
    Int_RestoreAsynSignal();      //调用本函数将引发线程切换,正在处理的事件被
                                    //挂起。
    Int_DisableAsynLine(ufl_line);
    g_ptEventRunning->wakeup_from = CN_STS_WAIT_ASYN_SIGNAL;
    g_ptEventRunning->event_status = CN_STS_EVENT_READY;
    return true;
}
Example #2
0
// =============================================================================
// 功能:数据传送函数,完成数据的发送和接收。该函数完成的功能如下:
//       1.若器件驱动为了避免组包的麻烦,可先发命令再发送数据,分多次调用,多次调用前
//         后被CSActive和CsInactive函数包裹;
//       2.根据Dev查找所属SPI总线;
//       3.若缓冲区大于发送字节数,则直接将数据填入缓冲区;
//       4.若为阻塞发送,则等待总线信号量,若为非阻塞,则等待buf信号量;
//       5.发生超时或错误时,拉高CS并释放信号量
// 参数:Dev,器件指针
//       spidata,SPI数据结构体
//       block_option,阻塞选项,为true时,表明最后一次传输为阻塞方式,否则为非阻塞
//       timeout,超时参数,us
// 返回:返回发送状态,超时或错误或无错误
// =============================================================================
s32 SPI_Transfer(struct tagSPI_Device *Dev,struct tagSPI_DataFrame *spidata,
                u8 block_option,u32 timeout)
{
    struct tagSPI_CB *SPI;
//  struct semaphore_LCB *spi_semp;
    s32 result ;
    u32 written=0;
    u32 base_time = 0,rel_timeout = timeout;

    if(NULL == Dev)
        return CN_SPI_EXIT_PARAM_ERR;

    SPI = (struct tagSPI_CB *)Rsc_GetParent(&Dev->DevNode);//查找该器件属于哪条总线
    if(NULL == SPI)
        return CN_SPI_EXIT_PARAM_ERR;

    base_time = (u32)DjyGetTime();
    //若配置需自动片选,则本函数内部需拉低片选
    if(Dev->AutoCs == true)
    {
        if(false == Lock_SempPend(SPI->SPI_BusSemp,timeout))    //需要等待总线空闲
        {
            result = CN_SPI_EXIT_TIMEOUT;
            goto exit_from_bus_timeout;
        }
        __SPI_AutoCsActive(SPI,Dev);
    }

    Lock_SempPend(SPI->SPI_BlockSemp,0);                        //相当于重置信号量

    //禁止调试或未登记pTransferTxRx,使用轮询方式通信
    if((Djy_QuerySch() == false) || (SPI->pTransferTxRx == NULL)
            || (SPI->Flag & CN_SPI_FLAG_POLL))
    {
        if(SPI->pTransferPoll != NULL)
        {
            SPI->pTransferPoll(SPI->SpecificFlag,spidata->SendBuf,spidata->SendLen,
                spidata->RecvBuf,spidata->RecvLen,spidata->RecvOff);

            if(Dev->AutoCs == true)
                __SPI_AutoCsInactive(SPI,Dev->Cs);
            result = CN_SPI_EXIT_NOERR;
        }
        goto exit_from_no_err;
    }

    if(spidata->RecvLen)
        block_option = true;                            //接收数据自动转为阻塞
    SPI->SPI_Buf.Offset = 0;                            //发送前先清空缓冲区
    SPI->Frame = *spidata;
    SPI->BlockOption = block_option;

    //如果非阻塞方式,且缓冲区够大,则直接写入缓冲区
    //若不是,则先发送调用者提供的缓冲区,直到剩余字节数能够填充到缓冲区
    if((!block_option) && (spidata->SendLen <= SPI->SPI_Buf.MaxLen))
    {
        memcpy(SPI->SPI_Buf.pBuf,spidata->SendBuf,spidata->SendLen);
        written = spidata->SendLen;
    }

    //调用启动时序的回调函数
    if(true == SPI->pTransferTxRx(SPI->SpecificFlag,
                                spidata->SendLen,
                                spidata->RecvLen,
                                spidata->RecvOff
                                ))
    {
        rel_timeout = (u32)DjyGetTime();
        if(rel_timeout - base_time < timeout)
            rel_timeout = timeout - (rel_timeout - base_time);
        else
        {
            result = CN_SPI_EXIT_TIMEOUT;
            goto exit_from_timeout;
        }

        //需要等待的情况:1.阻塞发送;2.数据未全部填到缓冲区
        if((true == block_option) || (written < spidata->SendLen))
        {
            //等待中断函数释放信号量
            if(!Lock_SempPend(SPI->SPI_BlockSemp,rel_timeout))
            {
                result = CN_SPI_EXIT_TIMEOUT;
                goto exit_from_timeout;
            }
        }

        result = CN_SPI_EXIT_NOERR;
        goto exit_from_no_err;
    }else
    {
        result = CN_SPI_EXIT_UNKNOW_ERR;
        goto exit_from_timeout;
    }

exit_from_timeout:
    if(Dev->AutoCs == true)                     //自动片选时,返回前需拉低片选
    {
        __SPI_AutoCsInactive(SPI,Dev->Cs);
    }
exit_from_bus_timeout:
exit_from_no_err:
    return result;
}