Perl - Device::SerialPort, 2-way communication
Jason Short
Posts: 21
I've been using a perl module called Device::SerialPort to glue together Macromedia Flash and my BS2 and It's been working fairly well and I now have two way communications over the web to the stamp. My issue is this: sending data to the stamp via serIn is spotty. I can read perfectly, but I can't write with any reliability. It seems to recognize my input only 50% of the time for any send.
Here is my code (just the important parts):
...
pins VAR WORD
RXData VAR BYTE
main:
SERIN 10, 84, 100, readSenors, [noparse][[/noparse]WAIT ("X"),RXData]
SERIN 10, 84, [noparse][[/noparse]DEC5 pins]
GOTO parseCommand
readSenors:
Do Stuff...
GOTO main
parseCommand:
Do Stuff...
GOTO main
I've adjusted the timeout for the SERIN and it really makes no difference
I tried this with no luck at all: (moving the DEC inline)
SERIN serInPin, 84, 100, readSenors, [noparse][[/noparse]WAIT ("X"),RXData, DEC5 pins]
From the manual's description DEC5 should work if I send this string "XD65535" but it hangs. I have found that RXData get captured, DEC5 is the section that gives me the headaches.
I've also tried this:
SERIN 10, 84, 100, readSenors, [noparse][[/noparse]WAIT ("X"),RXData]
SERIN 10, 84, [noparse][[/noparse]DEC pins]
with sending this string "XD" and then "65535A" but it was very spotty, only working 50% of the time. Again RXData gets captured every time correctly.
I'm guessing there could be two issues. One, I'm just using DEC wrong, or two, I'm sending too quickly in sequence from Perl on the PC side? Or maybe what I think I'm sending is not really the case.
Has anyone used Device::Serial before? is there anything I should know? or an easy way to test my output to the BS2 to see if the fault is on the PC side?
I'll post my Perl server when I get this figured out. It's pretty sweet and uses sockets to connect multiple clients over the internet to the BS2.
Jason
Post Edited (Jason Short) : 10/7/2005 6:21:13 PM GMT
Here is my code (just the important parts):
...
pins VAR WORD
RXData VAR BYTE
main:
SERIN 10, 84, 100, readSenors, [noparse][[/noparse]WAIT ("X"),RXData]
SERIN 10, 84, [noparse][[/noparse]DEC5 pins]
GOTO parseCommand
readSenors:
Do Stuff...
GOTO main
parseCommand:
Do Stuff...
GOTO main
I've adjusted the timeout for the SERIN and it really makes no difference
I tried this with no luck at all: (moving the DEC inline)
SERIN serInPin, 84, 100, readSenors, [noparse][[/noparse]WAIT ("X"),RXData, DEC5 pins]
From the manual's description DEC5 should work if I send this string "XD65535" but it hangs. I have found that RXData get captured, DEC5 is the section that gives me the headaches.
I've also tried this:
SERIN 10, 84, 100, readSenors, [noparse][[/noparse]WAIT ("X"),RXData]
SERIN 10, 84, [noparse][[/noparse]DEC pins]
with sending this string "XD" and then "65535A" but it was very spotty, only working 50% of the time. Again RXData gets captured every time correctly.
I'm guessing there could be two issues. One, I'm just using DEC wrong, or two, I'm sending too quickly in sequence from Perl on the PC side? Or maybe what I think I'm sending is not really the case.
Has anyone used Device::Serial before? is there anything I should know? or an easy way to test my output to the BS2 to see if the fault is on the PC side?
I'll post my Perl server when I get this figured out. It's pretty sweet and uses sockets to connect multiple clients over the internet to the BS2.
Jason
Post Edited (Jason Short) : 10/7/2005 6:21:13 PM GMT
Comments
Jason
Try this first, and see what happens:
pins VAR WORD
RXData VAR BYTE
SERIN serInPin, 84, 100, readSenors, [noparse][[/noparse]WAIT ("X"), RXData, pins]
If that goes well, then try this:
pins VAR WORD
RXData VAR BYTE
SERIN serInPin, 84, 200, readSenors, [noparse][[/noparse]WAIT ("X"),RXData, DEC 5 pins]
and if that fails, continue moving the timeout parameter upwards until it becomes reliable.
If none of that above works, drop the baud rate on both sides until you get reliable communications. Once it becomes reliable, you can consider adding any formatter(s) back in. Any formatter (DEC being one) will take a fair amount of time to execute, and that time occurs during byte fetch time; thus effectively reducing the overall potential throughput. WORD processing (verses BYTE processing) represents the worst case, since more potential digits are involved. More actual digits (in the imput stream) also exacerbates worst case scenario. By worst case here, we're saying longest processing time.
Regards,
Bruce Bates
So if you set the time-out to 100 mSecs, what you're doing is hoping that during that magic 100 mSecs you send all of your data. This could work, but if you miss part of the window, what the BS2 gets will be garbled.
So it sounds like some kind of simple hand-shake might be in order here.
Also, I think you need a 'space' character between parameters for the BS2 SERIN parsing (dividing things into parameters) to work. If you do that, "X D 65535 " should be correctly recieved by
"SERIN SerPin, 84, 200, TimeOut, [noparse][[/noparse]WAIT ("X"), RxData, DEC5 MyWord]"
Note starting a NEW 'SERIN' in the middle of a message is NOT a good idea -- the BS2 will go 'deaf' for 100 uSec or so as the second SERIN statement begins execution.
I thought that the internal SERIN timeout clock resets itself on receipt of any data, so that it won't fall to the timeout label unless there is "silence" for the timeout period. At least previous messages suggesting shorter timeout periods in noisy environments to preven "forever-waits" seem to indicate that this is the case....If that assumption is correct, then one should not have to receive all of their data within the timeout window, would they?
Seeking understanding...
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Truly Understand the Fundamentals and the Path will be so much easier...
So it's very important to send an "end of token" character -- like a space character, or a CHR(13) (aka CR, aka <carriage-return>) at the end of your string, so your last data element will be properly parsed by the SERIN command.
Some Parallax person can give us the authoritative answer on this, though.
The following comes directly from the PBASIC Help File, and should aid in understanding, but I don't consider it entirely definitive, due to its obvious brevity:
quote
result VAR Byte
Main:
SERIN 1, 16468, 2000, No_Data, [noparse][[/noparse]DEC result]
DEBUG CLS, ? result
STOP
No_Data:
DEBUG CLS, "Timed out"
STOP
If no data arrives within 2 seconds, the program aborts SERIN and continues at the label No_Data.
Here's a very important concept: this timeout feature is not picky about the kind of data SERIN receives; if any serial data is received, it prevents the timeout. In the example above, SERIN wants a decimal number. But even if SERIN received letters "ABCD..." at intervals of less than two seconds, it would never abort.
end quote
Regards,
Bruce Bates
'my front door filter
SERIN serInPin, 84, 100, readSenors, [noparse][[/noparse]WAIT ("X")];
'get perl to block until reply for .5 seconds at least
' send out an X to perl
SEROUT serOutPin, 84, [noparse][[/noparse]"X"]
'when perl gets the X it knows it can send in the clear, and the BS2 blocks
SERIN serInPin, 84, [noparse][[/noparse]WAIT ("X"), DEC5 pins];
'once perl sends the data it resumes normal operation
SERIN serInPin, 84, [noparse][[/noparse]RXData, DEC pins]
I send this string "A 125 A" and it hangs waiting for a number
I send this string moments later "255 A" and DEC catches the 255 and continues. 125 was lost or ignored in the first place.
in the manual I see a very complex input style:
SERIN 1, 16468, [noparse][[/noparse]WAIT("pos: "), DEC yOffset, DEC4 yOffset]
No matter how I craft the input stream I don't seem to be able to replicate it.
Is there a preferred character to trigger the DEC formatter?
Again, if you want to get stuff from a SINGLE STRING, don't use two SERIN's to get it.
You might try sending "A<CR>125<CR>", and see if [noparse][[/noparse]RXData, DEC Pins] gets the data.
(where "<CR>" is replaced by a single carriage return character, of course. You don't actually send the "<", then "C", etc.)
It almost seems as if you're testing SERIN to see if you can make it fail. Now that you see it can and will fail when the WRONG data is sent to it; wrong in the sense that it's not how you described it, you might want to send it proper data, and see what it will do. Here is a set of data that should work first time and every time:
Data based on a SERIN structured like this:
SERIN serInPin, 84, [noparse][[/noparse]RXData, DEC5 pins]
Data:
A1 <CR>
B12 <CR>
C123 <CR>
D1234 <CR>
E12345 <CR>
Let us know how you make out with that.
Regards,
Bruce Bates
at least dec now works!
SERIN serInPin, 84, [noparse][[/noparse]RXData, DEC pins]
send the string "X\r255\r" ( \r being a Perl escape for a return)
I couldn't find the preference for certain characters in the manual but CR and LF work really well and they must be before and after.
I'm still wrestling with the timeout killing my data transfer.
anything less than 500ms will start garbling my data occasionally. 10ms will garble it every time.
main:
SERIN serInPin, 84, 50, readSenors,[noparse][[/noparse]RXData] ' any data garbled or not will trip this front door 90% of the time
SEROUT serOutPin, 84, [noparse][[/noparse]"X"] ' send Perl an OK to send the real data
SERIN serInPin, 84, 5000, main, [noparse][[/noparse]RXData, DEC pins] ' receive the data
SEROUT serOutPin, 84, [noparse][[/noparse]"Y"] ' let perl know we've read it ok, or have perl try again
goto parsecommand
I've not lost any data yet with this method.
Jason
Could you post the procedure you're using in perl for the serial port? I may want to try that. My TCL code is getting me nowhere. TCL is not known for playing with serial ports well and I know perl can be used with TK. Thanks.
Note that a 5000 mSec timeout (5 seconds) will terminate almost immediately once the data has been recieved, so you're not really slowing your program down there -- unless of course the data sender has been hosed -- in which case you have a 5 second delay before you detect that, which shouldn't be a problem.
And yes, it's not obvious that "\r" is a token terminating character that SERIN likes.
I've used IO:Select to manage the file handles
and IO::Socket to manage the networking.
The Serial port is converted into a file handle and added to a set of file handles within the Select Object
Select then magically chooses the file handles that have information ready to read and therefor eliminates any blocking.
Using this method I can get as many clients to connect to the BS2 over the net as I want.
Run the server by typing "perl serialToFlash.pl" (optionally add a " &" at the end to make it run independently as a process in UNIX.)
Connect to it with telnet and send commands formatted like this: "code:number". As it is written for my needs, Perl parses the command and formats it for the serial connection to the BS2. You could do any parsing or none if you don't need to. In my example the number represents a Bitmask of output to be set to High or Low. "H:255" will set pins 0-7 to high, "L:24" will set pins 3 and 4 to low. I'm using the XMLSocket object within Flash to connect to the server.
note: be sure to include the port number with telnet command i.e. telnet 192.168.10.127 7070
There is a loop that ensures the data sent to the BS2 is received but it is not error checking, only an "OK" that the DEC read the value. Error checking could be added really easily though.
Also note everything is "event based" meaning only changes are sent over the network. That's why I needed the fast timeout in the command parsing loop. I wanted button presses to be sensed almost immediately but still maintain optimum 2-way communication on a single stamp.
Jason
Post Edited (Jason Short) : 10/7/2005 6:22:50 PM GMT