Cyclic Banana Checks

Door Infant op woensdag 30 juli 2014 18:15 - Reacties (15)
CategorieŽn: Gepruts, Sparta: Fiets verbouwen tot het stuk gaat., Views: 7.035

Dit is een vervolg op:
Dooie Fiets
Banana?
Bananen Taal

Het gaat zeker helpen om die een beetje door te lezen, anders heb je geen flauw idee waar dit over gaat.
Mijn titel-verzin-o-matic kwam na afloop met deze zeer gepaste titel: Cyclic Banana Checks.
Dit gaat waarschijnlijk ook de meest on-duidelijk post tot nu toe worden, maar ja... het dient voornamelijk ter documentatie.

*Kuch pas op spel fouten kuch*

De vorige post hield op met de cliffhanger dat er wellicht nu een kookwekker van de ronde Batavus display gemaakt kan worden. Dat gaan we natuurlijk niet doen, om meerde redenen:

1: Ik hoef geen kookwekker.
2: Hij piept / vibreert niet, wat een must is voor een degelijke kookwekkert. (geen typo)

En als derde punt: Mijn PC is c.a. 50W aan vermogen aan het verstoken, om er data naartoe te slingeren. 50W zou je, mits hij het aan kan, toch nog 3 minuten lang uit een AA batterij kunnen halen.
(En als hetgene wat je aan het kook-wekkeren bent bijv. een zacht gekookt ei moet worden, kan die 50W voor ei-verwarming gebruikt worden.)

Dat is allemaal vrij aardig, maar zo gezegd sub-optimaal.
Hoe kan het optimaler?
Het probleem is nu, dat we wel berichtjes naar het display kunnen sturen, maar we moeten steeds de checksum aan het einde gokken. Omdat de communicatie ook nog eens moeilijk traag is, staat de PC daar eigenlijk 99% van de tijd op te wachten.

Om de volgende onorthodoxe en enigszins lompe manier van aanpak te volgen, is het handig dat je een soort van een idee hebt hoe een crc ongeveer werkt. In plaats van de Wiki, kan ik deze aanraden:
A Painless Gguide To CRC Error Detection

Op zich hoef je helemaal niet te weten hoe een crc precies werkt om ze te kunnen gebruiken. Er staan namelijk talloze voorbeelden online, die al in software verwerkt zitten.Pak bijv deze 8-bit CRC uit een of andere linux kernel module:
http://lxr.free-electrons.com/source/lib/crc8.c

Of deze bijv. bijv uit chromium:

De laatste gebruikt een tabel waarmee de CRC berekeningen gedaan worden, de eerste niet.
Met een tabel-loze functie, zou je zo'n tabel kunnen generen. Dat is wat reken intensiever. Maar daarna kun je de snelle tabel-functie kunt gebruiken, met als nadeel dat die wat meer geheugen gebruikt, en maar een vaste CRC variatie kan implementeren.

Een andere eigenschap van een CRC functie kan zijn dat je hem in een of meerdere stappen kan uitvoeren:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
//Any CRC8 function interface:
uint8_t crc8(uint8_t* data,uint8_t len, uint8_t crc);

//Data
uint8_t data[4] = {1,2,3,4};
uint8_t crc;

//In one go:
crc = crc8(&data[0],4,0x00);

//Same result, in two goes:
crc = crc8(&data[0],2,0x00);
crc = crc8(&data[2],2,crc);


Hierboven een stukje voorbeeld code:
Als eerste een definitie naar een willekeurige crc8 functie. Deze functie geeft als output een crc getal. Als input moet je hem een stuk data geven, en de lengte waarover de crc berekend moet worden.

Ik zou de functie in twee stappen kunnen aanroepen, of in een enkele keer. Als ik het in twee stappen doe, geeft ik de crc die de eerste stap oplevert mee als argument aan de tweede. In beide gevallen is het argument in de eerste stap 0x00, en het eindresultaat hetzelfde.

