martedì 21 agosto 2018

Bluetooth LE cached name scan

Lavorando ad un progetto in cui un beacon BLE cambia spesso il proprio nome ho scoperto che la funzione ScanResult (vedi qui per esempio) non aggiorna i nomi dei beacon una volta scoperti (come se avesse una cache interna). Usando invece la funzioen ScanRecord, come nel codice sottostante, tutto funziona in modo corretto


-----------------------------
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.blescan.lucainnocenti.blescan">

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>



    <uses-feature        android:name="android.hardware.bluetooth_le"        android:required="true" />

    <application        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>
-----------------------------


-----------------------------
package com.blescan.lucainnocenti.blescan;

import android.Manifest;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private BluetoothAdapter mBluetoothAdapter  = null;
    private BluetoothLeScanner mBluetoothLeScanner = null;

    public static final int REQUEST_BT_PERMISSIONS = 0;
    public static final int REQUEST_BT_ENABLE = 1;

    private boolean mScanning = false;
    private Handler mHandler = null;

    private Button btnScan = null;



    private ScanCallback mLeScanCallback =
            new ScanCallback() {

                @Override                public void onScanResult(int callbackType, final ScanResult result) {
                    super.onScanResult(callbackType, result);
                    final ScanRecord scanRecord = result.getScanRecord();


                    if (scanRecord.getDeviceName() != null) {
                        Log.d("BLE", scanRecord.getDeviceName());
                    }

                }

                @Override                public void onScanFailed(int errorCode) {
                    super.onScanFailed(errorCode);
                    Log.d("BLE", "error");
                }
            };






    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnScan = (Button) findViewById(R.id.btnScan);

        new Handler().postDelayed(new Runnable() {
            @Override            public void run() {
                if (mScanning){
                    mScanning = false;
                    scanLeDevice(false);
                    btnScan.setText("STOP");
                } else {
                    mScanning = true;
                    scanLeDevice(true);
                    btnScan.setText("SCAN");
                }
            }
        }, 30000);




        btnScan.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View view) {
                onBtnScan();
            }
        });
        this.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        this.mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
        this.mHandler = new Handler();

        checkBtPermissions();
        enableBt();
    }

    public void onBtnScan(){
        if (mScanning){
            mScanning = false;
            scanLeDevice(false);
            btnScan.setText("STOP");
        } else {
            mScanning = true;
            scanLeDevice(true);
            btnScan.setText("SCAN");
        }
    }

    public void checkBtPermissions() {
        this.requestPermissions(
                new String[]{
                        Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN                },
                REQUEST_BT_PERMISSIONS);
    }

    public void enableBt(){
        if (mBluetoothAdapter == null) {
            // Device does not support Bluetooth        }
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_BT_ENABLE);
        }
    }

    public void scanLeDevice(final boolean enable) {
        // ScanSettings mScanSettings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_BALANCED).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).build();
        if (enable) {
            mScanning = true;
            Log.i("Scanning", "start");
            mBluetoothLeScanner.startScan(mLeScanCallback);
        } else {
            Log.i("Scanning", "stop");
            mScanning = false;
            mBluetoothLeScanner.stopScan(mLeScanCallback);
        }
    }
-----------------------------

venerdì 17 agosto 2018

ESP 32 Bluetooth Beacon

Avevo gia' comprato da diverso tempo una scheda da sviluppo di ESP32 (ESP-VROOM-32) ma non avevo avuto modo di trovarle un utilizzo serio.
Adesso l'ho tirata fuori per creare una sorta di beacon bluetooth programmabile. In pratica il sistema deve consumare il meno possibile (e quindi deve utilizzare lo sleep mode del processore) fino a quando viene premuto un pulsante; fino a che il pulsante e' mantenuto premuto deve attivarsi il bluetooth, al momento del rilascio del pulsante il dispositivo deve segnalare per 10 secondi che si sta spengendo (o meno che sta andando in sleep mode) e poi deve addormentarsi



Il pinout della scheda e' il seguente


Per poter programmare la scheda con Arduino IDE (su Mac) si deve eseguire il seguente comando

mkdir -p ~/Documents/Arduino/hardware/espressif && \
cd ~/Documents/Arduino/hardware/espressif && \
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
python get.py
Si devono installare i driver USB to UART VCP scaricabili da qui


Queste le impostazione dell'Arduino IDE. E' consigliato di usare una Flash Frequency di 40 MHz ed una Upload Speed di 115200

