Hi,
I am having trouble handling an asynch stream over a serial port. I cannot use prefixed streams because the external device Tiny Spectrum Analyser (TSA) does not provide this.
The process I am using is:
1. Send a "scan" command to the SA over the serial port AStream.write
2. Using AStream_NewData I process the stream recursively until I have received all of the data.
3. I then repeat the process with different scan parameters until I have scanned all bands
The amount of data returned by the TSA varies considerably and so sometimes a single return to AStream_NewData will have the entire response at other times two or three buffers will need to be processed.
To prevent the sending of new scan commands before all the received data has been received and processed, I am waiting for a resumable sub to be completed which I run when the processing of the data has been finalised. The TSA is half duplex, you cannot sends a command until the TSA has set its data with a "cr> ". If you do send a message before completion of the return datathe TSA stalls and must be power cycled to restart.
The problem I am having is the program is not waiting for the resumable sub and also the resumable sub is run without any call to it. I had a look at the B4X Language manual and noticed on page 69 at the bottom that:
Notes:
- It is safer to use CallSubDelayed than CallSub. CallSub will fail if the second sub is never paused
(for example if the sleep is only called based on some condition).
- There is an assumption here that FirstSub will not be called again until it is completed.
In particular the second point about the first sub not being called until it is completed is relavant in my case as it is quite possible for AStream_NewData to interrupt its own processing as new data becomes available.
A flow chart of the process I am using is shown below:
		
		
	
	
		 
	
The code is:
	
	
	
	
	
	
	
		
			
			
			
			
			
		
	
	
	
		
	
	
		
	
	
	
	
	
	
	
	
		
			
			
			
			
			
		
	
	
	
		
	
	
		
	
	
	
	
	
	
	
	
		
			
			
			
			
			
		
	
	
	
		
	
	
		
	
	
	
	
	
	
	
	
		
			
			
			
			
			
		
	
	
	
		
	
	
		
	
	
	
	
	
	
	
	
		
			
			
			
			
			
		
	
	
	
		
	
	
		
	
	
	
	
	
	
	
	
		
			
			
			
			
			
		
	
	
	
		
	
	
		
	
I guess one solution would be to use time-outs, however I wish to scan on a virtualy continuous basis with only a small "dead time" at the each of scan. As the amount end of the data stream can be determined, iI wish to use this as a flag for "all data received."
			
			I am having trouble handling an asynch stream over a serial port. I cannot use prefixed streams because the external device Tiny Spectrum Analyser (TSA) does not provide this.
The process I am using is:
1. Send a "scan" command to the SA over the serial port AStream.write
2. Using AStream_NewData I process the stream recursively until I have received all of the data.
3. I then repeat the process with different scan parameters until I have scanned all bands
The amount of data returned by the TSA varies considerably and so sometimes a single return to AStream_NewData will have the entire response at other times two or three buffers will need to be processed.
To prevent the sending of new scan commands before all the received data has been received and processed, I am waiting for a resumable sub to be completed which I run when the processing of the data has been finalised. The TSA is half duplex, you cannot sends a command until the TSA has set its data with a "cr> ". If you do send a message before completion of the return datathe TSA stalls and must be power cycled to restart.
The problem I am having is the program is not waiting for the resumable sub and also the resumable sub is run without any call to it. I had a look at the B4X Language manual and noticed on page 69 at the bottom that:
Notes:
- It is safer to use CallSubDelayed than CallSub. CallSub will fail if the second sub is never paused
(for example if the sleep is only called based on some condition).
- There is an assumption here that FirstSub will not be called again until it is completed.
In particular the second point about the first sub not being called until it is completed is relavant in my case as it is quite possible for AStream_NewData to interrupt its own processing as new data becomes available.
A flow chart of the process I am using is shown below:
The code is:
			
				scanAllBandsForThisSignalSet:
			
		
		
		'--------------------------------------------------------------------------------------------
'Scan each bands sequentially. The scan of a single band yields as reply 
'from the TSA for that band.
Public Sub scanAllBandsForThisSignalSet
    Dim bList As List
    bList.Initialize
    Main.progBandScan.Progress = 0
    Dim count As Int = 0
    bandIndex = 0
    
    Main.AllScansCompleteFlag = False
    
    bList = Main.Band_Data.MbandList
    
    For Each Record() As Object In bList
        count = count + 1
        
        'setBandSweepAndScan(band,      start,     stop,      BandMargin,  NoPoints,  rbw
        currentStart = Record(1) * 1e6
        CurrentStop  = Record(2) * 1e6
        setBandSweepAndScan(Record(0), Record(1), Record(2), Record(11),  Record(10), Main.Band_Data.SigSrcCurrentRecord.RBW_Khz)
        
        ' Wait for processing complete before sending another command
        Wait For (saDataReceived) Complete(done As Boolean)
        bandIndex = bandIndex + 1
    Next
    
    Main.AllScansCompleteFlag = True
    CallSubDelayed(Me, "saAllScansComplete")
End Sub
			
				setBandSweepAndScan:
			
		
		
		'--------------------------------------------------------------------------------------------
