venerdì 25 febbraio 2022

Grafica base in Go

 package main


import "github.com/fogleman/gg"

func main() {
    dc := gg.NewContext(1000, 1000)
    //dc.Push()
    dc.DrawCircle(500, 500, 400)
    dc.SetRGB255(0, 0, 0)
    dc.Fill()
   
    dc.SetHexColor("#008080")
    dc.DrawRectangle(10,10,40,30)
    dc.SetRGB255(255, 0, 0)

    dc.Fill()
   
    dc.SavePNG("out.png")
}

martedì 22 febbraio 2022

Webassembly Golang Mandelbrot

Era da tempo che volevo provare WebAssembly (abbreviato wasm).. ho scoperto che sia GoLang che Qt permettono di compilare in Wasm e cosi' ho fatto una prova

Per eseguire applicazioni WAsm si deve configurare il webserver a riconoscere il Mime Type wasm . In Apache e' sufficiente aggiungere la linea in /etc/mime.types mentre in NGinx /etc/nginx/mime.types con application/wasm  wasm;

Il file compilato deve avere l'estensione .wasm

Per compilare il file go.wasm si usa la linea di comando

GOOS=js GOARCH=wasm go build -o wasm.wasm

ATTENZIONE: i file wasm rimangono in cache del browser. In fase di sviluppo e' quindi necessario sincerarsi di pulire la cache con CTRL+SHIFT+R (od usare una sessione anonima)

Per creare il file wasm_exec.js e' sufficiente (attenzione al punto finale)

cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

Il programma genera una immagine dell'insieme di Mandelbrot che viene codificata in PNG e successivamente in Base64 per divenire la src del tag img della pagina web

https://github.com/c1p81/gowasm_mand


wasm.go

package main

// cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

import (
"bytes"
"encoding/base64"
"fmt"
"image"
"image/color"
"image/png"
"io/ioutil"
"syscall/js"
)

func funzione() js.Func {
jsonFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {

//////////////////////////////////////////////////////////////////////////////
var SCREEN_WIDTH int = 400
var SCREEN_HEIGHT int = 400

var re_min float32 = -2.0
var im_min float32 = -1.2
var re_max float32 = 1.0
var im_max float32 = 1.2

var iterazioni int = 1024

var a, b float32
var x, y, x_new, y_new, somma float32
var k, i, j int

var re_factor float32 = (re_max - re_min)
var im_factor float32 = (im_max - im_min)

m := image.NewRGBA(image.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))

for i = 0; i < SCREEN_HEIGHT; i++ {
for j = 0; j < SCREEN_WIDTH; j++ {
a = re_min + (float32(j) * re_factor / float32(SCREEN_WIDTH))
b = im_min + (float32(i) * im_factor / float32(SCREEN_HEIGHT))
x = 0
y = 0

for k = 0; k < iterazioni; k++ {
x_new = (float32(x) * float32(x)) - (float32(y) * float32(y)) + float32(a)
y_new = (float32(2) * float32(x) * float32(y)) + float32(b)
somma = (x_new * x_new) + (y_new * y_new)
if somma > 4 {
if k%2 == 0 {
m.Set(j, i, color.RGBA{0, 0, 0, 255})
} else {
m.Set(j, i, color.RGBA{255, 255, 255, 255})
}
break
}
x = x_new
y = y_new
}
}
}

buf := new(bytes.Buffer)
if err := png.Encode(buf, m); err != nil {
return ("unable to encode png")
}
readBuf, _ := ioutil.ReadAll(buf)

enc := base64.StdEncoding.EncodeToString([]byte(readBuf))

return "data:image/png;base64," + enc
})
return jsonFunc
}

func main() {
fmt.Println("Inizio")
js.Global().Set("go_function", funzione())
fmt.Println(funzione())
<-make(chan bool)
}

 

Index.html