Ho trovato un problema (che a quanto pare e' piuttosto comune) ovvero che non sempre e' possibile caricare lo sketch via Arduino sul modulo ESP a causa dell'errore


Timed out waiting for packet header
Non so quale e' la soluzione...a forza di provare, premendo i tasti boot e reset, la scheda ritorna a funzionare




----------------------------------
#include "SimpleBLE.h"
SimpleBLE ble;

const int buttonPin = 14;    
int buttonState = 0;     
int prevState = 0;   

void setup() {
  Serial.begin(115200);

  pinMode(buttonPin, INPUT);
  Serial.println("Start");

  esp_sleep_enable_ext0_wakeup(GPIO_NUM_14,1); //1 = High, 0 = Low
  

}

void loop() {
  buttonState = digitalRead(buttonPin);

  if ((buttonState == HIGH)  && (prevState == 0)) {
    Serial.println("Start BLE");
    prevState = 1;
    ble.begin("ESP32");
  }

  if ((buttonState == LOW)  && (prevState == 1)) {
    Serial.println("Stop BLE");
    ble.end();
    delay(2000);
    ble.begin("ESP32 OFF");
    delay(10000);
    ble.end();
    Serial.println("Sleep Mode");
    delay(1000);
    prevState = 0,
    esp_deep_sleep_start();
  }
----------------------------------

martedì 14 agosto 2018

PMII 32 - Cisco router 2500 series

Due router CISCO inizio anni 2000. Erano utilizzati per connessioni ISDN

Cisco CPA 2503


Cisco 2511




Olivetti Logos 62

Ho trovato questa Olivetti Logos 62 in pessime condizioni. Connessa alla corrente si sente un ronzio di fondo ma non si accende nessun led sul display. La macchina e' di fine 1985 a vedere le etichette di controllo qualita' dentro alla scocca



La cosa piu' sorprendete e' che tutta l'elettronica e' praticamente contenuta in un solo chip, un NEC D1260C (Calculator on a chip) usato da Olivetti su altre calcolatrici da tavolo dalla fine degli anni 70



L'organizzazione interna del PCB e' simile ad altre calcolatrici da tavolo Olivetti (vedi Logos 49)





La tastiera presentava dei tasti che non tornavano indietro. Pensando che ci fossero problemi alle molle ho smontato il tutto per scoprire che non ci sono molle ma una tastiera a membrana con delle capsule celesti elastiche


martedì 7 agosto 2018

Quater square multiplication

Un metodo per effettuare moltiplicazioni usando somme e sotttrazioni ed una tabella di lookup

La tabella di lookup e' formata dalla parte intera della divisione per 4 di quadrati dei numeri interi

---------------------------------
for i in range (20):
print (int(i*i/4))
-----------------------------------------

lookup = [0,0,1,2,4,6,9,12,16,20,25,30,36,42,49,56,64,72,81,90]

si usa la seguente identita'


per esempio se si vuole moltiplicare x=7 per y=5 si calcola la differenza (2) e la somma (12). Si guarda nella tabella di lookup le posizioni 2 e 12 che corrispondono ai valori 1 e 36 (in pratica dalla tabella si ricavano (x +y)^2/4 e (x -y)^2/4 . A questo punto basta effettuare la sottrazione (36-1) per avere il risultato della moltiplicazione

---------------------------------
lookup = [0,0,1,2,4,6,9,12,16,20,25,30,36,42,49,56,64,72,81,90]

m1 = 7
m2 = 5
diff = m1 - m2
somma = m1 + m2
a1 = lookup[diff]
a2 = lookup[somma]

risultato = a2 - a1
print (risultato)
---------------------------------

Una accortezza: i valori dei moltiplicatori devono essere ordinati con m1>m2

lunedì 6 agosto 2018

CORDIC

Quando a scuola mi hanno spiegato le serie di Taylor hanno aggiunto che le calcolatrici elettroniche usavano questo sistema per calcolare il valore delle funzioni trigonometriche...ho scoperto solo in questi giorni che l'algoritmo realmente impiegato e' CORDIC . Il metodo e' preferito alle serie di potenze perche', con la giusta formulazione, puo' essere sviluppato solo con "shift and add" binari e quindi implementabile anche su microprocessori/microcontrollori di bassa potenza di calcolo

Una delle pagine piu' esaurienti per il metodo si trova a questo indirizzo. Di fatto si tratta di eseguire una rotazione di un vettore

Per una implementazione del metodo si puo' usare il seguente codice in Python 3

La tabella di lookup serve solo per capire dopo quante iterazioni di i si puo' terminare il calcolo e quindi puo' essere omessa nel caso si sappia a priori il valore. In ogni caso la tabella di lookup si puo' ricavare da
------------
import math

for i in range(20):
print (i)
print (math.atan(2**(-i)))
print ("--------")
------------

in z si deve mettere il valore in radianti dell'angolo di rotazione desiderato (in questo caso 70°)
in x,y si trovano le proiezioni del vettore e quindi anche i valori del coseno e del seno della rotazione

in generale si puo' usare una base della potenza diversa da 2. L'utilizzo della base 2 e' utile perche' permette in un calcolatore binario di evitare le moltiplicazioni potendo effettuare dei semplici shift bit

importanti sono anche i valori di inizializzazione dell'algoritmo. Con x=1,y=0 si ottengono come risultati tangente,seno e coseno ma con altre impostazioni si possono calcolare funzioni iperboliche e
----------------------------
import math

lookup = [0.7853981633974483,
0.46364760900080615,
0.24497866312686414,
0.12435499454676144,
0.06241880999595735,
0.031239833430268277,
0.015623728620476831,
0.007812341060101111,
0.0039062301319669718,
0.0019531225164788188,
0.0009765621895593195,
0.0004882812111948983,
0.00024414062014936177,
0.00012207031189367021,
6.103515617420877e-05,
3.0517578115526096e-05,
1.5258789061315762e-05,
7.62939453110197e-06,
3.814697265606496e-06,
1.907348632810187e-06]

K = 0.6072529350088812561694

z = 1.22173 # 70° cos(70°)=0.342 sin(70°)=0.9396
x = 1
y = 0
k = 1

for i in range(19):
if z <= 0:
di = -1.0
else:
di = 1.0
k = k*math.cos(math.atan(di * 2.0**(-i)))
newx = x - (y * di * 2.0**(-i)) 
newy = y + (x * di * 2.0**(-i))
x = newx
y = newy
z = z - (di * lookup[i])
print("{0:2d}".format(i),end=' ')

print("{0:f}".format(x),end=' ')
print("{0:f}".format(y),end=' ')
print("{0:f}".format(k),end=' ')

print("{0:f}".format(z))

print ()
print ("Tangente : " + str(y/x))
print ("Coseno   : " + str(x*K))
print ("Seno       : " + str(y*K))
----------------------------
Per calcolare la tangente e' sufficiente dividere y per x
i valori di x ed y, devono essere invece moltiplicati per un valore che deriva da

k = k*math.cos(math.atan(di * 2.0**(-i)))

e converge abbastanza rapidamente al valore di 0.6072529350088812561694
Visto che tale valore e' costante ed indipendente dalla rotazione lo si puo' inserire come una costante senza necessariamente ricalcolarlo ogni volta 

Di seguito l'output del programma

----------------------------
 n      x         y         k        z
 0 1.000000 1.000000 0.707107 0.436332
 1 0.500000 1.500000 0.632456 -0.027316
 2 0.875000 1.375000 0.613572 0.217663
 3 0.703125 1.484375 0.608834 0.093308
 4 0.610352 1.528320 0.607648 0.030889
 5 0.562592 1.547394 0.607352 -0.000351
 6 0.586770 1.538603 0.607278 0.015273
 7 0.574749 1.543187 0.607259 0.007461
 8 0.568721 1.545433 0.607254 0.003554
 9 0.565703 1.546543 0.607253 0.001601
10 0.564192 1.547096 0.607253 0.000625
11 0.563437 1.547371 0.607253 0.000136
12 0.563059 1.547509 0.607253 -0.000108
13 0.563248 1.547440 0.607253 0.000014
14 0.563154 1.547474 0.607253 -0.000047
15 0.563201 1.547457 0.607253 -0.000016
16 0.563225 1.547449 0.607253 -0.000001
17 0.563236 1.547444 0.607253 0.000007
18 0.563230 1.547447 0.607253 0.000003

Tangente : 2.7474483008390256

Coseno   : 0.3420233441629116
Seno     : 0.9396914557676728
----------------------------

Per concludere l'algoritmo dovrebbe riscritto in matematica intera per avere i massimi benefici in termini di velocita'

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