'This sub sends out a sweep command to sweep the points in a band
' It is a resumable sub and uses completion functions to signal to
' other application modules
Public Sub setBandSweepAndScan(band As Int, start As Double, _
    stop As Double, BandMargin As Double, NoPoints As Int, rbw As Int)
    'Construct the frequency strings
    Dim startStr As String
    Dim stopStr As String
    Main.scanCompleteFlag = False
    scanDataStreamText = ""
    noValidScanLines = 0
    Main.noScanBytesTotalExpected = networkPars.NO_CHARS_IN_SCAN_RESPONSE_PER_LINE * NoPoints + networkPars.NO_CHARS_IN_SCAN_RESPONSE_TERMINATION
    Main.noScanBytesReceived = 0
    
    bandNo = band
    
    start = start * 1e6
    If start < 1e6 Then
        startStr = NumberFormat(start, 1, 0) & "k"
    else if start < 1000e6 Then
        startStr = NumberFormat(start / 1000000, 1, 0) & "M"
    else if start > = 1 Then
        startStr = NumberFormat(start / 1e9, 1, 0) & "G"
    End If
    
    stop = stop * 1e6
    If stop < 1e6 Then
        stopStr = NumberFormat(stop, 1, 0) & "k"
    else if stop < 1000e6 Then
        stopStr = NumberFormat(stop / 1e6, 1, 0) & "M"
    else if stop > = 1 Then
        stopStr = NumberFormat(stop / 1e9, 1, 0) & "G"
    End If
    
    ' Sweep the band
    Main.dataReceivedFlag = False
    chCount = False
    dataStr = ""
'    noPointsThisScan = NoPoints
    cmd = "scan"
    commandStr = cmd & " " & startStr & " " & stopStr & " " & NoPoints & " " & 3
    noOfPackets = 0
    Main.writeCmdSerial(commandStr)
    Main.dataReceivedFlag = False
End Sub
			
				AStream_NewData:
			
		
		
		Public Sub writeCmdSerial(cmdStr As String)
    Dim str As String
    str = cmdStr & Chr(13)
    byteBuffer = bc.StringToBytes(str, "UTF8")
    astream.Write(byteBuffer)
End Sub
			
				AStream_NewData:
			
		
		
		'--------------------------------------------------------------------------------------------
Private Sub AStream_NewData (Buffer() As Byte)
    Dim s As String = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
    SaCom.processCmdRx(Buffer)
End Sub
			
				Process command reply:
			
		
		
		public Sub processCmdRx(Buffer() As Byte)
    replyError = False
    tempStr = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
Select cmd
        Case "pause"
            checkReplyForErrorsShortCmds("pause")
            Main.dataReceivedFlag = True
        Case "lna"
            (...)
        Case "scan"   
            cleanUpScanData(Buffer)
            Main.dataReceivedFlag = True
    End Select
End Sub
'--------------------------------------------------------------------------------------------
Private Sub cleanUpScanData(buffer() As Byte)
    Log("Cleanup L429" & "   "  & DateTime.Time(DateTime.now))
    Dim newDataStart As Int = sb.Length
    sb.Append(BytesToString(buffer, 0, buffer.Length, charset))
    Dim s As String = sb.ToString
    Dim start As Int = 0
    For i = newDataStart To s.Length - 1
        noOfPackets = noOfPackets + 1
        Dim c As Char = s.CharAt(i)
        If i = 0 And c = Chr(10) Then '\n...
            start = 1 'might be a broken end of line character
            Continue
        End If
        If c = Chr(10) Then '\n
            Log("Cleanup chr(10)")
            CallSubDelayed2(Me, "checkAndProcessScanLine", s.SubString2(start, i))
'            checkAndProcessScanLine(s.SubString2(start, i))
            start = i + 1
        Else If c = Chr(13) Then '\r
            Log("Cleanup chr(13)")
            CallSubDelayed2(Me, "checkAndProcessScanLine", s.SubString2(start, i))
'            checkAndProcessScanLine(s.SubString2(start, i))
            If i < s.Length - 1 And s.CharAt(i + 1) = Chr(10) Then '\r\n
                i = i + 1
            End If
            start = i + 1
        End If
    Next
    If start > 0 Then sb.Remove(0, start)
End Sub
			
				checkAndProcessScanLine:
			
		
		
		'--------------------------------------------------------------------------------------------
private Sub checkAndProcessScanLine(scanLineStr As String)
    If scanLineStr.Contains("level") Or scanLineStr.Contains("scan") Then
        Return
    End If
    
    scanDataStreamText = scanDataStreamText  & Chr(10) & scanLineStr
    noValidScanLines = noValidScanLines + 1
    
    If noValidScanLines = Main.Band_Data.getBandNoPointsArray(bandIndex) Then
        'Process the data   
        getScanListFromSaResult(scanDataStreamText)
        CallSubDelayed(Me, "saDataReceived")
    End If
    Return
End SubI guess one solution would be to use time-outs, however I wish to scan on a virtualy continuous basis with only a small "dead time" at the each of scan. As the amount end of the data stream can be determined, iI wish to use this as a flag for "all data received."
 
				 
 
		 
 
		 
 
		 
 
		