Net Streams

This forum is about you. Feel free to discuss anything is related to embedded and electronics, your awesome projects, your ideas, your announcements, not necessarily related to ChibiOS but to embedded in general. This forum is NOT for support.
Post Reply
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Net Streams

Post 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
User avatar
Tectu
Posts: 1225
Joined: Thu May 10, 2012 9:50 am

Re: Net Streams

Post by Tectu »

Do I understand this correctly - you can actually chprintf() over TCP/IP? :o


~ Tectu
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Net Streams

Post by Giovanni »

or even use a shell

Giovanni
User avatar
Tectu
Posts: 1225
Joined: Thu May 10, 2012 9:50 am

Re: Net Streams

Post by Tectu »

This sounds very awesome... sadly I don't know anything about ethernet nor LwIP :(


~ Tectu
tinito
Posts: 112
Joined: Tue Jun 07, 2011 10:32 am
Has thanked: 1 time
Been thanked: 1 time

Re: Net Streams

Post 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!
fzahn
Posts: 1
Joined: Wed Jan 01, 2014 6:40 pm

Re: Net Streams

Post 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
Post Reply