14. februar 2013 - 13:15Der er
16 kommentarer og 1 løsning
Køre Function/Sub flere gange uden at lave longblocking,
Hej,
jeg er ved at lave et program som skal skrive og læse fra en TCP Stream og kontrollere et anlæg via Modbus.
Jeg kan sagtens skrive og læse til TCP Streamen. Men jeg har det problem at det er ikke altid at der bliver svaret på, og jeg vil derfor gerne have den til at forsøge 3 gange indtil den for svar.
Jeg kører med BeginRead i en seperat Sub for at være sikker på at den læser alt den data jeg efterspørger og læser hele tiden, har prøvet med blot Read men resultatet er ikke stabilt.
Jeg gemmer indholdet fra BeginRead Sub'en i en Global variable DataReceived,
Problemet er hvis jeg laver en loop som sender til streamen 3 gange med et lille sleep indtil DataReceived er noget så skriver den aldrig til variablen og stopper efter 3 forsøg. Skriver jeg så igen så virker den blot med det gamle svar som er kommet efter loopen.
Jeg kender ikke noget til modbus.. men. med TCP er du garanteret levering, det burde derfor ikke være nødvendigt at sende beskeden flere gange. Det lyder til gengæld som om du prøver at læse svaret før det er kommet retur. Kan du ikke hooke en event op til at modtage svaret, eller polle efter svaret så du prøver at modtage, indtil du har modtaget noget istedet for at blive ved med at sende.
Ja altså jeg er også sikker på den er leveret for kan se på anlægget at den gør det ting jeg beder den om, som sagt problemet er bare jeg ikke altid får svar på det, og det skal jeg bruge i mit program da det kan være en temperatur den skal sende tilbage.
Har du en ide til hvordan det kan gøres? Da mit nuværende Async NetworkStreamBeginRead jo ikke er så nemt at få til at virke.
Jeg har nemlig før prøvet at lave en NetworkStream.Read, men når jeg gør det og f.eks. har sat buffer(64) eller lign, så venter den jo til der er 64bytes og da svaret kan variaere fra 8-50 bytes er det sq lidt svært at styre syntes jeg. og sætter jeg den til Buffer(0 eller 1) så smider den bare en helvede masse 00 bytes i hoved + lidt data + en masse nuller igen.
er du sikker på at 00 bytene ikke er del af protokollen der returneres. Jeg antager at du ikke har skrevet koden på den dims du snakker med. så vidt jeg kan se er de første 8 bytes i en modus besked ikke data. stemmer det overens med hvad du får tilbage?
Hej igen, Jeg har nu brugt aftenen på at lave mit program så simpelt som overhoved muligt og droppet alt det jeg var ude i med Async læsning osv. Less is more eller hvad man siger.
Når jeg sender "1E:10:03:EB:00:01:02:00:03:4E:7A" til min Moxa NPort via følgende Function får jeg følgende svar 1E:10:03:EB:00:01:73:D6:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
Og det er rigtig find for nu ser det ud som om jeg for alt det text som jeg skal bruge, og ser ud til at være rimelig stabilt, hvis jeg kigger på min Log på Moxa NPorten deler den svaret op i 2 receive linier og jeg tror det har været mit problem. 2013/02/15 10:16:27[T] 1E 10 03 EB 00 01 02 00 03 4E 7A 2013/02/15 10:16:27[R] 1E 2013/02/15 10:16:27[R] 10 03 EB 00 01 73 D6
Tilgengæld har jeg stadig det problem at jeg modtager ikke et svar hver eneste gang jeg sender en kommando. Nogen gange skal den sendes 3 gange pr gang. Nogen ideer?
Og endt op med følgende kode:
Public Function SendReceive(ByVal SendCommand As String) Dim returnCode As String = Nothing
'//Write Dim outText As String = SendCommand Dim outNumBytes As Integer = 0 Dim outStream As Byte() = New Byte((outText.Length + 1) \ 3 - 1) {}
Try For outNumBytes = 0 To outStream.Length - 1 outStream(outNumBytes) = Byte.Parse(outText.Substring(3 * outNumBytes, 2), Globalization.NumberStyles.HexNumber) Next
NetworkStream.Write(outStream, 0, outNumBytes)
txtLastSend.Text = outText txtLastReceived.Text = Nothing Catch ex As Exception returnCode = "Error: " & ex.Message
Return returnCode Exit Function End Try
'//Read Dim inStream(32) As Byte Dim inBytes As New StringBuilder(inStream.Length * 2) Dim inText As String = Nothing
Do While NetworkStream.CanRead And NetworkStream.DataAvailable
Altså hvis jeg fjerner denne så laver den jo Read uendeligt, Hvordan kan jeg bedst lave en løsning der så stopper read'en når den ikke modtager mere data.
Den første byte er desværre blot ID'en på den ModBus slave enhed. i det her tilfælde 1E = 30. Og går igen på både write og read. Problemet med CR/LF er desværre at af en eller anden årsag så deler den svaret op i flere linier når jeg kigger i Moxa loggen f.eks.
2013/02/15 15:08:34[T] 1E 10 03 EB 00 01 02 00 03 4E 7A 2013/02/15 15:08:34[R] 1E 2013/02/15 15:08:34[R] 10 03 EB 00 01 73 D6
[T] er transmit og selvfølgelig er den streng jeg sender. [R] er receive og der skulle optimalt jo komme 1E 10 03 EB 00 01 73 D6 i en linie. men tilsyneladende deles den i to linier. Men det kan jo også være Moxa NPorten eller lign der laver noget pjat for det virkede fint som SerielPort istedet for TCP.
Der er ligesom 3 typer svar jeg kan få ud af de 3 forskellige typer kommando'er man kan sende. Kort fortalt.
FUNC 3 Byte 1 = Slave ID, Byte 2 = Function 3, Byte 3 = antal bytes at læse, Byte 4+5 6+7 osv = Data, Sidste 2 bytes er CRC.
FUNC 4: Byte 1 = Slave ID, Byte 2 = Function 4, Byte 3 = Antal bytes for at læse, Byte 4+5 6+7 8+9 osv osv = Data, Sidste to bytes CRC.
FUNC 16: Den ovenfra den er rimelig nem for den har et fast svar på 8 bytes og de er altid Byte 1 = Slave ID, Byte 2 = Function 10(16 decimalt), Byte 3 = (mængde af data som kommer her 3 bytes), Byte 4-6 = Affald :), Byte 7+8 = CRC.
Saa du skal altsaa foerst laese 3 bytes. Saa tager du vaerdien af den 3. byte og bestemmer hvor mange bytes du skal laese. Og du venter indtil du har faaet dem alle. Og naar du har det saa koerer du videre.
Det er super Arne, du har jo fuldstændig ret, jeg skal blot lige lave en kode der passer til det, midlertidigt er jeg dog kommet ud over det ved blot at lave 64bytes også sortere alle de sidste fra. Men når jeg skal kigge lidt på den del af koden igen så fixer jeg det da sådan at den læser 3 bytes og så hvor mange der er nødvendigt derefter.
En anden ting arne, Jeg har et andet problem også som du måske kan give mig et praj til. Jeg har en TcpListener hvor jeg modtager en Stream, jeg sender teksten 1E:03:03:EC:00:01:47:D4 som en ASCII som så bliver lavet om til byte som så bliver lavet om til ASCII igen på "server" siden. Men når denne bliver lavet om med Dim modtaget as string = Encoding.ASCII.GetString(ByteString) og jeg skal bruge modtaget videre så kan jeg godt skrive teksten til console eller eventviewer og få samme tekst ud altså "1E:03:03:EC:00:01:47:D4" som tekst. men bruger jeg strengen til en funktion så laver den input strengen var ikke korrekt eller lign. Men tager jeg og sætter modtaget = "1E:03:03:EC:00:01:47:D4" så kan jeg godt bruge strengen. Hvad går der galt i encodningen der?
Og smid lige et svar til det andet så du kan få nogle points.
Hold da kæft du er hurtig :) Jeg tror jeg har fixet det jeg har ændret følgende nedenunder. Problemet var nok som du siger at i ASCII konverteringen var der mere data i form af ingen ting eller lign. Nu ASCII jeg selvf samme data som jeg modtager og det ser ud til at virke. Tak Endnu engang.
Fra: --------------------- Dim TcpReceiveBytes(TcpClient.ReceiveBufferSize) As Byte TcpStream.Read(TcpReceiveBytes, 0, CInt(TcpClient.ReceiveBufferSize))
Dim TcpReceive As String = Encoding.ASCII.GetString(TcpReceiveBytes)
Til: --------------------- Dim TcpReceiveBytes(TcpClient.ReceiveBufferSize) As Byte TcpStream.Read(TcpReceiveBytes, 0, CInt(TcpClient.ReceiveBufferSize))
Dim TcpReceive As String = Encoding.ASCII.GetString(TcpReceiveBytes, 0, TcpClient.ReceiveBufferSize)
Ja - du har nok haft nogle null bytes efter de egentlige data.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.