mercoledì 23 gennaio 2019

Wakeup Arduino Uno con interrupt da MPU6050

L'accelerometro MPU6050 (altrimenti conosciuto come Gy-521) ha un pin interrupt che puo' essere programmato per risvegliare una Arduino Uno
Ho semplificato un po' il codice ritrovato a questo link


si possono personalizzare le soglie di attivazione dell'interrupt modificando il valore di MOT_THR e MOT_DUR


-----------------------------------------------------------------------
#include <avr/sleep.h>  
#include <Wire.h>


#define SIGNAL_PATH_RESET  0x68
#define I2C_SLV0_ADDR      0x37
#define ACCEL_CONFIG       0x1C 
#define MOT_THR            0x1F  // Motion detection threshold bits [7:0]
#define MOT_DUR            0x20  // Duration counter threshold for motion interrupt generation, 1 kHz rate, LSB = 1 ms
#define MOT_DETECT_CTRL    0x69
#define INT_ENABLE         0x38
#define WHO_AM_I_MPU6050   0x75 // Should return 0x68
#define INT_STATUS 0x3A
//when nothing connected to AD0 than address is 0x68
#define ADO 0
#if ADO
#define MPU6050_ADDRESS 0x69  // Device address when ADO = 1
#else
#define MPU6050_ADDRESS 0x68  // Device address when ADO = 0
#endif

int wakePin = 2;                 // pin used for waking up  


void wakeUpNow() 
{       
}  


void writeByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
  Wire.begin();
  Wire.beginTransmission(address);  // Initialize the Tx buffer
  Wire.write(subAddress);           // Put slave register address in Tx buffer
  Wire.write(data);                 // Put data in Tx buffer
  Wire.endTransmission();           // Send the Tx buffer
}

uint8_t readByte(uint8_t address, uint8_t subAddress)
{
  uint8_t data;                            // `data` will store the register data   
  Wire.beginTransmission(address);         // Initialize the Tx buffer
  Wire.write(subAddress);                  // Put slave register address in Tx buffer
  Wire.endTransmission(false);             // Send the Tx buffer, but send a restart to keep connection alive
  Wire.requestFrom(address, (uint8_t) 1);  // Read one byte from slave register address 
  data = Wire.read();                      // Fill Rx buffer with result
  return data;                             // Return data read from slave register
}


void setup() 
{  
    Serial.begin(9600);
    writeByte( MPU6050_ADDRESS, 0x6B, 0x00);
    writeByte( MPU6050_ADDRESS, SIGNAL_PATH_RESET, 0x07);//Reset all internal signal paths in the MPU-6050 by writing 0x07 to register 0x68;
    writeByte( MPU6050_ADDRESS, I2C_SLV0_ADDR, 0x20);//write register 0x37 to select how to use the interrupt pin. For an active high, push-pull signal that stays until register (decimal) 58 is read, write 0x20.
    writeByte( MPU6050_ADDRESS, ACCEL_CONFIG, 0x01);//Write register 28 (==0x1C) to set the Digital High Pass Filter, bits 3:0. For example set it to 0x01 for 5Hz. (These 3 bits are grey in the data sheet, but they are used! Leaving them 0 means the filter always outputs 0.)
    writeByte( MPU6050_ADDRESS, MOT_THR, 20);  //Write the desired Motion threshold to register 0x1F (For example, write decimal 20).  
    writeByte( MPU6050_ADDRESS, MOT_DUR, 40 );  //Set motion detect duration to 1  ms; LSB is 1 ms @ 1 kHz rate  
    writeByte( MPU6050_ADDRESS, MOT_DETECT_CTRL, 0x15); //to register 0x69, write the motion detection decrement and a few other settings (for example write 0x15 to set both free-fall and motion decrements to 1 and accelerometer start-up delay to 5ms total by adding 1ms. )   
    writeByte( MPU6050_ADDRESS, INT_ENABLE, 0x40 ); //write register 0x38, bit 6 (0x40), to enable motion detection interrupt.     
    writeByte( MPU6050_ADDRESS, 0x37, 160 ); // now INT pin is active low

    pinMode(2, INPUT);        // sets the digital pin 7 as input
    pinMode(wakePin, INPUT_PULLUP);  // wakePin is pin no. 2
}  

