BitBastelei #225 – Gigaset (DECT) auf LiPo umbauen

BitBastelei #225 - Gigaset (DECT) auf LiPo umbauen

(307 MB) 00:32:27

2017-01-01 10:59 🛈

Es ist wieder Congresszeit (33C3), das heißt ich krame meine DECT-Telefone wieder aus. Im letzten Video zu diesen Teilen saß ich im Zelt auf dem Chaos Communication Camp und ärgerte mich über eine nicht funktionierende Akkuladung. Schluss damit: Nun soll ein Li-Ion-Zelle die alten Ni-MH-Akkus ersetzen und, wenn wir schon dabei sind, ein Mikro-USB-Anschluss zum Laden nachgerüstet werden.

 

BitBastelei #224 – USB Power Monitor – Software

BitBastelei #224 - USB Power Monitor - Software

(42 MB) 00:24:11

2016-12-25 11:00 🛈

In Folge #222 hatten wir einen USB Power-Monitor gebaut, welcher Spannung und Strom misst und somit auch mAh und mWh berechnen können soll. Diesmal geht es um die Softwareseite – alles kein Hexenwerk (und vermutlich mit unzähligen Bugs), aber ein gutes Beispiel wie man verschiedene, einfache Codefragmente zu einer nützlichen Software kombinieren kann.

Quellcode:

@Github

/*
* USBMeter Test Sketch
* Copyright (c) 2017, Florian Knodt - www.adlerweb.info
* 
* Based on U8G2 HelloWorld.ino 
* Copyright (c) 2016, olikraus@gmail.com
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, 
* are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice, this list 
*    of conditions and the following disclaimer.
*    
*  * Redistributions in binary form must reproduce the above copyright notice, this 
*    list of conditions and the following disclaimer in the documentation and/or other 
*    materials provided with the distribution.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
*  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
*  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
*  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
*
*/

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // All Boards without Reset of the Display

unsigned int ref_u = 610;
unsigned int ref_i = 412;
unsigned int ref_i_o = 145;
unsigned int ref_i_mva = 131;
unsigned int ref_DP = 615;
unsigned int ref_DN = 613;
unsigned int ref_VCC = 616;
unsigned int ref_OV = 2175;

unsigned int AA0=0;
unsigned int AA1=0;
unsigned int AA2=0;
unsigned int AA3=0;
unsigned int AA6=0;
unsigned int AA7=0;

void setup(void) {
  pinMode(2, OUTPUT);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);

  analogReference(INTERNAL);

  Serial.begin(115200);
  Serial.println("USBMonitor Self-Test");
  
  u8g2.begin();
}

void printV(unsigned int volt) {
  unsigned int temp = volt / 100;
  boolean srt = false;

  if(temp > 10) srt = true;
  
  u8g2.print(temp);
  u8g2.print('.');
  if(srt) {
    temp = (volt % 100) / 10;
  }else{
    temp = volt % 100;
    if(temp < 10) u8g2.print('0');
  }
  u8g2.print(temp);
}


void printV(signed int volt) {
  if(volt > 0) printV((unsigned int)volt);

  u8g2.print('-');
  volt *= -1;
  unsigned int temp = volt / 100;
  
  u8g2.print(temp);
  u8g2.print('.');
  temp = (volt % 100) / 10;
  u8g2.print(temp);
}

void loop(void) {
  u8g2.clearBuffer();					// clear the internal memory
  u8g2.setFont(u8g2_font_unifont_t_latin);	// choose a suitable font
  
  u8g2.setCursor(10, 12);
  u8g2.print("SELF-TEST-MODE");

  u8g2.setCursor(0, 26);
  u8g2.print("S1:");
  u8g2.print((digitalRead(5) ? 1 : 0));
  
  u8g2.setCursor(42, 26);
  u8g2.print("S2:");
  u8g2.print((digitalRead(4) ? 1 : 0));
  
  u8g2.setCursor(85, 26);
  u8g2.print("S3:");
  u8g2.print((digitalRead(3) ? 1 : 0));

  u8g2.setCursor(0, 37);
  u8g2.print("A0:");
  //u8g2.print(analogRead(A0));
  unsigned int adco = (float)analogReadCache(AA0) * ref_u / 1000;
  printV(adco);

  u8g2.setCursor(64, 37);
  u8g2.print("A1:");
  //u8g2.print(analogRead(A1));
  signed int itmp=0;
  adco = (float)analogReadCache(AA1) * ref_i / 1000;
  itmp = adco - ref_i_o;
  itmp *= ref_i_mva;
  itmp /= 10;
  printV(itmp);

  u8g2.setCursor(0, 48);
  u8g2.print("A2:");
  //u8g2.print(analogRead(A2));
  adco = (float)analogReadCache(AA2) * ref_DP / 1000;
  printV(adco);

  u8g2.setCursor(64, 48);
  u8g2.print("A3:");
  //u8g2.print(analogRead(A3));
  adco = (float)analogReadCache(AA3) * ref_DN / 1000;
  printV(adco);

  u8g2.setCursor(0, 59);
  u8g2.print("A6:");
  //u8g2.print(analogRead(A6));
  adco = (float)analogReadCache(AA6) * ref_OV / 1000;
  printV(adco);

  u8g2.setCursor(64, 59);
  u8g2.print("A7:");
  //u8g2.print(analogRead(A7));
  adco = (float)analogReadCache(AA7) * ref_VCC / 1000;
  printV(adco);

  Serial.print((AA0));
  Serial.print(';');
  Serial.print((AA1));
  Serial.print(';');
  Serial.print((AA2));
  Serial.print(';');
  Serial.print((AA3));
  Serial.print(';');
  Serial.print((AA6));
  Serial.print(';');
  Serial.print((AA7));
  Serial.print(';');
  Serial.print(itmp);
  Serial.println();
    
  u8g2.sendBuffer();					// transfer internal memory to the display

  if(Serial.available() > 0) {
    char in = Serial.read();
    switch(in) {
      case '1':
      case 1:
        digitalWrite(2, HIGH);
        Serial.println("o1");
        break;
      case '0':
      case 0:
        digitalWrite(2, LOW);
        Serial.println("o0");
        break;
        
    }
  }

  //Wait 100ms to next display
  unsigned long lct = millis() + 500;
  while(millis() <= lct) {
    AA0 = (AA0 + (analogRead(A0)*10)) / 2;
    AA1 = (AA1 + (analogRead(A1)*10)) / 2;
    AA2 = (AA2 + (analogRead(A2)*10)) / 2;
    AA3 = (AA3 + (analogRead(A3)*10)) / 2;
    AA6 = (AA6 + (analogRead(A6)*10)) / 2;
    AA7 = (AA7 + (analogRead(A7)*10)) / 2;
  }
}

