Using Loops in CRBasic to Prevent Unnecessary Skipped Scans

by Gary Roberts | Updated: 05/31/2017 | Comments: 0

Search the Blog


Subscribe to the Blog

Get an email when a new article is posted. Choose the topics that interest you most.


Area / Application

Product Category

Activity

Corporate / News

Enter your email address:



Suggest an Article

Is there a topic you would like to learn more about? Let us know.

Leave this field empty

Do/Loop with some program code

Maybe you’re like me when it comes to skipped scans. I have always disliked seeing skipped scans in my data loggers. I have been trained to watch out for them and do my best to write my CRBasic programs in a way that makes them not appear. The Campbell Scientific Support and Implementation Engineers (formally known as Application Engineers or AEs) tell me that skipped scans are a sign of trouble in my system. When I see them, something is amiss, and I need to do some maintenance on my station before I lose too much of my data.

Skipped scans, when used this way, are a good thing, right? They let us know that something is wrong.

Skipped scans sometimes tell us that we have an SDI-12 sensor that is no longer responding correctly or in the amount of time that we expected it to. Skipped scans can also tell us that some TCP/IP functions, such as EmailSend() or FTPClient(), are taking too long or are not working as they should be. That is great diagnostic information for us to use. (Read the "Tips and Tricks: Skip Skip Hooray [Not]" article for more information.)

The main scan, and each slow sequence (up to four in a CRBasic program), has a record in the Status table showing how many times the data logger was unable to complete a scan. The row named SkippedScan in the Status table tells us how many times the main scan was not fully completed. The SkippedSlowScan(x) rows tells us the same thing for each slow scan (“x” being the number of the slow scan it is associated with).

SkippedScan 0
SkippedSystemScan 0
SkippedSlowScan(1) 0
SkippedSlowScan(2) 0
SkippedSlowScan(3) 0

So, as a station or system operator, keeping track of skipped scans can be very beneficial.

Avoiding False Skipped Scans

There are ways that we can programmatically keep these vital statistics clean while still having the data logger do what it needs to do without it giving a false skipped scan.

What do I mean by that? Let me give you an example.

Using the EmailRelay() Function

Recently, Campbell Scientific added a new function called EMailRelay(). (You can learn more about it in the “Sending Email from Your Data Logger Just Got Easier” blog article.) It gives you the ability to send an email or text message to your users without having to go through all the headache of setting up email accounts or working with your IT staff to get access to the office email system. It is a great little function that helps you send out alerts quickly. 

Campbell Scientific Support and Implementation Engineers recommend that CRBasic programmers add this function into one of the slow sequences in their programs. Why? Because there are times (depending on network speed, server load, etc.) that the EmailRelay() function might take longer to run than was originally expected. Maybe longer than the slow sequence’s scan interval. When it does run longer, it might hang up long enough that the scan it is in runs into the next scan interval, causing the data logger to log a skipped scan.

Is this something that we need to be bothered with? In this case, if EmailRelay() is the only function running in the slow sequence, no. Nothing was messed up. The data logger could send the alert it needed to. It just took longer than expected to send it.

We will still get a skipped scan. In LoggerNet, it will show up in red in the Station Status of the Connect screen. (Watch the "Connect Window Tutorial" for more information.) It is going to annoy us and want us to do something about it. In this case, there is nothing neither we nor the data logger can fix that we have control over.

So how do we get around this? We don’t want to be presented with skipped scans when there isn’t an error that we need to deal with. How do we only see skipped scans in the Status table when there really is something going wrong with our system?

Using a Do/Loop Instruction

This is where a Do/Loop instruction instead of a Scan/NextScan in a slow sequence is very helpful.

For example, we may have a simple CRBasic program using EmailRelay() that looks something like this:


'Main program variables
Public battery_voltage
Public panel_temperature
Public temperature

'EmailRelay() constants
Const _EMAIL_ATTACHMENT = ""
Const _EMAIL_SUBJECT = "Email Message"
Const _EMAIL_TO_ADDRESS = "some.user@campbellsci.com"
Const _CR_LF = CHR(13) & CHR(10)

'EmailRelay() variables
Public email_message As String * 300
Public email_relay_server_response As String * 100
Public email_trigger As Boolean
Public email_tx_success

BeginProg
	Scan (1,Sec,3,0)
		Battery (battery_voltage)
		PanelTemp (panel_temperature,250)
		TCDiff (temperature,1,mV2_5C,1,TypeT,panel_temperature,True ,0,250,1.0,0)
    
		If temperature > 30 Then 
			email_trigger = True
		EndIf
	NextScan

	SlowSequence
		Scan(1,sec,1,0)
			If email_trigger = True Then
				email_trigger = False 'reset my trigger
				email_message = "Warning!" & _CR_LF & _CR_LF
				email_message = email_message & "This is a automatic email message from the datalogger station " & Status.StationName & ". "
				email_message = email_message & "An alarm condition has been identified." & _CR_LF
				email_message = email_message & "The temperature is " & temperature & " degrees C." & _CR_LF 
				email_message = email_message & "Datalogger time is " & Status.Timestamp
				email_tx_success = EmailRelay (_EMAIL_TO_ADDRESS,_EMAIL_SUBJECT,email_message,email_relay_server_response,_EMAIL_ATTACHMENT)
			EndIf
		NextScan
EndProg

