martedì 14 gennaio 2014

Compressione SMS in Android (2)

Riprendendo dalla puntata precedente, in questo caso la compressione non e' orientata ai caratteri ma si basa sull'ottimizzare il numero di bit per comprimere il dato. Come gia' detto l'obbiettivo e' trasferire informazioni geografiche quindi coordinate lat/long che possono essere descritte come numeri in virgola mobile (non e' previsto avere segni di separazione perche' sara' solo la posizione a determinare la distinzione tra un dato ed il successivo)

Una coordinata in gradi decimali (se non ho sbagliato) necessita' di almeno 5 decimali per avere una precisione al secondo di arco in grado sessagesimali.
La logica e' piu' o meno questa:
1) si prende il numero in virgola mobile e lo si converte nella sua rappresentazione binaria (come stringa)
2) si divide la stringa in pezzi da 7 bit (per il formato SMS)
3) si prendono solo i primi 5 gruppi di 7 bit (il resto dell'informazione e' ridondante)
4) i 7 bit vengono convertiti in un intero (0-127) e quindi nel corrispondente caratttere della tabella SMS
5) il percorso inverso per la riconversione in float

il vantaggio non e' drammatico. Si descrive un numero che puo' essere scritto con 8 caratteri in 5 gruppi da 7 bit (quindi il messaggio occupa circa 0.62 dell'originale, ovvero 1.6 dipende da punto si vede)
Questi sono i passaggi

-------------------------------------------------------------------
Messaggio originale :43.26432
100000001000101101000011101010100111100110111011101011011100000
Messaggio compresso : ¡"h:S
100000001000101101000011101010100110000000000000000000000000000
Messaggio decompresso : 43.26431846618652
-------------------------------------------------------------------
ed ecco il codice

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

package sms_compr;

import java.math.BigInteger;

/**
 *
 * @author l.innocenti
 */
public class Sms_compr {
    private static int valore;
    private static String reverse = "";
    private static String passaggio = "";
    
    

     static private int converti_sms(char carattere)
    {
       int codice=0;
       switch (carattere)
            {
             case '@': codice=0;break;
             case '£': codice=1;break;
             case '$': codice=2;break;
             case '¥': codice=3;break;
             case 'è': codice=4;break;
             case 'é': codice=5;break;
             case 'ù': codice=6;break;
             case 'ì': codice=7;break;
             case 'ò': codice=8;break;
             case 'Ç': codice=9;break;
             case '\n': codice=10;break;
             case 'Ø': codice=11;break;
             case 'ø': codice=12;break;
             case '\r': codice=13;break;
             case 'Å': codice=14;break;
             case 'å': codice=15;break;
             case 'Δ': codice=16;break;
             case '_': codice=17;break;
             case 'Φ': codice=18;break;
             case 'Γ': codice=19;break;
             case 'Λ': codice=20;break;
             case 'Ω': codice=21;break;
             case 'Π': codice=22;break;
             case 'Ψ': codice=23;break;
             case 'Σ': codice=24;break;
             case 'Θ': codice=25;break;
             case 'Ξ': codice=26;break;
             //case '': codice=27;break;
             case 'Æ': codice=28;break;
             case 'æ': codice=29;break;
             case 'ß': codice=30;break;
             case 'É': codice=31;break;
             case ' ': codice=32;break;
             case '!': codice=33;break;
             case '"': codice=34;break;
             case '#': codice=35;break;
             case '¤': codice=36;break;
             case '%': codice=37;break;
             case '&': codice=38;break;
             case '\'': codice=39;break;
             case '(': codice=40;break;
             case ')': codice=41;break;
             case '*': codice=42;break;
             case '+': codice=43;break;
             case ',': codice=44;break;
             case '-': codice=45;break;
             case '.': codice=46;break;
             case '/': codice=47;break;
             case '0': codice=48;break;
             case '1': codice=49;break;
             case '2': codice=50;break;
             case '3': codice=51;break;
             case '4': codice=52;break;
             case '5': codice=53;break;
             case '6': codice=54;break;
             case '7': codice=55;break;
             case '8': codice=56;break;
             case '9': codice=57;break;
             case ':': codice=58;break;
             case ';': codice=59;break;
             case '<': codice=60;break;
             case '=': codice=61;break;
             case '>': codice=62;break;
             case '?': codice=63;break;
             case '¡': codice=64;break;
             case 'A': codice=65;break;
             case 'B': codice=66;break;
             case 'C': codice=67;break;
             case 'D': codice=68;break;
             case 'E': codice=69;break;
             case 'F': codice=70;break;
             case 'G': codice=71;break;
             case 'H': codice=72;break;
             case 'I': codice=73;break;
             case 'J': codice=74;break;
             case 'K': codice=75;break;
             case 'L': codice=76;break;
             case 'M': codice=77;break;
             case 'N': codice=78;break;
             case 'O': codice=79;break;
             case 'P': codice=80;break;
             case 'Q': codice=81;break;
             case 'R': codice=82;break;
             case 'S': codice=83;break;
             case 'T': codice=84;break;
             case 'U': codice=85;break;
             case 'V': codice=86;break;
             case 'W': codice=87;break;
             case 'X': codice=88;break;
             case 'Y': codice=89;break;
             case 'Z': codice=90;break;
             case 'Ä': codice=91;break;
             case 'Ö': codice=92;break;
             case 'Ñ': codice=93;break;
             case 'Ü': codice=94;break;
             case '§': codice=95;break;
             case '¿': codice=96;break;
             case 'a': codice=97;break;
             case 'b': codice=98;break;
             case 'c': codice=99;break;
             case 'd': codice=100;break;
             case 'e': codice=101;break;
             case 'f': codice=102;break;
             case 'g': codice=103;break;
             case 'h': codice=104;break;
             case 'i': codice=105;break;
             case 'j': codice=106;break;
             case 'k': codice=107;break;
             case 'l': codice=108;break;
             case 'm': codice=109;break;
             case 'n': codice=110;break;
             case 'o': codice=111;break;
             case 'p': codice=112;break;
             case 'q': codice=113;break;
             case 'r': codice=114;break;
             case 's': codice=115;break;
             case 't': codice=116;break;
             case 'u': codice=117;break;
             case 'v': codice=118;break;
             case 'w': codice=119;break;
             case 'x': codice=120;break;
             case 'y': codice=121;break;
             case 'z': codice=122;break;
             case 'ä': codice=123;break;
             case 'ö': codice=124;break;
             case 'ñ': codice=125;break;
             case 'ü': codice=126;break;
             case 'à': codice=127;break;
       }
       return codice;
    }

    public static void main(String[] args) {
         char[] sms = new char[128];
        

        sms[0] = '@';
        sms[1] = '£';
        sms[2] = '$';
        sms[3] = '¥';
        sms[4] = 'è';
        sms[5] = 'é';
        sms[6] = 'ù';
        sms[7] = 'ì';
        sms[8] = 'ò';
        sms[9] = 'Ç';
        sms[10] = '\n';
        sms[11] = 'Ø';
        sms[12] = 'ø';
        sms[13] = '\r';
        sms[14] = 'Å';
        sms[15] = 'å';
        sms[16] = 'Δ';
        sms[17] = '_';
        sms[18] = 'Φ';
        sms[19] = 'Γ';
        sms[20] = 'Λ';
        sms[21] = 'Ω';
        sms[22] = 'Π';
        sms[23] = 'Ψ';
        sms[24] = 'Σ';
        sms[25] = 'Θ';
        sms[26] = 'Ξ';
        //sms[27] = '';
        sms[28] = 'Æ';
        sms[29] = 'æ';
        sms[30] = 'ß';
        sms[31] = 'É';
        sms[32] = ' ';
        sms[33] = '!';
        sms[34] = '"';
        sms[35] = '#';
        sms[36] = '¤';
        sms[37] = '%';
        sms[38] = '&';
        sms[39] = '\'';
        sms[40] = '(';
        sms[41] = ')';
        sms[42] = '*';
        sms[43] = '+';
        sms[44] = ',';
        sms[45] = '-';
        sms[46] = '.';
        sms[47] = '/';
        sms[48] = '0';
        sms[49] = '1';
        sms[50] = '2';
        sms[51] = '3';
        sms[52] = '4';
        sms[53] = '5';
        sms[54] = '6';
        sms[55] = '7';
        sms[56] = '8';
        sms[57] = '9';
        sms[58] = ':';
        sms[59] = ';';
        sms[60] = '<';
        sms[61] = '=';
        sms[62] = '>';
        sms[63] = '?';
        sms[64] = '¡';
        sms[65] = 'A';
        sms[66] = 'B';
        sms[67] = 'C';
        sms[68] = 'D';
        sms[69] = 'E';
        sms[70] = 'F';
        sms[71] = 'G';
        sms[72] = 'H';
        sms[73] = 'I';
        sms[74] = 'J';
        sms[75] = 'K';
        sms[76] = 'L';
        sms[77] = 'M';
        sms[78] = 'N';
        sms[79] = 'O';
        sms[80] = 'P';
        sms[81] = 'Q';
        sms[82] = 'R';
        sms[83] = 'S';
        sms[84] = 'T';
        sms[85] = 'U';
        sms[86] = 'V';
        sms[87] = 'W';
        sms[88] = 'X';
        sms[89] = 'Y';
        sms[90] = 'Z';
        sms[91] = 'Ä';
        sms[92] = 'Ö';
        sms[93] = 'Ñ';
        sms[94] = 'Ü';
        sms[95] = '§';
        sms[96] = '¿';
        sms[97] = 'a';
        sms[98] = 'b';
        sms[99] = 'c';
        sms[100] = 'd';
        sms[101] = 'e';
        sms[102] = 'f';
        sms[103] = 'g';
        sms[104] = 'h';
        sms[105] = 'i';
        sms[106] = 'j';
        sms[107] = 'k';
        sms[108] = 'l';
        sms[109] = 'm';
        sms[110] = 'n';
        sms[111] = 'o';
        sms[112] = 'p';
        sms[113] = 'q';
        sms[114] = 'r';
        sms[115] = 's';
        sms[116] = 't';
        sms[117] = 'u';
        sms[118] = 'v';
        sms[119] = 'w';
        sms[120] = 'x';
        sms[121] = 'y';
        sms[122] = 'z';
        sms[123] = 'ä';
        sms[124] = 'ö';
        sms[125] = 'ñ';
        sms[126] = 'ü';
        sms[127] = 'à';
        double lat = 43.26432; //64 bit
        String stringa;
        String compressa = "";
        
        System.out.println("Messaggio originale :"+ lat);

        //convert il double in una stringa con la conversione binaria del dato
        stringa = Long.toBinaryString(Double.doubleToRawLongBits(lat));
        System.out.println(stringa);
        
        //divide il dato in pezzi da 7 bit
        //per mandare il dato via SMS con la tabella caratteri SMS
        String b1 = stringa.substring(0, 7);
        String b2 = stringa.substring(7, 14);
        String b3 = stringa.substring(14, 21);
        String b4 = stringa.substring(21, 28);
        String b5 = stringa.substring(28, 35);
        //String b6 = stringa.substring(35, 42);
        //String b7 = stringa.substring(42, 49);
        //String b8 = stringa.substring(49, 56);
      
        //convert il valore binario a base 7 in intero
        int d1 = Integer.parseInt(b1, 2);
        int d2 = Integer.parseInt(b2, 2);
        int d3 = Integer.parseInt(b3, 2);
        int d4 = Integer.parseInt(b4, 2);
        int d5 = Integer.parseInt(b5, 2);
        //int d6 = Integer.parseInt(b6, 2);
        //int d7 = Integer.parseInt(b7, 2);
        //int d8 = Integer.parseInt(b8, 2);
        
        //usando la tabella di compressione prende i primi 5 gruppi di 7 bit
        //e li codifica come SMS
        //compressa = compressa + sms[d1]+sms[d2]+sms[d3]+sms[d4]+sms[d5]+sms[d6]+sms[d7]+sms[d8];
        compressa = compressa + sms[d1]+sms[d2]+sms[d3]+sms[d4]+sms[d5];
        System.out.println("Messaggio compresso : "+compressa);
        
        for (int t=0; t<compressa.length();t++)
            {
            valore = converti_sms(compressa.charAt(t));
            String v = Integer.toBinaryString(valore);
           reverse = new StringBuffer(v).toString();
           //System.out.println(reverse);


        

            while ((reverse.length() %7) != 0)
                {
                reverse = "0"+reverse ;
                }
            passaggio = passaggio + reverse;
            //System.out.println("a "+reverse);

            }
        

        
        passaggio = passaggio + "0000000000000000000000000000";
        System.out.println(passaggio);

        
        double doubleVal = Double.longBitsToDouble(new BigInteger(passaggio, 2).longValue());
        System.out.println("Messaggio decompresso : "+doubleVal);
        
        
        
    }
    
}

Compressione SMS in Android

Per la solita applicazione su cui sto lavorando adesso, sarebbe utile effettuare la compressione dei dati di un SMS per trasportare la maggiore quantita' di informazioni. Ho fatto un paio di prove, la prima e' questa basata semplicemente sulla compressione dei caratteri

Fonte Wikipedia


I dati previsti sono numerici con alcuni segni di interpunzione per cui l'intero set di caratteri puo' essere descritto con un set di 16 caratteri (4 bit). I dati trasportati sono coordinate geografiche, informazioni sul tempo, dati di antenne e stato della batteria
Considerando che la tavola dei caratteri piu' semplice per gli SMS racchiude 7 bit c'e' un discreto guadagno (un fattore di 1.75)

Attualmente gli SMS permettono di inviare 1120 bit, ovvero 160 caratteri con la tabella a 7 bit e 140 con la tabella ad 8 bit.(le tabelle dei codici SMS non sono confrontabili con quelle ASCII)

Usando il codice riportato dopo il salto e' stata effettuata una prova codificando

---------------------------------------------
Messaggio : 12.3455;43.123123;22;-45;13:23:21 12/03/2013
Lungh. messaggio 44
Valore numerici convertiti a 7 bit 72 22 11 85 39 120 34 98 72 120 17 58 45 116 33 30 68 7 97 71 84 0 23 2 72 127 127 
Messaggio compresso a 7 Bit tabella GSM : HΠØU'x"bHx_:-t!ßDìaGT@Ψ$Hàà
Lungh.Mess.Compresso 27
Messaggio Decompresso :12.3455;43.123123;22;-45;13:23:21 12/03/2013   
---------------------------------------------

Come si osserva che il messaggio e' compresso con un fatto di circa 1.7 (il limite teorico di 1.75 non e' raggiunto per una serie di aggiustamenti nel passare da 4 a 7 bit)