unsigned int analogReadCache(unsigned int out) {
  return out/10;
}
/*
* USBMeter Test Sketch
* Copyright (c) 2017, Florian Knodt - www.adlerweb.info
* 
* Based on U8G2 HelloWorld.ino 
* Copyright (c) 2016, olikraus@gmail.com
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, 
* are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice, this list 
*    of conditions and the following disclaimer.
*    
*  * Redistributions in binary form must reproduce the above copyright notice, this 
*    list of conditions and the following disclaimer in the documentation and/or other 
*    materials provided with the distribution.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
*  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
*  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
*  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
*  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
*
*/

#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <EEPROM.h>

U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // All Boards without Reset of the Display

//#define DEBUG

#define LED 13
#define FET 2
#define SW 3
#define RE1 4
#define RE2 5

#define ADC_U A0
#define ADC_I A1
#define ADC_DP A3
#define ADC_DN A2
#define ADC_VCC A7
#define ADC_OV A6

#define BROWNOUT 0 //4.6V - write EEPROM and shut down

static const float version = 0.02;

unsigned long lasttime = millis();
unsigned int runtime=0;

unsigned long lastkey = 0;
boolean lastkeyact = false;

unsigned int u_min = 475;
unsigned int u_max = 525;

unsigned int ref_u = 610;

/*
 * 10A

  unsigned int ref_i = 497;
  unsigned int ref_i_o = 174;
  unsigned int ref_i_mva = 146;
*/

/*
 * 5A
*/
  unsigned int ref_i = 412;
  unsigned int ref_i_o = 145;
  unsigned int ref_i_mva = 131;
/**/

unsigned int ref_DP = 615;
unsigned int ref_DN = 613;
unsigned int ref_VCC = 616;
unsigned int ref_OV = 2175;

unsigned int volt=0;
signed int amp=0;
signed int mAh=0;
signed long mWh=0;

char mAh_c=0;
char mWh_c=0;

unsigned int lastVcc=0;

unsigned int DP=0;
unsigned int DN=0;

byte signaling = 0; //0=open; 1=data; 2=apple-500; 3=Apple-1000; 4=Apple-2000; 5=DCP

/*
 * When D+ = D? = 2.0 V, the device may pull up to 500 mA.
 * When D+ = 2.0 V and D? = 2.8 V, the device may pull up to 1 A of current.
 * When D+ = 2.8 V and D? = 2.0 V, the device may pull up to 2 A of current.
 */

char flags[4];
byte uov = 0;
byte uovAct = 0;

byte menu = 0;
byte menuAct = 0;
char uartBtn = 0x00;

unsigned int adc_u = 0;
unsigned int adc_i = 0;
unsigned int adc_DP = 0;
unsigned int adc_DN = 0;
unsigned int adc_VCC = 0;
unsigned int adc_OV = 0;

boolean running = false;
boolean output = false;

void setup() {
  unsigned int tRead=0;
  
  // put your setup code here, to run once:
  pinMode(LED, OUTPUT);
  pinMode(FET, OUTPUT);

  pinMode(SW, INPUT_PULLUP);
  pinMode(RE1, INPUT_PULLUP);
  pinMode(RE2, INPUT_PULLUP);

  pinMode(ADC_U, INPUT);
  pinMode(ADC_I, INPUT);
  pinMode(ADC_DP, INPUT);
  pinMode(ADC_DN, INPUT);
  pinMode(ADC_VCC, INPUT);
  pinMode(ADC_OV, INPUT);

  digitalWrite(LED, LOW);
  digitalWrite(FET, LOW);
  digitalWrite(ADC_U, LOW);
  digitalWrite(ADC_I, LOW);
  digitalWrite(ADC_DP, LOW);
  digitalWrite(ADC_DN, LOW);
  digitalWrite(ADC_VCC, LOW);
  digitalWrite(ADC_OV, LOW);

  analogReference(INTERNAL); //1.1V internal bandgap reference

  EEPROM.get(0, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) u_min = tRead;
  EEPROM.get(2, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) u_max = tRead;
  EEPROM.get(4, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) ref_u = tRead;
  EEPROM.get(6, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) ref_i = tRead;
  EEPROM.get(8, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) ref_DP = tRead;
  EEPROM.get(10, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) ref_DN = tRead;
  EEPROM.get(12, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) ref_VCC = tRead;
  EEPROM.get(14, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) ref_OV = tRead;
  EEPROM.get(16, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) mAh = tRead;
  EEPROM.get(18, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) mWh = tRead;
  EEPROM.get(22, tRead);
  if(tRead > 0x0000 && tRead < 0xFFFF) runtime = tRead;
  
  Serial.begin(115200);

  Serial.println(F("#BOOT"));
  Serial.println(F("#USB POWER Monitor - www.adlerweb.info"));
  Serial.print(F("#Version: "));
  Serial.println(version);

  Serial.print(F("#[C] uMin: "));
  Serial.println(u_min);
  Serial.print(F("#[C] uMax: "));
  Serial.println(u_max);
  Serial.print(F("#[C] ref_u: "));
  Serial.println(ref_u);
  Serial.print(F("#[C] ref_i: "));
  Serial.println(ref_i);
  Serial.print(F("#[C] ref_DP: "));
  Serial.println(ref_DP);
  Serial.print(F("#[C] ref_DN: "));
  Serial.println(ref_DN);
  Serial.print(F("#[C] ref_VCC: "));
  Serial.println(ref_VCC);
  Serial.print(F("#[C] ref_OV: "));
  Serial.println(ref_OV);
  Serial.print(F("#[C] mAh: "));
  Serial.println(mAh);
  Serial.print(F("#[C] mWh: "));
  Serial.println(mWh);
  Serial.print(F("#[C] runtime: "));
  Serial.println(runtime);
  
  u8g2.begin();
  u8g2.firstPage();

  do {
    u8g2.setFont(u8g2_font_6x13_tr);
    u8g2.drawStr(11,13,"USB POWER MONITOR");
    u8g2.drawStr(11,25,"www.adlerweb.info");
  
    String out;
    out = "Version: ";
    out += version;
  
    char outc[out.length()+1];
    out.toCharArray(outc, sizeof(outc));
  
    u8g2.drawStr(25,50,outc);
  } while ( u8g2.nextPage() );

  delay(1000);
}


