HW Requirements

Wio-link board

WiFi connected PC/Laptop + Router

Software tools

Anaconda (Py3.4+, ampy, esptools), Visual Studio, PuTTY, httplib header, Any text editor, Chrome browser on PC

Demonstration of BrainStem Customised WebGL game

https://www.gpupowered.org/brainstem/game.html

Introduction

The chrome browser ships with a simple jumper game that can be controlled with a single key (space bar). But, it needs to be played on the laptop keyboard that takes away the freedom and fun. What can be done in the days of the lockdown ?

The Wio-link bare board has a single CONFIG button on it. 

 → A great pairing to create a game, to be played free of the laptop or internet !

Note — The steps below will destroy the shipped firmware on wiolink board.

Design

The system consists of 3 parts:

  1. The Wio-link acting as a WiFi-remote, running micropython (code below)
  2. The Server running on the Laptop, connected with wio on local network, running a server either Python or C++ (code below)
  3. The Chrome Browser on the Laptop, running chrome:\\dino

Programming the Wio-link (as Controller)

Without the connector, the board has just 2 buttons - RESET, and CONFIG. Left with no choice than to choose the CONFIG button.
For the USB serial port to come up install the serial driver, referred in the notes in references below.
Finding the GPIO config for the CONFIG button took a while. It took just some more extra time to figure out it was pulled high, looking at the Schematic PDF on the Wiolink site.
The rest was easy to figure out.

The board is programmed to send data in JSON via the micropython json library.


Micropython code (for Wiolink as Station)

https://gist.github.com/prabindh/f8bac87189949e877f97a26666d062ab

import network
import urequests
import ujson
import machine
import time

def do_post(url, data):

    headers = {'Content-Type': 'application/json'}

    r = urequests.post(url, data=data, headers=headers)
    #print(r)
    results = r.json()
    #print(results)
    
def do_connect_as_ap(ap_ssid, ap_pwd):
    ap = network.WLAN(network.AP_IF)
    ap.active(True)
    sta_if = network.WLAN(network.STA_IF)
    sta_if.active(False)
    ap.config(essid=ap_ssid, password=ap_pwd)

    while ap.active() == False:
      pass
    print('network config:', ap.ifconfig())
       
def do_connect_as_station(sta_ssid, sta_pwd):
    ap = network.WLAN(network.AP_IF)
    ap.active(False)

    sta_if = network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print('connecting to network...')
        sta_if.active(True)
        sta_if.connect(sta_ssid, sta_pwd)
        while not sta_if.isconnected():
            pass
    print('network config:', sta_if.ifconfig())


### Main config parameters
kelvi_host_ip = "http://10.41.2.37:8000/"
WHICH_PIN = 0 ## GPIO 0 - config button in wiolink
key_val = 0
self_id = 100 # Some unique id for this station
ap_ssid = "MicroPython-abba"
ap_pwd = "abba"
sta_ssid = ""
sta_pwd = ""

# Connect to target host
do_connect_as_station(sta_ssid, sta_pwd);

data = {}
data["station-id"] = str(self_id)
data["counter"] = 0

# DEMO - Loop for 50 presses at this time
press_count = 0
while press_count < 50:
    time.sleep_ms(50)
    key_val = machine.Pin(WHICH_PIN).value()

    if int(key_val) == 0: # default pulled high
        press_count = press_count + 1
        
        data["value"] = int(1)
        data["counter"] = press_count
        json_data = ujson.dumps(data)
        # POST to target host
        try:
            do_post(kelvi_host_ip, json_data)
        except:
            print('Error posting')


Programming the PC (as Server)

Python sample code

C++ server code (alternative to Python)

https://gist.github.com/prabindh/9dee285a38c4b708811f1fce7a36eca5Operation

// Prabindh Sundareson 2020
// Age of the lockdown

#include "pch.h" // include #include "httplib.h" in this file
#include <iostream>

static httplib::Server svr;

void pressSpace()
{
    INPUT ip;
    ip.type = INPUT_KEYBOARD;
    ip.ki.time = 0;
    ip.ki.dwFlags = 0;
    ip.ki.wScan = 0; 
    
    ip.ki.wVk = VK_SPACE;

    ip.ki.dwExtraInfo = 0;
    SendInput(1, &ip, sizeof(INPUT));

    // Release the key
    ip.ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(1, &ip, sizeof(INPUT));
}

int main()
{
    std::cout << "Hello World!\n"; 
    svr.Post("/", [&](const auto& req, auto& res) {
        pressSpace();
        std::cout << "Received\n";
        });
    svr.listen("10.41.2.37", 8000);
}


Start the server application on the PC. Ensure to update the IP addresses for your case.

Playing the game


The game can be manually launched by typing in Chrome browser address bar.

chrome:\\dino 
Update the IP addresses, and program the ESP board. 
Connect the Wio-link to battery-bank. It automatically connects to the network
Click the CONFIG button on the Wio-link. It triggers the SPACE key on the PC and the game starts. Keep pressing CONFIG button, just like how the SPACE button on the PC will be pressed when the DINO is to jump.
Have fun.

Other games

Try this WebGL game tuned for single keys - https://www.gpupowered.org/brainstem/game.html

The below game can also be used

https://scratch.mit.edu/projects/189057541

Latency Analysis 

Latency analysis, by logging time of POST messages received from the board via standard WiFi configuration, reveals that it is between 

