# Oshonsoft programs with INTERRUPTS and PARSE

#### camerart

Joined Feb 25, 2013
2,082
Here you go.
Note that at the top you see:
The active setting speeds up the timers for use in the sim. Bigger number is slower timers.
Comment that out and uncomment the line above to set PR2 to 250 for the live version.

This code uses TIMER2 to generate an interrupt every 20ms. It drives a set of timers from that interrupt.
Each timer is one byte that counts from whatever value you set (0-255) down to 0 then stops at 0. Each timer is used as a guard timer on various info.

To know if a timer has timed out, just read it and test for 0 as you see in main_loop.

There are 2 periods in use:
20ms/count for the UART receive guard timer. This timer is set and begins to run whenever setUARTchannel is called to select a new channel. The default time is 5secs.
Main waiting for new sentence OR timeout:
    waitBuf:
If buf_done = 0 Then
'Other processing..
If ms20_RXguard = 0 Then
Goto sentence_done
Endif
Goto waitBuf
Endif

'Sentence is received, proceed to parsing it
'Since parsing SHARES some variables with the IRQ service, you can't begin
'looking for the next sentence until parsing is complete.
Gosub parse  'parse the received sentence

'Process any new data from parseing (while new sentence is being received)
If prsed_GNRMC = 1 Then
Hserout "T=", strtim, " N=", strlat, " W=", strlong, CrLf  'process new data
prsed_GNRMC = 0  'and clear flag to indicate that new data has been "processed"
Endif

If prsed_QEIDEG = 1 Then
Hserout "QEIDEG=  ", qeideg, CrLf  'QEIDEG=BASE 4431 Opto encoder
prsed_QEIDEG = 0
Endif

If prsed_REMOTE = 1 Then
Hserout "REMVOLT=", strremvolt, " REMALT=", strremalt, " REMDIST=", strremdist, CrLf
prsed_REMOTE = 0
Endif

If prsed_GOOD = 0 Then  'parse tried but string was unknown, corrupt or wrong length
Hserout "Parse fail Chan: ", #datasw, CrLf
Endif

'-------------- SENTENCE PROCESSING COMPLETE  ---------------
'Done receiving, parsing and processing ONE sentence.
sentence_done:
Gosub next_channel  'select next channel
Gosub setUARTchannel  'start UART on channel(datasw), begins looking for sentence

Goto main_loop
Suppose the $GNRMC sentence is sent 2 times a second. A minimum timer setting would be: 2x 46.8ms (45 characters at 1.04ms/char at 9600baud) + 500ms (time between sentences) + 20ms (timer uncertainty). = 613.6ms. Rounding up to the timer period you get 620ms. The timer setting is then 620ms/20ms = 31. So with those assumptions on the worst case, you wait up to 620ms for any sentence, not my overly generous 5 sec. How can that be better? • Decrease the TX time between sentences to the minimum available for all of them. • The guard timer can be set to different values for each channel by moving where we set it to the individual channel set code. No sense in waiting the worst case sentence if others are faster. • Decrease the timer period. If we're not waiting 5 sec for a sentence, we can run the 8bit timer faster for finer resolution. • Determine what the inter-sentence time is based on. I assumed the worst case last character to next$. It may be time between the $of successive sentences. That would shorten the guard time by a sentence length. That also could be different for each channel. • Relocate the channel switch for the next sentence to just after the return from parse. That way, it can start looking for the next sentence while you process the new sentence and do whatever else you need. No sense in leaving the receiver idle when it could be getting the next sentence in the background In a nutshell, I set the times very long so that we wouldn't be tripped up by timeouts while verifying other stuff. If we're ready to tune the timers, let me know what you think the max wait time for each sentence should be. Onward! Hi JT, If I'm reading my oscilloscope correctly, the length of the longest$sentence (GPS) is 70ms and the gap till the next $is 130ms so total 200ms and as it is set to 5xsec this adds up. The QEIDEG sentence will always be the same length, but the REMOTE is an example for testing, I'm not sure what that will be until working on the REMOTE. Both of these are sent 5Xsec also. Regarding your comment in #306, you mention a COMPASS, there is a COMPASS peripheral (SPI), but the Degrees we're talking about here is from an incremental encoder on 18F4431 which is a dial on the transmitter, where a bearing can be steered. C. Last edited: #### JohnInTX Joined Jun 26, 2012 4,214 OK so we'll set the$GNRMC RX guard time to 300ms - 200ms between the $and 45ms for the message. Note that even if the message length is 70ms, we are only reading until the "W" which shortens it. Changing the REMOTE format is OK. You'll of course need to update 'parse' to extract the various bits. What is the rep rate of the other two sentences? I'll update those times and send something to you. Thread Starter #### camerart Joined Feb 25, 2013 2,082 OK so we'll set the$GNRMC RX guard time to 300ms - 200ms between the $and 45ms for the message. Note that even if the message length is 70ms, we are only reading until the "W" which shortens it. Changing the REMOTE format is OK. You'll of course need to update 'parse' to extract the various bits. What is the rep rate of the other two sentences? I'll update those times and send something to you. Hi JT, I tried 25 instead of 250, which I think '=' 1/2 sec and it seemed to work ok. I switched off/on the REMOTE TX from the computer. With the GPS, the$GNRMC sentences @5/sec, if we miss the 1st digit of a message and go to the W in the next, I assume it would see:
$GNRMC,123456.00,A,1234.76019,N,01234.93717,W,0.301,,150620,,,A*7E........................................................ ............................................................$GNRMC,123456.00,A,1234.76019,N,01234.93717,W
,0.301,,150620,,,A*7E

