How does Matlab determine size of BytesAvailable for Serial Connection? - matlab

How does Matlab determine the value of the BytesAvailable which is used in the tmtool for serial connection?
I have to send, say 512 bytes from my Matlab to my device over UART. The problem is only 96 bytes are sent to my device. i don't understand what happened to my remaining bytes! FYI: The value of BytesAvailableFcnCount being shown now is 48. On checking here, I found that the default value is 48. So I increased it to 512; but the same issue recurred. I have BytesAvailable being shown still 95!
Please suggest me some way. I have pasted the code in which I am trying to do this:
fopen(obj1); //obj1 is the name of my serial object
A = fopen('Path of the file I am using');
txdata = fread(A,[5 100],'uint8','ieee-be');
[my_count_rows, my_count_columns]=size(txdata);
for my_i = 1:my_count_columns
for jjj = 1:my_count_rows
fwrite(obj1,txdata(jjj,my_i),'uint8');
end
end

Related

Matlab: TCP Connection Fread data Size Warning Error

I have a TCP server in my Matlab code, my client sends some data (max 4 bytes) on some triggers from another application to Matlab. I am receiving those numbers but I am also receiving this warning message many times:
Warning: The specified amount of data was not returned within the Timeout period. 'tcpip' unable to read all requested data. For more information on possible reasons, see TCPIP Read Warnings.
clc;
t = tcpip('0.0.0.0', 55000,'InputBufferSize', 1024,'NetworkRole','Server', 'TimeOut', 0.5);
fopen(t);
while(1)
data = fread(t, 4, 'char');
dataChar = char(data);
dataDouble = str2double(dataChar);
if (~isnan(dataDouble))
if (dataDouble == 0)
fclose(t); % closing the tcp connecting
error('0 value is received!') % to jump out of Matlab run mode
else
disp("Last Receieved double was: " + dataDouble)
end
end
end
I also tried get(obj1,'BytesAvailable'), but it gives me error. Does anyone know how to bypass this warning?
You are trying to read data from the tcpip object while there is non to be read (i.e. the buffer is already empty). Matlab will wait for a while to see if anything comes, then issue a warning.
The normal way to work with tcpip obj is execute a callback on a certain event, and use this callback to read data from the buffer.
There are two modes: either trigger the buffer when a certain terminator is found (e.g. a line feed, if reading text) or when a certain number of bytes have been received.
Assuming all messages have a byte length 4, the syntax would be:
t = tcpip('0.0.0.0', 55000,'InputBufferSize', 1024,'NetworkRole','Server', 'TimeOut', 0.5);
t.BytesAvailableFcnCount = 4; % n=4
t.BytesAvailableFcnMode = 'byte'; %Read after n bytes have been received
t.BytesAvailableFcn = #myTcpipCallback;
fopen(t);
The callback will be called each time 4 bytes have been received. The callback function syntax would be:
function myTcpipCallback(obj,evt)
data=fread(obj,4,'char'); %Read 4 characters
% ... do something with data ... %
if bad_data_received==true
fclose(obj);
end
end
The while loop is not necessary, it is already handled internally by the tcpip object. The syntax of the callback function follows the Matlab standard callbackFunction(obj,evt) where obj is the object from where the event triggering the callback comes (here a tcpip object, but graphic objects work the same) and evt a structure containing data about the event (e.g. IP/port from where the message comes; for a KeyPress event that would be the key and modifiers).
You write that the client on another application will sent maximum 4 bytes. It is really more convenient to have a fixed the number of bytes (this can be achieved by padding messages on the client side) or some terminator should mark the end if the massages.
Working with a terminator (assuming for instance each message ends up with a line feed), the syntax would be:
t.BytesAvailableFcnMode = 'terminator';
t.Terminator = char(10); % or newline or recent versions of Matlab
and the callback
function myTcpipCallback(obj,evt)
data=[obj.UserData ; fread(obj,obj.BytesAvailable,'char')]; %Read all available characters
%Just in case, check that we have not received more than one message
term=[0;find(data==obj.Terminator)];
for ii=1:length(term)-1
msg=data(term(ii)+1:term(ii+1));
%Do something with msg%
end
obj.UserData=data(term(ii)+1:end);
end
If the client sends data fast, some extra data could have been bufferized while the callback function was waiting in the queue, so by the time it is executed, there could be several messages available. The code should take that possibility into account. Unfortunately, the number of bytes available in the buffer when the callback has been triggered is not in the event data.
Finally, if you intend to receive messages of arbitrary length with complex rules to determine if it is complete or not, another possibility is to read bytes one by one and have your own a buffer somewhere, e.g. in the object userdata.
t.BytesAvailableFcnCount = 1; % n=1
t.BytesAvailableFcnMode = 'byte'; %Read after n bytes have been received
and the callback:
function myTcpipCallback(obj,evt)
% Bufferize
obj.UserData=[obj.UserData ; fread(obj,1,'char')]; %Read 1 byte
% Check if the message if known
msg = obj.UserData;
if isComplete(msg) %
obj.UserData=[]; % empty buffer
processMessage(msg); % do something with message
end
end

