tiistai 23. syyskuuta 2014

Fakin' it (quick note)

( Previous part here )

As per original intent of this blog I'm just quickly adding this idea here.

Okay then. In earlier parts I mentioned changing duty cycle and problems it will cause. Now, if we take short enough buffer of pulses - let's say 3-7 full pulses - the figures become meaningful again. During normal driving the change of speed (ie. pulse duration/duty cycle) should not be that quick and the pulses should be fairly similar, so spurious (artificial) pulse should be fairly obvious.

Mind you, first spurious pulse should not be enough to raise a red flag - that could be caused by sudden braking or quick acceleration (or losing grip momentarily, like in winter). Variation in pulses when speed is relatively constant, now that might be an issue.

One red flag is too constant pulse though - if the speed remains same for entire drive, there absolutely is something wrong. Picking up customers, turns, traffic lights, stopping at destination - all that causes variation. And by entire drive I mean entire drive, not just long parts of it - driver may just be using cruise on empty main road.

And then there just could be speed indication on meter's display, along with the fare reading.

torstai 18. syyskuuta 2014

JKartta on täällä! (in finnish)

This is - I think - mostly of interest to Finnish people so this time I'm writing in Finnish. In short, I feel that I can now release the map app I've been working on. Since the material covered is Finland and the app itself is in Finnish I expect that it isn't that interesting for people elsewhere -- unless I get around to implementing OpenStreetMap support some day.

Ja sitten itse asia suomeksi.


Ainakin minulle Jolla-puhelimessa suurimpia ongelmia on ollut kunnon maastokarttaohjelman puute. Käsittääkseni ainakin toisen näistä toisilla alustoilla olevista saisi toimimaan kikkailulla kolmannen osapuolen kauppojen kanssa, mutta siihen ei huvittanut lähteä joten päätin sitten noin oman huvin ja hyödyn vuoksi (jos ei muuta niin tulipa opeteltua Qt:n ja QML:n käyttöä) askarrella Jollalle natiiviapplikaation.

Alun perin lähtökohtana oli Maanmittauslaitoksen avoin aineisto, mutta kun harrastuksiin kuuluu mm. metsästys ja metsänhoito, avoimeen aineistoon liittyi iso paha puute - rajatiedot. Niitä ei ole saatavissa avoimessa aineistossa vaan ne täytyy lisensoida mikä tietysti kustantaa jonkin verran.

Näinpä päätin sitten tehdä ohjelmasta saman tien laajempaan jakeluun soveltuvan, missä tietysti pienenä hankaluutena on jakelu - Jollan app store ei toistaiseksi ainakaan tue maksullisia ohjelmia. Joten vaihtoehdoksi ei oikein jää kuin hoitaa tuo puoli itse toistaiseksi, ja miettiä asiaa uudestaan sitten kun tilanne virallisen kaupan osalta muuttuu.

Nyt ohjelma (mielikuvituksellisesti nimettynä JKartta) on sitten siinä kunnossa että uskallan tuota tarjota rajallisesti koekäyttöön, oman palvelimen kautta toimitettuna ja pykälää verran tavallista app storea vaikeammin laskutettuna (käytännössä pankkisiirrolla).

Sitten esimerkkikuvaa ohjelmasta. Tässä on käytössä ohjelman oletusasetuksena oleva 1:20000 mittakaava, jolloin puhelimen ruudulle mahtuu noin 1050x1900 metriä karttaa. Alareunan tummennetulle alueelle tulevat viestit (ja jos mitään näytettävää ei siellä ole, ei ole tummennustakaan), ja tässä punainen pallo kertoo myös että GPS:llä saatu sijainti on ruudun ulkopuolella; palloa koskettamalla kartta keskitetään nykyiseen sijaintiin.
Harmaa "merkki" keskellä ruutua on talletettu huomiopiste. Huomiopisteet voi (tällä hetkellä) lisätä vain käsin, joko ruudulla näkyvään kohtaan tai koordinaattien perusteella jonnekin toisaalle. GPX-importti ei olisi iso työ (nykyinen toteutus osaa jo kuljetun matkan mittauksen ja reitin näytön; se osaisi periaattessa näyttää jo talletetut reititkin mutta reittien talletus/lataus vielä puuttuu) mutta nämä joutuvat vielä vähän odottamaan.




Alla on käytössä mittakaava 1:10000, ruudulla näkyy tällöin n. 530x950 metriä (tarkat lukemat pitäisi tarkistaa ja laskea taulukoista, nämä mitat ovat kuitenkin "tarpeeksi lähellä"). Olen omalta osaltani todennut että tuo 1:20k mittakaava on yleensä maastossa käyttökelpoisin.


Ohjelman hinta koostuu suoraan ladatuista karttaruuduista - ruudulle mahtuu hiukan tilanteesta riippuen enimmillään 15 kappaletta (joista osa ei tietenkään näy kokonaan). Ensimäisen kerran käynnistettäessä ohjelma lataa vain näytön keskimäisen ruudun automaatisesti mutta tämän asetuksen voi halutessaan muuttaa, joko 1x1, 3x3 tai kaikki näytöllä vähänkään olevat ruudut. Ladatut ruudut tietysti säilyvät puhelimen muistissa jotta niitä ei tarvitse ladata enää uudestaan.