All sentences repeat @5/sec.
C

#### JohnInTX

Joined Jun 26, 2012
4,214
Hi JT,
I tried 25 instead of 250, which I think '=' 1/2 sec and it seemed to work ok. I switched off/on the REMOTE TX from the computer.

With the GPS, the $GNRMC sentences @5/sec, if we miss the 1st digit of a message and go to the W in the next, I assume it would see:$GNRMC,123456.00,A,1234.76019,N,01234.93717,W,0.301,,150620,,,A*7E........................................................
............................................................$GNRMC,123456.00,A,1234.76019,N,01234.93717,W ,0.301,,150620,,,A*7E All sentences repeat @5/sec. C Correct! So the elapsed time for the two sentences in red is 200ms (5/sec) + 1.04ms * 45 (the number of characters in the 2ed 'good' one.) I'd round it up to 300ms for now. The timing would be essentially the same for the other two, a little shorter because of fewer characters in the sentence. I am detailing the timers to offer better resolution and will post when tested. When done, that will pretty much finish this phase i.e. getting the communications robust and properly parsed into strings. There are some detail performance improvements we can contemplate before tying a bow on it: We should move the 'next channel' selection to right after parse so that it can receive while you are processing the previous message. You should realize that Hserout is a 'blocking' routine i.e. it hogs the CPU for roughly 1.04ms per character sent. If that is an issue, we can address it. You can get some immediate benefit by being less verbose in your readouts. As long as you are sending all of that info back to the PC, you will be missing the occasional REMOTE message because of the half-duplex nature of the comms link. Is that going to be a problem? Let me know what you think about those questions. JinT #### JohnInTX Joined Jun 26, 2012 4,214 I detailed the various timers for better resolution. Timers are running at actual speed (not sped up for sim). We should move the 'next channel' selection to right after parse so that it can receive while you are processing the previous message. Done. See the notes. Have fun! #### Attachments • 17.7 KB Views: 2 Thread Starter #### camerart Joined Feb 25, 2013 2,082 I detailed the various timers for better resolution. Timers are running at actual speed (not sped up for sim). Done. See the notes. Have fun! Hi JT, For my scanning preferences, I try to keep things as flowing as possible, and of course had to accept the fact that e,g, [Hseropen 9600] needs to be in a certain order with [RCSTA.CREN = 0] as you explained. For me, I prefer the [On High Interrupt] to be top of the SUBROUTINES, then each [GOSUB/CALL ROUTINE] in order of use below their [GOSUB/CALL] If that's ok with you, I can re-order them, but again of course, if it is poor programming then I'll accept them as you place them. It would also be safer for you to move them, in case of me confusing the situation, but I'm happy to do it. NOTE: Oshonsoft requires the END before any SUBROTINES/INTERRUPTS. -------------------------------------------------------------------------------------------------------- "Correct! So the elapsed time for the two sentences in red is 200ms (5/sec) + 1.04ms * 45 (the number of characters in the 2ed 'good' one.) I'd round it up to 300ms for now." I'm not as good at calculations as you are, and I've spent my life guessing. Regarding the length of time to wait, if there is no signal: My logic is, that if there is no signal, there won't be a '$' within 1.5 %sentences, so 300ms, any longer is slowing down the other 2x % sentences till a signal is received. So I would guess 300ms for the timer, would be better, any thoughts? If it helps, I think that only 1x

