Saving data of command window from callback function

Hi guys,
I am using a callback function which reads a characteristic of a bluetooth module to achieve high sampling frequency. But since I am now using callback function I am not able to store the data as I wish. I can display it and see it in the command window but I want it as variables in the workspace. How can I achieve that?
Right know I just see my values in the command window and am not able to store it in workspace.
%% Setup connection
bt = ble("RN4871-BT_C719");
c = characteristic(bt,"59C88760-5364-11E7-B114-B2F933D5FE66","0F300FD5-78CD-4449-8865-A84136B8A286");
%% read values
tic;
c.DataAvailableFcn = @displayCharacteristicData;
%%
unsubscribe(c);
%% callback function
function displayCharacteristicData(src,~)
data = read(src,'oldest');
disp(data);
toc;
end
When I tried this I got the error message that there it could not find the variable "i"
%% Setup connection
bt = ble("RN4871-BT_C719");
c = characteristic(bt,"59C88760-5364-11E7-B114-B2F933D5FE66","0F300FD5-78CD-4449-8865-A84136B8A286");
%%
s = 1000;
i = 1;
t = zeros(1,s);
v1 = zeros(1,s);
v2 = zeros(1,s);
tic;
c.DataAvailableFcn = @displayCharacteristicData;
%%
unsubscribe(c);
%%
function displayCharacteristicData(src,~)
data = read(src,'oldest');
v1(i)=data(1);
v2(i)=data(2);
t(i)=toc;
i=i+1;
end

1 comentario

hello
is there any reason why data cannot be output of your function ?
function data = displayCharacteristicData(src,~)

Iniciar sesión para comentar.

Respuestas (1)

Jan
Jan el 22 de En. de 2021
function data = displayCharacteristicData(src,~, Flush)
persistent Store
if isempty(Store)
Store = struct('v1', [], 'v2', [], 't', []);
end
if nargin == 3
data = Store;
Store = [];
end
data = read(src,'oldest');
i = numel(Store.v1) + 1;
Store.v1(i) = data(1);
Store.v2(i) = data(2);
Store.t(i) = toc;
end
Now the data are collected persistently inside the callback and flushed, of you call the callback with 3 inputs.
Note that this let the Struct grow iteratively, which consumes a lot of ressources. A smarter method would be to increase the size in steps and crop them finally:
function data = displayCharacteristicData(src,~, Flush)
persistent Store
if isempty(Store)
Store = struct('v1', zeros(1, 1000), 'v2', zeros(1, 1000), 't', zeros(1, 1000), 'count', 0);
end
if nargin == 3
data = Store;
Store = [];
end
data = read(src,'oldest');
count = Store.count + 1;
if count > numel(Store.v1)
Store.v1(count + 1000) = 0;
Store.v2(count + 1000) = 0;
Store.vt(count + 1000) = 0;
end
Store.v1(count) = data(1);
Store.v2(count) = data(2);
Store.t(count) = toc;
Store.count = count;
end
I'd use clock instead of tic/toc.

6 comentarios

Hi Jan,
Thank you for your answer. But using your solution I got an error:
"Invalid value for DataAvailableFcn. Specify [] or a function handle that accepts two inputs."
So I did use the same procedure as proposed here for the callback function: https://www.mathworks.com/help/matlab/ref/matlabshared.blelib.characteristic.read.html
Then define a further function as so called wrapper:
function displayCharacteristicData_CB(src, event)
displayCharacteristicData(src, event);
end
Now the callback has its function with 2 inputs, while the data collection is done inside your function, which can flush the data on demand.
I don't understand this either.
With timer and serial callbacks you can add input arguments to the callback function. In this simple example the Line object is passed to the timercallback to change the data plotted
t = timer;
t.BusyMode = 'drop';
t.ExecutionMode = 'fixedRate';
t.TasksToExecute = 10;
t.Period = 1;
p = plot(0:10, 0:10);
axis([0 10 0 100])
t.TimerFcn = {@myTimerCallback, p};
%%
start(t)
%%
function myTimerCallback(obj, evt, p)
p.YData = p.YData+1;
end
In AppDesigner, I can also use
%app.p is a property defined elsewhere in the app
t.TimerFcn = @app.myTimerCallback;
%%
function myTimerCallback(app, obj, event)
app.p.YData = app.p.YData+1;
end
I figured for the ble notification callback, c.DataAvailableFcn should be able to replace t.TimerFcn above but I get the same error as @Sakin Sivakurunathar:
Invalid value for DataAvailableFcn. Specify [] or a function handle that accepts two inputs.
I can accomplish getting the Line Object into the callback by using a global variable but that is something I try to avoid.
@Jan, in your wrapper example, both the wrapped and wrapper function have the same inputs so how does this actually help getting outside data into the callback without using a global variable. I would like to implement the ble notification callback in AppDesigner, so I need to be able to pass the app argument in order for the callback to be able to update UI elements within the app from the callback.
I had the same problem when using the BLE subscrition callback with AppDesigner.
Here's how I solved it:
% Definition of the function to callback
function displayCharacteristicData(app, src)
Data = read(src,'oldest');
disp(Data)
end
% Passing of the callback function elsewhere in the app
app.c.DataAvailableFcn = @(obj,event)app.displayCharacteristicData(obj);
So do you know if there is a way without using Appdesigner? Because I still could not figure out how to solve my problem.

Iniciar sesión para comentar.

Categorías

Más información sobre App Building en Centro de ayuda y File Exchange.

Productos

Preguntada:

el 21 de En. de 2021

Comentada:

el 21 de Feb. de 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by