mercoledì 8 giugno 2016

Windows XP e Dropbox (API)

Il prossimo 29 agosto Dropbox terminera' il supporto per il client Windows XP.
Al contrario di come fanno altre ditte, per esempio Google con Chrome, la fine del supporto non indica che non saranno piu' sviluppati aggiornamenti ma che il client terminera' il suo funzionamento (sara' sempre disponibile l'interfaccia web)

Considerando che Dropbox e' di proprieta' Microsoft e che il servizio e' fondamentalmente gratuito non e' da biasimare Microsoft se cerca di piazzare qualche SO nuovo...ma forse una soluzione semplice esiste ed e' quella di usare un client Python usanto le API dell'SDK di Dropbox




Per usare il client Python ci si deve prima registrare su Dropbox Developer, creare una App (la piu' semplice e' App Folder) e generare un Access Token

Successivamente si scaricare l'SDK Python di Dropbox da questo indirizzo https://github.com/dropbox/dropbox-sdk-python installandolo poi con il classico

python setup.py install

a questo si puo' modificare il programma updown.py che permette di sincronizzare una cartella (cosi' come fa il client). Per personalizzare la directory da sincronizzare si deve modificare la rootdir (di default e' Downloads) e la cartella remota di Dropbox.

il progrramma si lancia quindi con la sintassi (il token si deve copiare dalle impostazioni della app)

python updown.py --token xxxxxxxxxxxxxxxxxxxxxxxxxxxxx --yes 

(lo yes finale risponde in modo affermativo alle domande in modo da sovrascrivere in modo automatico)


i file sincronizzati non si trovano nella radice di Dropbox ma nella sottodirectory /App/nomedellaApp








Mandelbrot su C64 in Assembler

Frugando su internet ho trovato la versione in Assembler di Mandelbrot per C64 compresa nel progetto Resurrection (sotto cartella Mandelbrot)

Il codice e' ben commentato ed il risultato e' in modalita' testo



Il tempo di calcolo su VICE in emulazione del tempo reale del C64 risulta essere di 90 secondi con 26 iterazioni per punto
Il codice e' compilabile con il crosscompiler ACME e necessita della libreria stdlib
----------------------------------------------------------------
;Mandelbrot test code

!source "../stdlib/stdlib.a"
!to "Mandelbrot.prg", cbm
!sal
!sl "Mandelbrot.map"
!svl "Mandelbrot.lbl"
!cpu 6510
!ct pet

!source "../stdlib/BASICEntry80d.a"

!macro OutputFAC {
jsr $bddd ; Convert FAC#1 to ASCII String. Kills FAC#2
jsr $b487 ; Set Up String
jsr $ab21 ; Output String
}

LDFAC = $bba2
STFAC = $bbd4
SUBFAC = $b850
DIVFAC = $bb0f
CMPFAC = $bc5b
MULFAC = $ba28
ADDFAC = $b867
SETFAC = $b391

!macro LoadFAC .addr {
lda #<.addr
ldy #>.addr
jsr LDFAC
}

!macro StoreFAC .addr {
ldx #<.addr
ldy #>.addr
jsr STFAC
}

!macro SubMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr SUBFAC
}
!macro SubFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+SubMemFAC Temp
}

!macro DivMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr DIVFAC
}
!macro DivFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+DivMemFAC Temp
}

!macro CmpFACMem .addr {
+StoreFAC Temp
+LoadFAC .addr
+CmpMemFAC Temp
}
!macro CmpMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr CMPFAC
}

!macro MulMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr MULFAC
}

!macro AddMemFAC .addr {
lda #<.addr
ldy #>.addr
jsr ADDFAC
}

!macro SetFAC_Y {
lda #0
jsr SETFAC
}

kMaxIterations = 26

!zn
*=BASICEntry
cld
jsr CINT


; Speed testing for some FP ops. As we can see even some simple operations are very slow
!if 0 {
sei
.tl1
lda #0
sta VIC2BorderColour
+MACROWaitForRaster 64
inc VIC2BorderColour

+LoadFAC xmin
inc VIC2BorderColour

+SubMemFAC xmax
inc VIC2BorderColour

+DivFACMem ScrW
inc VIC2BorderColour

+StoreFAC xs
inc VIC2BorderColour

+MulMemFAC xs
inc VIC2BorderColour

+StoreFAC xs
inc VIC2BorderColour

jmp .tl1
}