void dbug(String str) {
  #ifdef DEBUG
    Serial.print("D:");
    Serial.println(str);
  #endif
}


void loop() {
  unsigned int passed = (millis()-lasttime)/1000;
  
  getReadings();
  checkVcc();
  procUART();
  procSwitch();
  
  if(!u8g2.nextPage() && (millis()-lasttime)/1000 > 0) {
    dbug("FRAME");
    
    if(running && runtime < 0xFFFF) {
      runtime += (millis()-lasttime)/1000;
    }

    lasttime = millis();

    u8g2.firstPage();

    volt = procVolt();
    amp = procAmp();
    procmAh(passed);
    procmWh(passed);

    procDP();
    procDN();
    procSignaling();

    flags[0] = 'C';
    if(running) flags[0] = 'D';
    flags[1] = 'Q';
    if(output) flags[1] = 'S';
    
    switch(signaling) {
      case 1: //Data
        flags[2] = 'f';
        break;
      case 2: //Apple 0.5
      case 3: //Apple 1.0
      case 4: //Apple 2.0
        flags[2] = 'I';
        break;
      case 5: //DCP
        flags[2] = 'J';
        break;
      default: //0=OPEN
        flags[2] = 'H';
    }

    uovAct = uov;
    menuAct = menu;
    
    Serial.print('!');
    Serial.print(volt);
    Serial.print(';');
    Serial.print(amp);
    Serial.print(';');
    Serial.print(mAh);
    Serial.print(';');
    Serial.print(mWh);
    Serial.print(';');
    Serial.print(runtime);
    Serial.print(';');
    Serial.print(running);
    Serial.print(';');
    Serial.print(output);
    Serial.print(';');
    Serial.print(signaling);
    Serial.print(';');
    Serial.print(lastVcc);
    Serial.println();
  }

  switch(menuAct) {
    case 0:
      u8g2.setFont(u8g2_font_6x13_tr);
      u8g2.drawStr(38,13,"USB PWR MONITOR");
    
      drawVolt();
      drawAmp();
    
      drawWatt();
      
      drawAh();
      drawWh();
      
      drawTime(runtime);
    
      switch(uovAct) {
        case 1:
          u8g2.drawStr(115,63,"UV");
          break;
        case 2:
          u8g2.drawStr(115,63,"OV");
          break;
      }
    
      u8g2.setFont(u8g2_font_m2icon_9_tf);
      u8g2.drawStr(0,11,flags);
      break;
    case 1:
      u8g2.setFont(u8g2_font_6x13_tr);
      u8g2.drawStr(38,13,"USB PWR MONITOR");

      drawDP();
      drawDN();
      drawSignaling();
      drawVCC();
      
      u8g2.setFont(u8g2_font_m2icon_9_tf);
      u8g2.drawStr(0,11,flags);
      break;
    case 2:
      u8g2.setFont(u8g2_font_6x13_tr);
      u8g2.drawStr(38,13,"USB PWR MONITOR");
      u8g2.drawStr(0,25,"Lower Limit:");

      drawUMin();

      u8g2.setFont(u8g2_font_m2icon_9_tf);
      u8g2.drawStr(0,11,flags);
      break;
    case 3:
      u8g2.setFont(u8g2_font_6x13_tr);
      u8g2.drawStr(38,13,"USB PWR MONITOR");
      u8g2.drawStr(0,25,"Upper Limit:");

      drawUMax();

      u8g2.setFont(u8g2_font_m2icon_9_tf);
      u8g2.drawStr(0,11,flags);
      break;
  }
  
}

void getReadings(void) {
  #ifdef DEBUG
  Serial.print('.');
  #endif
  
  if(adc_u == 0) {
    adc_u = analogRead(ADC_U)*10;
  }else{
    adc_u = (adc_u + analogRead(ADC_U)*10) / 2;
  }
  
  if(adc_i == 0) {
    adc_i = analogRead(ADC_I)*10;
  }else{
    adc_i = (adc_i + analogRead(ADC_I)*10) / 2;
  }
  
  if(adc_DP == 0) {
    adc_DP = analogRead(ADC_DP)*10;
  }else{
    adc_DP = (adc_DP + analogRead(ADC_DP)*10) / 2;
  }
  
  if(adc_DN == 0) {
    adc_DN = analogRead(ADC_DN)*10;
  }else{
    adc_DN = (adc_DN + analogRead(ADC_DN)*10) / 2;
  }
  
  if(adc_VCC == 0) {
    adc_VCC = analogRead(ADC_VCC)*10;
  }else{
    adc_VCC = (adc_VCC + analogRead(ADC_VCC)) / 2;
  }
  
  if(adc_OV == 0) {
    adc_OV = analogRead(ADC_OV);
  }else{
    adc_OV = (adc_OV + analogRead(ADC_OV)*10) / 2;
  }
}

void checkVcc(void) {
  unsigned int vccchk = getVcc();

  if(vccchk <= BROWNOUT) {
    EEPROM.put(16, mAh);
    EEPROM.put(18, mWh);
    EEPROM.put(22, runtime);
    fetOff();
    digitalWrite(LED, HIGH);
    Serial.println(F("E:VCC"));
    Serial.flush();
    while(1) {}
  }
}

unsigned int getVcc(void) {
  unsigned int adco = (float)adc_VCC * ref_VCC / 10000;
  lastVcc = adco;
  adc_VCC = 0;
  return adco;
}