Je zou dit in zoveel stappen kunnen doen als je zelf wilt. In de code uit de eerste link is dat het makkelijkst te zien:

C:
1
2
3
while (nbytes-- > 0)
    crc = table[(crc ^ *pdata++) & 0xff]; 
return crc;



Als kan deze loop halverwege afbreken, en in een nieuwe verder gaan met dezelfde crc.

Stel dat we zo'n functie, waarvan we de details nog niet precies weten, op de volgende display data willen los laten:

10 C1 29 26 03 0c c0 00 c0 00 f0 13 37 68

Dit gaat overigens 1337 op het display zetten:
Pakketje!


Het probleem is dat ik niet weet waar de crc precies over berekend wordt. Het kan over alles zijn, het kan dat bijv de eerste waarde C1 een samenvoeging van 0xC0 en 0x01, en dat daar een CRC over gedaan wordt. Maar het wordt in ieder geval over de data gedaan, en die staat aan het einde.

Dus ik dacht: Als ik nou een tabel maak, waarin ik voor verschillende getallen aan het einde van de data, de correcte CRCs opsla, dan kan ik in ieder geval later op mijn gemak een crc functie gaan zoeken die diezelfde output produceert, zonder dat ik deze hele opstelling mee hoef te nemen.

Nou, zo gezegd, zo gedaan. Dat levert dus weer een klein programmatie op. Dat heeft iets van drie kwartier getallen naar het display geschoten, en leverde toen de volgende tabel op:

code:
1
2
3
Data from 01
5F CE 3E AF 9D 0C FC 6D 98 09 F9 68 5A CB 3B AA 
.....



