mercoledì 1 giugno 2016

Sviluppo assembler su C64

Mi e' presa la voglia di tornare alle origini e programmare in assembler sul MOS 6502 (o meglio sul MOS 6510 del Commodore 64). Ovviamente il computer fisico e' in qualche discarica (o spero recuperato) e cerco di usare l'emulatore VICE

In modo, piu' o meno tradizionale, dopo aver avviato l'emulatore, si deve impiegare un assemblatore (nel caso Turbo Assembler per C64...con una curiosa omonimia con TASM Borland per x86) caricando l'immagine di un disco (preventivamente scaricat) con File/Attach Disk Image/Disk 8
con LOAD"$",8 e successivo LIST si ottiene il contenuto del disco


Si carica l'assemblatore con LOAD"*",8,1 ed al READY si digita SYS36864 entrando nella schermata nera di editing. Questo e' il semplice programma di test che stampa a video una stringa


programma in sintassi TASM
--------------------------------------------------
* = $1000

!basic
    ldx #$00
loop  
    lda message,x
    sta $0400,x
    inx
    cpx #$04
    bne loop
    rts
message .text "luca"
--------------------------------------------------

Per compilare il programma si deve usare la combinazione BackArrow+3 ma BackArrow non esiste sulla tastiera PC; si tratta del tasto piu' in alto a sinistra al di sotto del tasto di ESC (che nella tastiera italiana e' il backslash o barra rovescia)




s per start e si avvia il programma. Per rientrare nella fase di editing e' sufficiente ridigitare SYS 36864


E' comunque piuttosto noioso procedere nel modo classico ed e' molto piu' comodo usare C64 Studio (una IDE con allegato ACME un cross compiler 6502) e che permette di eseguire il programma lanciando autonomamente VICE



La differenza sostanziale tra i due metodi e' che usando C64 Studio si deve scrivere un preambolo in Basic che lancia poi il codice Assembler (in pratica una sola linea di codice BASIC che indichi un SYS49152 per passare il controllo al codice assembler...tale preambolo e' ralizzato con le sole righe *=$0801 ovvero la locazione di memoria dove risiede il compilatore BASIC e !basic.. non risulta necessario impostare *=$01000)

programma in sintassi ACME. Da notare come viene dichiarata la stringa
--------------------------------------------------
;set program start address
* = $0801

!basic
    ldx #$00
loop  
    lda message,x
    sta $0400,x
    inx
    cpx #$04
    bne loop
    rts
message !scr "luca"

fra le altre cose con C64 Studio si puo' utilizzare anche direttamente Basic


ArduinoTheremin

Questo progetto e' stata soltanto una occasione per usare la libreria Mozzi e non puo' considerato completo e finito.
Con Mozzi e' possibile trasformare Arduino in un sintetizzatore usando semplicemente il pin 9 ed il Ground collegandoli ai pin di un jack audio da pcb. Fra le altre cose il segnale in uscita e' cosi' alto che puo' essere direttamente mandato in cuffia senza necessita' di amplificazione


L'idea e' quella di usare due sensori ultrasonici SR-04 per controllare la frequenza ed il volume. Il problema e' che Mozzi usa i timer di Arduino per la propria necessita' di produzione audio e quindi SR-04 non e' il componente piu' adatto per interfacciarsi a Mozzi




le frequenze sono scalate da 4 a 40 cm con frequenze da 100 a 660 Hz (la frequenza e' stata poi portata 4 ottave piu' alto) mentre il volume va da 0 al massimo passando da 4 a 40 cm

la base utilizzata deriva da questo sketch
---------------------------------------------------------
/*
This file uses a Ultrasonic Sensor code that was
 modified from the a code found on: 
 http://winkleink.blogspot.ca/2012/05/arduino-hc-sr04-ultrasonic-distance.html
 and modified codes from Mozzi examples and reference documentation.
 */

// Include Mozzi Classes
#include <MozziGuts.h>;
#include <mozzi_config.h>
#include <Oscil.h>;
#include <tables/sin1024_int8.h>;
#include <tables/saw2048_int8.h>;
#include <tables/cos2048_int8.h>;
#include <mozzi_rand.h>;
#include <LowPassFilter.h>;

#define CONTROL_RATE 64

Oscil <2048, AUDIO_RATE> osc(SAW2048_DATA); // Oscilator waveform
Oscil <COS2048_NUM_CELLS, CONTROL_RATE> filterMod(COS2048_DATA); // Low Pass Filter waveform
Oscil <2048, CONTROL_RATE> kvib(SAW2048_DATA); // Vibrato Waveform
LowPassFilter lpf;

// Ultrasonic Sensor Pins
int trigPin = 11;
int echoPin = 12;
// Ultrasonic Sensor Pins
int trigPin2 = 8;
int echoPin2 = 7;

byte volume;

void setup(){
  Serial.begin(115200);
  startMozzi(CONTROL_RATE);
  //lpf.setResonance(20);
  kvib.setFreq(16.5f);
  filterMod.setFreq(1.3f);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(trigPin2, OUTPUT);
  pinMode(echoPin2, INPUT);
}

