Page 1 of 1

Net Streams

Posted: Fri Aug 09, 2013 1:05 pm
by Giovanni
Hi,

The following code has been contributed via email by W.S.

It looks pretty useful: lwIP sockets wrapped in ChibiOS streams.

Giovanni

netstream.c

Code: Select all

#include "netstream.h"
#include "lwip/sockets.h"

static size_t writes(void *ip, const uint8_t *bp, size_t n) {
  NetStream *sp = ip;

  return lwip_write(sp->socket, bp, n);
}

static size_t reads(void *ip, uint8_t *bp, size_t n) {
  NetStream *sp = ip;

  return lwip_read(sp->socket, bp, n);
}

static msg_t put(void *ip, uint8_t b) {
  return (writes(ip, &b, 1) == 1 ? Q_OK : Q_RESET);
}

static msg_t get(void *ip) {
  uint8_t b;

  return (reads(ip, &b, 1) == 1 ? b : Q_RESET);
}

static const struct NetStreamVMT vmt = {writes, reads, put, get};

void nsObjectInit(NetStream *sp, int socket) {

  sp->vmt  = &vmt;
  sp->socket = socket;

}


netstream.h

Code: Select all

#ifndef NETSTREAM_H_
#define NETSTREAM_H_

#include <stddef.h>
#include <stdint.h>
#include <chtypes.h>
#include <chstreams.h>

#define _net_stream_data                                                 \
  _base_sequential_stream_data                                              \
   int socket;

struct NetStreamVMT {
  _base_sequential_stream_methods
};

/**
 * @extends BaseSequentialStream
 *
 * @brief Memory stream object.
 */
typedef struct {
  const struct NetStreamVMT *vmt;
  _net_stream_data
} NetStream;

#ifdef __cplusplus
extern "C" {
#endif
  void nsObjectInit(NetStream *sp, int socket);
#ifdef __cplusplus
}
#endif

#endif /* NETSTREAM_H_ */


Giovanni

Re: Net Streams

Posted: Fri Aug 09, 2013 4:27 pm
by Tectu
Do I understand this correctly - you can actually chprintf() over TCP/IP? :o


~ Tectu

Re: Net Streams

Posted: Fri Aug 09, 2013 7:20 pm
by Giovanni
or even use a shell

Giovanni

Re: Net Streams

Posted: Fri Aug 09, 2013 10:58 pm
by Tectu
This sounds very awesome... sadly I don't know anything about ethernet nor LwIP :(


~ Tectu

Re: Net Streams

Posted: Fri Sep 20, 2013 12:19 pm
by tinito
Really loved the idea, and played around a little with it to remove dependency from the sockets API, relying only on the more efficient netconn API.
Not sure if I did everything in the correct/best way, but it seems to work ;)

netstream.h

Code: Select all

#ifndef NETSTREAM_H_
#define NETSTREAM_H_

#include "ch.h"

#define _net_stream_data \
   _base_sequential_stream_data \
   struct netconn * conn; \
   struct netbuf * inbuf; \
   size_t in_offset;

struct NetStreamVMT {
   _base_sequential_stream_methods
};

/**
 * @extends BaseSequentialStream
 */
typedef struct {
   const struct NetStreamVMT *vmt;_net_stream_data
} NetStream;

#ifdef __cplusplus
extern "C" {
#endif
void nsObjectInit(NetStream *sp);
void nsStart(NetStream *sp, struct netconn * conn);
#ifdef __cplusplus
}
#endif

#endif /* NETSTREAM_H_ */



netstream.c

Code: Select all

#include "netstream.h"
#include "lwip/api.h"

#include "ch.h"
#include "hal.h"

static size_t write(void *ip, const uint8_t *bp, size_t n) {
   NetStream *sp = ip;

   return netconn_write_partly(sp->conn, bp, n, NETCONN_COPY, NULL);
}

static size_t read(void *ip, uint8_t *bp, size_t n) {
   NetStream *sp = ip;
   err_t err;

   /* If last input buffer was completely consumed, wait for a new packet. */
   while (sp->inbuf == NULL) {
      /* Wait for new packet. */
      err = netconn_recv(sp->conn, &sp->inbuf);
      if (err != ERR_OK) {
         /* Connection closed (or any other errors). */
         return 0;
      }
   }

   netbuf_copy_partial(sp->inbuf, bp, n, sp->in_offset);
   sp->in_offset += n;

   /* Check if there is more data to read. */
   if (sp->in_offset >= netbuf_len(sp->inbuf)) {
      n -= (sp->in_offset - netbuf_len(sp->inbuf));
      netbuf_delete(sp->inbuf);
      sp->in_offset = 0;
      sp->inbuf = NULL;
   }

   return n;
}

static msg_t put(void *ip, uint8_t b) {
   return (write(ip, &b, 1) == 1 ? Q_OK : Q_RESET);
}

static msg_t get(void *ip) {
   uint8_t b;

   return (read(ip, &b, 1) == 1 ? b : Q_RESET);
}

static const struct NetStreamVMT vmt = { write, read, put, get };

void nsObjectInit(NetStream *sp) {

   sp->vmt = &vmt;
   sp->inbuf = NULL;
   sp->in_offset = 0;
}

void nsStart(NetStream *sp, struct netconn * conn) {

   sp->conn = conn;
}



Then I can spawn a shell for each connection like this:

Code: Select all

/*
 * TCP server thread.
 */
static msg_t server_thread(void *arg) {
   uint16_t port = *((uint16_t *) arg);
   struct netconn *conn, *newconn;
   err_t err;

   chRegSetThreadName("server");

   /* Create a new TCP connection handle */
   conn = netconn_new(NETCONN_TCP);
   LWIP_ERROR("TCP server: invalid conn", (conn != NULL), return RDY_RESET;);

   /* Bind to a port. */
   netconn_bind(conn, NULL, port);

   /* Listen for connections. */
   netconn_listen(conn);

   while (TRUE) {
      err = netconn_accept(conn, &newconn);
      if (err != ERR_OK)
         continue;

      /* Dynamic allocation to allow multiple shell instances. */
      NetStream * nsp = chHeapAlloc(NULL, sizeof(NetStream));
      ShellConfig * shell_cfgp = chHeapAlloc(NULL, sizeof(ShellConfig));

      if(nsp && shell_cfgp) {
         nsObjectInit(nsp);
         nsStart(nsp, newconn);

         shell_cfgp->sc_channel = (BaseSequentialStream *) nsp;
         shell_cfgp->sc_commands = commands;

         shellCreate(shell_cfgp, SHELL_WA_SIZE, NORMALPRIO - 1);
      }
   }
   return RDY_OK;
}



Simple and impressive!

Re: Net Streams

Posted: Wed Jan 01, 2014 6:47 pm
by fzahn
Hi,

this is exactly what i was looking for and I can access the shell via "nc -c ip_address".

Unfortunately I did not find a useful way, to exit the shell and close the tcp-connection to it...
I tried combinations of "shellExit(RDY_OK)" and netconn_close(newconn) but without success.
When executing the netconn_close the system hangs, when not doing shellExit....
But after shellExit the following commands are not executed anymore.


Any ideas?


Thanks and best regards

Florian