Skip to content

Porting picoTCP OS

Daniele Lacamera edited this page Jun 10, 2018 · 2 revisions

Porting to a new Operating System

Overview

When using picoTCP in combination with an operating system, your system looks roughly like this:

The application can interface with the OS, picotcp, and picotcp-bsd through their respective APIs. You should already be familiar with the API of your OS of choice and the one from picoTCP.

picotcp-bsd is an extra library that will provide POSIX/BSD/Berkeley style sockets, on top of the native picoTCP API, using the OS's facilities.

Porting picoTCP to an operating system basically consists of a few things:

  1. Writing an interface for picotcp-bsd to the OS.
  2. Optionally modifying the device driver to play nice with the OS.
  3. Using the picotcp-bsd interface, instead of native picotcp API.

1. Writing the picotcp-bsd interface

picotcp-bsd will use a few primitives from your OS, and you should implement wrappers to init/use/destroy these. Namely: mutexes, signals and optionally threads.

Mutexes

void * pico_mutex_init(void);

Used to create a mutex native to the OS, and wraps it in an opaque 'mutex void pointer'. Returns NULL in case of failure.


void pico_mutex_deinit(void * mutex);

Destroys and frees a mutex previously created using pico_mutex_init.


void pico_mutex_lock(void * mutex);

Tries to lock a mutex, and will block without a timeout until it becomes available.


int  pico_mutex_lock_timeout(void * mutex, int timeout);

Same as pico_mutex_lock but will give up after timeout, which is specified in milliseconds.


void pico_mutex_unlock(void * mutex);

Unlocks a previously locked mutex.


Signals

void * pico_signal_init(void);

Used to create a signal (or semaphore) native to the OS, and wraps it in an opaque 'signal void pointer'. Returns NULL in case of failure.


void pico_signal_deinit(void * signal);

Destroys and frees a signal previously created using pico_signal_init.


void pico_signal_wait(void * signal);

Wait for a signal to be sent, blocking indefinitely until it gets the signal.


int  pico_signal_wait_timeout(void * signal, int timeout);

Same as pico_signal_wait but will give up after timeout, which is specified in milliseconds.


void pico_signal_send(void * signal);

Sends a signal, so another thread waiting for this signal gets unblocked.


Threads

NOTE: These are actually not used by picotcp-bsd yet, but can provide a nice unified API towards your application when porting across different OSes.

pico_thread_t pico_thread_create(pico_thread_fn thread, void *arg, int stack_size, int prio);
void pico_thread_destroy(pico_thread_t t);
void pico_threads_schedule(void);
void pico_msleep(int ms);

2. Device driver modifications

Driver and OS specific. E.g. send a signal/semaphore from the ISR, to wake up a thread that will enqueue packets into the stack.

3. Using picotcp-bsd interface

The picotcp-bsd interface needs to be initialized, after pico_stack_init, using pico_bsd_init. Also, instead of using pico_stack_tick, one should use the picotcp-bsd version instead: pico_bsd_stack_tick.

void main(void)
{
    pico_stack_init();
    pico_bsd_init();

    /* other initialization code */

    for (;;) {
        pico_bsd_stack_tick();
    }
}

After this, a second thread/task can be created, that can use all of the POSIX/BSD/Berkeley socket API function provided by picotcp-bsd.

E.g.:

static int init_server(void)
{
    struct sockaddr_in srv = { 0 };
    int sock_fd;

    srv.sin_family = AF_INET;
    srv.sin_addr.s_addr = INADDR_ANY;
    srv.sin_port = short_be(7);

    sock_fd = pico_newsocket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0)
        panic();

    if (pico_bind(sock_fd, (struct sockaddr *)&srv, sizeof(struct sockaddr_in)) < 0)
        panic();

    if (pico_listen(sock_fd, 2) < 0)
        panic();
    /* more code */
}
Clone this wiki locally