Ja vielä esimerkki tapauksesta jossa vain kolme karttaruutua on ladattuna. Näinkin ohjelmaa voi käyttää mutta rajallinen kartan näkyvyys tekee navigoinnin (maamerkkien vertaamisen) vaikeammaksi. Tästä näkee myös hyvin yhden karttaruudun koon; nämäkin siis 1:20000 mittakaavalla jossa yhden karttaruudun alue on n. 250x250 metriä.

Tällä hetkellä hinnaksi asettuu 20€ (sis ALV 24%) per 200 karttaruutua. Vaikka ohjelmaan luultavasti tulee lisäominaisuuksia jatkossa (kompassi, GPX-import yms yms), jo ostetut ruudut eivät katoa.
Käyttäjätunnuksia (sekä tietysti itse ohjelmaa) ja lisätietoja voi kysyä esim. sähköpostilla; toni piste rasanen at trippi piste fi .


Rant: Appliance UI

At the moment a certain large European brand is running an advert that (to paraphrase) says that whenever there is a problem, they'll think up a solution. This time the solution appears to be clay. In a dishwasher. Why exactly would anyone knowingly add clay to their clothes, or to their dishes is beyond me, but then again, they don't say it's clay, they use the "nicer" name. But I digress, I have something else in mind (granted, distantly related.)

We have washing machine/dryer combination made by this same company I referred above. Remember the slogan, (again paraphrasing) "problem? we'll think of the solution". Well, it certainly seems that exactly none of their engineers responsible of this trainwreck of an user interface have any children.

As evidence I present you the interface of the washing machine (with manufacturer and models photoshopped out)


Pretty nice in general. Select general program with the wheel. Do necessary adjustment with following buttons, then start with that nice large button at right. Full of nice, bright controls that you can twist or push. Even when the program is running. And twisting that very easily accessible wheel, even a bit, will permanently cancel current washing program.

The thing about children - especially toddlers - is that they are very very curious. Nice bright lights? That will draw their attention. And if that wheel is touched, well, goodbye program, the only option is to start all over again. Even if program was two thirds - or seven eights - or or ... -- of the way through. Just because someone came and touched the damn wheel. Absolutely no way to resume or even know how far the program was.

This is not good UI design. This is very very bad UI design. Insanely bad design. Shame on you, company-that-I-refuse-to-name-here.

Now, compare it to our Rosenlew dishwasher (no photo of that, sorry). If a program is running, you have to press and hold two buttons down for about five seconds to cancel it. And cancelled I have, many many times when the said toddler has managed to start washing cycle on that dishwasher. But so far he never ever has managed to stop ongoing program. I have had to turn the washer on a few times (even then it resumes from previous state - exactly as one would expect!) but either way, much much better than the stupid washing machine.



tiistai 9. syyskuuta 2014

Dead.


It was bound to happen some day. I had some documents with me on an USB stick and when I come bad home it doesn't work anymore. Not even a blib. Completely dead.

Damn. That was my favorite USB stick, size and shape were close to perfect; not too small to get lost, not too bulky to cause problems when using or carrying it. Oh well. Time to go shopping again.


Fortunately there wasn't anything that critical on it so loss isn't that big deal. I didn't really have any expectations about recovering it but I cracked it open anyway, primarily to see what's inside.

As it turns out, not much. Other size of the PCB is fully taken by single 64Gbit  (8 GByte) flash chip, other side has controller (SM321QF - based on quick googling not very trustworhy chip), crystal and some passives. Measurement only confirmed what I expected, that is, it's dead, for good.

The other stick above it is one that I have used in car player, here only for reference. It's perfect there - small form factor, doesn't stick out from radio's front panel and doesn't draw wrong kind of attention (although who in his right mind would bother to steal El Cheapo-brand car player anyway...).
What I'm more amazed is how they have managed to fit same 8Gbytes of memory on such a small space, comparing to one below. I kinda suspect the size is "bought" with high cost of long-time reliability, so even more reason not to use it for anything critical. We'll see when it dies...

Oh, and when I said there wasn't anything critical on dead stick I lied a bit. There wasn't anything critical in sense of "data I can't afford to lose". There was some stuff in sense of "documents I don't want to get to wrong hands".


I'm pretty sure that now it's unrecoverable enough.

maanantai 1. syyskuuta 2014

Fakin' it (part 3)


Previous parts here and here.

Previously I've thrown in some ideas considering speed signal tampering that some less than honest drivers may be employing. This series is primarily focused on what kind of signals to expect and low-cost tampering detection on cheap(ish) MCU. So now it's time for some actual code to do the magic (or the difficult part of it, at least).

