Aiemmin selvittelin fyysisen rajapinnan toteutusta, sekä liikenteen kaappaamista. Seuraava askel on saada äänenvoimakkuustieto esille, jotta saan projektin alkuperäisen tavoitteen täytettyä. Mutta, homma lähti vähän lapasesta. Näistä lisää tulevissa julkaisuissa.
Datan dekoodaus
Kehysten alku mietitytti. Äänenvoimakkuuskehykset alkoivat aina samalla tavalla, 1F0 01F, mutta ensimmäinen sana vaihtui sen mukaan, ohjasinko äänenvoimakkuutta analogisäätimellä vai GLM-sovelluksella. Toinen sana pysyi koko ajan samana.
Päättelin, että ensimmäinen on osoite tai lähettäjän tunniste ja toinen äänenvoimakkuuskomento. Kolme seuraavaa sanaa muuttuivat asetusarvon mukana, joten niissä kulki itse äänenvoimakkuus. Lopussa oli vielä kaksi sanaa, jotka näyttivät tarkisteelta, ja viimeisenä päättymismerkki.
Tässä kohdassa tekoälystä oli hyötyä. Annoin sille joitain eri äänenvoimakkuusasetuksia ja väylältä luetut arvot, ja se löysi niiden välisen korrelaation. Pian laskentakaava putkahtikin ulos:
Tässä raw on 24-bittinen arvo, joka muodostuu kolmesta datasanasta. Esimerkiksi:
07F 0FF 0FF: 0,0 dB
000 000 008: −120,4 dB (tämä on hieman harhaanjohtava, sillä GLM-ohjelma näyttää tässä −100,0 dB)
Sanat, joita tarkisteeksi epäilin, olivat aluksi Claudelle täysi mysteeri. Kun annoin sille vihjeen, että kyseessä voisi olla CRC, korrelaatio löytyi taas. Kyseessä on CRC-16/GSM, jonka parametrit ovat:
Polynomial: 0x1021
Initial value: 0x0000
RefIn / RefOut: False (no bit-reversal of input bytes or final result)
XorOut: 0xFFFF (the raw CRC is inverted at the end)
CRC lasketaan osoitesanan alatavusta (esimerkiksi 0xF0) ja sen jälkeisestä datasta, eli päättävää 07E-merkkiä ei oteta mukaan. Claude kirjoitti myös esimerkkikoodin CRC:n laskemiseksi.
Äänenvoimakkuuden lukeminen onnistuu ilman CRC:täkin. Sen tarkistaminen on silti kannattavaa, sillä väylällä voi tulla bittivirheitä. Näytöllä väärä arvo vilahtaa vain hetken, mutta jos virheellinen arvo päätyisi vahvistimeen asti, korvat voisivat joutua koville 😉
Yksi kokonainen äänifreimi Katsotaan lopuksi yksi kehys sana kerrallaan. Äänenvoimakkuus on −45,0 dB, ja sitä säädetään GLM-sovelluksella:
1FF 01F 000 0B8 044 0F5 0FD 07E
Sana
Arvo
Merkitys
1
1FF
Osoite, broadcast
2
01F
Äänenvoimakkuuskomento
3–5
000 0B8 044
raw = 0x00B844 = 47172, josta 20 × log10(47172) − 138,4738 = −45,0 dB
6–7
0F5 0FD
CRC-16/GSM
8
07E
Kehyksen päättävä merkki
Sama äänenvoimakkuus, kun sitä säädetään kaukosäätimellä tai analogisäätimellä, näyttää tältä:
1F0 01F 000 0B8 044 090 004 07E
Eroja on kaksi. Osoite on 1F0, eli lähettäjänä on hubi, ja CRC on eri (090 004). Äänenvoimakkuuden arvo ei muutu. CRC vaihtuu, koska se lasketaan osoitteen alatavusta alkaen, joten eri osoite antaa eri CRC:n, vaikka muu sisältö olisi sama.
Nyt kaikki on selvillä näyttöprojektin toteuttamiseksi, joka on ensikerran aihe.
Päivitys 15.10.2026: Muutettu väylänopeus 296000 =) 287700. Myös kaappaus ohjelma päivitetty tämän myötä versiosta 2.1 versioon 2.2.
Edellisessä osassa kävin läpi, kuinka dekoodausprojekti lähti liikkeelle. Nyt on raudan vuoro, eli millä viestit saadaan luettua, ja ehkäpä joskus vielä dekoodattua.
GLM:n käyttämä väylänopeus on hyvin erikoinen, 287700 (mitattu, prosessorin kellotaajuus huomioiden todennäköisesti asetettu 288000). Lisäksi 9N2 on sekin harvinaisempi, eikä kaikki mikrokontrollerit osaa tätä, ainakaan natiivisti.
Myöskään Raspberry Pi Pico 2:n UART ei natiivisti tue yhdeksää databittiä, mutta tämä on mahdollista saada toimimaan PIO:n avulla. Käytännössä siis bitit luetaan väylältä ohjelmallisesti. Tämä syö jonkin verran suorituskykyä, mutta tähän mennessä teho ei ole loppunut kesken. Pientä hidastumista on ollut toisinaan havaittavissa, kun monenlaisia juttuja on tullut testattua. Tämäkin hidastelu poistui, kun siirsin pelkän vastaanoton pyörimään Picon toiselle ytimelle.
Tässä osassa käsitellään vain Pico 2:n rautaa, sen kytkentää RS-485-muuntimeen ja edelleen RJ-45-liittimeen. Varsinainen analyysiohjelmisto jää seuraavaan osaan. Pico2:n firmis löytyy tästä blogauksesta, eli pääset kaappaamaan dataa vaikka heti.
Rauta
Hyvä uutinen on, että rauta on yksinkertainen. Väylää ainoastaan kuunnellaan, joten lähetyssuuntaa ei tarvitse ohjata mitenkään. Tällöin ei ole vaaraa että vahingossa menisi sotkemaan oikean GLM-järjestelmän toimintaa.
Kokonaisuus koostuu kolmesta osasta. Ensimmäinen on RJ-45-liitin, josta tuodaan sisään differentiaalinen RS-485-signaali, joka kulkee navoilla 1 (D+/A) ja 2 (D−/B).
Kolmas on Pico 2, joka lukee muuntimen lähdön ja lähettää kehykset USB:llä tietokoneelle.
Kasaaminen
RJ-45:n pinni 1 menee 485-moduulin D+/A-liittimeen ja pinni 2 liittimeen D−/B. TTL-puolella VCC menee Picon 3,3 voltin ulostuloon ja GND Picon maahan. TXD-pinni, joka antaa vastaanotetun datan ulos, kytketään Picon GP1-nastaan. RXD-pinni, eli moduulin lähetystulon jätin kytkemättä, sillä TX valo syttyy ja väyläliikenne häiriintyy.
RS-485-puolen GND jää niin ikään kytkemättä, eikä RJ-45:n pinniä 8, eli väylän maata, ole kytketty mihinkään. Tämän kytkemisellä ei toisaalta ole haittavaikutuksiakaan.
485:n käyttöjännite on kytketty Picon 3,3V ulostuloon, sillä Picon GPIO nasta ei kestä 5V jännitettä. Moduulissa on automaattinen suunnanohjaus, joten erillisiä DE- ja RE-nastoja ei ole.
Johdotus: RXD ja RS-485-puolen GND jäävät kytkemättä.
Kytkeminen väylään
Väylässä on normaalisti 120 ohmin päätevastukset molemmissa päissä, molemmat sijaitsee GLM-adapterissa: kaapeli kulkee hubilta kaiuttimelle toiselle, ja viimeisen kaiuttimen kaapeli palaa takaisin hubiin. Omassa kytkennässäni Pico on kytketty linjan viimeiseksi laitteeksi, eikä linjaa ole johdettu takaisin hubille. Päätevastus on siis vain lähettävässä päässä, enkä ole lisännyt omaa vastusta kuuntelijan päähän. Moduulissa on valmiina 120 ohmin päätevastus, mutta se on oletuksena pois päältä ja kytkeytyy päälle vain, jos yhdistää juotoskohdan R16 umpeen. Minulla se ei ole käytössä. GLM:n sisäinen päätevastus lähettävässä päässä riittää, ja kaikki toimii ongelmitta myös kymmenen kaiuttimen järjestelmässä. Suuremmissa järjestelmissä päätevastus voi olla tarpeen.
Pico ei ole pakko kytkeä väylän viimeiseksi laitteeksi. Jos kuuntelija halutaan väylän keskelle, tarvitaan toinen RJ-45-liitin, jotta signaalit saadaan viedyiksi läpi seuraavalle laitteelle. Silloin molemmat liittimet kytketään rinnan samoihin napoihin.
Toimintatapa
Pico lukee siis vain yhtä nastaa, ja PIO tekee loput. Se näytteistää bitit 287700 baudin nopeudella, ottaa mukaan yhdeksännen databitin ja hyväksyy sanan vasta, kun molemmat stop-bitit ovat kohdallaan.
Työ on jaettu kahden ytimen kesken. Toinen ydin hoitaa vain vastaanoton: se tyhjentää PIO:n puskurin jatkuvasti, purkaa HDLC-escapet, kokoaa sanat kehyksiksi ja tallentaa ne aikaleiman ja järjestysnumeron kanssa rengaspuskuriin. Toinen ydin muotoilee kehykset tekstiriveiksi ja lähettää ne USB:llä tietokoneelle. Näin USB-liikenne ei hidasta vastaanottoa. Jos kehyksiä silti katoaa, firmware kertoo siitä # stat -riveillä, ja järjestysnumeroon tulee aukko. Status-rivi tulee 5 sekunnin välein, tai sekunnin välein, jos jokin laskuri on muuttunut.
Firmware
Pico 2:n capture-firmware on ladattavissa tästä. Paketissa on valmis UF2-tiedosto ja englanninkielinen README. Firmwaren asentaminen ei vaadi ohjelmointityökaluja: pidä Picon BOOTSEL-painiketta pohjassa, kun kytket USB-johdon tietokoneeseen, ja kopioi glm_capture.UF2 asemalle, joka ilmestyy näkyviin. Pico käynnistyy sen jälkeen itse.
Firmware toimii vain Pico 2:lla (RP2350), ei alkuperäisellä Pico 1:llä.
PuTTY
Kun rauta on kasassa ja firmware asennettu, Pico näkyy tietokoneella USB-sarjaporttina. Jokainen väylän kehys tulee siitä tekstirivinä, ja sen lukemiseen riittää PuTTY.
PuTTY:ssä valitaan yhteystyypiksi Serial ja kirjoitetaan sarjaportin nimeksi Picon COM-portti, jonka numeron näkee Windowsin Laitehallinnasta. Nopeudella ei ole oikeastaan merkitystä, koska data kulkee USB:n yli, mutta sen tulee olla väylän nopeutta suurempi, esimerkiksi 921600. Muut asetukset ovat 8 databittiä, 1 stop-bitti, ei pariteettia ja flow controlina None.
Ja jos ihmettelet miksi USB:ssä ei käytetä samaa 9N2 kuin GLM väylässä, niin Pico toimii välissä kääntäjänä. Merkit lähetetään USB:n kautta ASCII merkkeinä, eli tavallisena tekstinä, jotka ovat 8-bittisiä.
PuTTY:n asetukset. Flow controlin pitää olla NoneYhteystyypiksi Serial. Paina lopuksi Open.
Kannattaa myös nostaa scrollback suureksi, esimerkiksi 200000 riviin, ja laittaa lokitus päälle valinnalla All session output. Tiedostonimeen kannattaa lisätä päivämäärä ja kellonaika, esimerkiksi glm_&Y&M&D_&T.txt, jolloin jokaisesta tallennuksesta tulee oma tiedostonsa. Asetukset kannattaa lopuksi tallentaa omaksi sessiokseen.
Kun portti avautuu, ruudulle tulee ensin otsikkorivi, joka alkaa # glm-capture. Sen jälkeen tulevat kehykset, esimerkiksi tällaisina riveinä:
@12345678,89 101 009 05D 0E7 07E
Alussa on mikrosekuntiaikaleima ja kehyksen järjestysnumero. Perässä ovat kehyksen sanat kolmella heksanumerolla, ja 07E päättää kehyksen. Jos järjestysnumeroon tulee aukko, jokin kehys on kadonnut matkalla.
Väylän kehykset PuTTY:ssä. Vanhassa versiossa oli hieman eri väylänopeus käytössä.
GLM-ohjelman vaikutus näkyvään liikenteeseen Huomaa, että väylällä tapahtuu paljon vähemmän, jos GLM ei ole päällä. Ilman sitä näkyy ainoastaan hubin lähettämä äänenvoimakkuus. Kun tietokone ja Genelec GLM -sovellus ovat käynnissä, GLM kyselee kaiuttimilta tietoja ja kaiuttimet vastaavat, ja kaikki tämä näkyy väylällä.
Jos PuTTY:ssä näkyy vain harvakseltaan samoja rivejä, tarkista siis ensin, että GLM on käynnissä.
Käsin analysointi oli hidasta
PuTTY toimii hyvin, kun halutaan nähdä, että dataa tulee, ja tallentaa se tiedostoon. Varsinaiseen tutkimiseen se on silti kankea. Rivejä tulee tasaisena virtana, samat kyselyt ja vastaukset toistuvat kierros toisensa jälkeen, ja kiinnostavat kohdat hukkuvat niiden sekaan. Käsin analysointi oli hidasta, minkä myötä alkuperäinen projekti pelkän äänenvoimakkuuden näyttämisestä muuttui kokonaisvaltaisen kaappaussovelluksen ja tietorakenteiden salojen selvittämiseen. Mutta näistä lisää tulevissa kirjoituksissa. Seuraavalla kerralla aiheena äänenvoimakkuusarvon purkaminen.
Genelecin kaiuttimet ovat laadukkaita, mutta niissä on yksi merkittävä puute: äänenvoimakkuusnäyttö puuttuu. Vaikka äänenvoimakkuuden arvon näkeminen itsessään ei ole kovin tarpeellista, on ainakin yksi tilanne, jossa siitä on hyötyä: kun käynnistät systeemin etkä muista, onko äänenvoimakkuus hiljaisella, kohtuullisella vai korvat räjäyttävällä tasolla.
Tämä toteutus on ollut mielessäni jo vuosia. Osia on tullut hankittua ja kokeiluja tehtyä viimeisten noin neljän vuoden aikana. Projekti, kuten kaikki muukin, pysähtyi erittäin syvän masennuksen ja työuupumuksen vuoksi lähes 1,5 vuoden ajaksi. En vieläkään ole kunnossa, mutta toistaiseksi on päästy pois syvimmästä montusta.
Asiat saa ratkaistua kynällä ja paperilla tai Excelillä, mutta isojen datamassojen käsitteleminen on huomattavasti helpompaa tekoälyn avulla. Tekoäly onkin kehittynyt näiden vuosien aikana huimasti. Asiat eivät tekoälyn avustuksella ratkea itsestään, vaan sitä täytyy avustaa aika paljon – ihan kuten työkavereitakin, kun töissä yritetään ratkaista jotain ongelmaa.
Väylän selvittäminen
Ensin oli tutkittava, minkälaista dataa väylässä kulkee. Väylässä on tuttu RJ-45-liitin, mutta kyse ei ole Ethernetistä. Väylässä on myös 120 ohmin terminointi (molemmat päätevastukset sijaitsevat GLM Adapterissa).
Pinneissä 1 ja 2 kulkee differentiaalinen signaali. Skoopilla tarkasteltuna jännite oli noin ±2,5 V. Sarjaportin asetuksista ei ollut mitään hajua, joten niitä piti kokeilla käsin. Samalla piti yrittää päätellä bittinopeutta skoopin näkymästä. Myöskään A- ja B-signaalien napaisuudesta ei ollut hajuakaan.
Skoopistani (Rigol MSO5074) löytyy sarjaporttidekooderi, joka näyttää, jos viesti ei ole kunnollinen. Alla olevassa kuvassa näkyy tilanne, jossa johtojen napaisuus, väylänopeus ja sarjaväylän asetukset ovat pielessä. Jotain dataa se sai purettua, mutta virheellisesti.
Kun kaikki asetukset ovat kunnossa, viestit alkavat aueta ilman virheitä. Oikeat asetukset olivat lopulta varsin erikoinen ja epästandardi kokoonpano: 287700 / 9N2.
Tämän jälkeen olikin ratkottava, mitä tämä kaikki tarkoittaa. Yllä olevassa kuvassa näkyy globaali äänenvoimakkuusasetus, mutta väylällä kulkee paljon muutakin tietoa – siitä lisää myöhemmin.
Tämä oli pieni askel eteenpäin, seuraavaksi vastaanotetun datan purkamiseen. Siitä lisää ensi kerralla.
Tässä blogauksessa käsittelen perustarkkuuksisen IEEE 754 luvun muuttamista liukuluvuksi (reaaliluvuksi). Asian käsittely juontaa juurensa eräästä modbus-väylään liitettävästä laitteesta, jonka antamat tulokset normaaleilla muunnosoperaatiolla antoi käsittämättömiä tuloksia.
Väylältä saatu arvo piti saada muutetuksi reaaliluvuksi. Väylälaitteelta saatu arvo oli esimerkiksi 402851D8h. Kun tälle luvulle teki DWORD_TO_REAL muunnoksen, sai tulokseksi 1.076384 * 10^9, vaikka oikea arvo olisi ollut 2.6299953. Jokin siis mätti ja pahasti.
Selvisi, että ABB AC500 logiikat / CoDeSys ohjelmointikieli ei tue liukulukumuunnosta natiivisti. Muunnosta ei siis voinut tehdä DWORD_TO_REAL toimintoa käyttäen. Samalla selvisi, ettei sopivaa muunnospalikkaa ole ainakaan yleisesti saatavilla, joten sellainen oli tehtävä itse. Mutta ennen muunnospalikan ohjelmoimista, oli tiedettävä miten IEEE 754 luku ylipäätään muodostuu.
IEEE 754 on liukulukustandardi, joka on yleisin tietokoneissa käytettävä liukulukustandardi. Satandardi määrittää neljä erilaista liukulukua, erot liittyvät näyttötarkkuuteen ja lukualueen suuruuteen.
Nimi
Eng. nimi
Etumerkki
Exponentti
Desimaaliosa
Bias
Puolitarkkuus
Half precision
1 [15]
5 [14-10]
10 [9-0]
15
Perustarkkuus
Single precision
1 [31]
8 [30-23]
23 [22-0]
127
Kaksoistarkkuus
Double precision
1 [63]
11 [62-52]
52 [51-0]
1023
Quadruple precision
1 [127]
15 [126-112]
112 [111-0]
16383
Mittalaitteen antama tieto on kahden sanan pituinen, eli DWORD (32bit). Toisinsanoen mittatieto on perustakkuuksinen liukuluku. Tämä tarkoittaa, että 31. bitti kertoo luvun etumerkin, seuraavat 8 bittiä (bitit 30-23) kertovat exponentin ja loput 23 bittiä (bitit 22-0) desimaaliosan. Muut tarkkuusluokat lasketaan saman periaatteen mukaisesti, mutta niissä on vain enemmän/vähemmän bittejä ja tarkkuuluokkakohtainen bias. Allaolevaa ohjetta voi siis käyttää nämä seikat huomioonottaen myös muissa tarkkuusluokissa.
Muunnos tapahtuu seuraavasti:
Muunnetaan DWORD, eli tuplasana, binäärimuotoon: 4028 51D8 h => 01000000 00101000 01010001 11011000 b
Ryhmitellään edellinen bittijono kolmeen ryhmään, edelläkuvatun mukaisesti: 01000000001010000101000111011000
Luvun etumerkki määräytyy bitin 31 mukaan: 0 = positiivinen, 1 = negatiivinen. Koska bitti on tällä kertaa 0, on luku positiivinen.
Seuraavasta ryhmästä lasketaan exponentti, joka on suora b => dec muunnos. Exponentti on siis 10000000 b => 128.
Koska luku on perustarkkuuksinen, on exponentin bias 127. Täten lopulliseksi exponentiksi muodostuu 128 – 127 = 1.
Seuraava vaihe, eli desimaaliosan laskenta on kaikkein työläin prosessi koko muunnoksessa. Luku muodostuu 2-kantalukuisen negatiivisien potenssien summasta, potenssi määräytyy bitin paikan mukaan (eniten merkitsevä bitti vasemmalla, vähiten merkitsevä oikealla). 01010000101000111011000 b => 0*2^-1 + 1*2^-2 + 0*2^-3 + 1*2^-4 + 0*2^-5 + 0*2^-6 … => 1/4 + 1/16 + 1/1024 … = 0.314997673034668
Lopullinen tulos lasketaan kaavalla (-1)^etumerkkibitti * (1 + desimaaliosa) * 2^(exponentti – bias) => (-1)^0 *(1 + 0.314997673034668) * 2^(128 – 127) = 2.62999534607
Contains information related to marketing campaigns of the user. These are shared with Google AdWords / Google Ads when the Google Ads and Google Analytics accounts are linked together.
90 days
__utma
ID used to identify users and sessions
2 years after last activity
__utmt
Used to monitor number of Google Analytics server requests
10 minutes
__utmb
Used to distinguish new sessions and visits. This cookie is set when the GA.js javascript library is loaded and there is no existing __utmb cookie. The cookie is updated every time data is sent to the Google Analytics server.
30 minutes after last activity
__utmc
Used only with old Urchin versions of Google Analytics and not with GA.js. Was used to distinguish between new sessions and visits at the end of a session.
End of session (browser)
__utmz
Contains information about the traffic source or campaign that directed user to the website. The cookie is set when the GA.js javascript is loaded and updated when data is sent to the Google Anaytics server
6 months after last activity
__utmv
Contains custom information set by the web developer via the _setCustomVar method in Google Analytics. This cookie is updated every time new data is sent to the Google Analytics server.
2 years after last activity
__utmx
Used to determine whether a user is included in an A / B or Multivariate test.
18 months
_ga
ID used to identify users
2 years
_gali
Used by Google Analytics to determine which links on a page are being clicked
30 seconds
_ga_
ID used to identify users
2 years
_gid
ID used to identify users for 24 hours after last activity
24 hours
_gat
Used to monitor number of Google Analytics server requests when using Google Tag Manager
1 minute
Marketing cookies are used to follow visitors to websites. The intention is to show ads that are relevant and engaging to the individual user.
A video-sharing platform for users to upload, view, and share videos across various genres and topics.
Registers a unique ID on mobile devices to enable tracking based on geographical GPS location.
1 day
VISITOR_INFO1_LIVE
Tries to estimate the users' bandwidth on pages with integrated YouTube videos. Also used for marketing
179 days
PREF
This cookie stores your preferences and other information, in particular preferred language, how many search results you wish to be shown on your page, and whether or not you wish to have Google’s SafeSearch filter turned on.
10 years from set/ update
YSC
Registers a unique ID to keep statistics of what videos from YouTube the user has seen.
Session
DEVICE_INFO
Used to detect if the visitor has accepted the marketing category in the cookie banner. This cookie is necessary for GDPR-compliance of the website.
179 days
LOGIN_INFO
This cookie is used to play YouTube videos embedded on the website.