Tag Archives: programming

Quick n easy media viewer in a browser

Februari 2021 i made a website to view images and movies in a browser to do some quick sorting. (borrowed some code from a codepen page i recall correctly)
At the time i didn´t have a good way to view webp webm media.
I wanted to view multiple files at the same time, and make it short and simple.

BTW no webserver needed, just open the file from a directory!
jpg’s png’s webm webp mp4 svg and animated gifs work. (maybe more, didn’t test more, whatever your browser supports)

With recent updates of the chrome browser the video attributes to mute is broken, i so made a workaround.
Also everything is in one file now.
Except for one issue .. i couldn´t create one file for images AND videos.

There is a piece of javascript i could not fix … yet
I have to do execute a document.createElement which is different for images and videos.
Also the attributes of video are mute,autoplay,loop,playinline

Examples:

index.html

<a href="video.html">Video version</a>
<div id="drop-area">
  <form class="my-form">
    <label class="button" for="fileElem">Drop some images</label>
  </form>
  <div id="gallery" /></div>
</div>
<style>
body {
  font-family: sans-serif;
}
#drop-area {
  border: 2px solid #ccc;
}
.my-form {
  margin-bottom: 10px;
}
#gallery {
  margin-top: 10px;
}
#gallery img {
  width: 300px;
}
}
#fileElem {
  display: none;
}
</style>
<script>
let dropArea = document.getElementById("drop-area")
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, preventDefaults, false)   
  document.body.addEventListener(eventName, preventDefaults, false)
})
;['dragenter', 'dragover'].forEach(eventName => {
  dropArea.addEventListener(eventName, highlight, false)
})
;['dragleave', 'drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, unhighlight, false)
})
dropArea.addEventListener('drop', handleDrop, false)
function preventDefaults (e) {
  e.preventDefault()
  e.stopPropagation()
}
function highlight(e) {
  dropArea.classList.add('highlight')
}
function unhighlight(e) {
  dropArea.classList.remove('active')
}
function handleDrop(e) {
  var dt = e.dataTransfer
  var files = dt.files
  handleFiles(files)
}
function handleFiles(files) {
  files = [...files]
  files.forEach(previewFile)
}
function previewFile(file) {
  let reader = new FileReader()
  reader.readAsDataURL(file)
  reader.onloadend = function() {
    let img = document.createElement('img')
    img.src = reader.result
    document.getElementById('gallery').appendChild(img)
  }
}
</script>

video.html

<a href="index.php">Images version</a>
<div id="drop-area">
  <form class="my-form">
    <label class="button" for="fileElem">Drop some videos</label>
  </form>
  <div id="gallery" /></div>
</div>
<style>
body {
  font-family: sans-serif;
}
#drop-area {
  border: 2px solid #ccc;
}
.my-form {
  margin-bottom: 10px;
}
#gallery {
  margin-top: 10px;
}
#gallery video {
  width: 300px;
}
}
#fileElem {
  display: none;
}
</style>
<script>
let dropArea = document.getElementById("drop-area")
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, preventDefaults, false)   
  document.body.addEventListener(eventName, preventDefaults, false)
})
;['dragenter', 'dragover'].forEach(eventName => {
  dropArea.addEventListener(eventName, highlight, false)
})
;['dragleave', 'drop'].forEach(eventName => {
  dropArea.addEventListener(eventName, unhighlight, false)
})
dropArea.addEventListener('drop', handleDrop, false)
function preventDefaults (e) {
  e.preventDefault()
  e.stopPropagation()
}
function highlight(e) {
  dropArea.classList.add('highlight')
}
function unhighlight(e) {
  dropArea.classList.remove('active')
}
function handleDrop(e) {
  var dt = e.dataTransfer
  var files = dt.files
  handleFiles(files)
}
function handleFiles(files) {
  files = [...files]
  files.forEach(previewFile)
}
function previewFile(file) {
  let reader = new FileReader()
  reader.readAsDataURL(file)
  reader.onloadend = function() {
    let video = document.createElement('video')
    video.setAttribute('volume', '0');
    video.setAttribute('height', '300');
    video.setAttribute('autoplay', true);
    video.setAttribute('loop', true);
    video.setAttribute('playsinline', true);
    video.setAttribute('oncanplay', 'this.muted=true');
    video.src = reader.result
    document.getElementById('gallery').appendChild(video)
  }
}
</script>

Motion detection for stupid webcams

Last year i made a script for a friend who wanted to detect visually if his garden sprinkler was on or off. A few days ago i saw someone who wanted to see if things where moving in his house. (didn’t trust his landlord i think)
But he only had a dumb/simple/cheap camera .. so it had no motion detection.

I was thinking of my script, and could easily adapt it for this usage.

Most ipcams have somekind of URL/API you can use to capture a image.
Some examples below

# Reolink
wget "http://ipnumber/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=randomstring&user=user&password=password" -O image.jpg