void sleepNow() 
{  
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    
    sleep_enable();                        
    delay(500);  
    attachInterrupt(0,wakeUpNow, LOW); 
    delay(500);
    sleep_mode();     

     //ritorno da interrupt
     delay(500);

     sleep_disable();         
     delay(500);  
     detachInterrupt(0);   
                                
}  

uint16_t readdata;
void loop() 
{     
      sleepNow();     
      /*readdata = readByte(MPU6050_ADDRESS,0x3A);
      Serial.print(readdata);Serial.print("-");
      readdata = readByte(MPU6050_ADDRESS,0x37);
      Serial.println(readdata);*/
      Serial.println("Movimento registrato");     

}  

Livello Automatico Stanley AL24

Questo livello viene venduto in kit con il treppiede e la stadia da 5 m. E' uno strumento economico e di prestazioni adeguate al prezzo....l'unica cosa veramente strana e' che la stadia non presenta la bolla circolare

La distanza massima tra due punti e' di circa 50-60 m (considerando la posizione del cannochiale al centro tra i due punti)



Per misurare le distanze si usano i due riferimenti al di sopra ed al di sotto del crocefilo. Per esempio nell'immagine sotto riportate le misure sono circa 1,395 e 1,265. La distanza della stadia (dato il rapporto 1:100) puo' essere calcolata come 1,395-1,265=0,13*100 = 13 m

La stadia non e' verticale ma ero da solo ;>

Persistenza delle variabili in Alexa Skills

La persistenza delle variabili in Alexa Skills con NodeJS si ottiene tramite PersistantAttributes che si appoggia su DynamoDB in modo trasparente



In questa prima fase viene settata una variabile (per semplicita' statica) in modo persistente. Se non e' settata crea una nuova stringa. Importante impostare la chiamata come asincrona

Da notare che le variabili sono relative ad un determinato account per cui ogni utente ritrovera' le proprie impostazioni

---------------------------------------------------------------------------
const LaunchRequestHandler = {
  canHandle(handlerInput) {
     return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    
  },
  
  async handle(handlerInput) {    
    const attributesManager = handlerInput.attributesManager;
    var speechText = "Benvenuto nella skill ";

    const attributes = await attributesManager.getPersistentAttributes() || {};

    if (Object.keys(attributes).length === 0) {
      attributes.nameValue = "Luca";
      attributesManager.setPersistentAttributes(attributes);
      await attributesManager.savePersistentAttributes();
    }else {
      speechText = "Benvenuto  ${attributes.nameValue.toString()}";
    }
    
    return handlerInput.responseBuilder
      .speak(speechText)
      .withShouldEndSession(false)
      .getResponse();
  },
};
---------------------------------------------------------------------------


Con questo codice si puo' richiamare il valore della variabile da altra intent

---------------------------------------------------------------------------
 const attributesManager = handlerInput.attributesManager;
  const attributes = await attributesManager.getPersistentAttributes()
  var speechOutput =  attributes.nameValue.toString();
---------------------------------------------------------------------------

Per salvare i dati e' necessario impostare il nome della tabella in cui sono salvate le variabili e la possibilita' di creare in automatico la tabella ove non esista
---------------------------------------------------------------------------
const skillBuilder = Alexa.SkillBuilders.standard();

exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequestHandler,
    YesHandler,
    geo,
    HelpHandler,
    ExitHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)
  .withTableName('alexa-data')
  .withAutoCreateTable(true)
  .lambda();
---------------------------------------------------------------------------


martedì 22 gennaio 2019

Emulatore in Pascal per Commodore 64

