Simplest TinyCLR Web Server

Want to run a simple web server on your TinyCLR2.0? Check out my toggle sample. It is very rudimentary, but it works. Tested using a FEZ feather.

using GHIElectronics.TinyCLR.Devices.Display;
using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.I2c;
using GHIElectronics.TinyCLR.Devices.Network;
using GHIElectronics.TinyCLR.Devices.Spi;
using GHIElectronics.TinyCLR.Devices.Uart;
using GHIElectronics.TinyCLR.Drivers.Microchip.Winc15x0;
using GHIElectronics.TinyCLR.Drivers.SolomonSystech.SSD1306;
using GHIElectronics.TinyCLR.Pins;
using Prowler.Properties;
using System;
using System.Collections;
using System.Diagnostics;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Resources;
using System.Text;
using System.Threading;


namespace Prowler
{
    class Program
    {
        static string _address = "0.0.0.0";
        static HttpListener webServer;
        static Thread webWorkerThread;
        static GpioPin led;
        static void Main()
        {

            webServer = new HttpListener("http", 80);
            webWorkerThread = new Thread(() =>
            {
                while (webServer.IsListening)
                {
                    var context = webServer.GetContext();
                    ProcessInboundGetRequest(context);
                }
            });

            var gpioController = GpioController.GetDefault();
            led = gpioController.OpenPin(SC20100.GpioPin.PE11);
            led.SetDriveMode(GpioPinDriveMode.Output);

            SetupWiFiConnection(gpioController);
        }

        private static void SetupWiFiConnection(GpioController gpioController)
        {
            var enablePin = gpioController.OpenPin(GHIElectronics.TinyCLR.Pins.SC20100.GpioPin.PA8);
            enablePin.SetDriveMode(GpioPinDriveMode.Output);
            enablePin.Write(GpioPinValue.High);
            var cs = gpioController.OpenPin(SC20100.GpioPin.PD15);
            WiFiNetworkInterfaceSettings wifiSettings = new WiFiNetworkInterfaceSettings()
            {
                Ssid = "ssid",
                Password = "password",
                IsDhcpEnabled = true,
                IsDynamicDnsEnabled = true,
                TlsEntropy = new byte[] { 0, 1, 2, 3 }
            };
            var settings = new SpiConnectionSettings()
            {
                ChipSelectLine = cs,
                ClockFrequency = 4000000,
                Mode = SpiMode.Mode0,
                ChipSelectType = SpiChipSelectType.Gpio,
                ChipSelectHoldTime = TimeSpan.FromTicks(10),
                ChipSelectSetupTime = TimeSpan.FromTicks(10)
            };
            SpiNetworkCommunicationInterfaceSettings netInterfaceSettings = new SpiNetworkCommunicationInterfaceSettings()
            {
                SpiApiName = SC20100.SpiBus.Spi3,
                GpioApiName = SC20100.GpioPin.Id,
                SpiSettings = settings,
                InterruptPin = gpioController.OpenPin(SC20100.GpioPin.PB12),
                InterruptEdge = GpioPinEdge.FallingEdge,
                InterruptDriveMode = GpioPinDriveMode.InputPullUp,
                ResetPin = gpioController.OpenPin(SC20100.GpioPin.PB13),
                ResetActiveState = GpioPinValue.Low
            };

            var networkController = NetworkController.FromName("GHIElectronics.TinyCLR.NativeApis.ATWINC15xx.NetworkController");
            networkController.SetInterfaceSettings(wifiSettings);
            networkController.SetCommunicationInterfaceSettings(netInterfaceSettings);
            networkController.SetAsDefaultController();
            byte[] address = new byte[4];
            networkController.NetworkAddressChanged += (NetworkController sender, NetworkAddressChangedEventArgs e) =>
            {
                var ipProperties = sender.GetIPProperties();
                address = ipProperties.Address.GetAddressBytes();
                if (address[0] > 0)
                {
                    if (!webServer.IsListening)
                    {
                        webServer.Start();
                        webWorkerThread.Start();
                    }
                }
                else
                {
                    if (webServer.IsListening)
                    {
                        webServer.Stop();
                        webWorkerThread.Abort();
                    }
                }
                _address = $"{address[0]}.{address[1]}.{address[2]}.{address[3]}";
                Debug.WriteLine(_address);
            };

            // Starting a new thread for monitoring the WiFi
            new Thread(() =>
            {
                while (enablePin.Read() == GpioPinValue.High)
                {
                    try
                    {
                        //Try enabling WiFi interface
                        networkController.Enable();
                        //Sleep for 2sec to give ample time fr wifi to connect
                        Thread.Sleep(2000);

                        //Poll WiFi connection link every 5sec
                        while (networkController.GetLinkConnected())
                        {
                            Thread.Sleep(5000);
                        }
                        if (!networkController.GetLinkConnected())
                            networkController.Disable();
                    }
                    catch (Exception)
                    {
                        Debug.WriteLine("Unable to connect to AP");
                        Thread.Sleep(2000);
                    }
                }
            }).Start();
        }

