Пример #1
0
void Serial_writeByte(uint8_t data)
{
    CRITICAL_VAL();

    CRITICAL_ENTER();

    if(     (UCSR0A & (1U << UDRE0)) &&
            Queue_empty(&TxBuff))
    {
        UDR0 = data;
    }
    else
    {
        UCSR0B |= (1U << UDRIE0);
        while(!Queue_write(&TxBuff, &data))
        {
            CRITICAL_EXIT();

            WAIT_INT();

            CRITICAL_ENTER();
        }
    }

    CRITICAL_EXIT();
}
Пример #2
0
/** Send start condition in the bus and receive (read) up to 'length' bytes in
 'buff' from the device of address 'addr'. The value pointed by 'numread' holds
 the actual number of bytes received. The function returns immediately after
 starting the communication. To test if the communication has finished use the
 function I2c_getStatus(). A stop condition is not sent by this function. */
void I2c_read(uint8_t addr, uint8_t *buff, uint8_t length, uint8_t *numread)
{
    CRITICAL_VAL();
    CRITICAL_ENTER();
    {
        if(RxTxBuffer.status == IDLE)
        {
            RxTxBuffer.status = STA_SLAR;
            CRITICAL_EXIT();

            *numread = 0U;

            RxTxBuffer.addr = (addr << 1U) | 1U;
            RxTxBuffer.rxbuff = buff;
            RxTxBuffer.length = length;
            RxTxBuffer.num = numread;

            TWCR = I2C_TWCR_SEND_STA; /* Send STA. */
        }
        else
        {
            CRITICAL_EXIT();
        }
    }
}
Пример #3
0
/*
void egl_delete_object( EGL_HANDLE handle )
{
  egl_sendmsg(handle,EGL_MSG_DELETE);
}
*/
void egl_object_set_redraw(EGL_HANDLE handle)
{
	EGL_OBJECT_PTR pObj = ( EGL_OBJECT_PTR )handle;
	CRITICAL_ENTER();
	pObj->bNeedRedraw=TRUE;
	CRITICAL_EXIT();
}
Пример #4
0
/**
 * 功能: 队列注册的定时器的回调函数,给到期的任务返回EASYRTOS_TIMEOUT的标志.
 * 将到期的任务移除队列悬挂列表,并加入Ready列表.
 *
 * 参数:
 * 输入:                                                输出:
 * POINTER cb_data 回调函数数据包含需要唤醒的TCB等信息   POINTER cb_data 回调函数数据包含需要唤醒的TCB等信息                              
 * 
 * 返回:void
 * 
 * 调用的函数:
 * (void)tcb_dequeue_entry (timer_data_ptr->suspQ, timer_data_ptr->tcb_ptr);
 * (void)tcbEnqueuePriority (&tcb_readyQ, timer_data_ptr->tcb_ptr);
 */
static void eQueueTimerCallback (POINTER cb_data)
{
    QUEUE_TIMER *timer_data_ptr;
    CRITICAL_STORE;

    /* 获取队列定时器回调指针 */
    timer_data_ptr = (QUEUE_TIMER *)cb_data;

    /* 检测参数是否为空 */
    if (timer_data_ptr)
    {
        /* 进入临界区  */
        CRITICAL_ENTER ();

        /* 给任务设置标志位,标识任务是因为定时器回调唤醒的 */
        timer_data_ptr->tcb_ptr->pendedWakeStatus = EASYRTOS_TIMEOUT;

        /* 取消定时器注册 */
        timer_data_ptr->tcb_ptr->pended_timo_cb = NULL;

        /* 将任务移除悬挂列表,将任务移出receive或者send列表 */
        (void)tcb_dequeue_entry (timer_data_ptr->suspQ, timer_data_ptr->tcb_ptr);

        /* 将任务加入Ready队列 */
        if (tcbEnqueuePriority (&tcb_readyQ, timer_data_ptr->tcb_ptr) == EASYRTOS_OK)
        {
          timer_data_ptr->tcb_ptr->state= TASK_READY;
        }

        /* 退出临界区 */
        CRITICAL_EXIT ();
    }
}
Пример #5
0
/**
 * 功能: 信号量注册的定时器的回调函数,给到期的任务返回EASYRTOS_TIMEOUT的标志.
 * 将到期的任务移除队列悬挂列表,并加入Ready列表.
 *
 * 参数:
 * 输入:                                                输出:
 * POINTER cb_data 回调函数数据包含需要唤醒的TCB等信息   POINTER cb_data 回调函数数据包含需要唤醒的TCB等信息                              
 * 
 * 返回:void
 * 
 * 调用的函数:
 * (void)tcb_dequeue_entry (timer_data_ptr->suspQ, timer_data_ptr->tcb_ptr);
 * (void)tcbEnqueuePriority (&tcb_readyQ, timer_data_ptr->tcb_ptr);
 */
static void eSemTimerCallback (POINTER cb_data)
{
    SEM_TIMER *timer_data_ptr;
    CRITICAL_STORE;

    /* 获取SEM_TIMER结构指针 */
    timer_data_ptr = (SEM_TIMER *)cb_data;

    /* 检查参数是否为空 */
    if (timer_data_ptr)
    {
      /* 进入临界区 */
      CRITICAL_ENTER ();

      /* 设置标志,表明任务是由于timeout到期而唤醒的  */
      timer_data_ptr->tcb_ptr->pendedWakeStatus = EASYRTOS_TIMEOUT ;

      /* 解除timeout定时器注册 */
      timer_data_ptr->tcb_ptr->pended_timo_cb = NULL;

      /* 将任务移除信号量悬挂队列 */
      (void)tcb_dequeue_entry (&timer_data_ptr->sem_ptr->suspQ, timer_data_ptr->tcb_ptr);

      /* 将任务加入Ready队列 */
      if (tcbEnqueuePriority (&tcb_readyQ, timer_data_ptr->tcb_ptr) == EASYRTOS_OK)
      {
        timer_data_ptr->tcb_ptr->state = TASK_READY;
      }
      /* 退出临界区 */
      CRITICAL_EXIT ();

      /* 这里没有启动调度器,因为之后在退出timer ISR的时候会通过atomIntExit()启动 */
    }
}
Пример #6
0
/** Return the number of counts the timer had.

 Note: This function may return an outdated value if interrupts are disabled. */