Mi sono imbattuto per caso in questo progetto ospitato su GitHub (che rimanda pero' ad un progetto del 2008) in cui viene programmato un semplice emulatore per Commodore 64 e lo ho trovato molto istruttivo perche' il codice (forse perche' in Pascal) e' molto semplice da seguire ed offre uno spaccato della programmazione di una macchina di emulazione


Emulatore in esecuzione in shell su Linux


Si parte semplicemente creando un array di 64K byte che rappresentano la memoria di un C64 (si vedra' in seguito che parte di questi 64Kb saranno occupati da ROM)

Ognuna delle celle dell'array rappresenta una locazione di memoria che puo' essere letta o scritta con un semplice accesso all'array mediante puntatore

Si definiscono quindi le variabili byte A (accumulatore),X,Y,S (stack pointer varia da 0x01FF a 0x0100) ,P (processor status usato per contenere delle flags) ed IR (instruction register, contenuto di memoria che si utilizza) che rappresentano i registri della cpu 6510 con il registro PC (Program counter) che e' di lunghezza word 16 bit (dato che deve contenere un numero 0.65535 )

Il ciclo base dell'emulatore semplicemente legge il contenuto della memoria puntato da PC, interpreta l'istruzione macchine ed modifica il Program Counter per andare alla successiva istruzione

=================================
while true do
begin
    IR := peek(PC);
    inc(PC);
    case IR of
        $00 : interpret instruction $00
        $01 : interpret instruction $01
    else : unknown instruction encountered
end;
end.

=================================

Si devono quindi implementare tutti i codici macchina e come questi modificano lo stato dei registri e le locazioni di memoria ed il flusso di programma

Il 6510 ha circa una ottantina di Opcode da implementare per realizzare un emulatore

Il 6510 usa come base un sistema little endian per cui il byte meno significativo di una word e' registrato nella prima locazione di memoria (o locazione di memoria piu' bassa)

Impostata l'emulazione del processore il passo successivo e' quello di inizializzare le ROM del C64 che, al minimo, devono contenere il Kernal ma puo' essere utile anche avere il Basic. Si prendono i due file del Kernal e del Basic, si legge il contenuto e lo si copia rispettivamente alle locazioni di memoria $A000...$BFFF e $E000...$FFFF. (un altro settore di memoria destinato alla ROM e' compreso tra $D000 e $DFFF....tutto il resto della memoria..anche se frammentato e' considerata RAM)

Il boot della macchina inizia leggendo il valore della locazione $FFFC-$FFFD ed impostando il program counter (una word) a questa locazione (in pratica viene lanciato un Cold Reset della macchina. Di default il valore letto e' $FCE2 (ovvero il mitico SYS 64738)

Il codice ROM si aspetta di dover ricevere informazioni dal VIC e dalla tastiera ma dato che questi non sono ancora emulati al capitolo 3 dell'emulatore viene inviato un segnale 

Nel capitolo 4 viene introdotta la lettura da tastiera e l'output in modalita' testo
Per la tastiera, ogni volta che viene premuto un tasto (if keypressed) viene letta la lunghezza del buffer di tastiera alla locazione $C6 (il buffer di tastiera puo' contenere al massimo 10 caratteri), se il numero e' inferiore a 10 inserisce il nuovo carattere nel buffer che si trova tra $0277 e $0280 ed incrementa la locazione $C6

Per l'output a video viene letta la memoria video testuale che e' compresa tra $400 e $7E7 (1Kb). Nell'emulatore la schermata viene ricreata ogni volta che c'e' un accesso in lettura nell'area di memoria $400-$7E7

Per la posizione del cursore vengono lette le locazioni di memoria $00D3 e $00D6

Dal capitolo 5 viene gestita la creazione degli interrupt. In pratica un interrupt e' un evento che interrompe momentaneamente il ciclo di base del processore While True Do. Gli interrupt possono essere mascherabili e non mascherabili: di fatto viene messo nello stack il valore del program counter  ed il contenuto del registro delle flags (in modo da recuperarlo quando si esce dall'interrupt) e poi si passa il controllo dell'esecuzione al codice dell'interrupt puntato dalle locazioni di memoria $FFFE-$FFFF (essendo un indirizzo di memoria e' una word) se e' mascherabile oppure $FFFA-$FFFB se non e' mascherabile

GLi interrupt sono generati da un dispositivo hardware ma esiste la possibilita' di avere interrupt software via  BRK

Su C64 viene generato un IRQ con un clock di 50 Hz

Il codice Pascal si compila tranquillamente, almeno fino al capitolo 5, su Linux usando  FreePascal


lunedì 21 gennaio 2019

Casio fx-7500G



Ascentia 700n 4/33 LS43

Purtroppo in pessime condizioni....486 dx33 ... comprato per far girare un programma solo DOS



Texas Instruments TI-57 II

La mia prima calcolatrice scientifica...ancora dopo 30 anni ha le batterie funzionanti


LCD-286

Questo computer e' piuttosto particolare perche' non presenta nessun etichetta che indichi la ditta di fabbricazione oppure codice identificativo ad esclusione di LCD-286


Chiuso si presenta come un parallelepipedo con la tastiera che copre l'LCD



Si tratta sostanzialmente di un desktop 286 con tastiera a presa DIN con un display LCD inclinabile (esiste un pulsante Tilt che sgancia il display e permette di inclinarlo)


Si possono montare dei floppy disk drive da 3 1/2  e 5 1/4 standard



Queste invece sono le schede ISA nascoste dietro uno sportellino



Su internet ho trovato altre macchine simili senza marca... forse si tratta OEM





venerdì 18 gennaio 2019

Sviluppare Alexa Skills: Echo od emulatore??

Questa e' una cosa che ho imparato a spese mie: gli emulatori di Alexa, anche quello ufficiale di Amazon, non hanno lo stesso comportamento e funzionalita' dei dispositivi Echo



Per esempio gli emulatori hanno problemi sono le skills di flash briefing od con il reprompt
Quando si sviluppa e' quindi sempre meglio utilizzare un dispositivo Echo reale in modo da non perdere la testa pensando di aver fatto un errore nel codice di una skill quando invece il problema e' il dispositivo

Alexa Skills: Reprompt e YesNoIntent

Per avere una maggiore interazione utente Alexa puo' terminare la propria frase con una domanda e rimanere in attesa di una risposta da parte dell'utente

Questa fase e' gestita tramite la direttiva reprompt e si possono usare le BuildIntents Yes e No quando e' sufficiente che l'utente interagisca in modo affermativo o negativo

Per esempio partendo da un custom intent si puo' aggiungere il reprompt
===========================================

const geo = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return (request.type === 'IntentRequest'
        && request.intent.name === 'geo');
  },
  
  
  async handle(handlerInput) {
  const response = await httpGet();
  //console.log("Risposta "+response);

  const { intent } = handlerInput.requestEnvelope.request;
  const activity = intent.slots.luogo.value;
  var speechOutput = response;
  
  
  if (activity == "firenze")
      {
        speechOutput = "_______________";
        //console.log("Speechout firenze"+ speechOutput+data);
      }
  
  if (activity == "milano")
      {
        speechOutput = "_______________";
      }
  
    console.log(activity);

    return handlerInput.responseBuilder
      .speak(speechOutput)
      .reprompt("Vuoi la spiegazione del messaggio?")
      .getResponse();
      
  },
};

===========================================

Si aggiunge quindi il buildinten Yes
-------------------------------------------------
                {
                    "name": "AMAZON.YesIntent",
                    "samples": []
                }
-------------------------------------------------

a questo punto per gestire la eventuale risposta positiva si aggiunge alla lambda

--------------------------------------------------
const YesHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.YesIntent'
  },
  handle(handlerInput) {

    return handlerInput.responseBuilder
      .speak("Speigazione")
      .getResponse();
  },
};
--------------------------------------------------