        private static void ProcessInboundGetRequest(HttpListenerContext context)
        {
            try
            {
                switch (context.Request.HttpMethod.ToUpper())
                {
                    case "POST":
                        switch (context.Request.RawUrl.ToUpper())
                        {
                            case "/":
                                led.Write(led.Read() == GpioPinValue.High ? GpioPinValue.Low : GpioPinValue.High);
                                context.Response.StatusCode = 200;
                                context.Response.ContentType = "application/json";
                                var buffer = Encoding.UTF8.GetBytes($"{{\"led\": {(led.Read() == GpioPinValue.High).ToString().ToLower()}}}");
                                context.Response.ContentLength64 = buffer.Length;
                                context.Response.OutputStream.Write(buffer, 0, buffer.Length);
                                
                                break;
                            default:
                                break;
                        }
                        break;
                    default:
                        switch (context.Request.RawUrl.ToUpper())
                        {
                            case "/":
                                var resource = Resources.GetString(Resources.StringResources.index);

                                context.Response.StatusCode = 200;
                                context.Response.ContentType = "text/html";
                                var buffer = Encoding.UTF8.GetBytes(resource);
                                context.Response.ContentLength64 = buffer.Length;
                                context.Response.OutputStream.Write(buffer, 0, buffer.Length);
                                break;
                            default:
                                break;
                        }
                        break;
                }

            }
            finally
            {
                context.Response.OutputStream.Close();
            }
        }
    }
}

Create an index.html file and add it as a resource.then add this code.

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <!--<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">-->

    <title>Hello, FEZ Web Server!</title>
</head>
<body>
    <h1>Hello, FEZ Web Server</h1>
    <div>
        <form id="frmAction">
            <div>
                <label>
                    <input type="checkbox" name="led" id="led" readonly disabled />
                    Onboard LED
                </label>
            </div>
            <p>
                <button type="submit">
                    Change
                </button>
            </p>
        </form>
    </div>
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <!--<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>-->
    <script type="text/javascript">
        var led = document.getElementById('led');
        var ajax = new XMLHttpRequest();
        ajax.onreadystatechange = function (state) {
            if (state.currentTarget.readyState == 4) {
                var data = JSON.parse(state.currentTarget.responseText);

                if (data.led) {
                    led.checked = true;
                } else {
                    led.checked = false;
                }
            }
        };
     
        window.onload = function () {
            var checked = false;
            var data = {};
            var form = document.getElementById('frmAction');

            if (led) {
                data[led.name] = false;
            }

            if (form) {

                led.addEventListener('change', function (event) {
                    data[led.name] = led.checked;
                });

                form.addEventListener('submit', function (event) {
                    event.preventDefault();

                    ajax.open('POST', '', true);
                    ajax.setRequestHeader('content-type', 'applcation/json');

                    var json = JSON.stringify(data);
                    ajax.send(json)
                  
                });
            }
        };

    </script>
</body>
</html>
8 Likes

For a more advanced webserver please check out, this work is being done by @sytak.

4 Likes