Let's start with constraints. Cars typically generate between 1000 and 28000 pulses per kilometer (mostly depending on manufacturer), or 1 to 28 pulses per meter. Lower bound that interests us is, say, 20km/h, and upper for example at 200km/h. So valid frequency range is from 5.5 Hz to 1.5 kHz (roughly).

To make any judgement on pulse length the timer resolution will need to be at least one decade, preferably two above these, so we'll want our timer that does the measurement to run at approximately 150kHz. This pretty much rules out interrupts, there is no way you could get acceptable performance from any (microcontroller) software at that rate.

Fortunately most MCUs expose the underlying accumulator counter that is used to set timer interrupt periods, so we can use that to our advantage. For quick test I used a PIC24-based board I happened to have handily available. The processor (specific model not that important) has main oscillator at 8 MHz and has 5 timers, of which only one was used. So I chose to implement this measurement system using Timer 2 of the MCU.

PIC24's timers come with prescaler that is used to scale down the main oscillator frequency. In this case 1:64 prescaler gives us 125kHz resolution which is close enough to previously calculated 150kHz so we can work with it. Since the counter is 16-bit, this gives us minimum frequency of 1.9 Hz so lower bound is no problem either - anything slower is too slow to be indication of tampering (in this application at least).

So, variables and initialization of timer and the ISR (I'm using MPLAB X as IDE and Microchip's C compilers here);

// Calculate new value if these are set
volatile unsigned int tmrAccStop, tmrAccCnt; 
// Accumulator in interrupt 
volatile unsigned int tmrAccCntInt; 

void timer2Init()
{
  T2CON = 0; // stop timer, reset control reg
  TMR2 = 0; // clear timer acc register
  PR2 = 65535; // period; set to maximum 16-bit value
  IPC1bits.T2IP = 1; // interrupt priority
  IFS0bits.T2IF = 0; // clear interrupt status flag
  IEC0bits.T2IE = 1; // enable timer1 int

   // TON=1 - start timer
   // TCKPS=2 (1:64) - prescaler
  T2CON = (1<<15) | (2<<4);
}

void __attribute__((interrupt, auto_psv, shadow)) _T2Interrupt(void)
{
  ++tmrAccCntInt;
  IFS0bits.T2IF = 0;
}

Since we are mostly interested of first period, if the tmrAccCntInt variable is set it can simply be used as indication that pulse period was longer than our lower bound and further processing is not needed.

Then the IO Change Notification interrupt (I'm not including IO setup since there's nothing special there);

void __attribute__((interrupt, auto_psv, shadow)) _CNInterrupt(void)
{
  // Change notification is signalled on both rising and lowering edge. 
  // Here we want just rising edge, so checking for it.
  // By triggering on both rising and lowering edge you could easily add 
  // duty cycle measurement too.
  if (PORTE & 2) // Pin E1
    { tmrAccStop = TMR2;
      TMR2 = 0;
       // Counter; if non-zero, timer has overflowed  
       // so rate is lower than 1,9Hz (approx)
      tmrAccCnt = tmrAccCntInt;           
      tmrAccCntInt = 0;  // Clear internal counter
    }
 
  IFS1bits.CNIF = 0; // clear Input Change Notification
}

Since we are not sharing Timer2 with other functions we can simply clear its accumulator in interrupt. This makes the following math a bit easier since we don't have to deal with partial periods or timer overflows.

Note that I didn't put any math in interrupt. In this example involved math is very light, but nevertheless, in general rule you should never do any complex math in interrupts if you can avoid it; store results to suitable temporaries and do the math in main() to make time spent in interrupts lower.

Then the main loop (again, I'm excluding setup since with exception of parts listed above it's pretty trivial);

  while (1)
    {
      unsigned int n, end;

      __asm__ volatile("disi #0x3FFF"); // Disable interrupts

      if (tmrAccStop != 0xffff) // if not ffff, we have new reading ready.
        {
          n = tmrAccCnt;
          end = tmrAccStop;

          tmrAccStop = 0xffff; // clear reading for next
        }
      else
        {
          end = 0xffff; // no new reading; don't do anything.
        }

      __asm__ volatile("disi #0x0"); // Enable interrupts.

       // It would be possible to do entire analysis with interrupts disabled
       // but I prefer to make critical sections as short as possible for same
       // reason I don't do math in interrupts.

      if (end != 0xffff)
        {        
          if ( (n > 0) || (end > 65000) )
            { // Timer interrupt triggered or period long enough; can be ignored
              debugWrite("no event\r");
            }
          else
            {  
              debugWriteInt("period=", end);
            }
        }
    }

DebugWrite functions are simple utility functions that write given string and data to serial output. Nothing fancy in there.

Yes, since stop isn't initialized this will trigger spurious first reading. Yes, this will also miss readings if  main doesn't run fast enough. And the end result isn't exactly useful alone. And I'm not sure if this even compiles as this is a copy-pate from several thousands of lines long project I am using to quickly test these ideas. But this shows you how to measure shorter signal periods that typical interrupts allow, and further refinement of results aren't exactly rocket science either.

Happy hunting :)