void procUART(void) {
  unsigned int temp=0;
  if(Serial.available()) {
    switch(Serial.read()) {
      case '1':
        fetOn();
        Serial.println(F("OK"));
        break;
      case '0':
        fetOff();
        Serial.println(F("OK"));
        break;
      case 'r':
        runtime = 0;
        mAh=0;
        mWh=0;
        mAh_c=0;
        mWh_c=0;
        uov=0;
        Serial.println(F("OK"));
        break;
      case 's':
        running = false;
        fetOff();
        Serial.println(F("OK"));
        break;
      case 'S':
        running = true;
        fetOn();
        Serial.println(F("OK"));
        break;
      case '<':
        temp = Serial.parseInt();
        if(temp > 0) {
          u_min = temp;
          EEPROM.put(0, u_min);
          Serial.println(F("OK"));
        }
        break;
        temp = Serial.parseInt();
        if(temp > 0) {
          u_max = temp;
          EEPROM.put(2, u_max);
          Serial.println(F("OK"));
        }
        break;
      case 'u':
        temp = Serial.parseInt();
        if(temp > 0) {
          ref_u = temp;
          EEPROM.put(4, ref_u);
          Serial.println(F("OK"));
        }
        break;
      case 'i':
        temp = Serial.parseInt();
        if(temp > 0) {
          ref_i = temp;
          EEPROM.put(6, ref_i);
          Serial.println(F("OK"));
        }
        break;
      case 'p':
        temp = Serial.parseInt();
        if(temp > 0) {
          ref_i = temp;
          EEPROM.put(8, ref_i);
          Serial.println(F("OK"));
        }
        break;
      case 'n':
        temp = Serial.parseInt();
        if(temp > 0) {
          ref_DN = temp;
          EEPROM.put(10, ref_DN);
          Serial.println(F("OK"));
        }
        break;
      case 'v':
        temp = Serial.parseInt();
        if(temp > 0) {
          ref_VCC = temp;
          EEPROM.put(12, ref_VCC);
          Serial.println(F("OK"));
        }
        break;
      case 'O':
        temp = Serial.parseInt();
        if(temp > 0) {
          ref_OV = temp;
          EEPROM.put(14, ref_OV);
          Serial.println(F("OK"));
        }
        break;
      case 'V':
        Serial.print(F("#Version: "));
        Serial.println(version);
        break;
      case 'm':
        uartBtn = 'm';
        break;
      case '+':
        uartBtn = '+';
        break;
      case '-':
        uartBtn = '-';
        break;
    }
  }
}

void procSwitch(void) {
  if(( lastkey+100) > millis()) return;
  
  if(lastkeyact) {
    if(digitalRead(SW) == HIGH && digitalRead(RE1) == HIGH && digitalRead(RE2) == HIGH) {
      lastkeyact = false;
      lastkey = millis()+50;
    }

    return;
  }
  
  if(digitalRead(SW) == LOW || uartBtn == 'm') {
    lastkeyact = true;
    lastkey = millis();

    if(menu == 2) {
      unsigned int temp=0;
      EEPROM.get(0, temp);

      if(temp != u_min) EEPROM.put(0, u_min);
    }
    if(menu == 3) {
      unsigned int temp=0;
      EEPROM.get(2, temp);

      if(temp != u_max) EEPROM.put(2, u_max);
    }
    
    menu++;
    if(menu > 3) menu = 0;
  }

  switch(menu) {
    case 0:
      if(digitalRead(RE1) == LOW || uartBtn == '+') {
        lastkeyact = true;
        lastkey = millis();
        if(running) {
          fetOff();
          running = false;
        }else{
          fetOn();
          uov=0;
          running = true;
        }
      }
      if(digitalRead(RE2) == LOW || uartBtn == '-') {
        lastkeyact = true;
        lastkey = millis();
        runtime = 0;
        mAh=0;
        mWh=0;
        mAh_c=0;
        mWh_c=0;
        uov=0;
      }
      break;
    case 1:
      break;
    case 2:
      if(digitalRead(RE1) == LOW || uartBtn == '+') {
        lastkeyact = true;
        lastkey = millis();
        u_min++;
      }
      if(digitalRead(RE2) == LOW || uartBtn == '-') {
        lastkeyact = true;
        lastkey = millis();
        u_min--;
      }
      break; 
    case 3:
      if(digitalRead(RE1) == LOW || uartBtn == '+') {
        lastkeyact = true;
        lastkey = millis();
        u_max++;
      }
      if(digitalRead(RE2) == LOW || uartBtn == '-') {
        lastkeyact = true;
        lastkey = millis();
        u_max--;
      }
      break;
  }
  uartBtn = 0x00;
}

unsigned int procVolt(void) {
  unsigned int adco = (float)adc_u * ref_u / 10000;

  if(adco > 620) { //use secondary ADC
    adco = (float)adc_OV * ref_OV / 1000;
  }

  adc_u=0;
  adc_OV=0; 
  
  return adco;
}

signed int procAmp(void) {
  signed int adco=0;

  
  
  adco = (((signed long)adc_i * ref_i) - ((signed long)ref_i_o*10000)) * ((float)ref_i_mva/100000);
  /*adco = adco - ref_i_o;
  adco *= ref_i_mva;
  adco /= 10;*/

  adc_i = 0;
  
  if(!output) return 0;
  return adco;
}

void procmAh(unsigned int timedelta) {
  boolean neg = false;
  signed int tamp = amp;

  if(tamp < 0) {
    tamp *= -1;
    neg = true;
    mAh_c = 0;
  }
  
  signed long temp = mAh_c;

  temp += (signed long)(tamp * 10 * timedelta) / 36;

  if(neg) {
    mAh -= (temp/100);
  }else{
    mAh += (temp/100);
    mAh_c = temp % 100;
  }
}

void procmWh(unsigned int timedelta) {
  signed long temp = mWh_c;
  temp += (((signed long)amp * timedelta * volt) / 3600);
  mWh_c = temp % 10;
  mWh += (temp/10);
}

void procDP(void) {
  DP = (float)adc_DP * ref_DP / 10000;
  adc_DP = 0;
}

void procDN(void) {
  DN = (float)adc_DN * ref_DN / 10000;
  adc_DN = 0;
}

