text: /* Copyright (c) 2019 Unisoc Communications Inc.
   * SPDX-License-Identifier: Apache-2.0
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #if 1
  #include "sys_arch.h"
  #include "cmsis_os.h"
  #include "cmsis_os2.h"
  #include "lwip/sys.h"
  #include "rtx_lib.h"
  
  #include <stdio.h>
  #include <string.h>
  #include "mbed_assert.h"
  #define NO_ERR  0
  #define ERR     -1
  
  //#define RDA_SYS_DEBUG
  #ifdef RDA_SYS_DEBUG
  #define RDA_SYS_PRINT(fmt, ...) do {\
              printf(fmt, ##__VA_ARGS__);\
      } while (0)
  #else
  #define RDA_SYS_PRINT(fmt, ...)
  #endif
  
  
  /* Alarm */
  // Timer definitions
  #define osTimerInvalid  0
  #define osTimerStopped  1
  #define osTimerRunning  2
  #if 0
  // Timer structures, same as os_timer_cb(rt_CMSIS.c)
  typedef struct rda_ostmr_cb {
      struct rda_ostmr_cb *next;                    // Pointer to next active Timer
      uint8_t             state;                    // Timer State
      uint8_t              type;                    // Timer Type (Periodic/One-shot)
      uint16_t         reserved;                    // Reserved
      uint32_t             tcnt;                    // Timer Delay Count
      uint32_t             icnt;                    // Timer Initial Count
      void                 *arg;                    // Timer Function Argument
      const osTimerDef_t *timer;                    // Pointer to Timer definition
  } rda_ostmr_cb_t;
  #endif
  //#define USING_STDLIB
  
  #if !defined(USING_STDLIB)
  typedef struct rda_tmr_node {
      mbed_rtos_storage_timer_t _obj_mem;
  } rda_tmr_node_t;
  
  typedef struct rda_tmr_ctrl {
      unsigned char *buff;
      unsigned char *state;
      unsigned char max_node_num;
      unsigned char node_size;
      unsigned char node_cntr;
      unsigned char last_freed_node_idx;
  } rda_tmr_ctrl_t;
  
  #define MAX_ALARM_NUM       (28)
  #define WORD_ALIGN(n)       (((n) + 0x03UL) & ~0x03UL)
  #define MAX_ALARM_STAT_SIZE WORD_ALIGN(MAX_ALARM_NUM >> 3)
  #define MAX_ALARM_MEM_SIZE  (MAX_ALARM_NUM * WORD_ALIGN(sizeof(mbed_rtos_storage_timer_t)) + MAX_ALARM_STAT_SIZE)
  
  unsigned long g_alarm_buf[WORD_ALIGN(MAX_ALARM_MEM_SIZE) >> 2] = {0};
  rda_tmr_ctrl_t g_alarm_ctrl = {
      (unsigned char *)g_alarm_buf + MAX_ALARM_STAT_SIZE,
      (unsigned char *)g_alarm_buf,
      MAX_ALARM_NUM,
      WORD_ALIGN(sizeof(mbed_rtos_storage_timer_t)),
      0U,
      0U
  };
  
  __STATIC_INLINE unsigned char get_node_state(unsigned char *buf, unsigned char idx)
  {
      unsigned char state, ofst;
      ofst = (idx & 0x07U);
      buf += (idx >> 3);
      state = (*buf >> ofst) & 0x01U;
      return state;
  }
  
  __STATIC_INLINE void set_node_state(unsigned char *buf, unsigned char idx, unsigned char state)
  {
      unsigned char ofst, tmp;
      ofst = (idx & 0x07U);
      buf += (idx >> 3);
      tmp = *buf & (~(0x01U << ofst));
      *buf = tmp | (((state & 0x01U) << ofst));
  }
  
  static rda_tmr_node_t *get_tmr_node(void)
  {
      rda_tmr_node_t *node = NULL;
      unsigned char idx = g_alarm_ctrl.last_freed_node_idx;
      if ((idx < g_alarm_ctrl.max_node_num) && (0U == get_node_state(g_alarm_ctrl.state, idx))) {
          set_node_state(g_alarm_ctrl.state, idx, 1U);
          node = (rda_tmr_node_t *)(g_alarm_ctrl.buff + idx * g_alarm_ctrl.node_size);
          g_alarm_ctrl.node_cntr++;
      } else {
          for (idx = 0U; idx < g_alarm_ctrl.max_node_num; idx++) {
              if(0U == get_node_state(g_alarm_ctrl.state, idx)) {
                  set_node_state(g_alarm_ctrl.state, idx, 1U);
                  node = (rda_tmr_node_t *)(g_alarm_ctrl.buff + idx * g_alarm_ctrl.node_size);
                  g_alarm_ctrl.node_cntr++;
                  break;
              }
          }
      }
      return node;
  }
  
  static void put_tmr_node(rda_tmr_node_t *node)
  {
      unsigned char *node_buf = (unsigned char *)node;
      unsigned char idx = (node_buf - g_alarm_ctrl.buff) / g_alarm_ctrl.node_size;
      if ((node_buf > g_alarm_ctrl.buff) && (idx < g_alarm_ctrl.max_node_num) &&
          (1U == get_node_state(g_alarm_ctrl.state, idx))) {
          set_node_state(g_alarm_ctrl.state, idx, 0U);
          g_alarm_ctrl.node_cntr--;
          g_alarm_ctrl.last_freed_node_idx = idx;
      }
  }
  #endif /* !USING_STDLIB */
  
  /**
   * @brief     : get current time in units of micro second
   * @param[in] :
   * @param[out]:
   * @return    : return time value with uint32 type
   */
  unsigned long rda_get_cur_time_ms(void)
  {
      return sys_now();
  }
  
  /**
   * @brief     : create an alarm with given function, return timer handle
   * @param[in] : func(callback)/data(pass to func)/mode(once or periodic)
   * @param[out]:
   * @return    : return timer handle, a pointer to the timer structure, non-zero is valid
   */
  void * rda_alarm_create_v2(void *func, unsigned int data, unsigned int mode)
  {
      osTimerId_t handle;
      mbed_rtos_storage_timer_t* _obj_mem = NULL;
      MBED_ASSERT(func != NULL);
      osTimerAttr_t attr = { 0 };
  #if defined(USING_STDLIB)
      _obj_mem = (mbed_rtos_storage_timer_t*)malloc(sizeof(mbed_rtos_storage_timer_t));
  #else  /* USING_STDLIB */
      _obj_mem = (mbed_rtos_storage_timer_t*)get_tmr_node();
  #endif /* USING_STDLIB */
      MBED_ASSERT(_obj_mem != NULL);
      memset(_obj_mem, 0, sizeof(_obj_mem));
      attr.cb_mem = _obj_mem;
      attr.cb_size = sizeof(mbed_rtos_storage_timer_t);
      //printf("hehehehe fun %p\r\n", func);
      handle = osTimerNew((osTimerFunc_t)func, mode, (void *)data, &attr);
      //printf("time cb %p handle %p\r\n", _obj_mem, handle);
      MBED_ASSERT(handle != NULL);
      return handle;
  }
  
  void * rda_alarm_create(void *func, unsigned int data)
  {
      return rda_alarm_create_v2(func, data, osTimerOnce);
  }
  
  /**
   * @brief     : delete an alarm with given handle, then reset the handle
   * @param[in] : *handle(pointer to the timer structure)
   * @param[out]: **handle(address of the handle variable)
   * @return    :
   */
  int rda_alarm_delete(void **handle)
  {
      if (NULL != *handle) {
          osTimerId timer_id = (osTimerId)(*handle);
          osStatus retval = osTimerDelete(timer_id);
          if (osOK == retval) {
  #if defined(USING_STDLIB)
              free(timer_id);
  #else  /* USING_STDLIB */
              put_tmr_node((rda_tmr_node_t *)timer_id);
  #endif /* USING_STDLIB */
              *handle = NULL;
          } else {
              RDA_SYS_PRINT("Delete alarm error: %d\r\n", retval);
              return ERR;
          }
          return NO_ERR;
      }
      return ERR;
  }
  
  /**
   * @brief     : start an alarm, raise a function call after given timeout delay
   * @param[in] : handle(pointer to the timer structure)/timeout(micro second)
   * @param[out]:
   * @return    :
   */
  int rda_alarm_start(void *handle, unsigned int timeout_ms)
  {
      if (NULL != handle) {
          osTimerId timer_id = (osTimerId)handle;
          osStatus retval = osTimerStart(timer_id, (uint32_t)timeout_ms);
          if (osOK != retval) {
              RDA_SYS_PRINT("Start alarm error: %d\r\n", retval);
              return ERR;
          }
          return NO_ERR;
      }
      return ERR;
  }
  
  /**
   * @brief     : stop an alarm, will not raise a function call any more
   * @param[in] : handle(pointer to the timer structure)
   * @param[out]:
   * @return    :
   */
  int rda_alarm_stop(void *handle)
  {
      if (NULL != handle) {
          osTimerId timer_id = (osTimerId)handle;
          osStatus retval = osTimerStop(timer_id);
          if (osOK != retval) {
              RDA_SYS_PRINT("Stop alarm error: %d\r\n", retval);
              return ERR;
          }
          return NO_ERR;
      }
      return ERR;
  }
  
  
  
  /* Semaphore */
  void* rda_sem_create(unsigned int count)
  {
      osSemaphoreId_t sem;
      mbed_rtos_storage_semaphore_t *_obj_mem = (mbed_rtos_storage_semaphore_t*)malloc(sizeof(mbed_rtos_storage_semaphore_t));
      osSemaphoreAttr_t attr = { 0 };
      attr.name = "rda_unnamed_sem";
      attr.cb_mem = _obj_mem;
      attr.cb_size = sizeof(mbed_rtos_storage_semaphore_t);
      sem = osSemaphoreNew(1, count, &attr);
      MBED_ASSERT(sem != NULL);
  
      return (void*)sem;
  }
  
  int rda_sem_wait(void* sem, unsigned int millisec)
  {
      int res;
  
      res = osSemaphoreWait(sem, millisec);
      if (res > 0) {
          return NO_ERR;
      } else {
          RDA_SYS_PRINT("rda_sem_wait error %d\r\n", res);
          return ERR;
      }
  }
  
  int rda_sem_release(void *sem)
  {
      int res;
  
      res = osSemaphoreRelease(sem);
      if (res == 0) {
          return NO_ERR;
      } else {
          RDA_SYS_PRINT("rda_sem_release error %d\r\n", res);
          return ERR;
      }
  }
  
  int rda_sem_delete(void *sem)
  {
      int res;
  
      res = osSemaphoreDelete(sem);
      free(sem);
      if (res == 0) {
          return NO_ERR;
      } else {
          RDA_SYS_PRINT("rda_sem_delete error %d\r\n", res);
          return ERR;
      }
  }
  
  /* Mail */
  void* rda_mail_create(unsigned int msgcnt, unsigned int msgsize)
  {
      unsigned int mq_size = msgcnt * (msgsize + sizeof(os_message_t));
      osMessageQueueId_t msgq;
      mbed_rtos_storage_msg_queue_t *_obj_mem = (mbed_rtos_storage_msg_queue_t*)malloc(sizeof(mbed_rtos_storage_msg_queue_t));
      MBED_ASSERT(_obj_mem != NULL);
      memset(_obj_mem, 0, sizeof(mbed_rtos_storage_msg_queue_t));
      void *_mq_mem = (void *)malloc(mq_size);
      MBED_ASSERT(_mq_mem != NULL);
      memset(_mq_mem, 0, mq_size);
      osMessageQueueAttr_t attr = { 0 };
      attr.name = "rda_unnamed_message_queue";
      attr.cb_mem = _obj_mem;
      attr.cb_size = sizeof(mbed_rtos_storage_msg_queue_t);
      attr.mq_mem = _mq_mem;
      attr.mq_size = mq_size;
      msgq = osMessageQueueNew(msgcnt, msgsize, &attr);
      MBED_ASSERT(msgq != NULL);
  
      return (void*)msgq;
  }
  
  int rda_mail_get(void *msgq, void *msg, unsigned int wait)
  {
      int ret;
      ret = osMessageQueueGet(msgq, msg, 0, wait);
      return ret;
  }
  
  int rda_mail_put(void *msgq, void *msg, unsigned int wait)
  {
      int ret;
      ret = osMessageQueuePut(msgq, msg, 0, wait);
      return ret;
  }
  
  /* Mutex */
  void* rda_mutex_create(void)
  {
      osMutexId_t rdamutex;
      osMutexAttr_t attr = { 0 };
      mbed_rtos_storage_mutex_t *_obj_mem = (mbed_rtos_storage_mutex_t *)malloc(sizeof(mbed_rtos_storage_mutex_t));
      memset(_obj_mem, 0, sizeof(mbed_rtos_storage_mutex_t));
      attr.name = "rda_unnamed_mutex";
      attr.cb_mem = _obj_mem;
      attr.cb_size = sizeof(mbed_rtos_storage_mutex_t);
      attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
      rdamutex = osMutexNew(&attr);
      MBED_ASSERT(rdamutex != NULL);
      return (void *)rdamutex;
  }
  
  int rda_mutex_wait(void *rdamutex, unsigned int millisec)
  {
      osMutexId_t mutex = (osMutexId_t)rdamutex;
      osStatus res;
      res = osMutexWait(mutex, millisec);
      if (res == osOK) {
          return NO_ERR;
      } else {
          return ERR;
      }
  }
  
  int rda_mutex_realease(void *rdamutex)
  {
      osMutexId_t mutex = (osMutexId_t)rdamutex;
      osStatus res;
      res = osMutexRelease(mutex);
      if(res == osOK) {
          return NO_ERR;
      } else {
          return ERR;
      }
  }
  
  int rda_mutex_delete(void *rdamutex)
  {
      osMutexId_t mutex = (osMutexId_t)rdamutex;
      osStatus res;
      res = osMutexDelete(mutex);
      free(mutex);
      if (res == osOK) {
          return NO_ERR;
      } else {
          return ERR;
      }
  }
  
  /* Thread */
  void* rda_thread_new(const char *pcName,
                              void (*thread)(void *arg),
                              void *arg, int stacksize, int priority)
  {
      osThreadId_t     id;
      osThreadAttr_t   _attr = { 0 };
      mbed_rtos_storage_thread_t *_obj_mem = (mbed_rtos_storage_thread_t *)malloc(sizeof(mbed_rtos_storage_thread_t));
      MBED_ASSERT(_obj_mem != NULL);
      memset(_obj_mem, 0, sizeof(mbed_rtos_storage_thread_t));
      _attr.priority = priority;
      _attr.stack_size = stacksize;
      _attr.name = pcName ? pcName : "rda_unnamed_thread";
      _attr.stack_mem = malloc(stacksize);
      MBED_ASSERT(_attr.stack_mem != NULL);
      _attr.cb_size = sizeof(mbed_rtos_storage_thread_t);
      _attr.cb_mem = _obj_mem;
      _attr.tz_module = 0;
      
      //Fill the stack with a magic word for maximum usage checking
      for (uint32_t i = 0; i < (_attr.stack_size / sizeof(uint32_t)); i++) {
          ((uint32_t *)_attr.stack_mem)[i] = 0xE25A2EA5;
      }
      id = osThreadNew(thread, arg, &_attr);
      if (id == NULL){
          free(_attr.stack_mem);
          free(_attr.cb_mem);
          RDA_SYS_PRINT("sys_thread_new create error\n");
          return NULL;
      }
      return (void *)id;
  }
  
  int rda_thread_delete(void* id)
  {
      osStatus ret;
      unsigned int *stk = ((osRtxThread_t *)id)->stack_mem;
      ret = osThreadTerminate(id);
      free(id);
      free(stk);
      if (ret != osOK) {
          return ERR;
      }
      return NO_ERR;
  }
  
  void* rda_thread_get_id(void)
  {
      osThreadId id = osThreadGetId();
      return (void*)id;
  }
  #endif
  