Matlab Serial Port: ErrorFcn Callback is not executed after Timeout - matlab

i'm trying to do some serial communication with matlab.
Settings are:
9600 baude
8 databits
0 paritybit
1 stopbit
main .m-file
SYN = 1;
FIN = 2;
ACK = 4;
NAK = 8;
PWM = 16;
MAG = 32;
txByte = 0;
rxByte = 0;
serobj = serial('COM3');
set(serobj,'Baudrate', 9600);
set(serobj,'Parity', 'none');
set(serobj,'Databits', 8);
set(serobj,'StopBits', 1);
set(serobj,'FlowControl', 'none');
set(serobj,'ErrorFcn',#TimeOutErrorFcn);
set(serobj,'Timeout',1);
fopen(serobj);
% Start the handshake
fwrite(serobj, SYN, 'uint8');
% wait for answer
rxByte = fread(serobj,1,'uint8');
if(isempty(rxByte))
rxByte = 255;
end
% what is the answer?
switch (rxByte(1))
case ACK+SYN
fwrite(serobj, ACK, 'uint8');
case NAK
fclose(serobj);
otherwise
fwrite(serobj, NAK, 'uint8');
fclose(serobj);
end
while(strcmp(get(serobj, 'Status'),'open'))
% Do some communication
end
callback function as .m-file
function TimeOutErrorFcn(obj, event)
%TIMEOUTERRORFCN Summary of this function goes here
% Detailed explanation goes here
disp('Error');
% close the connection here, send FIN and do fclose(serobj)
end
After the timeout is exceeded, the TimeOutErrorFcn is not called! All i get is the following output on the command promt:
Warning: The specified amount of data was not returned within the Timeout period.
Mathsworks help says:
Timeout
Waiting time to complete a read or write operation
You configure Timeout to be the maximum time (in seconds) to wait to complete a read or write operation.
If a time-out occurs, the read or write operation aborts. Additionally, if a time-out occurs during an asynchronous read or write operation, then:
An error event is generated.
The callback function specified for ErrorFcn is executed.
ErrorFcn
Specify the callback function to execute when an error event occurs
expand all in page
Description
You configure ErrorFcn to execute a callback function when an error event occurs.
Note An error event is generated only for asynchronous read and write operations.
An error event is generated when a time-out occurs. A time-out occurs if a read or write operation does not successfully complete within the time specified by the Timeout property. An error event is not generated for configuration errors such as setting an invalid property value.
If the RecordStatus property value is on, and an error event occurs, the record file records this information:
The event type as Error
The error message
The time the event occurred using the format day-month-year hour:minute:second:millisecond
To learn how to create a callback function, see Creating and Executing Callback Functions.
So, I really don't see my mistake.

You aren't doing an asynchronous read operation, so therefore an error event doesn't occur. Instead, it is a warning. To force your error function to run, you need to tell Matlab to label that warning as an error. Try adding this to the top of your code:
warning('error', 'instrument:fread:unsuccessfulRead');
If there are other warnings that you want to flag as errors, you can get the command by issuing "verbose on".

Related

Non blocking UDP receiver in Matlab GUI

I'm creating a MATLAB GUI using the app designer (very similar to, but better than, GUIDE) which I want to use to monitor the data output of my simulink model in real time.
In other words, I have a simulink model and a GUI, both running in the same MATLAB instance and I want to send packets over UDP from the simulink model and use that data in my GUI to update plots. However, I don't know how to read the data from the UDP packet without blocking.
Is there a way to bind a handler when a packet is received so that I can execute a function to update plots/fields?
Of course, beside BytesAvailableFcn matlab has the datagramreceivedfcn to call your custom function on new dagatrams, which is nonblocking while fread/fscanf are blocking (temporarily). Regarding callbacks in matlab read events and cbs
Compilable standalone could look like:
%% standalone main
%{
see docs/*
%}
function exitcode = main(port, remotePort)
% sanitize input
if(~exist('port','var') || ~exist('remotePort','var'))
disp(['args: port remotePort']);
exit(1);
end
if ischar(port)
port=str2num(port);
end
if ischar(remotePort)
remotePort=str2num(remotePort);
end
% create udp object
u = udp('127.0.0.1',remotePort, 'LocalPort', port);
% connect the UDP object to the host
fopen(u);
exitcode = 0;
% since we poll, suppress warning
warning('off','instrument:fscanf:unsuccessfulRead');
warning VERBOSE
% specify callback on datagram
while true
msgEnc= fscanf(u);
% timed out without datagram
if isempty(msgEnc)
continue
end
% do sth with msgEnc (which is a readable string)
fprintf(u, 'heard sth'); %answer
end
end
If you would like to use simulink block use udpreceive
which has a non-blokcking capability
A First In First Out (FIFO) buffer receives the data. At every time
step, the Data port outputs the requested values from the buffer. In a
nonblocking mode, the Status port indicates if the block has received
new data.

Serial async write: How to add data to the output buffer & weird output buffer behaviour

I am using asynchronous serial write operation to send data. Using fwrite() I cannot send data if a write operation is already in progress. It returns an error:
Unsuccessful write: An asynchronous write is already in progress.
How can I simply add the extra data I need to write to the existing output buffer, instead of having to wait for it to finish?
Also, I tried to see the number of bytes left to output, but it would either show the full number (511, default size) or zero. So I increased the size of the output buffer to 100,000 sent that many items and plotted the BytesToOutput, this is what I got:
It drops from ~25,000 directly to 0!? Can anyone explain this please?
Here is my code:
instrreset; %closes, deletes and clears all available serial objects
s=serial('/dev/ttyACM0');
s.BaudRate= 1000000;
s.Timeout= 0.1;
s.OutputBufferSize= 100000;
fopen(s);
data=[1:99999];
bytesLeft=zeros(1,100000);
disp('sending data now... wait for it to complete')
tic()
fwrite(s, data, 'uint8', 'async');
f=1;
while ( strcmp(s.TransferStatus, 'write') )
bytesLeft(f)=s.BytesToOutput;
f=f+1;
%disp(s.BytesToOutput)
end
toc()
plot(bytesLeft);
fclose(s);
delete(s);
clear s;

Reading raw serial data in Matlab

I'm trying to read some raw telemetry data via serial. Each message terminates with \r\n and there are 4 kinds of messages.
I setup the port like this:
if exist('s')
fclose(s);
delete(s);
clear s;
end
s = serial('/dev/ttyS99');
s.BaudRate = 57600;
s.BytesAvailableFcnMode = 'terminator';
s.Terminator = 'CR/LF';
s.DataBits = 8;
s.Parity = 'none';
s.StopBits = 1;
s.BytesAvailableFcn = #serial_callback;
s.OutputEmptyFcn = #serial_callback;
fopen(s);
For the calback, i wrote a simple function
function serial_callback(obj, event)
if (obj.BytesAvailable > 0)
[serial_out, count] = fscanf(obj);
disp(count)
end
end
end
Using fscanf, I get random message lengths. For instance, I am searching for a message with length 42, and it only retrieves messages with length near that value (40, 43, 46...).
I i use fread with unspecified size, I allways get a full 512 bytes buffer. If I specify the size in fread with get(obj, 'BytesAvailable), it degenerates in the sizes of fscanf, i.e., totally random.
So, am I doing something wrong, is matlab bad for parsing serial data...?
P.S. I am getting something like 40 messages of 20~40 bytes per second.
Call the callback function everytime a \r\n has been received, using BytesAvailableFcnMode to configure. fscanf should only be called when a line is completely received by the buffer.
Use fgets or fgetl to read one line from file. This will keep all things after the first \r\n in the buffer. I don't have a serial port nor a Tek so I can't verify this to be working for serial ports.
Probably you need a while loop to read all lines in the buffer. Again I'm not sure how serial does callback but it's unlikely to continuously triggering callback function when there's nothing newly arrived after callback has been called.

Passing variable from event handler

I would be very grateful for help, advice or suggestion. I have an application to control geodetic instrument using synchoronous interface. However some commands are asynchronous by its nature, e.g. GetReflectors. After this command is triggered I receive as many server answers as is the number of available reflectors. So I have registered an COM event and associate handler function. So far so good. I can display the data coming but I do not know how to pass some variable to the main function. I tried to save variable as .mat file or in .txt file and read it. Actually it works in Matlab but it does not works in compiled .exe aplication (Error firing event). Even disp command does not work in compiled aplication (display nothing). So the main question is: how to pass variables from handler to main function. Is there a way? Global variables? Thank you Filip
Edit: I am adding an code to demostrate the problem... I need to save Reflector Name and Reflector ID so as the user can choose one (because there are multiple events coming with different Reflectors).
function pushbutton_GetReflectors_Callback(hObject, eventdata, handles)
ltsync = actxserver ('LTControl.LTCommandSync2'); %Act as server: LTConnect2
ltsync.events() %List of all COM events
ltsync.registerevent({'ReflectorsData' 'ReflectorsHandler'}) %Register event
ltsync.GetReflectors() %Ask instrument for reflectors
pause(3) %Time to receive answers
end
function ReflectorsHandler(varargin) %Handler of the event ReflectorsData
%var1,var2,reflectorID,reflectorName,var5,surfaceOffset,reflectorsTotal,var8,var9
disp('Reflector Data:');
disp(varargin{3}) %Reflector ID
disp(varargin{4}) %Reflector name
end
I believe you can solve this problem by passing a function handle to registerevent instead of just the string function name, and creating a class to allow you to pass the data back. First, the class:
classdef ReflectorsResponse < handle
properties (SetAccess = private)
reflectors
responseComplete = false;
reflectorsTotal = NaN;
end
methods
function respond(obj, varargin)
% Create a struct for each reflector (or you could define
% another class, but let's keep it simple for the time being)
newRefl = struct();
newRefl.ID = varargin{3};
newRefl.name = varargin{4};
newRefl.surfaceOffset = varargin{6};
% ... store other properties in struct
% Store this reflector
obj.reflectors = [obj.reflectors; newRefl];
% Store total reflector count and check for completion
if isnan(obj.reflectorsTotal)
obj.reflectorsTotal = varargin{7};
end
if length(obj.reflectors) == obj.reflectorsTotal
obj.responseComplete = true;
end
end
end
end
You can then use this by making the respond method your handler:
function pushbutton_GetReflectors_Callback(hObject, eventdata, handles)
% Create the response object and associated handler function handle
response = ReflectorsResponse();
handlerFun = #(varargin)response.respond(varargin{:});
ltsync = actxserver ('LTControl.LTCommandSync2'); %Act as server: LTConnect2
ltsync.events() %List of all COM events
ltsync.registerevent({'ReflectorsData' handlerFun}) %Register event
ltsync.GetReflectors() %Ask instrument for reflectors
% Wait for request to complete
while ~response.responseComplete
pause(0.1);
drawnow update;
% NOTE: Should add a timeout to this loop
end
% Do stuff with response.reflectors
end
This will wait until there has been a response for each of the reflectors, the number of which is determined from the first response. Note that you should add a timeout to the while loop, otherwise you risk waiting infinitely.
If there are lots of these asynchronous requests that you have to handle, I would suggest encapsulating the entire request/response sequence (including the creation of the ActiveX server, setup of the event handler, and waiting for the response(s)) in a generalised base class, and deriving specific subclasses for each different request.

Specifying timeout when reading URL image with MATLAB imread function

The MATLAB imread function provides the ability to read an image from a URL. This generally works OK, but occasionally I encounter an image that takes a very long time to respond.
For instance, at the time of posting the following URL appears to just be stuck in a 'connecting...' state for over 5 minutes before finally succeeding.
http://www.hollywoodheadache.com/wp-content/uploads/2007/12/tom-and-julia.jpg
Is there any way I can set a timeout within MATLAB?
Thanks
I don't know how to interrupt imread with a timer object. Besides, I suspect about its possibility. But I may recommend you to check whether you can access to the file first, and then, you get the file. I have written the following function to check the file and internet status:
function flag = does_url_exist(urlName)
url =java.net.URL(urlName);
try
link = openStream(url);
parse = java.io.InputStreamReader(link);
snip = java.io.BufferedReader(parse);
if ~isempty(snip)
flag = 1;
else
flag = 0;
end
catch exception
flag = 0;
end
end
Then it is as follows:
fname = 'http://www.hollywoodheadache.com/wp-content/uploads/2007/12/tom-and-julia.jpg';
if(does_url_exist(fname))
img = imread(fname);
end
Note that for internet connection checking, I took the initial code from this post. Also note that if you are sure that the file exists, it is not efficient to check it again since it increases the running time.