marshalling arbitrary-length binary data from udp() object

I am reading binary data from instrumentation using the Matlab udp() object.
I am surprised by the apparent lack of support for reading arbitrary length data types. How does one read a 24-bit integer? Or a 24-bit float? These are not that strange in instrumentation, and I have found only 8/16/32/64 data types in the documentation.
Have you looked tried help fread? The documentation shows it supports reading up to 64 bits at a time using bitN where N is a value between 1 and 64.
fid = udp(<your parameters here>); % use fopen to open the stream.
...
A = fread(fid,1,'bit24=>int32'); % stream 24 bits to a 32 bit integer.
B = fread(fid,1,'ubit24=>uint32'); % stream 24 bits to a 32 bit unsigned integer.
Since floating point specs vary, so this may or may not work for your situation:
C = fread(fid,1,'bit24=>float32'); % transcode 24bits to 32 bit float (MATLAB spec)
UPDATE
Seeing that the udp/fread implementation does not support this casting there are a couple, not-so-pretty, workarounds you can try.
Read in uchar data in multiples of three and then multiply it by their byte offsets directly. For example:
% First determine number of bytes on the stream and make sure you
% have at 3 or more bytes to read so you can calculate thirdOfBytesExpected.
[anMx3result, packetCount] = fread(fid,[thirdOfBytesExpected,3]);
unsigned20bitInt = anMx3result*(2.^(0:8:16))';
To be precise, the unsigned20bitInt is actually stored as a MATLAB double here. So if you need to write it elsewhere, you will need to bring it back to the individual uchar types it came from.
The not so pretty option is to eat the overhead of streaming the data back to a binary file format as an interim step so that you can then use the base fread method mentioned above. Not an ideal solution, but perhaps worth considering if you just need something to work.
% your original code for opening the udp handle
....
tmpFid = fopen('tmp.bin','rw');
[ucharVec, bytesRead] = fread(udpFid,bytesExpected,'uchar=>uchar');
bytesWritten = fwrite(tmpFid,ucharVec,'uchar');
% Do some quality control on bytes read vs written ...
fseek(tmpFid,-bytesWritten,'cof');
% in theory you should be able to just go to the beginning
% of the file each time like this fseek(tmpFid, 0, 'bof');
% provided you also reset to the beginning prior writing or after reading
% Read in the data as described originally
num24ByteIntsToRead = bytesWritten/3;
A = fread(tmpFid,num24BytsIntsToRead,'bit24=>int32');

Real Time Data Import from Arduino to Matlab. What BufferSize? Why delay?

I am using a Kitronyx Snowboard (it has an Arduino Leonardo) with the Matrix Sensor 1610. I want to read my data from the serial port directly into Matlab and visualize it.
I have two problems which I think are related:
First of all I can read the Matrix but with a delay. The longer I wait the longer the delay.
Second of all after a while I’ll always get:
Error using serial/fprintf (line 144)
Unexpected error: A timeout occurred during the write operation..
The bigger the InputBufferSize the longer I can plot my data (which doesn’t really matter because of problem one)
How do I know what’s the convenient buffer size? Has anyone any idea why the delay and how I can get rid of it?
Thank you so much in advance
Mike
close all %close all figures
clear all %clear all workspace variables
fclose('all') %close all Files
delete(instrfindall) %Reset Com Port
delete(timerfindall) %Delete Timers
% setup serial
serialPort = serial('COM3');
command = 'A';
nrow = 16;
ncol = 10;
row_index = [9,10,11,12,13,14,15,16,8,7,6,5,4,3,2,1];
col_index = [1,2,3,4,5,6,7,8,9,10];
% 10x16 = 160 bytes
lendata = 160;
BaudRate = 11520;
InputBufferSize = 115200;
Timeout = 5;
set(serialPort , 'BaudRate', BaudRate);
set(serialPort , 'InputBufferSize', InputBufferSize);
set(serialPort , 'Timeout', Timeout);
fopen(serialPort);
while 1
% Request data
fprintf(serialPort, command);
% Get data
%Data is read as string (CSV)
data_string = fgets(serialPort);
data_string_array = strsplit(data_string, ',');
data = str2double(data_string_array);
% Reshape data (1D -> 2D array)
data2d = zeros(nrow, ncol);
k = 1;
for i = 1:nrow
for j = 1:ncol
data2d(row_index(i), col_index(j)) = data(k);
k = k + 1;
end
end
%resize 16x10 image to 160x100 image
data2d_resized = imresize(data2d,50);
imshow(data2d_resized,[0 100]);
end
I don't think we have enough information to give a definitive answer, but there are some considerations.
1) The input buffer is just memory that is set aside to hold data that is received at the serial port. Data fills the buffer until you remove it with a read statement (fgets(), fread(), etc). As long as the buffer size is larger than the amount of data you will receive between read cycles (see below), and it is a small number relative to the RAM available, it will not be a problem.
2) The command fgets() returns the line terminator characters with the string. You don't need these characters; consider using fegtl() or fscanf() instead.
3) The symptoms you describe make it sound like the Arduino is sending a more data with each iteration, or it is sending data faster than your Matlab program can process it. Your code is written in such a way that if more data arrives than you expect, you will not notice this until the input buffer is full and things start crashing.
Try printing the size of the data in the input buffer (disp(serialPort.BytesAvailable)) and the length of the string returned in each iteration.
If this is the problem, you may have to implement some flow control- have the Matlab program send a character back to the Arduino when it is ready for more data. Or read all the data from the input buffer in each read cycle, not just one line.
4) If matlab execution speed is an issue, consider replacing the "Reshape" loop with the reshape command. For loops are always slower than built-in functions.