De data aan het einde van het display commando was dus 0x01 0x00 en levert in dit geval CRC 0x5F op (Eerste waarde in de tabel.
0x01 0x01 leverde CRC 0xCE op, etc.

Maar er is een probleem: 0xFF komt 4 keer voor, en dat zou niet moeten. (Alles hoort in een crc tabel maar 1 keer voor te komen).

Dat zou een aantal dingen kunnen betekenen:
1: Dat er drie getallen zijn die nooit geaccepteerd worden door het display.
2: Ik heb iets fout heb gedaan.
3: Er wordt een brakke/rare crc gebruikt.

2 lijkt me het meest voor de hand liggende. Om het iets zekerder te weten, besloot ik om er ook maar bij te loggen of het antwoord terug ontvangen ook gelukt is ja of nee, en laat dat een nachtje draaien.

De volgende dag had ik een berg met prachtige tabbelen, behalve 1tje.

code:
1
2
3
4
5
Data from 10
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
....
Succes table:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00



Moment dat ik ergens in mijn fop-data een 0x10 stop, faalt het en is het bericht nooit goed.

Nou... dat zou op zich kunnen, en zou betekenen dat je het nooit kan zien als je exact 10 km/h fietst. Maar hij zou dan ook nooit kunnen weergeven dat je 10km hebt afgelegd.... niet erg waarschijnlijk.

Het bericht begint ook altijd met 0x10... dat is vast geen toeval. Grote kans dat er iets van escaping wordt toegepast.

Zucht, dat kan natuurlijk ook op 100 verschillende manieren, maar ik dacht, ik probeer het door achter elke 0x10 in de data gewoon nog een 0x10 te vrotten.

...en dat werkte in ťťn keer! Feest!
En nu?
Het volgende programmatje heb ik gewoon een hele berg crc functies in gepropt, en die gaat dan domweg wat eigenschappen naar de crc functie slingeren, en een tabbelletje bijhouden, net zolang tot die overeen komt met de hiervoor ge-log-te tabellen. (Ge-logde? het krijgt allebij geen rode streepies!)

Zo ziet het dat er uit.?!

De init waarde is het argument wat aan de crc functie mee gegeven word. Omdat de tabellen die ik zojuist gemaakt heb halverwege de data begonnen, weet ik niet wat de vorige crc waarde was, dus daar probeert deze gewoon alle combinaties van.

Een crc wil ook nog wel een een xor operatie aan het einde doen, en ten slotten kunnen de operaties in de functie in LSB of MSB volgorde met een verschillend aantal polynomen gedaan worden.

Dit programma probeert gewoon alles, en dat zou best wel eens even kunnen duren.

Bij de tweede crc functie die hij ging proberen, kwam er na een aantal minuten al het volgende te staan:
Pakketje!

253 matches! Dat betekent gewoon dat hij het heeft gevonden!

De persoon die dit protocol verzonnen heeft heeft er vast met opzet 0x42 als magisch polynoom in gestopt. Ik weet het zeker.

Nu de gebruikte crc functie bekend is, is de laatste stap uitvinden over wat de crc berekend wordt. Dat was ook een vrij kort stukje code.

Ik nam dan twee willekeurige berichtjes die gelogd waren. Als je nu de crc functie het correcte startgetal en startpositie mee geeft, en over het hele bericht inclusief de crc laat heen lopen, zouden beide het zelfde getal moeten op leveren. Dat is ook een handige eigenschap van een crc functie.

Dat was in no time gevonden: Het start getal is 0x07.

De uiteindelijk crc-code is een aanpassing op code die hier vandaan komt:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
    CRC-8 for Sparta ION bus communication.
*/
uint8_t crc8_bow( uint8_t *data_in, uint8_t len, uint8_t init){
    uint8_t crc;
    uint8_t i,j,f;    
    uint8_t data;
    crc = init;
    for (j = 0; j != len; j++){
        data = data_in[j];        
        for(i = 8; i; i--) {
            f = ((crc ^ data) & 0x01);
            if (f == 0x01){
                crc = crc ^ 0x42;
            }
            crc = (crc >> 1) & 0x7F;
            if (f == 0x01){
                crc = crc | 0x80;
            }
            data = data >> 1;
        }
    }    
    return crc;
}


En je dient hem als volgt aan te roepen:

C:
1
2
//Do a CRC check:
uint8_t crc = crc8_bow(data,len,0x07);


Het lollige is nu dat ik zo snel als het display het aan kan er berichtjes naar toe kan schieten.
(Hij haperde hier af en toe nog omdat ik 0x10 nog niet escapde.)
Youtube

Niet alleen dat, ik kan nu het verkeer fatsoenlijk in kaart gaan brengen. Van elk bericht kan ik verifiŽren of de CRC okee is, en nog belangrijker: Ik kan zelf berichten samen stellen, en kijken of daar een antwoord op komt.

Nou, hier kwam een bedroevend lage hoeveelheid elektronica en mechanisch geneuzel aan te pas, namelijk niks. Dat zal ik volgende keer goed maken.

Volgende: Alles moet draaien 09-'14 Alles moet draaien
Volgende: Bananen taal 06-'14 Bananen taal

Reacties


Door Tweakers user Damic, woensdag 30 juli 2014 18:29

JAwadde je fietst rap :p


Door Tweakers user TheMazzter, woensdag 30 juli 2014 19:34

Is het je ook al gelukt om op deze manier met de motor en de batterij te praten? Of heb je daar weer een andere crc functie voor nodig?

Door Tweakers user Infant, woensdag 30 juli 2014 19:41

TheMazzter schreef op woensdag 30 juli 2014 @ 19:34:
Is het je ook al gelukt om op deze manier met de motor en de batterij te praten? Of heb je daar weer een andere crc functie voor nodig?
Alle communicatie is hetzelfde gestructureerd. De communicatie tussen display-accu, en accu-motor gebruikt deze crc.

Door Tweakers user azerty, woensdag 30 juli 2014 20:21

Snelle fietser op dat filmpje bedoelt hij ;)

Door Tweakers user Infant, woensdag 30 juli 2014 20:31

Jaja, 0.1Mm/h

Door Tweakers user -RetroX-, woensdag 30 juli 2014 20:46

Bananas!

[Reactie gewijzigd op woensdag 30 juli 2014 20:46]


Door Tweakers user sjaak, donderdag 31 juli 2014 15:09