void updateControl(){

  // Distance Sensor
  int duration, distance;
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(100);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;
  int freq = map(distance, 4, 40, 100, 660);
  /*
  C = 261
  C#= 277
  D = 293
  D#= 311
  E = 329 
  F = 349
  F#= 369
  G = 391
  G#= 415
  A = 439
  A#= 466
  B = 493
  C = 523
  */
  
  
  int duration2, distance2;
  digitalWrite(trigPin2, HIGH);
  delayMicroseconds(100);
  digitalWrite(trigPin2, LOW);
  duration2 = pulseIn(echoPin2, HIGH);
  distance2 = (duration2/2) / 29.1;
  volume = map(distance2, 4, 40, 0, 255);
  
  byte cutoff_freq = 100 + filterMod.next()/2;
  lpf.setCutoffFreq(cutoff_freq);
  osc.setFreq(freq*2);

  //float depth = 1; // vibrato depth
  //float vibrato = depth * kvib.next();

  /*if (rand(CONTROL_RATE/2) == 0) // Low Pass Filter Frequency
  {
    filterMod.setFreq((float)rand(255)/64);
  }
  byte cutoff_freq = 100 + filterMod.next()/2;
  lpf.setCutoffFreq(cutoff_freq);

  if(xRead > 500){
    osc.setFreq(freq);
  }
  else if(xRead < 500){
    osc.setFreq(freq*4);
  } */
}

int updateAudio(){
  char audio = (lpf.next(osc.next())*volume)>>8;
  return (int) audio;
}

void loop(){
  audioHook(); 
}

lunedì 30 maggio 2016

Foto aeree con Google Carboard

Visto che l'esperimento con gli anaglifi era riuscito ma non nel modo ottimale ho provato a migliorare, questa volta usando un vero stereoscopio,ovvero Google Cardboard, anche se dal costo decisamente economico (uno stereoscopio da tavolo per foto aeree costa sopra il migliaio di euro)


Sul telefono ho montato una semplice pagina web sul telefono Android che scalava e centrava i due fotogrammi precedentemente registrati a mano (in versioni successive sarebbe comodo avere la possibilita' di spostare uno dei fotogrammi via telecomando bluetooh per centrare le immagini guardando nel visore)

Con questo sistema la visualizzazione 3D e' decisamente buona e molto piu' simile a quella del vero stereovisore per foto aeree rispetto a quella anaglifica

index.html
-------------------------
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class ="stereo">
    <div id="sinistra">
      <img alt="Sinistra" title="Sinitra" src="594_2.png" style="width: 100%; max-height: 100%"/>
   </div>
    <div id="destra">
      <img alt="Sinistra" title="Sinitra" src="595_2.png" style="width: 100%; max-height: 100%"/>

   </div>
</div>
</body>
-------------------------

style.css
-------------------------
.stereo{
        width: 100%;
        overflow: hidden;
    }

    #sinistra {
        float: left;
        width: 50%;
    }
   #sinistra img
   {

      margin: auto;
      display: block;
   }
    #destra {
        float: left;
        width: 50%;
    }
   #destra img
   {
      margin: auto;
      display: block;
   }
-------------------------



Foto aeree con anaglifi

A lavoro mi capita spesso la necessita' di visualizzare foto aeree ma non ho un visore stereoscopico. Ho scoperto un sistema semplice (e lecito) per scaricare le stereocoppie dal sito della Regione Toscana (evitando un generoso esborso) e cosi' mi sono messo alla ricerca di un sistema per visualizzare la terza dimensione


Il primo tentativo e' stato quello di utilizzare gli anaglifi mediante l'uso degli occhialini rossi/ciano (qualcuno si ricorda del film lo Squalo 3D??)

Il sistema piu' semplice, una volta scelti i due fotogrammi, e' quello di usare il programma AnaBuilder che permette di coregistrare in automatico le due immagini sia come traslazione che come rotazione dal menu Actions/AutoFit with borders detection


Il risultato non e' male, anche considerando che non c'e' intervento umano, ma il programma riesce a lavorare solo su piccole porzioni della stampa. Introducendo una stampa completa della foto aerea, normalmente in formato 24x24 cm scannerizzata poi a 600 dpi, il programma si blocca.



Il risultato finale e' una immagine blandamente in 3D perche' manda tutta l'esagerazione verticale che fornisce un vero stereoscopio

ps. per scaricare la stereocoppie si puo' andare su Geoscopio, selezionare l'area di interesse, cliccare su Fotogrammi per esempio 2013 (non tutti gli anni hanno la copertura completa del territorio!!) , poi con lo strumento Freccia +, si seleziona uno squadro di un fotogramma e si clicca su visualizza fotogramma. Si ripete il tutto con il fotogramma vicino ed abbiamo una stereocoppia giocando con  poi con i livelli di zoom per avere il dettaglio desiderato. Per rimuovere la finestra della legenda si puo' premere il tasto h (il visualizzatore di immagini e' IIPImage)


Fauna caldinese - Nido

Nido, forse di passero, caduto a terra








giovedì 26 maggio 2016

Bossac: extra argument found su IDE Arduino Due

