ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_sys_arch.c Source File

lwip_sys_arch.c

00001 /* Copyright (C) 2012 mbed.org, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 #include <string.h>
00019 
00020 /* mbed includes */
00021 #include "mbed_error.h"
00022 #include "mbed_interface.h"
00023 #include "us_ticker_api.h"
00024 
00025 /* lwIP includes. */
00026 #include "lwip/opt.h"
00027 #include "lwip/debug.h"
00028 #include "lwip/def.h"
00029 #include "lwip/sys.h"
00030 #include "lwip/mem.h"
00031 
00032 /* Define the heap ourselves to give us section placement control */
00033 #ifndef ETHMEM_SECTION
00034 #if defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM)
00035 #  if defined (__ICCARM__)
00036 #     define ETHMEM_SECTION
00037 #  elif defined(TOOLCHAIN_GCC_CR)
00038 #     define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
00039 #  else
00040 #     define ETHMEM_SECTION __attribute__((section("AHBSRAM1"),aligned))
00041 #  endif
00042 #elif defined(TARGET_LPC1768)
00043 #  if defined (__ICCARM__)
00044 #     define ETHMEM_SECTION
00045 #  elif defined(TOOLCHAIN_GCC_CR)
00046 #     define ETHMEM_SECTION __attribute__((section(".data.$RamPeriph32")))
00047 #  else
00048 #     define ETHMEM_SECTION __attribute__((section("AHBSRAM0"),aligned))
00049 #  endif
00050 #else
00051 #define ETHMEM_SECTION
00052 #endif
00053 #endif
00054 
00055 /* LWIP's mem.c doesn't give visibility of its overhead; memory area has to be big
00056  * enough to hold "MEM_SIZE" (which we specify) plus mem.c's overhead. Have to work
00057  * it all out here, copying code from mem.c */
00058 struct mem {
00059   /** index (-> ram[next]) of the next struct */
00060   mem_size_t next;
00061   /** index (-> ram[prev]) of the previous struct */
00062   mem_size_t prev;
00063   /** 1: this area is used; 0: this area is unused */
00064   u8_t used;
00065 };
00066 
00067 #define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
00068 #define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
00069 
00070 #if defined (__ICCARM__)
00071 #pragma location = ".ethusbram"
00072 #endif
00073 LWIP_DECLARE_MEMORY_ALIGNED(lwip_ram_heap, MEM_SIZE_ALIGNED + (2U*SIZEOF_STRUCT_MEM)) ETHMEM_SECTION;
00074 
00075  #if NO_SYS==1
00076 #include "cmsis.h"
00077 
00078 /* Saved total time in ms since timer was enabled */
00079 static volatile u32_t systick_timems;
00080 
00081 /* Enable systick rate and interrupt */
00082 void SysTick_Init(void) {
00083     if (SysTick_Config(SystemCoreClock / 1000)) {
00084         while (1);     /* Capture error */
00085     }
00086 }
00087 
00088 /** \brief  SysTick IRQ handler and timebase management
00089  *
00090  *  This function keeps a timebase for the sysTick that can be
00091  * used for other functions. It also calls an external function
00092  * (SysTick_User) that must be defined outside this handler.
00093  */
00094 void SysTick_Handler(void) {
00095     systick_timems++;
00096 }
00097 
00098 /* Delay for the specified number of milliSeconds */
00099 void osDelay(uint32_t ms) {
00100     uint32_t to = ms + systick_timems;
00101     while (to > systick_timems);
00102 }
00103 
00104 /* Returns the current time in mS. This is needed for the LWIP timers */
00105 u32_t sys_now(void) {
00106   return (u32_t) systick_timems;
00107 }
00108 
00109 #else
00110 /* CMSIS-RTOS implementation of the lwip operating system abstraction */
00111 #include "arch/sys_arch.h"
00112 
00113 /*---------------------------------------------------------------------------*
00114  * Routine:  sys_mbox_new
00115  *---------------------------------------------------------------------------*
00116  * Description:
00117  *      Creates a new mailbox
00118  * Inputs:
00119  *      sys_mbox_t mbox         -- Handle of mailbox
00120  *      int queue_sz            -- Size of elements in the mailbox
00121  * Outputs:
00122  *      err_t                   -- ERR_OK if message posted, else ERR_MEM
00123  *---------------------------------------------------------------------------*/
00124 err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) {
00125     if (queue_sz > MB_SIZE)
00126         error("sys_mbox_new size error\n");
00127     
00128 #ifdef CMSIS_OS_RTX
00129     memset(mbox->queue, 0, sizeof(mbox->queue));
00130     mbox->def.pool = mbox->queue;
00131     mbox->def.queue_sz = queue_sz;
00132 #endif
00133     mbox->id = osMessageCreate(&mbox->def, NULL);
00134     return (mbox->id == NULL) ? (ERR_MEM) : (ERR_OK);
00135 }
00136 
00137 /*---------------------------------------------------------------------------*
00138  * Routine:  sys_mbox_free
00139  *---------------------------------------------------------------------------*
00140  * Description:
00141  *      Deallocates a mailbox. If there are messages still present in the
00142  *      mailbox when the mailbox is deallocated, it is an indication of a
00143  *      programming error in lwIP and the developer should be notified.
00144  * Inputs:
00145  *      sys_mbox_t *mbox         -- Handle of mailbox
00146  *---------------------------------------------------------------------------*/
00147 void sys_mbox_free(sys_mbox_t *mbox) {
00148     osEvent event = osMessageGet(mbox->id, 0);
00149     if (event.status == osEventMessage)
00150         error("sys_mbox_free error\n");
00151 }
00152 
00153 /*---------------------------------------------------------------------------*
00154  * Routine:  sys_mbox_post
00155  *---------------------------------------------------------------------------*
00156  * Description:
00157  *      Post the "msg" to the mailbox.
00158  * Inputs:
00159  *      sys_mbox_t mbox        -- Handle of mailbox
00160  *      void *msg              -- Pointer to data to post
00161  *---------------------------------------------------------------------------*/
00162 void sys_mbox_post(sys_mbox_t *mbox, void *msg) {
00163     if (osMessagePut(mbox->id, (uint32_t)msg, osWaitForever) != osOK)
00164         error("sys_mbox_post error\n");
00165 }
00166 
00167 /*---------------------------------------------------------------------------*
00168  * Routine:  sys_mbox_trypost
00169  *---------------------------------------------------------------------------*
00170  * Description:
00171  *      Try to post the "msg" to the mailbox.  Returns immediately with
00172  *      error if cannot.
00173  * Inputs:
00174  *      sys_mbox_t mbox         -- Handle of mailbox
00175  *      void *msg               -- Pointer to data to post
00176  * Outputs:
00177  *      err_t                   -- ERR_OK if message posted, else ERR_MEM
00178  *                                  if not.
00179  *---------------------------------------------------------------------------*/
00180 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) {
00181     osStatus status = osMessagePut(mbox->id, (uint32_t)msg, 0);
00182     return (status == osOK) ? (ERR_OK) : (ERR_MEM);
00183 }
00184 
00185 /*---------------------------------------------------------------------------*
00186  * Routine:  sys_arch_mbox_fetch
00187  *---------------------------------------------------------------------------*
00188  * Description:
00189  *      Blocks the thread until a message arrives in the mailbox, but does
00190  *      not block the thread longer than "timeout" milliseconds (similar to
00191  *      the sys_arch_sem_wait() function). The "msg" argument is a result
00192  *      parameter that is set by the function (i.e., by doing "*msg =
00193  *      ptr"). The "msg" parameter maybe NULL to indicate that the message
00194  *      should be dropped.
00195  *
00196  *      The return values are the same as for the sys_arch_sem_wait() function:
00197  *      Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
00198  *      timeout.
00199  *
00200  *      Note that a function with a similar name, sys_mbox_fetch(), is
00201  *      implemented by lwIP.
00202  * Inputs:
00203  *      sys_mbox_t mbox         -- Handle of mailbox
00204  *      void **msg              -- Pointer to pointer to msg received
00205  *      u32_t timeout           -- Number of milliseconds until timeout
00206  * Outputs:
00207  *      u32_t                   -- SYS_ARCH_TIMEOUT if timeout, else number
00208  *                                  of milliseconds until received.
00209  *---------------------------------------------------------------------------*/
00210 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) {
00211     u32_t start = us_ticker_read();
00212     
00213     osEvent event = osMessageGet(mbox->id, (timeout != 0)?(timeout):(osWaitForever));
00214     if (event.status != osEventMessage)
00215         return SYS_ARCH_TIMEOUT;
00216     
00217     *msg = (void *)event.value.v;
00218     
00219     return (us_ticker_read() - start) / 1000;
00220 }
00221 
00222 /*---------------------------------------------------------------------------*
00223  * Routine:  sys_arch_mbox_tryfetch
00224  *---------------------------------------------------------------------------*
00225  * Description:
00226  *      Similar to sys_arch_mbox_fetch, but if message is not ready
00227  *      immediately, we'll return with SYS_MBOX_EMPTY.  On success, 0 is
00228  *      returned.
00229  * Inputs:
00230  *      sys_mbox_t mbox         -- Handle of mailbox
00231  *      void **msg              -- Pointer to pointer to msg received
00232  * Outputs:
00233  *      u32_t                   -- SYS_MBOX_EMPTY if no messages.  Otherwise,
00234  *                                  return ERR_OK.
00235  *---------------------------------------------------------------------------*/
00236 u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) {
00237     osEvent event = osMessageGet(mbox->id, 0);
00238     if (event.status != osEventMessage)
00239         return SYS_MBOX_EMPTY;
00240     
00241     *msg = (void *)event.value.v;
00242     
00243     return ERR_OK;
00244 }
00245 
00246 /*---------------------------------------------------------------------------*
00247  * Routine:  sys_sem_new
00248  *---------------------------------------------------------------------------*
00249  * Description:
00250  *      Creates and returns a new semaphore. The "ucCount" argument specifies
00251  *      the initial state of the semaphore.
00252  *      NOTE: Currently this routine only creates counts of 1 or 0
00253  * Inputs:
00254  *      sys_sem_t sem         -- Handle of semaphore
00255  *      u8_t count            -- Initial count of semaphore
00256  * Outputs:
00257  *      err_t                 -- ERR_OK if semaphore created
00258  *---------------------------------------------------------------------------*/
00259 err_t sys_sem_new(sys_sem_t *sem, u8_t count) {
00260 #ifdef CMSIS_OS_RTX
00261     memset(sem->data, 0, sizeof(uint32_t)*2);
00262     sem->def.semaphore = sem->data;
00263 #endif
00264     sem->id = osSemaphoreCreate(&sem->def, count);
00265     if (sem->id == NULL)
00266         error("sys_sem_new create error\n");
00267     
00268     return ERR_OK;
00269 }
00270 
00271 /*---------------------------------------------------------------------------*
00272  * Routine:  sys_arch_sem_wait
00273  *---------------------------------------------------------------------------*
00274  * Description:
00275  *      Blocks the thread while waiting for the semaphore to be
00276  *      signaled. If the "timeout" argument is non-zero, the thread should
00277  *      only be blocked for the specified time (measured in
00278  *      milliseconds).
00279  *
00280  *      If the timeout argument is non-zero, the return value is the number of
00281  *      milliseconds spent waiting for the semaphore to be signaled. If the
00282  *      semaphore wasn't signaled within the specified time, the return value is
00283  *      SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
00284  *      (i.e., it was already signaled), the function may return zero.
00285  *
00286  *      Notice that lwIP implements a function with a similar name,
00287  *      sys_sem_wait(), that uses the sys_arch_sem_wait() function.
00288  * Inputs:
00289  *      sys_sem_t sem           -- Semaphore to wait on
00290  *      u32_t timeout           -- Number of milliseconds until timeout
00291  * Outputs:
00292  *      u32_t                   -- Time elapsed or SYS_ARCH_TIMEOUT.
00293  *---------------------------------------------------------------------------*/
00294 u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) {
00295     u32_t start = us_ticker_read();
00296     
00297     if (osSemaphoreWait(sem->id, (timeout != 0)?(timeout):(osWaitForever)) < 1)
00298         return SYS_ARCH_TIMEOUT;
00299     
00300     return (us_ticker_read() - start) / 1000;
00301 }
00302 
00303 /*---------------------------------------------------------------------------*
00304  * Routine:  sys_sem_signal
00305  *---------------------------------------------------------------------------*
00306  * Description:
00307  *      Signals (releases) a semaphore
00308  * Inputs:
00309  *      sys_sem_t sem           -- Semaphore to signal
00310  *---------------------------------------------------------------------------*/
00311 void sys_sem_signal(sys_sem_t *data) {
00312     if (osSemaphoreRelease(data->id) != osOK)
00313         mbed_die(); /* Can be called by ISR do not use printf */
00314 }
00315 
00316 /*---------------------------------------------------------------------------*
00317  * Routine:  sys_sem_free
00318  *---------------------------------------------------------------------------*
00319  * Description:
00320  *      Deallocates a semaphore
00321  * Inputs:
00322  *      sys_sem_t sem           -- Semaphore to free
00323  *---------------------------------------------------------------------------*/
00324 void sys_sem_free(sys_sem_t *sem) {}
00325 
00326 /** Create a new mutex
00327  * @param mutex pointer to the mutex to create
00328  * @return a new mutex */
00329 err_t sys_mutex_new(sys_mutex_t *mutex) {
00330 #ifdef CMSIS_OS_RTX
00331 #if defined(__MBED_CMSIS_RTOS_CA9) || defined(__MBED_CMSIS_RTOS_CM)
00332     memset(mutex->data, 0, sizeof(int32_t)*4);
00333 #else
00334     memset(mutex->data, 0, sizeof(int32_t)*3);
00335 #endif
00336     mutex->def.mutex = mutex->data;
00337 #endif
00338     mutex->id = osMutexCreate(&mutex->def);
00339     if (mutex->id == NULL)
00340         return ERR_MEM;
00341     
00342     return ERR_OK;
00343 }
00344 
00345 /** Lock a mutex
00346  * @param mutex the mutex to lock */
00347 void sys_mutex_lock(sys_mutex_t *mutex) {
00348     if (osMutexWait(mutex->id, osWaitForever) != osOK)
00349         error("sys_mutex_lock error\n");
00350 }
00351 
00352 /** Unlock a mutex
00353  * @param mutex the mutex to unlock */
00354 void sys_mutex_unlock(sys_mutex_t *mutex) {
00355     if (osMutexRelease(mutex->id) != osOK)
00356         error("sys_mutex_unlock error\n");
00357 }
00358 
00359 /** Delete a mutex
00360  * @param mutex the mutex to delete */
00361 void sys_mutex_free(sys_mutex_t *mutex) {}
00362 
00363 /*---------------------------------------------------------------------------*
00364  * Routine:  sys_init
00365  *---------------------------------------------------------------------------*
00366  * Description:
00367  *      Initialize sys arch
00368  *---------------------------------------------------------------------------*/
00369 osMutexId lwip_sys_mutex;
00370 osMutexDef(lwip_sys_mutex);
00371 
00372 void sys_init(void) {
00373     us_ticker_read(); // Init sys tick
00374     lwip_sys_mutex = osMutexCreate(osMutex(lwip_sys_mutex));
00375     if (lwip_sys_mutex == NULL)
00376         error("sys_init error\n");
00377 }
00378 
00379 /*---------------------------------------------------------------------------*
00380  * Routine:  sys_jiffies
00381  *---------------------------------------------------------------------------*
00382  * Description:
00383  *      Used by PPP as a timestamp-ish value
00384  *---------------------------------------------------------------------------*/
00385 u32_t sys_jiffies(void) {
00386     static u32_t jiffies = 0;
00387     jiffies += 1 + (us_ticker_read()/10000);
00388     return jiffies;
00389 }
00390 
00391 /*---------------------------------------------------------------------------*
00392  * Routine:  sys_arch_protect
00393  *---------------------------------------------------------------------------*
00394  * Description:
00395  *      This optional function does a "fast" critical region protection and
00396  *      returns the previous protection level. This function is only called
00397  *      during very short critical regions. An embedded system which supports
00398  *      ISR-based drivers might want to implement this function by disabling
00399  *      interrupts. Task-based systems might want to implement this by using
00400  *      a mutex or disabling tasking. This function should support recursive
00401  *      calls from the same task or interrupt. In other words,
00402  *      sys_arch_protect() could be called while already protected. In
00403  *      that case the return value indicates that it is already protected.
00404  *
00405  *      sys_arch_protect() is only required if your port is supporting an
00406  *      operating system.
00407  * Outputs:
00408  *      sys_prot_t              -- Previous protection level (not used here)
00409  *---------------------------------------------------------------------------*/
00410 sys_prot_t sys_arch_protect(void) {
00411     if (osMutexWait(lwip_sys_mutex, osWaitForever) != osOK)
00412         error("sys_arch_protect error\n");
00413     return (sys_prot_t) 1;
00414 }
00415 
00416 /*---------------------------------------------------------------------------*
00417  * Routine:  sys_arch_unprotect
00418  *---------------------------------------------------------------------------*
00419  * Description:
00420  *      This optional function does a "fast" set of critical region
00421  *      protection to the value specified by pval. See the documentation for
00422  *      sys_arch_protect() for more information. This function is only
00423  *      required if your port is supporting an operating system.
00424  * Inputs:
00425  *      sys_prot_t              -- Previous protection level (not used here)
00426  *---------------------------------------------------------------------------*/
00427 void sys_arch_unprotect(sys_prot_t p) {
00428     if (osMutexRelease(lwip_sys_mutex) != osOK)
00429         error("sys_arch_unprotect error\n");
00430 }
00431 
00432 u32_t sys_now(void) {
00433     return us_ticker_read() / 1000;
00434 }
00435 
00436 void sys_msleep(u32_t ms) {
00437     osDelay(ms);
00438 }
00439 
00440 // Keep a pool of thread structures
00441 static int thread_pool_index = 0;
00442 static sys_thread_data_t thread_pool[SYS_THREAD_POOL_N];
00443 
00444 /*---------------------------------------------------------------------------*
00445  * Routine:  sys_thread_new
00446  *---------------------------------------------------------------------------*
00447  * Description:
00448  *      Starts a new thread with priority "prio" that will begin its
00449  *      execution in the function "thread()". The "arg" argument will be
00450  *      passed as an argument to the thread() function. The id of the new
00451  *      thread is returned. Both the id and the priority are system
00452  *      dependent.
00453  * Inputs:
00454  *      char *name                -- Name of thread
00455  *      void (*thread)(void *arg) -- Pointer to function to run.
00456  *      void *arg                 -- Argument passed into function
00457  *      int stacksize             -- Required stack amount in bytes
00458  *      int priority              -- Thread priority
00459  * Outputs:
00460  *      sys_thread_t              -- Pointer to thread handle.
00461  *---------------------------------------------------------------------------*/
00462 sys_thread_t sys_thread_new(const char *pcName,
00463                             void (*thread)(void *arg),
00464                             void *arg, int stacksize, int priority) {
00465     LWIP_DEBUGF(SYS_DEBUG, ("New Thread: %s\n", pcName));
00466     
00467     if (thread_pool_index >= SYS_THREAD_POOL_N)
00468         error("sys_thread_new number error\n");
00469     sys_thread_t t = (sys_thread_t)&thread_pool[thread_pool_index];
00470     thread_pool_index++;
00471     
00472 #ifdef CMSIS_OS_RTX
00473     t->def.pthread = (os_pthread)thread;
00474     t->def.tpriority = (osPriority)priority;
00475     t->def.stacksize = stacksize;
00476     t->def.stack_pointer = (uint32_t*)malloc(stacksize);
00477     if (t->def.stack_pointer == NULL) {
00478       error("Error allocating the stack memory");
00479     }
00480 #endif
00481     t->id = osThreadCreate(&t->def, arg);
00482     if (t->id == NULL)
00483         error("sys_thread_new create error\n");
00484     
00485     return t;
00486 }
00487 
00488 #endif
00489 
00490 #ifdef LWIP_DEBUG
00491 
00492 /** \brief  Displays an error message on assertion
00493 
00494     This function will display an error message on an assertion
00495     to the debug output.
00496 
00497     \param[in]    msg   Error message to display
00498     \param[in]    line  Line number in file with error
00499     \param[in]    file  Filename with error
00500  */
00501 void assert_printf(char *msg, int line, char *file) {
00502     if (msg)
00503         error("%s:%d in file %s\n", msg, line, file);
00504     else
00505         error("LWIP ASSERT\n");
00506 }
00507 
00508 #endif /* LWIP_DEBUG */