Aihearkisto: Ohjelmointi

Genelec GLM väylän datan dekoodaus – osa 3

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:

dB=20×log10(raw)−138.4738

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

SanaArvoMerkitys
11FFOsoite, broadcast
201FÄänenvoimakkuuskomento
3–5000 0B8 044raw = 0x00B844 = 47172, josta 20 × log10(47172) − 138,4738 = −45,0 dB
6–70F5 0FDCRC-16/GSM
807EKehyksen 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.

Genelec GLM -väylän datan dekoodaus – osa 2 

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

Toinen osa on TTL-RS-485-muunnin, jossa on MAX3485-piiri. Se muuttaa väylän differentiaalisen signaalin 3,3 voltin logiikkatasoksi.

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

Liitteet

Pico 2 – GLM Capture 2.2 firmware

Genelec GLM -väylän datan dekoodaus – osa 1

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.

Perustarkkuuksisen IEEE 754 standardin mukaisen luvun muuttaminen liukuluvuksi

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.

NimiEng. nimiEtumerkkiExponenttiDesimaaliosaBias
PuolitarkkuusHalf precision1 [15]5 [14-10]10 [9-0]15
PerustarkkuusSingle precision1 [31]8 [30-23]23 [22-0]127
KaksoistarkkuusDouble precision1 [63]11 [62-52]52 [51-0]1023
Quadruple precision1 [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:

  1. Muunnetaan DWORD, eli tuplasana, binäärimuotoon: 4028 51D8 h => 01000000 00101000 01010001 11011000 b
  2. Ryhmitellään edellinen bittijono kolmeen ryhmään, edelläkuvatun mukaisesti: 0 10000000 01010000101000111011000
  3. Luvun etumerkki määräytyy bitin 31 mukaan: 0 = positiivinen, 1 = negatiivinen. Koska bitti on tällä kertaa 0, on luku positiivinen.
  4. Seuraavasta ryhmästä lasketaan exponentti, joka on suora b => dec muunnos. Exponentti on siis 10000000 b => 128.
  5. Koska luku on perustarkkuuksinen, on exponentin bias 127. Täten lopulliseksi exponentiksi muodostuu 128 – 127 = 1.
  6. 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
  7. Lopullinen tulos lasketaan kaavalla (-1)^etumerkkibitti * (1 + desimaaliosa) * 2^(exponentti – bias) => (-1)^0 *(1 + 0.314997673034668) * 2^(128 – 127) = 2.62999534607
  8. Tulos on siis noin 2.63