Het was even geleden maar weer een mooi stuk! Ik vind het vooral mooi hoe je, een voor mij, ingewikkeld stukje techniek toch redelijk makkelijk weet uit te leggen en te doorgronden.

Keep up the good work, ik kijk uit naar je volgende stukje. :)

Door Tweakers user Lamerikx, donderdag 31 juli 2014 21:32

Heerlijk om dit soort blogs te lezen! Sommige delen begrijp ik niet maar die probeer ik dan uit te zoeken.
Als ik het niet verkeerd heb, heb je zoiets ook met laptop accu's gedaan ofniet? Die blogs vond ik ook tof om te lezen. In iedergeval bedankt voor het leesvoer en ik hou je komende blogs ook in de gaten!

Door Tweakers user MartijnAbel, donderdag 31 juli 2014 23:35

Leest heerlijk weg, en ook tof om te zien dat je er zo in thuis bent!
Ik wacht met smart op de volgende banaan update :D

Door Tweakers user SeenD, vrijdag 1 augustus 2014 14:16

Goed geschreven. Ik ga je blog volgen. Ik hou wel van dit soort tweaks. :)

Btw spelfout is 1 woord. Niet twee. :P

Door Tweakers user Karmos, zondag 3 augustus 2014 13:11

Na 3 keer dit gelezen te hebben, schreeuwt er een stem in mijn hoofd: DAFUQ did i just read? 8)7

[Reactie gewijzigd op zondag 3 augustus 2014 13:11]


Door Tweakers user Infant, zondag 3 augustus 2014 13:41

Lamerikx schreef op donderdag 31 juli 2014 @ 21:32:
Als ik het niet verkeerd heb, heb je zoiets ook met laptop accu's gedaan ofniet? Die blogs vond ik ook tof om te lezen. In iedergeval bedankt voor het leesvoer en ik hou je komende blogs ook in de gaten!
Bedankt. Klopt, het voornaamste verschil dat de communicatie tussen accu en notebook iets van een gedocumenteerde standaard volgt. Deze fiets gebruikt een of ander on gedocumenteerd protocol, dus dat is wat meer trial and error.
Karmos schreef op zondag 03 augustus 2014 @ 13:11:
Na 3 keer dit gelezen te hebben, schreeuwt er een stem in mijn hoofd: DAFUQ did i just read? 8)7
Zal ik volgende keer nog meer waarschuwingen bovenin zetten? Met kleurtjes ofzo?

Door Tweakers user BenPi, maandag 11 augustus 2014 22:23

Geweldig leesvoer wat nieuwsgierig blijft naar meer!!!!!
Zou ik ook met je progjes zo,n display kunnen aansturen?, ik heb namelijk een sloper hier staan met motor, maar met een niet aangemeld display.
Schijnbaar wordt het display bij de motor of vv opgeslagen , maar niet in de accu.
De accu kan gewoon gewisseld worden.
Je krijgt dan de E0014 foutmelding.
Ik kijk dagelijks naar een vervolg.Maakt niet uit waarover het leest gewoon erg leuk.
GA DOOR.

Door Tweakers user Mike55, woensdag 1 oktober 2014 22:28

Leuk om te lezen wat je al ondekt cq gevonden hebt ..... als zendamateur /zelfbouwer heerlijk om te zien dat er nog mensen zijn die de dingen "des ebike" willen weten en speciaal de Sparta. Ben zelf ook een tijdje aan het zoeken geweest maar heb uiteindelijk toch de boel eruit gesloopt en heb voor 45 euro een china controller + "display"gekocht en deze op de Sparta gemonteerd . De banaan "gecleaned " en gebruikt deze nu als accubron. Samen met een pedaaltrap-sensor fiets ik nu heerlijk , met drie ondersteuning standen, door het dorp !! :)
Ik zal proberen om ook een topic met foto's teplaatsen ... maar wat mij betreft ga door met het posten ik vind het geweldig om te lezen
Michael

Reageren is niet meer mogelijk