Class mit serial Modul erstellt für BMW IBus(Datenbus)
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
ok, priorityqueue hab ich teilweise auch verstanden, nur eine frage bleibt offen.
wenn ich neue items dem queue putte, egal ob prio 0 oder 1. bleibt hier dann trotzdem FIFO? was nicht passieren darf, dass sie neue sachen vorn einreihen. dann fährt man unter umstanden mit zwei queues besser?
was mir auch sorgen bereitet, dass nach den 17ms erst das telegram geholt wird. geht das denn ausreichend schnell? wenn es blöd läuft ist das telegramm geholt, aber der bus ist wieder belegt. dann gibts kollisionen und das telegram ist auch weg, weil ja nicht mehr im queue.
wenn ich neue items dem queue putte, egal ob prio 0 oder 1. bleibt hier dann trotzdem FIFO? was nicht passieren darf, dass sie neue sachen vorn einreihen. dann fährt man unter umstanden mit zwei queues besser?
was mir auch sorgen bereitet, dass nach den 17ms erst das telegram geholt wird. geht das denn ausreichend schnell? wenn es blöd läuft ist das telegramm geholt, aber der bus ist wieder belegt. dann gibts kollisionen und das telegram ist auch weg, weil ja nicht mehr im queue.
empty Sig
@harryberlin: das Schreiben der Pakete ist so sicher gelöst, wie es eben geht. Natürlich geht FIFO bei einer PriorityQueue verloren, weil die höher priorisierten Pakete als erstes geliefert werden. Aber das ist doch genau das, was Du willst. Für genau Deinen Fall sind PriorityQueue gemacht, damit man eben nicht umständlich mit mehreren Queues arbeiten muß. Im Gegensatz zu Deiner Lösung, wo an vielen unterschiedlichen Stellen per sleep geschlafen wird, wird bei meiner Lösung exakt nach 17ms und wenn ein Paket zum Senden ansteht das Paket mit der höchsten Priorität gesendet. Das weiß ich deshalb so genau, weil alles, was das Schreiben betrifft in einer Schleife mit einer Handvoll Zeilen steckt und nicht über eine ganze Klasse und mehrere Threads verteilt ist.
Das Lesen von Paketen ist bei mir noch miserabel gelöst, weil ich die Fehlerbehandlung nicht verstehe. Ich glaube kaum, dass einzelnen Bytes weglassen und dann hoffen, dass eine sinnvolle Nachricht kommt, eine stabile Lösung ist.
Das Lesen von Paketen ist bei mir noch miserabel gelöst, weil ich die Fehlerbehandlung nicht verstehe. Ich glaube kaum, dass einzelnen Bytes weglassen und dann hoffen, dass eine sinnvolle Nachricht kommt, eine stabile Lösung ist.
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
@Sirius3
es darf nicht sein, dass eine spätere high prio nachricht sich vor die andere einreiht. FIFO muss hier dennoch bestehen.
beim lesen ist die fehlerbehandlung wichtig, da so kollisionen beim schreiben erkannt werden können. oder es werden bus fehler erkannt, die man nicht ausschließen sollte. jetzt wird vermutlich blackjack den finger heben, wegen den excepts. zudem gibt es tatsächlich korrupte nachrichten auf dem bus. z.B. beim aufwecken des bus gibt es eine merkwürdige nachricht die keine informationen enthält. eine autokorrektur ist hier nicht sinnvoll. also besser korrupte sachen verwerfen als sie versuchen zu verstehen. deswegen ja auch die checksum.
wenn man wüsste wie weit die daten fehlerhaft sind, kann man natürlich mehr verwerfen, nur weiß man es eben nicht. also schritt für schritt.
bmw ibus ist hier ganz gut erklärt: http://www.alextronic.de/bmw/projects_b ... _ibus.html
es darf nicht sein, dass eine spätere high prio nachricht sich vor die andere einreiht. FIFO muss hier dennoch bestehen.
beim lesen ist die fehlerbehandlung wichtig, da so kollisionen beim schreiben erkannt werden können. oder es werden bus fehler erkannt, die man nicht ausschließen sollte. jetzt wird vermutlich blackjack den finger heben, wegen den excepts. zudem gibt es tatsächlich korrupte nachrichten auf dem bus. z.B. beim aufwecken des bus gibt es eine merkwürdige nachricht die keine informationen enthält. eine autokorrektur ist hier nicht sinnvoll. also besser korrupte sachen verwerfen als sie versuchen zu verstehen. deswegen ja auch die checksum.
wenn man wüsste wie weit die daten fehlerhaft sind, kann man natürlich mehr verwerfen, nur weiß man es eben nicht. also schritt für schritt.
bmw ibus ist hier ganz gut erklärt: http://www.alextronic.de/bmw/projects_b ... _ibus.html
empty Sig
Schieb in die PriorityQueue Tupel in der Form (priority, message_count, message). message_count ist dabei einfach ein Integer den du für jede Nachricht erhöhst. Wenn die Priorität gleich ist, wird somit nach message_count sortiert und du erreicht das FIFO Verhalten, das du haben möchtest.
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
@DasIch
Ist nur leider auch endlich. Klar man kann sagen "das programm läuft eh nur zeitweise" dann ist egal. Aber vllt. wirds ja doch mal eine Dauerlösung.
Ist nur leider auch endlich. Klar man kann sagen "das programm läuft eh nur zeitweise" dann ist egal. Aber vllt. wirds ja doch mal eine Dauerlösung.
empty Sig
Das ist endlich nur insofern dass message_count irgendwann nicht mehr in den Arbeitsspeicher passt. An die Grenze wirst du so schnell nicht stoßen. Das ist vielleicht offensichtlicher wenn du überlegst dass mein Vorschlag äquivalent dazu ist einen timestamp zu benutzen.
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
@DasIch
Keine schlechte Idee.
Doch Timestamp ist nicht so gut, da ich die Zeit vom Bus lese und im Pi dann entsprechend setze.
Keine schlechte Idee.
Doch Timestamp ist nicht so gut, da ich die Zeit vom Bus lese und im Pi dann entsprechend setze.
empty Sig
@harryberlin: wenn Du eine PriorityQueue brauchst, die auch noch die Reihenfolge innerhalb einer Priorität einhält, dann schreib Dir doch einfach selbst eine:
Wie schon geschrieben, hast Du darauf ja in Deiner ursprünglichen Implementierung auch keinen Wert gelegt.
Code: Alles auswählen
from collections import defaultdict, deque
from Queue import Queue
class PriorityQueue(Queue):
'''Variant of Queue that retrieves open entries in priority order (lowest first).
Entries are tuples of the form: (priority number, data).
'''
def _init(self, maxsize):
self.queue = defaultdict(deque)
def _qsize(self):
return sum(len(q) for q in self.queue.iteritems())
def _put(self, item):
self.queue[item[0]].append(item)
def _get(self):
prio = min(self.queue)
result = self.queue[prio].popleft()
if not self.queue[prio]:
del self.queue[prio]
return result
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
Danke für die Mühe.Sirius3 hat geschrieben:...dann schreib Dir doch einfach selbst eine...
"einfach" hast du gut formuliert. Das hätte ich nie auf einfache Weise zustande gebracht.
Darf man denn den Name "PriorityQueue" so nutzen, da es doch eigentlich der von einem modul ist.
empty Sig
@Sirius3: `self.queue` ist ein irreführender Name, und `_qsize()` ist fehlerhaft. Da müsste man über `itervalues()` iterieren, denn die `iteritems()` haben alle die Länge 2, egal wie viele Elemente in der Queue stecken.
Ich denke die Variante von DasIch ist besser, denn da bleiben die (Laufzeit)Eigenschaften der Heapqueue erhalten, die dort als Implementierung dahinter steckt.
@harryberlin: Welches Modul hat den Namen `PriorityQueue`? In der Standardbibliothek gibt es keines das so heisst.
Ich denke die Variante von DasIch ist besser, denn da bleiben die (Laufzeit)Eigenschaften der Heapqueue erhalten, die dort als Implementierung dahinter steckt.
@harryberlin: Welches Modul hat den Namen `PriorityQueue`? In der Standardbibliothek gibt es keines das so heisst.
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
@BlackJack
meine meinung: wer weit unten im code arbeitet, geht davon aus, dass "PriorityQueue" importiert wurde, und erwartet ein verhalten, was nicht dem entspricht.
man könnte doch der lösung von DasIch eine routine dazu bastseln, die feststellt, wenn die queue leer ist, und den counter zurücksetzt.
das liese sich evtl. sogar über die "except Empty:" lösen.
meine meinung: wer weit unten im code arbeitet, geht davon aus, dass "PriorityQueue" importiert wurde, und erwartet ein verhalten, was nicht dem entspricht.
man könnte doch der lösung von DasIch eine routine dazu bastseln, die feststellt, wenn die queue leer ist, und den counter zurücksetzt.
das liese sich evtl. sogar über die "except Empty:" lösen.
empty Sig
@harryberlin: Das ist ein ziemlich generischer Name einer allgemein bekannten abstrakten Datenstruktur. Ich denke nicht, dass man sich dafür einen anderen Namen ausdenken muss, nur weil es den auch in einem Modul in der Standardbibliothek gibt. Dann müsste man bei *jedem* Namen, den man selbst vergibt, erst einmal im Index von der Python-Dokumentation nachschauen. Und da sind *viele* Namen. Teilweise ja auch innerhalb der Standardbibliothek mehrfach verwendete (`open()`), oder dann auch in (bekannten/verbreiteten) Bibliotheken von Drittanbietern (`Image`). Und so wirklich viel anders verhält sich die `PriorityQueue` von Sirius3 vom Effekt her ja auch nicht. Es ist halt eine Prioritätswarteschlange, die zusätzlich innerhalb der Prioritäten noch eine Reihenfolge beachtet.
Bevor man den Zähler zurück setzt, sollte man da vielleicht erst einmal nachweisen, dass das ein Problem ist/wird. Ab welcher Byteanzahl wäre Dir eine ganze Zahl an der Stelle denn zu gross? Wenn der Zähler innerhalb eines Jahres Dauerbetrieb 64-Bit erreicht, entspricht das über 580 Milliarden Packets *pro Sekunde*. Wenn das technisch überhaupt über die Leitung gehen würde, was ich bei 9600 Baud sehr stark bezweifle.
Bevor man den Zähler zurück setzt, sollte man da vielleicht erst einmal nachweisen, dass das ein Problem ist/wird. Ab welcher Byteanzahl wäre Dir eine ganze Zahl an der Stelle denn zu gross? Wenn der Zähler innerhalb eines Jahres Dauerbetrieb 64-Bit erreicht, entspricht das über 580 Milliarden Packets *pro Sekunde*. Wenn das technisch überhaupt über die Leitung gehen würde, was ich bei 9600 Baud sehr stark bezweifle.
@BlackJack: ja, die Flüchtigkeitsfehler, itervalues ist natürlich richtig. self.queue benutzen alle Queue-Implementationen zum Speichern der Elemente, daher der Name. Ob ich eine Laufzeit von O(n) erwarte oder wie bei der "normalen" Queue von O(1) ist wohl Geschmacksache. Bei wenigen Prioritäten, wie bei diesem Problem, bin ich nahe an O(1), was mir persönlich sympatisch ist.
So ein Jahr kann ziemlich schnell vorbei sein. Daher würde ich eher sagen, dass, wenn man alle 17ms eine Nachricht verschickt, ein 64bit-Zähler gerade mal 993 Millionen Jahre reicht.
So ein Jahr kann ziemlich schnell vorbei sein. Daher würde ich eher sagen, dass, wenn man alle 17ms eine Nachricht verschickt, ein 64bit-Zähler gerade mal 993 Millionen Jahre reicht.
Hm, ob das dann reicht? Was ist denn die Lebenserwartung von einem qualitativ guten BMW im Dauerbetrieb?
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
So ihr beiden Scherzkekse
Hab nun mal die Tasten klimpern lassen und größtenteils den code umgeschrieben.
Auch Hex-String-hin-und-her wollte ich vermeiden, dennoch vorerst noch zurück geben beim lesen und zum schreiben übergeben.
Das öffnen des Serial Ports habe ich geändert.
Ich habs noch nicht getestet, da ich aktuell zwei Probleme sehe:
1. in der funktion "write_bus_packet", die so aufgerufen werden soll:
funktioniert das denn überhaupt mit der checksum,
oder sollte es so aussehen?:
2. in der funktion "read_bus_packet", bei der rückgabe:
wie mache ich das mit der data liste
edit:
ich habs
und hier mal der ganze code. bitte keine anmerkungen zu den log, note, und dialog_ok funktionen und monitor class. das wäre grad "out of topic"
Hab nun mal die Tasten klimpern lassen und größtenteils den code umgeschrieben.
Auch Hex-String-hin-und-her wollte ich vermeiden, dennoch vorerst noch zurück geben beim lesen und zum schreiben übergeben.
Das öffnen des Serial Ports habe ich geändert.
Ich habs noch nicht getestet, da ich aktuell zwei Probleme sehe:
1. in der funktion "write_bus_packet", die so aufgerufen werden soll:
Code: Alles auswählen
ibus.write_bus_packet('80', '3B', ['02', '36'])
Code: Alles auswählen
checksum = src ^ (len(data) + 2) ^ dst
Code: Alles auswählen
checksum = int(src, 16) ^ (len(data) + 2) ^ int(dst, 16)
wie mache ich das mit der data liste
Code: Alles auswählen
'data': message[3:data_length], # TODO: Convert to hex string array(exp. ['0A', 'AD']) in one line?
ich habs
Code: Alles auswählen
'data': ['%02X' % i for i in message[3:data_length]],
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
###### intall these pakets #####
# sudo apt-get install python-serial
import xbmc, xbmcgui, xbmcaddon
import time
from threading import Thread
import os
import serial
from Queue import PriorityQueue, Empty
__author__ = 'harryberlin'
ADDON = xbmcaddon.Addon()
ADDONNAME = ADDON.getAddonInfo('name')
ADDONID = ADDON.getAddonInfo('id')
ADDONPATH = ADDON.getAddonInfo('path')
ICON = os.path.join(ADDONPATH, 'icon.png')
def log(string, lvl=1):
thread = Thread(target=_log_thread, args=(string, lvl))
thread.setDaemon(True)
thread.start()
def _log_thread(string, lvl=1):
return xbmc.log('IBUSCOMMUNICATOR: ' + string)
def note(heading, message=" ", time=5000):
thread = Thread(target=_note_thread, args=(heading, message, time))
thread.setDaemon(True)
thread.start()
def _note_thread(heading, message=" ", time=5000):
xbmcgui.Dialog().notification(heading=' %s' % heading, message=' %s' % message, icon=ICON, time=time)
log('NOTIFICATION: ' + heading + ' - ' + message)
def dialog_ok(label1, label2='', label3=''):
thread = Thread(target=_dialog_ok_thread, args=(label1, label2, label3))
thread.setDaemon(True)
thread.start()
def _dialog_ok_thread(label1, label2='', label3=''):
xbmcgui.Dialog().ok('IBusCommunicator', label1, label2, label3)
def set_kodi_prop(property, value, id=10000):
xbmc.executebuiltin('SetProperty(%s,%s,%s)' % (property, value, id))
def get_kodi_prop(property, id=10000):
value = xbmcgui.Window(id).getProperty(property)
return value
class Monitor(xbmc.Monitor):
def __init__(self):
xbmc.Monitor.__init__(self)
class IBusFace(object):
def __init__(self, device_path):
self.serial_port = serial.Serial()
self.serial_port.port = device_path
self.serial_port.baudrate = 9600
self.serial_port.bytesize = serial.EIGHTBITS
self.serial_port.parity = serial.PARITY_EVEN
self.serial_port.stopbits = serial.STOPBITS_ONE
self.read_error_counter = 0 # counter for read errors
set_kodi_prop('msgerr_cnt', '0')
self.read_buffer = []
self.read_access = False # set False to trim packet_buffer
self.write_buffer = PriorityQueue()
self.write_counter = 0
# Reading Thread
self.cancel_read_thread = False
self.read_thread = Thread(target=self._reading)
self.read_thread.setDaemon(True)
# Writing Thread
self.cancel_write_thread = False
self.write_thread = Thread(target=self._writing)
self.write_thread.setDaemon(True)
@staticmethod
def _calculate_checksum(packet):
result = 0
for value in packet:
result ^= value
return result
def _cut_read_buffer(self, offset=1):
self.read_access = False
time.sleep(0.003)
self.read_buffer = self.read_buffer[offset:]
self.read_access = True
def _wait_free_bus(self, waiting=17, timeout=1000):
cts_counter = 0
while cts_counter < waiting:
if self.serial_port.getCTS():
cts_counter += 1
if not timeout > 0:
return False
timeout -= 1
else:
cts_counter = 0
if not timeout > 0:
return False
timeout -= 1
time.sleep(0.001)
return True
def _reading(self):
self.read_access = True
while not self.cancel_read_thread:
self._read_char()
time.sleep(0.001)
def _read_char(self):
try:
while self.serial_port.inWaiting() > 0:
if self.cancel_read_thread:
return
if self.read_access:
self.read_buffer.append(ord(self.serial_port.read()))
except:
log('IBUS: Hit a serialException')
return
def _writing(self):
cts_count = 0
while not self.cancel_write_thread:
if self.serial_port.getCTS():
cts_count += 1
else:
cts_count = 0
if cts_count > 17:
try:
prio, write_counter, data = self.write_buffer.get(timeout=0.001)
self.serial_port.write(data)
self.serial_port.flush()
cts_count = 0
except Empty:
pass
else:
time.sleep(0.001)
def connect(self):
try:
self.serial_port.open()
self.serial_port.setRTS(False)
if not self._wait_free_bus(120, 2000):
log('IBUS: Can not locate free Bus')
return False
self.serial_port.flushInput()
# start reading
self.read_thread.start()
self.write_thread.start()
return True
except:
return False
def disconnect(self):
self.cancel_read_thread = True
self.cancel_write_thread = True
time.sleep(200)
if self.serial_port.isOpen():
self.serial_port.close()
def flush_input(self):
self.serial_port.flushInput()
def set_rts(self, rts_state):
self.serial_port.setRTS(rts_state)
def get_rts(self):
return self.serial_port.rts
def read_bus_packet(self):
try:
data_length = self.read_buffer[1]
except:
# list is not big enough
return None
if data_length < 3 or data_length > 37:
#log('IBUS: Length of +37 found (%s), %s' % (data_length, self.read_buffer), 2)
log('IBUS: Length of +37 found (%s)' % data_length)
self._cut_read_buffer()
self.read_error_counter += 1
set_kodi_prop('msgerr_cnt', '%s' % self.read_error_counter)
return None
else:
buffer_len = len(self.read_buffer)
if buffer_len < 5 or buffer_len < data_length + 2:
return None
message = self.read_buffer[:data_length + 2]
if self._calculate_checksum(message) == 0:
#log('IBUS-READ: %s' % ' '.join(message), 5)
return {
'src': '%02X' % message[0],
'len': '%02X' % data_length, # message[1]
'dst': '%02X' % message[2],
'data': ['%02X' % i for i in message[3:data_length]],
'xor': '%02X' % message[-1],
}
else:
#log('IBUS: Corrupt packet found (%s), %s' % (data_length, self.read_buffer), 2)
log('IBUS: Corrupt packet found')
self._cut_read_buffer()
return None
def write_bus_packet(self, src, dst, data, highprio=False):
checksum = src ^ (len(data) + 2) ^ dst
for c in data:
checksum ^= ord(c)
data = '%c%c%c%s%c' % (src, len(data) + 2, dst, data, checksum)
self.write_buffer.put((0 if highprio else 1, self.write_counter, data))
self.write_counter += 1
def write_hex_message(self, hexstring):
hexstring_tmp = hexstring.split(' ')
src = hexstring_tmp[0]
dst = hexstring_tmp[2]
data = hexstring_tmp[3:-1]
self.write_bus_packet(src, dst, data)
def main():
monitor = Monitor()
ibus = IBusFace('/dev/ttyUSB0')
log('IBus connect')
if not ibus.connect():
note('IBus Error', 'Can not open serial device')
return
note('IBus connected')
while not monitor.abortRequested():
packet = ibus.read_bus_packet()
if packet:
log('%s %s %s %s %s' % (packet['src'], packet['len'], packet['dst'], ' '.join(packet['data']), packet['xor']))
time.sleep(0.001)
log("IBus disconnect")
ibus.disconnect()
if __name__ == '__main__':
main()
empty Sig
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
Habs nun getestet.
Es war noch ein Fehler drin. Bei erfolgreich erkannten Packet wurde es nicht aus dem buffer gelöscht.
Und bei "'data': ['%02X' % i for i in message[3:data_length + 1]]," hat noch + 1 gefehlt.
und das lesen läuft schon mal.
Es war noch ein Fehler drin. Bei erfolgreich erkannten Packet wurde es nicht aus dem buffer gelöscht.
Und bei "'data': ['%02X' % i for i in message[3:data_length + 1]]," hat noch + 1 gefehlt.
und das lesen läuft schon mal.
empty Sig
@harryberlin: die natürlich Repräsentation von Zahlen in einem Programm sind Zahlen und nicht Hex-Strings. Und die natürliche Repräsentation von Bytes sind Bytestrings und nicht Hex-Strings. Bei src könnte man sich noch streiten, was denn das ist, String oder Zahl, aber bei len!
Ein Aufruf von write_bus_packet kann genausogut so aussehen, ohne die Probleme, die Deine Hex-Repräsentation überall macht:
Und wenn Du eine Methode write_hex_message brauchst, dann halt so:
Warum startest Du zum Loggen einen eigenen Thread? Und wohin returned _log_thread was auch immer?
Die Monitor-Klasse ist sinnfrei.
Die Parameterübergabe gleich beim Serial-Aufruf fand ich übersichtlicher. read_access hat immer noch die gleichen Probleme mit Nebenläufigkeit. Die korrekte Lösung ist auch hier eine Queue zu benutzen!
_wait_free_bus ist umständlich, wenn nicht sogar fehlerhaft. Du hast jetzt zwei unabhängige cts-Counter. Warum bist Du von meiner Lösung hier abgewichen?
Busy-Waiting bei _read_char ist schlecht. Warum bist Du da von meiner Lösung abgewichen?
connect ersetzt eine sinnvolle Exception durch einen nichtssagenden Returnwert. BlackJack hat ja dieses Thema schon ausführlichst erörtert. try-except ersartzlos löschen!
set_rts und get_rts würde man schöner als Property schreiben.
read_bus_packet: welche Exception erwartest Du da? None ist kein guter Rückgabewert bei einem Fehler. Ich würde ja so lange warten, bis ein korrektes Paket gelesen wurde, eventuell noch mit einem TimeOut-Parameter, falls man nicht solange warten will.
Ein Aufruf von write_bus_packet kann genausogut so aussehen, ohne die Probleme, die Deine Hex-Repräsentation überall macht:
Code: Alles auswählen
ibus.write_bus_packet(0x80, 0x3B, '02 36'.replace(' ', '').decode('hex'))
Code: Alles auswählen
def write_hex_message(self, hexstring):
data = ''.join(hexstring.split()).decode('hex')
self.write_bus_packet(src=ord(data[0]), dst=ord(data[1]), data=data[3:-1])
Die Monitor-Klasse ist sinnfrei.
Die Parameterübergabe gleich beim Serial-Aufruf fand ich übersichtlicher. read_access hat immer noch die gleichen Probleme mit Nebenläufigkeit. Die korrekte Lösung ist auch hier eine Queue zu benutzen!
_wait_free_bus ist umständlich, wenn nicht sogar fehlerhaft. Du hast jetzt zwei unabhängige cts-Counter. Warum bist Du von meiner Lösung hier abgewichen?
Busy-Waiting bei _read_char ist schlecht. Warum bist Du da von meiner Lösung abgewichen?
connect ersetzt eine sinnvolle Exception durch einen nichtssagenden Returnwert. BlackJack hat ja dieses Thema schon ausführlichst erörtert. try-except ersartzlos löschen!
set_rts und get_rts würde man schöner als Property schreiben.
read_bus_packet: welche Exception erwartest Du da? None ist kein guter Rückgabewert bei einem Fehler. Ich würde ja so lange warten, bis ein korrektes Paket gelesen wurde, eventuell noch mit einem TimeOut-Parameter, falls man nicht solange warten will.
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
@Sirius3
1.
die message ist bei mir angekommen, dass hex strings nicht gut sind. jedoch aktuell ist es nun mal so(großteil vom code habe ich nicht gezeigt). warum habe ich bereits erklärt.
dass da noch was passieren muss, ist angekommen.
2.
wie erwähnt, keine diskussion zu log, note, dialog_ok und monitor klasse.
returnt wird der aufruf einer xbmc funktion.
die monitor klasse wird noch erweitert und soll schon mal im code so stehen.
3.
ich finde es mit connect besser, da ich unabhängig von init connecten und disconnecten kann.
4.
wie mache ich ein property daraus?
5.
welche nebenläufigkeit meinst du genau? ich habe einmal den loop, der mir die daten in den buffer schiebt. andermal will ich den buffer kürzen und will das rein schaufeln von daten also überspringen.
wo siehst du da problem mit dem flag?
eine queue ist hier fehl am platz, weil wenn ich z.B. 10 zeichen aus der queue geholt habe und merke "uh, das kannst ja gar nicht gebrauchen", dann fange ich an mir einen buffer zu basteln, weil die 10 zeichen aus dem queue raus sind aber nicht verworfen werden dürfen. unter umständen fängt 2 zeichen später ein brauchbares telegram an.
6.
ich muss am anfang auf eine große lücke warten, um einen guten einstieg zu finden. ich könnte natürlich auch gleich direkt einsteigen, aber erzeuge unter umständen readerrors, die man von vorherein vermeiden kann.
diese funktion wird auch nur einmal aufgerufen und vor dem start der threads.
so sehe ich hier keine probleme.
die cts counter brauchen keinen zusammenhang mehr.
7.
ich bin abgewichen, weil eine queue nicht sinnvoll ist. siehe 4.
8.
der return-wert bei connect ist True oder False. eindeutiger als schwarz oder weiß erkenne ich hier nicht.
zudem weiß ich nicht so recht mit excepts umzugehen. wenn ich nach sinnvollen quellen frage, bekomme ich aus erfahrung keine rückmeldung(ja ich kann mit google umgehen).
also erspare ich es mir und gehe dem mal nach, wenn ich richtig lust dazu habe.
ihr solltet es nicht immer gleich als 100% fehlerfreie sache ansehen, was hier vorgelegt wird. es sieht vllt. fast aus wie copy/paste. nur ich versuche auch zu verstehen, was ich da kopiere. und war eigentlich vorerst ganz zufrieden mit dem was ich da nun zusammen gebastelt hab.
9.
bei read_bus_packet wird None returnt wenn eben nix brauchbares dabei ist. da dies über ein loop aufgerufen wird, wäre es nicht sinnvoll zu warten. ein timeout rein zu stricken, macht die funktion nur komplexer.
unterm strich möchte ich sagen, so ausführungen mit kleinen codeschnippseln (wie zu hex und string), sowas verstehe ich besser. dem kann ich besser folgen, als text den ich mir 10 mal durchlesen muss und nach fremdwörtern googlen muss. aber kein problem, das mache ich auch gern.
und danke für die unterstützung.
1.
die message ist bei mir angekommen, dass hex strings nicht gut sind. jedoch aktuell ist es nun mal so(großteil vom code habe ich nicht gezeigt). warum habe ich bereits erklärt.
Code: Alles auswählen
ibus.write_bus_packet('80', '3B', ['02', '36'])
2.
wie erwähnt, keine diskussion zu log, note, dialog_ok und monitor klasse.
returnt wird der aufruf einer xbmc funktion.
die monitor klasse wird noch erweitert und soll schon mal im code so stehen.
3.
ich finde es mit connect besser, da ich unabhängig von init connecten und disconnecten kann.
4.
wie mache ich ein property daraus?
5.
welche nebenläufigkeit meinst du genau? ich habe einmal den loop, der mir die daten in den buffer schiebt. andermal will ich den buffer kürzen und will das rein schaufeln von daten also überspringen.
wo siehst du da problem mit dem flag?
eine queue ist hier fehl am platz, weil wenn ich z.B. 10 zeichen aus der queue geholt habe und merke "uh, das kannst ja gar nicht gebrauchen", dann fange ich an mir einen buffer zu basteln, weil die 10 zeichen aus dem queue raus sind aber nicht verworfen werden dürfen. unter umständen fängt 2 zeichen später ein brauchbares telegram an.
6.
ich muss am anfang auf eine große lücke warten, um einen guten einstieg zu finden. ich könnte natürlich auch gleich direkt einsteigen, aber erzeuge unter umständen readerrors, die man von vorherein vermeiden kann.
diese funktion wird auch nur einmal aufgerufen und vor dem start der threads.
so sehe ich hier keine probleme.
die cts counter brauchen keinen zusammenhang mehr.
7.
ich bin abgewichen, weil eine queue nicht sinnvoll ist. siehe 4.
8.
der return-wert bei connect ist True oder False. eindeutiger als schwarz oder weiß erkenne ich hier nicht.
zudem weiß ich nicht so recht mit excepts umzugehen. wenn ich nach sinnvollen quellen frage, bekomme ich aus erfahrung keine rückmeldung(ja ich kann mit google umgehen).
also erspare ich es mir und gehe dem mal nach, wenn ich richtig lust dazu habe.
ihr solltet es nicht immer gleich als 100% fehlerfreie sache ansehen, was hier vorgelegt wird. es sieht vllt. fast aus wie copy/paste. nur ich versuche auch zu verstehen, was ich da kopiere. und war eigentlich vorerst ganz zufrieden mit dem was ich da nun zusammen gebastelt hab.
9.
bei read_bus_packet wird None returnt wenn eben nix brauchbares dabei ist. da dies über ein loop aufgerufen wird, wäre es nicht sinnvoll zu warten. ein timeout rein zu stricken, macht die funktion nur komplexer.
unterm strich möchte ich sagen, so ausführungen mit kleinen codeschnippseln (wie zu hex und string), sowas verstehe ich besser. dem kann ich besser folgen, als text den ich mir 10 mal durchlesen muss und nach fremdwörtern googlen muss. aber kein problem, das mache ich auch gern.
und danke für die unterstützung.
empty Sig
ad 1: wenn Du diese Signatur für Dein externes Interface noch brauchst, dann schreib Dir eine kurze Wrapper-Methode, aber intern kannst Du schon sauber arbeiten und aller neuer Code arbeitet dann mit der sauberen Schnittstelle.
ad 2: warauf ich hinaus wollte: der Returnwert wird nirgends verwendet, weil wohin soll der Thread das denn schicken? Die Threads sehen einfach nur so aus, als ob sie reichlich überflüssig sind.
ad 3: versteh den Zusammenhang mit meinem Post nicht
ad 4: mit @property
ad 5: ich muß nicht verstehen, was Du genau mit welchen Zeichen machst, um zu erkennen, dass sobald mehrere Threads ungeschützt auf die selbe Struktur zugreifen, es kracht. Eine Queue ist die einfachste Lösung, jetzt mußt Du nur noch Dein restliches Programm so umschreiben, dass es mit der Queue umgehen kann. Das sauberste wäre, das Erkennen der Telegramme innerhalb des read-Threads zu erledigen und read_bus_packet in ein einfaches read_queue.get() zu verwandeln. Dann ist das mit dem TimeOut auch nicht komplex.
ad 6: race-conditions sind komplex. cts-counter wird hier nicht mit dem Counter aus dem write-Thread synchronisiert und damit ist die Methode fehlerhaft. Lösung ein cts-counter, der solange er verändert wird durch ein Lock geschützt ist.
ad 7: siehe ad 5
ad 8: try-except ist der Ersatz für return True/False. Da Du ersteres schon halbwegs einsetzt, mach den Fehler des nackten excepts besser im Hauptprogramm und Log die Fehelermeldung wenigstens mit.
ad 9: siehe ad 5
ad 2: warauf ich hinaus wollte: der Returnwert wird nirgends verwendet, weil wohin soll der Thread das denn schicken? Die Threads sehen einfach nur so aus, als ob sie reichlich überflüssig sind.
ad 3: versteh den Zusammenhang mit meinem Post nicht
ad 4: mit @property
ad 5: ich muß nicht verstehen, was Du genau mit welchen Zeichen machst, um zu erkennen, dass sobald mehrere Threads ungeschützt auf die selbe Struktur zugreifen, es kracht. Eine Queue ist die einfachste Lösung, jetzt mußt Du nur noch Dein restliches Programm so umschreiben, dass es mit der Queue umgehen kann. Das sauberste wäre, das Erkennen der Telegramme innerhalb des read-Threads zu erledigen und read_bus_packet in ein einfaches read_queue.get() zu verwandeln. Dann ist das mit dem TimeOut auch nicht komplex.
ad 6: race-conditions sind komplex. cts-counter wird hier nicht mit dem Counter aus dem write-Thread synchronisiert und damit ist die Methode fehlerhaft. Lösung ein cts-counter, der solange er verändert wird durch ein Lock geschützt ist.
ad 7: siehe ad 5
ad 8: try-except ist der Ersatz für return True/False. Da Du ersteres schon halbwegs einsetzt, mach den Fehler des nackten excepts besser im Hauptprogramm und Log die Fehelermeldung wenigstens mit.
ad 9: siehe ad 5
-
- User
- Beiträge: 227
- Registriert: Donnerstag 17. Dezember 2015, 12:17
zu 1.
step by step. alles auf einmal lösen ist nicht meine stärke.
zu 2.
die threads sind da, um nicht unnötig aufzuhalten. ob das der fall ist, darüber lässt sich streiten.
zu 3.
zu Aufruf des Serial
zu 4.
du meinst so:
und aufruf zum setzen dann:
ibus.rts = True
und abfrage einfach
rtslevel = ibus.rts
zu. 5
a) gelesen wird nur von einem thread.
b) wenn die daten aus dem queue geholt(get) wurden, und nicht brauchbar sind, sind sie weg. aber das darf nicht sein! es muss ein zeichen wegfallen und erneut geprüft werden, ggf. weitere nachgeholt werden. wenn von einer geldscheinrolle ein schein zerissen ist, verwirfst du doch auch nicht gleich die ganze rolle, sondern schaust dir die anderen scheine an. oder habe ich beim verstehen der englischen queue doku was falsch verstanden?
c) ich verstehe nicht, warum du mir da gedanklich nicht folgen kannst?
ok, ich habs noch mal versucht zu verstehen, aber ich komme hier nicht weiter, wie bring ich lock und den thread in verbindung?
oben im init habe ich noch zusätzlich und dann die funktion "_cut_read_buffer" geändert. geht das denn? lock weiß doch gar nicht welchen thread es anhalten soll.
zu 6.
die cts-counter sind völlig unabhängig. die funktion wait_free_bus könnte man nun genauso gut direkt in die connect funktion rein schreiben.
zu 8.
du meinst return Exception und dann wie gehts weiter im hauptprogramm? so vielleicht?
step by step. alles auf einmal lösen ist nicht meine stärke.
zu 2.
die threads sind da, um nicht unnötig aufzuhalten. ob das der fall ist, darüber lässt sich streiten.
zu 3.
zu Aufruf des Serial
zu 4.
du meinst so:
Code: Alles auswählen
@property
def rts(self):
return self.serial_port.rts
@rts.setter
def rts(self, rts_state):
self.serial_port.setRTS(rts_state)
ibus.rts = True
und abfrage einfach
rtslevel = ibus.rts
zu. 5
a) gelesen wird nur von einem thread.
b) wenn die daten aus dem queue geholt(get) wurden, und nicht brauchbar sind, sind sie weg. aber das darf nicht sein! es muss ein zeichen wegfallen und erneut geprüft werden, ggf. weitere nachgeholt werden. wenn von einer geldscheinrolle ein schein zerissen ist, verwirfst du doch auch nicht gleich die ganze rolle, sondern schaust dir die anderen scheine an. oder habe ich beim verstehen der englischen queue doku was falsch verstanden?
c) ich verstehe nicht, warum du mir da gedanklich nicht folgen kannst?
ok, ich habs noch mal versucht zu verstehen, aber ich komme hier nicht weiter, wie bring ich lock und den thread in verbindung?
oben im init habe ich noch zusätzlich
Code: Alles auswählen
self.read_lock = Lock()
Code: Alles auswählen
def _cut_read_buffer(self, offset=1):
with self.read_lock:
self.read_buffer = self.read_buffer[offset:]
die cts-counter sind völlig unabhängig. die funktion wait_free_bus könnte man nun genauso gut direkt in die connect funktion rein schreiben.
zu 8.
du meinst return Exception und dann wie gehts weiter im hauptprogramm? so vielleicht?
Code: Alles auswählen
...
if packet == Exception:
log(packet)
else:
log('%s %s %s %s %s' % (packet['src'],
packet['len'],
packet['dst'],
' '.join(packet['data']),
packet['xor']))
...
empty Sig