E' un po ' di tempo che non usavo Arduino Due ed la proma novita' e che per compilare i programmi nella IDE 1.6.8 si devono scaricare le definizioni della scheda da Strumenti/Scheda/Gestore Scheda selezionando Arduino SAM Boards 32 bits ARM Cortex-M3


Una volta modificato in questo modo l'ambiente di sviluppo ho provato a compilare uno sketch ma sia su Windows che Linux compariva lo stesso messaggio

bossac : extra argument found

il problema risiede nello switch w e si risolve andando nel file

/home/linnocenti/.arduino15/packages/arduino/hardware/sam/1.6.8/platform.txt

si va quindi alla riga 106 e si elimina dopo -w il codice {upload.verify}. La riga corretta e' la seguente

tools.bossac.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -U {upload.native_usb} -e -w -b "{build.path}/{build.project_name}.bin" -R
in questo modo la compilazione arriva al termine correttamente

mercoledì 25 maggio 2016

Troubleshooting Mysql

Questa volta sono stato contattato perche' un server, che in passato ho montato ed amministrato direttamente per un annetto, aveva iniziato a fare le bizze.
Una rapida occhiata con htop ha mostrato che la macchina era in picco con il processore tra 85% e 100% e con tutti i processi principali occupati da Mysql



Htop


Una volta capito il responsabile c'era da capire il motivo. Il primo sospetto, visto il tempo di esecuzione di ogni processo, era che le query fossero talmente lunghe e frequenti da sovrapporsi nel tempo da creare un effetto a cascata che rendeva dopo un po' il tempo il server non utilizzabile

Per definire il problema ho usato il comando

mysqladmin -u root -p -i 1 processlist
in questo modo si ottiene una lista dei processi in corso sul server MySql 
evidenziando anche la query ed il tempo di esecuzione di ciascuna query.
In questo modo si ottiene una  lista dei processi in corso sul server Mysql evidenziando anche la query in corso ed il tempo di esecuzione. Impostando il parametro i ad 1 si ottiene i dati relativi ad 1 secondo di tempo. Nel parziale listato si e' visto che in un secondo venivano eseguite oltre 120 query complesse con il tempo in secondo impiegato da ciascun  thread
------------------------------------------------------------------------
+-------+----------------------+--------------------------+--------+---------+------+----------------------+------------------------------------------------------------------------------------------------------+----------+
| Id    | User                 | Host                     | db     | Command | Time | State                | Info                                                                                                 | Progress |
+-------+----------------------+--------------------------+--------+---------+------+----------------------+------------------------------------------------------------------------------------------------------+----------+
| 12296 | utente               | localhost                | db | Query   | 2    | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.f     
                                        WHERE NET = (SELECT NET.NET_ID
         | 0.000    |
| 12299 | utente               | localhost                | db | Query   | 16   | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.f     
                                        WHERE NET = (SELECT NET.NET_ID
         | 0.000    |
| 12303 | utente               | localhost                | db | Query   | 4    | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.f     
                                        WHERE NET = (SELECT NET.NET_ID
         | 0.000    |
| 12308 | utente               | localhost                | db | Query   | 33   | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.f     
                                        WHERE NET = (SELECT NET.NET_ID
         | 0.000    |
| 13392 | utente               | localhost                | db | Query   | 35   | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.E     
                                        WHERE NET = (SELECT NET.NET_ID
                     | 0.000    |
| 13396 | utente               | localhost                | db | Query   | 11   | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.E     
                                        WHERE NET = (SELECT NET.NET_ID
                     | 0.000    |
| 13399 | utente               | localhost                | db | Query   | 5    | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.E     
                                        WHERE NET = (SELECT NET.NET_ID
                     | 0.000    |
| 13403 | utente               | localhost                | db | Query   | 26   | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.E     
                                        WHERE NET = (SELECT NET.NET_ID
                     | 0.000    |
| 13411 | utente               | localhost                | db | Query   | 40   | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.E     
                                        WHERE NET = (SELECT NET.NET_ID
                     | 0.000    |
| 14407 | utente               | localhost                | db | Query   | 45   | Sending data         | SELECT AVG(VAL) AS VAL
                                        FROM db.E     
                                        WHERE NET = (SELECT NET.NET_ID
                     | 0.000    |
| 14411 | utente               | localhost                | db | Query   | 54   | Sending data         | SELECT AVG(VAL) AS VAL 

------------------------------------------------------------------------
ovviamente un traffico che ha messo in ginocchio il server.

Un metodo alternativo e' quello di installare mytop (un clone del comando top specifico per MySql)
Il comando si puo' lanciare passando i parametri da file di configurazione oppure tramite switch sulla linea di comando. Ho usato la seconda strada

mytop -u root -d databasename --prompt
(e' necessario inserire il nome del database, non accetta il monitoraggio di tutti i db)

Mytop del server quando sono state interrotte le query lunghe

In questa modalita' vengono mostrate le query per secondo e le query lente con il traffico di rete











Aruco Tag e filtri Kalman

Usando gli Aruco tag in ambiente esterno con illuminazione solare a diverse ore e in diversi periodi dell'anno ho trovato un errore nell...