Listening for packets

starlon

New member
I think I know what you're going to tell me, but I wanted to ask anyways. I'm playing with my LCD through Python, using pygtk for the GUI. I'm using gobject.io_add_watch to listen to the LCD. It calls a callback when the file is ready to be read. It works in a way. One of two things seems to be happening. Either the LCD is sending the wrong data, which I'm doubting, or the callback's being called in the middle of transmissions. I'm using threading to provide a lock so I'm not writing to the device when the callback's reading from the device. Below is the output with Fan 0 reporting. The only time I wrote to the LCD was to turn on reporting right before the first line.

Code:
Fan #: 0, Fan tach cycles: 2, MSB: 204, LSB: 199, RPM: 0
Fan #: 0, Fan tach cycles: 8, MSB: 205, LSB: 178, RPM: 1577
Fan #: 0, Fan tach cycles: 8, MSB: 205, LSB: 156, RPM: 1578
Fan #: 0, Fan tach cycles: 8, MSB: 204, LSB: 158, RPM: 1585
Fan #: 8, Fan tach cycles: 154, MSB: 153, LSB: 204, RPM: 53454
Fan #: 8, Fan tach cycles: 98, MSB: 81, LSB: 204, RPM: 63478
Fan #: 8, Fan tach cycles: 108, MSB: 65, LSB: 204, RPM: 87134
Fan #: 0, Fan tach cycles: 8, MSB: 203, LSB: 205, RPM: 1592
Sometimes I get spurious temperature packets as well, but they're rare.
Looking for additional LCD resources? Check out our LCD blog for the latest developments in LCD technology.
 

CF Tech

Administrator
RPM: 63478
Was the fan making a high pitched sound? Are you wearing hearing protection and safety glasses? :eek:

Yes, the CRC is pretty important to check an keep synchronization with the packets. Once you get your Python up, if you are interested in sharing it, we can make it a sticky in the 3rd Party Software forum.
 

starlon

New member
Ok will do :) I'm just putting together a "Test" app right now, but it may branch out. It's a lot of fun that's for sure.

I'm having an issue with the key presses though. They fail a lot, as in the CRC doesn't match and the values are all crazy. I've noticed a lot of dropped packets in fact. I didn't mind so much till it affected key presses. Is it supposed to fail so often?

Code:
[starlon@localhost CF635]$ python CF635.py
Failure
Len: 1, Key: 4
Len: 1, Key: 10
Failure
Len: 1, Key: 4
Len: 1, Key: 10
Len: 1, Key: 4
Len: 1, Key: 10
Failure
Len: 1, Key: 1
Len: 1, Key: 7
Failure
Len: 1, Key: 1
Len: 1, Key: 7
Len: 1, Key: 2
Failure
Failure
 

CF Tech

Administrator
No, if you check a module with the 633_WinTest, you will never see a key packet fail. You can have all 32 temperature sensors, all four fans, and constant stream of screen updates (with their acknowledges), and any key presses you can hammer into the keypad going at once without error.

So there is probably something with your incoming packet handling that is not quite right yet.

Be sure that any terminal input processing (CR -> CR/LF translation, for example) is turned off.

Try to follow the check_for_packet code closely.
 

starlon

New member
This isn't working out easily on Linux.

"Pipes, FIFO's, NamedPipes?, TTY's and socket(7)'s are all objects which aren't seekable, they are just linear streams of bytes. If you try and seek on one of them you will get a ESPIPE error."


It's possible though. I've written a seekable buffer. It's having trouble keeping up in real time though. After allowing it to run for a while only reporting sensors, it's no longer reporting in real time. You can press a key and it won't be read by the program for a while. I'm not sure how I'm going to approach this yet. I tried backwards truncating the buffer, cutting off the length of incoming data. It's not enough. The code's looking great though. I did as you suggested and followed the WinTest program's packet code.
 

starlon

New member
I think I got it. I just backwards truncated buffer.data when its length was > MAX_DATA_LENGTH. It seems to be working fine now.
 

CF Tech

Administrator
OK, good I am glad you have it going.

It is a fairly lightweight protocol, on the other end is a 4-mips 8-bit micro that has a whopping 256 bytes of RAM :)

I do have a fellow that does some Python work. I can have him look at your code and offer suggestions. It you are interested, we can do that here (public) or through our ticket system (private).
 

starlon

New member
Sure I wouldn't mind some help. I don't mind doing it on the forum. There's a lot of room for improvement as I still can't get real time button presses consistently. Every now and then a button press/release is missed, especially when a lot of data's coming in, and sometimes the button presses lag a little due to the seekable buffer, but I'm not going to be playing games with this key pad. :)

I think I'm going to create a weather station. I was looking at a kit the other night.
 

starlon

New member
Here it is. There's some quirk related to the current printed messages. Or maybe I'm just tired and it's not really there. One can only dream. Bin.process_packet should be executing callbacks.
 

Attachments

starlon

New member
The following fixes that problem I mentioned.

Code:
diff -u ./old/pyCF635Driver.py ./pyCF635Driver.py
--- ./old/pyCF635Driver.py	2009-04-18 16:17:17.000000000 -0500
+++ ./pyCF635Driver.py	2009-04-18 17:29:34.000000000 -0500
@@ -28,7 +28,7 @@
 import Queue
 import gobject
 
