void chCoreGrowI(size_t size) { chDbgCheckClassI(); size = MEM_ALIGN_NEXT(size); chDbgCheck(endmem + size <= realendmem, "chCoreGrowI"); endmem += size; }
/** * @brief Performs a reset operation on the semaphore. * @post After invoking this function all the threads waiting on the * semaphore, if any, are released and the semaphore counter is set * to the specified, non negative, value. * @post This function does not reschedule so a call to a rescheduling * function must be performed before unlocking the kernel. Note that * interrupt handlers always reschedule on exit so an explicit * reschedule must not be performed in ISRs. * * @param[in] sp pointer to a @p semaphore_t structure * @param[in] n the new value of the semaphore counter. The value must * be non-negative. * * @iclass */ void chSemResetI(semaphore_t *sp, cnt_t n) { thread_t *tp; cnt_t cnt; chDbgCheckClassI(); chDbgCheck((sp != NULL) && (n >= (cnt_t)0)); cnt = sp->cnt; sp->cnt = n; tp = nil.threads; while (cnt < (cnt_t)0) { chDbgAssert(tp < &nil.threads[CH_CFG_NUM_THREADS], "pointer out of range"); /* Is this thread waiting on this semaphore?*/ if (tp->u1.semp == sp) { chDbgAssert(NIL_THD_IS_WTSEM(tp), "not waiting"); cnt++; (void) chSchReadyI(tp, MSG_RESET); } tp++; } }
/** * @brief Retrieves a message from a mailbox. * @details This variant is non-blocking, the function returns a timeout * condition if the queue is empty. * * @param[in] mbp the pointer to an initialized @p mailbox_t object * @param[out] msgp pointer to a message variable for the received message * @return The operation status. * @retval MSG_OK if a message has been correctly fetched. * @retval MSG_RESET if the mailbox has been reset. * @retval MSG_TIMEOUT if the mailbox is empty and a message cannot be * fetched. * * @iclass */ msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp) { chDbgCheckClassI(); chDbgCheck((mbp != NULL) && (msgp != NULL)); /* If the mailbox is in reset state then returns immediately.*/ if (mbp->reset) { return MSG_RESET; } /* Is there a message in queue? if so then fetch.*/ if (chMBGetUsedCountI(mbp) > (size_t)0) { *msgp = *mbp->rdptr++; if (mbp->rdptr >= mbp->top) { mbp->rdptr = mbp->buffer; } mbp->cnt--; /* If there is a writer waiting then makes it ready.*/ chThdDequeueNextI(&mbp->qw, MSG_OK); return MSG_OK; } /* No message, immediate timeout.*/ return MSG_TIMEOUT; }
/** * @brief Disables a Virtual Timer. * @pre The timer must be in armed state before calling this function. * * @param[in] vtp the @p virtual_timer_t structure pointer * * @iclass */ void chVTDoResetI(virtual_timer_t *vtp) { chDbgCheckClassI(); chDbgCheck(vtp != NULL); chDbgAssert(vtp->vt_func != NULL, "timer not set or already triggered"); /* Removing the element from the delta list.*/ vtp->vt_next->vt_delta += vtp->vt_delta; vtp->vt_prev->vt_next = vtp->vt_next; vtp->vt_next->vt_prev = vtp->vt_prev; vtp->vt_func = (vtfunc_t)NULL; /* The above code changes the value in the header when the removed element is the last of the list, restoring it.*/ ch.vtlist.vt_delta = (systime_t)-1; #if CH_CFG_ST_TIMEDELTA > 0 || defined(__DOXYGEN__) { if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) { /* Just removed the last element in the list, alarm timer stopped.*/ port_timer_stop_alarm(); } else { /* The alarm is set to the next element in the delta list.*/ port_timer_set_alarm(ch.vtlist.vt_lasttime + ch.vtlist.vt_next->vt_delta); } } #endif /* CH_CFG_ST_TIMEDELTA > 0 */ }
/** * @brief Creates a new thread into a static memory area. * @details The new thread is initialized but not inserted in the ready list, * the initial state is @p CH_STATE_WTSTART. * @post The initialized thread can be subsequently started by invoking * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS() * depending on the execution context. * @note A thread can terminate by calling @p chThdExit() or by simply * returning from its main function. * @note Threads created using this function do not obey to the * @p CH_DBG_FILL_THREADS debug option because it would keep * the kernel locked for too much time. * * @param[out] tdp pointer to the thread descriptor * @return The pointer to the @p thread_t structure allocated for * the thread into the working space area. * * @iclass */ thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp) { thread_t *tp; chDbgCheckClassI(); chDbgCheck(tdp != NULL); chDbgCheck(MEM_IS_ALIGNED(tdp->wbase, PORT_WORKING_AREA_ALIGN) && MEM_IS_ALIGNED(tdp->wend, PORT_STACK_ALIGN) && (tdp->wend > tdp->wbase) && ((size_t)((tdp->wend - tdp->wbase) * sizeof (stkalign_t)) >= THD_WORKING_AREA_SIZE(0))); chDbgCheck((tdp->prio <= HIGHPRIO) && (tdp->funcp != NULL)); /* The thread structure is laid out in the upper part of the thread workspace. The thread position structure is aligned to the required stack alignment because it represents the stack top.*/ tp = (thread_t *)((uint8_t *)tdp->wend - MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN)); /* Initial state.*/ tp->state = CH_STATE_WTSTART; /* Stack boundary.*/ tp->stklimit = tdp->wbase; /* Setting up the port-dependent part of the working area.*/ PORT_SETUP_CONTEXT(tp, tdp->wbase, tp, tdp->funcp, tdp->arg); /* The driver object is initialized but not started.*/ return _thread_init(tp, tdp->name, tdp->prio); }
/** * @brief Posts an high priority message into a mailbox. * @details This variant is non-blocking, the function returns a timeout * condition if the queue is full. * * @param[in] mbp the pointer to an initialized @p mailbox_t object * @param[in] msg the message to be posted on the mailbox * @return The operation status. * @retval MSG_OK if a message has been correctly posted. * @retval MSG_RESET if the mailbox has been reset. * @retval MSG_TIMEOUT if the mailbox is full and the message cannot be * posted. * * @iclass */ msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg) { chDbgCheckClassI(); chDbgCheck(mbp != NULL); /* If the mailbox is in reset state then returns immediately.*/ if (mbp->reset) { return MSG_RESET; } /* Is there a free message slot in queue? if so then post.*/ if (chMBGetFreeCountI(mbp) > (size_t)0) { if (--mbp->rdptr < mbp->buffer) { mbp->rdptr = mbp->top - 1; } *mbp->rdptr = msg; mbp->cnt++; /* If there is a reader waiting then makes it ready.*/ chThdDequeueNextI(&mbp->qr, MSG_OK); return MSG_OK; } /* No space, immediate timeout.*/ return MSG_TIMEOUT; }
/** * @brief Resets an input queue. * @details All the data in the input queue is erased and lost, any waiting * thread is resumed with status @p Q_RESET. * @note A reset operation can be used by a low level driver in order to * obtain immediate attention from the high level layers. * * @param[in] iqp pointer to an @p input_queue_t structure * * @iclass */ void chIQResetI(input_queue_t *iqp) { chDbgCheckClassI(); iqp->q_rdptr = iqp->q_wrptr = iqp->q_buffer; iqp->q_counter = 0; chThdDequeueAllI(&iqp->q_waiting, Q_RESET); }
/** * @brief Resets an output queue. * @details All the data in the output queue is erased and lost, any waiting * thread is resumed with status @p Q_RESET. * @note A reset operation can be used by a low level driver in order to * obtain immediate attention from the high level layers. * * @param[in] oqp pointer to an @p output_queue_t structure * * @iclass */ void chOQResetI(output_queue_t *oqp) { chDbgCheckClassI(); oqp->q_rdptr = oqp->q_wrptr = oqp->q_buffer; oqp->q_counter = chQSizeI(oqp); chThdDequeueAllI(&oqp->q_waiting, Q_RESET); }
/** * @brief Resets an output queue. * @details All the data in the output queue is erased and lost, any waiting * thread is resumed with status @p Q_RESET. * @note A reset operation can be used by a low level driver in order to * obtain immediate attention from the high level layers. * * @param[in] oqp pointer to an @p OutputQueue structure * * @iclass */ void chOQResetI(OutputQueue *oqp) { chDbgCheckClassI(); oqp->q_rdptr = oqp->q_wrptr = oqp->q_buffer; oqp->q_counter = chQSizeI(oqp); while (notempty(&oqp->q_waiting)) chSchReadyI(fifo_remove(&oqp->q_waiting))->p_u.rdymsg = Q_RESET; }
/** * @brief Resets an input queue. * @details All the data in the input queue is erased and lost, any waiting * thread is resumed with status @p Q_RESET. * @note A reset operation can be used by a low level driver in order to * obtain immediate attention from the high level layers. * * @param[in] iqp pointer to an @p InputQueue structure * * @iclass */ void chIQResetI(InputQueue *iqp) { chDbgCheckClassI(); iqp->q_rdptr = iqp->q_wrptr = iqp->q_buffer; iqp->q_counter = 0; while (notempty(&iqp->q_waiting)) chSchReadyI(fifo_remove(&iqp->q_waiting))->p_u.rdymsg = Q_RESET; }
/** * @brief Releases an object into a memory pool. * @pre The memory pool must be already been initialized. * @pre The freed object must be of the right size for the specified * memory pool. * @pre The added object must be properly aligned. * * @param[in] mp pointer to a @p memory_pool_t structure * @param[in] objp the pointer to the object to be released * * @iclass */ void chPoolFreeI(memory_pool_t *mp, void *objp) { struct pool_header *php = objp; chDbgCheckClassI(); chDbgCheck((mp != NULL) && (objp != NULL)); php->next = mp->next; mp->next = php; }
/** * @brief Releases an object into a memory pool. * @pre The memory pool must be already been initialized. * @pre The freed object must be of the right size for the specified * memory pool. * @pre The object must be properly aligned to contain a pointer to void. * * @param[in] mp pointer to a @p MemoryPool structure * @param[in] objp the pointer to the object to be released * * @iclass */ void chPoolFreeI(MemoryPool *mp, void *objp) { struct pool_header *php = objp; chDbgCheckClassI(); chDbgCheck((mp != NULL) && (objp != NULL), "chPoolFreeI"); php->ph_next = mp->mp_next; mp->mp_next = php; }
/** * @brief Enables a virtual timer. * @details The timer is enabled and programmed to trigger after the delay * specified as parameter. * @pre The timer must not be already armed before calling this function. * @note The callback function is invoked from interrupt context. * * @param[out] vtp the @p virtual_timer_t structure pointer * @param[in] delay the number of ticks before the operation timeouts, the * special values are handled as follow: * - @a TIME_INFINITE is allowed but interpreted as a * normal time specification. * - @a TIME_IMMEDIATE this value is not allowed. * . * @param[in] vtfunc the timer callback function. After invoking the * callback the timer is disabled and the structure can * be disposed or reused. * @param[in] par a parameter that will be passed to the callback * function * * @iclass */ void chVTDoSetI(virtual_timer_t *vtp, systime_t delay, vtfunc_t vtfunc, void *par) { virtual_timer_t *p; chDbgCheckClassI(); chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE)); vtp->vt_par = par; vtp->vt_func = vtfunc; p = ch.vtlist.vt_next; #if CH_CFG_ST_TIMEDELTA > 0 || defined(__DOXYGEN__) { systime_t now = port_timer_get_time(); /* If the requested delay is lower than the minimum safe delta then it is raised to the minimum safe value.*/ if (delay < CH_CFG_ST_TIMEDELTA) delay = CH_CFG_ST_TIMEDELTA; if (&ch.vtlist == (virtual_timers_list_t *)p) { /* The delta list is empty, the current time becomes the new delta list base time.*/ ch.vtlist.vt_lasttime = now; port_timer_start_alarm(ch.vtlist.vt_lasttime + delay); } else { /* Now the delay is calculated as delta from the last tick interrupt time.*/ delay += now - ch.vtlist.vt_lasttime; /* If the specified delay is closer in time than the first element in the delta list then it becomes the next alarm event in time.*/ if (delay < p->vt_delta) port_timer_set_alarm(ch.vtlist.vt_lasttime + delay); } } #endif /* CH_CFG_ST_TIMEDELTA > 0 */ /* The delta list is scanned in order to find the correct position for this timer. */ while (p->vt_delta < delay) { delay -= p->vt_delta; p = p->vt_next; } /* The timer is inserted in the delta list.*/ vtp->vt_prev = (vtp->vt_next = p)->vt_prev; vtp->vt_prev->vt_next = p->vt_prev = vtp; vtp->vt_delta = delay /* Special case when the timer is in last position in the list, the value in the header must be restored.*/; p->vt_delta -= delay; ch.vtlist.vt_delta = (systime_t)-1; }
/** * @brief Starts the timer in one shot mode. * * @param[in] gptp pointer to the @p GPTDriver object * @param[in] interval time interval in ticks * * @api */ void gptStartOneShotI(GPTDriver *gptp, gptcnt_t interval) { chDbgCheckClassI(); chDbgCheck(gptp != NULL, "gptStartOneShotI"); chDbgAssert(gptp->state == GPT_READY, "gptStartOneShotI(), #1", "invalid state"); gptp->state = GPT_ONESHOT; gpt_lld_start_timer(gptp, interval); }
void *chCoreUnreserveI(size_t size) { chDbgCheckClassI(); size = MEM_ALIGN_NEXT(size); if ((size_t)(realendmem - endmem) < size) return NULL; endmem += size; return endmem; }
/** * @brief Starts the timer in continuous mode. * * @param[in] gptp pointer to the @p GPTDriver object * @param[in] interval period in ticks * * @iclass */ void gptStartContinuousI(GPTDriver *gptp, gptcnt_t interval) { chDbgCheckClassI(); chDbgCheck(gptp != NULL, "gptStartContinuousI"); chDbgAssert(gptp->state == GPT_READY, "gptStartContinuousI(), #1", "invalid state"); gptp->state = GPT_CONTINUOUS; gpt_lld_start_timer(gptp, interval); }
/** * @brief Handles incoming data. * @details This function must be called from the input interrupt service * routine in order to enqueue incoming data and generate the * related events. * @note The incoming data event is only generated when the input queue * becomes non-empty. * @note In order to gain some performance it is suggested to not use * this function directly but copy this code directly into the * interrupt service routine. * * @param[in] sdp pointer to a @p SerialDriver structure * @param[in] b the byte to be written in the driver's Input Queue * * @iclass */ void sdIncomingDataI(SerialDriver *sdp, uint8_t b) { chDbgCheckClassI(); chDbgCheck(sdp != NULL, "sdIncomingDataI"); if (chIQIsEmptyI(&sdp->iqueue)) chIOAddFlagsI(sdp, IO_INPUT_AVAILABLE); if (chIQPutI(&sdp->iqueue, b) < Q_OK) chIOAddFlagsI(sdp, SD_OVERRUN_ERROR); }
void *chCoreReserveI(size_t size) { chDbgCheckClassI(); size = MEM_ALIGN_NEXT(size); if ((size_t)(endmem - nextmem) < size) return NULL; endmem -= size; return endmem; }
/** * @brief Adds a set of event flags directly to the specified @p thread_t. * @post This function does not reschedule so a call to a rescheduling * function must be performed before unlocking the kernel. Note that * interrupt handlers always reschedule on exit so an explicit * reschedule must not be performed in ISRs. * * @param[in] tp the thread to be signaled * @param[in] mask the event flags set to be ORed * * @iclass */ void chEvtSignalI(thread_t *tp, eventmask_t mask) { chDbgCheckClassI(); chDbgCheck(tp != NULL); tp->epmask |= mask; if (NIL_THD_IS_WTOREVT(tp) && ((tp->epmask & tp->u1.ewmask) != (eventmask_t)0)) { (void) chSchReadyI(tp, MSG_OK); } }
/** * @brief Stalls an IN endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @return The operation status. * @retval FALSE Endpoint stalled. * @retval TRUE Endpoint busy, not stalled. * * @iclass */ bool_t usbStallTransmitI(USBDriver *usbp, usbep_t ep) { chDbgCheckClassI(); chDbgCheck(usbp != NULL, "usbStallTransmitI"); if (usbGetTransmitStatusI(usbp, ep)) return TRUE; usb_lld_stall_in(usbp, ep); return FALSE; }
/** * @brief Signals all threads that are waiting on the condition variable. * @post This function does not reschedule so a call to a rescheduling * function must be performed before unlocking the kernel. Note that * interrupt handlers always reschedule on exit so an explicit * reschedule must not be performed in ISRs. * * @param[in] cp pointer to the @p condition_variable_t structure * * @iclass */ void chCondBroadcastI(condition_variable_t *cp) { chDbgCheckClassI(); chDbgCheck(cp != NULL); /* Empties the condition variable queue and inserts all the threads into the ready list in FIFO order. The wakeup message is set to @p MSG_RESET in order to make a chCondBroadcast() detectable from a chCondSignal().*/ while (cp->c_queue.p_next != (void *)&cp->c_queue) chSchReadyI(queue_fifo_remove(&cp->c_queue))->p_u.rdymsg = MSG_RESET; }
/** * @brief Starts a receive operation on the UART peripheral. * @note The buffers are organized as uint8_t arrays for data sizes below * or equal to 8 bits else it is organized as uint16_t arrays. * @note This function has to be invoked from a lock zone. * * @param[in] uartp pointer to the @p UARTDriver object * @param[in] n number of data frames to send * @param[out] rxbuf the pointer to the receive buffer * * @iclass */ void uartStartReceiveI(UARTDriver *uartp, size_t n, void *rxbuf) { chDbgCheckClassI(); chDbgCheck((uartp != NULL) && (n > 0) && (rxbuf != NULL), "uartStartReceiveI"); chDbgAssert((uartp->state == UART_READY) && (uartp->rxstate == UART_RX_IDLE), "uartStartReceiveI(), #1", "not active"); uart_lld_start_receive(uartp, n, rxbuf); uartp->rxstate = UART_RX_ACTIVE; }
/** * @brief Stalls an OUT endpoint. * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number * * @return The operation status. * @retval FALSE Endpoint stalled. * @retval TRUE Endpoint busy, not stalled. * * @iclass */ bool_t usbStallReceiveI(USBDriver *usbp, usbep_t ep) { chDbgCheckClassI(); chDbgCheck(usbp != NULL, "usbStallReceiveI"); if (usbGetReceiveStatusI(usbp, ep)) return TRUE; usb_lld_stall_out(usbp, ep); return FALSE; }
/** * @brief Signals one thread that is waiting on the condition variable. * @post This function does not reschedule so a call to a rescheduling * function must be performed before unlocking the kernel. Note that * interrupt handlers always reschedule on exit so an explicit * reschedule must not be performed in ISRs. * * @param[in] cp pointer to the @p condition_variable_t structure * * @iclass */ void chCondSignalI(condition_variable_t *cp) { chDbgCheckClassI(); chDbgCheck(cp != NULL); if (queue_notempty(&cp->c_queue)) { thread_t *tp = queue_fifo_remove(&cp->c_queue); tp->p_u.rdymsg = MSG_OK; chSchReadyI(tp); } }
/** * @brief Handles outgoing data. * @details Must be called from the output interrupt service routine in order * to get the next byte to be transmitted. * @note In order to gain some performance it is suggested to not use * this function directly but copy this code directly into the * interrupt service routine. * * @param[in] sdp pointer to a @p SerialDriver structure * @return The byte value read from the driver's output queue. * @retval Q_EMPTY if the queue is empty (the lower driver usually * disables the interrupt source when this happens). * * @iclass */ msg_t sdRequestDataI(SerialDriver *sdp) { msg_t b; chDbgCheckClassI(); chDbgCheck(sdp != NULL, "sdRequestDataI"); b = chOQGetI(&sdp->oqueue); if (b < Q_OK) chIOAddFlagsI(sdp, IO_OUTPUT_EMPTY); return b; }
void *chCoreTrimI(size_t size) { uint8_t *p; chDbgCheckClassI(); p = (uint8_t *)MEM_ALIGN_PREV(endmem - size); if (p < nextmem) return NULL; endmem = p; return (void *)p; }
/** * @brief Stops the timer. * * @param[in] gptp pointer to the @p GPTDriver object * * @api */ void gptStopTimerI(GPTDriver *gptp) { chDbgCheckClassI(); chDbgCheck(gptp != NULL, "gptStopTimerI"); chDbgAssert((gptp->state == GPT_READY) || (gptp->state == GPT_CONTINUOUS) || (gptp->state == GPT_ONESHOT), "gptStopTimerI(), #1", "invalid state"); gptp->state = GPT_READY; gpt_lld_stop_timer(gptp); }
/** * @brief Signals all the Event Listeners registered on the specified Event * Source. * @details This function variants ORs the specified event flags to all the * threads registered on the @p EventSource in addition to the event * flags specified by the threads themselves in the * @p EventListener objects. * @post This function does not reschedule so a call to a rescheduling * function must be performed before unlocking the kernel. Note that * interrupt handlers always reschedule on exit so an explicit * reschedule must not be performed in ISRs. * * @param[in] esp pointer to the @p EventSource structure * @param[in] mask the event flags set to be ORed * * @iclass */ void chEvtBroadcastFlagsI(EventSource *esp, eventmask_t mask) { EventListener *elp; chDbgCheckClassI(); chDbgCheck(esp != NULL, "chEvtBroadcastMaskI"); elp = esp->es_next; while (elp != (EventListener *)esp) { chEvtSignalFlagsI(elp->el_listener, elp->el_mask | mask); elp = elp->el_next; } }
/** * @brief Allocates an object from a memory pool. * * @param[in] mp pointer to a @p MemoryPool structure * @return The pointer to the allocated object. * @retval NULL if pool is empty. * * @iclass */ void *chPoolAllocI(MemoryPool *mp) { void *objp; chDbgCheckClassI(); chDbgCheck(mp != NULL, "chPoolAllocI"); if ((objp = mp->mp_next) != NULL) mp->mp_next = mp->mp_next->ph_next; else if (mp->mp_provider != NULL) objp = mp->mp_provider(mp->mp_object_size); return objp; }
/** * @brief Allocates a memory block. * @details The size of the returned block is aligned to the alignment * type so it is not possible to allocate less than * <code>MEM_ALIGN_SIZE</code>. * * @param[in] size the size of the block to be allocated. * @return A pointer to the allocated memory block. * @retval NULL allocation failed, core memory exhausted. * * @iclass */ void *chCoreAllocI(size_t size) { void *p; chDbgCheckClassI(); size = MEM_ALIGN_NEXT(size); if ((size_t)(endmem - nextmem) < size) return NULL; p = nextmem; nextmem += size; return p; }