Teensy 4.1 ethernet with mongoose network library

Psykokwak

Member
Hi all,
There is a fairly well-known cross-platform library in the embedded world called "mongoose" : https://mongoose.ws/

This library is able to:
  • TCP client/server
  • UDP client/server
  • HTTP(S) client/server
  • Websocket(S) client/server
  • MQTT(S) client/server


It is completely asynchronous and above all, it does not rely on any intermediate network layer (like QNEthernet or Native Ethernet or even LWIP).
I just realized its port for the Teensy 4.1 and its performance is superior to anything I've tested elsewhere.
To install it, just copy the two files (.h / .c) from the library into the project folder and include the .h in your project.

While waiting for my PR to be merged, you can already try it from here : https://github.com/cesanta/mongoose/pull/1954

And there an sketch exemple that serve an LittleFS "www" directory on HTTP :
Code:
#include "driver_teensy41.h"
#include "mongoose.h"

#include "IPAddress.h"

#include <LittleFS.h>
#include <MTP_Teensy.h>

struct mg_mgr mgr;  // Mongoose event manager
struct mip_if mif;  // MIP network interface

LittleFS_Program _fs;

struct Entry {
  const char endsWith[16];
  const char mimeType[32];
};

// Table of extension->MIME strings stored in PROGMEM, needs to be global due
// to GCC section typing rules
const Entry mimeTable[] = {{".html", "text/html"},
                           {".htm", "text/html"},
                           {".css", "text/css"},
                           {".txt", "text/plain"},
                           {".js", "application/javascript"},
                           {".json", "application/json"},
                           {".png", "image/png"},
                           {".gif", "image/gif"},
                           {".jpg", "image/jpeg"},
                           {".ico", "image/x-icon"},
                           {".svg", "image/svg+xml"},
                           {".ttf", "application/x-font-ttf"},
                           {".otf", "application/x-font-opentype"},
                           {".woff", "application/font-woff"},
                           {".woff2", "application/font-woff2"},
                           {".eot", "application/vnd.ms-fontobject"},
                           {".sfnt", "application/font-sfnt"},
                           {".xml", "text/xml"},
                           {".pdf", "application/pdf"},
                           {".zip", "application/zip"},
                           {".gz", "application/x-gzip"},
                           {".appcache", "text/cache-manifest"},
                           {"", "application/octet-stream"}};

const char *mygm_http_get_content_type(const String &f) {
  const char *contentType = NULL;
  int s = (sizeof(mimeTable) / sizeof(mimeTable[0]));
  for (int i = 0; i < s; i++)
    if (f.endsWith(mimeTable[i].endsWith)) contentType = mimeTable[i].mimeType;

  if (!contentType) contentType = mimeTable[s - 1].mimeType;

  return contentType;
}

#define CHUNKSIZE 1350
struct FileContainerStruct {
  File file;
  char *chunkBuffer;
};

void mymg_http_serve_file_begin(struct mg_connection *c, mg_str *uri) {
  String path = "/www" + String(uri->ptr).substring(0, uri->len);
  if (path.endsWith("/")) path += "index.html";

  const char *contentType = mygm_http_get_content_type(path);

  FileContainerStruct *pFcs = new FileContainerStruct();

  pFcs->chunkBuffer = new char[CHUNKSIZE];
  if (!(pFcs->chunkBuffer)) {
    delete pFcs;
    mg_http_reply(c, 500, "", "Memory allocation error\n");
    return;
  }

  pFcs->file = _fs.open(path.c_str(), FILE_READ);
  Serial.printf(" -> %s : %s (%d/%d) : ", path.c_str(), pFcs->file.name(),
                pFcs->file.size(), pFcs->file.available());
  Serial.printf("%s\n", contentType);

  if (!(pFcs->file)) {
    delete pFcs;
    mg_http_reply(c, 404, "", "File Not found\n");
    return;
  }

  c->fn_data = pFcs;
  mg_printf(c,
            "HTTP/1.1 200 OK\r\nTransfer-Encoding: "
            "chunked\r\nContent-Type: %s\r\n\r\n",
            contentType);
}