si deve infine aggiungere lo YesHandler 

---------------------------------------------------
const skillBuilder = Alexa.SkillBuilders.standard();

exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequestHandler,
    YesHandler,
    geo,
    HelpHandler,
    ExitHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)


  .lambda();
  


martedì 15 gennaio 2019

Installare Debian testing su Lenovo X1 Carbon

Mi sono trovato a dover installare Debian su un Ultrabook Lenovo X1 Carbon e dover seguire una procedura mai provata.

Di solito installo i driver della scheda WiFi al secondo riavvio, anche perche' i driver sono spesso proprietari, usando la Ethernet per scaricare la distribuzione (Debian testing e' scaricabile solo come netinst)

X1 Carbon non ha una Ethernet integrata ed il dongle USB della Lenovo monta un Realtek 8153 il cui driver non e' compreso nel Cd di installazione



Come fare allora. Arrivato a questa schermata ho trovato il firmware della scheda di rete Wireless del Carbon (iwlwifi-7260-17.ucode), ho scaricato il file .dpgk su un altro computer, lo ho scompattato con ar e salvato il file .ucode (nel pacchetto ve ne sono molti altri) su una chiavetta USB


A questo punto ho rimosso il supporto USB con la iso Debian e messo quello con il driver. L'installer ha preso al volo il cambio di chiavetta e montato il driver attivando il WiFi. E' pero' necessario continuare l'installazione con il supporto di installazione e qui le cose si fanno un po' piu/ complicate.,...reinserendo la chiavetta di installazione questa non viene montata in automatico. Si deve entrare in shell (CTRL+ALT+F4) e montare a mano la chiavetta su /cdrom.
A questo punto si ritorna sulla finestra dell'installer (CTRL+ALT+F7) per terminare la configurazione