uint32_t timerCounts(void)
{
    /* There is no reliable way to know if the timer has overflowed.
     The register TAIV shows only the highest priority pending interrupt, so if
     there is an overflow and a capture interrupt pending we may get an
     inconsistent TimerIntCount. */

    uint32_t timerIntCount;
    uint16_t timerCount;
    CRITICAL_VAL();

    CRITICAL_ENTER();
    {
        timerIntCount = TimerIntCount;

        #if 1
        {
            /* Capture disabled */
            timerCount = TAR;
            if(TACTL & TAIFG)
                timerCount = 65535U;
        }
        #else
        {
            /* Capture enabled - lose precision for consistency */
            timerCount = 0U;
        }
        #endif
    }
    CRITICAL_EXIT();

    return (timerIntCount * 65536U + timerCount);
}
Пример #7
0
void egl_scroll_set_position( EGL_HANDLE hObj, int totalcount, int viewcount, int precount )
{
    EGL_OBJECT_PTR pObj = ( EGL_OBJECT_PTR )hObj;
    SCBAR_DATA* scbardata = ( SCBAR_DATA* )pObj->selfdata;
    scbardata->m_totalcount = totalcount;
    scbardata->m_viewcount = viewcount;
    scbardata->m_upcount = precount;
    if( scbardata->m_bVerticalMode )
    {
        scbardata->m_thumb_box_h = viewcount * scbardata->m_center_box_h / totalcount;
        scbardata->m_pos = precount * scbardata->m_center_box_h / totalcount;
        if( scbardata->m_pos + scbardata->m_thumb_box_h > scbardata->m_center_box_h || totalcount == precount + viewcount )
        {
            scbardata->m_pos = scbardata->m_center_box_h - scbardata->m_thumb_box_h;
        }
    }
    else
    {
        scbardata->m_thumb_box_w = viewcount * scbardata->m_center_box_w / totalcount;
        scbardata->m_pos = precount * scbardata->m_center_box_w / totalcount;
        if( scbardata->m_pos + scbardata->m_thumb_box_w > scbardata->m_center_box_w || totalcount == precount + viewcount )
        {
            scbardata->m_pos = scbardata->m_center_box_w - scbardata->m_thumb_box_w;
        }
    }
	CRITICAL_ENTER();
    pObj->bNeedRedraw = TRUE;
	CRITICAL_EXIT();
}
Пример #8
0
/** Send start condition in the bus and send (write) up to 'length' bytes from
 'buff' to the device of address 'addr'. The value pointed by 'numsent' holds
 the actual number of bytes sent. The function returns immediately after
 starting the communication. To test if the communication has finished use the
 function I2c_getStatus(). A stop condition is not sent by this function. */
void I2c_write(uint8_t addr, const uint8_t *buff, uint8_t length, uint8_t *numsent)
{
    CRITICAL_VAL();
    CRITICAL_ENTER();
    {
        if(RxTxBuffer.status == IDLE)
        {
            RxTxBuffer.status = STA_SLAW;
            CRITICAL_EXIT();

            *numsent = 0U;

            RxTxBuffer.addr = (addr << 1U);
            RxTxBuffer.txbuff = buff;
            RxTxBuffer.length = length;
            RxTxBuffer.num = numsent;

            TWCR = I2C_TWCR_SEND_STA; /* Send STA. */
        }
        else
        {
            CRITICAL_EXIT();
        }
    }
}
Пример #9
0
BOOL egl_image_button_callback( EGL_HANDLE hObj, EVENT_CALLBACK cb )
{
    EGL_OBJECT_PTR pObj = ( EGL_OBJECT_PTR )hObj;
    CRITICAL_ENTER();
    pObj->cb = cb;
    CRITICAL_EXIT();
    return TRUE;
}
Пример #10
0
void egl_label_set_color(EGL_HANDLE h, EGL_COLOR clr)
{
	EGL_OBJECT_PTR pObj=EGL_HANDLE_TO_OBJECT(h);
	LABEL_DATA* label = (LABEL_DATA*)pObj->selfdata;
	CRITICAL_ENTER();
	label->font_clr = clr;
	CRITICAL_EXIT();
}
Пример #11
0
void egl_checkbutton_set_check( EGL_HANDLE hObj, BOOL b )
{
	EGL_OBJECT_PTR pObj = ( EGL_OBJECT_PTR )hObj;
	CHECK_DATA* checkdata = ( CHECK_DATA* )pObj->selfdata;
	checkdata->m_bChecked = b;
	CRITICAL_ENTER();
	pObj->bNeedRedraw = TRUE;
	CRITICAL_EXIT();
}
Пример #12
0
void egl_checkbutton_set_style( EGL_HANDLE hObj, int style )
{
	EGL_OBJECT_PTR pObj = ( EGL_OBJECT_PTR )hObj;
	CHECK_DATA* checkdata = ( CHECK_DATA* )pObj->selfdata;
	checkdata->m_style = style;
	CRITICAL_ENTER();
	pObj->bNeedRedraw = TRUE;
	CRITICAL_EXIT();
}
Пример #13
0
void egl_show_object( EGL_HANDLE h, BOOL bShow )
{
    EGL_OBJECT_PTR pObj = ( EGL_OBJECT_PTR )h;
    if( pObj == NULL )
        return ;
    if(bShow==FALSE && pObj->bVisible==TRUE && pObj->parentWin==(EGL_WINDOW_PTR)egl_window_get_active())
	{
		egl_window_invalidate_rect(&pObj->rect);
		CRITICAL_ENTER();
	}
	else
	{
		CRITICAL_ENTER();
		pObj->bNeedRedraw = TRUE;
	}
	pObj->bVisible = bShow;
	CRITICAL_EXIT();
}
Пример #14
0
void egl_scroll_set_bgcolor( EGL_HANDLE hObj, unsigned char r, unsigned char g, unsigned char b )
{
    EGL_OBJECT_PTR pObj = ( EGL_OBJECT_PTR )hObj;
    SCBAR_DATA* scbardata = ( SCBAR_DATA* )pObj->selfdata;
    scbardata->m_bg_color = MAKE_COLORREF( r, g, b );
	CRITICAL_ENTER();
    pObj->bNeedRedraw = TRUE;
	CRITICAL_EXIT();
}
Пример #15
0
EGL_FONT* egl_set_font(EGL_HANDLE h,EGL_FONT* font)
{
	EGL_FONT* old;
	EGL_OBJECT_PTR pObj = EGL_HANDLE_TO_OBJECT(h);
	CRITICAL_ENTER();
	old =pObj->pFont;
	pObj->pFont=font;
	CRITICAL_EXIT();
	return old;
}
Пример #16
0
/** Add counts to timer counter variable.

 This function allows to update the timer count for the time the microcontroller
 has been sleeping. This way the application will know time has passed if it
 should do something in the meantime.

  void enter_sleep_mode_and_update_time(void) {
    hw_sleep();
    after_wakeup();
    timerAddSleepedCounts(TIMER_MS_TO_COUNT(1000));
  }
 */