void procSignaling(void) {
  if(DP > 180 && DP < 220 && DN > 180 && DN < 220) {
    signaling = 2; //Apple 0.5A
  }else if(DP > 180 && DP < 220 && DN > 260 && DN < 300) {
    signaling = 3; //Apple 1.0A
  }else if(DP > 260 && DP < 300 && DN > 180 && DN < 220) {
    signaling = 4; //Apple 2.0A
  }else{ //Check if pins are shorted for DCP
    digitalWrite(ADC_DP, LOW);
    pinMode(ADC_DP, OUTPUT);
    delay(2);
    if(analogRead(ADC_DN) > 16) {
      signaling = 1; //Nope - looks like something else is pulling it HIGH, propably data
    } else{
      pinMode(ADC_DP, INPUT_PULLUP);
      delay(2);
      if(analogRead(ADC_DN) > 16) {
        signaling = 0; //Nothing changed - propably not connected
      } else{
        signaling = 5; //Looks like DCP
      }
    }
    digitalWrite(ADC_DP, LOW);
    pinMode(ADC_DP, INPUT);
  }
}

void drawVolt(void) {
  String out;

  unsigned int adc = volt;

  if(uov==0) {
    if(adc < u_min) {
      Serial.println("UV");
      uov=1;
      fetOff();
      running = false;
    }
    if(adc > u_max) {
      Serial.println("OV");
      uov=2;
      fetOff();
      running = false;
    }
  }

  out =  "U: ";
  out += adc/100;
  out += '.';
  adc %= 100;
  if(adc < 10) out += '0';
  out += adc;
  out += "V";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,25,outc);
}

void drawAmp(void) {
  String out;

  signed int adc = amp;

  out =  "I: ";
  if(adc < 0) {
    out += '-';
    adc *= -1;
  }
  out += adc/100;
  out += '.';
  adc %= 100;
  if(adc < 10) out += '0';
  out += adc;
  out += "A";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(64,25,outc);
}

void drawWatt() {
  String out;

  signed int adc = (signed long)((signed long)volt * (signed long)amp) / 100;

  out =  "P: ";
  
  if(adc < 0) {
    out += '-';
    adc *= -1;
  }
  
  out += adc/100;
  out += '.';
  adc %= 100;
  if(adc < 10) out += '0';
  out += adc;
  out += "W";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,37,outc);
}

void drawAh(void) {
  String out = "";

  signed int adc = mAh;

  if(adc<0) {
    out += '-';
    adc*=-1;
  }

  out += adc/1000;
  out += '.';
  adc %= 1000;
  if(adc < 100) out += '0';
  if(adc < 10) out += '0';
  out += adc;
  out += "Ah";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,50,outc);
}

void drawWh(void) {
  String out = "";

  signed int adc = mWh;

  if(adc<0) {
    out += '-';
    adc*=-1;
  }

  out += adc/1000;
  out += '.';
  adc %= 1000;
  if(adc < 100) out += '0';
  if(adc < 10) out += '0';
  out += adc;
  out += "Wh";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(64,50,outc);
}

void drawTime(unsigned int calctime) {
  String out;

  int days = calctime / 86400;
  calctime %= 86400;

  int hours = calctime / 3600;
  calctime %= 3600;

  int minutes = calctime / 60;
  calctime %= 60;

  out  = days;
  out += "d ";
  out += hours;
  out += "h ";
  out += minutes;
  out += "m ";
  out += calctime;
  out += "s";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,63,outc);
}

void drawDP(void) {
  String out;

  unsigned int adc = DP;

  out =  "D+: ";
  out += adc/100;
  out += '.';
  adc %= 100;
  if(adc < 10) out += '0';
  out += adc;
  out += "V";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,25,outc);
}

void drawDN(void) {
  String out;

  unsigned int adc = DN;

  out =  "D-: ";
  out += adc/100;
  out += '.';
  adc %= 100;
  if(adc < 10) out += '0';
  out += adc;
  out += "V";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(64,25,outc);
}

void drawSignaling(void) {
  String out;

  switch(signaling) {
    case 0:
      out = "Not connected";
      break;
    case 1:
      out = "Data Connection";
      break;
    case 2:
      out = "Apple 0.5A";
      break;
    case 3:
      out = "Apple 1.0A";
      break;
    case 4:
      out = "Apple 2.0A";
      break;
    case 5:
      out = "USB Charger";
      break;
    default:
      out = "Unknown";
  }

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,37,outc);
}

void drawVCC(void) {
  String out;

  unsigned int adc = lastVcc;

  out =  "Vcc: ";
  out += adc/100;
  out += '.';
  adc %= 100;
  if(adc < 10) out += '0';
  out += adc;
  out += "V";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,63,outc);
}

void drawUMin(void) {
  String out;

  unsigned int adc = u_min;

  out =  "Umin: ";
  out += adc/100;
  out += '.';
  adc %= 100;
  if(adc < 10) out += '0';
  out += adc;
  out += "V";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,50,outc);
}

void drawUMax(void) {
  String out;

  unsigned int adc = u_max;

  out =  "Umax: ";
  out += adc/100;
  out += '.';
  adc %= 100;
  if(adc < 10) out += '0';
  out += adc;
  out += "V";

  char outc[out.length()+1];
  out.toCharArray(outc, sizeof(outc));

  u8g2.drawStr(0,50,outc);
}

void fetOff(void) {
  output = false;
  digitalWrite(FET, LOW);
}

void fetOn(void) {
  output = true;
  digitalWrite(FET, HIGH);
}


 

BitBastelei #223 – 10€ IP-Kamera – viel Kommunikation für wenig Geld (Hi3516C)

BitBastelei #223 - 10€ IP-Kamera - viel Kommunikation für wenig Geld (Hi3516C)

(274 MB) 00:52:48

2016-12-18 11:00 🛈

Bei einigen Preisen kommt – trotz Bullshitverdacht – doch die Neugier in mir hoch, so auch als eine IP-Kamera für gerade mal 10€ durchtickerte. Jene Geräte waren zuletzt durch ihre massenhafte Übernahme durch das „Mirai“-Botnet auffällig geworden. 720p, vernunftige Framerate, Nachtsicht und mit Outdoor-Bildern in der Beschreibung – für den Preis ein üppiges Versprechen. Auf den ersten Blick sieht Sie sogar recht gut verarbeitet aus – schaut man jedoch darauf wie und wohin die Kamera kommuniziert wird schnell klar, dass sie besser nicht ungeschützt ins Netz sollte.