-from CFListener import CFListener
+from CFListener import CFListener, responses
 from CFThreaded import *
 
 class Bin:
@@ -40,7 +40,7 @@
 	def add(self, command, callback, args):
 		if type(args) != type([]):
 			args = [args]
-		self.dict[command] = [callback, args, self.visitor.packet.deepcopy()]
+		self.dict[responses[command]] = [callback, args, self.visitor.packet.deepcopy()]
 
 	def process_packet(self, command):
 		print "Process packet", self.visitor.packet.command, self.dict.keys()
 

starlon

New member
This fixes issues with responses not being processed. Basically what happens is a command is queued up. Every second a command is sent out and removed from the queue. Each command has a payload consisting of a callback and optional arguments which is meant to handle the response packet. All response packets are processed universally so nothing's missed.

Let me know if you have any questions.
 

Attachments

starlon

New member
How important is the part that says wait for the response before sending another command? What I've written is entirely asynchronous and since it's buffered things seem to make it difficult to meet this specification. What I've done instead is send commands every 300mS and check to see if packets need to be resent every 500mS. I've been playing with those numbers though. It seems to do better when packets are resent later rather than sooner. I'm still not getting all of the Dallas sensors to register. Reading the LCD's text (Read8ByteMemory) seems to do better in this case as well. The drawback to sending commands so slowly is that changing the LCD's contrast and backlight is laggish.

Edit: My problems might be that I don't understand threading and pygtk's use of threading. I'm unable to produce a consumer/producer situation due to locking.
 
Last edited:

starlon

New member
Was the fan making a high pitched sound? Are you wearing hearing protection and safety glasses? :eek:

Yes, the CRC is pretty important to check an keep synchronization with the packets. Once you get your Python up, if you are interested in sharing it, we can make it a sticky in the 3rd Party Software forum.
How about this one?

Code:
Fan #: 0, Fan tach cycles: 124, MSB: 1, LSB: 1, RPM: 4381921
That packet got through the packet algorithm from WinTest somehow. It has only been happening recently and I suspect myself as the culprit somehow. Anyhow, I'm Xtreme computing so I need Xtreme cooling, no?
 

CF Tech

Administrator
The display is guaranteed to respond to a packet within 250mS, so you should be OK if you only send one packet every 300mS.

There still has to be something funky going on, especially with that weird fan packet.

If I was more familiar with Python I'd offer to look at your code, but I have never touched it, so I guess I'd be pretty useless.
 

starlon

New member
Yeah I have a couple of issues that I'll eventually work out. These fan packets just started, and I'm not sure what I could have done to cause it. I haven't touched the listener as far as I recall. They're very rare as well. Sometimes I might see a few together, but other times I don't see them at all.
 
.... They're very rare as well. Sometimes I might see a few together, but other times I don't see them at all.
I haven't looked at your code because I know squat about python, but if your 'listener' is not seeing every packet, then you are probably not parsing the input stream correctly (which would also explain the packets with bogus numbers).
 

starlon

New member
Well, I know for a fact some packets aren't seen. The buffer is only allowed to grow so large till data is discarded. I think this is the main cause of any response packets being missed and those command packets being sent back out. I'm entirely puzzled by the fan packets though. I know you guys know little about Python, but it makes a suitable pseudocode as well. I think part of my problem is Python is interpreted and a deal slower than other LCD programs. I haven't measured it yet, but there seems to be some lag caused by the buffer. That on top of the highly threaded pygtk and essentially building this project's core on top of this signal/event driven library, obviously it's not optimal for this project's nature.

Anyhow, here's the packet code, ported from 635_WinTest.

Code:
	def check_for_packet(self):
		if not self.CF635.ser: return
		self.buffer.set_current(0)
		if len(self.buffer.peek(4)) != 4: return
		self.buffer.set_current(0)
		tmp = self.buffer.peek()
		if tmp == '': return
		if MAX_COMMAND<(0x3F&ord(tmp)): 
			self.buffer.read() 
			self.tossed = self.tossed + 1
			return 
		self.packet.command = ord(tmp)
		tmp = self.buffer.peek()
		if tmp == '': return
		if MAX_DATA_LENGTH<ord(tmp):
			self.buffer.read()
			self.tossed = self.tossed + 1
			return
		self.packet.data_length = ord(tmp)
		if len(self.buffer.peek(self.packet.data_length + 2)) < self.packet.data_length + 2:
			return
		self.buffer.set_current(self.buffer.get_current()-(self.packet.data_length + 2))
		self.packet.data = self.buffer.peek(self.packet.data_length)
		self.packet.crc[0] = self.buffer.peek()
		self.packet.crc[1] = self.buffer.peek()

		if self.packet.crc.as_word() != self.CF635.getCRC('%c%c%s' % (chr(self.packet.command), chr(self.packet.data_length), self.packet.data)):
			self.buffer.read()
			self.tossed = self.tossed + 1
			return
		self.buffer.read(self.packet.data_length+4)
		self.emit('packet-ready')
		return
I'm baffled why those fan packets are getting through. It might be a race condition with self.packet being the only Packet object per device. Maybe I should isolate each packet. I hate the idea of creating an object for every single packet though. It might just be a timing issue.
 
Top