void timerAddSleepedCounts(uint32_t counts)
{
    CRITICAL_VAL();

    CRITICAL_ENTER();
    {
        TimerIntCount += counts / 256UL;
    }
    CRITICAL_EXIT();
}
Пример #17
0
void egl_scroll_get_position( EGL_HANDLE hObj, int* totalcount, int* viewcount, int* upcount )
{
    EGL_OBJECT_PTR pObj = ( EGL_OBJECT_PTR )hObj;
    SCBAR_DATA* scbardata = ( SCBAR_DATA* )pObj->selfdata;
	CRITICAL_ENTER();
    *totalcount = scbardata->m_totalcount;
    *viewcount = scbardata -> m_viewcount;
    *upcount = scbardata->m_upcount;
	CRITICAL_EXIT();
}
Пример #18
0
/** Return the number of counts the timer had.

 Note: This function may return an outdated value if interrupts are disabled. */
uint32_t timerCounts(void)
{
    uint32_t timerIntCount;
    uint8_t timerCount;
    CRITICAL_VAL();

    CRITICAL_ENTER();
    {
        timerIntCount = TimerIntCount;
        timerCount = TCNT0;
        if(TIFR0 & (1U << TOV0))
            timerCount = 255U;
    }
    CRITICAL_EXIT();
    return (timerIntCount * 256UL + timerCount);
}
Пример #19
0
BOOL egl_label_set_text(EGL_HANDLE h,char* text)
{
	EGL_OBJECT_PTR pObj=EGL_HANDLE_TO_OBJECT(h);
	LABEL_DATA* label = (LABEL_DATA*)pObj->selfdata;
	CRITICAL_ENTER();
	if(label->str)
		free(label->str);
	label->str=(char*)strdup(text);
	if(label->str==NULL)
	{
		CRITICAL_EXIT();
		return FALSE;
	}
	pObj->bNeedRedraw=TRUE;
	CRITICAL_EXIT();
	return TRUE;
}
Пример #20
0
/**
 * 功能: 设置计数信号量的Count
 *
 * 参数:
 * 输入:                                        输出:
 * EASYRTOS_SEM *sem 信号量指针                 EASYRTOS_SEM *sem 信号量指针
 * uint8_t count设置的Count数               
 * 
 * 返回:
 * 返回 EASYRTOS_OK 成功
 * 返回 EASYRTOS_ERR_PARAM 错误的参数
 * 
 * 调用的函数:
 * 无
 */
