Donatien Garnier / LwIPNetworking

Dependencies:   DebugLib Socket lwip lwip-sys

Dependents:   EthernetInterface

Fork of NetworkingCoreLib by Donatien Garnier

Revision:
0:013f5d54248c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/lwip/arch/sys_arch.cpp	Thu May 24 14:49:40 2012 +0000
@@ -0,0 +1,829 @@
+/* sysarch.cpp */
+/*
+Copyright (C) 2012 ARM Limited.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#define __DEBUG__ 0
+#ifndef __MODULE__
+#define __MODULE__ "sys_arch.cpp"
+#endif
+
+extern "C"
+{
+#include "lwip/opt.h"
+#include "lwip/def.h"
+#include "lwip/sys.h"
+#include "lwip/arch.h"
+#include "cc.h"
+#include "sys_arch.h"
+}
+
+#include "core/fwk.h"
+#include "rtos.h"
+#include "mbed.h" //From mbed library
+
+/*
+From http://lwip.wikia.com/wiki/Porting_for_an_OS:
+
+The sys_arch provides semaphores and mailboxes to lwIP. For the full
+lwIP functionality, multiple threads support can be implemented in the
+sys_arch, but this is not required for the basic lwIP functionality.
+*/
+
+extern "C" 
+/*
+The file is .cpp to be able to use the C++ abstraction of Mutexes, Semaphores, etc.
+however it should be linked in a C-fashion
+*/
+{
+
+#if SYS_LIGHTWEIGHT_PROT == 0
+#error "SYS_LIGHTWEIGHT_PROT must be set"
+#endif
+
+#if SYS_LIGHTWEIGHT_PROT
+//Critical regions protection
+static Mutex sys_arch_protect_mtx;
+
+sys_prot_t sys_arch_protect(void)
+{
+
+  sys_arch_protect_mtx.lock();
+
+  return 0;
+}
+
+void sys_arch_unprotect(sys_prot_t pval)
+{
+
+  LWIP_UNUSED_ARG(pval);
+  sys_arch_protect_mtx.unlock();
+
+}
+#endif
+
+//Mutexes
+
+/** Create a new mutex
+ * @param mutex pointer to the mutex to create
+ * @return a new mutex */
+err_t sys_mutex_new(sys_mutex_t *pMtx)
+{
+
+  SYS_ARCH_DECL_PROTECT(lev);
+  DBG("Trying to create new mutex");
+
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  pMtx->pMtx = new Mutex();
+  SYS_ARCH_UNPROTECT(lev);
+
+  if(pMtx->pMtx == NULL)
+  {
+    DBG("No mem");
+
+    return ERR_MEM;
+  }
+
+  pMtx->valid = true;
+
+  DBG("mutex created OK");
+
+  return ERR_OK; //Return the semaphore
+}
+
+/** Lock a mutex
+ * @param mutex the mutex to lock */
+void sys_mutex_lock(sys_mutex_t *pMtx)
+{
+
+  ((Mutex*)(pMtx->pMtx))->lock();
+
+}
+
+/** Unlock a mutex
+ * @param mutex the mutex to unlock */
+void sys_mutex_unlock(sys_mutex_t *pMtx)
+{
+
+  ((Mutex*)(pMtx->pMtx))->unlock();
+
+}
+
+/** Delete a mutex
+ * @param mutex the mutex to delete */
+void sys_mutex_free(sys_mutex_t *pMtx)
+{
+
+  SYS_ARCH_DECL_PROTECT(lev);
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  delete ((Mutex*)(pMtx->pMtx));
+  SYS_ARCH_UNPROTECT(lev);
+
+}
+
+/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_mutex_valid(sys_mutex_t *pMtx)
+{
+
+  if (pMtx->pMtx != NULL)
+  {
+
+    return pMtx->valid;
+  }
+
+  return false;
+}
+
+/** Set a mutex invalid so that sys_mutex_valid returns 0 */
+void sys_mutex_set_invalid(sys_mutex_t *pMtx)
+{
+
+  pMtx->valid = false;
+
+}
+
+//Semaphores
+
+/*
+The implementation reserves a pool of semaphores that can be used by
+LwIP in order to only use static allocation
+*/
+
+//static sys_sem sys_sem_pool[LWIP_SEMAPHORES_COUNT] = { 0 };
+
+/*
+Creates and returns a new semaphore. The count argument specifies the
+initial state of the semaphore. Returns the semaphore, or SYS_SEM_NULL
+on error.
+*/
+err_t sys_sem_new_mul(sys_sem_t *pSem, u8_t size, u8_t count)
+{
+
+  SYS_ARCH_DECL_PROTECT(lev);
+  DBG("Trying to create new semaphore of size=%d", size);
+
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  pSem->pSphre = new Semaphore(size);
+  SYS_ARCH_UNPROTECT(lev);
+  if(pSem->pSphre == NULL)
+  {
+    ERR("Failed!");
+    return ERR_MEM;
+  }
+
+  while(count < size)
+  {
+    ((Semaphore*)(pSem->pSphre))->wait();
+    count++;
+  }
+  pSem->valid = true;
+
+
+  return ERR_OK; //Return the semaphore
+}
+
+
+/*
+Creates and returns a new semaphore. The count argument specifies the
+initial state of the semaphore. Returns the semaphore, or SYS_SEM_NULL
+on error.
+*/
+err_t sys_sem_new(sys_sem_t *pSem, u8_t count)
+{
+
+  SYS_ARCH_DECL_PROTECT(lev);
+  DBG("Trying to create new semaphore of count=%d", count);
+
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  pSem->pSphre = new Semaphore(1);
+  SYS_ARCH_UNPROTECT(lev);
+  if(pSem->pSphre == NULL)
+  {
+    ERR("Failed!");
+    return ERR_MEM;
+  }
+
+  if(!count)
+  {
+    ((Semaphore*)(pSem->pSphre))->wait();
+  }
+  pSem->valid = true;
+
+
+  return ERR_OK; //Return the semaphore
+}
+
+/*
+Frees a semaphore created by sys_sem_new. Since these two functions
+provide the entry and exit point for all semaphores used by lwIP, you
+have great flexibility in how these are allocated and deallocated (for
+example, from the heap, a memory pool, a semaphore pool, etc).
+*/
+void sys_sem_free(sys_sem_t *pSem)
+{
+  SYS_ARCH_DECL_PROTECT(lev);
+  DBG("Deleting semaphore");
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  delete ((Semaphore*)(pSem->pSphre));
+  SYS_ARCH_UNPROTECT(lev);
+
+}
+
+/*
+Signals (or releases) a semaphore.
+*/
+void sys_sem_signal(sys_sem_t* pSem)
+{
+
+  ((Semaphore*)(pSem->pSphre))->release(); //Produce (i.e. release) a resource
+
+}
+
+/*
+Blocks the thread while waiting for the semaphore to be signaled. The
+timeout parameter specifies how many milliseconds the function should
+block before returning; if the function times out, it should return
+SYS_ARCH_TIMEOUT. If timeout=0, then the function should block
+indefinitely. If the function acquires the semaphore, it should return
+how many milliseconds expired while waiting for the semaphore. The
+function may return 0 if the semaphore was immediately available.
+*/
+u32_t sys_arch_sem_wait(sys_sem_t* pSem, u32_t timeout)
+{
+
+  int ret;  
+  Timer t;
+  uint32_t timeout_sphre;
+  int time_spent;
+  
+  timeout_sphre = (timeout != 0) ? timeout : osWaitForever /*block indefinitely*/;
+  
+  t.start();
+  ret = ((Semaphore*)(pSem->pSphre))->wait(timeout_sphre);
+  if(ret == 0)
+  {
+
+    return SYS_ARCH_TIMEOUT;
+  }
+  time_spent = t.read_ms();
+
+  return time_spent; 
+}
+
+/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_sem_valid(sys_sem_t *pSem)
+{
+
+  if (pSem->pSphre != NULL)
+  {
+
+    return (pSem->valid);
+  }
+
+  return false;
+}
+
+/** Set a semaphore invalid so that sys_sem_valid returns 0 */
+void sys_sem_set_invalid(sys_sem_t *pSem)
+{
+
+  pSem->valid = false;
+
+}
+
+//Mailboxes
+
+/*
+The implementation reserves a pool of mailboxes of generic (void*) type that can be used by
+LwIP in order to only use static allocation
+*/
+
+#define QUEUE_SIZE 8
+#define SYS_MBOX_SIZE QUEUE_SIZE
+#if 0
+/*
+Returns a new mailbox, or SYS_MBOX_NULL on error.
+*/
+err_t sys_mbox_new(sys_mbox_t *pMbox, int size)
+{
+
+  SYS_ARCH_DECL_PROTECT(lev);
+  ERR("Trying to create new queue of size %d", size);
+
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  if(size > QUEUE_SIZE)
+  {
+    ERR("Queue size > QUEUE_SIZE");
+  }
+  pMbox->pQueue = new Queue<void,QUEUE_SIZE>();
+  SYS_ARCH_UNPROTECT(lev);
+  if(pMbox->pQueue == NULL)
+  {
+
+    return ERR_MEM;
+  }
+  pMbox->valid = true;
+
+
+  return ERR_OK; //Return the mailbox
+}
+
+/*
+Deallocates a mailbox. If there are messages still present in the
+mailbox when the mailbox is deallocated, it is an indication of a
+programming error in lwIP and the developer should be notified.
+*/
+void sys_mbox_free(sys_mbox_t* pMbox)
+{
+  ERR("WHY??");
+
+  SYS_ARCH_DECL_PROTECT(lev);
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  delete ((Queue<void,QUEUE_SIZE>*)(pMbox->pQueue));
+  SYS_ARCH_UNPROTECT(lev);
+
+}
+
+/*
+Posts the "msg" to the mailbox.
+*/
+void sys_mbox_post(sys_mbox_t* pMbox, void *msg)
+{
+
+  if(msg == NULL)
+  {
+    ERR("NULL");
+    Thread::wait(100);
+  }
+
+  ((Queue<void,QUEUE_SIZE>*)(pMbox->pQueue))->put(msg, osWaitForever);
+
+}
+
+/*
+Blocks the thread until a message arrives in the mailbox, but does not
+block the thread longer than timeout milliseconds (similar to the
+sys_arch_sem_wait() function). The msg argument is a pointer to the
+message in the mailbox and may be NULL to indicate that the message
+should be dropped. This should return either SYS_ARCH_TIMEOUT or the
+number of milliseconds elapsed waiting for a message.
+*/
+u32_t sys_arch_mbox_fetch(sys_mbox_t* pMbox, void **msg, u32_t timeout)
+{
+  Timer t;
+  uint32_t timeout_queue;
+  int time_spent;
+  osEvent evt;
+  
+  timeout_queue = (timeout != 0) ? timeout : osWaitForever /*block indefinitely*/;
+  
+  t.start();
+  evt = ((Queue<void,QUEUE_SIZE>*)(pMbox->pQueue))->get(timeout_queue);
+  if(evt.status != osEventMessage)
+  {
+    return SYS_ARCH_TIMEOUT;
+  }
+  time_spent = t.read_ms();
+  if(msg!=NULL)
+  {
+    *msg = evt.value.p;
+  }
+  else
+  {
+    ERR("Dropped");
+    Thread::wait(100);
+  }
+  return time_spent; 
+}
+
+/*
+This is similar to sys_arch_mbox_fetch, however if a message is not
+present in the mailbox, it immediately returns with the code
+SYS_MBOX_EMPTY. On success 0 is returned with msg pointing to the
+message retrieved from the mailbox.
+*/
+u32_t sys_arch_mbox_tryfetch(sys_mbox_t* pMbox, void **msg)
+{
+
+  osEvent evt;
+
+  evt = ((Queue<void,QUEUE_SIZE>*)(pMbox->pQueue))->get(0);
+  if(evt.status != osEventMessage)
+  {
+    return SYS_MBOX_EMPTY;
+  }
+  if(msg!=NULL)
+  {
+    *msg = evt.value.p;
+  }
+  else
+  {
+    ERR("Dropped");
+    Thread::wait(100);
+  }
+
+  return ERR_OK; 
+}
+
+/*
+Tries to post a message to mbox by polling (no timeout).
+*/
+#define X() do{(*((volatile uint32_t *)0x40024048))=__LINE__;}while(0)
+#define D(d) do{(*((volatile uint32_t *)0x4002404C))=d;}while(0)
+err_t sys_mbox_trypost(sys_mbox_t* pMbox, void *msg)
+{
+  int ret;
+
+  if(msg == NULL)
+  {
+    ERR("NULL");
+    Thread::wait(100);
+  }
+
+  ret = ((Queue<void,QUEUE_SIZE>*)(pMbox->pQueue))->put(msg,0);
+  if(ret != osOK)
+  {
+    ERR("FULL");
+    return ERR_MEM; 
+  }
+
+  return ERR_OK;
+}
+
+/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_mbox_valid(sys_mbox_t *pMbox)
+{
+
+  if (pMbox->pQueue != NULL)
+  {
+
+    return (pMbox->valid);
+  }
+
+  return false;
+}
+
+/** Set an mbox invalid so that sys_mbox_valid returns 0 */
+void sys_mbox_set_invalid(sys_mbox_t *pMbox)
+{
+
+  pMbox->valid = false;
+
+}
+#else
+
+/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */
+int sys_mbox_valid(sys_mbox_t *pMbox)
+{
+  return (pMbox->valid);
+}
+
+/** Set an mbox invalid so that sys_mbox_valid returns 0 */
+void sys_mbox_set_invalid(sys_mbox_t *pMbox)
+{
+  pMbox->valid = false;
+}
+
+/*-----------------------------------------------------------------------------------*/
+err_t
+sys_mbox_new(sys_mbox_t* mb, int size)
+{
+  LWIP_UNUSED_ARG(size);
+
+  mb->first = mb->last = 0;
+  sys_sem_new(&mb->not_empty, 0);
+  sys_sem_new(&mb->not_full, 0);
+  sys_sem_new(&mb->mutex, 1);
+  mb->wait_send = 0;
+  mb->valid=true;
+
+  return ERR_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+sys_mbox_free(sys_mbox_t* mb)
+{
+  if ((mb != NULL)) {
+    sys_arch_sem_wait(&mb->mutex, 0);
+
+    sys_sem_free(&mb->not_empty);
+    sys_sem_free(&mb->not_full);
+    sys_sem_free(&mb->mutex);
+    //mb->not_empty = mb->not_full = mb->mutex = NULL;
+    mb->valid=false;
+    /*  LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+err_t
+sys_mbox_trypost(sys_mbox_t* mb, void *msg)
+{
+  u8_t first;
+  LWIP_ASSERT("invalid mbox", (mb != NULL) );
+
+  sys_arch_sem_wait(&mb->mutex, 0);
+
+  LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n",
+                          (void *)mb, (void *)msg));
+
+  if ((mb->last + 1) >= (mb->first + SYS_MBOX_SIZE)) {
+    sys_sem_signal(&mb->mutex);
+    return ERR_MEM;
+  }
+
+  mb->msgs[mb->last % SYS_MBOX_SIZE] = msg;
+
+  if (mb->last == mb->first) {
+    first = 1;
+  } else {
+    first = 0;
+  }
+
+  mb->last++;
+
+  if (first) {
+    sys_sem_signal(&mb->not_empty);
+  }
+
+  sys_sem_signal(&mb->mutex);
+
+  return ERR_OK;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+sys_mbox_post(sys_mbox_t* mb, void *msg)
+{
+  u8_t first;
+  LWIP_ASSERT("invalid mbox", (mb != NULL));
+
+  sys_arch_sem_wait(&mb->mutex, 0);
+
+  LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *)mb, (void *)msg));
+
+  while ((mb->last + 1) >= (mb->first + SYS_MBOX_SIZE)) {
+    mb->wait_send++;
+    sys_sem_signal(&mb->mutex);
+    sys_arch_sem_wait(&mb->not_full, 0);
+    sys_arch_sem_wait(&mb->mutex, 0);
+    mb->wait_send--;
+  }
+
+  mb->msgs[mb->last % SYS_MBOX_SIZE] = msg;
+
+  if (mb->last == mb->first) {
+    first = 1;
+  } else {
+    first = 0;
+  }
+
+  mb->last++;
+
+  if (first) {
+    sys_sem_signal(&mb->not_empty);
+  }
+
+  sys_sem_signal(&mb->mutex);
+}
+/*-----------------------------------------------------------------------------------*/
+u32_t
+sys_arch_mbox_tryfetch(sys_mbox_t* mb, void **msg)
+{
+  LWIP_ASSERT("invalid mbox", (mb != NULL));
+
+  sys_arch_sem_wait(&mb->mutex, 0);
+
+  if (mb->first == mb->last) {
+    sys_sem_signal(&mb->mutex);
+    return SYS_MBOX_EMPTY;
+  }
+
+  if (msg != NULL) {
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *)mb, *msg));
+    *msg = mb->msgs[mb->first % SYS_MBOX_SIZE];
+  }
+  else{
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *)mb));
+  }
+
+  mb->first++;
+
+  if (mb->wait_send) {
+    sys_sem_signal(&mb->not_full);
+  }
+
+  sys_sem_signal(&mb->mutex);
+
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+u32_t
+sys_arch_mbox_fetch(sys_mbox_t* mb, void **msg, u32_t timeout)
+{
+  u32_t time_needed = 0;
+  LWIP_ASSERT("invalid mbox", (mb != NULL));
+
+  /* The mutex lock is quick so we don't bother with the timeout
+     stuff here. */
+  sys_arch_sem_wait(&mb->mutex, 0);
+
+  while (mb->first == mb->last) {
+    sys_sem_signal(&mb->mutex);
+
+    /* We block while waiting for a mail to arrive in the mailbox. We
+       must be prepared to timeout. */
+    if (timeout != 0) {
+      time_needed = sys_arch_sem_wait(&mb->not_empty, timeout);
+
+      if (time_needed == SYS_ARCH_TIMEOUT) {
+        return SYS_ARCH_TIMEOUT;
+      }
+    } else {
+      sys_arch_sem_wait(&mb->not_empty, 0);
+    }
+    sys_arch_sem_wait(&mb->mutex, 0);
+  }
+
+  if (msg != NULL) {
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *)mb, *msg));
+    *msg = mb->msgs[mb->first % SYS_MBOX_SIZE];
+  }
+  else{
+    LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *)mb));
+  }
+
+  mb->first++;
+
+  if (mb->wait_send) {
+    sys_sem_signal(&mb->not_full);
+  }
+
+  sys_sem_signal(&mb->mutex);
+
+  return time_needed;
+}
+
+#endif
+
+//Threads and timeout lists
+
+/*
+The implementation reserves a pool of threads that can be used by
+LwIP in order to only use static allocation
+*/
+
+//sys_thread_t* lwip_system_threads = NULL; //Linked list of active threads
+//struct sys_timeo* lwip_system_timeouts = NULL; // Default timeouts list for lwIP
+
+/*
+Instanciates a thread for LwIP:
+name is the thread name. thread(arg) is the call made as the thread's
+entry point. stacksize is the recommended stack size for this thread.
+prio is the priority that lwIP asks for. Stack size(s) and priority(ies)
+are defined in lwipopts.h.
+*/
+
+struct sys_thread
+{
+  Thread* pTask;
+  //struct sys_timeo* timeouts;
+  struct sys_thread* next;
+};
+struct sys_thread* lwip_system_threads = NULL; //Linked list of active threads
+
+sys_thread_t sys_thread_new(const char *name, lwip_thread_fn fn, void *arg, int stacksize, int prio)
+{
+  SYS_ARCH_DECL_PROTECT(lev);
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  struct sys_thread* pT = new struct sys_thread;
+  SYS_ARCH_UNPROTECT(lev);
+  if(pT==NULL)
+  {
+    ERR("No mem");
+    return;
+  }
+
+  SYS_ARCH_PROTECT(lev); //Protect this section
+
+  //Link in list
+  pT->next = lwip_system_threads;
+  lwip_system_threads = pT;
+
+
+  SYS_ARCH_UNPROTECT(lev); //Protect this section
+
+  DBG("Trying to create new thread of stacksize %d and prio %d", stacksize, prio);
+
+  //Must be done at the very end because the task will start immediately
+  SYS_ARCH_PROTECT(lev);
+  pT->pTask = new Thread((void (*)(void const *argument))fn, arg, (osPriority)prio /*FIXME*/, stacksize);
+  SYS_ARCH_UNPROTECT(lev);
+
+  DBG("pT->pTask=%p", pT->pTask);
+  if(pT->pTask == NULL)
+  {
+    SYS_ARCH_PROTECT(lev);
+
+    //Unlink
+    if(pT == lwip_system_threads)
+    {
+      lwip_system_threads = pT->next;
+    }
+    else
+    {
+      struct sys_thread* pLT = lwip_system_threads;
+      while(pLT->next != pT)
+      {
+        pLT = pLT->next;
+      }
+      pLT->next = pT->next;
+    }
+    SYS_ARCH_UNPROTECT(lev); //Release protection
+    SYS_ARCH_PROTECT(lev);
+    delete pT;
+    SYS_ARCH_UNPROTECT(lev);
+    ERR("No mem");
+    return;
+  }
+
+  DBG("Thread OK");
+  return; //Return the thread
+}
+#if 0
+struct sys_timeouts *sys_arch_timeouts(void) {
+  struct sys_timeo* timeouts;
+  
+  SYS_ARCH_DECL_PROTECT(lev);
+  
+  timeouts = &lwip_system_timeouts; //If there is no match, just return the system-wide default version
+  
+  SYS_ARCH_PROTECT(lev); //Protect this section
+  
+  sys_thread_t pT = lwip_system_threads;
+
+  // Search the threads list for the thread that is currently running
+  for ( ; pT!=NULL; pT=pT->next)
+  {
+     if ( Task::isCurrent(pT->pTask) )
+     {
+      timeouts = pT->timeouts;
+     }
+  }
+  
+  SYS_ARCH_UNPROTECT(lev); //Release protection
+
+  return timeouts;
+}
+#endif
+/*
+Architecture-specific initialization.
+*/
+static Timer sys_jiffies_timer;
+
+void sys_init(void)
+{
+  sys_jiffies_timer.start();
+}
+
+/*
+Used by PPP as a timestamp-ish value.
+*/
+u32_t sys_jiffies(void)
+{
+  static u32_t jiffies = 0;
+  jiffies += 1 + sys_jiffies_timer.read_ms()/10;
+  sys_jiffies_timer.reset();
+
+  return jiffies;
+}
+
+/**
+ * Sleep for some ms. Timeouts are NOT processed while sleeping.
+ *
+ * @param ms number of milliseconds to sleep
+ */
+//Change DG, arch specific
+void
+sys_msleep(u32_t ms)
+{
+  Thread::wait(ms);
+}
+
+} //extern "C"