SSR Relay a stato solido per Arduino

Per un progetto in cui mi serve un relay ho voluto provare a sostituire un rele' meccanico con uno a stato solido (in particolare un modulo da due SSR della Keyestudio)

Lo ho connesso come d'uso per i relay ad una Arduino Uno e non avevo interruzione di corrente al dispositivo



Dopo un po' di pensatoio ho provato ad isolare il problema.
A componente singolo attaccato ad Arduino l'SSR presenta due stati: uno a resistenza infinita (ops....molto molto alta sopra la scala del multimetro) ed uno stato di circa 6 KOhm...in pratica c'e' uno stato disconnesso ed uno con una resistenza non trascurabile....non c'e' praticamente circuitazione tra i due connettori quando il rele' e' chiuso

Se attacco un carico sui terminali la cosa diventa ancora piu' strana....in pratica il rele' non interrompe mai la connessione tra gli elettrodi... alla fine sono capitato su questo documento in cui viene spiegato il motivo per cui un rele' non fa il suo lavoro

Torno ai rele' meccanici....

lunedì 14 gennaio 2019

Arduino Sleep Mode e risveglio con Interrupt da DS3231

Arduino ha diverse modalita' di funzionamento, oltre a quella standard, per ridurre al minimo il consumo di una eventuale batteria. La modalita' sleep mode interna al processore prevede un watchdog che puo' essere settato al massimo ad 8 secondi; per ottenere dei tempi di sleep mode piu' lunghi di deve fornire al microprocessore un segnale dall'esterno che viene gestito come interrupt