When this program is running and the temperature gets higher than 30 degrees Celsius, the data logger trips the alarm by setting the email_trigger variable to True. In the slow sequence, which is running a scan of every second, the EmailRelay() instruction runs. EmailRelay() definitely will take longer than one second to send the email message. In fact, it could take up to 70 seconds if the data logger cannot talk to the EmailRelay server. In either case, the data logger will record skipped scans for the first slow sequence regardless of whether EmailRelay() is successful or not.

So let’s put EmailRelay() into a Do/Loop instead and use CRBasic to tell us when EmailRelay() did not work:


'Main program variables
Public battery_voltage
Public panel_temperature
Public temperature

'EmailRelay() constants
Const _EMAIL_ATTACHMENT = ""
Const _EMAIL_SUBJECT = "Email Message"
Const _EMAIL_TO_ADDRESS = "some.user@campbellsci.com"
Const _CR_LF = CHR(13) & CHR(10)

'EmailRelay() variables
Public email_message As String * 300
Public email_relay_server_response As String * 100
Public email_relay_results_human_readable As String * 100
Public email_trigger As Boolean
Public email_tx_success

BeginProg
	Scan (1,Sec,3,0)
		Battery (battery_voltage)
		PanelTemp (panel_temperature,250)
		TCDiff (temperature,1,mV200C,U1,TypeT,panel_temperature,True ,0,250,1.0,0)
    
		If temperature > 30 Then 
			email_trigger = True
		EndIf
	NextScan

	SlowSequence
		Do
			If email_trigger = True Then
				email_trigger = False 'reset my trigger
				email_message = "Warning!" & _CR_LF & _CR_LF
				email_message = email_message & "This is a automatic email message from the datalogger station " & Status.StationName & ". "
				email_message = email_message & "An alarm condition has been identified." & _CR_LF
				email_message = email_message & "The temperature is " & temperature & " degrees C." & _CR_LF 
				email_message = email_message & "Datalogger time is " & Status.Timestamp
         
				'1st attempt
				email_tx_success = EmailRelay (_EMAILTO_ADDRESS,_EMAIL_SUBJECT,email_message,email_relay_server_response,_EMAIL_ATTACHMENT)
         
				'If EmailRelay was not successful, let us try one more time.
				If email_tx_success <> -1 Then
					'2nd attempt
					email_tx_success = EmailRelay (_EMAIL_TO_ADDRESS,_EMAIL_SUBJECT,email_message,email_relay_server_response,_EMAIL_ATTACHMENT)
				EndIf
         
				'tell my human what happened with EmailRelay in human speak instead of loggerspeak
				'  my user got this information from the CRBasic help for EmailRelay
				Select Case email_tx_success
				Case -1
					email_relay_results_human_readable = "EmailRelay server received the message from the datalogger successfully!"
				Case 0
					email_relay_results_human_readable = "The connection to the EmailRelay server failed."
				Case -2
					email_relay_results_human_readable = "Execution of the EmailRelay function did not occur due to lack of records or not enough time."
				Case -3
					email_relay_results_human_readable = "A connection to the EmailRelay server was made but there was an error in communication."
				EndSelect    
			EndIf
		Loop
EndProg

By putting EmailRelay() in a Do/Loop instead of a Scan/NextScan, the Do/Loop runs constantly until email_trigger becomes set to True. When it does, the CRBasic code between the If Then and EndIf statements gets executed.

If EmailRelay() takes 10 seconds to do its job or 70 seconds to finish, the data logger does not record a skipped scan. So now we avoid seeing red in LoggerNet’s Connect screen!

Verifying the Success of Sent Emails

How will we know if the data logger is having trouble sending emails using EmailRelay()? We can look at the value that EmailRelay() returns to the data logger, as well as the troubleshooting variables in the function itself.

In our example program, we can create a variable called email_tx_success that we and the data logger can use to determine success and failure.


email_tx_success = EmailRelay (…

When EmailRelay() is executed, it returns a value to email_tx_success depending on what happened. The details can be found in CRBasic’s Help or in the Case statements added to the CRBasic program in this example.

We can also look at the variable email_relay_server_response to get more details if we need to. This variable contains the information returned to the data logger by the EmailRelay() server. Upon successful communication with the server, email_relay_server_response may contain something like this:


{"messagetype":"acknowledgement","message":"email-sent"}

This response is in JSON format and could easily be parsed by the data logger if we needed to do something with it and have the data logger act upon it.

In our example, here’s how the data logger could retry sending a failed message depending on the response it received with its first attempt:


'If EmailRelay was not successful, let us try one more time.
 				If (email_tx_success <> -1) Then
					'2nd attempt
					email_tx_success = EmailRelay (_EMAIL_TO_ADDRESS,_EMAIL_SUBJECT,email_message,email_relay_server_response,_EMAIL_ATTACHMENT)
				EndIf

It is a simple example that you can expand on if you need to.

Conclusion

Do/Loops in slow sequences are a great way to avoid seeing skipped scans in your data logger. I hope you find these examples useful. You can download the original EmailRelay() example, as well as the Do/Loop EmailRelay() example

Are there other ways you program your data loggers to avoid unnecessary skipped scans? If so, please share below.


Share This Article



About the Author

gary roberts Gary Roberts is the Product Manager over communications and software products at Campbell Scientific, Inc. He spends his days researching new technology, turning solutions to problems into stellar products, doing second-tier support, or geeking out on Campbell gear. Gary's education and background are in Information Technology and Computer Science. When he's not at work, he is out enjoying the great outdoors with his Scouts, fighting fire/EMS, working amateur radio, or programming computers.

View all articles by this author.


Comments

Please log in or register to comment.