Smartphone e privacy

Ieri ho trovato questo BlackBerry a terra per strada. E' il secondo cellulare che trovo, il primo lo trovai al cinema oltre 10 anni fa (considerando la diffusione dei cellulari direi che la mia media di ritrovamento e' piuttosto scarsa)


Il cellulare era acceso e sbloccato per cui nel giro di 5 minuti ho trovato nell'agenda un numero relativo ad un familiare del proprietario ed il telefono e' stato restituito
C'e' pero' da fare una considerazione: se fossi stato un male intenzionato mi sono trovato per le mani un oggetto con configurato un account Google (con sicuramente l'account di posta configurato viste le icone sulla home) ma anche un account Facebook (sempre viste le icone sulla home) e con un po' di fortuna avrei raccattato una quantita' di dati sensibili preoccupante (se l'utente usava anche GDrive ero a cavallo)
Dieci anni fa ritrovare un telefono voleva dire, se maleintenzionati, farsi qualche telefonata gratuita e magari tenersi il telefono, oggi il rischio della perdita di uno smartphone e' decisamente preoccupante.
Di fatto lo stesso motivo che mi ha permesso di riconsegnare in breve tempo il telefono (ovvero il fatto che non fosse protetto con un pin code o simili) potrebbe riverlarsi, nelle mani sbagliate, un grave rischio per il conto in banca del proprietario

lunedì 13 gennaio 2014

Batteria bruciata su JIAYU G3T

Il telefono in questione, uno JIAYU G3T (in breve le caratteristiche 4.5 pollici HD IPS Gorillla Quad Core 1.5Ghz MTK6589T Android 4.2 Dual SIM WIFI GPS 8MP) durante la carica ha segnalato, tramite sistema operativo, un surriscaldamento della batteria

Il possessore, un amico, ha spento il telefono (lasciandolo pero' in carica). Al mattino successivo la pessima sorpresa: batteria fusa, parte della scocca fusa ed ovviamente telefono che non parte
Piccola nota: acquistato da circa un mese




Mandelbrot su Arduino con TvOut

Un metodo veloce per visualizzare dati derivanti da una Arduino senza utilizzare display appositi ed impiegando solo due uscite digitali puo' essere quella di ricorrere alla libreria TvOut ed inviando il segnale all'uscita SVideo di un comune televisore


In questo modo, usando un semplice connettore S-Video ed un paio di resistenze, si puo' avere una visualizzazione senza troppi problemi
Lo schema delle resistenza e' il seguente


Alcuni riportano che' obbligatoria una resistenza da 75 Ohm anche sul GND. Per quanto mi riguarda il tutto ha funzionato anche senza (ho avuto difficolta' a trovare questo taglio di resistenza)
Importante: sul sito e' indicato che per la Arduino Uno i pin digitali da collegare sono D7 (Video), D9 (Sync) e GND ma nel mio caso hanno funzionato D8 (Video), D9 (Sync) e GND

La risoluzione di base e' sostanzialmente pessima, un misero 128x98, ma per un sistema cosi' semplice non e' male
Ovviamente non potevo esimermi dal provare a disegnare l'insieme di Mandelbrot




-----------------------------------------------------------------------------
#include <TVout.h>
TVout TV;


int SCREEN_WIDTH = 0;
int SCREEN_HEIGHT = 0;

float re_min = -2.0;
float im_min = -1.2;
float re_max = 1.0;
float im_max = 1.2;
int iterazioni = 60;
float a,b;
float x,y,x_new,y_new;
int test;
int k,j,i;


void setup(void) {
  TV.start_render(_PAL);
  TV.delay_frame(50);

  TV.clear_screen();
  SCREEN_WIDTH = TV.horz_res();
  SCREEN_HEIGHT = TV.vert_res();

  //---------------------------------
  float re_factor = (re_max-re_min);
  float im_factor = (im_max-im_min);
  for (i=0;i<SCREEN_HEIGHT;i++)
     {
     for (j=0;j<SCREEN_WIDTH;j++)
      {
      a = re_min+(j*re_factor/SCREEN_WIDTH); 
      b = im_min+(i*im_factor/SCREEN_HEIGHT);
      x = 0;
      y = 0;
      test = 0;
      for (k=0;k<iterazioni;k++)
       {
       x_new = (x*x)-(y*y)+a;
       y_new = (2*x*y)+b;
       if (((x_new*x_new)+(y_new*y_new))>4)
        {
        test = k;
        if (k%2)
          {
            TV.set_pixel(j,i,1); 
         }     
        break;
        }
       x = x_new;
       y = y_new;
       }
      }
     }
}

void loop(void) {
  while (1) {}
}

venerdì 10 gennaio 2014

74HC4050 Level Shifter con Arduino

Il 74HC4050 permette di cambiare il voltaggio di una porta digitale Arduino da 5 V ad un valore differente (tipicamente 3.3V, molti componenti moderni funzionano a questa tensione) senza alternarne lo stato logico

In pratica in pin del 4050 sono a coppie AY. Quando sul pin A si ha una tensione di 5V sul corrispondente pin Y si avra' la tensione di 3.3V



ed ecco la versione reale
il cavo giallo e' l'uscita del pin D13 dopo essere passata per il level shifter
il cavo nero e' il gnd (in realta' sono due cavi perche' su uno e' montato il voltmetro)
il cavo bianco e rosso e' l'uscita del pin D13 senza conversione