Per fornire tale segnale esterno uno dei metodi piu' comodi e' quello di usare un RTC che preveda il canale SQW come il DS3231 (che peraltro risulta essere molto piu' preciso del DS1307)

Il DS3231 funzione su I2C per cui le connessioni sono VCC=3.3 V (attenzione), GND, SDA su A4 Arduino e SCL su A5 Arduino. In piu' si deve collegare SQW sul Pin dell'Arduino per avere segnale di risveglio


Sul DS3231 ci sono due allarmi ma ne sara' usato uno che dopo ogni utilizzo sara' spostato di 60 minuti nel futuro e subito dopo la scheda sara' messa in sleep mode in attesa di essere risvegliata

Il codice del loop riparte dall'ultima istruzione eseguita prima di essere andata in sleep

-------------------------------------------------------------------------------------------------
#include <Wire.h>
#include <RTClibExtended.h>
#include <LowPower.h>

#define wakePin 2    
RTC_DS3231 rtc;     
//-------------------------------------------------
void wakeUp()        // here the interrupt is handled after wakeup
{
}
//------------------------------------------------------------

void setup() {
  Serial.begin(9600);
  delay(3000);
  //imposta il PIN D2 per il wqakeup
  pinMode(wakePin, INPUT);;

  Wire.begin();
  rtc.begin();
  rtc.adjust(DateTime(__DATE__, __TIME__));   //imposta l'orologio in fase di compilazione col computer
  
  //elimina allarmi eventualmente presenti
  rtc.armAlarm(1, false);
  rtc.clearAlarm(1);
  rtc.alarmInterrupt(1, false);
  rtc.armAlarm(2, false);
  rtc.clearAlarm(2);
  rtc.alarmInterrupt(2, false);

  rtc.writeSqwPinMode(DS3231_OFF);
  delay(1000);
  Serial.println("Inizio");

}

//------------------------------------------------------------

void loop() {

    DateTime now = rtc.now();
    Serial.print(now.hour(),DEC);
    Serial.print(":");
    Serial.print(now.minute(),DEC);
    Serial.print(":");
    Serial.print(now.second(),DEC);
    Serial.println();
    
   //calcola la prossima ora di risveglio ovvero dopo un'ora
    DateTime nextAlarm = now + TimeSpan(0, 1, 0, 0);
  // l'ordine del timespan e' giorni,ore,minuti,secondi
    
    rtc.setAlarm(ALM1_MATCH_HOURS, nextAlarm.minute(), nextAlarm.hour(), nextAlarm.second());   //imposta l'allarme 
    rtc.alarmInterrupt(1, true);
    delay(3000); // wait for console
    attachInterrupt(0, wakeUp, LOW);          
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);   //entra in sleep su questa istruzione
    detachInterrupt(0);                                    //execution resumes from here after wake-up
    //cancella la precedente impostazione dell'allarme 1
    rtc.armAlarm(1, false);
    rtc.clearAlarm(1);
    rtc.alarmInterrupt(1, false);
    delay(3000);
}


Addipresto Lanza

Era da tempo che volevo aggiungere alla mia collezione di regoli calcoatori una calcolatrice analogica per addizioni ma i prezzi su Ebay non sono trascurabili. Ieri ad un mercatino per 10 euro ho preso questa Addipresto Lanza completa del suo stilo originale perfettamente funzionante (a dire il vero sono strumenti cosi' semplici che e' difficile si rompano)




E' databile indicativamente seconda meta' degli anni 60 ed ha 7 rotori decimali. Non ha indicatore di overflow ma semplicemente il conteggio riparte da zero


Per effettuare una somma, per esempio 65+47 (come nel video sottostante). si procede puntando lo stilo sul numero delle unita' e ruotando verso il basso procedendo poi con il rotore delle decine. Inserito il primo addendo si ripete la procedura per il secondo per avere infine il risultato sul display in alto ovvero 112. Il reset e' effettuato con la levetta rossa



Le sottrazioni possono essere effettuate con i numeri in rosso come complemento a 9

Alcune informazioni sul meccanismo interno si possono ricavare a questo link

mercoledì 9 gennaio 2019

Cordova File Plugin per salvare file

questo esempio e' stato ripreso da questo esempio

si parte da zero

cordova create MyApp
cordova platform add android
cordova plugin add cordova-plugin-file

a questo punto e' stato creato il progetto base. Si apre Android Studio e si risolvono i vari errori di Gradle e poi si fa una prima build. In seguito si modificano i file come segue

Nella pagina html l'unico aspetto importante e' che siano importati cordova.js e /js/index.js

/assets/www/index.html
////////////////////////////////////////////////////////////
<html>
    <head>

        <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
        <meta name="format-detection" content="telephone=no">
        <meta name="msapplication-tap-highlight" content="no">
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
        <link rel="stylesheet" type="text/css" href="css/index.css">
        <title>Hello World</title>
    </head>
    <body onload="onLoad()">
        <div class="app">
            <h1>Apache Cordova</h1>
            <div id="deviceready" class="blink">
                <p class="event listening">Connecting to Device</p>
                <p class="event received">Device is Ready</p>
            </div>
        </div>
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="js/index.js"></script>

    </body>