ERESULT eSemResetCount (EASYRTOS_SEM *sem, uint8_t count)
{
  ERESULT status;
  CRITICAL_STORE;
  EASYRTOS_TCB *tcb_ptr;
  

  
  /* 参数检查 */
  if (sem == NULL || sem->type != SEM_COUNTY)
  {
    status = EASYRTOS_ERR_PARAM;
  }
  else
  {
    if (sem->suspQ && sem->count == 0)
    {
      /* 进入临界区 */
      CRITICAL_ENTER ();
      tcb_ptr = tcb_dequeue_head (&sem->suspQ);
      if (tcbEnqueuePriority (&tcb_readyQ, tcb_ptr) != EASYRTOS_OK)
      {
        
        /* 若加入Ready列表失败,退出临界区 */
        CRITICAL_EXIT ();

        status = EASYRTOS_ERR_QUEUE;
      }
      else
        CRITICAL_EXIT ();
    }
    
    /* 设置count值 */
    sem->count = count;

    /* 成功 */
    status = EASYRTOS_OK;
  }
  return (status);  
}
Пример #21
0
void egl_scroll_set_size( EGL_HANDLE hObj, int w, int h )
{
    EGL_OBJECT_PTR scbar = ( EGL_OBJECT_PTR )hObj;
    SCBAR_DATA* scbardata = ( SCBAR_DATA* )scbar->selfdata;
    scbar->rect.w = w;
    scbar->rect.h = h;
    if( scbardata->m_bVerticalMode )
    {
        scbardata->m_left_box_h = scbar->rect.w;
        scbardata->m_left_box_w = scbar->rect.w;
        scbardata->m_right_box_h = scbar->rect.w;
        scbardata->m_right_box_w = scbar->rect.w;
        scbardata->m_center_box_h = scbar->rect.h  - scbardata->m_left_box_h * 2;
        scbardata->m_thumb_box_x = scbar->rect.x + 1;
        scbardata->m_thumb_box_y = scbar->rect.y + scbardata->m_left_box_h;
        scbardata->m_thumb_box_h = scbardata->m_center_box_h / scbardata->m_totalcount * scbardata->m_viewcount;
        scbardata->m_thumb_box_w = scbar->rect.w - 2;
        scbardata->m_maxpos = h - scbardata->m_left_box_h * 2 - scbardata->m_thumb_box_h;
    }
    else
    {
        scbardata->m_left_box_h = scbar->rect.h;
        scbardata->m_left_box_w = scbar->rect.h;
        scbardata->m_right_box_h = scbar->rect.h;
        scbardata->m_right_box_w = scbar->rect.h;
        scbardata->m_center_box_w = scbar->rect.w - scbardata->m_left_box_w * 2;
        scbardata->m_thumb_box_x = scbar->rect.x + scbardata->m_left_box_w;
        scbardata->m_thumb_box_y = scbar->rect.y + 1;
        scbardata->m_thumb_box_w = scbardata->m_center_box_w / scbardata->m_totalcount * scbardata->m_viewcount;
        scbardata->m_thumb_box_h = scbar->rect.h - 2;
        scbardata->m_maxpos = w - scbardata->m_left_box_w * 2 - scbardata->m_thumb_box_w;
    }
    scbar->selfdata = scbardata;
	CRITICAL_ENTER();
    scbar->bNeedRedraw = TRUE;
	CRITICAL_EXIT();
}
Пример #22
0
/**
 * 功能: 取出队列中的数据,若对队列为空,根据timeout的不同值有不同的处理方式.
 * 1.timeout>0 悬挂调用的任务,当timeout到期的时候唤醒任务并返回timeout标志
 * 2.timeout=0 永久悬挂调用的任务,直到从队列中等到数据.
 * 3.timeout=-1 不悬挂任务,若队列为空会返回队列为空标志.
 * 当有任务被悬挂的时候,将会调用调度器.
 *
 * 参数:
 * 输入:                                        输出:
 * EASYRTOS_QUEUE *qptr 队列指针                EASYRTOS_QUEUE *qptr 队列指针
 * int32_t timeout timeout时间,依赖于心跳时间   void *msgptr 放入队列的消息
 * void *msgptr 放入队列的消息                
 * 
 * 返回:
 * EASYRTOS_OK 成功
 * EASYRTOS_WOULDBLOCK 本来会被悬挂但由于timeout为-1所以返回了
 * EASYRTOS_TIMEOUT 信号量timeout到期
 * EASYRTOS_ERR_DELETED 队列在悬挂任务时被删除
 * EASYRTOS_ERR_CONTEXT 错误的上下文调用
 * EASYRTOS_ERR_PARAM 参数错误
 * EASYRTOS_ERR_QUEUE 将任务加入运行队列失败
 * EASYRTOS_ERR_TIMER 注册定时器未成功
 * 
 * 调用的函数:
 * eCurrentContext();
 * tcbEnqueuePriority (&qptr->getSuspQ, curr_tcb_ptr);
 * eTimerRegister (&timerCb);
 * tcb_dequeue_entry (&qptr->getSuspQ, curr_tcb_ptr);
 * easyRTOSSched (FALSE);
 * queue_remove (qptr, msgptr);
 */