Montando sull'Arduino il semplice sketch Blink il risultato e' il seguente (prima viene misurata l'uscita pura dal pin D13 e poi quella modificata dal level shifter)


giovedì 9 gennaio 2014

GPS Tracking e batteria in Android

Sto sviluppando una applicazione per effettuare il tracciamento di escursionisti (a piedi ed in ambiente di montagna) per cui una delle caratteristiche richieste e' la lunga durata della batteria
Normalmente un cellulare Android con batteria completamente carica non riesce a tracciare piu' di 5 ore di percorso, un tempo scarsino per una escursione dato che mediamente di parla di 6-9 ore

Una soluzione che sto valutando e' quello di non tracciare con continuita' ma di accendere l'antenna GPS per un minuto (tempi inferiori non garantiscono che ci sia il fix del punto Gps) e che rimanga spenta un tempo prestabilito (diciamo 4-5 minuti che a piedi con velocita' uguale od inferiore a 5 Km/h corrisponde ad un punto ogni 400 m). In tale modo non si ha la traccia del sentiero ma si ha sempre la posizione  sul percorso
(l'applicazione nella versione definitiva dovrebbe una applicaizone orientata al soccorso)

Una prima prova e' stata effettuata con il programma riportato al termine del post: i punti sono stati acquisiti ogni 4 minuti (durante la prova lo spostamento e' stato effettuato in macchina quindi le acquisizioni sono molto distanziate)
In giallo i punti acquisiti
ed ecco la tabella delle acquisizioni con i tempi



