lwip-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lwip-users] Best way to send sensor data from RAW sockets


From: Paul Archer
Subject: Re: [lwip-users] Best way to send sensor data from RAW sockets
Date: Wed, 7 Mar 2012 08:42:32 +1100

On Wed, Mar 7, 2012 at 4:08 AM, address@hidden <address@hidden> wrote:
> Just for clarity: I'm assuming you mean using a raw API udp pcb here (as
> opposed to "BSD" sockets in raw mode, i.e. not UDP or TCP but another,
> application-managed transport protocol)?

To avoid confusion here is the source code for my module (maybe
someone can make use of it in the future, under BSD license)

/**
 * \defgroup MODULES_WALKIETALKIED WalkieTalkied
 * \ingroup MODULES
 * \{
 */
/*****************************************************************************
 *                          D E F I N E S
 ****************************************************************************/
#define WALKIETALKIED_PORT        1234
#define WALKIETALKIED_QUEUE_LEN   64

/*****************************************************************************
 *                            T Y P E S
 ****************************************************************************/
typedef struct {
    struct udp_pcb *pcb;    /**< */
    uint16_t seq_num;
} WalkieTalkied_State_t;

typedef struct {
    ADPCM_State_t adpcm_state;
    uint16_t seq_num;
    size_t nsamples;
} WalkieTalkie_Packet_t;

/*****************************************************************************
 *                 F U N C T I O N     P R O T O T Y P E S
 ****************************************************************************/

/*****************************************************************************
 *                     G L O B A L     V A R I A B L E S
 ****************************************************************************/
#define WALKIETALKIED_BUFFER_SIZE 5
struct pbuf *WalkieTalkied_RecvBuffer[WALKIETALKIED_BUFFER_SIZE];

/****************************************************************************/
/**
 *
 */
static void WalkieTalkied_Recv(void *arg, struct udp_pcb *pcb, struct
pbuf *p, struct ip_addr *addr, u16_t port)
{
    WalkieTalkied_State_t *state = (WalkieTalkied_State_t *)arg;
    struct pbuf *q;
    WalkieTalkie_Packet_t *pkt;

    LWIP_UNUSED_ARG(pcb);
    LWIP_UNUSED_ARG(addr);
    LWIP_UNUSED_ARG(port);

    syslog(LOG_DEBUG, "Recved %d bytes from %d.%d.%d.%d:%d",
            p->tot_len,
            ip4_addr1(addr), ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr),
            ntohs(port));

    /* Can't handle a packet over two pbufs */
    pkt = p->payload;
    if (p->len < sizeof(*pkt)) {
        syslog(LOG_ERR, "First pbuf is only %d bytes (needs to be %d bytes)",
                p->len, sizeof(*pkt));
        pbuf_free(p);
        return;
    }

    /* TODO: Need to place it in the circular buffer */
    /* TODO: Use state->seq_num to calculate where in the circular buffer */
    WalkieTalkied_RecvBuffer[0] = p;

    /* Check the sequence numbers */
    while (WalkieTalkied_RecvBuffer[0]) {
        uint16_t pbuf_bytes = sizeof(*pkt);
        size_t nsamples     = 0;
        p = WalkieTalkied_RecvBuffer[0];

        /* Process the data */
        for (q = p; q != NULL; q = q->next) {
            uint16_t i;

            for (i = pbuf_bytes; i < q->len; i++) {
                uint8_t code = ((uint8_t *)q->payload)[i];

                if (nsamples < pkt->nsamples) {
                    uint8_t  in;
                    uint16_t out;

                    in = pkt->nsamples % 2 ?
                        (code & 0xF0) >> 4: (code & 0x0F) >> 0;
                    out = ADPCM_Decode(&(pkt->adpcm_state), in);

                    /* TODO: Give the out sample to the DAC */
                    DTRACE("out = 0x%04x", out);
                    nsamples++;
                }
            }

            HEXDUMP(LOG_DEBUG, "walkied_rx", q->payload, q->len, true);
            pbuf_bytes = 0;
        }

        state->seq_num = pkt->seq_num;

        /* Free it and update the circular buffer */
        pbuf_free(WalkieTalkied_RecvBuffer[0]);
        WalkieTalkied_RecvBuffer[0] = NULL;
    }

}

static void WalkieTalkied_Timer(void *arg)
{
    WalkieTalkied_State_t *state = (WalkieTalkied_State_t *) arg;

    /* Re-add the timer */
    sys_timeout(100, WalkieTalkied_Timer, state);

    /* TODO: Read from the queue here and form a UDP packet to send */
}

/**
 * This is a callback function to allow the lwIP thread to create
 * the raw UDP socket.
 *
 * \param[in] arg
 */
static void WalkieTalkied_CreateSocket(void *arg)
{
    WalkieTalkied_State_t *state = NULL;
    struct udp_pcb            *pcb   = NULL;

    LWIP_UNUSED_ARG(arg);

    if ((pcb = udp_new()) == NULL) {
        goto create_error;
    }

    udp_bind(pcb, IP_ADDR_ANY, WALKIETALKIED_PORT);

    /* Allocate a state variable with the socket */
    if ((state = calloc(1, sizeof(*state))) == NULL) {
        goto create_error;
    }
    state->pcb = pcb;

    /* Setup the callbacks */
    udp_recv(pcb, WalkieTalkied_Recv, state);
    sys_timeout(10, WalkieTalkied_Timer, state);

    return;

create_error:
    if (state) {
        free(state);
    }
    if (pcb) {
        udp_remove(pcb);
    }

    return;
}

/**
 * Initialise the Walkie Talkie server
 */
void WalkieTalkied_Init(void)
{
    tcpip_callback(WalkieTalkied_CreateSocket, NULL);
}

/** \} */

>> My question is, what is the best way for my audio data to get into a
>> packet and send it?
> I guess the best way is still using sys_timeout(). There's of course nothing
> wrong with correct programming layering. As it seems you are currently using
> some kind of queue for that, you can either
> - wait on that queue and then call tcpip_callback() when you know you want
> to send a packet or
> - convert your API from queue handling to a more generic interface, then
> your queue can be one kind to implement that interface, collecting packet
> data and calling tcpip_callback() to send a packet would be another way to
> implement that interface.
Yeah I too was thinking that I could convert my audio output function
(which currently uses an write() API)
to instead go through my own WalkieTalkie_Write() which would buffer
the data. Then once the buffer is full
send it via tcpip_callback(). I could still have the sys_timeout() in
place in-case the buffer is only half full for a long
period of time, upon which the sys_timeout will expire and also send the packet.

Thanks for getting back to me, its much appreciated to see I am on the
right track.


----
Regards
Paul Archer
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]