</html>
////////////////////////////////////////////////////////////

sull'evento deviceready si aggiunge quindi il codice evidenziato

/assets/www/js/index.js
///////////////////////////////////////////////////////////

var app = {
    // Application Constructor
    initialize: function() {
        document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
    },

    // deviceready Event Handler
    //
    // Bind any cordova events here. Common events are:
    // 'pause', 'resume', etc.
    onDeviceReady: function() {
        this.receivedEvent('deviceready');
    },

    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');

        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');

        console.log('Received Event: ' + id);
        var fileName = 'myfile.txt';    // your file name
        var data = '...';               // your data, could be useful JSON.stringify to convert an object to JSON string
        window.resolveLocalFileSystemURL( cordova.file.externalRootDirectory, function( directoryEntry ) {
            directoryEntry.getFile(fileName, { create: true }, function( fileEntry ) {
                fileEntry.createWriter( function( fileWriter ) {
                    fileWriter.onwriteend = function( result ) {
                        console.log( 'pippoplutopaperino' );
                    };
                    fileWriter.onerror = function( error ) {
                        console.log( error );
                    };
                    fileWriter.write( data );
                }, function( error ) { console.log( error ); } );
            }, function( error ) { console.log( error ); } );
        }, function( error ) { console.log( error ); } );
    }
};

app.initialize();

///////////////////////////////////////////////////////////

/res/config.xml
anche in questo file si modifica aggiungendo la parte evidenziata
///////////////////////////////////////////////////////////
<?xml version='1.0' encoding='utf-8'?>
<widget id="io.cordova.hellocordova" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <feature name="Whitelist">
        <param name="android-package" value="org.apache.cordova.whitelist.WhitelistPlugin" />
        <param name="onload" value="true" />
    </feature>
    <name>HelloCordova</name>
    <description>
        A sample Apache Cordova application that responds to the deviceready event.
    </description>
    <author email="dev@cordova.apache.org" href="http://cordova.io">
        Apache Cordova Team
    </author>
    <content src="index.html" />
    <access origin="*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="tel:*" />
    <allow-intent href="sms:*" />
    <allow-intent href="mailto:*" />
    <allow-intent href="geo:*" />
    <allow-intent href="market:*" />
    <preference name="loglevel" value="DEBUG" />
    <feature name="File">
        <param name="android-package" value="org.apache.cordova.file.FileUtils" />
        <param name="onload" value="true" />
    </feature>
    <allow-navigation href="cdvfile:*" />
    <preference name="AndroidPersistentFileLocation" value="Compatibility" />
    <preference name="AndroidExtraFilesystems" value="files,cache, sdcard, cache-external, files-external" />
</widget>
///////////////////////////////////////////////////////////

se tutto e' andata a buon fine si trovera' il file myfile.txt nella cartella Documenti

martedì 8 gennaio 2019

Mandelbrot su Olivetti M10

Per la rubrica Retrocomputing Estremo insieme di Mandelbrot su Olivetti, splendido portatile del 1983 marcato Olivetti ma non prodotto da Olivetti, con un processore 8085 (dove il 5 sta per 5 Volt, non c'e' bisogno della doppia alimentazione 5-12V) a 2.4 MHz

25 minuti di calcolo per una griglia 64x44 con soglia di 20 cicli utilizzando Virtual T, un emulatore per Olivetti M10 e TRS-80
Il codice BASIC e' stato adattato partendo dalla base di Rosetta Code






Perche' ho usato un emulatore....non ho nella mia collezione un Olivetti M10??
Errato serial 40301385 24K perfettamente funzionate




lunedì 7 gennaio 2019

Interagire con DynamoDB con Lambda e API Gateway

Un sistema per interagire con DynamoDB mediante una funzione Lambda triggerata da API Gateway




Prima prima cosa ho creato a mano una tabella in DynamoDB con due colonne nome (stringa) ed indice (numerico)