ERESULT eQueueGive (EASYRTOS_QUEUE *qptr, int32_t timeout, void *msgptr)
{
    CRITICAL_STORE;
    ERESULT status;
    QUEUE_TIMER timerData;
    EASYRTOS_TIMER timerCb;
    EASYRTOS_TCB *curr_tcb_ptr;

    /* 参数检查 */
    if ((qptr == NULL) || (msgptr == NULL))
    {
        status = EASYRTOS_ERR_PARAM;
    }
    else
    {
        /* 进入临界区 */
        CRITICAL_ENTER ();

        /* 若队列已满,悬挂调用此函数的任务 */
        if (qptr->num_msgs_stored == qptr->max_num_msgs)
        {
            /* timeout >= 0, 任务将被悬挂 */
            if (timeout >= 0)
            {

                /* 获取当前任务TCB */
                curr_tcb_ptr = eCurrentContext();

                /* 检查是否在任务上下文 */
                if (curr_tcb_ptr)
                {
                    /* 将当前任务添加到send悬挂列表中 */
                    if (tcbEnqueuePriority (&qptr->putSuspQ, curr_tcb_ptr) == EASYRTOS_OK)
                    {
                        /* 设置任务状态标志位为悬挂 */
                        curr_tcb_ptr->state = TASK_PENDED;

                        status = EASYRTOS_OK;

                        /* timeout>0 注册定时器回调 */
                        if (timeout)
                        {
                            /* 填充定时器需要的数据 */
                            timerData.tcb_ptr = curr_tcb_ptr;
                            timerData.queue_ptr = qptr;
                            timerData.suspQ = &qptr->putSuspQ;


                            /* 填充回调需要的数据 */
                            timerCb.cb_func = eQueueTimerCallback;
                            timerCb.cb_data = (POINTER)&timerData;
                            timerCb.cb_ticks = timeout;

                            /* 在任务TCB中存储定时器回调,方便对其进行取消操作 */
                            curr_tcb_ptr->pended_timo_cb = &timerCb;

                            /* 注册定时器 */
                            if (eTimerRegister (&timerCb) != EASYRTOS_OK)
                            {
                                /* 注册失败 */
                                status = EASYRTOS_ERR_TIMER;
                                
                                (void)tcb_dequeue_entry (&qptr->putSuspQ, curr_tcb_ptr);
                                curr_tcb_ptr->state = TASK_RUN;
                                curr_tcb_ptr->pended_timo_cb = NULL;
                            }
                        }

                        /* 不需要注册定时器 */
                        else
                        {
                            curr_tcb_ptr->pended_timo_cb = NULL;
                        }

                        /* 退出临界区 */
                        CRITICAL_EXIT ();

                        /* 检测是否注册成功 */
                        if (status == EASYRTOS_OK)
                        {
                            /* 当前任务被悬挂,我们将调用调度器 */
                            easyRTOSSched (FALSE);
                            
                            /* 下次任务将从此处开始运行,此时队列被删除 或者timeout到期 或者调用了eQueueGive */
                            status = curr_tcb_ptr->pendedWakeStatus;

                            /** 
                             * 检测pendedWakeStatus,若其值为EASYRTOS_OK,则说明
                             * 读取是成功的,若为其他的值,则说明有可能队列被删除
                             * 或者timeout到期,此时我们只需要退出就好了
                             */
                            if (status == EASYRTOS_OK)
                            {
                                /* 进入临界区 */
                                CRITICAL_ENTER();

                                /* 将消息加入队列 */
                                status = queue_insert (qptr, msgptr);

                                /* 退出临界区 */
                                CRITICAL_EXIT();
                            }
                        }
                    }
                    else
                    {
                        /* 将任务加入悬挂队列失败 */
                        CRITICAL_EXIT();
                        status = EASYRTOS_ERR_QUEUE;
                    }
                }
                else
                {
                    /* 不再任务上下文,不能悬挂任务 */
                    CRITICAL_EXIT ();
                    status = EASYRTOS_ERR_CONTEXT;
                }
            }
            else
            {
                /* timeout == -1, 不需要悬挂任务,且队列此时数据量为0 */
                CRITICAL_EXIT();
                status = EASYRTOS_WOULDBLOCK;
            }
        }
        else
        {
            /* 不用悬挂任务,直接将数据复制进队列 */
            status = queue_insert (qptr, msgptr);

            /* 退出临界区 */
            CRITICAL_EXIT ();

            /**
             * 只在任务上下文环境调用调度器。
             * 中断环境会有eIntExit()调用调度器。.
             */
            if (eCurrentContext())
                easyRTOSSched (FALSE);
        }
    }

    return (status);
}
Пример #23
0
/**
 * 功能: 放置信号量,根据信号量类型不同会有以下不同反应:
 * 1、二值信号量
 * 当计数为0的时候计数加1,计数已经为1则会返回溢出错误。
 * 2、计数信号量
 * 计数加1,当计数大于127时,则会返回溢出错误。
 * 3、互斥锁
 * 当互斥锁拥有者调用的时候,若计数<=0,则计数加1,当计数达到1时,清除拥有任务。
 * 当非拥有者调用的时候返回EASYRTOS_ERR_OWNERSHIP
 * 当有任务被悬挂的时候,将会调用调度器.
 *
 * 参数:
 * 输入:                                      输出:
 * EASYRTOS_SEM * sem 信号量指针              EASYRTOS_SEM * sem 信号量指针       
 * 
 * 返回:
 * EASYRTOS_OK 成功
 * EASYRTOS_ERR_OVF 计数信号量count>32767(>32767)
 * EASYRTOS_ERR_PARAM 错误的参数
 * EASYRTOS_ERR_QUEUE 将任务加入运行队列失败
 * EASYRTOS_ERR_TIMER 注册定时器未成功
 * EASYRTOS_ERR_BIN_OVF 二值信号量count已经为1
 * EASYRTOS_SEM_UINIT 信号量没有被初始化
 * EASYRTOS_ERR_OWNERSHIP 尝试解锁Mutex的任务不是Mutex拥有者
 * 
 * 调用的函数:
 * eCurrentContext();
 * tcb_dequeue_head (&sem->suspQ);
 * tcbEnqueuePriority (&tcb_readyQ, tcb_ptr);
 * eTimerCancel (tcb_ptr->pended_timo_cb);
 * easyRTOSSched (FALSE);
 */