Il programma implementa un Timer (che scatta ogni minuto) ed un Location Manager.
Quando il numero di cicli del timer (variabile contatore) e' un multiplo di 5 viene attivato il Location Manager altrimenti vengono disattivate le update dallo stesso manager (e viene spenta l'antenna)
Semplice ma funzionale
----------------------------------------------------------
package com.test.tempo;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.WindowManager;

public class MainActivity extends Activity {

private Timer t;
private TimerTask task;
private LocationManager mlocManager;
private MyLocationListener mlocListener;
private double contatore;
public String tempo_gps;
public double latitudine;
public double longitudine;
public long old_time;
public boolean gps_fix;
public long tempo;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//mantiene lo schermo attivo 
   getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

contatore = 0;

//GESTIONE DEL GPS
mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();
        mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        // se il GPS non e' abilitato richiede l'intervento dell'utente
        if (!mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
        startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
        }

//GESTIONE DEL TIMER
        t = new Timer();     
   task = new TimerTask() {  
   @Override  
     public void run() {  
    runOnUiThread(new Runnable() {  
   @Override  
   public void run() {  
    //nella variabile contatore ci sono i minuti trascorsi
    contatore = contatore+1;
    //se i minuti sono divisibili per 5 allora si acquisisce per un minuto la posizione
    //acquisisce anche al primo ciclo per inizializzare il GPS
    if (((contatore % 5) == 0) || (contatore == 0))
    {
    //abilita GPS
       mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
    }
    else
    {
    //disabilita GPS
    mlocManager.removeUpdates(mlocListener);
    }
         
     }  //fine run
    });  
   }  
  };
  //il timer scatta una volta ogni 60 secondi
  t.scheduleAtFixedRate(task, 0, 60000);
  // FINE DELLA GESTIONE DEL TIMER
}