void mymg_http_serve_file_chunk(struct mg_connection *c) {
  if (!(c->fn_data)) return;
  if (c->send.len != 0) return;

  FileContainerStruct *pFcs = (FileContainerStruct *) c->fn_data;
  size_t l = pFcs->file.readBytes(pFcs->chunkBuffer, CHUNKSIZE);
  mg_http_write_chunk(c, pFcs->chunkBuffer, l);
  if (l == 0) mymg_http_server_file_interrupt(c);
}

void mymg_http_server_file_interrupt(struct mg_connection *c) {
  if (!(c->fn_data)) return;

  FileContainerStruct *pFcs = (FileContainerStruct *) c->fn_data;

  Serial.printf("Close : %s\n", pFcs->file.name());
  pFcs->file.close();
  delete pFcs->chunkBuffer;
  delete pFcs;
  c->fn_data = NULL;
}

static void handler(struct mg_connection *c, int ev, void *ev_data,
                    void *fn_data) {
  struct mg_http_message *hm = (struct mg_http_message *) ev_data;

  switch (ev) {
    case MG_EV_HTTP_MSG:
      if (mg_http_match_uri(hm, "/api/hello")) {
        mg_http_reply(c, 200, "", "OK : %.*s\n", hm->uri.len, hm->uri.ptr);
        break;
      }

      // serve file
      mymg_http_serve_file_begin(c, &(hm->uri));
      break;

    case MG_EV_POLL:
      mymg_http_serve_file_chunk(c);
      break;

    case MG_EV_CLOSE:
    case MG_EV_ERROR:
      mymg_http_server_file_interrupt(c);
      break;
  }
}

void setup() {
  Serial.begin(115200);

  if (!_fs.begin(1024 * 1024 * 2)) {
    Serial.print("Error starting file system.\n");
    while (1)
      ;  // Error, so don't do anything more - stay stuck here
  }

  MTP.addFilesystem(_fs, "LittleFS");

  // Set logging function to a serial print
  mg_log_set_fn([](char ch, void *) { Serial.print(ch); }, NULL);
  mg_log_set(MG_LL_INFO);
  mg_mgr_init(&mgr);

  MG_INFO(("Starting TCP/IP stack..."));

  mif.driver = &mip_driver_teensy41;

  IPAddress ip(192, 168, 123, 10);
  IPAddress mask(255, 255, 255, 0);
  mif.enable_dhcp_client = false;
  mif.enable_dhcp_server = false;

  mif.ip = ip;
  mif.mask = mask;

  mip_init(&mgr, &mif);

  // Setup HTTP listener. Respond "ok" on any HTTP request
  mg_http_listen(&mgr, "http://0.0.0.0", handler, NULL);
}

void loop() {
  mg_mgr_poll(&mgr, 1);
  MTP.loop();
}

Thanks to ssilverman and PaulStoffregen for their work.
 
When I try to use it, it expects a
Code:
mongoose_custom.h
. Can you explain how to set this up correctly?
 
Yes. Create a "mongoose_custom.h" file with the following :

Code:
#pragma once

#if defined(ARDUINO_TEENSY41)
#include "Arduino.h"

#define MG_ARCH_TEENSY41 42
#endif

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <time.h>

#define MG_ARCH               MG_ARCH_TEENSY41
#define MG_ENABLE_SOCKET      0
#define MG_ENABLE_MIP         1
#define mkdir(a, b) (-1)
 
Hi, I used to Test this Library, but was not able to build.

I use Arduino 1.8.19.

Where I have to put folder mongoose-master?
Where I have to put driver_teensy41.h ?

Thank you.
 
I just saw that it has GPLv2 license. This makes it unusable for anything else than private projects, as your entire code becomes GPLv2 with all obligations as you compile it. Are there similar projects like this with more free licenses like LGPL or MIT?
 
Hi, I after a while struggeling with other issues im back tryin to work with Mongoose.ws.

HTTP and UDP is working but MQTT is not.

With mg_log_set(MG_LL_VERBOSE) I get:

3cda 3 mongoose.c:7378:mg_connect_resol 3 192.168.179.8:49152->192.168.179.10:1883
3f9d 3 mongoose.c:3140:mg_mqtt_pub 3 [topic] -> [message]
Unknown eth type 88e1
Unknown eth type 8912

mosquitto on my RASPI says nothing in its LOG about my Teensy.

To Psykokwak: Are you working on your driver for Mongoose.ws since it don´t work with the current Version?
 
Back
Top