# Foscam
wget "http://ipnumber:88/CGIProxy.fcgi?cmd=snapPicture2&usr=user&pwd=password&cnt=randomstring" -O image.jpg

# Edimax
wget "http://user:password@ipnumber/jpg/image.jpg" -O image.jpg

# Hikvision
wget "http://user:password@ipnumber/ISAPI/Streaming/channels/101/picture" -O image.jpg

So using below script i can capture a image, compare it to the previous, and when it’s above a certain threshold sends a email.

#!/bin/bash
# Only uses wget and image-magick
treshhold=500
fuzzyness=20%
# CHANGE WEBCAM THINGY TO OWN URL AND CREDENTIALS
wget -q "http://webcamip/cgi-bin/api.cgi?cmd=Snap&channel=0&user=user&password=password" -O previous.jpg
while true;  do
wget -q "http://webcamip/cgi-bin/api.cgi?cmd=Snap&channel=0&user=user&password=password" -O current.jpg
value=$(compare -fuzz $fuzzyness previous.jpg current.jpg -metric mae diff.jpg 2>&1 | cut -f1 -d.)
if [ $value -gt $treshhold ] ; then
echo "ping $treshhold"
echo "Something moved" | mail -s "Movement" user@example.com -A diff.jpg
fi
# Comment below if you want to compare against a base line .. not previous image
cat current.jpg > previous.jpg
sleep 60
done

Example previous picture

Example current picture

I got mailed with result

Hints tips:

Use crop to detect only a part.

copy current.jpg to a second file
Use painting black a part and compair with different treshhold fuzzyness to get different hotspots.

Below detects RED, use above ide with crop to detect red/green/blue leds

compare -verbose -metric mae 1.jpg 2.jpg /tmp/1.diff
1.jpg JPEG 2560x1920 2560x1920+0+0 8-bit sRGB 248819B 0.050u 0:00.057
2.jpg JPEG 2560x1920 2560x1920+0+0 8-bit sRGB 248949B 0.030u 0:00.137
Image: 1.jpg
  Channel distortion: MAE
  Channel distortion: MAE
    red: 12517.5 (0.191005)
    green: 11967.1 (0.182607)
    blue: 12492.8 (0.190628)
    all: 12325.8 (0.18808)
1.jpg=>/tmp/1.diff JPEG 2560x1920 2560x1920+0+0 8-bit sRGB 1.19495MiB 1.470u 0:00.197

Glade and python – network tester

THIS IS A WORK IN PROGRESS ! .. Updates follow

UPDATE: Found a glade project from 2002
https://www.henriaanstoot.nl/2002/02/20/reverse-engineering-a-alpha-ticker-led-scoller/

The goal of this project is to have a raspberry-pi with a screen wich shows network information.
It wil be using a battery, touchscreen .. maybe some status leds.
When debugging network issues we want to have information when/if/how a network port works on our switches.

It should show:

  • dhcp ip
  • gateway
  • can access internet?
  • speedtest
  • detect if vlan tagged network packets are present on the port?
  • icmp test
  • list of detected nearby hosts?

A long time ago i played with glade and C / Perl.

But i’d rather use python so i’m looking into glade/python combi for this little project.

Glade is a gnome/GTK user interface RAD tool. (Rapid Application Development)

i’ve used zenity and yad before to create simple gui’s for bash scripts, these where only for quick and dirty solutions. (See other posts)
Glade is a far better solution, but a little harder to use.

Below is a little framework i started with

Python script

import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk

class Handler:
    def onDestroy(self, *args):
        Gtk.main_quit()

    def on_firstbutton_clicked(self, button):
        print("Ping test")

builder = Gtk.Builder()
builder.add_from_file("mytest.glade")
builder.connect_signals(Handler())

window = builder.get_object("Main")
window.show_all()

Gtk.main()

Glade file

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="Main">
    <property name="can-focus">False</property>
    <property name="title" translatable="yes">Networktool</property>
    <property name="default-width">440</property>
    <property name="default-height">250</property>
    <property name="icon-name">network-wired</property>
    <child>
      <object class="GtkFixed" id="fixed1">
        <property name="visible">True</property>
        <property name="can-focus">False</property>
        <child>
          <object class="GtkButton" id="firstbutton">
            <property name="label" translatable="yes">Ping test</property>
            <property name="width-request">100</property>
            <property name="height-request">16</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">True</property>
            <signal name="clicked" handler="on_firstbutton_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="x">56</property>
            <property name="y">40</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="speedtest">
            <property name="label" translatable="yes">Speed test</property>
            <property name="width-request">100</property>
            <property name="height-request">16</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
            <property name="receives-default">True</property>
          </object>
          <packing>
            <property name="x">56</property>
            <property name="y">89</property>
          </packing>
        </child>
        <child>
          <object class="GtkTextView">
            <property name="width-request">179</property>
            <property name="height-request">166</property>
            <property name="visible">True</property>
            <property name="can-focus">True</property>
          </object>
          <packing>
            <property name="x">222</property>
            <property name="y">36</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

Which is generated using the Glade designer