Amdroid/CM: Eingehende SMS werden nicht angezeigt

Die Älteren unter euch können sich eventuell erinnern: SMS. Ein System um Textnachrichten an Mobiltelefone zu senden. Begrenzte Textlänge, hohe Gebühren und nicht verschlüsselt. Eigentlich heute Obsolet, aber einige Anbieter denken immer noch, dass dieses Verfahren modern sei – auch wenn es seit fast 7 Jahren als unsicher eingestuft wird. Hallo Banken. Es kam wie es kommen musste: Ich sah mich genötigt ein Produkt über eine dieser Gesellschaften zu bezahlen und – nichts. Während die Webseite freudig vermeldete, dass ich eine passende TAN erhalten hätte machte mein Handy keinen Mucks. Toll, ich hab ein Zahlungsziel. Aber auch nichts ungewöhnliches – im Telefonica-Netz kommt es ja nicht unbedingt selten zu Störungen, also warten wir halt.

Einige Stunden später noch immer nichts, also müssen wir wohl selbst Hand anlegen. Erste Anlaufstelle: Test-SMS senden. Gar nicht so einfach, denn SMS-Funktion hab ich eigentlich auf keinem anderen Gerät mehr installiert. Glücklicherweise habe ich noch einen „echten“ Telefonanschluss ohne VoIP und konnte daher per Modem ein SMS-Gateway erreichen. Allerdings ohne Erfolg. Also machen wir mal ein altes Handy fit und versuchen es da – woho, SMS. Es muss also an meinem Endgerät liegen.

Per ADB zeigt sich nach einigem (teuren) Geteste folgender Fehler:

12-14 11:07:05.216  3179  5307 W MmsSmsDatabaseHelper: Upgrading database from version 64 to 67.
12-14 11:07:05.216  3179  5307 E SQLiteLog: (1) table sms_restricted already exists
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper: table sms_restricted already exists (code 1): , while compiling: CREATE VIEW sms_restricted AS SELECT * FROM sms WHERE type=1 OR type=2;
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper: android.database.sqlite.SQLiteException: table sms_restricted already exists (code 1): , while compiling: CREATE VIEW sms_restricted AS SELECT * FROM sms WHERE type=1 OR type=2;
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:500)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1677)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1608)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at com.android.providers.telephony.MmsSmsDatabaseHelper.upgradeDatabaseToVersion66(MmsSmsDatabaseHelper.java:1721)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at com.android.providers.telephony.MmsSmsDatabaseHelper.onUpgrade(MmsSmsDatabaseHelper.java:1466)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:256)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:187)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at com.android.providers.telephony.SmsProvider.query(SmsProvider.java:160)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.content.ContentProvider.query(ContentProvider.java:1020)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.content.ContentProvider$Transport.query(ContentProvider.java:239)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper:  at android.os.Binder.execTransact(Binder.java:565)
12-14 11:07:05.218  3179  5307 E MmsSmsDatabaseHelper: Destroying all old data.

Das kommt mir doch irgendwie bekannt vor… Schade, dass der Fehler nicht in der GUI erscheint und man so vermutet, dass alles ohne Störung funktionieren würde. Also löschen wir auch hier die kaputte Datenbank. Leider nicht ganz so einfach, denn zu dieser Meldung schweigen sich die Suchmaschinen aus und auch im Log wird der Dateiname der betroffenen Datenbank leider nicht erwähnt. Abhilfe schafft „Self Rubber Ducking“ , welcher augenscheinlich sehr von Migrationscode angetan ist. Fündig wurde ich dann im Ordner, welcher sich auch schon bei der Telefonie als Verursacher zeigte – hätte man drauf kommen können. Meh.

Also – leicht angepasst:

adb shell
su -
rm -rf /data/user_de/0/com.android.providers.telephony/databases/mmssms.*

Nach einem Reboot kann dann auch der Fintechler wieder mit mir kommunizieren. Ich wäre ja dafür langsam mal offene Standards für sowas zu schaffen – sowas wie U2F mit angezeigten Transaktionsdaten…

Amdroid/CM: com.android.phone force-close nach Update

Ja, schmutzig ist praktisch – zumindest wenn es um Updates geht. Obwohl die meisten Entwickler empfehlen möglichst bei jedem Update mit einem frischen System zu beginnen versuche ich meine Daten so lange wie möglich mitzuschleifen („Dirty Flash“) – leider gibt es noch immer unzählige Apps, welche keine brauchbare Backup-Funktion bieten und auch systembasierte Lösungen wie Titanium Backup sind leider nicht unfehlbar.

Zuletzt war ich etwas nachlässig – mein Handy war noch auf Version 2, aktuell Version 9 meiner aktuellen ROM. Zeit zum Aktalisieren, vor allem da Dirty Cow gerade bekannt wurde.

Also, Sideload drüber und – narf. „Telefon reagiert nicht mehr“. Gemeint ist hierbei die Telefon-App, also jene, welche Sprachtelefonie ermöglicht. Brauch ich zwar normal nicht, aber die Popups nerven doch etwas.

Über ADB ließ sich folgendes im Log erspähen:

12-06 16:43:32.820  3708  3708 E AndroidRuntime: FATAL EXCEPTION: main
12-06 16:43:32.820  3708  3708 E AndroidRuntime: Process: com.android.phone, PID: 3708
12-06 16:43:32.820  3708  3708 E AndroidRuntime: java.lang.IllegalArgumentException: column 'user_network_mode' does not exist
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:333)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:87)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at com.android.internal.telephony.SubscriptionController.getSubInfoRecord(SubscriptionController.java:293)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at com.android.internal.telephony.SubscriptionController.getSubInfoUsingSlotIdWithCheck(SubscriptionController.java:1631)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at com.android.internal.telephony.SubscriptionInfoUpdater.updateSubscriptionInfoByIccId(SubscriptionInfoUpdater.java:593)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at com.android.internal.telephony.SubscriptionInfoUpdater.handleSimLoaded(SubscriptionInfoUpdater.java:421)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at com.android.internal.telephony.SubscriptionInfoUpdater.handleMessage(SubscriptionInfoUpdater.java:338)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:102)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:154)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:6140)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
12-06 16:43:32.820  3708  3708 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)