I note this latest program is LIVE. I've just tried it and if you recall previously, the $GNRMC Sentence PARSED at 1x sometimes 2x/sec, and now mostly being PARSED 2x/Sec, so improvement there. ----------------------------------------------------------------------------- "You can get some immediate benefit by being less verbose in your readouts. " Will you clarify please? -------------------------------------------------------------------------------------- "As long as you are sending all of that info back to the PC, you will be missing the occasional REMOTE message because of the half-duplex nature of the comms link. Is that going to be a problem? " Looking at the Terminal view, the$GNRMC sentences seem more successful than the REMOTE sentences. I can't tell with the QEIDEG sentence. I don't think it will be a problem when flying, as the REMOTE messages will be things like battery voltage, and perhaps temperature, which change slowly. QEIDEG knob will be turned pretty slowly I think, you didn't mention QEIDEG, but I don't thnk it will be a problem.
Well done again. What colour will the bow be? A small thing, but if we are using BST, then the Day will be before the month, so 140720. which of course is the correct way round.

EDIT: I just ran the #328 program, with REMOTE OFF, and tried to keep up counting the other two $Sentences using the LEDS, and it was >110/Sec. C. Last edited: #### JohnInTX Joined Jun 26, 2012 4,214 I think the 300ms is fine for sentences at 5/sec. You could tighten it up a bit but at this point, I'd leave it at that. Re: LIVE. I said that because the PR2 setting for the TIMER2 system tik was set to the LIVE value instead of the shorter value for the sim. BUT, I forgot about the OSH define that shortened delays for the sim. That was left enabled so there might be some issues there. To mitigate problems like that, I like to put ALL of the things that are target related (sim or LIVE PCB) near the top of the source file so that I don't miss things like that. Re: less verbose readouts. Hserout waits on each character to be fully sent before it returns. At 9600 baud, each character is about 1msec. So for timing purposes, sending a 30 character message to the PC has the same timing as dropping a Waitms(30) into your code. It's actually a little worse when you include overhead but you get the idea. My point was that we've sped this thing up considerably and now things like Hserout can be a factor in the total processing time. There are ways to beat that if the delay from the reports to the PC are an issue. But shortening the number of characters sent is a cheap way to make that part of the code run faster if that becomes an issue. If it's fast enough now, just make a note of this discussion and continue on. Re: REMOTE readouts. There's not much we can do to fix the lost messages due to the half-duplex radio. I thought up a way to synchronize a timer to the REMOTE message to figure out when it might be using the radio but it's not trivial and best left alone unless you have a compelling reason. But since REMOTE doesn't have fast changing information, you could keep the other stuff more current by only selecting and processing$REMOTE once in awhile rather than a round-robin deal. The code is currently structured to make that not too hard to do. You could specify the channels in a string that indicated the order to look for sentences:
"020202021" Alternate between 0 and 2 4 times then get REMOTE.
OR
"000010002" Get channel 0 mostly and poke in 1 and 2 once in awhile as needed.
Using a string allows you to rework the scheduling just by re-typing the string. Nice.

Organizing the source code: Sure. Move the blocks around to make yourself comfortable. As you've seen, I am visually organized and like lots of space and delimiters. I try to write so that each function or routine fits on one screen or close to it. I would consider using OSH's INCLUDE directive to move all of the support functions to another file and just have the declarations and main loop in the main file. That way, you treat those other functions as black-boxes that just do helpful things and you can concentrate on your main code flow. But it's completely up to you. You will be integrating this back into your other code and need to be able to manage that so have at it.

BST: sure, I didn't recall your method of time and was too lazy to look it up.

So.. I'm thinking this is about ready to kick loose? If not, what's left?
J

#### camerart

Joined Feb 25, 2013
2,082
I think the 300ms is fine for sentences at 5/sec. You could tighten it up a bit but at this point, I'd leave it at that.

