blob: 1389a0f29735fb8f773d6d6d46c244de44b680ab [file] [log] [blame]
/****************************************************************************
* arch/arm/src/nrf91/nrf91_modem_os.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <arch/irq.h>
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
#include <nuttx/signal.h>
#include <nuttx/mm/mm.h>
#include <debug.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include "nrf_modem.h"
#include "nrf_modem_os.h"
#include "nrf91_modem.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define NRF_ESHUTDOWN 110
#define NRF91_MODEM_WAITING_PREALLOC (32)
/****************************************************************************
* Private Types
****************************************************************************/
struct nrf91_modem_os_waiting_s
{
sem_t sem;
uint32_t context;
bool waiting;
struct timespec ts_start;
};
struct nrf91_modem_os_s
{
sem_t sem[NRF_MODEM_OS_NUM_SEM_REQUIRED];
uint8_t sem_cntr;
mutex_t waiting_lock;
struct nrf91_modem_os_waiting_s waiting[NRF91_MODEM_WAITING_PREALLOC];
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
static struct nrf91_modem_os_s g_nrf91_modem_os;
static struct mm_heap_s *g_shmtxheap = NULL;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: nrf_waiting_get
****************************************************************************/
struct nrf91_modem_os_waiting_s *nrf_waiting_get(void)
{
struct nrf91_modem_os_waiting_s *ret = NULL;
int i = 0;
nxmutex_lock(&g_nrf91_modem_os.waiting_lock);
for (i = 0; i < NRF91_MODEM_WAITING_PREALLOC; i++)
{
if (g_nrf91_modem_os.waiting[i].waiting == false)
{
ret = &g_nrf91_modem_os.waiting[i];
nxsem_init(&ret->sem, 0, 0);
break;
}
}
nxmutex_unlock(&g_nrf91_modem_os.waiting_lock);
return ret;
}
/****************************************************************************
* Name: nrf_waiting_free
****************************************************************************/
void nrf_waiting_free(struct nrf91_modem_os_waiting_s *w)
{
nxmutex_lock(&g_nrf91_modem_os.waiting_lock);
nxsem_destroy(&w->sem);
w->context = 0;
w->waiting = false;
nxmutex_unlock(&g_nrf91_modem_os.waiting_lock);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nrf_modem_os_init
*
* Description:
* Initialize the glue layer.
*
****************************************************************************/
void nrf_modem_os_init(void)
{
memset(&g_nrf91_modem_os, 0, sizeof(struct nrf91_modem_os_s));
/* Initialize shared memory TX heap */
g_shmtxheap = mm_initialize("shmtx",
(void *) NRF91_SHMEM_TX_BASE,
NRF91_SHMEM_TX_SIZE);
nxmutex_init(&g_nrf91_modem_os.waiting_lock);
}
/****************************************************************************
* Name: nrf_modem_os_shutdown
*
* Description:
* Deinitialize the glue layer.
*
* When shutdown is called, all pending calls to @c nrf_modem_os_timedwait
* shall exit and return -NRF_ESHUTDOWN.
*
****************************************************************************/
void nrf_modem_os_shutdown(void)
{
struct nrf91_modem_os_waiting_s *waiting = NULL;
int i = 0;
/* TODO: send AT+CFUN=0 */
/* Wake up all waiting semaphores */
for (i = 0; i < NRF91_MODEM_WAITING_PREALLOC; i++)
{
waiting = &g_nrf91_modem_os.waiting[i];
if (waiting->waiting == true)
{
nxsem_post(&waiting->sem);
}
}
/* Uninitialize shared memory TX heap */
mm_uninitialize(g_shmtxheap);
}
/****************************************************************************
* Name: nrf_modem_os_shm_tx_alloc
*
* Description:
* Allocate a buffer on the TX area of shared memory.
*
****************************************************************************/
void *nrf_modem_os_shm_tx_alloc(size_t bytes)
{
return mm_malloc(g_shmtxheap, bytes);
}
/****************************************************************************
* Name: nrf_modem_os_shm_tx_free
*
* Description:
* Free a shared memory buffer in the TX area.
*
****************************************************************************/
void nrf_modem_os_shm_tx_free(void *mem)
{
mm_free(g_shmtxheap, mem);
}
/****************************************************************************
* Name: nrf_modem_os_alloc
*
* Description:
* Allocate a buffer on the library heap.
*
****************************************************************************/
void *nrf_modem_os_alloc(size_t bytes)
{
return malloc(bytes);
}
/****************************************************************************
* Name: nrf_modem_os_free
*
* Description:
* Free a memory buffer in the library heap.
*
****************************************************************************/
void nrf_modem_os_free(void *mem)
{
free(mem);
}
/****************************************************************************
* Name: nrf_modem_os_busywait
*
* Description:
* Busy wait.
*
****************************************************************************/
void nrf_modem_os_busywait(int32_t usec)
{
up_udelay(usec);
}
/****************************************************************************
* Name: nrf_modem_os_timedwait
*
* Description:
* Put a thread to sleep for a specific time or until an event occurs.
*
****************************************************************************/
int32_t nrf_modem_os_timedwait(uint32_t context, int32_t *timeout)
{
struct nrf91_modem_os_waiting_s *waiting = NULL;
struct timespec ts_now;
struct timespec abstime;
int32_t remaining = 0;
int32_t diff = 0;
int ret = -EAGAIN;
/* Modem is not initialized or was shut down */
if (!nrf_modem_is_initialized())
{
ret = -NRF_ESHUTDOWN;
goto errout;
}
if (*timeout == 0)
{
ret = -EAGAIN;
goto errout;
}
/* Get free waiting slot */
waiting = nrf_waiting_get();
if (waiting == NULL)
{
ret = -ENOMEM;
goto errout;
}
waiting->context = context;
waiting->waiting = true;
clock_systime_timespec(&waiting->ts_start);
if (*timeout < 0)
{
/* Wait for event */
nxsem_wait(&waiting->sem);
ret = OK;
}
else
{
/* Wait for event or timeout */
abstime.tv_sec = *timeout / 1000;
abstime.tv_nsec = (*timeout % 1000) * 1000000;
nxsem_timedwait(&waiting->sem, &abstime);
}
/* Free a waiting slot */
nrf_waiting_free(waiting);
/* Modem is not initialized or was shut down */
if (!nrf_modem_is_initialized())
{
ret = -NRF_ESHUTDOWN;
goto errout;
}
/* Handle timeout */
if (ret < 0)
{
clock_systime_timespec(&ts_now);
diff = ((ts_now.tv_sec - waiting->ts_start.tv_sec) * 1000 +
(ts_now.tv_nsec - waiting->ts_start.tv_nsec) / 1000000);
remaining = *timeout - diff;
/* Return remaining timeout */
*timeout = (remaining > 0) ? remaining : 0;
if (*timeout == 0)
{
ret = -EAGAIN;
}
}
errout:
return ret;
}
/****************************************************************************
* Name: nrf_modem_os_event_notify
*
* Description:
* Notify the application that an event has occurred.
*
****************************************************************************/
void nrf_modem_os_event_notify(uint32_t context)
{
struct nrf91_modem_os_waiting_s *waiting = NULL;
int i = 0;
for (i = 0; i < NRF91_MODEM_WAITING_PREALLOC; i++)
{
waiting = &g_nrf91_modem_os.waiting[i];
if (waiting->waiting == true)
{
if (waiting->context == context || context == 0)
{
nxsem_post(&waiting->sem);
}
}
}
}
/****************************************************************************
* Name: nrf_modem_os_sleep
*
* Description:
* Put a thread to sleep for a specific amount of time.
*
****************************************************************************/
int nrf_modem_os_sleep(uint32_t timeout)
{
/* Timeout in ms */
nxsig_usleep(timeout * 1000);
return OK;
}
/****************************************************************************
* Name: nrf_modem_os_errno_set
*
* Description:
* Set errno.
*
****************************************************************************/
void nrf_modem_os_errno_set(int errno_val)
{
set_errno(errno_val);
}
/****************************************************************************
* Name: nrf_modem_os_is_in_isr
*
* Description:
* Check if executing in interrupt context.
*
****************************************************************************/
bool nrf_modem_os_is_in_isr(void)
{
return up_interrupt_context();
}
/****************************************************************************
* Name: nrf_modem_os_sem_init
*
* Description:
* Initialize a semaphore.
*
****************************************************************************/
int nrf_modem_os_sem_init(void **sem, unsigned int initial_count,
unsigned int limit)
{
sem_t *modemsem = &g_nrf91_modem_os.sem[g_nrf91_modem_os.sem_cntr];
int ret = OK;
UNUSED(limit);
DEBUGASSERT(g_nrf91_modem_os.sem_cntr < NRF_MODEM_OS_NUM_SEM_REQUIRED);
ret = nxsem_init(modemsem, 0, initial_count);
g_nrf91_modem_os.sem_cntr++;
*sem = (void *)modemsem;
return ret;
}
/****************************************************************************
* Name: nrf_modem_os_sem_give
*
* Description:
* Give a semaphore.
*
****************************************************************************/
void nrf_modem_os_sem_give(void *sem)
{
nxsem_post((sem_t *)sem);
}
/****************************************************************************
* Name: nrf_modem_os_sem_take
*
* Description:
* Take a semaphore.
*
****************************************************************************/
int nrf_modem_os_sem_take(void *sem, int timeout)
{
int ret = OK;
sem_t *s = sem;
if (timeout == -1)
{
ret = nxsem_wait(s);
}
else
{
struct timespec abstime;
abstime.tv_sec = timeout / 1000;
abstime.tv_nsec = (timeout % 1000) * 1000000;
ret = nxsem_timedwait(s, &abstime);
}
return ret;
}
/****************************************************************************
* Name: nrf_modem_os_sem_count_get
*
* Description:
* Get a semaphore's count.
*
****************************************************************************/
unsigned int nrf_modem_os_sem_count_get(void *sem)
{
int sval = 0;
nxsem_get_value((sem_t *)sem, &sval);
return sval;
}
/****************************************************************************
* Name: nrf_modem_os_log
*
* Description:
* Generic logging procedure.
*
****************************************************************************/
void nrf_modem_os_log(int level, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsyslog(level, fmt, ap);
va_end(ap);
}
/****************************************************************************
* Name: nrf_modem_os_logdump
*
* Description:
* Logging procedure for dumping hex representation of object.
*
****************************************************************************/
void nrf_modem_os_logdump(int level, const char *str, const void *data,
size_t len)
{
syslog(level, "nrf_modem_os_logdump");
lib_dumpbuffer(str, data, len);
}