Dankenswerterweise gibt es einen passenden Post von Daan, welcher die Ursache genau beschreibt und einen passenden Befehl zum zurücksetzen der defekten Datenbank anbietet. Hierbei gehen ggf. Einstellungen verloren, diese muss man ggf. später von seiner Datensicherung wieder einspielen.

adb shell
su -
rm -rf /data/user_de/0/com.android.providers.telephony/databases/telephony.*

Nach dem Befehl war dann Ruhe und sogar das telefonieren funktioniert wieder. Fein.

BitBastelei #222 – USB Power Monitor – Hardware-Überlegungen

BitBastelei #222 - USB Power Monitor - Hardware-Überlegungen

(151 MB) 00:18:22

2016-12-11 11:00 🛈

Den USB Charger-Doctor und seine Gefährten dürften die meisten von euch kennen. Die kleinen Geräte können Spannung und Strom eines USB-Anschlusses messen und anzeigen. Leider fehlen mir ein paar Funktionen wie z.B. ein PC-Anschluss um die Daten aufzeichnen zu können. Also: Bauen wir uns selbst einen.

Ergänzungen:

Einem aktuellen Video von Hugatry’s HackVlog nach sollte sich auch Qualcomm Quick Charge erkennen lassen (EN):
https://www.youtube.com/watch?v=UYRZ0t5eyjE

Etwa zeitgleich hat auch Great Scott Labs ein ähnliches Gerät gebaut. Er nutzt statt einer PC-Anbindung eine SD-Karte zum aufzeichnen (EN):
https://www.youtube.com/watch?v=lrugreN2K4w

BitBasics OLED: Unterschiede & Ansteuerung mit Arduino

BitBasics OLED: Unterschiede & Ansteuerung mit Arduino

(255 MB) 00:25:41

2016-12-04 11:00 🛈

OLEDs werden in letzter Zeit auch bei vielen Bastlern immer beliebter. Statt einer Pixelmatrix mit Flüssigkristallen und externer Beleuchtung sorgen hier organische Komponenten für selbstleuchtende Bildpunkte. Durch die Technologie erreichen sie einen hohen Kontrast und sind auch draußen gut lesbar. Wer sich nicht durch die geringe Lebensdauer abschrecken lässt wird meist bei einem der zahlreichen 0.96″-Modulen mit 124×64 Pixeln und SSD1306-Controller landen. Mit diesen muss man sich nicht mit den zahlreichen Pins des Displays abmühen, sondern erhält einen fertigen Datenanschluss wie z.B. I²C.
Für die Ansteuerung unter Arduino muss man sich dabei nicht erst in das Datenblatt des OLED-Controllers einlesen, sondern kann auf eine der zahlreichen Libraries zurückgreifen. Die vermutlich bekannteste ist U8G2, Nachfolger der beliebten U8GLib. Mit diesen lassen sich Texte und Grafiken mit nur wenig Zeilen ausgeben.

BitBastelei #221 – Transistor-Tester „T4“ mit Grafik-LCD

BitBastelei #221 - Transistor-Tester "T4" mit Grafik-LCD

(231 MB) 00:18:45

2016-11-27 11:00 🛈

Vor einiger Zeit hatte ich einen Transistor-Tester-Bausatz vorgestellt, welcher – wie der Name schon sagt – Transistoren prüft, deren Pinout ermittelt und auch Widerstände, Spulen und Kondensatoren messen kann. Inzwischen hat sich einiges getan und diverse neue Versionen sind auf dem Markt aufgetaucht. Das heutige T4-Modell nutzt statt des bisherigen 16×4-Zeichen-LCD (CLCD) ein grafisches Display (GLCD), welches gleich die passenden Schaltzeichen anzeigen kann. Für 6€ kann man nicht viel falsch machen und optisch schneller zu erfassende Anzeige klingt gut – werfen wir mal einen Blick darauf.

Wie auch schon der Vorgänger basiert das Modul auf der Arbeit von Markus Frejek, Karl-Heinz Kübbeler und den Helfern aus dem mikrocontroller.net-Forum.

Links zum Thema:

 

Windows/GPG/Smartcard – GPG mit Powershell bei SC-Verbindung neu starten

Beim Thema E-Mail-Verschlüsselung ist GPG weit verbreitet. Die Gundfunktionen sind z.B. mit Thunderbird und Enigmail oder gar eine Appliance auch für Einsteiger nutzbar und durch das WoT erstpart man sich die Abhängigkeit von – teils Zweifelhaften – zentralen Zertifizierungsstellen. Ich selbst nutze seit einiger Zeit keinen Softwareschlüssel sondern ein dediziertes HSM (Hardware Security Module) in Form eines YubiKey. Hiermit befindet sich der Key nicht mehr auf dem PC und auch die Verschlüsselung/Signierung läuft in Teilen auf dem Prozessor des YubiKey. Was unter Linux ohne große Änderungen funktioniert macht bei Windows eher wenig Spaß. Zwar ist auch GPG4Win in der Lage mit CryptoCards & Co umzugehen, häufiges Ein- und Ausstecken führt jedoch schnell zu einem hängenden GPG-Agent oder Absturzen der scdaemon.exe (GPG SmartCard Daemon). Einzige Abhilfe: Alle GPG-Prozesse beenden und neu starten. Da Verschlüsselung und Windows ohnehin eher selten zu finden ist sind auch Informationen dazu dünn gesät. Da ich teilweise um das System aus Redmond nicht herum komme und ein Fix in GPG4Win nicht in Sichtweite ist muss also wieder einmal der Holzhammer her: Irgendwie muss beim Einstecken des USB-Gerätes das GPG-System zurückgesetzt werden.

Also frisch ans Werk. Als Sprache soll mal wieder Powershell herhalten – direkt verfügbar, halbwegs systemnah, sollte passen. Über WMI kann man sich auch über ab- und angesteckte Geräte informieren lassen. Leider konnte ich keine Möglichkeit finden weitere Infos wie z.B. Hersteller oder Treiber gleich mit zu erhalten. Da sonst eher wenig Gerätefluktuation zu erwarten ist ziehe ich die „passt scho“-Karte und werde das GPG-System bei jedem neu auftauchenden Gerät einmal zurücksetzen.

