From: albertleng on 16 Jun 2010 14:22 Hi all. I'm writing a program which is connected to Fire Alarm System via serial port. The Fire Alarm System will send me data like shown below. COMMON TRBL RST :: 22:18:50 16/06/2010 P:06 C:02 D:0137 Z6-4-9_BV_CLOSED 4S Corridor COMMON TRBL ACT :: 22:18:50 16/06/2010 P:06 C:02 D:0137 Z6-4-9_BV_CLOSED 4S Corridor My program needs to send "0" or "1" via DDE to another program based on the FAS message. Referring to the above message, "COMMON TRBL RST" is the message to reset an alarm, "COMMON TRBL ACT" is the message to activate an alarm and "D:0137" is the locationID. My program needs to send the status via DDE based on the "... RST" or "...ACT" message and the locationID. Upon startup, my program will read from a config file for the available ACT message, RST message and a list of locationIDs. I am encountering a few issues: 1) In my MSCOMM1_OnComm event, using breakpoint, i notice that my program always receives just the portion of the FAS message, for e.g., I'll receive only "COM" at one time and then, I press F5 to carry on. Next time, I'll receive another portion of the whole chunk like "MON TRBL RST... ...". Because of this, i can't capture any alarm ACT or alarm RST at all. How can i ensure i don't lose any data from FAS? 2) If I can solve the first issue, please suggest to me the most efficient way to process the chunk of data received by my program. Below are my code. Please help. Private Sub MSComm1_OnComm() Static strBuffer As String Dim strData As String Dim normalLocation1 As Integer Dim alarmLocation1 As Integer Dim normalLocation2 As Integer Dim alarmLocation2 As Integer Dim normalLocation3 As Integer Dim alarmLocation3 As Integer Dim normalLocation As Integer Dim alarmLocation As Integer Dim normalMsg As String Dim alarmMsg As String Dim finalNormalLocation As Integer Dim finalAlarmLocation As Integer Dim pointIndex As Integer Dim i As Integer Dim j As Integer Select Case MSComm1.CommEvent Case comEvReceive strData = MSComm1.Input strBuffer = strBuffer & strData tTerminal.Text = tTerminal.Text & strBuffer //This is the part where i put breakpoint and notice that my program keeps receiving only part of the FAS message. If Len(tTerminal.Text) > (Len(normalMsg1) + 1) Then //normalMsg1, normalMsg2, normalMsg3, alarmMsg1, alarmMsg2 and alarmMsg3 are the possible Alarm ACT and RST messages //defined in the config files. For i = 1 To Len(tTerminal.Text) normalLocation1 = InStr(i, Mid$(tTerminal.Text, i, Len(normalMsg1) + 1), normalMsg1) alarmLocation1 = InStr(i, Mid$(tTerminal.Text, i, Len(alarmMsg1) + 1), alarmMsg1) If normalMsg2 <> "" Then normalLocation2 = InStr(i, Mid$(tTerminal.Text, i, Len(normalMsg2) + 1), normalMsg2) Else normalLocation2 = 0 End If If alarmMsg2 <> "" Then alarmLocation2 = InStr(i, Mid$(tTerminal.Text, i, Len(alarmMsg2) + 1), alarmMsg2) Else alarmLocation2 = 0 End If If normalMsg3 <> "" Then normalLocation3 = InStr(i, Mid$(tTerminal.Text, i, Len(normalMsg3) + 1), normalMsg3) Else normalLocation3 = 0 End If If alarmMsg3 <> "" Then alarmLocation3 = InStr(i, Mid$(tTerminal.Text, i, Len(alarmMsg3) + 1), alarmMsg3) Else alarmLocation3 = 0 End If //FindSmallest is a method i wrote to find the smallest number of the 3 numbers normalLocation = FindSmallest(normalLocation1, normalLocation2, normalLocation3) If normalLocation <> 0 Then If normalLocation1 = normalLocation Then normalMsg = normalMsg1 ElseIf normalLocation2 = normalLocation Then normalMsg = normalMsg2 ElseIf normalLocation3 = normalLocation Then normalMsg = normalMsg3 End If End If alarmLocation = FindSmallest(alarmLocation1, alarmLocation2, alarmLocation3) If alarmLocation <> 0 Then If alarmLocation1 = alarmLocation Then alarmMsg = alarmMsg1 ElseIf alarmLocation2 = alarmLocation Then alarmMsg = alarmMsg2 ElseIf alarmLocation3 = alarmLocation Then alarmMsg = alarmMsg3 End If End If //totalPoint is the total venues/LocationIDs For j = 1 To totalPoint If alarmLocation <> 0 Then //Send 1 via DDE to a program if point j is an alarm If InStr(strBuffer, PointAddress(j)) > 0 Then txtPoint(j).Text = "1" txtPoint(j).LinkMode = vbLinkManual txtPoint(j).LinkPoke End If ElseIf normalLocation <> 0 Then //Send 0 via DDE to a program if point j is an alarm If InStr(strBuffer, PointAddress(j)) > 0 Then txtPoint(j).Text = "0" txtPoint(j).LinkMode = vbLinkManual txtPoint(j).LinkPoke End If Else Exit For End If Next j Next i tTerminal.Text = "" strBuffer = "" End If End Select End Sub
From: Steve on 16 Jun 2010 15:52 I have always done this with a receive buffer. The idea is to simply "pluck" data (characters) from the com port as they come in whilest all the while looking for the character (or group of characters) that indicate end of message. Once you have received the end of message marker your buffer now should contain the entire message. Only then, with the complete message, do you attempt to parse it and perform the appropriate logic. Here is an air code example to illustrate Private Sub MSCOMM1_OnComm() Dim strData As String Static strBuffer As String 'Change this to whatever is the marker for end of message Const END_OF_MSG As String = vbCrLf If MSComm1.CommEvent = comEvReceive Then 'Retrieve characters from com port strData = MSComm1.Input 'Test if characters just retrieved contain end of message marker If InStr(strData, END_OF_MSG) > 0 Then 'This has the end of message somewhere in so we have to find it strBuffer = strBuffer & Left(strData, InStr(strData, END_OF_MSG) + Len(END_OF_MSG)) 'Now that we have a complete message we send it off to be processed ProcessMsg strBuffer 'Now that the message has been processed we start over looking for a new message strBuffer = Mid(strData, InStr(strData, END_OF_MSG) + Len(END_OF_MSG)) Else 'We have not recieved the end of the message yet so just add this data to our buffer strBuffer = strBuffer & strData End If End If End Sub Private Sub ProcessMsg() 'Do your message parsing and handling logic here End Sub Hope this helps, Steve
From: Dee Earley on 17 Jun 2010 06:10 On 16/06/2010 20:52, Steve wrote: > I have always done this with a receive buffer. The idea is to simply > "pluck" data (characters) from the com port as they come in whilest all > the while looking for the character (or group of characters) that > indicate end of message. Once you have received the end of message > marker your buffer now should contain the entire message. Only then, > with the complete message, do you attempt to parse it and perform the > appropriate logic. > > Here is an air code example to illustrate > > Private Sub MSCOMM1_OnComm() > Dim strData As String > Static strBuffer As String > > 'Change this to whatever is the marker for end of message > Const END_OF_MSG As String = vbCrLf > > If MSComm1.CommEvent = comEvReceive Then > 'Retrieve characters from com port > strData = MSComm1.Input > > 'Test if characters just retrieved contain end of message marker > If InStr(strData, END_OF_MSG) > 0 Then > 'This has the end of message somewhere in so we have to find it > strBuffer = strBuffer & Left(strData, InStr(strData, END_OF_MSG) + > Len(END_OF_MSG)) > > 'Now that we have a complete message we send it off to be processed > ProcessMsg strBuffer > > 'Now that the message has been processed we start over looking for a new > message > strBuffer = Mid(strData, InStr(strData, END_OF_MSG) + Len(END_OF_MSG)) > Else > 'We have not recieved the end of the message yet so just add this data > to our buffer > strBuffer = strBuffer & strData > End If > End If > > End Sub > > Private Sub ProcessMsg() > 'Do your message parsing and handling logic here > End Sub Bear in mind that you MAY receive multiple end of lines per call. This caught me out for a while and I couldn't figure out why it was backlogged by a number of commands. Here's a sample that does essentially the same thing with a socket control: http://hashvb.earlsoft.co.uk/Designing_network_protocols#Receiving_data -- Dee Earley (dee.earley(a)icode.co.uk) i-Catcher Development Team iCode Systems (Replies direct to my email address will be ignored. Please reply to the group.)
From: Larry Serflaten on 17 Jun 2010 18:49 "albertleng" <albertleng(a)gmail.com> wrote > 2) If I can solve the first issue, please suggest to me the most > efficient way to process the chunk of data received by my program. As you have read, others have suggested that you need to add what you get from the connection to what has already arrived, and then parse that for an end of line sequence. eg: (From Mr. Grier's reply) Buffer = Buffer & MSComm1.Input CrLfPosition = InStr(Buffer, vbCrLf) If CrLfPostion > 0 Then Dim Temp As String Temp = Mid$(Buffer, 1, CrLfPosition -1) Process(Temp) 'you write this code<<< - Temp contains a full line Buffer = Mid$(Buffer, CrLfPosition +1) 'this is important! clean-up required End If I wanted to suggest that you avoid processing the input from the OnComm event. Instead of processing it then and there, add the recieved line to a collection (a queue) and enable a timer: ... Temp = Mid$(Buffer, 1, CrLfPosition -1) RcvQue.Add Temp ProcessTimer.Enable Buffer = Mid$(Buffer, CrLfPosition +1) 'this is important! clean-up required ... When the timer fires, then call your process routine: Private Sub ProcessTimer_Timer() If RcvQue.Count > 0 Then Process RcvQue(1) RcvQue.Remove 1 Else ProcessTimer.Enabled = False End If End Sub That way, you get in and get out of the OnComm event quickly, always a good idea when talking with the outside world. As far as actually doing the string manipulations and other work, That would best be handled in another thread, once you get the communication up and working. It seemed to me you were checking Terminal.Text quite often and should have really assigned the needed portion to a string for processing. But first, see if you can get your complete messages working, then post again to clean up the processing code.... LFS
From: albertleng on 20 Jun 2010 10:36 Hi all. Thank you so much. I think your help has helped me to have a big leap forward in solving my problem. I have changed my program accordingly as below: Private Sub MSComm1_OnComm() Static Buffer As String Dim CrLfPosition As Integer If MSComm1.CommEvent = comEvReceive Then Buffer = Buffer & MSComm1.Input Print #LogFNo, Format(Now, "YYYYYYYY-MM-DD hh:mm:ss") & " " & "Received = " & MSComm1.Input logFLineNo = logFLineNo + 1 CrLfPosition = InStr(Buffer, vbCrLf) If CrLfPosition > 0 Then tTerminal.Text = Buffer ListMessage.AddItem Format(Now, "YYYYYYYY-MM-DD hh:mm:ss") & " " & " Received " & Buffer, ListMessage.ListCount Print #LogFNo, Format(Now, "YYYYYYYY-MM-DD hh:mm:ss") & " " & "Received = " & MSComm1.Input logFLineNo = logFLineNo + 1 Dim Temp As String Temp = Mid$(Buffer, 1, CrLfPosition - 1) Call ProcessFASMessage(Temp) Buffer = Mid$(Buffer, CrLfPosition + 1) End If End If End Sub Private Sub ProcessFASMessage(Temp As String) Dim j As Integer 'There are 3 alarmMsgs and 3 normalMsgs in this system. 'PointAddress is the device name If (InStr(Temp, alarmMsg1) > 0) Or (InStr(Temp, alarmMsg2) > 0) Or _ (InStr(Temp, alarmMsg3) > 0) Then For j = 1 To totalPoint If InStr(Temp, PointAddress(j)) > 0 Then txtPoint(j).Text = "1" txtPoint(j).LinkMode = vbLinkManual txtPoint(j).LinkPoke ListMessage.AddItem Format(Now, "YYYYYYYY-MM-DD hh:mm:ss") & " " & " Send " & txtPoint(j).Text _ & " to " & txtPoint(j).LinkItem, ListMessage.ListCount Print #LogFNo, Format(Now, "YYYYYYYY-MM-DD hh:mm:ss") & " " & " Send " & txtPoint(j).Text _ & " to " & txtPoint(j).LinkItem logFLineNo = logFLineNo + 1 End If Next j ElseIf (InStr(Temp, normalMsg1) > 0) Or (InStr(Temp, normalMsg2) > 0) Or _ (InStr(Temp, normalMsg3) > 0) Then For j = 1 To totalPoint If InStr(Temp, PointAddress(j)) > 0 Then txtPoint(j).Text = "0" txtPoint(j).LinkMode = vbLinkManual txtPoint(j).LinkPoke ListMessage.AddItem Format(Now, "YYYYYYYY-MM-DD hh:mm:ss") & " " & " Send " & txtPoint(j).Text _ & " to " & txtPoint(j).LinkItem, ListMessage.ListCount Print #LogFNo, Format(Now, "YYYYYYYY-MM-DD hh:mm:ss") & " " & " Send " & txtPoint(j).Text _ & " to " & txtPoint(j).LinkItem logFLineNo = logFLineNo + 1 End If Next j End If End Sub I don't have access to site at the moment and my testing is done using virtual serial port downloaded from http://www.eterlogic.com/downloads/SetupVSPE.zip I'll need my people on site to test it out and let me know the outcome. Anyway, in my system, both the normal/alarm message and the device name are on the same line. How about if normal/alarm message and the device name are in separate line? How can i effectively process the message then? Thanks again, everyone. On Jun 18, 6:49 am, "Larry Serflaten" <serfla...(a)gmail.com> wrote: > "albertleng" <albertl...(a)gmail.com> wrote > > > 2) If I can solve the first issue, please suggest to me the most > > efficient way to process the chunk of data received by my program. > > As you have read, others have suggested that you need to add what you > get from the connection to what has already arrived, and then parse that > for an end of line sequence. eg: (From Mr. Grier's reply) > > Buffer = Buffer & MSComm1.Input > CrLfPosition = InStr(Buffer, vbCrLf) > If CrLfPostion > 0 Then > Dim Temp As String > Temp = Mid$(Buffer, 1, CrLfPosition -1) > Process(Temp) 'you write this code<<< - Temp contains a full line > Buffer = Mid$(Buffer, CrLfPosition +1) 'this is important! clean-up required > End If > > I wanted to suggest that you avoid processing the input from the OnComm event. > Instead of processing it then and there, add the recieved line to a collection (a queue) > and enable a timer: > > ... > Temp = Mid$(Buffer, 1, CrLfPosition -1) > RcvQue.Add Temp > ProcessTimer.Enable > Buffer = Mid$(Buffer, CrLfPosition +1) 'this is important! clean-up required > ... > > When the timer fires, then call your process routine: > > Private Sub ProcessTimer_Timer() > If RcvQue.Count > 0 Then > Process RcvQue(1) > RcvQue.Remove 1 > Else > ProcessTimer.Enabled = False > End If > End Sub > > That way, you get in and get out of the OnComm event quickly, always > a good idea when talking with the outside world. > > As far as actually doing the string manipulations and other work, That would > best be handled in another thread, once you get the communication up and > working. It seemed to me you were checking Terminal.Text quite often and > should have really assigned the needed portion to a string for processing.. > But first, see if you can get your complete messages working, then post again > to clean up the processing code.... > > LFS
|
Next
|
Last
Pages: 1 2 Prev: Clear debug window Next: I need to convert hex colors from Photoshop to something usable inGDI |