ERESULT eSemGive (EASYRTOS_SEM * sem)
{
  ERESULT status;
  CRITICAL_STORE;
  EASYRTOS_TCB *tcb_ptr;
  EASYRTOS_TCB *curr_tcb_ptr;
  
  /* 参数检查 */
  if (sem == NULL)
  {
    status = EASYRTOS_ERR_PARAM;
  }
  else if (sem->type == NULL)
  {
    status = EASYRTOS_SEM_UINIT;
  }
  else
  {
    
    /* 获取正在运行的任务的TCB */
    curr_tcb_ptr = eCurrentContext();
        
    /* 进入临界区 */
    CRITICAL_ENTER ();
    
    if (sem->type == SEM_MUTEX && sem->owner != curr_tcb_ptr)
    {
        /* 退出临界区 */
        CRITICAL_EXIT ();
        
        status = EASYRTOS_ERR_OWNERSHIP;
    }

    /* 将被信号量悬挂的任务置入Ready任务列表 */
    else 
    {
      
      if (sem->suspQ && sem->count == 0)
      {
        sem->owner = NULL;
        //if ( sem->type == SEM_MUTEX )sem->count++;
        tcb_ptr = tcb_dequeue_head (&sem->suspQ);
        if (tcbEnqueuePriority (&tcb_readyQ, tcb_ptr) != EASYRTOS_OK)
        {
          
          /* 若加入Ready列表失败,退出临界区 */
          CRITICAL_EXIT ();

          status = EASYRTOS_ERR_QUEUE;
        }
        else
        {
          
          /* 给等待的任务返回EASYRTOS_OK */
          tcb_ptr->pendedWakeStatus = EASYRTOS_OK;
          tcb_ptr->state = TASK_READY;
          
          /* 设置任务为新的互斥锁ower */
          sem->owner = tcb_ptr;
          
          /* 解除该信号量timeout注册的定时器 */
          if ((tcb_ptr->pended_timo_cb != NULL)
              && (eTimerCancel (tcb_ptr->pended_timo_cb) != EASYRTOS_OK))
          {
            
              /* 解除定时器失败 */
              status = EASYRTOS_ERR_TIMER;
          }
          else
          {
            
              /* 没有timeout定时器注册 */
              tcb_ptr->pended_timo_cb = NULL;

              /* 成功 */
              status = EASYRTOS_OK;
          }

          /* 退出临界区 */
          CRITICAL_EXIT ();

          if (eCurrentContext())
              easyRTOSSched (FALSE);
        }
      }
    

      /* 若没有任务被该信号量悬挂,则增加count,然后返回 */
      else
      {
        switch (sem->type)
        {
          case SEM_COUNTY:
            
            /* 检查是否溢出 */
            if (sem->count == 32767)
            {
              
              /* 返回错误标识 */
              status = EASYRTOS_ERR_OVF;
            }
            else
            {
              
              /* 增加count并返回 */
              sem->count++;
              status = EASYRTOS_OK;
            }
          break;
          
          case SEM_BINARY:
            
            /* 检查是否已经为1 */
            if (sem->count == 1)
            {
              
              /* 返回错误标识 */
              status = EASYRTOS_ERR_OVF;
            }
            else
            {
              
              /* 增加count并返回 */
              sem->count = 1;
              status = EASYRTOS_OK;
            }
          break;
          
          case SEM_MUTEX:
            if (sem->count>1)
            {
              
              /* 返回错误标识 */
              status = EASYRTOS_ERR_OVF;
            }
            else
            {
              sem->count++;
              //测试 若sem->count==1 清除掉拥有者
              if (sem->count>=1)sem->owner=NULL;
              status = EASYRTOS_OK;
            }
          break;
        }
      }

      /* 退出临界区 */
      CRITICAL_EXIT ();
    }
  }

  return (status);
}
Пример #24
0
/**
 * 功能: 获取信号量,若信号量数量为0,根据timeout的不同值和信号量的不同类型有不同的处理方式.
 *
 * 一、二值信号量和计数信号量
 * 1.timeout>0 悬挂调用的任务,当timeout到期的时候唤醒任务并返回timeout标志
 * 2.timeout=0 永久悬挂调用的任务,直到获取到信号量.
 * 3.timeout=-1 不悬挂任务,若信号量计数为0会返回信号量为0的标志.
 *
 * 二、互斥锁
 * 若调用者为拥有者,则进入递归调用模式,计数变为负值,并不会悬挂任务。
 * 若调用者不是拥有者,则根据timeout的不同值有以下的处理方式。
 * 1.timeout>0 悬挂调用的任务,当timeout到期的时候唤醒任务并返回timeout标志
 * 2.timeout=0 永久悬挂调用的任务,直到获取到信号量.
 * 3.timeout=-1 不悬挂任务,若信号量计数为0会返回信号量为0的标志.
 *
 * 当有任务被悬挂的时候,将会调用调度器.
 *
 * 参数:
 * 输入:                                        输出:
 * EASYRTOS_SEM *sem  信号量指针                EASYRTOS_SEM *sem  信号量指针
 * int32_t timeout timeout时间,依赖于心跳时间                  
 * 
 * 返回:
 * EASYRTOS_OK 成功
 * EASYRTOS_TIMEOUT 信号量timeout到期
 * EASYRTOS_WOULDBLOCK 技术为0的时候,timeout=-1
 * EASYRTOS_ERR_DELETED 信号量在悬挂任务时被删除
 * EASYRTOS_ERR_CONTEXT 错误的上下文调用
 * EASYRTOS_ERR_PARAM  错误的参数
 * EASYRTOS_ERR_QUEUE 将任务加入运行队列失败
 * EASYRTOS_ERR_TIMER 注册没有成功
 * EASYRTOS_SEM_UINIT 信号量没有被初始化
 * 
 * 调用的函数:
 * eCurrentContext();
 * tcbEnqueuePriority (&sem->suspQ, curr_tcb_ptr);
 * eTimerRegister (&timerCb);
 * (void)tcb_dequeue_entry (&sem->suspQ, curr_tcb_ptr);
 * easyRTOSSched (FALSE);
 */
