Tag Archives: programming

Bios Extension boot and bootsector programs.

Followup on

Today two boot projects.
One using a bios extension, so it chip based.
Second is a floppy disk boot program. (Creating a test situation to get our old Boot floppy demo working. ( That one without using an operatingsystem like ms-dos.

Creating a Secondary Bios ROM

NAME mycode
.model small
ORG 0h

.code
	dw 0AA55h ;  Magic header your bios is looking for
	db 16     ; lenght of this rom in 512 bytes == 8k
	jmp short clear ; jmp to program

ORG 20h                 ; start of program
	
clear:  mov cx,10       ; clear, set keyboard led and print 10 # chars
	mov ah,0ah
	mov al,31h
	int 10h
	mov bh,0
	mov cx,1
start:	mov al, 11000000b
        out 80h, al
print:  mov cx,10
	mov ah,0ah
	mov al,"#"
	int 10h
loop1:  nop           ; loop until doomsday
	jmp loop1
	db -68        ; This makes the checksum 0
                      ; steps to take: edit source, make this byte entry 0
                      ; compile using make.bat in dosbox
                      ; check checksum using my python script
                      ; output was 68 hex 0x44
                      ; edit asm file place -68 to make the checksum 0x00 again
                      ; compile and burn to ROM
ORG 2000h             ; create end of rom 0000h-1fffh = 8K
END

make.bat in dosbox

@ECHO OFF
MASM /DARCH_TYPE="T" /DCPU_TYPE="V" 1;
LINK 1;
EXE2COM 1.EXE

Python script here: https://www.henriaanstoot.nl/2023/06/20/bios-hacking/

Write EEprom

minipro -w 1.COM -p AT28C64

Part 2 – Bootsector program !

Allmost the same as above, but booting from a Floppy disk.

Video mode info : https://stanislavs.org/helppc/int_10-0.html

Assembly code

use16              ; 16 bits 
org 0x7c00         ; start address ( change? )

mov ah,0x0         ; ah 0h - video mode 
mov al,0x0         ; al 0h - mode 0 - 40x25 chars
int 10h            ; scree routines 
mov cx,11h         ; 11 chars
mov ah,0ah         ; ah 0ah - print char mode
mov al,'#'         ; choose char as #
int 10h            ; execute 


times 510 - ($-$$) db 0 ; fill rest 512 bytes sector

dw 0xaa55 ; magic bytes 

Python Spotify Genre Cube v2

Spotify version

Next to do: Lasercut a wooden cube with better lettering.

Run the python part on a server

and

First export some API credentials

export SPOTIPY_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export SPOTIPY_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export SPOTIPY_REDIRECT_URI="http://localhost:8080/callback"

Code below:

from flask import Flask, request, redirect
from requests_oauthlib import OAuth2Session
from requests.auth import HTTPBasicAuth
import requests
import json
import spotipy
from spotipy.oauth2 import SpotifyOAuth
from pprint import pprint
from time import sleep
import spotipy.util as util
import sys
import paho.mqtt.client as mqttClient
import time
import os
import subprocess

Connected = False


broker_address = "MQTTSERVER"
port = 1883


def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("Connected to broker")
        global Connected
        Connected =True
    else:
        print("Connection failed")

def on_message(client, userdata, message):
    print (message.payload)
    myurl = 'spotify:playlist:' + str(message.payload.decode())

    results = sp.start_playback(context_uri=myurl, offset={"position": 1})

client = mqttClient.Client("PythonSpotifyGenreCube")
client.on_connect = on_connect
client.on_message = on_message

client.connect(broker_address, port=port,keepalive=60 )
client.loop_start()
time.sleep(4) # Wait for connection setup to complete
client.subscribe('spotify/playlist')
#client.loop_stop()    #Stop loop

#while Connected != True:
#    client.loop()
#    time.sleep(0.1)
#    print("test")
#    client.subscribe('spotify/playlist')



app = Flask(__name__)

AUTH_URL = 'https://accounts.spotify.com/authorize'
TOKEN_URL = 'https://accounts.spotify.com/api/token'
REDIRECT_URI = 'http://localhost:8080/callback'
CLIENT_ID = "xxxxxxxxxxxxxxxxxx"
CLIENT_SECRET = "xxxxxxxxxxxxxxxxxxxxx"
SCOPE = [
    "user-read-email",
    "playlist-read-collaborative"
]

@app.route("/login")
def login():
    spotify = OAuth2Session(CLIENT_ID, scope=SCOPE, redirect_uri=REDIRECT_URI)
    authorization_url, state = spotify.authorization_url(AUTH_URL)
    return redirect(authorization_url)

@app.route("/callback", methods=['GET'])
def callback():
    code = request.args.get('code')
    res = requests.post(TOKEN_URL,
        auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET),
        data={
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': REDIRECT_URI
        })
    return json.dumps(res.json())


username = "fashice"
scope = "user-read-playback-state,user-modify-playback-state,playlist-read-private"
util.prompt_for_user_token(username,scope,client_id='xxxxxxxxxxxxxxxxxxxxx',client_secret='xxxxxxxxxxxxxxxxxxxxxxxxxxxx',redirect_uri='http://localhost:8080/callback')

sp = spotipy.Spotify(client_credentials_manager=SpotifyOAuth(scope=scope))

# Shows playing devices
res = sp.devices()
pprint(res)


# Change track
#sp.start_playback(uris=['spotify:track:6gdLoMygxxxxxxxxxxxxxxx'])
#results = sp.start_playback(context_uri=myurl, offset={"position": 1})


## Change volume
#sp.volume(100)
#sleep(2)
#sp.volume(50)
#sleep(2)
#sp.volume(100)
#


playlists = sp.user_playlists(username)

#for playlist in playlists['items']:
#    print(playlist['name'])


playlists = sp.current_user_playlists()
#print (playlists)
for playlist in playlists['items']:
    print(playlist['id'] + ' ' +  playlist['name'])



#if __name__ == '__main__':
#   app.run(port=8080,debug=True)


while Connected != True:
    time.sleep(0.1)
    client.subscribe('spotify/playlist')

try:
    while True:
        time.sleep(1)


except KeyboardInterrupt:
    print ("exiting")
    client.disconnect()
    client.loop_stop()

Machine code Monitor in ROM on real BBC Acorn Hardware

My BBC Acorn model B is working again. The original monitor is still dead.

Time to play with some machine code and ROMs.

My machine has a NFS rom installed. (NetFS)

Econet was Acorn Computers’s low-cost local area network system, intended for use by schools and small businesses. It was widely used in those areas, and was supported by a large number of different computer and server systems produced both by Acorn and by other companies.

I found a ROM online called Gremlin. It is a 16K rom file. But at the moment I only got some 28C64 (8k) or 28C256 (32k) eeproms.

32k it is. But de beeb having address line A14 floating high, I need to flash the upper 16k of the 32k ROM.

So I made the 16K rom into a 32K using cat

cp Gremlin\ v1.21\ \(1983\)\(Computer\ Concepts\).rom 16k.rom
cat Gremlin\ v1.21\ \(1983\)\(Computer\ Concepts\).rom >> 16k.rom

minipro -w 16k.rom -p AT28C256

I got the rom from this page:
https://acorn.huininga.nl/pub/unsorted/roms/Gremlin%20v1.21%20(1983)(Computer%20Concepts).rom

Below booting straight into the monitor program.

Manual:

6502 and Wozmon

Ben posted a youtube about Wozmon running on his 6502.

In 1976, Steve Wozniac wrote what’s commonly known simply as Wozmon.

Wozmon is a machine-code monitor program written by Wozniak for the Apple 1. In Only 256 bytes ! Being pure 6502 code easily adaptable.
A monitor program allows you to view/edit and run machine code using simple commands.

I’ve got a different setup as Ben’s computer.
But changing the necessary, and it will run on my 6502.

I’m not using rs232 voltage levels (-7 till -25 and +7 till +25 volts).
I’m using a usb serial uart standard 5v leveling stick …

For address decoder see other post

Simplified schematic of my UART/ACIA

Compiling the Wosmon gave me an error, DEC is not a valid opcode for a bare 6502 .. but we have a 65c02.
Solution: Add -c02 extra opcodes

error 1 in line 187 of "wozmon.s": illegal operand types
>                DEC                    ; Decrement A.

# fix .. add -c02
vasm6502_oldstyle -c02 -Fbin -dotdir wozmon.s

Below Apple I Manual with the sourcecode for Wozmon

Debugging a cool robot

A friend bought a mini robot for his son.
But it didn’t work as it should.

No way i let this opportunity pass to play with it!

This is the one:
https://elektronicavoorjou.nl/product/maqueen-plus-v2/
Maqueen Plus V2 – Geavanceerde STEM Educatie Robot voor micro:bit

https://wiki.dfrobot.com/SKU_MBT0021-EN_Maqueen_Plus_STEAM_Programming_Educational_Robot#target_0

So you can program this in a blockly like manner.

Problems we encountered:

  • Uploading didn’t work
    Solution: Using chrome it had access to the usb port to upload, firefox didn’t work
  • The program didn’t compile, faulty or zero size hex file.
    Solution: Wrong Maqueen library was in the examples
    (After changing, needed version update also, see below)
  • Not everything is in Dutch (I like English, but this is for the boy), maqueen V2 needed a lot of translation.
    (So we joined https://crowdin.com/project/makecode/nl to help translating the libraries)

Apparently my AI camera can be connected to this robot!

Bios hacking

Followup on :

I wrote a little python script which checks the checksum of a Bios.

In a previous post i used hexedit to play around changing a Bios dump.

Below posted python script calculates the checkum using the following:

Add all bytes in the file and do a modulo 256 on this number. The output should be 0.

My previous edit gave me a output of C2, so I changed an unused byte FF into (FF-C2) 3D.
No more checksum errors when booting!

Next to do, get a Bios like Glabios or PcXtBios to start my own code from a secondary Eeprom.

import sys

# Bios sum modulo should be 0
# edit  last or unused byte to fix
# python bios-checksum-test.py MYROM.edit.checksum
# 0

f = open(sys.argv[1],'rb')
m = f.read()
print  '%x' % ( ( sum(ord(c) for c in m) & 0xFFFFFFFF ) % 256 )

Python3

import sys

# Bios sum modulo should be 0
# edit  last or unused byte to fix
# python bios-checksum-test.py MYROM.edit.checksum
# 0

f = open(sys.argv[1],'rb')
m = f.read()
checksum =  ( ( sum((c) for c in m) & 0xFFFFFFFF ) % 256 )
print(checksum, 'in hex =', hex(checksum))

Spotify control using python

For usage in this project:

Goto https://developers.spotify.com and add a APP

Write down the Client_id Client_secret and Redirect URL (callback)

Create a bash and python script

#!/bin/bash
export SPOTIPY_CLIENT_ID=2f660e11e70743febdxxxxxxxxxxxxx
export SPOTIPY_CLIENT_SECRET=b0741452a4fe43xxxxxxxxxxxxx
export SPOTIPY_REDIRECT_URI="http://localhost:8080/callback"

python3 spot.py $1

spot.py

import spotipy
from spotipy.oauth2 import SpotifyOAuth
from pprint import pprint
from time import sleep
import spotipy.util as util
import sys

username = "username"
scope = "user-read-playback-state,user-modify-playback-state,playlist-read-private"
util.prompt_for_user_token(username,scope,client_id=SPOTIPY_CLIENT_ID,client_secret=SPOTIPY_CLIENT_SECRET,redirect_uri=SPOTIPY_REDIRECT_URI)

sp = spotipy.Spotify(client_credentials_manager=SpotifyOAuth(scope=scope))

# Shows playing devices
res = sp.devices()
pprint(res)

myurl = 'spotify:playlist:' + sys.argv[1]

# Change track
results = sp.start_playback(context_uri=myurl, offset={"position": 1})

## Change volume example
#sp.volume(100)
#sleep(2)
#sp.volume(50)
#sleep(2)

playlists = sp.user_playlists(username)

playlists = sp.current_user_playlists()
for playlist in playlists['items']:
    print(playlist['id'] + ' ' +  playlist['name'])

Run bash script as follows.

playlistplayspotify.sh 0bJvpsn0TDxxxxxxxxxxxx
(0bJvpsn0TDxxxxxxxxxxxx – is playlist ID, as example below)

OUTPUT:

python3 spot.py 0bJvpsn0TDxxxxxxxxxxxx
{'devices': [{'id': 'e86eada2a91e29a396acxxxxxxxxxxxxxxxxxxxx',
              'is_active': True,
              'is_private_session': False,
              'is_restricted': False,
              'name': 'laptop',
              'type': 'Computer',
              'volume_percent': 100},
             {'id': '8571468b6c41973ccb0axxxxxxxxxxxxxxxxxxxx',
              'is_active': False,
              'is_private_session': False,
              'is_restricted': False,
              'name': 'DESKTOP-xxxxxxx',
              'type': 'Computer',
              'volume_percent': 76},
             {'id': '6c592503aa5a22b2fbdxxxxxxxxxxxxxxxxxxxxxx',
              'is_active': False,
              'is_private_session': False,
              'is_restricted': False,
              'name': 'TX-NR1030',
              'type': 'AVR',
              'volume_percent': 41}]}
0bJvpsn0TDxxxxxxxxxxxx Best Classical Music Of All Time
5aL9jeGMCAxxxxxxxxxxxx Programming music
37i9dQZEVCxxxxxxxxxxxx Discover Weekly
6pEJuA1UYJxxxxxxxxxxxx Highland/Small/Border Pipe Music
5p8Tabf5Zwxxxxxxxxxxxx Folk Instrumentals ( Celtic, Irish, Nordic, ... )
1oy8Ek4ddBxxxxxxxxxxxx Lounge
37i9dQZF1Dxxxxxxxxxxxx Irish Folk
etc etc

Shaders using Bonzomatic

Saw some demo-scene shader showdowns on YT the other day.

Two guys live programming shaders in less than a hour!

Fun to play with .. bonzomatic.
This shader program is realtime being compiled and the effect is shown on the background.

Below version I made using an example is changing to the music being played. (Fast Fourier transform function, see my other post about this)

Realtime draw maze using php gd lib

UPDATE FROM: https://www.henriaanstoot.nl/2023/05/08/wss-websocket-to-mqtt-updating-website/

Mqtt controlled

for f in 1 2 3 4 5 6 7 0 ; do mosquitto_pub -h mqttserver -t web/mapviewer -m $f ;sleep 2 ;done

Below can be used in yesterdays script.
And can be called as image source.

<img src="draw.php?direction=0">

CODE

<?php

function imagelinethick($image, $x1, $y1, $x2, $y2, $color, $thick = 3)
{
    /* this way it works well only for orthogonal lines
    imagesetthickness($image, $thick);
    return imageline($image, $x1, $y1, $x2, $y2, $color);
    */
    if ($thick == 1) {
        return imageline($image, $x1, $y1, $x2, $y2, $color);
    }
    $t = $thick / 2 - 0.5;
    if ($x1 == $x2 || $y1 == $y2) {
        return imagefilledrectangle($image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
    }
    $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
    $a = $t / sqrt(1 + pow($k, 2));
    $points = array(
        round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
        round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
        round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
        round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
    );
    imagefilledpolygon($image, $points, 4, $color);
    return imagepolygon($image, $points, 4, $color);
}
header("Content-Type: image/png");
$im = imagecreate(640, 640);
$background_color = imagecolorallocate($im, 0, 0, 0);
$text_color = imagecolorallocate($im, 255, 255, 255);
$text_color1 = imagecolorallocate($im, 128, 128, 128);

$max=640;
$depth1=80;
$depth2=160;
$depth3=190;
$depthcolor1 = imagecolorallocate($im, 255, 255, 255);
$depthcolor2 = imagecolorallocate($im, 128, 128, 128);
$depthcolor3 = imagecolorallocate($im, 32, 32, 32);

$direction = $_GET["direction"];


// draw always
imagelinethick($im,0,0,$depth1,$depth1,$depthcolor1);
imagelinethick($im,$max,0,$max-$depth1,$depth1,$depthcolor1);
imagelinethick($im,0,$max,$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$max,$max,$max-$depth1,$max-$depth1,$depthcolor1);

if ( $direction == "1" ) {
imagelinethick($im,$max-$depth1,$depth1,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth1,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth2,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth1,$depth2,$max-$depth2,$depth2,$depthcolor2);
// front
imagelinethick($im,$depth1,$depth1,$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "4" ) {
imagelinethick($im,$depth1,$max-$depth1,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth1,$depth1,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$max-$depth2,$max-$depth1,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$max-$depth1,$depth2,$depthcolor2);
// front
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "5" ) {
imagelinethick($im,$depth1,$depth2,$max-$depth1,$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth2,$max-$depth1,$max-$depth2,$depthcolor2);
// front
imagelinethick($im,$depth1,$depth1,$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "2" ) {
imagelinethick($im,$depth1,$depth1,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$depth1,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth1,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth1,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$depth3,$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth3,$depth3,$depthcolor3);
imagelinethick($im,$depth2,$max-$depth2,$depth3,$max-$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth3,$max-$depth3,$depthcolor3);
}

if ( $direction == "3" ) {
imagelinethick($im,$max-$depth1,$depth1,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth1,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$depth1,$depth2,$depthcolor2);
imagelinethick($im,$depth2,$max-$depth2,$depth1,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$depth2,$depth2,$max-$depth2,$depthcolor2);

//depth3
imagelinethick($im,$depth2,$depth2,$depth3,$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth3,$depth3,$depthcolor3);
imagelinethick($im,$depth2,$max-$depth2,$depth3,$max-$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth3,$max-$depth3,$depthcolor3);
//front
imagelinethick($im,$depth1,$depth1,$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "6" ) {
imagelinethick($im,$depth1,$depth1,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth1,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$depth2,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth2,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth2,$depth2,$depthcolor2);

//depth3
imagelinethick($im,$depth2,$depth2,$depth3,$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth3,$depth3,$depthcolor3);
imagelinethick($im,$depth2,$max-$depth2,$depth3,$max-$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth3,$max-$depth3,$depthcolor3);
//front
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "7" ) {
imagelinethick($im,$depth1,$depth2,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$depth1,$max-$depth2,$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$depth2,$max-$depth2,$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$depth2,$max-$depth2,$depth2,$depthcolor2);
imagelinethick($im,$max-$depth1,$max-$depth2,$max-$depth2,$max-$depth2,$depthcolor2);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth2,$depth2,$depthcolor2);
//depth3
imagelinethick($im,$depth2,$depth2,$depth3,$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$depth2,$max-$depth3,$depth3,$depthcolor3);
imagelinethick($im,$depth2,$max-$depth2,$depth3,$max-$depth3,$depthcolor3);
imagelinethick($im,$max-$depth2,$max-$depth2,$max-$depth3,$max-$depth3,$depthcolor3);
//front
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$depth1,$depth1,$depth1,$max-$depth1,$depthcolor1);
}

if ( $direction == "0" ) {
imagelinethick($im,$depth1,$depth1,$max-$depth1,$depth1,$depthcolor1);
imagelinethick($im,$max-$depth1,$depth1,$max-$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$max-$depth1,$max-$depth1,$depth1,$max-$depth1,$depthcolor1);
imagelinethick($im,$depth1,$max-$depth1,$depth1,$depth1,$depthcolor1);
}

imagepng($im);
imagedestroy($im);
?>

HLK-LD2410B Mqtt socket and canvas

Follow up on yesterday’s post

Using a html page with javascript, I made a proof of concept displaying realtime information from the sensor.

The sensor is active using a Home Assistant integration.
https://www.henriaanstoot.nl/2022/11/07/home-assistant-nodered-update/

But using the Node-red integration, i take the payload and write this to a mqtt topic

The HTML page below reads the topic using the websocket configured in mosquitto and draws the distance using canvas

cat /etc/mosquitto/conf.d/websockets.conf
listener 9001
protocol websockets
allow_anonymous true


Distance drawn using canvas. Little dividers on top are meters

HTML PAGE with javascript

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title></title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
	<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
 	<script type = "text/javascript" 
         src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script type = "text/javascript">
	var connected_flag=0	
	var mqtt;
    var reconnectTimeout = 2000;
	var host="MQTTSERVER";
	var port=9001;
var sub_topic="web/#";
	function onConnectionLost(){
	console.log("connection lost");
	document.getElementById("status").innerHTML = "Connection Lost";
	document.getElementById("messages").innerHTML ="Connection Lost";
	connected_flag=0;
	}
	function onFailure(message) {
		console.log("Failed");
		document.getElementById("messages").innerHTML = "Connection Failed- Retrying";
        setTimeout(MQTTconnect, reconnectTimeout);
        }
	function onMessageArrived(r_message){
		out_msg="Message received "+r_message.payloadString+"<br>";
		//out_msg=out_msg+"Message received Topic "+r_message.destinationName;
		//console.log("Message received ",r_message.payloadString);
		console.log(out_msg);
		document.getElementById("messages").innerHTML =out_msg;
		var topic=r_message.destinationName;
		if(topic=="web/module1")
		{
		document.getElementById("module1").innerHTML =r_message.payloadString;
		}
		if(topic=="web/module2")
		{
		document.getElementById("module2").innerHTML =r_message.payloadString;
		
		var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var centerX = 10;
context.clearRect(0, 0, 1800, 1000);
var centerY = 10;
var radius = r_message.payloadString;

let circle = new Path2D();  // 
circle.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);

//context.fillStyle = 'white';

context.fillStyle = "rgba(255, 255, 255, 0.2)";
context.fill(circle); //   

context.lineWidth = 5;
context.strokeStyle = '#000066';
context.stroke(circle);  //

// top line
context.beginPath();
context.moveTo(10, 10);
context.lineTo(1500, 10);
context.stroke();

// 3x dividers		
context.beginPath();
context.moveTo(400, 0);
context.lineTo(400, 20);
context.stroke();
		
context.beginPath();
context.moveTo(800, 0);
context.lineTo(800, 20);
context.stroke();
		
context.beginPath();
context.moveTo(1200, 0);
context.lineTo(1200, 20);
context.stroke();
		
		}
		}
	function onConnected(recon,url){
	console.log(" in onConnected " +reconn);
	}
	function onConnect() {
	  // Once a connection has been made, make a subscription and send a message.
	document.getElementById("messages").innerHTML ="Connected to "+host +"on port "+port;
	connected_flag=1
	document.getElementById("status").innerHTML = "Connected";
	console.log("on Connect "+connected_flag);
	mqtt.subscribe(sub_topic);
	  }

    function MQTTconnect() {

	console.log("connecting to "+ host +" "+ port);
	var x=Math.floor(Math.random() * 10000); 
	var cname="controlform-"+x;
	mqtt = new Paho.MQTT.Client(host,port,cname);
	//document.write("connecting to "+ host);
	var options = {
        timeout: 3,
		onSuccess: onConnect,
		onFailure: onFailure,
      
     };
	
        mqtt.onConnectionLost = onConnectionLost;
        mqtt.onMessageArrived = onMessageArrived;
		//mqtt.onConnected = onConnected;

	mqtt.connect(options);
	return false;
  
 
	}
	function sub_topics(){
		document.getElementById("messages").innerHTML ="";
		if (connected_flag==0){
		out_msg="<b>Not Connected so can't subscribe</b>"
		console.log(out_msg);
		document.getElementById("messages").innerHTML = out_msg;
		return false;
		}
	var stopic= document.forms["subs"]["Stopic"].value;
	console.log("Subscribing to topic ="+stopic);
	mqtt.subscribe(stopic);
	return false;
	}
	function send_message(msg,topic){
		if (connected_flag==0){
		out_msg="<b>Not Connected so can't send</b>"
		console.log(out_msg);
		document.getElementById("messages").innerHTML = out_msg;
		return false;
		}
		var value=msg.value;
		console.log("value= "+value);
		console.log("topic= "+topic);
		message = new Paho.MQTT.Message(value);
		message.destinationName = "web/"+topic;

		mqtt.send(message);
		return false;
	}

	
    </script>

  </head>
  <body onload="MQTTconnect()">
	

 <table>
<tr><td>Sensor1:<td><td  id="module1"><td><td >
<tr><td>Sensor2:</td><td  id="module2"><td></tr>

</table>
<div id="status">Connection Status: Not Connected</div>
</div>
<br>

Messages:<p id="messages"></p>
     <canvas id="canvas" width="1600" height="1000"></canvas>  
  </body>
</html>