[Top][All Lists]
[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