<html>
<head>
<meta charset="utf-8"/>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("wasm.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
</head>
<body>
<center> 2
<img id="immagine" name="immagine" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" /><br><br>
<input id="button" type="submit" name="button" onclick="ff()"/> <br>
<textarea id="imgbase64" name="imgbase64" cols="80" rows="200"></textarea>

</center>



<script>
var ff = function() {
immagine.src = go_function(ff)
imgbase64.value = go_function(ff)
}
</script>
</body>
</html>




venerdì 11 febbraio 2022

Ser2Net Go

 Premesso che questo non e' il sistema corretto di usare una goroutine in quanto non termina mai ho provato a fare questo programma che in una goroutine legge i valori da una porta seriale e tramite un channel manda i dati ad un'altra goroutine che invia sulla rete

non e' un codice da copiare

package main
import (
    "bufio"
    "fmt"
    "io"
    "log"
    "net"
    "time"

    "github.com/tarm/serial"
)

/*
per fare i test si puo' creare una porta seriale virtuale con
socat -d -d pty,raw,echo=0 pty,raw,echo=0
il sistema risponde con messaggi del tipo
socat -d -d pty,raw,echo=0 pty,raw,echo=0

2022/01/02 14:53:04 socat[18636] N PTY is /dev/pts/3
2022/01/02 14:53:04 socat[18636] N PTY is /dev/pts/4
2022/01/02 14:53:04 socat[18636] N starting data transfer loop with FDs [5,5] and [7,7]

si apre un altro terminale e si inviano i messaggi sulla seconda porta
echo "messaggio" > /dev/pts/4
il programma in Go deve andare in ascolto sull /dev/pts/3
*/

func main() {
    canale := make(chan []byte, 1024)

    usbRead := &serial.Config{Name: "/dev/pts/3", Baud: 9600}
    //s, err := serial.OpenPort(c)
    port, err := serial.OpenPort(usbRead)
    if err != nil {
        log.Fatal(err)
    }
    scanner := bufio.NewScanner(port)
    go scrivi_channel(canale, scanner)

    listener, err := net.Listen("tcp", "localhost:8000")
    if err != nil {
        log.Fatal(err)
    }
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err) // e.g., connection aborted
            continue
        }
        handleConn(conn, canale) // handle one connection at a time
    }
}

func handleConn(c net.Conn, canale chan []byte) {
    defer c.Close()
    for {
        _, err := io.WriteString(c, string(<-canale)+" "+time.Now().Format("15:04:05\n"))
        if err != nil {
            return // e.g., client disconnected
        }
        time.Sleep(1 * time.Second)
    }
}

func scrivi_channel(canale chan []byte, scanner *bufio.Scanner) {
    buf := make([]byte, 128)
    scanner.Buffer(buf, 128)
    for {

        //scanner.Buffer(buf, 128)
        scanner.Scan()
        input := scanner.Text()
        fmt.Println(input)
        canale <- []byte(input)
        time.Sleep(1 * time.Second)
    }

    //time.Sleep(1 * time.Second)
    //canale <- []byte("test")
}

Rest Client in Python

Dopo la versione in Go la medesima funzione in Python 


import requests
from requests.structures import CaseInsensitiveDict
import json

url = "http://xxxxxxxxxxxxx/api/v1/authentication/"

headers = CaseInsensitiveDict()


headers["api-key"] = "apikey"
headers["Accept"] = "application/json"
headers["api-version"] = "v1"
headers["device-language"] = "it"
headers["id-user-session"] = "guest"
headers["Authorization"] = "Basic Z2xxxxxxxxxxxxxxxxxxxxxxxxxxx=="



resp = requests.get(url, headers=headers)

print(resp.content)
if(resp.ok):
    jData = json.loads(resp.content)

    print("The response contains {0} properties".format(len(jData)))
    print("\n")
    for key in jData:
        print(str(key) + " : " + str(jData[key]))
else:
    resp.raise_for_status()

TicTacToe Go

 Volevo provare a creare una macchina di apprendimento per il gioco TicTacToe (Tris) 

Il passo e' stato quello di creare il gioco per umani...la cosa che mi ha dato piu' soddisfazione e' stata la funzione per determinare la condizione di vittoria dei giocatori

In pratica ogni casella del gioco e' associata ad una potenza di 2...si sommano i valori delle caselle e si fa un AND con la maschera di bit delle condizioni di vittoria

il prossimo passo e' salvare le varie partite con una Trie 

---------------------------

Il nome delle caselle e' cosi' ordinato

0 | 1 | 2
______
3 | 4 | 5
______
6 | 7 | 8



package main

import (
    "fmt"
    "math"
    "os"
    "strconv"
)

var display [9]int // array per mostrare il gioco
var step int       // numero di mossa
var giocatore int
var mossa_valida bool

func reset() {
    for k := 0; k < 9; k++ {
        display[k] = 0
    }
    step = 1
    giocatore = 3
    mossa_valida = false
}

