C/C++ - IP Connection

Dies ist die Beschreibung der C/C++ API Bindings für die IP Connection. Die IP Connection kümmert sich um die Kommunikation zwischen einem Brick Daemon oder einer WIFI/Ethernet Extension. Bevor Bricks und Bricklets über deren API angesprochen werden können muss eine IP Connection erzeugt und die TCP/IP Verbindung hergestellt werden.

Eine Installationanleitung für die C/C++ API Bindings ist Teil deren allgemeine Beschreibung.

Beispiele

Der folgende Beispielcode ist Public Domain (CC0 1.0).

Enumerate

Download (example_enumerate.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <stdio.h>

#include "ip_connection.h"

#define HOST "localhost"
#define PORT 4223

// Print incoming enumeration information
void cb_enumerate(const char *uid, const char *connected_uid,
                  char position, uint8_t hardware_version[3],
                  uint8_t firmware_version[3], uint16_t device_identifier,
                  uint8_t enumeration_type, void *user_data) {
    (void)user_data;

    printf("UID:               %s\n", uid);
    printf("Enumeration Type:  %d\n", enumeration_type);

    if(enumeration_type == IPCON_ENUMERATION_TYPE_DISCONNECTED) {
        printf("\n");
        return;
    }

    printf("Connected UID:     %s\n", connected_uid);
    printf("Position:          %c\n", position);
    printf("Hardware Version:  %d.%d.%d\n", hardware_version[0],
                                            hardware_version[1],
                                            hardware_version[2]);
    printf("Firmware Version:  %d.%d.%d\n", firmware_version[0],
                                            firmware_version[1],
                                            firmware_version[2]);
    printf("Device Identifier: %d\n", device_identifier);
    printf("\n");
}

int main(void) {
    // Create IP Connection
    IPConnection ipcon;
    ipcon_create(&ipcon);

    // Connect to brickd
    if(ipcon_connect(&ipcon, HOST, PORT) < 0) {
        fprintf(stderr, "Could not connect to brickd\n");
        return 1;
    }

    // Register enumeration callback to "cb_enumerate"
    ipcon_register_callback(&ipcon,
                            IPCON_CALLBACK_ENUMERATE,
                            (void (*)(void))cb_enumerate,
                            NULL);

    // Trigger enumerate
    ipcon_enumerate(&ipcon);

    printf("Press key to exit\n");
    getchar();
    ipcon_destroy(&ipcon); // Calls ipcon_disconnect internally
    return 0;
}

Authenticate

Download (example_authenticate.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <stdio.h>

#include "ip_connection.h"

#define HOST "localhost"
#define PORT 4223
#define SECRET "My Authentication Secret!"

// Authenticate each time the connection got (re-)established
void cb_connected(uint8_t connect_reason, void *user_data) {
    IPConnection *ipcon = (IPConnection *)user_data;

    switch(connect_reason) {
    case IPCON_CONNECT_REASON_REQUEST:        printf("Connected by request\n"); break;
    case IPCON_CONNECT_REASON_AUTO_RECONNECT: printf("Auto-Reconnected\n"); break;
    }

    // Authenticate first...
    if (ipcon_authenticate(ipcon, SECRET) < 0) {
        fprintf(stderr, "Could not authenticate\n");
        return;
    } else {
        printf("Authentication succeeded\n");
    }

    // ...reenable auto reconnect mechanism, as described below...
    ipcon_set_auto_reconnect(ipcon, true);

    // ...then trigger enumerate
    ipcon_enumerate(ipcon);
}

// Print incoming enumeration information
void cb_enumerate(const char *uid, const char *connected_uid,
                  char position, uint8_t hardware_version[3],
                  uint8_t firmware_version[3], uint16_t device_identifier,
                  uint8_t enumeration_type, void *user_data) {
    // avoid unused parameter warnings
    (void)user_data; (void)connected_uid; (void)position;
    (void)hardware_version; (void)firmware_version; (void)device_identifier;

    printf("UID: %s, Enumeration Type: %d\n", uid, enumeration_type);
}

int main(void) {
    // Create IP Connection
    IPConnection ipcon;
    ipcon_create(&ipcon);

    // Disable auto reconnect mechanism, in case we have the wrong secret.
    // If the authentication is successful, reenable it.
    ipcon_set_auto_reconnect(&ipcon, false);

    // Register connected callback to "cb_connected"
    ipcon_register_callback(&ipcon,
                            IPCON_CALLBACK_CONNECTED,
                            (void (*)(void))cb_connected,
                            &ipcon);

    // Register enumeration callback to "cb_enumerate"
    ipcon_register_callback(&ipcon,
                            IPCON_CALLBACK_ENUMERATE,
                            (void (*)(void))cb_enumerate,
                            NULL);

    // Connect to brickd
    if(ipcon_connect(&ipcon, HOST, PORT) < 0) {
        fprintf(stderr, "Could not connect to brickd\n");
        return 1;
    }

    printf("Press key to exit\n");
    getchar();
    ipcon_destroy(&ipcon); // Calls ipcon_disconnect internally
    return 0;
}

API

Die meistens Funktionen der C/C++ Bindings geben einen Fehlercode (e_code) zurück.

Mögliche Fehlercodes sind:

  • E_OK = 0
  • E_TIMEOUT = -1
  • E_NO_STREAM_SOCKET = -2
  • E_HOSTNAME_INVALID = -3
  • E_NO_CONNECT = -4
  • E_NO_THREAD = -5
  • E_NOT_ADDED = -6 (seit C/C++ Bindings Version 2.0.0 nicht mehr verwendet)
  • E_ALREADY_CONNECTED = -7
  • E_NOT_CONNECTED = -8
  • E_INVALID_PARAMETER = -9
  • E_NOT_SUPPORTED = -10
  • E_UNKNOWN_ERROR_CODE = -11
  • E_STREAM_OUT_OF_SYNC = -12
  • E_INVALID_UID = -13
  • E_NON_ASCII_CHAR_IN_SECRET = -14
  • E_WRONG_DEVICE_TYPE = -15
  • E_DEVICE_REPLACED = -16
  • E_WRONG_RESPONSE_LENGTH = -17

wie in ip_connection.h definiert.

Grundfunktionen

void ipcon_create(IPConnection *ipcon)

Erzeugt ein IP Connection Objekt das verwendet werden kann um die verfügbar Geräte zu enumerieren. Es wird auch für den Konstruktor von Bricks und Bricklets benötigt.

void ipcon_destroy(IPConnection *ipcon)

Zerstört die IP Connection. Ruft intern ipcon_disconnect() auf. Der Socket zum Brick Daemon wird geschlossen und alle Threads der IP Connection werden beendet.

int ipcon_connect(IPConnection *ipcon, const char *host, uint16_t port)

Erstellt eine TCP/IP Verbindung zum gegebenen host und port. Host und Port können auf einen Brick Daemon oder eine WIFI/Ethernet Extension verweisen.

Bricks/Bricklets können erst gesteuert werden, wenn die Verbindung erfolgreich aufgebaut wurde.

Blockiert bis die Verbindung aufgebaut wurde und gibt einen Fehlercode zurück falls kein Brick Daemon oder WIFI/Ethernet Extension auf dem gegebenen Host und Port horcht.

int ipcon_disconnect(IPConnection *ipcon)

Trennt die TCP/IP Verbindung zum Brick Daemon oder einer WIFI/Ethernet Extension.

int ipcon_authenticate(IPConnection *ipcon, const char *secret)

Führt einen Authentifizierungs-Handshake mit dem verbundenen Brick Daemon oder WIFI/Ethernet Extension durch. Ist der Handshake erfolgreich dann wechselt die Verbindung vom nicht-authentifizierten in den authentifizierten Zustand und die Kommunikation kann normal weitergeführt werden. Schlägt der Handshake fehl wird die Verbindung durch die Gegenseite geschlossen. Die Authentifizierung kann fehlschlagen wenn das Authentifizierungsgeheimnis nicht übereinstimmt oder Authentifizierung für den Brick Daemon oder die WIFI/Ethernet Extension nicht aktiviert ist.

Für mehr Informationen zur Authentifizierung siehe das dazugehörige Tutorial.

Neu in Version 2.1.0.

int ipcon_get_connection_state(IPConnection *ipcon)

Kann die folgenden Zustände zurückgeben:

  • IPCON_CONNECTION_STATE_DISCONNECTED = 0: Keine Verbindung aufgebaut.
  • IPCON_CONNECTION_STATE_CONNECTED = 1: Eine Verbindung zum Brick Daemon oder der WIFI/Ethernet Extension ist aufgebaut.
  • IPCON_CONNECTION_STATE_PENDING = 2: IP Connection versucht im Moment eine Verbindung aufzubauen.
void ipcon_set_auto_reconnect(IPConnection *ipcon, bool auto_reconnect)

Aktiviert oder deaktiviert Auto-Reconnect. Falls Auto-Reconnect aktiviert ist, versucht die IP Connection eine Verbindung zum vorher angegebenen Host und Port wieder herzustellen, falls die aktuell bestehende Verbindung verloren geht. Auto-Reconnect greift also erst nach einem erfolgreichen Aufruf von ipcon_connect().

Standardwert ist true.

bool ipcon_get_auto_reconnect(IPConnection *ipcon)

Gibt true zurück wenn Auto-Reconnect aktiviert ist und false sonst.

void ipcon_set_timeout(IPConnection *ipcon, uint32_t timeout)

Setzt den Timeout in Millisekunden für Getter und für Setter die das Response-Expected-Flag aktiviert haben.

Standardwert ist 2500.

uint32_t ipcon_get_timeout(IPConnection *ipcon)

Gibt den Timeout zurück, wie er von ipcon_set_timeout() gesetzt wurde.

int ipcon_enumerate(IPConnection *ipcon)

Broadcast einer Enumerierungsanfrage. Alle Bricks und Bricklets werden mit einem Enumerate Callback antworten.

void ipcon_wait(IPConnection *ipcon)

Hält den aktuellen Thread an bis ipcon_unwait() aufgerufen wird.

Dies ist nützlich falls ausschließlich auf Callbacks reagiert werden soll oder wenn auf einen spezifischen Callback gewartet werden soll oder wenn die IP Connection in einem Thread gestartet wird.

wait und unwait agieren auf die gleiche Weise wie acquire und release einer Semaphore.

void ipcon_unwait(IPConnection *ipcon)

Startet einen Thread der vorher mit ipcon_wait() angehalten wurde wieder.

wait und unwait agieren auf die gleiche Weise wie acquire und release einer Semaphore.

Konfigurationsfunktionen für Callbacks

void ipcon_register_callback(IPConnection *ipcon, int16_t callback_id, void (*function)(void), void *user_data)

Registriert die function für die gegebene callback_id. Die user_data werden der Funktion als letztes Parameter mit übergeben.

Die verfügbaren Callback IDs mit zugehörenden Funktionssignaturen sind unten beschrieben.

Callbacks

Callbacks können registriert werden um über Ereignisse informiert zu werden. Die Registrierung wird mit der Funktion ipcon_register_callback() durchgeführt. Die Parameter bestehen aus dem IP Connection Objekt, der Callback ID, der Callback Funktion und optionalen Benutzer Daten:

void my_callback(int p, void *user_data) {
    printf("parameter: %d\n", p);
}

ipcon_register_callback(&ipcon, IPCON_CALLBACK_EXAMPLE, (void (*)(void))my_callback, NULL);

Die verfügbaren IDs mit den zugehörigen Callback Funktionssignaturen werden weiter unten beschrieben.

IPCON_CALLBACK_ENUMERATE
void callback(const char *uid, const char *connected_uid, char position, uint8_t hardware_version[3], uint8_t firmware_version[3], uint16_t device_identifier, uint8_t enumeration_type, void *user_data)

Der Callback empfängt sieben Parameter:

  • uid: Die UID des Bricks/Bricklets.
  • connected_uid: Die UID des Gerätes mit dem der Brick/das Bricklet verbunden ist. Für ein Bricklet ist dies die UID des Bricks oder Bricklets mit dem es verbunden ist. Für einen Brick ist es die UID des untersten Bricks im Stapel. Der unterste Master Brick hat die Connected-UID "0". Mit diesen Informationen sollte es möglich sein die komplette Netzwerktopologie zu rekonstruieren.
  • position: Für Bricks: '0' - '8' (Position in Stapel). Für Bricklets: 'a' - 'h' (Position an Brick) oder 'i' (Position des Raspberry Pi (Zero) HAT) oder 'z' (Bricklet an Isolator Bricklet).
  • hardware_version: Major, Minor und Release Nummer der Hardwareversion.
  • firmware_version: Major, Minor und Release Nummer der Firmwareversion.
  • device_identifier: Eine Zahl, welche den Brick/Bricklet repräsentiert.
  • enumeration_type: Art der Enumerierung

Mögliche Enumerierungsarten sind:

  • IPCON_ENUMERATION_TYPE_AVAILABLE = 0: Gerät ist verfügbar (Enumerierung vom Benutzer ausgelöst: ipcon_enumerate()). Diese Enumerierungsart kann mehrfach für das selbe Gerät auftreten.
  • IPCON_ENUMERATION_TYPE_CONNECTED = 1: Gerät wurde neu verbunden (Automatisch vom Brick gesendet nachdem die Kommunikation aufgebaut wurde). Dies kann bedeuten, dass das Gerät die vorher eingestellte Konfiguration verloren hat und neu konfiguriert werden muss.
  • IPCON_ENUMERATION_TYPE_DISCONNECTED = 2: Gerät wurde getrennt (Nur bei USB-Verbindungen möglich). In diesem Fall haben nur uid und enumeration_type einen gültigen Wert.

Es sollte möglich sein Plug-and-Play-Funktionalität mit diesem Callback zu implementieren (wie es im Brick Viewer geschieht).

Die Device Identifier Werte sind hier zu finden. Es gibt auch Konstanten für diese Werte, welche nach dem folgenden Muster benannt sind:

<device-type>_DEVICE_IDENTIFIER

Zum Beispiel: MASTER_DEVICE_IDENTIFIER oder AMBIENT_LIGHT_DEVICE_IDENTIFIER.

IPCON_CALLBACK_CONNECTED
void callback(uint8_t connect_reason, void *user_data)

Dieser Callback wird aufgerufen wenn die IP Connection eine Verbindung zu einem Brick Daemon oder einer WIFI/Ethernet Extension aufgebaut hat, mögliche Gründe sind:

  • IPCON_CONNECT_REASON_REQUEST = 0: Verbindung aufgebaut nach Anfrage vom Benutzer.
  • IPCON_CONNECT_REASON_AUTO_RECONNECT = 1: Verbindung aufgebaut nach durch Auto-Reconnect.
IPCON_CALLBACK_DISCONNECTED
void callback(uint8_t disconnect_reason, void *user_data)

Dieser Callback wird aufgerufen wenn die Verbindung der IP Connection zu einem Brick Daemon oder einer WIFI/Ethernet Extension getrennt wurde, mögliche Gründe sind:

  • IPCON_DISCONNECT_REASON_REQUEST = 0: Trennung wurde vom Benutzer angefragt.
  • IPCON_DISCONNECT_REASON_ERROR = 1: Trennung aufgrund eines unlösbaren Problems.
  • IPCON_DISCONNECT_REASON_SHUTDOWN = 2: Trennung wurde vom Brick Daemon oder WIFI/Ethernet Extension eingeleitet.