Problem with connection.readln waiting for carriage return - delphi

I'm facing problem with TCpindy connection.readln method , I had no control in the other side sending data , when using Readln method in server side application hang (because receiving data don't contain carrige return ) , i'm trying readstring method but without success
Is there any suggestion to encouter this problem , me be looking for other component rather than indy ,
I need to get data from other client (tcp connection ) without any information about size of receiving data and without carriage return at the end of each frame.

You have to know how the data is being sent in order to read it properly. TCP is a byte stream, the sender needs to somehow indicate where one message ends and the next begins, either by:
prefixing each message with its
length
putting unique delimiters in between
each message
pausing in time between each message
Indy can handle all of these possibilities, but you need to identify which one is actually being used first.
Worse case scenerio, use the CurrentReadBuffer() method, which returns a String of whatever raw bytes are available at that moment.

Related

Sending cyclic message using CANoe - IL DLL

I have a configuration setup with two CAN nodes and an attached database. I have added a CANOEILNLVECTOR.dll to both the nodes. By adding this Dll file all my messages are sent cyclic as I see in trace window.
Now I set some value for a signal in a message, For Eg:
variables
{
message Battery_Traction Batt_msg;
}
on start
{
Batt_msg.Isolation_Signal = 0x02; //0x02:On
output(Batt_msg);
}
What I see on trace is: The message is cyclic but only for the first instance the value set by me above appears in trace. For all of the rest times the signal value in the message in set to default.
As seen in the image value 0x02 is sent only once.
I am not sure what could be the problem, as seen in image attached value set by me is only sent once.
When using output you are putting the message directly onto the CAN bus, but you are not changing the value inside of your (simulated) node, so the interaction layer is still sending the old value.
You can change the signal value in the interaction layer by just putting a $ in front of the signal name and set the value.
In your case most likely $Isolation_Signal = 0x02
Outputting the message on the CAN bus at the right time, with the right cycle time and so on will be handled by the interaction layer.
You have two ways to influence dynamically the value of your message: IL DLLs and custom message sending.
Custom message sending is the basic way, where
you define the message ex.: message Battery_Traction Batt_msg;
you trigger its sending(output function)
you set up cyclic sending on timer Cycletimemsg1 {output(msg1);}
and so on.
IL DLLs are doing this all for you, without much coding effort from your side, but they rely heavily on the dbc settings and attributes you have linked as database to your CAN Channel.
Unfortunately, they don't play well together, meaning you need advanced CANoe know-how of them to use both in the same environment. You basically bypassed your CANOEILNLVECTOR.dlls working by sending explicit message.
So your code if you are accessing your signal through IL, should look like this:
variables
{
/*no need to define custom message object, they are already "known" to IL by dbc*/
}
on start
{
$Batt_msg::Isolation_Signal = 0x02; //0x02:On
/*NO need for output either (IF YOUR MESSAGE IS defined Cyclic in dbc), */
}
If your signal is not identified at $Batt_msg::Isolation_Signal, just dragndrop the signal from the CAPL browsers Symbols panel, and add the $ sign before it.
Through dollar($) sign, you access the dbsignal class objects signal value attribute.

Messagebox working in debug mode but not in normal run

I am making a software for GSM Modem. It works on serial communication using AT commands. We give AT commands to it and it respond via serial communication. I am giving it a command to check balance in a SIM AT+CUSD=1,"*141#". Its response is like this:
+CUSD: 0, "Your balance is ... xxxxxxx "
Now I want to display this on a messagebox. This is the small code I am using:
String data = serialPort1.ReadExisting(); //to receive serial data and store it in data strig
logsTextBox.AppendText(data); // display it in text box
logsTextBox.AppendText("\n");
if (data.Contains("+CUSD:"))
{
MessageBox.Show(data);
}
Now when I put breakpoint and debug the code, it works properly and show complete data in message box but when I run it normally it shows just few characters in message box. Like this:
Instead it should be like this:
The problem what I have found is when debug all the data content which is shown in 2nd image gets save in data variable so it is displayed completely in message box. But when in normal run, the complete data is not received in string data so thats why it shows less data as shown in first image. How to solve this issue. What could be the reason. Please help.
This is a typical behavior for a serial port. They are very slower. When the DataReceived event fires, you'd typically only get one or two characters. Notably is that it works well when you debug because single-stepping through the code gives the lots of time to serial port to receive additional characters. But it will go Kaboom as soon as you run without a debugger because the string isn't long enough.
You'll need to modify the code by appending the string you receive to a string variable at class scope. Only parse the string after you've received all the characters you expected. You'll need some way to know that you've received the full response. Most typically serial devices will terminate the string with a special character. Often a line-feed.
If that's the case then you can make it easy by setting the SerialPort.NewLine property to that terminator and calling ReadLine() instead of ReadExisting().
You should call ReadExisting until empty string is returned, concatenating the results to data on each call. Perhaps debug mode has a larger read buffer for the serial port than normal mode.

Read all data on Indy Server buffer