func controlla_vittoria() int {
    totale_1 := 0
    totale_2 := 0

    // per il calcolo della scacchiera ad ogni casella corrispondente un valore di potenza di 2
    // si sommano tutti le caselle occupate da un giocatore
    // poi si effettua un AND logic con le 8 posizioni vincenti

    // giocatore 1
    for k := 0; k < 9; k++ {
        if display[k] == 3 {
            totale_1 = totale_1 + int(math.Pow(float64(2), float64(k)))
        }
    }

    if (totale_1 & 448) == 448 {
        return 1
    }
    if (totale_1 & 56) == 56 {
        return 1
    }
    if (totale_1 & 7) == 7 {
        return 1
    }
    if (totale_1 & 292) == 292 {
        return 1
    }
    if (totale_1 & 146) == 146 {
        return 1
    }
    if (totale_1 & 73) == 73 {
        return 1
    }
    if (totale_1 & 273) == 273 {
        return 1
    }
    if (totale_1 & 84) == 84 {
        return 1
    }

    // giocatore 2
    for k := 0; k < 9; k++ {
        if display[k] == 2 {
            totale_2 = totale_2 + int(math.Pow(float64(2), float64(k)))
        }
    }

    if (totale_2 & 448) == 448 {
        return 2
    }
    if (totale_2 & 56) == 56 {
        return 2
    }
    if (totale_2 & 7) == 7 {
        return 2
    }
    if (totale_2 & 292) == 292 {
        return 2
    }
    if (totale_2 & 146) == 146 {
        return 2
    }
    if (totale_2 & 73) == 73 {
        return 2
    }
    if (totale_2 & 273) == 273 {
        return 2
    }
    if (totale_2 & 84) == 84 {
        return 2
    }

    return 0 // se ritorna 0 nessuno ha vinto
}

func casella(c int) string {
    switch c {
    case 0:
        return (" ")
    case 3:
        return ("X")
    case 2:
        return ("O")
    }
    return " "
}

func mostra_gioco() {
    fmt.Print(casella(display[0]))
    fmt.Print("|")
    fmt.Print(casella(display[1]))
    fmt.Print("|")
    fmt.Println(casella(display[2]))
    fmt.Println("-----")
    fmt.Print(casella(display[3]))
    fmt.Print("|")
    fmt.Print(casella(display[4]))
    fmt.Print("|")
    fmt.Println(casella(display[5]))
    fmt.Println("-----")
    fmt.Print(casella(display[6]))
    fmt.Print("|")
    fmt.Print(casella(display[7]))
    fmt.Print("|")
    fmt.Println(casella(display[8]))
}

func main() {

    var tasto int

    step = 1
    giocatore = 3
    mossa_valida = false
    mostra_gioco()
    fmt.Println("Turno al Giocatore " + strconv.Itoa(giocatore-2))

    for {
        for { // controlla se e' una mossa valida

            if !mossa_valida {
                fmt.Print("Enter move: ")
                fmt.Scanln(&tasto)
                // controlla se e' un tasto valido

                if display[tasto] == 0 { // controlla se la casella e' valida
                    mossa_valida = true
                    display[tasto] = giocatore
                    giocatore = ((giocatore + 1) % 2) + 2
                    fmt.Println("Turno al Giocatore " + string(giocatore+2))
                    break
                } else {
                    fmt.Println("Mossa non valida")
                }

            }
        }

        step++ // aumenta il numero della mossa
        mossa_valida = false
        mostra_gioco()
        v := controlla_vittoria()
        switch v {
        case 1:
            fmt.Println("****************************")
            fmt.Println("*** Vittoria Giocatore 1 ***")
            fmt.Println("****************************")
            reset()
            mostra_gioco()
            break
        case 2:
            fmt.Println("****************************")
            fmt.Println("*** Vittoria Giocatore 2 ***")
            fmt.Println("****************************")
            reset()
            mostra_gioco()
            break
        }
        if step == 9 {
            fmt.Println("***************************")
            fmt.Println("******** Pareggio *********")
            fmt.Println("***************************")
            reset()
            mostra_gioco()
            break
        }
    }
    os.Exit(0)
}

Rest client in GO

Un semplice di client di servizio Restful con GO