[20 mSec], to [50 mSec]

The bigger latency then comes from sending the event from the WIN32 calls, not from the board to server latency!!

Complete logs below.

100 1 1  received at  2020-04-10 12:12:07.724608
100 1 2  received at  2020-04-10 12:12:08.151093
100 1 3  received at  2020-04-10 12:12:08.598288
100 1 4  received at  2020-04-10 12:12:08.979383
100 1 5  received at  2020-04-10 12:12:09.273631
100 1 6  received at  2020-04-10 12:12:09.573033
100 1 7  received at  2020-04-10 12:12:09.898250
100 1 8  received at  2020-04-10 12:12:10.208289
100 1 9  received at  2020-04-10 12:12:10.447456
100 1 10  received at  2020-04-10 12:12:10.773320
100 1 11  received at  2020-04-10 12:12:11.099245
100 1 12  received at  2020-04-10 12:12:11.399964
100 1 13  received at  2020-04-10 12:12:11.702992
100 1 14  received at  2020-04-10 12:12:12.024359
100 1 15  received at  2020-04-10 12:12:12.323310
100 1 16  received at  2020-04-10 12:12:12.623391
100 1 17  received at  2020-04-10 12:12:12.935384
100 1 18  received at  2020-04-10 12:12:13.198287
100 1 19  received at  2020-04-10 12:12:13.498083
100 1 20  received at  2020-04-10 12:12:13.776701
100 1 21  received at  2020-04-10 12:12:14.052354
100 1 22  received at  2020-04-10 12:12:14.382828
100 1 23  received at  2020-04-10 12:12:14.703696
100 1 24  received at  2020-04-10 12:12:14.974985
100 1 25  received at  2020-04-10 12:12:15.298031
100 1 26  received at  2020-04-10 12:12:15.604071
100 1 27  received at  2020-04-10 12:12:15.874282
100 1 28  received at  2020-04-10 12:12:16.147933
100 1 29  received at  2020-04-10 12:12:16.474828
100 1 30  received at  2020-04-10 12:12:16.773056
100 1 31  received at  2020-04-10 12:12:17.073746
100 1 32  received at  2020-04-10 12:12:17.325133
100 1 33  received at  2020-04-10 12:12:17.603454
100 1 34  received at  2020-04-10 12:12:17.899451
100 1 35  received at  2020-04-10 12:12:18.222717
100 1 36  received at  2020-04-10 12:12:18.448621
100 1 37  received at  2020-04-10 12:12:18.748199
100 1 38  received at  2020-04-10 12:12:19.027133
100 1 39  received at  2020-04-10 12:12:19.323433
100 1 40  received at  2020-04-10 12:12:19.604310
100 1 41  received at  2020-04-10 12:12:19.874419
100 1 42  received at  2020-04-10 12:12:20.201802
100 1 43  received at  2020-04-10 12:12:20.474866
100 1 44  received at  2020-04-10 12:12:20.775987
100 1 45  received at  2020-04-10 12:12:21.051938
100 1 46  received at  2020-04-10 12:12:21.349364
100 1 47  received at  2020-04-10 12:12:21.675391
100 1 48  received at  2020-04-10 12:12:22.001692
100 1 49  received at  2020-04-10 12:12:22.304648
100 1 50  received at  2020-04-10 12:12:22.599697
100 1 1  received at  2020-04-10 12:12:29.420736
100 1 2  received at  2020-04-10 12:12:29.719733
100 1 3  received at  2020-04-10 12:12:30.021739
100 1 4  received at  2020-04-10 12:12:30.318738
100 1 5  received at  2020-04-10 12:12:30.600114
100 1 6  received at  2020-04-10 12:12:30.894645
100 1 7  received at  2020-04-10 12:12:31.197378
100 1 8  received at  2020-04-10 12:12:31.470342
100 1 9  received at  2020-04-10 12:12:31.750208
100 1 10  received at  2020-04-10 12:12:32.046959
100 1 11  received at  2020-04-10 12:12:32.345444
100 1 12  received at  2020-04-10 12:12:32.595216
100 1 13  received at  2020-04-10 12:12:32.922765
100 1 14  received at  2020-04-10 12:12:33.195076
100 1 15  received at  2020-04-10 12:12:33.471044
100 1 16  received at  2020-04-10 12:12:33.776442
100 1 17  received at  2020-04-10 12:12:34.070468
100 1 18  received at  2020-04-10 12:12:34.395479
100 1 19  received at  2020-04-10 12:12:34.671788
100 1 20  received at  2020-04-10 12:12:34.970704
100 1 21  received at  2020-04-10 12:12:35.271015
100 1 22  received at  2020-04-10 12:12:35.569985
100 1 23  received at  2020-04-10 12:12:35.845321
100 1 24  received at  2020-04-10 12:12:36.168989
100 1 25  received at  2020-04-10 12:12:36.494370
100 1 26  received at  2020-04-10 12:12:36.770505
100 1 27  received at  2020-04-10 12:12:37.044347
100 1 28  received at  2020-04-10 12:12:37.363101


Live

Here is a quick video of how it works with Chrome Dino

https://www.youtube.com/watch?v=HNrKkD0Jzb0

BrainStem GLTF2 WebGL Game

And video of another game based on WebGL + Brainstem GLTF2 model, created exclusively for playing with the Wiolink