; The main Mandelbrot code.
;xs=(xmax-xmin)/40.0;
+LoadFAC xmin
+SubMemFAC xmax
+DivFACMem ScrW
+StoreFAC xs

;ys=(ymax-ymin)/24.0;
+LoadFAC ymin
+SubMemFAC ymax
+DivFACMem ScrH
+StoreFAC ys

;for (y=0;y<24;y++) {
lda #0
sta y

.l1
;   for (x=0;x<40;x++) {
lda #0
sta x

.l2
;      p=xmin+(x*xs);
ldy x
+SetFAC_Y
+MulMemFAC xs
+AddMemFAC xmin
+StoreFAC p


;      q=ymin+(y*ys);
ldy y
+SetFAC_Y
+MulMemFAC ys
+AddMemFAC ymin
+StoreFAC q


;         xtemp=0;
;         x0=0;
;         y0=0;
ldy #0
+SetFAC_Y
+StoreFAC x0
+StoreFAC y0


;         i=0;
lda #0
sta i

.while
;         while (((x0*x0)+(y0*y0))<4 && ++i<kMaxIterations)  {
; i check, first, simple integer check
lda i
cmp #kMaxIterations
bcc .ltkMaxIterations

jmp .escape
.ltkMaxIterations

; mul check
+LoadFAC x0
+MulMemFAC x0
+StoreFAC Temp2
+LoadFAC y0
+MulMemFAC y0
+AddMemFAC Temp2
+CmpFACMem Escape
bcc .lt4
jmp .escape
.lt4

;++i
inc i

; xtemp = (x0*x0) - (y0*y0) + p
+LoadFAC x0
+MulMemFAC x0
+StoreFAC Temp2
+LoadFAC y0
+MulMemFAC y0
+SubMemFAC Temp2
+AddMemFAC p
+StoreFAC xtemp

;            y0=(2 * x0 * y0) +q;
+LoadFAC x0
+MulMemFAC y0
+StoreFAC Temp2
ldy #2
+SetFAC_Y
+MulMemFAC Temp2
+AddMemFAC q
+StoreFAC y0


;            x0=xtemp;
+LoadFAC xtemp
+StoreFAC x0

;            }
jmp .while

.escape
; Range check to adjust for printable characters
lda i
; lsr ; Potential for shit adjustment, change kMaxIterations to accomodate
cmp #26 ; Letters in the alphabet!
bcc .okChar
lda #' '
jmp .rawOut
.okChar
clc
adc #64
.rawOut
jsr CHROUT

; Finish for loops
inc x
lda x
cmp #40
beq .ol2
jmp .l2
.ol2
inc y
lda y
cmp #24 ; MPi: TOOD: Keep the last line clear for an IRQ scrolling message
beq .ol1
jmp .l1
.ol1

.flash
; inc VIC2BorderColour
jmp .flash

; C64 Floating point values
; MPi: TODO: Must update the assembler to create these
xmin !by $82, $a0, $00, $00, $00 ; -2.5
xmax !by $81, $40, $00, $00, $00 ; 1.5
ymin !by $81, $c0, $00, $00, $00 ; -1.5
ymax !by $81, $40, $00, $00, $00 ; 1.5
ScrW !by $86, $20, $00, $00, $00 ; 40
ScrH !by $85, $40, $00, $00, $00 ; 24
Escape !by $83, $00, $00, $00, $00 ; 4

; Float storage
Temp = *
Temp2 = * + 5
xs = * + 10
ys = * + 15
p = * + 20
q = * + 25
xtemp = * + 30
x0 = * + 35
y0 = * + 40
; Bytes
x = * + 45
y = * + 46
i = * + 47
----------------------------------------------------------------



IEEE 754

Si tratta di un metodo di memorizzazione di numeri float  con varia lunghezza nel numero di bit (in questo caso sara' utilizzata solo la rappresentazione a 32 bit). Un convertitore on line di numeri in formato IEEE754 puo' esssere trovato a questo link

I bit sono cosi' divisi
1 bit di segno
8 bit di esponente : 2 elevato all'esponente
23 bit : mantissa del numero

In questo formato i numeri 12.5 e 3.5 ottengono la seguente rappresentazione binaria

12.5  0 10000010 10010000000000000000000  1.5625   4718592
3.5    0 10000000 11000000000000000000000  1.75     6291456

il primo bit e' in entrambi i casi 0 perche' i due numeri sono positivi

12.5 puo' essere espresso come 2^3 *1.5625. L'esponente e' quindi 3 ma deve essere sommato il valore di 127 per cui l'esponente e' 127 + 3 = 130d =  10000010b. Infine 10010000000000000000000 e' la rappresentazione binaria di 1.5625

Lo stesso si puo' ripetere per il numero 3.5 che puo' essere espresso come 2^1*1.75

Per sommare i due numeri si procede allineando gli esponenti a quello piu' basso (in questo caso 1). 12.5 viene quindi espresso come 6.25*2^1 (spostando l'esponente di due si moltiplica la mantissa per quattro ovvero 2^spostamento). A questo punto si sommando le mantissa e la somma e' uguale a (6.25+1.75)*2^1 = 8*2=16 ovvero il risultato desiderato (12.5+3.5)

per moltiplicare i due numeri (12.5*3.5=43.75) si procede sommando gli esponenti e moltiplicando le mantisse. In questo caso 2^(1+3)*(1.5625*1.75)=2.734375*2^4. La mantissa deve essere normalizzata perche' e' superiore a 2 per cui il risultato sara' 1.3671875*2^5 ovvero 43.75


Perche' tanto confusione .. perche' ai computer piacciono i numeri a base due ed interi

Questa e' un sistema standardizzato ma esistono altri modi per descrivere un numero. In questo fantastico documento del 1976 a firma tale Roy Rankin e Steve Wozniak sulle procedure matematiche per il 6502 con una rappresentazione a 32 bit nel formato

 Exponent    Two's Complement Mantissa
  SEEEEEEE  SM.MMMMMM  MMMMMMMM  MMMMMMMM
     n         n+1       n+2       n+3

Repository per Yocto su Intel Edison

Come fatto notare in un precedente post, il repository di default opkg di Intel Edison non e' cosi' fornito cosi' si e' abituati per esempio con Arduino YUN.




La soluzione deriva dalle AlexT's Edison Page,   un repository non ufficiale che riporta un discreto numero di pacchetti di uso comune gia' in formato binario

Per abilitare questo repository si deve aggiungere al file /etc/opkg/base-feeds.conf le seguenti righe

-------------------------------
src/gz all http://repo.opkg.net/edison/repo/all
src/gz edison http://repo.opkg.net/edison/repo/edison
src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32
-------------------------------
si digita quindi
opkg update

(sul sito viene esplicitamente indicato di non usare opkg upgrade ma di configurare l'upgrade pacchetto per pacchetto pena la saturazione della rootfs)
Si possono quindi installare pacchetti come opencv e motion senza fatica

lunedì 6 giugno 2016

Moltiplicazione veloce per 10 in binario

Questo e' un sistema rapido per effettuare moltiplicazioni per 10 su un calcolatore binario ripresa da questo documento

L'idea e' quella di dividere la moltiplicazione per 10 come (numero*8)+(numero*2) che equivale ovviamento a numero numero*(8+2). Il vantaggio di questo procedimento e' che in con codificato binario le moltiplicazione per 2 (e per i suoi multipli) consistono semplicemente in uno spostamento verso sinistra dei bit.

Un esempio: moltiplichiamo 123x10
la codifica binaria di 123 e' 1111011
lo shift di un posto (moltiplicazione per due) e' 11110110
lo shift di tre posti (moltiplicazione per otto) e' 1111011000
la somma binaria di 11110110 + 1111011000 equivale a 10011001110 che corrisponde al risultato desiderato di 1230

Il vantaggio di questo sistema e' che in Assembler esiste un comodo apposito per lo shift binario a sinistra che e' ASL nel 6502 e SHL in x86

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(); 
}

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...