ERESULT eSemTake (EASYRTOS_SEM *sem, int32_t timeout)
{
  CRITICAL_STORE;
  ERESULT status;
  SEM_TIMER timerData;
  EASYRTOS_TIMER timerCb;
  EASYRTOS_TCB *curr_tcb_ptr;

  /* 参数检查 */
  if (sem == NULL)
  {
    status = EASYRTOS_ERR_PARAM;
  }
  else if (sem->type == NULL)
  {
    status = EASYRTOS_SEM_UINIT;
  }
  else
  {
    /* 进入临界区 防止在此时信号量发生变化 */
    CRITICAL_ENTER ();
    
    /* 获取正在运行任务的TCB */
    curr_tcb_ptr = eCurrentContext();
        
    /**
     * 检测是否在任务上下文(而不是中断),因为MUTEX需要一个拥有者,所以不能
     * 被ISR调用
     */
    if (curr_tcb_ptr == NULL)
    {
        /* 退出临界区 */
        CRITICAL_EXIT ();

        /* 不在任务上下文中,无法悬挂任务 */
        status = EASYRTOS_ERR_CONTEXT;
    }

    /** 
     * 当为二值信号或者计数信号量的时候,则判断count是否为0.
     * 若为互斥锁信号量,则判断是否上下文与拥有任务不相同.
     * 满足其一,则悬挂该任务. 
     */
    else if (((sem->type != SEM_MUTEX) && (sem->count == 0)) || \\
             ((sem->type == SEM_MUTEX) && (sem->owner != curr_tcb_ptr) && (sem->owner != NULL)))
    {
      /* 若timeout >= 0 则悬挂任务 */
      if (timeout >= 0)
      {
        /* Count为0, 悬挂任务 */

        /* 若是在任务上下文中 */
        if (curr_tcb_ptr)
        {
          /* 将该任务加入该信号量的悬挂列表 */
          if (tcbEnqueuePriority (&sem->suspQ, curr_tcb_ptr) != EASYRTOS_OK)
          {
            /* 若失败,退出临界区 */
            CRITICAL_EXIT ();

            /* 返回错误 */
            status = EASYRTOS_ERR_QUEUE;
          }
          else
          {
            /* 将任务状态设置为悬挂 */
            curr_tcb_ptr->state = TASK_PENDED;
            
            status = EASYRTOS_OK;

            /* 根据timeout的值,决定是否需要注册定时器回调 */
            if (timeout)
            {
              /* 保存回调需要的数据 */
              timerData.tcb_ptr = curr_tcb_ptr;
              timerData.sem_ptr = sem;

              /* 定时器回调需要的数据 */
              timerCb.cb_func = eSemTimerCallback;
              timerCb.cb_data = (POINTER)&timerData;
              timerCb.cb_ticks = timeout;

              /**
               * 保存定时器回调在TCB中,当信号量GIVE的时候,方便取消
               * timeout注册的定时器
               */
              curr_tcb_ptr->pended_timo_cb = &timerCb;

              /* 注册timeout的定时器 */
              if (eTimerRegister (&timerCb) != EASYRTOS_OK)
              {
                /* 若注册失败,返回错误 */
                status = EASYRTOS_ERR_TIMER;

                /* 清除队列 */
                (void)tcb_dequeue_entry (&sem->suspQ, curr_tcb_ptr);
                curr_tcb_ptr->state = TASK_READY;
                curr_tcb_ptr->pended_timo_cb = NULL;
              }
            }

            /* 没有timeout请求 */
            else
            {
              curr_tcb_ptr->pended_timo_cb = NULL;
            }

            /* 退出临界区 */
            CRITICAL_EXIT ();

            /* 检查是否有错误发生 */
            if (status == EASYRTOS_OK)
            {
              /* 任务被悬挂,调用调度器启动一个新的任务 */
              easyRTOSSched (FALSE);

              /**
               * 通过eSemGive()唤醒会返回EASYRTOS_OK,当timeout时间到返回
               * EASYRTOS_TIMEOUT,当信号量被删除时,返回EASYRTOS_ERR_DELETED
               */
              status = curr_tcb_ptr->pendedWakeStatus;

              /**
               * 若线程在EASYRTOS_OK的情况下被唤醒时,其他任务增加了信号量
               * 计数并把控制权交给该任务。理论上,之前的任务增加信号量计数,
               * 然后这个任务减少信号量计数,但是为了能够让其他优先级更高的
               * 任务抢占,我们把减少计数的地方放在了eSemGive()中
               */
            }
          }
        }
        else
        {
          /* 退出临界区 */
          CRITICAL_EXIT ();

          /* 不在任务上下文,不能悬挂 */
          status = EASYRTOS_ERR_CONTEXT;
        }
      }
      else
      {
        /* timeout == -1, 不需要悬挂 */
        CRITICAL_EXIT();
        status = EASYRTOS_WOULDBLOCK;
      }
    }
    else
    {
      switch (sem->type)
      {
        case SEM_BINARY:
        case SEM_COUNTY:
            sem->count--;
            status = EASYRTOS_OK;
          break;
        case SEM_MUTEX:
          
          /* Count不是0,减少Count的值,并返回 */
          if (sem->owner == NULL)
          {
            sem->owner = curr_tcb_ptr;
          }
      
          /* Count不是0,减少Count的值,并返回 */
          if (sem->count>-32768)
          {
            sem->count--;
        
            /* 成功 */
            status = EASYRTOS_OK;
          }
          else {
            status = EASYRTOS_ERR_OVF;
          }
          break;
        default:
          status = EASYRTOS_SEM_UINIT;
      }

      /* 退出临界区 */
      CRITICAL_EXIT ();
  
    }
  }

  return (status);
}
Пример #25
0
/**
 * 功能: 删除信号量,并唤醒所有被该信号量悬挂的任务加入Ready列表中.同时取消该任务
 * 注册的定时器.若有任务被唤醒,则会启动调度器.
 *
 * 参数:
 * 输入:                                   输出:
 * EASYRTOS_SEM *sem 信号量指针            EASYRTOS_SEM *sem 信号量指针
 *
 * 返回:
 * 返回 EASYRTOS_OK 成功
 * 返回 EASYRTOS_ERR_QUEUE 将任务放置到Ready队列中失败
 * 返回 EASYRTOS_ERR_TIMER 取消定时器失败
 * 返回 EASYRTOS_ERR_PARAM 输入参数错误
 * 返回 EASYRTOS_ERR_DELETED 信号量在悬挂任务时被删除
 * 
 * 调用的函数:
 * tcb_dequeue_head (&sem->suspQ);
 * tcbEnqueuePriority (&tcb_readyQ, tcb_ptr);
 * eTimerCancel (tcb_ptr->pended_timo_cb);
 */
