|
Post by tsh73 on Nov 7, 2020 17:04:48 GMT -5
RealTerm has no idea about data being 17 characters so probably for it data appear on port at once Is it always 17 byte? Then you just read 17 bytes, - or spit next 17 bytes from double buffer, no matter what, no sentinels needed. (or it could be different - 17 or 15 bytes, as you said in first post?)
|
|
|
Post by johnking on Nov 8, 2020 7:21:12 GMT -5
Thanks for all your comments, and I apologize if parts pf my messages were unclear. tsh73 : yes I said 15-17 bytes, it looks now as if it is 17 bytes always. Based on 17 charachters lenghth below is my best solution, it runs two loops and all measurements are printed. I am sure it is not the best approach, but it is simple. I will try again this week with the start/stop sentinels. I agree it is more reliable, but until now not much luck with that. open "com1:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port cls
print #com1, "S" 'stopcommand print #com1, "C" 'startcommand
for testloop1 = 1 to 10 'run a loop of 10 measurements for test purpose for testloop2 = 1 to 100 'run a loop of 100 measurements within the previous loop
while lof(#com1) < 17 'do nothing until 17 packets are received wend
dataread$ = input$(#com1, lof(#com1)) 'read data
'the measurement value is on position 4&5 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,4,1)) lo = asc(mid$(dataread$,5,1)) hi = (hi-2)*255 'value is in binary, convert to decimal lo=lo-88 'value is in binary, convert to decimal value = ((hi+lo)/10)+60 'value is in binary, convert to decimal
'seconds passed since start of measurement is on position 14&15 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,14,1)) lo = asc(mid$(dataread$,15,1)) hi=hi*256 secondspassed = (hi+lo)
print testloop2,secondspassed, value
next testloop2 next testloop1
[end] print #com1, "S" 'stopcommand close #com1 'close port end
|
|
|
Post by Rod on Nov 8, 2020 7:46:23 GMT -5
Fixed length messages are easier to deal with. I have made a couple of changes to the code. Firstly if you know the message is 17 bytes then always extract 17 bytes from the buffer. If you just take the whole contents of the buffer you could conceivable read in half of the next message or indeed several messages and so get out of sync. I make sure I take all the messages out the buffer by looping until there are none. Later as you develop your program you might find you branch away to do something else. Messages would accumulate in the buffer.
The while wend loop you coded is just storing up trouble for later. You are severely restricting what your multi tasking PC can do, indeed what your program can do. So a timer is a better option. Its all about keeping pace.
I have not tested my code I hope there are no bugs but the concept of extracting whole messages and timing the reading pace are sound.
open "com1:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port cls
print #com1, "S" 'stopcommand print #com1, "C" 'startcommand count=0
'set up a repeating timer event to check the buffer 'check every 100ms but messages will only appear every second timer 100,[checkbuffer] wait
[checkbuffer] 'keep count, stop at 100 checks ie 10 seconds of data count=count+1
while lof(#com1) >= 17 'grab as many 17 byte messages as are in the buffer
dataread$ = input$(#com1, 17) 'read data
'the measurement value is on position 4&5 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,4,1)) lo = asc(mid$(dataread$,5,1)) hi = (hi-2)*255 'value is in binary, convert to decimal lo=lo-88 'value is in binary, convert to decimal value = ((hi+lo)/10)+60 'value is in binary, convert to decimal
'seconds passed since start of measurement is on position 14&15 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,14,1)) lo = asc(mid$(dataread$,15,1)) secondspassed = (hi+lo)
print testloop2,secondspassed, value
if count >100 then exit while wend
[end] timer 0 print #com1, "S" 'stopcommand close #com1 'close port end
|
|
|
Post by johnking on Nov 8, 2020 8:30:51 GMT -5
Hi Rod, no this code does work straight ahead.
It read one set of data.
But I understand the concept so I have a go with it.
|
|
|
Post by tsh73 on Nov 8, 2020 16:29:15 GMT -5
I found interesting piece of software named com0com sourceforge.net/projects/com0com/I do not know if it will work for you - it works for me, but I'm still on XP It adds pair(s) of virtual COM ports, linked to each other So in my case I've got COM17 and COM18 I could open 2 hyperterminals and read/write between them Or make a program write COM17 and read COM18 (or vice versa) Here's writer - I used johnking program (changed to COM18) as reader Had to terminate it with CtrlBreak though (it wants 10x100 17-bytes packages, me pass only 10) 'sender 'com17 paired to com18 by com0com 'open "com17:19200,n,8,1" for random as #commHandle mil = 1000 timer mil, [next]
open "com17:19200,n,8,1,ds0,cs0,rs" for random as #commHandle 'due to wiki article print "Sending..."
wait
[next] nLines=nLines+1 if nLines>10 then [over]
msg$=time$();".";time$("ms")mod 1000 '12 bytes
msg$=chr$(02)+msg$ 'add msg start for i = 1 to 2 'pad top 15 charcters msg$=msg$+chr$(randRange(0, 5)) 'with random low hex next msg$=msg$+chr$(03) 'add msg end
'add checksum, code by Rod b=0 for n=1 to 16 'read in all the characters up to the check digit d$=mid$(msg$,n,1) 'read hex value d=hexdec(d$) 'convert to decimal b=b xor d 'xor all the values in the message 'print d$,d,b 'note that the final xor value is decimal 68 hex 44 'so we can calculate the checkdigit next msg$=msg$+chr$(b) #commHandle msg$; 'print msg$ for i = 1 to len(msg$) print sh$(mid$(msg$,i,1)); a = asc(mid$(msg$,i,1)) if (a=13) or (a=10) then print 'sorry CR LF does not work in a mainwin next print 'next line because messages have no CRLF wait
[over] timer 0 close #commHandle print "*done*" end
sub pause mil t0=time$("ms") while time$("ms")-t0<mil SCAN wend end sub
function sh$(a$) 'a$ is single letter sh$=a$ a = asc(a$) if a<32 then sh$="[";a;"]" end function
'***************************************************** 'function returns a random integer in range [Min, Max) function randRange(Min, Max) randRange = Min + random(Max-Min) end function
'***************************************************** 'function returns a random integer in range [0, n) function random(n) random = int(rnd(1)*n) end function
|
|
|
Post by tsh73 on Nov 8, 2020 16:53:40 GMT -5
Ok changed johnking's program I made it read exactly 10 packages and added package visualization
The thing I could not quite get - if I run sender/reader it prints every 1 second But if I run only sender part somehow it prints every 5 seconds - why?
'by johnking 08 11 2020 'added 17-byte packet display
'open "com1:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port open "com18:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port cls
'print #com1, "S" 'stopcommand 'print #com1, "C" 'startcommand
'for testloop1 = 1 to 10 'run a loop of 10 measurements for test purpose 'for testloop2 = 1 to 100 'run a loop of 100 measurements within the previous loop for testloop2 = 1 to 10
while lof(#com1) < 17 'do nothing until 17 packets are received wend
dataread$ = input$(#com1, lof(#com1)) 'read data
'the measurement value is on position 4&5 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,4,1)) lo = asc(mid$(dataread$,5,1)) hi = (hi-2)*255 'value is in binary, convert to decimal lo=lo-88 'value is in binary, convert to decimal value = ((hi+lo)/10)+60 'value is in binary, convert to decimal
'seconds passed since start of measurement is on position 14&15 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,14,1)) lo = asc(mid$(dataread$,15,1)) hi=hi*256 secondspassed = (hi+lo)
print testloop2,secondspassed, value msg$ = dataread$ 'print msg$ for i = 1 to len(msg$) print sh$(mid$(msg$,i,1)); a = asc(mid$(msg$,i,1)) if (a=13) or (a=10) then print 'sorry CR LF does not work in a mainwin next print 'next line because messages have no CRLF
'next testloop2 'next testloop1 next
[end] print #com1, "S" 'stopcommand close #com1 'close port end
function sh$(a$) 'a$ is single letter sh$=a$ a = asc(a$) if a<32 then sh$="[";a;"]" end function
|
|
|
Post by tsh73 on Nov 8, 2020 17:30:55 GMT -5
Somehow I could not make Rod's code work
I did some tweaks (may be I broke it) and now it works if I run reader first, sender second. Otherwise it drops some bytes in first package and following packages come misaligned
EDIT It looks like johnking's program show something like this as well
code tweaked, see if you see something
'by johnking 08 11 2020 ' changed by Rod 'added 17-byte packet display
'open "com1:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port open "com18:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port cls
'print #com1, "S" 'stopcommand 'print #com1, "C" 'startcommand count=0
'set up a repeating timer event to check the buffer 'check every 100ms but messages will only appear every second timer 100,[checkbuffer] wait
[checkbuffer] 'keep count, stop at 100 checks ie 10 seconds of data count=count+1 print count, time$();".";time$("ms")mod 1000, lof(#com1)
while lof(#com1) >= 17 'grab as many 17 byte messages as are in the buffer
dataread$ = input$(#com1, 17) 'read data
'the measurement value is on position 4&5 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,4,1)) lo = asc(mid$(dataread$,5,1)) hi = (hi-2)*255 'value is in binary, convert to decimal lo=lo-88 'value is in binary, convert to decimal value = ((hi+lo)/10)+60 'value is in binary, convert to decimal
'seconds passed since start of measurement is on position 14&15 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,14,1)) lo = asc(mid$(dataread$,15,1)) secondspassed = (hi+lo)
print testloop2,secondspassed, value msg$ = dataread$ 'print msg$ for i = 1 to len(msg$) print sh$(mid$(msg$,i,1)); a = asc(mid$(msg$,i,1)) if (a=13) or (a=10) then print 'sorry CR LF does not work in a mainwin next print ,"len=";len(msg$)'next line because messages have no CRLF if count >100 then exit while wend
if count >100 then [end] wait
[end] timer 0 'print #com1, "S" 'stopcommand close #com1 'close port
print "over" end
'------------------------- function sh$(a$) 'a$ is single letter sh$=a$ a = asc(a$) if a<32 then sh$="[";a;"]" end function
|
|
|
Post by Rod on Nov 9, 2020 3:38:02 GMT -5
If you are setting up to receive a stream of messages it is probably a good idea to flush the buffer, just read in whatever is there to a string and dump or ignore it, then send your start signal.. that way you should always start with a clean 17 byte message.
|
|
|
Post by tsh73 on Nov 9, 2020 13:45:11 GMT -5
It kind of worked - after dumping stuff, it reads 17-bytes portions without a hitch.
but yesterday send program (without reading part) sent lines every 5 seconds now it just waits till I start reading part.
That's really strange 'course I did not change a thing.
EDIT after I opened both ports in HyperTerminal, it started to send lines without reader every 5 second But txcount( #commHandle ) keeps saying 0 - I would expect it build up?
Interesting. Again without reader running: #commHandle msg$; takes 5 second to send #commHandle msg$ takes 15 second to send - why so?
|
|
|
Post by Rod on Nov 9, 2020 15:10:52 GMT -5
There is no real mystery to serial transfer. If the transmit buffer is empty the message has been transmitted and will accumulate in the receive buffer. Why a delay? Is the delay a one off or is every message delayed and what size is your input buffer and transmit buffer during this delay? I think we are looking at an artefact of the port software. Ports do take a few seconds to establish, once established transmission is in my experience instant.
But we stray from the original question, the answer was fixed length, sentinels were a red herring.
|
|
|
Post by johnking on Nov 14, 2020 3:48:27 GMT -5
If you are setting up to receive a stream of messages it is probably a good idea to flush the buffer, just read in whatever is there to a string and dump or ignore it, then send your start signal.. that way you should always start with a clean 17 byte message. I have tested all week with my program and Rod's program with the 'keep count' approach. I cannot get Rod's work properly using that approach. I do not know why. By running my version (below) for a week I sometimes loose a second, somewhere inbetween 0-5 times a day. Maybe this is caused by background tasks the PC has to do, allthough I am running it on a PC that does not have any other tasks besides windows tasks. I am ok with that, could include a warning if that happens. But if I would flush the buffer like Rod suggests, is my approach below (see line 3) the way to do that, so just read the port once and go on ? open "com1:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port
cls
dataread$ = input$(#com1, lof(#com1)) 'read data once and get rid of it IS THIS THE BEST WAY ??
print #com1, "S" 'stopcommand
print #com1, "C" 'startcommand
for testloop = 1 to 10 'run a loop of 10 measurements for test purpose
while lof(#com1) < 17 'do nothing until 17 packets are received
wend
dataread$ = input$(#com1, lof(#com1)) 'read data
'the measurement value is on position 4&5 in the datastring 2 bytes, first "hi" second "lo"
hi = asc(mid$(dataread$,4,1))
lo = asc(mid$(dataread$,5,1))
hi = (hi-2)*256 'value is in binary, convert to decimal
lo=lo-88 'value is in binary, convert to decimal
value = ((hi+lo)/10)+60 'value is in binary, convert to decimal
'seconds passed since start of meaurement is on position 14&15 in the datastring 2 bytes, first "hi" second "lo"
hi = asc(mid$(dataread$,14,1))
lo = asc(mid$(dataread$,15,1))
hi=hi*256
secondspassed = (hi+lo)
print testloop,secondspassed, value
next testloop
[end]
print #com1, "S" 'stopcommand
close #com1 'close port
end
|
|
|
Post by Rod on Nov 15, 2020 3:01:28 GMT -5
Yes but if it has been working for a week flushing the buffer wont make any difference. To find out what is going on you need to write the time and data to a log. It probably is windows that is tying up the processor while it virus checks or cleans the system. What is probably happening is that you are reading two messages because of windows delays but only the first is getting parsed. Thats why I loop round in 17 byte segments in my code trying to get any missed messages.
This is a start at writing a timed log, I am just trying to get the raw data as it is sent. You might need to tweak it a bit. It runs for sixty seconds you might run it for longer and see what happens when a message is missed.
open "com1:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port dataread$ = input$(#com1, lof(#com1)) 'flush the buffer #com1 "S" 'stopcommand #com1 "C" 'startcommand t=time$("ms")+60000 while time$("ms")<t if lof(#com1)>0 dataread$ = input$(#com1, lof(#com1)) 'read data print time$("ms");"received "; for n= 1 to len(dataread$) print asc(mid$(dataread$,n,1);":"; next print end if wend
[end] #com1 "S" 'stopcommand close #com1 'close port end
|
|
|
Post by Rod on Nov 16, 2020 15:25:53 GMT -5
In your last code you wait till the buffer has at least 17 bytes, what if it has 34? A quick check would be to print the length of dataread$ as you parse it. That may show your missing messages.
|
|
|
Post by johnking on Jan 25, 2021 14:13:32 GMT -5
An update:
the program has been running since november in long sessions without missing any data. So I post my final code for others to use it.
'Bureau Geluid nl 'Cesva RS-60 seconde data opvragen via seriele poort
open "com1:19200,n,8,1,ds0,cs0,rs" for random as #com1 'open port cls
print #com1, "S" 'stopcommand print #com1, "C" 'startcommand
for testloop = 1 to 1000 'loopcounter to run a loop of 1000 measurements, make it larger if you want to take more measurements
while lof(#com1) < 17 'do nothing until 17 packets are received wend
dataread$ = input$(#com1, lof(#com1)) 'read data
'the measurement value is on position 4&5 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,4,1)) lo = asc(mid$(dataread$,5,1)) hi = (hi-2)*256 'value is in binary, convert to decimal lo=lo-88 'value is in binary, convert to decimal value = ((hi+lo)/10)+60 'value is in binary, convert to decimal
'seconds passed since start of meaurement is on position 14&15 in the datastring 2 bytes, first "hi" second "lo" hi = asc(mid$(dataread$,14,1)) lo = asc(mid$(dataread$,15,1)) hi=hi*256 secondspassed = (hi+lo)
'use the value for the loopcounter and the value for secondspassed to check if data is missing 'if the value for test = 0 then no data is missing 'if the value for test = 1 then data has been missed, since the loopcounter and secondspassed value must remain the same
if testloop = secondspassed then test=0 if testloop < secondspassed then test=1 if testloop > secondspassed then test=1
print testloop,secondspassed, value, test
next testloop
[end] print #com1, "S" 'stopcommand close #com1 'close port end
|
|