I have in TCP/IP a client that send a list of strings with writeln (all at the same time).
How can the TCPserver know that it has read all the data?
In Onexecute event, I have used:
If (not AThread.Terminated)and(athread.Connection.Connected) then
Memo1.lines.add(AThread.Connection.readln);
But the problem, is that some last lines are not read.
You should send each string with its own WriteLn(), then you can either:
Send the number of strings before sending the actual strings. The server can then read the number first, then call ReadLn() however many times the number says.
Send a unique terminating line after the strings. The server can then keep calling ReadLn() until the terminator is read. If you need to send a string that could be ambiquious with the terminator, escape the string before sending it, and then have the server unescape it after reading it.
Indy has reading/writing methods for handling both scenarios, such as WriteStrings(), ReadStrings(), WriteRFCStrings(), Capture(), etc.
On an unrelated note, you should not be checking the AThread.Terminated and AThread.Connection.Connected properties. Let Indy raise an exception if you try to read from or write to a disconnected socket, and let the server handle the exception. Also, TIdTCPServer is multi-threaded, and accessing UI controls in the OnExecute event (or OnConnect, OnDisconnect, or OnException) is not thread-safe. You MUST synchronize with the main UI thread to access them safely.

Read raw data from socket

I have a device that sends data to my server via gprs . The problem is that it sends raw data and i don't know where i can stop the reading
Currently i am using something TIdHttpServer and something like this to read the strings :
var
s : string;
repeat
s:=s+acontext.Connection.Socket.ReadChar;
until acontext.Connection.Socket.InputBufferIsEmpty;
Is there a better solution to my problem ?
TCP is stream oriented. If the protocol is unknown, the server only can try to read into a byte array (if memory is not a problem) or a file stream. If the client disconnects normally, the data is 'complete'. Unfortunately, if the protocol is unknown, the server can not tell wether the client died or disconnected normally.
InputBufferIsEmpty does not help, as it only says if there is data in the (TCP) buffer - and depending on latency this can happen frequently, but it does not mean that there are no more in-flight bytes.
You could try to 'reverse engineer' the protocol, by sending known strings over the client devices. But if the sender is a black box, there can be many special cases - think of encoding or 'escape' characters etc.
You could make up you own protocol.
Some ideas are:
use a special character or characters combo to define the end of the
message.
append at the start of the message some fixed size field with the size of the message

Connection Closed Gracefully when IdTCPClient.IOHandler.ReadStream()!

I'm new to delphi and this is my first project.
Here's a little bit of code:
procedure TForm1.Button2Click(Sender: TObject);
responseStringFromServer:TStringStream;
begin
try
if IdTCPClient1.Connected then
begin
dataSentToDevice:= 'http/1.0 content-length: 344 content-type: text/xml <?xml version="1.0" encoding="UTF-8" ?> ...'
IdTCPClient1.IOHandler.WriteLn(dataSentToDevice);
responseStringFromServer := TStringStream.Create;
IdTCPClient1.IOHandler.ReadStream(responseStringFromServer);
...
I have a device connected to local network. I manage to connect to it succesfully. Sending commands is working too, but when i do
IdTCPClient1.IOHandler.ReadStream(responseStringFromServer);
then it waits til device is done processing and an exception occurs: "Connection Closed Gracefully". So i'm not able to read data the device is supposed to send me. Device is not shutting down. I've read other posts and i understand that device itself drops connection.
I have a demo program that communicates with it and it works fine. I need to get response xml before it drops the connection.
Also the request is http and i am using IdTCPClient (i need to use xml request, i don't know how to do it with TidHTTP).
May it be that after device is sending response it drops the connection, so that my tcpclient gets connection dropped flag before receiving data.
Any help would be appreciated!
Also the request is http and i am
using IdTCPClient (i need to use xml
request, i don't know how to do it
with TidHTTP).
Working with IdHTTP is simple...
Drop an instance of it on your form,
select it.
In Object Inspector, go to
ProtocolVersion property, and set it
to pv1_0, then open its
Request property set, and set
Request.ContentType to text/xml, and
Request.ContentEncoding to UTF-8,
and set other properties if
required.
Add a button to your form and
double-click on it.
In your code, create an instance of
TStringStream, and load your XML
content into it.
Assign your stream to
IdHttp.Request.Source.
Call IdHttp.Get() method by giving
it a host address.
IdHttp.Get() returns a string which
is the response the server sent you.
The way you are calling ReadStream(), it will interpret the first 4 bytes (or 8 bytes if the TIdIOHandler.LargeStream property is True) as an Integer (or Int64) in network-byte order that specifies the length of the data, and then it will try to read that many bytes. Is the device actually sending such a length value? If not, then ReadStream() will attempt to read the wrong number of bytes. An EIdConnClosedGracefully exception means the device is closing the socket on its end. So either the device is closing the connection immediately after sending its data, or it is timing out waiting for you to send the next command, which you cannot do since you are blocked waiting for the wrong data from the previous command.
As said by #Remy Lebeau and the documentation (press F1 when your edit caret is over the ReadStream sentence):
AByteCount indicates the number of bytes from the IOHandler to be read into AStream. When AByteCount contains -1 and AReadUntilDisconnect contains False, the byte count is read as an Integer value from the IOHandler. The size of AStream is adjusted to match the size expected from the IOHandler.
This is very useful when you're connecting to servers written also in INDY WriteStream in one end, ReadStream in the other, or any other language if you send that byte cound as expected by INDY client.
If you're reading from a device, be sure the device is sending that info up-front the stream or change the way you read the data. If you know the size of the stream, just pass the second parameter: AByteCount. If the device will close the channel when the stream ends, pass -1 as the second parameter and True as the third parameter: AReadUntilDisconnect.
If the device send text of unknown length but using a known terminator (like CR/LF), you better use ReadLn method of IOHandler to get that string.
Take a look at if neither fits your needs, take a look on Read* methods of TIOHandlerClass and RTFM for each to find the correct one to get the data sent by the device.

Resources