La funzione Lambda per interagire con DynamoDB necessita di permessi. Per rendere le cose piu' semplici ho usato i permessi piu' estesi che corrispondono al ruolo AmazonDyamoDBFullAccess (per creare il ruolo si va in consolle di AWS, si apre IAM, Ruolo, Crea Ruolo, si selezione il servizio Lambda e si spunta AmazonDyamoDBFullAccess) Dopo aver salvato il ruolo con un nome si modifica il Ruolo di Esecuzione nella finestra della funzione Lambda impostando il nuovo ruolo

La funzione Lambda di seguito mostra un insertItem ed un getItem condizionato al valore dell'indice numerico

================================================
var AWS = require('aws-sdk');
var DOC = require('dynamodb-doc');
var dynamo = new DOC.DynamoDB();

exports.handler = function(event, context) {
  
  var tableName = "bollettini";
var item = {
    nome: "Federico",
    indice: Number(4)
}
var params = {
    TableName: tableName,
    Item: item
};


    dynamo.putItem(params, function (err, data) {
        if (err) console.log(err, err.stack); // an error occurred
        else console.log(data);               // successful response
    });
  
  var cb = function(err, data) {
    if(err) {
      console.log('error getItem: ',err);
      context.done('Unable to getItem', null);
    } else {
      if(data.Item && data.Item.nome) {
        context.done(null, data.Item);
      } else {
        context.done(null, {});
      }
    }
  };
  dynamo.getItem({TableName:"bollettini", Key:{indice:2}}, cb);

};
================================================

A questo punto per eseguire la Lambda e' necessario impostare un trigger che nel mio caso e' API Gateway. Dalla consolle di AWS si sceglie API Gateway, si selezione Create API, si indica il nome, Nella pagina successiva si clicca sul menu' a tendina Actions e si sceglie GET. Si apre una pagina sulla destra in si inserisce  l'ARN della Lambda e si salva. A questo punto si pubblica la API e si avra' come risposta un link del tipo https:/xxxxxxxx.execute-api.eu-west-1.amazonaws.com/test/

Puntano il browser al link indicato si mettera' in esecuzione la funzione Lambda

venerdì 4 gennaio 2019

Intel Edison: Batteria RTC o UPS

Ho ripreso la Intel Edison dal cassetto per un progetto che prevede di salvare dati da un GPS.
La Edison non sara' connessa ad una rete WiFi e quindi non e' possibile ricavare data/ora via NTP


Intel Edison dichiara nelle specifiche di montare un RTC (anche se non c'e' l'alloggiamento della batteria) rispettivamente sul pin 23 del modulo Edison od al pin 5 del J18 del mini breakout
Io in realta' uso il breakout Arduino e si trova solo il connettore J2 con indicazione BATT. Attandoci una LiPO che questa non funziona solo come batteria tampone per RTC ma funziona come un UPS per tutta la scheda (e quindi secondariamente mantiene vivo anche RTC)

In conclusione con il breakout Arduino non ha una connessione diretta con l'RTC, la batteria esterna alimenta tutta la scheda

giovedì 3 gennaio 2019

Salvare dati da seriale in blocchi orari

Una soluzione semplice per un problema: lo scopo e' registrati i dati derivanti in continuo da un GPS via seriale su file di dimensioni in base ad un'ora di acquisizione



Per fare cio' viene in aiuto il comando bash timeout che permette di interrompere dopo un certo numero di secondi un comando di lunga (od infinita esecuzione). Dopo essere passata un'ora viene di nuovo riavviato il comando per creare il nuovo file orario

-----------------------------------------------------------------
#!/bin/sh
while true
do
        timeout -s 15 3600 /home/root/gps_data.sh
done
-----------------------------------------------------------------

con il seguente semplice comando si invia tutto il flusso dati dalla seriale su USB verso un file

gps_data.sh
-----------------------------------------------------------------
(stty raw; cat> /media/sdcard/`date +%y%m%d%H%M`.txt) < /dev/ttyACM0
-----------------------------------------------------------------

in generale ho visto che il GPS produce circa 150Kb al secondo

LLama3 Anita

A seguito di questo post ho provato a vedere ho provato a vedere cosa accadeva ad utilizzare un modello specifico per la lingua italiana in...