Open82541 UA_Variant to String

Ich habe in letzter Zeit einige Projekte mit OPC UA und der freien Biblothek open62541 von open62541.org abgewickelt. Die Bibliothek wird aktiv betreut und kann mit ihren kommerziellen Konkurenten sehr gut mithalten, auch in produktiven Umgebungen.

Direktes Lesen und Konvertieren von Variablen in die C/C++ Equivalente ist sehr einfach möglich, nur Strings wollten nicht. Hintergrund ist, dass der Daten Pointer des variablen Datentype UA_Variant nicht Nullterminiert ist. Man muss deswegen ein neues String Objekt erzeugen und den Datenpointer inkl. Länger übergeben. Dann funktioniert es auch!

Für alle Open62541 User hier ein kurzes Beispiel, ohne das der eigentliche Datentyp explizit geprüft wird, damit das Beispiel kurz und verständlich bleibt.

#include <string>
#include "open62541.h"

std::string get_variable(UA_Client *client, int namespace_index, char *variable)
{
    std::string       ret;
    UA_Variant       *var;
    UA_NodeId         node_id;
    UA_StatusCode     status;
    UA_String         tmp_str;

    node_id = UA_NODEID_STRING(namespace_index, variable);
    status = UA_Client_readValueAttribute(client, node_id, var);

    if(status == UA_STATUSCODE_GOOD)
    {
       tmp_str = *reinterpret_cast<UA_String*>(var->data);
       ret = std::string(reinterpret_cast<char *>(tmp_str.data), tmp_str.length);
    }

    return ret;
}

Compilieren z.B. mit folgendem Befehl um eine Bibliothek zu erstellen:

g++ -c -o test test.c

Ubuntu 18.04 Update – LXC Container starten nicht

Ich nutze auf meinem Ubuntu Server LXC Kontainer. Beim Update von Ubuntu 16.04 auf 18.04 funktionieren diese nicht mehr. Das hat zwei Gründe:

  1. Gibt es das Hilfsscript unter /usr/share/lxc/config/debian.common.conf nicht mehr
  2. Es wurde auf einen neuen Konfigurationsdateivariante umgestellt

Man kann die Konfigurationen für alle Kontainer unter /var/lib/lxc/ finden. Zum Debuggen kann man folgende Zeile verwenden

lxc-start -n <container> -F --logfile=/var/log/lxc<container>.log --logpriority=debug

Dabei steht <container> für den Container, den man starten will.

In der Configuration unter /var/lib/lxc/<container>/config muss folgende Zeile auskommentiert werden:

lxc.include = /usr/share/lxc/config/debian.common.conf
#lxc.include = /usr/share/lxc/config/debian.common.conf

Anschließend konvertiert man die Datei noch ins neue Format. Dabei wird eine Kopie angelegt. Ich habe dazu noch mein eigenes Backup angelgt, man weiß ja nie.

lxc-update-config -c config

bzw.

lxc-update-config -c /var/lib/lxc/<container>/config

 

Ubuntu 18.04 Update – kein KDE Desktop

Ich habe vor kurzem mein Ubuntu von 16.04 auf 18.04 geupdatet. Zur Vorbereitung sollte man die wichtigsten Dinge sichern und das System auf den letzten Stand updaten:

apt-get update
apt-get upgrade
apt-get dist-upgrade

Es gibt zwei Methoden hierfür:

Ubuntumethode

Hierfür wird das Paket „“ installiert und anschließend der Updatemanager ausgeführt:

apt-get install update-managerdo-release-upgrade

Debianmethode

Hierfür wird einfach das Release im APT ersetzt und dann ein Update//Upgrade durchgeführt.

sed -i -e "s/xenial/bionic/g" /etc/apt/sources.list
apt-get update
apt-get dist-upgrade

Danach werden einige Dateien heruntergeladen und man wird ggf. gefragt ob man seine Konfigurationen behalten will oder die Systemmaintainer Version installieren will. Das bleibt jedem selber überlassen.

Nach dem Update ist bei mir ist zwar der Loginscreen erschienen, allerdings war nach dem eintippen der Logindaten Schluß und der bekannte Desktop (bei mir KDE) wurde nicht geladen.

Als ersten Versuch habe ich versucht den Grafikmanager SDDM neu zu konfigurieren aber ohne Erfolg.

apt-get install --reinstall sddm

Ein weitere Info aus mehreren Blogs lautet, Nvidia Pakete zu deinstallieren und ggf. die Treiber für die Nvidia Grafikkarten von Nvidia herunterzuladen.

apt-get remove nvidia-*

Lösung brachte das Paket „plasma-workspace-wayland“.

apt-get install plasma-workspace-wayland