Re: LIVE. I said that because the PR2 setting for the TIMER2 system tik was set to the LIVE value instead of the shorter value for the sim. BUT, I forgot about the OSH define that shortened delays for the sim. That was left enabled so there might be some issues there. To mitigate problems like that, I like to put ALL of the things that are target related (sim or LIVE PCB) near the top of the source file so that I don't miss things like that.

Re: less verbose readouts. Hserout waits on each character to be fully sent before it returns. At 9600 baud, each character is about 1msec. So for timing purposes, sending a 30 character message to the PC has the same timing as dropping a Waitms(30) into your code. It's actually a little worse when you include overhead but you get the idea. My point was that we've sped this thing up considerably and now things like Hserout can be a factor in the total processing time. There are ways to beat that if the delay from the reports to the PC are an issue. But shortening the number of characters sent is a cheap way to make that part of the code run faster if that becomes an issue. If it's fast enough now, just make a note of this discussion and continue on.

Re: REMOTE readouts. There's not much we can do to fix the lost messages due to the half-duplex radio. I thought up a way to synchronize a timer to the REMOTE message to figure out when it might be using the radio but it's not trivial and best left alone unless you have a compelling reason.

But since REMOTE doesn't have fast changing information, you could keep the other stuff more current by only selecting and processing $REMOTE once in awhile rather than a round-robin deal. The code is currently structured to make that not too hard to do. You could specify the channels in a string that indicated the order to look for sentences: "020202021" Alternate between 0 and 2 4 times then get REMOTE. OR "000010002" Get channel 0 mostly and poke in 1 and 2 once in awhile as needed. Using a string allows you to rework the scheduling just by re-typing the string. Nice. Organizing the source code: Sure. Move the blocks around to make yourself comfortable. As you've seen, I am visually organized and like lots of space and delimiters. I try to write so that each function or routine fits on one screen or close to it. I would consider using OSH's INCLUDE directive to move all of the support functions to another file and just have the declarations and main loop in the main file. That way, you treat those other functions as black-boxes that just do helpful things and you can concentrate on your main code flow. But it's completely up to you. You will be integrating this back into your other code and need to be able to manage that so have at it. BST: sure, I didn't recall your method of time and was too lazy to look it up. So.. I'm thinking this is about ready to kick loose? If not, what's left? J Hi JT, Re: REMOTE readouts. In the Terminal we can see all of the REMOTE sentences being TX, but we can't see the other two types, and I think it may be an optical illusion, that we're missing sentences. e,g, I mostly see 2x$GNRMC sentences, but there are 5x sent.

Re: INCLUDE There is an INCLUDE in the FULL program, for screen text, but I don't need to see it, for programming. It will be a good idea later.

Re: Other Timing issues. I'll try to remember what you say, regarding trimming sentences etc.

As for BST, It's just the way I save PIC programs, I wouldn't say you are lazy

I'm eager to "Kick loose" I'll move a few blocks around to help me scan, and hope I don't damage anything. I can always return to the #328