ERESULT eSemDelete (EASYRTOS_SEM *sem)
{
  ERESULT status;
  CRITICAL_STORE;
  EASYRTOS_TCB *tcb_ptr;
  uint8_t woken_threads = FALSE;

  /* 参数检查 */
  if (sem == NULL)
  {
    status = EASYRTOS_ERR_PARAM;
  }
  else
  {
    status = EASYRTOS_OK;

    /* 唤醒所有被悬挂的任务 */
    while (1)
    {
      /* 进入临界区 */
      CRITICAL_ENTER ();

      /* 检查是否有任务被悬挂 可能有很多任务被该信号量悬挂 &sem->suspQ为悬挂链表 */
      tcb_ptr = tcb_dequeue_head (&sem->suspQ);

      /* 若有任务被信号量悬挂 */
      if (tcb_ptr)
      {
        /* 对被悬挂的任务返回错误标志 */
        tcb_ptr->pendedWakeStatus = EASYRTOS_ERR_DELETED;

        /* 将任务TCB加入Ready的链表 */
        if (tcbEnqueuePriority (&tcb_readyQ, tcb_ptr) != EASYRTOS_OK)
        {
          /* 若加入失败,退出临界区 */
          CRITICAL_EXIT ();

          /* 退出循环,返回加入Ready链表失败 */
          status = EASYRTOS_ERR_QUEUE;
          break;
        }
        
        /* 成功则把任务设置为READY状态 */
        else tcb_ptr->state = TASK_READY;

        /* 若悬挂有timeout,取消对应的定时器 */
        if (tcb_ptr->pended_timo_cb)
        {
          if (eTimerCancel (tcb_ptr->pended_timo_cb) != EASYRTOS_OK)
          {
            /* 取消定时器失败,退出临界区 */
            CRITICAL_EXIT ();

            /* 退出循环,返回错误标识 */
            status = EASYRTOS_ERR_TIMER;
            break;
          }

          /* 标志没有timeout定时器注册 */
          tcb_ptr->pended_timo_cb = NULL;
        }

        /* 退出临界区 */
        CRITICAL_EXIT ();

        /* 请求调度器 */
        woken_threads = TRUE;
      }

      /* 没有被悬挂的任务了 */
      else
      {
        /* 退出临界区并结束循环 */
        CRITICAL_EXIT ();
        break;
      }
    }

    /* 有任务被唤醒则调用调度器 */
    if (woken_threads == TRUE)
    {
      /**
       *  只有在任务中才运行调度器,在中断中时会在退出中断
       *  时eIntExit()调用
       */
      if (eCurrentContext())
          easyRTOSSched (FALSE);
    }
  }

  return (status);
}
Пример #26
0
/**
 * 功能: 删除队列,并唤醒所有被该队列悬挂的任务加入Ready列表中.同时取消该任务
 * 注册的定时器.若有任务被唤醒,则会启动调度器.
 *
 * 参数:
 * 输入:                                   输出:
 * EASYRTOS_QUEUE *qptr 队列指针           EASYRTOS_QUEUE *qptr 队列指针
 *
 * 返回:
 * EASYRTOS_OK 成功
 * EASYRTOS_ERR_QUEUE 将任务放置到Ready队列中失败
 * EASYRTOS_ERR_TIMER 取消定时器失败
 * 
 * 调用的函数:
 * tcb_dequeue_head (&qptr->getSuspQ);
 * tcb_dequeue_head (&qptr->putSuspQ);
 * tcbEnqueuePriority (&tcb_readyQ, tcb_ptr);
 * eTimerCancel (tcb_ptr->pended_timo_cb);
 * eCurrentContext();
 * easyRTOSSched (FALSE);
 */
ERESULT eQueueDelete (EASYRTOS_QUEUE *qptr)
{
  ERESULT status;
  CRITICAL_STORE;
  EASYRTOS_TCB *tcb_ptr;
  uint8_t wokenTasks = FALSE;

  /* 参数检查 */
  if (qptr == NULL)
  {
    status = EASYRTOS_ERR_PARAM;
  }
  else
  {
    /* 默认返回 */
    status = EASYRTOS_OK;

    /* 唤醒所有被悬挂的任务(将其加入Ready队列) */
    while (1)
    {
      /* 进入临界区 */
      CRITICAL_ENTER ();

      /* 检查是否有线程被悬挂 (等待发送或等待接收) */
      if (((tcb_ptr = tcb_dequeue_head (&qptr->getSuspQ)) != NULL)
          || ((tcb_ptr = tcb_dequeue_head (&qptr->putSuspQ)) != NULL))
      {

        /* 返回错误状态 */
        tcb_ptr->pendedWakeStatus = EASYRTOS_ERR_DELETED;

        /* 将任务加入Ready队列 */
        if (tcbEnqueuePriority (&tcb_readyQ, tcb_ptr) != EASYRTOS_OK)
        {
          /* 退出临界区 */
          CRITICAL_EXIT ();

          /* 退出循环,返回错误 */
          status = EASYRTOS_ERR_QUEUE;
          break;
        }
        else tcb_ptr->state = TASK_READY;

        /* 取消阻塞任务注册的定时器 */
        if (tcb_ptr->pended_timo_cb)
        {
          /* 取消回调函数 */
          if (eTimerCancel (tcb_ptr->pended_timo_cb) != EASYRTOS_OK)
          {
              /* 退出临界区 */
              CRITICAL_EXIT ();

              /* 退出循环,返回错误 */
              status = EASYRTOS_ERR_TIMER;
              break;
          }

          /* 标记任务没有定时器回调 */
          tcb_ptr->pended_timo_cb = NULL;
        }

        /* 退出临界区 */
        CRITICAL_EXIT ();

        /* 是否调用调度器 */
        wokenTasks= TRUE;
      }

      /* 没有被悬挂的任务 */
      else
      {
        /* 退出临界区 */
        CRITICAL_EXIT ();
        break;
      }
    }

    /* 若有任务被唤醒,调用调度器 */
    if (wokenTasks == TRUE)
    {
      /**
       * 只在任务上下文环境调用调度器。
       * 中断环境会有eIntExit()调用调度器。
       */
      if (eCurrentContext())
        easyRTOSSched (FALSE);
    }
  }

  return (status);
}