When running you get below screen

Old glade program (2003)

Energy bill and ledserver

Having a lot of devices and running a Lab wil use a lot of energy. Now with the energy crisis in Europe, i had to take a closer look at whats using power in my house.

I notished some weird usage patterns while measuring.

I’m using a few shelly power plugs, to measure devices and powerstrips.

With these devices you can control devices connected to it.
On/Off/Timer etcetera.
It wil measure the power usage in watts, and it even got a temperature sensor.
I like the fact that it perfectly integrates into your home automation using an extensive API.
curl commands to controll, and even MQTT messaging. Intergrating in Home Assistant is a breeze.

So i was monitoring a bunch of stuff using Nodered/Grafana/Homeassistant and saw some recurring usage.
But being always late to check things, i made use of my ledserver i’ve build a long time ago.

This ledserver consists of a Raspberry Pi Zero, with a led string and a API written in python.

Below is autostarted on the Raspberry

( I made this ledserver for work, it showed the status of servers and services. Beside that every colleage had a range which he could use for his own scripts. I made some little bash script templates to have led funtions standard in your bash profile.

#!/usr/bin/python


# apt-get install python-flask
#

import Adafruit_WS2801
import Adafruit_GPIO.SPI as SPI
import struct

from flask import Flask, render_template, request
app = Flask(__name__)

PIXEL_COUNT = 32
SPI_PORT   = 0
SPI_DEVICE = 0

pixels = Adafruit_WS2801.WS2801Pixels(PIXEL_COUNT, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))

pixels.clear()
pixels.show()

@app.route("/led/<deviceName>/<color>")
def action(deviceName, color):
        if deviceName == 'reset':
                print ("reset")
                pixels.clear()
        print (deviceName)
        led = int(deviceName)
        s = color
        r = int(s[ :2], 16)
        b = int(s[2:4], 16)
        g = int(s[4: ], 16)

        pixels.set_pixel_rgb(led, r,g,b)
        pixels.show()

        templateData = {
                'rled'  : r,
                'bled'  : b,
                'gled'  : g,
                'deviceName'  : deviceName,
        }
        return render_template('index.html', **templateData)

@app.route("/control/<controlcommand>")
def actioncommand(controlcommand):
        if controlcommand == 'clear':

                print("clear")
                pixels.clear()
                pixels.show()

        templateData = {
                'controlcommand'  : controlcommand,
        }
        return render_template('index.html', **templateData)

@app.route("/range/<start>/<stop>/<color>")
def rangecommand(start,stop,color):
        s = color
        r = int(s[ :2], 16)
        b = int(s[2:4], 16)
        g = int(s[4: ], 16)
        startled = int(start)
        stopled = int(stop)
        while (startled < stopled):
          pixels.set_pixel_rgb(startled, r,g,b)
          startled=startled + 1
        pixels.show()

        templateData = {
                'rangecommand'  : rangecommand,
        }


        return render_template('index.html', **templateData)



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

Now you can control the leds with a simple curl command:

curl http://ledserver:8080/range/startled/endled/colorinrgb
curl http://ledserver:8080/led/lednumber/colorinrgb
curl http://ledserver:8080/control/clear

So today i made a little script to show power usage.

I’m reading the current power usage from a LS120 Youless

Youless LS120 device, which you can connect to your P1 connector.

With below bash script i’m reading the webinterface and update the ledstring.
I was using this ledserver for general notification usage. Below a 2 minute hack ..