I see ['Other processing here] is this where the FULL program MAIN LOOP goes?
C.

Code:
main_loop:  '/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

waitBuf:
If buf_done = 1 Then  'If got A sentence, parse it
Goto do_parse
Endif

If ms05_RXguard = 0 Then  'If timeout, change channels
Gosub next_channel
Gosub setUARTchannel
Endif

'Other processing here
Goto waitBuf  'loop until something happens

'Sentence is received, proceed to parsing it
'Since parsing SHARES some variables with the IRQ service, you can't begin
'looking for the next sentence until parsing is complete.
do_parse:
Gosub parse  'parse the received sentence

Gosub next_channel  'select next channel before processing
Gosub setUARTchannel  'start UART on channel(datasw), begins looking for sentence

'Process any new data from parseing (while new sentence is being received)
If prsed_GNRMC = 1 Then
Hserout "T=", strtim, " N=", strlat, " W=", strlong, CrLf  'process new data
prsed_GNRMC = 0  'and clear flag to indicate that new data has been "processed"
Endif

If prsed_QEIDEG = 1 Then
Hserout "QEIDEG=  ", qeideg, CrLf  'QEIDEG=BASE 4431 Opto encoder
prsed_QEIDEG = 0
Endif

If prsed_REMOTE = 1 Then
Hserout "REMVOLT=", strremvolt, " REMALT=", strremalt, " REMDIST=", strremdist, CrLf
prsed_REMOTE = 0
Endif

If prsed_GOOD = 0 Then  'parse tried but string was unknown, corrupt or wrong length
Hserout "Parse fail Chan: ", #prsed_ERRchan, CrLf
Endif

'-------------- SENTENCE PROCESSING COMPLETE  ---------------
'Done receiving, parsing and processing ONE sentence.
sentence_done:
Goto main_loop

End  'don't really need this as main stays in a loop

#### camerart

Joined Feb 25, 2013
2,082
Hi JT,
I re-arranged it slightly, and don't think I broke anything.

I tried in in SIM, but with the LIVE DATASWITCH acting differently from the SIM one, I don't think it SIMs correctly. I think a special long string of good and bad $sentences has to be made, that is exactly timed for the SIM. Anyway, it mostly SIMs, with a bit of coaxing, not your fault. I had job following it, with you're clever bits in it, but I could generally see it is good. LIVE it works really well. I think it may be time to add it into the FULL program. Note my last message. Cheers, C #### JohnInTX Joined Jun 26, 2012 4,214 Re: REMOTE readouts. In the Terminal we can see all of the REMOTE sentences being TX, but we can't see the other two types, and I think it may be an optical illusion, that we're missing sentences. e,g, I mostly see 2x$GNRMC sentences, but there are 5x sent.
I don't think it's an illusion, you really are 'missing' some sentences but that's the nature of the beast when you share the UART between 3 sources.
As a rough analysis consider that you are slicing one second of time into 5 slices each 200ms long (all sentences sent at 5/sec). The first sentence received occupies one of those slices. The other two use two more slices, leaving two left. The first sentence uses one of those leaving one for the next sentence. That uses up all of the slices in one second. Now, how many times did the first sentence get received in that full second of time? Two times, yes. So.. that's what you are seeing. It's the nature of the beast.
I see ['Other processing here] is this where the FULL program MAIN LOOP goes?
Depends. This little work of art we've done here is primarily concerned with receiving and parsing sentences. It also does some processing of data received in a newly received sentence. I would think a good organization would be:
While waiting on new data
do things that use the current data - flight controls etc.
parse that data fully into 'current' data INCLUDING any string to numeric variable conversion
Loop back to the top

As a general rule:
If the processing to be done is a direct result of a new sentence with the goal of updating system variables, put that code between the return from parse and the loop back to main_loop.
If it is something else, put it where it says Other Processing Here.

I think...

Give it a shot and see how that works.
EDIT: was typing when you posted #322. Glad it's working well LIVE. Glad also that you were able to follow my code including the 'clever bits'.
Carry on!

#### camerart

Joined Feb 25, 2013
2,082
I don't think it's an illusion, you really are 'missing' some sentences but that's the nature of the beast when you share the UART between 3 sources.
As a rough analysis consider that you are slicing one second of time into 5 slices each 200ms long (all sentences sent at 5/sec). The first sentence received occupies one of those slices. The other two use two more slices, leaving two left. The first sentence uses one of those leaving one for the next sentence. That uses up all of the slices in one second. Now, how many times did the first sentence get received in that full second of time? Two times, yes. So.. that's what you are seeing. It's the nature of the beast.
Depends. This little work of art we've done here is primarily concerned with receiving and parsing sentences. It also does some processing of data received in a newly received sentence. I would think a good organization would be:
While waiting on new data
do things that use the current data - flight controls etc.
parse that data fully into 'current' data INCLUDING any string to numeric variable conversion
Loop back to the top

As a general rule:
If the processing to be done is a direct result of a new sentence with the goal of updating system variables, put that code between the return from parse and the loop back to main_loop.
If it is something else, put it where it says Other Processing Here.

I think...

Give it a shot and see how that works.
EDIT: was typing when you posted #322. Glad it's working well LIVE. Glad also that you were able to follow my code including the 'clever bits'.
Carry on!
Hi JT,
I think it was my incorrect use of the word illusion, but I think it is exactly as you say.

As you say, I'll give it a shot. I'll do it as best as I can and put each section in blocks, to that it can be changed. For me this is an unknown 'adventure' so who knows what will happen. We can always drop back and start again with todays programs, I'm quite used to back tracking, and repairs.