Mit dem neuen Protokoll 2.0 ist es möglich Programme zu schreiben, die robust gegenüber Unterbrechungen, kurzen Stromausfällen und ähnlichem sind.
Der generelle Ansatz für ein solches Programm sieht aus wie folgt (Pseudocode):
func enumerate_callback(...) {
configure_brick();
configure_bricklet();
}
func connected_callback(...) {
ipcon.enumerate();
}
func main() {
ipcon.enumerate();
while (true) {
if (brick_is_configured) {
do_something_with_brick();
}
if (bricklet_is_configured) {
do_something_with_bricklet();
}
}
}
Es muss sichergestellt werden, dass die Konfiguration von Bricks und Bricklets während der Enumerierung stattfindet. Dies führt dazu, dass die Konfiguration (z.B. Callback-Periode) immer gesetzt wird, auch wenn ein Brick oder Bricklet neu gestartet wurde und dadurch seine Konfiguration verloren hat.
Eine Möglichkeit um dies zu realisieren ist, den Konfigurationscode in das Enumeration-Callback zu schreiben. Es sollte zusätzlich sichergestellt sein, dass eine neue Enumerierung ausgelöst wird, wenn eine TCP/IP-Verbindung neu aufgebaut wird, nachdem sie getrennt wurde. Wenn eine Verbindung getrennt und wiederhergestellt wird, ist nicht ausgeschlossen, dass ein Brick oder Bricklet in der Zwischenzeit neu gestartet wurde. Deshalb muss es auch dann neu konfiguriert werden.
Im Folgenden finden sich C#- und Python-Quelltexte für ein Programm, dass eine Temperatur auf einem LCD 20x4 Bricklet anzeigt. Dieses Programm sollte auch bei einem Neustart des Master Bricks oder einer verlorenen WLAN-Verbindung weiter funktionieren. Es ist sogar möglich, das Temperature oder LCD 20x4 Bricklet auszutauschen, da das Programm die UID aus der Enumerierung benutzt.
1using Tinkerforge;
2
3// This class will use any LCD Bricklet and Temperature Bricklet that
4// are connected to the PC and display the temperature on the LCD.
5//
6// The program should stay stable if Bricks are connected/disconnected,
7// if the Brick Daemon is restarted or if a Wi-Fi/RS485 connection is lost.
8// It will also keep working if you exchange the Master or one of the
9// Bricklets by a new one of the same type.
10//
11// If a Brick or Bricklet loses its state (e.g. callback configuration)
12// while the connection was lost, it will automatically be reconfigured
13// accordingly.
14class ExampleRugged
15{
16 private static string HOST = "localhost";
17 private static int PORT = 4223;
18
19 private static IPConnection ipcon = null;
20 private static BrickletLCD20x4 lcd = null;
21 private static BrickletTemperature temp = null;
22
23 static void Main()
24 {
25 // Create IP Connection
26 ipcon = new IPConnection();
27
28 // Register IP Connection callbacks
29 ipcon.EnumerateCallback += EnumerateCB;
30 ipcon.Connected += ConnectedCB;
31
32 // Connect to brickd, will trigger cb_connected
33 ipcon.Connect(HOST, PORT);
34 ipcon.Enumerate();
35
36 System.Console.WriteLine("Press enter to exit");
37 System.Console.ReadLine();
38 ipcon.Disconnect();
39 }
40
41 // Callback updates temperature displayed on lcd
42 static void TemperatureCB(BrickletTemperature sender, short temperature)
43 {
44 if(lcd != null)
45 {
46 lcd.ClearDisplay();
47 string s = "Temperature: " + temperature/100.0 + (char)0xdf + "C";
48 lcd.WriteLine(0, 0, s);
49 }
50 }
51
52 // Callback switches lcd backlight on/off based on lcd button 0
53 static void ButtonPressedCB(BrickletLCD20x4 sender, byte button)
54 {
55 if(lcd != null)
56 {
57 if(button == 0)
58 {
59 if(lcd.IsBacklightOn())
60 {
61 lcd.BacklightOff();
62 }
63 else
64 {
65 lcd.BacklightOn();
66 }
67 }
68 }
69 }
70
71 // Callback handles device connections and configures possibly lost
72 // configuration of lcd and temperature callbacks, backlight etc.
73 static void EnumerateCB(IPConnection sender, string UID, string connectedUID,
74 char position, short[] hardwareVersion,
75 short[] firmwareVersion, int deviceIdentifier,
76 short enumerationType)
77 {
78 if(enumerationType == IPConnection.ENUMERATION_TYPE_CONNECTED ||
79 enumerationType == IPConnection.ENUMERATION_TYPE_AVAILABLE)
80 {
81 // Enumeration is for LCD Bricklet
82 if(deviceIdentifier == BrickletLCD20x4.DEVICE_IDENTIFIER)
83 {
84 // Create lcd device object
85 lcd = new BrickletLCD20x4(UID, ipcon);
86 lcd.ButtonPressed += ButtonPressedCB;
87
88 lcd.ClearDisplay();
89 lcd.BacklightOn();
90 }
91 // Enumeration is for Temperature Bricklet
92 if(deviceIdentifier == BrickletTemperature.DEVICE_IDENTIFIER)
93 {
94 // Create temperature device object
95 temp = new BrickletTemperature(UID, ipcon);
96 temp.Temperature += TemperatureCB;
97
98 temp.SetTemperatureCallbackPeriod(50);
99 }
100 }
101 }
102
103 // Callback handles reconnection of IP Connection
104 static void ConnectedCB(IPConnection sender, short connectReason)
105 {
106 // Enumerate devices again. If we reconnected, the Bricks/Bricklets
107 // may have been offline and the configuration may be lost.
108 // In this case we don't care for the reason of the connection
109 ipcon.Enumerate();
110 }
111}
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4from tinkerforge.ip_connection import IPConnection
5from tinkerforge.bricklet_lcd_20x4 import LCD20x4
6from tinkerforge.bricklet_temperature import Temperature
7
8# This class will use any LCD Bricklet and Temperature Bricklet that
9# are connected to the PC and display the temperature on the LCD.
10#
11# The program should stay stable if Bricks are connected/disconnected,
12# if the Brick Daemon is restarted or if a Wi-Fi/RS485 connection is lost.
13# It will also keep working if you exchange the Master or one of the
14# Bricklets by a new one of the same type.
15#
16# If a Brick or Bricklet loses its state (e.g. callback configuration)
17# while the connection was lost, it will automatically be reconfigured
18# accordingly.
19class ExampleRugged:
20 HOST = "localhost"
21 PORT = 4223
22
23 def __init__(self):
24 self.lcd = None
25 self.temp = None
26
27 # Create IP Connection
28 self.ipcon = IPConnection()
29
30 # Register IP Connection callbacks
31 self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE,
32 self.cb_enumerate)
33 self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED,
34 self.cb_connected)
35
36 # Connect to brickd, will trigger cb_connected
37 self.ipcon.connect(ExampleRugged.HOST, ExampleRugged.PORT)
38
39 self.ipcon.enumerate()
40
41 # Callback switches lcd backlight on/off based on lcd button 0
42 def cb_button_pressed(self, button):
43 if self.lcd:
44 if button == 0:
45 if self.lcd.is_backlight_on():
46 self.lcd.backlight_off()
47 else:
48 self.lcd.backlight_on()
49
50 # Callback updates temperature displayed on lcd
51 def cb_temperature(self, temperature):
52 if self.lcd:
53 self.lcd.clear_display()
54 s = 'Temperature: {0:.2f}{1:c}C'.format(temperature/100.0, 0xdf)
55 self.lcd.write_line(0, 0, s)
56
57 # Callback handles device connections and configures possibly lost
58 # configuration of lcd and temperature callbacks, backlight etc.
59 def cb_enumerate(self, uid, connected_uid, position, hardware_version,
60 firmware_version, device_identifier, enumeration_type):
61 if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \
62 enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:
63
64 # Enumeration is for LCD Bricklet
65 if device_identifier == LCD20x4.DEVICE_IDENTIFIER:
66 # Create lcd device object
67 self.lcd = LCD20x4(uid, self.ipcon)
68 self.lcd.register_callback(self.lcd.CALLBACK_BUTTON_PRESSED,
69 self.cb_button_pressed)
70 self.lcd.clear_display()
71 self.lcd.backlight_on()
72 # Enumeration is for Temperature Bricklet
73 if device_identifier == Temperature.DEVICE_IDENTIFIER:
74 # Create temperature device object
75 self.temp = Temperature(uid, self.ipcon)
76 self.temp.register_callback(self.temp.CALLBACK_TEMPERATURE,
77 self.cb_temperature)
78
79 self.temp.set_temperature_callback_period(50)
80
81 # Callback handles reconnection of IP Connection
82 def cb_connected(self, connected_reason):
83 # Enumerate devices again. If we reconnected, the Bricks/Bricklets
84 # may have been offline and the configuration may be lost.
85 # In this case we don't care for the reason of the connection
86 self.ipcon.enumerate()
87
88
89if __name__ == "__main__":
90 ExampleRugged()
91 raw_input('Press key to exit\n') # Use input() in Python 3