#!/bin/bash
while true; do
number=$(echo $(curl -s http://youlessip/a | grep Watt | head -1 | awk '{ print $1 }') / 100  | bc)
curl -s http://ledserver:8080/control/clear
curl -s http://ledserver:8080/range/00/$number/010101
sleep 10
done
Using 9 leds = 9xx watt

IRQ redirect for other programs

I’ve got a ROM in my 6502 which can load programs at $0200.
When running own programs i want to use IRQ’s, but my rom is also using IRQ routines.
So i was wondering if i could ‘hijack’ this IRQ for own program purposes.

So i’ve altered the rom to use a vector in userspace.

  • CPU starts, getting vector from FFFC
  • Goto $8000 main ROM program
  • Setting a jmp routine on zero page $F0
    • 4C C9 FF
    • 4C C9 FF ; second time, first one will redirect
  • Running my program on $0200
  • Change first jmp C9 FF to my own IRQ part
    • Changed jmp vectors
    • 4C 6E 02 ; jmp $026E (myprg)
    • 4C C9 FF ; jmp $FFC9 (rom)
  • Run rest of program

All seems fine and dandy … buzzer is sounding, but no blinky leds.
When flashing the rom with only my program, everything works ..
So whats going on? .. anyone?

00000000  78 a9 6e 85 f1 a9 02 85  f2 58 a9 ff 8d 03 50 8d  |x.n......X....P.| ; sei , lda #$6e, store $f1, lda #$02, store $f2 - so address $026e
00000010  02 50 a9 00 8d 01 50 8d  00 50 85 04 20 45 02 a9  |.P....P..P.. E..|
00000020  77 8d 04 50 a9 07 8d 05  50 20 2f 02 4c 29 02 38  |w..P....P /.L).8|
00000030  a5 00 e5 04 c9 19 90 0c  a9 40 4d 00 50 8d 00 50  |.........@M.P..P|
00000040  a5 00 85 04 60 a9 00 85  00 85 01 85 02 85 03 a9  |....`...........|
00000050  c0 8d 0b 50 a9 a0 8d 0e  50 a9 0e 8d 08 50 a9 27  |...P....P....P.'|
00000060  8d 09 50 a9 00 8d 04 50  8d 05 50 58 60 40 48 a9  |..P....P..PX`@H.| ; at $6e opcode 48 (pha) 
00000070  0e 8d 08 50 a9 27 8d 09  50 e6 00 d0 0a e6 01 d0  |...P.'..P.......|
00000080  06 e6 02 d0 02 e6 03 68  4c f3 00                 |.......hL..|

ROM parts

MYIRQ = $F0                                     ; Own IRQ vector <=================== my additions/alterations

; Below definitions for VIA 1 my loadable program uses VIA 2
PORTB = $6000                                   ; VIA port B 
PORTA = $6001                                   ; VIA port A
DDRB = $6002                                    ; Data Direction Register B
DDRA = $6003                                    ; Data Direction Register A

-------------8<------- snip

PROGRAM_LOCATION = $0200                        ; memory location for user programs

    .org $8000

main:                                           ; boot routine, first thing loaded
    ldx #$ff                                    ; initialize the stackpointer with 0xff
    txs

; ISR redirect code  <=================== my additions/alterations
    sei
    lda #$4C
    sta MYIRQ
    sta MYIRQ + 3
    lda #<ISR
    sta MYIRQ + 1
    sta MYIRQ + 4
    lda #>ISR
    sta MYIRQ + 2
    sta MYIRQ + 5
    cli

; End ISR redirect <=================== till here

; below this the standard rom routines

-------------8<------- snip
    .org $FFC9                                  ; as close as possible to the ROM's end

ISR:                                                  <====================== Whole ISR not my code
CURRENT_RAM_ADDRESS = Z0                        ; a RAM address handle for indirect writing
    pha
    tya
    pha
    lda ISR_FIRST_RUN                           ; check whether we are called for the first time
    bne .write_data                             ; if not, just continue writing
    lda #1                                      ; otherwise set the first time marker
    sta ISR_FIRST_RUN                           ; and return from the interrupt
    jmp .doneisr
.write_data:
    lda #$01                                    ; progressing state of loading operation
    sta LOADING_STATE                           ; so program_ram routine knows, data's still flowing
    lda PORTB                                   ; load serial data byte
    ldy #0
    sta (CURRENT_RAM_ADDRESS),Y                 ; store byte at current RAM location
                                                ; increase the 16bit RAM location
    inc CURRENT_RAM_ADDRESS_L
    bne .doneisr
    inc CURRENT_RAM_ADDRESS_H
.doneisr
    pla                                         ; restore Y
    tay
    pla                                         ; restore A
    rti

    .org $fffc
    .word main                                  ; Main ROM program
    .word MYIRQ                                 ; Redirect to OWN irq vector <=================== my additions/alterations

RAM Program

; Second VIA stuff
PORTB = $5000
PORTA = $5001
DDRB = $5002
DDRA = $5003
;------------------8<-------------

; Vector pointer on zero page
MYIRQ = $F0 

ticks = $00 ; 4 Bytes
toggle_time = $04 ; 1 Byte

    .org $0200

start:
; IRQ REDIRECT
    sei               ; irq masked
    lda #<irq         ; get low byte IRQ routine address 
    sta MYIRQ + 1     ; store at $F1

    lda #>irq         ; get high part of address
    sta MYIRQ + 2     ; store at $F2
    cli               ; irq enabled
; IRQ END REDIRECT

; init of program part
    lda #%11111111
    sta DDRA
    sta DDRB
        lda #$00
    sta PORTA
    sta PORTB
    sta toggle_time
    jsr init_timer
    lda #$77
    sta T1CL
    lda #$07
    sta T1CH

loop:                       ; loop 
    jsr update_led          ; update led routine
    jmp loop

update_led:
    sec
    lda ticks
    sbc toggle_time
    cmp #25
    bcc exit_update_led
    ; Toggle led
    lda #%01000000
    eor PORTB
    sta PORTB
    lda ticks
    sta toggle_time
exit_update_led:
    rts

;-----------------------------8<------------- snip

irq:
    pha
    lda #$0e
    sta T2CL
    lda #$27
    sta T2CH
    inc ticks
    bne end_irq
    inc ticks + 1
    bne end_irq
    inc ticks + 2
    bne end_irq
    inc ticks + 3
end_irq:
    pla
    jmp MYIRQ + 3           ; jmp to vector which points to ROM routine ; should be $FFC9

6502 update

  • New amplifier part using a LM386
  • Buzzer and led on VIA 2, blinky and sound timed by the internal timers of the 6522
  • ACIA testing still going on, writing software
  • Mini matrix keyboard removed, and used the temporary cursor buttons for the test with a rom which allows for a 8bits upload method using a arduino and the 6522. (I’m working on the big keyboard)

Work in progress code

PORT2B = $5000 		; VIA PORTB
PORT2A = $5001 		; VIA PORTA
DDR2B = $5002  		; Data direction register
DDR2A = $5003  		; Data direction register

PORTB = $6000 		; display
PORTA = $6001 		; control display + matrix keyboard
DDRB = $6002  		; data direction register
DDRA = $6003  		; data direction register
SID = $7000   		; sid base address

E  = %10000000		; enable bit
RW = %01000000		; RW bit 
RS = %00100000		; Register Select bit 
HOME = %00000010 	; VIA PORTB HOME command
DADDR = %00010000 	; VIA DADDRESS

LINENO = $0200		; temp address linenumber (move to other location)
NEXTLINE = 40		; 2x16 Chars but internally 40


  .org $8000

reset:
  ldx #$ff
  txs		; reset stack

; ###################################################
; #                 DISPLAY CONTROL                 #
; ###################################################
; VIA Setup

  lda #%11111111 	; Set all pins on port B to output
  sta DDRB
  lda #%11100000 	; Set top 3 pins on port A to output
  sta DDRA

; DISPLAY Setup
  lda #%00111000 	; Set 8-bit mode; 2-line display; 5x8 font
  jsr lcd_instruction
  lda #%00001110 	; Display on; cursor on; blink off
  jsr lcd_instruction
  lda #%00000110 	; Increment and shift cursor; don't shift display
  jsr lcd_instruction
  lda #$00000001 	; Clear display
  jsr lcd_instruction

; ###################################################
; #             PRINT MESSAGE LINE NO 0             #
; ###################################################
  lda #0  		; set line number
  sta LINENO      	; store for subroutine
  jsr gotoline		; move cursor

  ldx #0		; message index pointer
print:
  lda message0,x 	; start of message
  beq nextprint      	; stop when null in message (asciiz <- Zero padded)
  jsr print_char	; print char
  inx			; incr index
  jmp print		; resume print
; ###################################################
; #             PRINT MESSAGE LINE NO 1             #
; ###################################################
nextprint:
  lda #1  		; set line number
  sta LINENO      	; store
  jsr gotoline
  ldx #0  		; index pointer                 
print2:
  lda message1,x  	; absolute address message + x in A
  beq sidsound        	; if x is 0, end of message     
  jsr print_char  	; jump subroutine
  inx             	; increment x
  jmp print2      	; loop print2



; ###################################################
; #             SID SOUND                           #
; ###################################################
sidsound:
  lda #0		
  sta SID+$5		; attack/decay duration
  	
  lda #250
  sta SID+$6		; sustain level/release duration
  	
  lda #$95		; frequency voice 1 low byte
  sta SID+$0
  	
  lda #$44		; frequency voice 1 high byte
  sta SID+$1
  
  lda #%00100001	; sawtooth + gate
  sta SID+$4		; control register voice 1
  
  lda #$0f		; filter mode and volume (bits 3-0 main volume)
  sta SID+$18		; filter mode and volume



; ###################################################
; #             2ND VIA                             #
; ###################################################
  lda #%11111111 	; set port A output
  sta DDR2A

  lda #%11111111	; all ones!
  sta PORT2A
; ###################################################
  lda #%11111111 	; set port A output
  sta DDR2A

  lda #%11111111	; all ones!
  sta PORT2A



; ###################################################
; #             MAIN PROGRAM LOOP                   #
; ###################################################
loop:
  jmp loop
;                   1234567812345678
message0: .asciiz  "VIA 1,2 SID TEST"
message1: .asciiz  "   FASH  2022   "

; ###################################################
; #             ONLY SUBROUTINES                    #
; ###################################################

; ###################################################
; #             Subroutine gotoline                 #
; # Moves character placement position on display   #
; # Needs : $LINENO ADDRESS                         #
; # Exit values : -                                 #
; # Destroys registers: -                           #
; ###################################################

gotoline:
  pha                             ; store a
  txa
  pha                             ; store x
  ldx LINENO
  lda #HOME                       ; cursor down
  jsr lcd_instruction
  lda #$80
nextline:
  ldx LINENO
  cpx #00
  beq endnextlines
loopline:
  adc #40
  jsr lcd_instruction
  dex
  stx LINENO
  jmp nextline
endnextlines:
  pla                             ; pop a
  tax                             ; a to x
  pla                             ; pop a
  rts




; ###################################################
; #             LCD SUBROUTINES                     #
; ###################################################
lcd_wait:
  pha
  lda #%00000000  ; Port B is input
  sta DDRB
lcdbusy:
  lda #RW
  sta PORTA
  lda #(RW | E)
  sta PORTA
  lda PORTB
  and #%10000000
  bne lcdbusy
  lda #RW
  sta PORTA
  lda #%11111111  ; Port B is output
  sta DDRB
  pla
  rts
lcd_instruction:
  jsr lcd_wait
  sta PORTB
  lda #0         ; Clear RS/RW/E bits
  sta PORTA
  lda #E         ; Set E bit to send instruction
  sta PORTA
  lda #0         ; Clear RS/RW/E bits
  sta PORTA
  rts
print_char:
  jsr lcd_wait
  sta PORTB
  lda #RS         ; Set RS; Clear RW/E bits
  sta PORTA
  lda #(RS | E)   ; Set E bit to send instruction
  sta PORTA
  lda #RS         ; Clear E bits
  sta PORTA
  rts

nmi:
  rti

irq:
  rti

  .org $fffa
  .word nmi
  .word reset
  .word irq
;  .word $0000

6502 Update

New address decoder in place!
Connected RAM/ROM/SID/VIA1/VIA2 and ACIA

ROM8000-FFFF
SID7000-700F (sound)
VIA16000-60xx (Hex key matrix)
ACIA6800-68xx (serial)
VIA25000-50xx (led test at the moment)
RAM0000-3FFF

To plan: Bigger maxtrix keyboard and other displays

ACIA 6551

Got a serial connection working between the 6502 and my linux machine!

At the moment when a reset occurs , hello is being printed.
Text typed in the minicom terminal, is echo-ed back and displayed on the LCD display.

Things learned: Do not trust internet schematics blindly!

The crystal used for the ACIA (pin 6/7 1.8432Mhz needs a 1M ohm resistor parallel over the crystal, and a 30nF capacitor from pin 7 to GND

When using a terminal emulator, and using 3 wires. Disable hardware handshake.

Keyboard rewired.

What didn´t work as planned:

New amplifier schematic for the SID. There is too much noise.

Amplifier with a LM628

Bought a dual power supply (5V and 12V). But this one has a lot of signal noise on the SID part and even my battlestation speakers!

LED test 2nd via

PORTB = $5000 ; VIA PORTB
PORTA = $5001 ; VIA PORTA
DDRB = $5002  ; Data direction register
DDRA = $5003  ; Data direction register

LED  = %10000000

	.org $8000

reset:

	lda #%11100000 ; Set top 3 pins on port A to output
	sta DDRA

	lda LED 
	sta PORTA

loop:		; done loop until doomsday
	jmp loop

irq:
nmi:
	.org $fffa
	.word nmi
	.word reset
	.word irq

ACIA part

ACIA_RX = $6800
ACIA_TX = $6800
ACIA_STATUS = $6801
ACIA_COMMAND = $6802
ACIA_CONTROL = $6803

    lda #$00
    sta ACIA_STATUS
    lda #$0b
    sta ACIA_COMMAND
    lda #$1f
    sta ACIA_CONTROL

Address decoder in a ATF22V10

Whereas i needed to use several logical components to make a address decoder, below i only need one!

cat addressdecoder-fash.PLD 

ATF22V10 (GAL22V10)
Address Decoder

PHI2 A15 A14 A13 A12 A11 A10 A9  A8  A7  A6 GND
xx xx RAM ROM SID ACIA VIA1 VIA2 DEV0 DEV1 BANK VCC

/RAM = PHI2 * /A15 * /A14
/ROM = A15 * BANK
/SID = /A15 * A14 * A13 * A12
/VIA1 = /A15 * A14 * A13 * /A12 * /A11
/ACIA = /A15 * A14 * A13 * /A12 * A11
/VIA2 = /A15 * A14 * /A13 * A12

/DEV0 = A15 * /BANK

DESCRIPTION
Address decoder

galasm addressdecoder-fash.PLD # Generates below file which i can flash into the PLD

cat addressdecoder-fash.jed

Used Program:   GALasm 2.1
GAL-Assembler:  GALasm 2.1
Device:         GAL22V10

*F0
*G0
*QF5892
*L0924 11111111111111111111111111111111111111111111
*L0968 11100111111111111111111111111111111111111111
*L1496 11111111111111111111111111111111111111111111
*L1540 11111011011110110111111111111111111111111111
*L2156 11111111111111111111111111111111111111111111
*L2200 11111011011101111011101111111111111111111111
*L2904 11111111111111111111111111111111111111111111
*L2948 11111011011101111011011111111111111111111111
*L3652 11111111111111111111111111111111111111111111
*L3696 11111011011101110111111111111111111111111111
*L4312 11111111111111111111111111111111111111111111
*L4356 11010111111111111111111111111111111111111111
*L4884 11111111111111111111111111111111111111111111
*L4928 01111011101111111111111111111111111111111111
*L5808 01000101010101010100
*L5828 0100000101100100011001000111001001100101011100110111001100100000
*C50fa
*
b734
Only the left chip! .. The two on the right are 7Segment decoders

So one chip replaces schematic below!

Programming ATF22V10 PLD – 7 Segment with Linux

The ATF22V10 is a Programmable Logic Device. This means you can program the logic in the chip.

Internally it looks like a big matrix of connections which you can program to connect/disconnect from certain logic.

It has just a bunch of inputs/outputs

So if we want to have a 7 Segment decoder (you can easily buy a BCD decoder .. but these only work for displaying 0-9 and not 0-9A-F for displaying HEX numbers)

7 Segment display
Binary IN7 Segment decodedDisplays
D C B AA B C D E F G
0 0 0 01 1 1 1 1 1 00
0 0 0 10 1 1 0 0 0 0 1
0 0 1 0 1 1 0 1 1 0 12
0 0 1 11 1 1 1 0 0 13
0 1 0 00 1 1 0 0 1 14
0 1 0 11 0 1 1 0 1 15
0 1 1 0 1 0 1 1 1 1 16
0 1 1 1 1 1 1 0 0 0 0 7
1 0 0 01 1 1 1 1 1 18
1 0 0 11 1 1 1 0 1 19
1 0 1 01 1 1 0 1 1 1A
1 0 1 10 0 1 1 1 1 1B
1 1 0 0 1 0 0 1 1 1 0C
1 1 0 10 1 1 1 1 0 1D
1 1 1 01 0 0 1 1 1 1E
1 1 1 11 0 0 0 1 1 1F

Now we see that segment A is 1 in the case of (0,2,3,5,6,7,8,9,A,C,E,F)

When programming the PLD we can write that as: (note / means inverted a plus is OR, and * is AND)
So A is 0 in case of input being (1,4,B,D)

/QA = /D1 * /C1 * /B1 * A1
    + /D1 * C1 * /B1 * /A1
    + D1 * /C1 * B1 * A1
    + D1 * C1 * /B1 * A1

Complete code for galasm

Compiling and burning

GAL22V10
7SEGMENT

Clock   D1   C1   B1   A1    D2   C2    B2    A2    NC  NC   GND
/OE   NC    NC  NC  QG    QF    QE    QD   QC    QB   QA   VCC


/QA =   /D1 * /C1 * /B1 * A1
        + /D1 * C1 * /B1 * /A1
        + D1 * /C1 * B1 * A1
        + D1 * C1 * /B1 * A1

/QB=    /D1 * C1 * /B1 * A1
        + /D1 * C1 * B1 * /A1
        + D1 * /C1 * B1 * A1
        + D1 * C1 * /B1 * /A1
        + D1 * C1 * B1 * /A1
        + D1 * C1 * B1 * A1

/QC =   /D1 * /C1 * B1 * /A1
        + D1 * C1 * /B1 * /A1
        + D1 * C1 * B1 * /A1
        + D1 * C1 * B1 * A1


/QD=      /D1 * /C1* /B1 * A1
        + /D1 * C1 * /B1 * /A1
        + /D1 * C1 * B1 * A1
        + D1 * /C1 * B1 * /A1
        + D1 * C1 * B1 * A1

/QE =     /D1 * /C1 * /B1 * A1
        + /D1 * /C1 * B1 * A1
        + /D1 * C1 * /B1 * /A1
        + /D1 * C1 * /B1 * A1
        + /D1 * C1 * B1 * A1
        + D1 * /C1 * /B1 * A1

/QF =     /D1 * /C1 * /B1 * A1
        + /D1 * /C1 * B1 * /A1
        + /D1 * /C1 * B1 * A1
        + /D1 * C1 * B1 * A1
        + D1 * C1 * /B1 * A1

/QG =     /D1 * /C1 * /B1 * /A1
        + /D1 * /C1 * /B1 * A1
        + /D1 * C1 * B1 * A1
        + D1 * C1 * /B1 * /A1

DESCRIPTION
A 7 segment hex decoder

galasm 7seghex.gal

minipro -p ATF22V10CQZ -w 7seghex.jed

minipro -p ATF22V10CQZ -w 7seghex.jed
Found TL866II+ 04.2.129 (0x281)
Warning: Firmware is newer than expected.
  Expected  04.2.128 (0x280)
  Found     04.2.129 (0x281)

VPP=12V
Warning! JED file doesn't match the selected device!

Declared fuse checksum: 0x98D5 Calculated: 0x98D5 ... OK
Declared file checksum: 0x40B3 Calculated: 0x41A8 ... Mismatch!
JED file parsed OK

Use -P to skip write protect

Erasing... 0.33Sec OK
Writing jedec file...  5.01Sec  OK
Reading device...  0.32Sec  OK
Writing lock bit... 0.35Sec OK
Verification failed at address 0x16C6: File=0x01, Device=0x00 < ------------------ Gives error, but burning seems okay

henri@zspot:~/projects/galasm$ minipro -p ATF22V10CQZ -r 7seghex.out
Found TL866II+ 04.2.129 (0x281)
Warning: Firmware is newer than expected.
  Expected  04.2.128 (0x280)
  Found     04.2.129 (0x281)
Reading device...  0.32Sec  OK

Gives all zeros as output, but device works!

Programming languages

I’ve used a lot of programming languages, and besides that a few scripting languages.

Scripting is used to automate stuff, but probably use other tools under the hood. A programming language can probably do this by itself. Most of the time a programming language needs compiling into a executable form. Whereas a script is directly intepreted at runtime.

I’m not good at programming, but i understand the syntax and can read most of it.
My programming is mostly by example/copy-paste.
Below a list of programming languages and a table below that some scripting languages.

Sooo .. what do i like, still use and why?

Bash is my swiss army knife.
Making Web stuff? – PHP
Iot – C and Javascript
Advanced programming/Longer programs or Machine Learning – Python

And because of recent projects … i have to mention 6502 machinecode!

Programming languages i’ve used

BasicThe first programming language i learned. There are many dialects for many different systems.
PascalI learned to program in school.
Generic pascal and later Turbo Pascal
PLM/86This is relatively unknown programming language. Written for intel processors. It used a lot of ms-dos subroutines. Like dsso which stands for dos-standard-string-out.
dsso(@(‘Print this text’,eos));
And called a dos routine like below
(assembly example)
mov dx,(messageaddress)
mov ah,09h
int 21h
AssemblyStarted with 6502 assemby on my little home computer (a vic-20).
After that i learned to program 8085 assembly in school.
Also learned a little Z80 programming.
When i got a amiga i started with 68000 assembly.
And getting the hang of it, some friends and me started programming 80×86.
CFor a project I needed C programming to control a parallel port, for example for my controllable webcam.
Also recently the microcontrollers like the Arduino’s are programmed in C/C++
PerlPerl was also a interesting language, i bought myself a book and started with the examples.
One of my friends was a Perl wizard, but i could never get the hang of it. Even with his help.
Tcl/TKTCL stands for Tool Command Language, i used the TK extension. So Tcl/TK i used for creating GUI tools in linux. But like what i later used zenity and yad, i think these are more scripting languages.
PHPPHP i used extensively, one of my first big projects was a tunesearch engine with a mysql database.
PythonThe last years i’ve been using python more and more. Python has become the de facto standard for IT.
HaskellWell .. it is a programming language but i only use it to configure my Xmonad desktop.
JavascriptI’ve made a lot of webbased nonsence. PHP/CGI scripts/flash but i also used javascript.
Now i’m primarily using javascript for NodeRed

Scripting languages i’ve used

batDos batch files is a kind of scripting language
KshKorn Shell, i did a workshop ksh because i was a AIX admin.
Didn’t use this much, because you could install the linux toolkit, and could use bash after that.
BashI write a lot of things in bash, this is my preferred tool for fast and easy automation.
When it’s web based i use PHP
LuaI had to write some plugins for my Flightsim Setup

What about Sql, Dbase, Sed, Puredata and blocky those are all on the Programming Lanuages page of Wikipedia???
Well those i find more of a application markup language.
Then you can say abc-music and bmw (bagpipe music writer) are languages also!??

Some call Ansible a programming language, but this is incorrect. It is driven by python scripts and yaml config files.

Below some code part examples of different CPU assembly code

#6502 
    PUSH CX
    PUSH DI
    PUSH SI
    MOV AX,cry
    MOV BX,(2*40)
    MUL BX
    MOV DI,AX
    ADD DI,(2*31)
    MOV SI,adr1
    SUB SI,8       
    MOV CX,8

Z80
    LD H,00H
    LD B,01H
    LD A,(IX+00)
    OUT (01H),A
    LD A,(IY+00)
    OUT (02H),A
    DJNZ LUS3
    LD B,01H
    LD A,(IX+07)
    OUT (01H),A
    LD A,(IY+07)
    OUT (02H),A

#8085
    LDA 2050
    MOV H, A
    LDA 2051
    ADD H
    MOV L, A
    MVI A 00
    ADC A
    MOV H, A
    SHLD 3050
    HLT

#68000
    bsr send
    bsr delay2
    move.w #$38,d0
    bsr send
    bsr delay2
    move.w #$38,d0
    bsr send
    bsr delay2
    move.w #$01,d0
    bsr send
    bsr delay2
    move.w #$0c,d0
    bsr send
    move.w #$06,d0
    bsr send
    rts

#80x68
    mov bx,split
    and bx,1111111111b
    mov dx,3d4h
    mov al,18h
    mov ah,bl
    out dx,ax
    mov bl,bh
    xor bh,bh
    shl bx,1
    mov bx,[bx+offset ormsk]
    mov al,9
    out dx,al
    inc dx
    in al,dx
    and al,10111111b

For assembly i use or used below:
vasm – vasm is a portable and retargetable assembler – which can be used for a lot of different CPUs
masm – a assembler for 80×86, i used this for programming on DOS machines. Also for little projects i used the alway available debug executable.
seka/masterseka – programming 68000 on my amiga