#Requires -version 2.0
Register-WmiEvent -Class Win32_DeviceChangeEvent -SourceIdentifier deviceChange
write-host (get-date -format s) " Beginning script..."
do {
    $newEvent = Wait-Event -SourceIdentifier deviceChange
    $eventType = $newEvent.SourceEventArgs.NewEvent.EventType
    $eventTypeName = switch($eventType) {
        1 {"Configuration changed"}
        2 {"Device arrival"}
        3 {"Device removal"}
        4 {"docking"}
    }
    write-host (get-date -format s) " Event detected = " $eventTypeName

    $newEvent.SourceEventArgs.NewEvent | fl

    if ($eventType -eq 2) {
            write-host (get-date -format s) " Starting task in 3 seconds..."
            start-sleep -seconds 3
            taskkill /T /F /IM gpg-agent.exe
            taskkill /T /F /IM scdaemon.exe
            taskkill /T /F /IM kleopatra.exe

            start -FilePath 'C:\Program Files (x86)\GNU\GnuPG\gpg-agent.exe' -ArgumentList '--daemon' -WorkingDirectory 'C:\Program Files (x86)\GNU\GnuPG\' -LoadUserProfile -WindowStyle Minimized
    }
    Remove-Event -SourceIdentifier deviceChange
} while (1-eq1) #Loop until next event
Unregister-Event -SourceIdentifier deviceChange

Das Grundkonstrukt selbst scheint von Andy.L13 zu stammen, die kläglichen versuche von Mass-Storage auf andere USB-Geräte umzustellen stammen von mir. In Zeile 24 kann man für WindowStyle statt Minimized auch Hidden nutzen um das Ganze im Hintergrund laufen zu lassen – ich bevorzuge ein optisches Feedback. Das Script kann passend in Autostart oder als geplanter Task verstaut werden.

Sicher keine saubere Lösung, aber „works for me“.


Edit: Stackoverflow (bzw warriorpostman) liefert

Das folgende Script reagiert nur noch auf den vom YubiKey emulierten Smartcard-Reader. Das Objekt $Event.SourceEventArgs.NewEvent.TargetInstance sieht wie folgt aus – die Informationen für’s Query sollten sich im Gerätemanager finden lassen:

__GENUS                     : 2
__CLASS                     : Win32_PnPEntity
__SUPERCLASS                : CIM_LogicalDevice
__DYNASTY                   : CIM_ManagedSystemElement
__RELPATH                   : Win32_PnPEntity.DeviceID="USB\\VID_1050&PID_0116&MI_02\\6&***&0&0002"
__PROPERTY_COUNT            : 24
__DERIVATION                : {CIM_LogicalDevice, CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER                    : TESTRECHNER
__NAMESPACE                 : root\CIMV2
__PATH                      : \\TESTRECHNER\root\CIMV2:Win32_PnPEntity.DeviceID="USB\\VID_1050&PID_0116&MI_02\\6&***&0&0002"
Availability                : 
Caption                     : Microsoft Usbccid-Smartcard-Leser (WUDF)
ClassGuid                   : {50dd5230-ba8a-11d1-bf5d-0000f805f530}
CompatibleID                : {USB\Class_0b&SubClass_00&Prot_00, USB\Class_0b&SubClass_00, USB\Class_0b}
ConfigManagerErrorCode      : 0
ConfigManagerUserConfig     : False
CreationClassName           : Win32_PnPEntity
Description                 : Microsoft Usbccid-Smartcard-Leser (WUDF)
DeviceID                    : USB\VID_1050&PID_0116&MI_02\6&***&0&0002
ErrorCleared                : 
ErrorDescription            : 
HardwareID                  : {USB\VID_1050&PID_0116&REV_***&MI_02, USB\VID_1050&PID_0116&MI_02}
InstallDate                 : 
LastErrorCode               : 
Manufacturer                : Microsoft
Name                        : Microsoft Usbccid-Smartcard-Leser (WUDF)
PNPDeviceID                 : USB\VID_1050&PID_0116&MI_02\6&***&0&0002
PowerManagementCapabilities : 
PowerManagementSupported    : 
Service                     : WUDFRd
Status                      : OK
StatusInfo                  : 
SystemCreationClassName     : Win32_ComputerSystem
SystemName                  : TESTRECHNER
PSComputerName              : TESTRECHNER

Ich werde mich am Service WUDFRd (aka Gerät mit Windows SmartCard-Treber) orientieren. Prinzipiell könne man aber auch auf die USB-ID triggern uns so Scripte bauen, welche bei einstecken eines USB-Sticks ein Backup durchführen oder bei verbinden einer unbekannten USB-Tastatur entsprechend reagieren (böse Ente). Das zugehörige Script:

$query =  "Select * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_PnPEntity' AND TargetInstance.Service = 'WUDFRd'"

if( Get-EventSubscriber | Where-Object {$_.SourceIdentifier -eq "YubiHammer"}) {
    Unregister-Event YubiHammer
}

Register-WmiEvent -Query $query -SourceIdentifier YubiHammer -Action{
    $Global:RemoteProcMon=$event 

    start-sleep -seconds 3
    taskkill /T /F /IM gpg-agent.exe
    taskkill /T /F /IM scdaemon.exe
    taskkill /T /F /IM kleopatra.exe

    start -FilePath 'C:\Program Files (x86)\GNU\GnuPG\gpg-agent.exe' -ArgumentList '--daemon' -WorkingDirectory 'C:\Program Files (x86)\GNU\GnuPG\' -LoadUserProfile -WindowStyle Minimized
}

 

BitBastelei #220 – Pfaff 360 Automatic

BitBastelei #220 - Pfaff 360 Automatic

(105 MB) 00:17:01

2016-11-20 11:00 🛈

Wenn alte Technik auftaucht lohnt meist ein Blick – diesmal ist es eine Nähmaschine aus den Pfaff-Werken, welche Ende der 50er auf den Markt kam. Auch nach mehr als 50 Jahren sind noch keine groben Mängel feststellbar.

Die Anleitung de Gerätes ist auf der Webseite von Eddy auch online zu finden: http://www.occaphot-ch.com/n%C3%A4hmasch-manuals/bagat-luznik/.

Nerd Inside