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.
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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | using Tinkerforge;
// This class will use any LCD Bricklet and Temperature Bricklet that
// are connected to the PC and display the temperature on the LCD.
//
// The program should stay stable if Bricks are connected/disconnected,
// if the Brick Daemon is restarted or if a Wi-Fi/RS485 connection is lost.
// It will also keep working if you exchange the Master or one of the
// Bricklets by a new one of the same type.
//
// If a Brick or Bricklet loses its state (e.g. callback configuration)
// while the connection was lost, it will automatically be reconfigured
// accordingly.
class ExampleRugged
{
private static string HOST = "localhost";
private static int PORT = 4223;
private static IPConnection ipcon = null;
private static BrickletLCD20x4 lcd = null;
private static BrickletTemperature temp = null;
static void Main()
{
// Create IP Connection
ipcon = new IPConnection();
// Register IP Connection callbacks
ipcon.EnumerateCallback += EnumerateCB;
ipcon.Connected += ConnectedCB;
// Connect to brickd, will trigger cb_connected
ipcon.Connect(HOST, PORT);
ipcon.Enumerate();
System.Console.WriteLine("Press enter to exit");
System.Console.ReadLine();
ipcon.Disconnect();
}
// Callback updates temperature displayed on lcd
static void TemperatureCB(BrickletTemperature sender, short temperature)
{
if(lcd != null)
{
lcd.ClearDisplay();
string s = "Temperature: " + temperature/100.0 + (char)0xdf + "C";
lcd.WriteLine(0, 0, s);
}
}
// Callback switches lcd backlight on/off based on lcd button 0
static void ButtonPressedCB(BrickletLCD20x4 sender, byte button)
{
if(lcd != null)
{
if(button == 0)
{
if(lcd.IsBacklightOn())
{
lcd.BacklightOff();
}
else
{
lcd.BacklightOn();
}
}
}
}
// Callback handles device connections and configures possibly lost
// configuration of lcd and temperature callbacks, backlight etc.
static void EnumerateCB(IPConnection sender, string UID, string connectedUID,
char position, short[] hardwareVersion,
short[] firmwareVersion, int deviceIdentifier,
short enumerationType)
{
if(enumerationType == IPConnection.ENUMERATION_TYPE_CONNECTED ||
enumerationType == IPConnection.ENUMERATION_TYPE_AVAILABLE)
{
// Enumeration is for LCD Bricklet
if(deviceIdentifier == BrickletLCD20x4.DEVICE_IDENTIFIER)
{
// Create lcd device object
lcd = new BrickletLCD20x4(UID, ipcon);
lcd.ButtonPressed += ButtonPressedCB;
lcd.ClearDisplay();
lcd.BacklightOn();
}
// Enumeration is for Temperature Bricklet
if(deviceIdentifier == BrickletTemperature.DEVICE_IDENTIFIER)
{
// Create temperature device object
temp = new BrickletTemperature(UID, ipcon);
temp.Temperature += TemperatureCB;
temp.SetTemperatureCallbackPeriod(50);
}
}
}
// Callback handles reconnection of IP Connection
static void ConnectedCB(IPConnection sender, short connectReason)
{
// Enumerate devices again. If we reconnected, the Bricks/Bricklets
// may have been offline and the configuration may be lost.
// In this case we don't care for the reason of the connection
ipcon.Enumerate();
}
}
|
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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | #!/usr/bin/env python
# -*- coding: utf-8 -*-
from tinkerforge.ip_connection import IPConnection
from tinkerforge.bricklet_lcd_20x4 import LCD20x4
from tinkerforge.bricklet_temperature import Temperature
# This class will use any LCD Bricklet and Temperature Bricklet that
# are connected to the PC and display the temperature on the LCD.
#
# The program should stay stable if Bricks are connected/disconnected,
# if the Brick Daemon is restarted or if a Wi-Fi/RS485 connection is lost.
# It will also keep working if you exchange the Master or one of the
# Bricklets by a new one of the same type.
#
# If a Brick or Bricklet loses its state (e.g. callback configuration)
# while the connection was lost, it will automatically be reconfigured
# accordingly.
class ExampleRugged:
HOST = "localhost"
PORT = 4223
def __init__(self):
self.lcd = None
self.temp = None
# Create IP Connection
self.ipcon = IPConnection()
# Register IP Connection callbacks
self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE,
self.cb_enumerate)
self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED,
self.cb_connected)
# Connect to brickd, will trigger cb_connected
self.ipcon.connect(ExampleRugged.HOST, ExampleRugged.PORT)
self.ipcon.enumerate()
# Callback switches lcd backlight on/off based on lcd button 0
def cb_button_pressed(self, button):
if self.lcd:
if button == 0:
if self.lcd.is_backlight_on():
self.lcd.backlight_off()
else:
self.lcd.backlight_on()
# Callback updates temperature displayed on lcd
def cb_temperature(self, temperature):
if self.lcd:
self.lcd.clear_display()
s = 'Temperature: {0:.2f}{1:c}C'.format(temperature/100.0, 0xdf)
self.lcd.write_line(0, 0, s)
# Callback handles device connections and configures possibly lost
# configuration of lcd and temperature callbacks, backlight etc.
def cb_enumerate(self, uid, connected_uid, position, hardware_version,
firmware_version, device_identifier, enumeration_type):
if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \
enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:
# Enumeration is for LCD Bricklet
if device_identifier == LCD20x4.DEVICE_IDENTIFIER:
# Create lcd device object
self.lcd = LCD20x4(uid, self.ipcon)
self.lcd.register_callback(self.lcd.CALLBACK_BUTTON_PRESSED,
self.cb_button_pressed)
self.lcd.clear_display()
self.lcd.backlight_on()
# Enumeration is for Temperature Bricklet
if device_identifier == Temperature.DEVICE_IDENTIFIER:
# Create temperature device object
self.temp = Temperature(uid, self.ipcon)
self.temp.register_callback(self.temp.CALLBACK_TEMPERATURE,
self.cb_temperature)
self.temp.set_temperature_callback_period(50)
# Callback handles reconnection of IP Connection
def cb_connected(self, connected_reason):
# Enumerate devices again. If we reconnected, the Bricks/Bricklets
# may have been offline and the configuration may be lost.
# In this case we don't care for the reason of the connection
self.ipcon.enumerate()
if __name__ == "__main__":
ExampleRugged()
raw_input('Press key to exit\n') # Use input() in Python 3
|