Der Hintergrund ist auch klar: KDE ist auf dem „alten“ System installiert. Der neue X-Server ist aber bei Ubuntu 18.04 nicht X11 sondern Wayland. KDE braucht deswegen ein Zwischenpaket, welches die API auf Wayland umsetzt.

Dann läufts auch mit KDE wieder.

PS.: Über Wayland und X11 lässt sich streiten, genauso über die verschiedenen Oberflächen wie KDE, Gnome, …

Unaligned Access beim Raspberry Pi

Ich habe eine kleine Microcontrollerschaltung mit einem STM32, welche Daten über UART an einen Raspberry PI überträgt. Die Daten sind in einem kleinen Protokoll verpackt, welches auf TLV (Tag Length Value) beruht und über CRC gesichert ist. Darüber werden sowohl char (1 byte) als auch integer und float übertragen (4 Bytes). Dabei wird ein Integer oder Float aus 4 Byte (INT1-4) gebildet. Es sieht dann so aus:

| Tag | Length | Byte   | CRC
| Tag | Length | Byte   | Byte   | Byte   | Byte | CRC
| Tag | Length | INT1   | INT2   | INT3   | INT4 | CRC 
| Tag | Length | FLOAT1 | FLOAT2 | FLOAT3 | FLOAT4 | CRC

Entwickelt habe ich es allerdings am PC in C++. Dort klappt die Wandlung des Streams zurück in ein INT/Float über einen Cast:

char *data;
...
reinterpret_cast<float>(data)
reinterpret_cast<float>(data + 4)

Am PC stellt der Cast kein Problem dar, auch wenn die Adresse nicht ein vielfaches von 4 ist (alignment). Am Raspberry PI allerdings kann der ARM Prozessor den Zugriff nur auf aligned Adressen machen und nicht auf Addressen die ungerade sind (0 = OK / 1,2,3 NOK). Ein X86 Prozessor schafft dies allerdings ist er dabei ein wenig langsamer, was aber kein Problem in diesem Kontext darstellt. Der ARM bricht mit Segmentation Fault ab, da er einen Busfehler feststellt (übrigens genau wie der STM32).

Um das handhaben zu können und das allgemeine Protoll nicht ändern zu müssen, kann man sich mit folgendem Konstrukt behelfen:

float ptr2float(char *ptr)
{
  union p2f
  {
    unsigned char c[4];
     float f;
  } tmp;

  tmp.c[0] = ptr[0];
  tmp.c[1] = ptr[1];
  tmp.c[2] = ptr[2];
  tmp.c[3] = ptr[3];

  return tmp.f;
}

Damit ist der Code portabel und funktioniert auch auf anderen Architekturen. Einen abgewandelten Code verwende ich auch auf dem Embedded Board mit einem STM32. Dabei kann man gleich auch die Konvertierung von little zu big endian machen oder umgekehrt. Ein strcpy oder memmove wäre auch möglich, allerdings ist  der Code meist länger, da man gewisse Dinge abfangen muss und auch das strcopy intern das Alignment beachten muss, was mehr Laufzeit kostet (hierzu sei der GCC Code von strcpy und strncpy empfohlen).

c’t Schlagseite als Bild und PDF

Ich bin langjähriger Leser ders Magizins C’T von des heise Verlags. Die ganzen Hefte aufzuheben, nachdem sie gelesen sind, würde ein eigenes Zimmer benötigen. Am Ende des Jahres archiviere ich manche Artikel. Dabei ist aber auch immer die „Schlagseite“ dabei, dem zweiwöchentlichen Comic der CT. Ein Übersicht über alle Schlagseiten von 2012 weg gibt es hier.

Die Papierseiten habe ich mir letztens angeschaut, und diese waren teilweise sehr sehr gelb! Deswegen habe ich mir gedacht, ich lade sie mir kostenlos von der heise.de Homepage runter und speichere sie als Bild und PDF. Das ist aber bei 26 Heften pro Jahr ganz schön mühsam. Ich habe deswegen meine Zeit darin investiert, das Ganze zu automatisieren. Diesmal in Python – damit geht der Download schnell und einfach.

Wer das Script haben will, kann es unter https://github.com/luckyhacky/schlagseite herunterladen. Kommentare und Anregungen sind gerne willkommen. Das Script ist as-it-is, d.h. es lädt immer alles herunter. Aktuell benötigt es Python 3.

PS.: Einen ähnlichen Ansatz hatte tamagothi.de allerdings war das Script auf die alte Seite bis 2012 ausgelegt. Diese gibt es nicht mehr. Auch die alte Schlagseite vor 2012 scheint nicht mehr verfügbar zu sein.

←Older