public class MyLocationListener implements LocationListener
    {


@Override
    public void onLocationChanged(Location loc)
    {
    latitudine = loc.getLatitude();
    longitudine = loc.getLongitude();
    tempo = loc.getTime();
    
    // e' considerato di avere il fix gps se non ci sono piu' di 5 secondi
    // tra due letture consecutive
    if ((tempo-old_time < 5000) && (old_time > 0))
    {
            gps_fix = true;
            Date date = new Date(tempo);
            SimpleDateFormat format = new SimpleDateFormat("dd/MM/yy HH:mm:ss zzz a");
            format.setTimeZone(TimeZone.getTimeZone("GMT"));
            tempo_gps = format.format(date);
            salva();
    }
    old_time = tempo;
    }


    @Override
    public void onProviderDisabled(String provider)
    {
    gps_fix = false;
    }


    @Override
    public void onProviderEnabled(String provider)
    {
    gps_fix = false;
    }


@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub

}
  }



//all'uscita dall'applicazione spenge il timer ed il GPS
protected void onDetroy()
{
super.onDestroy();
t.cancel();  
   t.purge();  
        mlocManager.removeUpdates(mlocListener);
}


private void salva()
// salva i dati su file
   {
            try {
                   File root = Environment.getExternalStorageDirectory();
                   if (root.canWrite()){
                       File data_file = new File(root, "sart.txt");
                       FileWriter data_file_writer= new FileWriter(data_file,true);
                       BufferedWriter out = new BufferedWriter(data_file_writer);
                            out.write(Double.toString(latitudine)+";"+Double.toString(longitudine)+";"+tempo_gps+"\n");
                            out.close();        
                   }
               } catch (IOException e) {
               }

           
   }


}

-------------------------------------------------------------
Manifest
-------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.tempo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.test.tempo.MainActivity"
            android:label="@string/app_name" 
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>


</manifest>


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