Terminator in MATLAB serial not working properly

I have a proble regarding the Terminator in Matlab serial component.
% Open a port
port = serial (comPort, 'Baudrate', 38400, 'Flowcontrol', 'none' ...
,'Parity', 'none', 'StopBits', 1, 'DataBits', 8 ...
,'Terminator', {'CR/LF', 'CR'}...
);
fopen (port);
initCmd = '/1ZR';
% initialize pump
fprintf(port, '%s\n', initCmd);
reply = fscanf(port)
The communication protocoll of my pump demands a carriage return for send and replies with a carriage return AND a line feed (and I hope I defined it right in the example code.
When I now send the initialization command, the pump initiates properly and sends the following reply:
>> reply =
ÿ/0#
>> int8(reply)
ans =
127 47 48 64 3 13 10
But I get the following warning even though the reply contains CR/LF:
Warning: Unsuccessful read: A timeout occurred before the Terminator was reached.
The reply is correct except for the 127. I do not expect this according to the manual. Is MATLAB interpreting the answer wrong completely?
Where is the problem? The last to numbers 13 10 represents the Terminator, but MATLAB is not able to detect it?

Serial Comunnication between matlab and arduino

I am trying to send data from MATLAB to ARDUINO using the following code for arduino and the second one for the matlab. Both code work fine and when i press 1 led lights up and when press 2 led become off. But actually what i am trying to do is when matlab run code it automatically send 1 to arduino and the led become on. i have tried may changes but cant able to do. when iam trying to run the third code (given below) the arduino status led blink that show it receive some thing but my actual led which is connected to pin 13 still off.
int ledPin=13;
int matlabData;
void setup()
{
pinMode(ledPin,OUTPUT);
Serial.begin(9600);
}
void loop()
{
if(Serial.available()>0) // if there is data to read
{
matlabData=Serial.read(); // read data
if(matlabData==1)
digitalWrite(ledPin,HIGH); // turn light on
else if(matlabData==2)
digitalWrite(ledPin,LOW); // turn light off
}
}
(MATLAB)
1.
clear all
2.clc
3.
4.answer=1; % this is where we'll store the user's answer
5.arduino=serial('COM4','BaudRate',9600); % create serial communication object on port COM4
6.
7.fopen(arduino); % initiate arduino communication
8.
9.while answer
10. fprintf(arduino,'%s',char(answer)); % send answer variable content to arduino
11. answer=input('Enter led value 1 or 2 (1=ON, 2=OFF, 0=EXIT PROGRAM): '); % ask user to enter value for variable answer
12.end
13.
14.fclose(arduino); % end communication with arduino
(MY edit code)
1.
clear all
2.clc
3.
4.answer=1; % this is where we'll store the user's answer
5.arduino=serial('COM4','BaudRate',9600); % create serial communication object on port COM4
6.
7.fopen(arduino); % initiate arduino communication
8.
9.%while answer
10. fprintf(arduino,'%s',char(answer)); % send answer variable content to arduino
11. answer='1'%('Enter led value 1 or 2 (1=ON, 2=OFF, 0=EXIT PROGRAM): '); % ask user to enter value for variable answer
12.%end
13.
14.fclose(arduino); % end communication with arduino
The difference is the following:
answer = input('bla')
yields an answer that is a number, i.e. answer is of type double. In your third case, you wrote answer='1' which is a char, so in fact, the variable answer is different in both cases. Try and change the code in the third part to this here:
answer = 1;
or change the fprintf command to
fprintf(arduino, '%s', str2num(answer));