package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    client := http.Client{}
    req, err := http.NewRequest("GET", "http://xxxxxxxxxxxxxxxxx/api/v1/authentication/", nil)
    if err != nil {
        //Handle Error
    }

    req.Header = http.Header{
        "Host":                  []string{"http://xxxxxxxxxxxxxxxxxx/api/v1/authentication/"},
        "api-key":         []string{"axxxxxxxxxxxx"},
        "api-version":     []string{"v1"},
        "device-language": []string{"it"},
        "id-user-session": []string{"guest"},
        "Accept":                []string{"application/json"},
        "Authorization":         []string{"Basic Z2lvxxxxxxxxxxxxxxsaQ=="},
    }

    res, err := client.Do(req)

    if err != nil {
        fmt.Errorf("got error")
    } else {
        //fmt.Println("--------------------------")
        //fmt.Println(res)
    }
    defer res.Body.Close()

    b, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatalln(err)
    }

    fmt.Println(string(b))
}

JSon in Go

 Leggere Json in Go non e' esattamente banale perche' il linguaggio e' fortemente tipizzato

Se il tracciato record del Json e' fissato e' conosciuto si puo' fare un Unmarshal del tracciato altrimenti con Json dinamici o non conosciuti la situazione diventa piu' complessa

Partiamo da un Json complesso

---------------------------------------------------------------------------

 {
        "statusCode":200,
        "message":"OK",
        "dataValue":
            {
                "versionWS":"v1",
                "language":"it",
                "idUserSession":
                "wguest",
                "user":
                    {
                        "userId":27,
                        "userName":"G",
                        "userSurname":"G",
                        "idUserSession":"c4cefc3032e3f8e63f3ee320b81cf1d5"
                    }
            }
    }

---------------------------------------------------------------------------

per fare l'Unmarshal del Json si deve definire tramite Struct il tracciato record con indicato anche il tipo di variabile associata ad ogni campo...in questo campo essendoci piu' livelli si devono creare delle Struct intermedie per i livelli piu' interni. Da notare che le variabilenelle Struct hanno la prima lettera maiuscola per l'esportazione ed il tag Json corrispondente

Interessa arriva a leggere la proprieta' idUserSession dell'utente (si tratta di gestire una authorization da un servizio Restful)

---------------------------------------------------------------------------

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    UserId        int32  `json:"userId"`
    UserName      string `json:"userName"`
    UserSurname   string `json:"userSurname"`
    IdUserSession string `json:"idUserSession"`
}

type dataValue struct {
    VersionWS            string `json:"versionWS"`
    Language             string `json:"it"`
    IdUserSession        string `json:"idUserSession"`
    Wguest string `json:"wguest"`
    User                 User   `json:"user"`
}

type messaggio struct {
    StatusCode int32     `json:"statusCode"`
    Message    string    `json:"message"`
    DataValue  dataValue `json:"dataValue"`
}

func main() {
    b := []byte(`    {
        "statusCode":200,
        "message":"OK",
        "dataValue":
            {
                "versionWS":"v1",
                "language":"it",
                "idUserSession":"",
                "guest":"",
                "user":
                    {
                        "userId":27,
                        "userName":"G",
                        "userSurname":"G",
                        "idUserSession":"c"
                    }
            }
    }`)
    var mes messaggio
    json.Unmarshal(b, &mes)
    fmt.Println(mes.DataValue.User.IdUserSession)

}

---------------------------------------------------------------------------

fino a qui e' abbastanza lineare. Senza il tracciato record non si puo' fare Unmarshal di una Struct ma si deve passare attraverso una interface e gestire i vari livelli di map fino a trovare il valore richiesto


---------------------------------------------------------------------------
package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    b := []byte(`    {
        "statusCode":200,
        "message":"OK",
        "dataValue":
            {
                "versionWS":"v1",
                "language":"it",
                "idUserSession":"":
                "guest":"",
                "user":
                    {
                        "userId":27,
                        "userName":"G",
                        "userSurname":"G",
                        "idUserSession":"c"
                    }
            }
    }`)

    var dat map[string]interface{}

    if err := json.Unmarshal(b, &dat); err != nil {
        panic(err)
    }
    test := dat["dataValue"].(map[string]interface{})["user"]
    if rec, ok := test.(map[string]interface{}); ok {
        for key, val := range rec {
            if key == "idUserSession" {
                fmt.Printf(" %s = %s", key, val)
                fmt.Println()
            }

        }
    }

}

---------------------------------------------------------------------------



Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...