MATLAB GUI with two push buttons exist. Each push button begins an execution of an infinite loop of reading a serial data from Com-Port(different). When I press a push button the while loop reading Serial port, but when I press the next push button, the port1 stops and then the port2 starts reading, and when I stops the port2, the port1 resuming.So here my question is, how all callback functions with while loops can work independently and simultaneously..
function samplegui_OpeningFcn(hObject, ~, handles, varargin)
handles.output = hObject;
handles.vec_A=[];
handles.vec_B=[];
handles.vec_C=[];
handles.vec_A_1=[];
handles.vec_B_1=[];
handles.vec_C_1=[];
guidata(hObject, handles);
function open_Callback(hObject, eventdata, handles) % push button1 to receive serial data.
cnt=0;
while 1
% Getting data from Serial Port
get_lines=fgets(handles.se) % getting data from serial port
if~isempty(get_lines)
cnt=cnt+1;
if strfind(get_lines,'T') %Parsing data
handles.vec_A=[handles.vec_A;[timet newword]];
plot(handles.vec_A(:,1),handles.vec_A(:,2:end),'r'); % plotting
% Same follows for parsing and plot vec_B and Vec_C
drawnow(); % to update the Plots
end
end
Pause(.05);
end
guidata(hObject, handles);
function open2_Callback(hObject, eventdata, handles) % push button2 to receive serial data.
cnt=0;
while 1
% Getting data from Serial Port
get_lines=fgets(handles.se2) % getting data from serial port2
if~isempty(get_lines)
cnt=cnt+1;
if strfind(get_lines,'T') % Parsing data
handles.vec_A_1=[handles.vec_A;[timet newword]];
plot(handles.vec_A_1(:,1),handles.vec_A_1(:,2:end),'r'); % plotting
% Same follows for parsing and plot vec_B and Vec_C
drawnow(); % to update the Plots
end
end
Pause(.05);
end
guidata(hObject, handles)
You cannot do this in MATLAB because it is only possible to execute one task at a time. The way around this would be to have a timer that listens to each serial port at a given interval and the push buttons start/stop this timer. You would not need a while loop with a pause in this case, you would just need a funciton that gets the data from a serial port once and call this function each time the timer fires.
%// Function called each time a timer is fired, gets data from specified serial port
function getData(hObject, handles, serialport)
get_lines = fgets(serialport);
if isempty(get_lines)
return
end
if strfind(get_lines,'T')
handles.vec_A = [handles.vec_A; [timet newword]];
plot(handles.vec_A(:,1),handles.vec_A(:,2:end),'r');
drawnow();
end
guidata(hObject, handles);
end
%// And for your button callbacks that will toggle the timers on/off
function open2_Callback(hObject, eventdata, handles)
if ~isfield(handles, 't2') || ~isvalid(handles.t2) || ~handles.t2.Running
%// Create a timer that checks the serial port twice a second
handles.t2 = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TimerFcn', #(s,e)getData(hObject, handles, handles.se2));
%// Start the timer
start(handles.t2);
else
%// Stop and destroy the timer
stop(handles.t2);
delete(handles.t2);
end
guidata(hObject, handles);
end
function open_Callback(hObject, eventdata, handles)
if ~isfield(handles, 't1') || ~isvalid(handles.t1) || ~handles.t1.Running
handles.t1 = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TimerFcn', #(s,e)getData(hObject, handles, handles.se1));
start(handles.t1);
else
stop(handles.t1);
delete(handles.t1);
end
guidata(hObject, handles);
end
Update
As mentioned by #Hoki in the comments, you could also set the byteAvailableFcn property of the serial connection which would automatically fire (somewhat assynchronously) when new data arrives. This would prevent you from having to periodically poll the serial port for new data.
function getData(serialport, hObject, handles)
get_lines = fgets(serialport);
if strfind(get_lines,'T')
handles.vec_A = [handles.vec_A; [timet newword]];
plot(handles.vec_A(:,1),handles.vec_A(:,2:end),'r');
drawnow();
end
guidata(hObject, handles);
end
set([handles.se2, handles.se1], 'BytesAvailableFcn', #(s,e)getData(s, hObject, handles);
function samplegui_OpeningFcn(hObject, ~, handles, varargin)
handles.output = hObject;
handles.vec_A=[];
handles.vec_B=[];
handles.vec_C=[];
handles.vec_A_1=[];
handles.vec_B_1=[];
handles.vec_C_1=[];
guidata(hObject, handles);
end
function getData_1(hObject, handles, serialport)
get_lines = fgets(handles.se_1);
if isempty(get_lines)
return;
end
if strfind(get_lines,'T')
handles.vec_A = [handles.vec_A; [timet newword]];
plot(handles.axes1,handles.vec_A(:,1),handles.vec_A(:,2:end),'r');
drawnow();
end
guidata(hObject, handles);
end
function getData_2(hObject, handles, serialport)
figure;
hold on;
ax(1)=subplot(3,1,1);
ax(2)=subplot(3,1,2);
ax(3)=subplot(3,1,3);
get_lines = fgets(serialport);
if isempty(get_lines)
return
end
if strfind(get_lines,'T')
handles.vec_A_1 = [handles.vec_A; [timet newword]];
plot(handles.vec_A_1(:,1),handles.vec_A_1(:,2:end),'r');
drawnow();
end
guidata(hObject, handles);
end
function open2_Callback(hObject, eventdata, handles)
if ~isfield(handles, 't2') || ~isvalid(handles.t2) || ~handles.t2.Running
%// Create a timer that checks the serial port twice a second
handles.t2 = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TimerFcn', #(s,e)getData_2(hObject, handles, handles.se2));
%// Start the timer
start(handles.t2);
else
%// Stop and destroy the timer
stop(handles.t2);
delete(handles.t2);
end
end
function open1_Callback(hObject, eventdata, handles)
if ~isfield(handles, 't1') || ~isvalid(handles.t1) || ~handles.t1.Running
%// Create a timer that checks the serial port twice a second
handles.t2 = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TimerFcn', #(s,e)getData_2(hObject, handles, handles.se2));
%// Start the timer
start(handles.t2);
else
%// Stop and destroy the timer
stop(handles.t2);
delete(handles.t2);
end
end
It is similar code while you given.. added while loop because It could not read data continously at the port.
Related
I have a GUI in Matlab, and several buttons, by one button I need to load a file (I don't want the directory to be shown) and by second button plot determined data.
Code for the first button:
[filename, pathname] = uigetfile({'*.xlsx;*.xls'});
Code for the second button:
fileID = fopen(strcat(pathname, filename), 'r');
handles.fileData = xlsread(strcat(pathname, filename));
axes(handles.axes1);
plot(handles.fileData(:,1),'-k')
hold on;
axes(handles.axes1)
plot(handles.fileData(:,2),'k')
I get an error message all the time:
Undefined function or variable 'pathname'.
HOw can I pass the function to the second button?
Thanks for your help in advance!
Ad hoc solution is using: setappdata and getappdata.
Example:
function pushbutton1_Callback(hObject, eventdata, handles)
setappdata(0, 'pathname', 'abc');
function pushbutton2_Callback(hObject, eventdata, handles)
pathname = getappdata(0, 'pathname'); % Return 'abc'.
Another simple solution is passing pathname in UserData member of the parent figure.
When both buttons are in the same figure, hObject.Parent is the handle to the figure, and UserData element is a "preparation" for passing data between GUI objects.
Example:
function pushbutton1_Callback(hObject, eventdata, handles)
hObject.Parent.UserData.pathname = 'abs';
function pushbutton2_Callback(hObject, eventdata, handles)
pathname = hObject.Parent.UserData.pathname; %Value is 'abc'
For more information refer to: https://www.mathworks.com/help/matlab/creating_guis/share-data-among-callbacks.html
Complete code sample without using guide tool:
I created the following sample without using guide tool because there is no simple way passing the fig file of guide in Stack Overflow.
function TestNoGuide()
clear all
close all
% Create figure
hObject = figure('position', [800 400 260 100], 'Toolbar','none');
% create structure of handles
handles = guihandles(hObject);
handles.hObject = hObject;
handles.pushbutton1 = uicontrol('style', 'pushbutton', 'position',[10 20 100 40], 'string' , 'Button1');
handles.pushbutton2 = uicontrol('style', 'pushbutton', 'position',[150 20 100 40], 'string' , 'Button2');
set(handles.pushbutton1, 'callback', {#pushbutton1_Callback, handles});
set(handles.pushbutton2, 'callback', {#pushbutton2_Callback, handles});
%Save the structure
guidata(hObject);
end
function pushbutton1_Callback(hObject, eventdata, handles)
[filename, pathname] = uigetfile({'*.xlsx;*.xls'});
setappdata(0, 'filename', filename);
setappdata(0, 'pathname', pathname);
end
function pushbutton2_Callback(hObject, eventdata, handles)
filename = getappdata(0, 'filename');
pathname = getappdata(0, 'pathname');
waitfor(warndlg(['filename = ', filename, ' pathname = ', pathname]));
end
Check it out, and tell me if it's working on your machine...
I am using awesome WM and I want to run a lua function after a client is created/deleted. Specifically, I want to change the name of a tag to the name of one of the clients that are on the tag.
I do this with a timer, but I think the best way to do this would be to register a callback function to awesomeWM that it will invoke when a client is created/removed.
Are there some hooks/callbacks that I can implement to tell awesome to do this for me?
---------------------------------------------UPDATE----------------------------------------
I tried using the signals, but i cant find the correct signal that changes calls my function AFTER the window is created and attached to the tag. I tried this with manage/unmanage tagged/untagged, and tag.new, etc, but no one helps.
Any ideas?
here is the code:
override_name_char = "<"
function tag_name_from_client(c)
if string.match(c.name, "Mozilla Firefox") then
return "Firefox"
end
if string.match(c.name, "Sublime Text") then
return "Sublime"
end
if string.match(c.name, "/bin/bash") then
return "Shell"
end
return ""
end
function tag_name_from_tag(tag)
if tag.name:match(override_name_char) then
return tag.name
end
for _, c in pairs(tag:clients()) do
return " "..tostring(awful.tag.getidx(tag)).." "..tag_name_from_client(c)
end
return tostring(awful.tag.getidx(tag))
end
function refresh_tag_name()
for s = 1, screen.count() do
for _,tag in pairs(awful.tag.gettags(s)) do
tag.name = tag_name_from_tag(tag)
end
end
end
client.connect_signal("tagged", refresh_tag_name)
client.connect_signal("untagged", refresh_tag_name)
--tag_timer = timer({timeout = 0.5})
--tag_timer:connect_signal("timeout", function()
--refresh_tag_name()
--end)
--tag_timer:start()
Thanks in advance for any help regarding this.
One of possible ways for v3.5.6, try this in your rc.lua
local naughty = require("naughty")
client.connect_signal("manage", function (c)
--filter client by class name
if c.class:lower() == "gedit" then
-- do things on client start
naughty.notify({text = "Gedit launched!"})
-- add exit signal for this client
c:connect_signal("unmanage", function() naughty.notify({text = "Gedit closed!"}) end)
end
end)
"A new client is created" is the manage signal.
"A new client was destroyed" is the unmanage signal.
So, something like the following (untested):
local function choose_name_for_tag(t)
for _, c in ipairs(t:clients() do
return "has client: " .. tostring(c.name or "unknown")
end
return "has no clients"
end
local function update_state()
for _, t in pairs(root.tags()) do
t.name = choose_name_for_tag(t)
end
end
client.connect_signal("manage", update_state)
client.connect_signal("unmanage", update_state)
tag.connect_signal("tagged", function(t)
t.name = choose_name_for_tag(t)
end)
tag.connect_signal("untagged", function(t)
t.name = choose_name_for_tag(t)
end)
I have multilevel game and all my objects stay 'empty' in memory between levels
what i mean is that if I set physics to hybrid, when i come again in the level, (or another level) it shows a box but without the picture. (and physics act on these empty boxes)
in the destroyScene I have made sure they are all
myObj:removeSelf()
myObj = nil
and i print a message to prove that it actually does it.
Also in the menu in the enterScene, just in case I do a
local prior_scene = storyboard.getprevious()
storyboard.purgescene( prior_scene )
and also tried a
storyboard.removeAll()
and even a
storyboard.purgeOnSceneChange = true
nothing works when i go to the next level, or into the same level again, all my previous objects are still here, I just don't get it
ok, it's gonna be a bit long but here the entire level. it does go through the destroyscene but somehow the display objects are not removed.
-- scene5
----------------------------------------------------------------------------------
local storyboard = require( "storyboard" )
local scene5 = storyboard.newScene()
function scene5:createScene( event )
local group = self.view
puppetJColCount = 0
print ("createScene5", puppetJColCount)
-----------------------------------------------------------------------------
-- CREATE display objects and add them to 'group' here.
-- Example use-case: Restore 'group' from previously saved state.
local physics = require("physics")
physics.start()
--physics.setScale(50)
puppetT_outside = false
puppetJ_outside = false
end -- scene -------------------------
-- set and release the catapult for puppetT
function arm_puppetT(event)
if event.phase == "began" then
display.getCurrentStage():setFocus(puppetT)
arming_puppetT = true
elseif event.phase == "moved" then
puppetT.x = event.x
puppetT.y = event.y
elseif event.phase == "ended" then
puppetT:applyLinearImpulse(event.xStart - event.x, event.yStart - event.y, puppetT.x, puppetT.y)
display.getCurrentStage():setFocus(nil)
arming_puppetT = false
end
end -- arm_puppetT ----------------------------------------------------------------------------
function build_puppetT()
-- setup puppetT
puppetT = display.newImage("assets/t-head-57-78.png")
puppetT.x = 80
puppetT.y = 100
physics.addBody(puppetT,"dynamic",{density=1.0, friction =0.3, bounce=0.2})
-- setup catapult event for arming puppetT
puppetT:addEventListener("touch", arm_puppetT)
end -- build_puppetT
function build_puppetJ_wall()
puppetJColCount = puppetJColCount + 1 -- how many columns of puppetJ
puppetJIJ = {} -- define puppetJ as an array
ij = 0
ipuppetJtot = 0
--puppetJColCount = 1
print ("build_puppetJ_wall puppetJColCount>" , puppetJColCount);
for i=1, 4 do
for j=1, puppetJColCount do
ij = ij + 1 -- # of puppetJs on the screen
ipuppetJtot = ipuppetJtot + 1
puppetJIJ = display.newImageRect("assets/j-head-70-75.png",80,75)
puppetJIJ.x = 600 + j*22
puppetJIJ.y = 100 + (puppetJIJ.height /2 * (i -1))
physics.addBody(puppetJIJ,"dynamic",{density=1.0,friction=0.3,bounce=0.2,isSensor=false,radius = var})
end
end
print ("building puppetJs #:" ,ipuppetJtot)
end -- build_puppetJ_wall -------------------------------------------------------------
function every_frame( event )
end -- every_frame --------------------------------------------------------------------
--reset level
function tap_reset_level(event)
puppetT:applyLinearImpulse(0, 0, 0, 0) -- stop the kick
print "restarting physics?"
puppetT:setLinearVelocity( 0, 0 ) -- stop the speed
puppetT.x = 80
puppetT.y = 100
for ij = 1,ipuppetJtot do
if (puppetJIJ) then
puppetJIJ:removeSelf()
puppetJIJ = nil ------
end
end
puppetT:removeSelf()
puppetT = nil
build_puppetJ_wall()
build_puppetT()
puppetT_outside = false
puppetJ_outside = false
-- physics.addBody(puppetT,"dynamic",{density=1.0, friction =0.3, bounce=0.2})
-- puppetT:addEventListener("touch", arm_puppetT)
--physics.start()
end -- tap_reset_level -------------------------------------------------------------------------
function tap_main_menu(event)
print ("going to main menu")
Runtime:removeEventListener("enterFrame", every_frame)
for ij = 1,ipuppetJtot do
if (puppetJIJ) then
puppetJIJ:removeSelf()
puppetJIJ = nil ------
end
end
if (puppetT) then
puppetT:removeSelf()
puppetT = nil
end
-- scene5:exitScene(scene5)
storyboard.gotoScene( "menu" )
end -- tap_main_menu ---------------------------------------------------------------------------------
-- ======================================================================================
-- Called immediately after scene has moved onscreen:
function scene5:enterScene( event )
local group = self.view
-----------------------------------------------------------------------------
-- INSERT code here (e.g. start timers, load audio, start listeners, etc.)
-- group:insert( reset_btn )
-- load background
print ("enterScene scene5 " , puppetJtot)
background = display.newImage("assets/parliament-1200-800.png",0,0)
--create reset level button
reset_btn = display.newImageRect( "assets/btn_reset_128.png", 50,50)
reset_btn.x = 50
reset_btn.y = 50
--create main menu button
main_menu_btn = display.newImageRect( "assets/btn_home_128.png", 50,50)
main_menu_btn.x = 100
main_menu_btn.y = 50
-- show the level
local myText = display.newText( "Level 5", display.contentWidth - 60, 50, "Helvetica", 24 )
myText:setTextColor(255, 255, 255)
-- insert(floor);
floor = display.newRect(20,display.contentHeight - 40,display.contentWidth - 40 ,10)
physics.addBody(floor,"static",{density=1.0, friction =-0.3,bounce=-0.2,isSensor=false})
-- build puppetT
build_puppetT()
print ("width=" , display.contentWidth , "height=",display.contentHeight)
-- setup puppetJs
build_puppetJ_wall()
-- everything happens in everyframe function
Runtime:addEventListener("enterFrame", every_frame)
--add reset event
reset_btn:addEventListener( "tap", tap_reset_level )
--add mainmenu event
main_menu_btn:addEventListener( "tap", tap_main_menu )
end -- scene:enterScene ----------------------------------------------------------------
-- ======================================================================================
-- Called when scene is about to move offscreen:
function scene5:exitScene( event )
local group = self.view
print "scene:exitScene5"
-----------------------------------------------------------------------------
-- INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.)
end -- exitScene
-- Called prior to the removal of scene's "view" (display group)
function scene5:destroyScene( event )
local group = self.view
Runtime:removeEventListener("enterFrame", every_frame)
puppetJColCount = 0
if (reset_btn) then
print ("destroyScene5 - removing tap_reset_level")
reset_btn:removeEventListener( "tap", tap_reset_level )
reset_btn:removeSelf()
end
reset_btn = nil
if (main_menu_btn) then
main_menu_btn:removeEventListener( "tap", tap_main_menu )
main_menu_btn:removeSelf()
end
main_menu_btn = nil
for ij = 1,ipuppetJtot do
if (puppetJIJ) then
puppetJIJ:removeSelf()
end
puppetJIJ = nil ------
end
if (puppetT) then
puppetT:removeSelf()
end
puppetT = nil
scene5 = nil
end -- destroyScene ------------------------------------------------------------
scene5:addEventListener( "createScene", scene5 )
scene5:addEventListener( "enterScene", scene5 )
scene5:addEventListener( "exitScene", scene5 )
scene5:addEventListener( "destroyScene", scene5 )
---------------------------------------------------------------------------------
return scene5
update:
Hi #DevfaR
Ha, I have restarted from scratch with the corona template and figured out a few things:
1) the exitScene/destroyScene actually does something if the local group is used to group display objects. it removes the display group !
not really obvious as there is only one declaration in it, no code as such
2) the reason why I had so much of removeSelf of objects all over the place is because nothing was working. So I tried pretty much everything under the web.
3) And the reason why it didnt work is because I was creating my display objects into a function. and somehow the display group is not passed there. if I move the code into the createScene function then indeed it is all cleared up when going to the next scene.
problem is .. I really would like to group my puppetCreation code !
e.g.
function scene:createScene( event )
local group = self.view
local physics = require("physics")
physics.start()
background = display.newImage("assets/bckg.png",0,0)
group:insert(background)
createPuppet1(group)
createPuppet2(group)
end
function createPuppet1(group)
puppet1= display.newImage("assets/puppet1.png",0,0)
group:insert(puppet1)
end
function createPuppet2(group)
puppet2= display.newImage("assets/puppet2.png",0,0)
group:insert(puppet2)
end
I passed (group) because the function createPuppet doesnt let me specify
local group = self.view
my email address is edualczatebed#gmail.com
thank you for your help
there's a lot of bug in your code the way you implement it is not good because when you go to a scene and then you switch to another scene your removing all of the object on the destroyScene together with it's listener which is not very efficient i cannot point out what's causing the problem because like i said there is a lot of bug in your code. i think you didn't quite understand how to use a storyboard on Corona. to give you an idea on how will you solve your problem i will implement some code for you to understand that even if you do not remove the object on destroyScene you can remove the object via it's on display groups.
local rectangle
local circle
local function nextScene(event)
storyboard.gotoScene( "scene_2", "fade", "500")
end
-- Called when the scene's view does not exist:
function scene:createScene( event )
local group = self.view
-----------------------------------------------------------------------------
rectangle = display.newRect(100,100,100,100)
rectangle:setFillColor(255,0,0)
rectangle.x = 100
rectangle.y = 100
circle = display.newCircle(100,100,50)
circle.x = 250
circle.y = 100
circle:setFillColor(0,255,0)
--inserting all of your object into display group so that if you destroy the scene the display group will be remove
group:insert(rectangle)
group:insert(circle)
-----------------------------------------------------------------------------
end
-- Called immediately after scene has moved onscreen:
function scene:enterScene( event )
local group = self.view
-----------------------------------------------------------------------------
rectangle:addEventListener("tap", nextScene)
circle:addEventListener("tap", nextScene)
-----------------------------------------------------------------------------
end
-- Called when scene is about to move offscreen:
function scene:exitScene( event )
local group = self.view
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
end
-- Called prior to the removal of scene's "view" (display group)
function scene:destroyScene( event )
local group = self.view
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
end
as you can see i create 2 object the rectangle and circle after i created the objects insert it to group then on enterScene i added a tap listener which will go to the second scene if i tap the object. notice that i didn't bother to remove the object and listener on destroyScene when i go to the scene_2 that is because when i insert the object to the display group whenever i change the scene it will always remove the object. so after moving to the next scene you can either purged the last scene or completely remove it so when you get back to that scene it will recreate the object.
hope this can help you solve your problem
I am creating a GUI in Matlab that will read and write data to a text file based on the trial duration. The user will enter the number of trials and trial duration and
then push the "start" button.
For example the user enters 5 trials at 10 seconds duration. While starting the 1st trial, I will need to read/write data continuously for 10 seconds, then stop and save the text file. This process will continue for the next 5 trials. Here is a brief code I tried to implement below.
How can I run both the timer for 10 seconds and simultaneously read/write data with that time limit?
Thanks in advance.
% Get Number of Trials
number_trials = str2double(get(handles.Number_Trials,'String'));
% Get Trial Duration
trial_duration = str2double(get(handles.Trial_Duration,'String'));
% Timer Counter
global timer_cnt
timer_cnt = 0;
global eye_data
eye_data = 0;
for i = 1:number_trials
% Set Current Trial Executing
set(handles.Current_Trial_Text,'String',num2str(i));
% Set Text File Specifications
data_fname = get(handles.Data_Filename_Edit_Text,'String');
file_fname = '.dat';
data_fname_txt = strcat(data_fname,file_fname);
% Timer Object
fprintf('%s\n','Timer Started');
% Pauses 10 Seconds
t = timer('TimerFcn','stat=false','StartDelay',10);
start(t);
stat = true;
while(stat == true)
disp('.');
pause(1)
end
fprintf('%s\n','Timer Ended');
delete(t);
end
In my experience, timers are usually used in the context of "wait this amount of time, then do foo" rather than how you're using it, which is "do foo until you've done it for this amount of time".
The humble tic/toc functions can do this for you.
t_start = tic;
while toc(t_start) < 10
% do data collection
end
I want my bot sends and receives messages in parallel threads. I also want my bot sends message back to user when receives any message from user. But now he sends it back to user every 5 seconds. I understand that it's because i used "loop do" but without infinity loop i cant use callbacks.
So how to send and receive messages in parallel threads? And how to overcome my "loop problem" when receiving messages?
require 'xmpp4r'
class Bot
include Jabber
def initialize jid,jpassword
#jid = jid
#jpassword = jpassword
#client = Client.new(JID::new(#jid))
#client.connect
#client.auth(#jpassword)
#client.send(Presence.new.set_type(:available))
end
def wait4msg
loop do
#client.add_message_callback do |msg|
send_message(msg.from,msg.body)
sleep 5
end
end
end
def send_message to,message
msg = Message::new(to,message)
msg.type = :chat
#client.send(msg)
end
def add_user jid
adding = Presence.new.set_type(:subscribe).set_to(jid)
#client.send(adding)
end
end
bot = Bot.new('from#example.xmpp','123456')
t1 = Thread.new do
bot.wait4msg
end
t2 = Thread.new do
bot.send_message('to#example.xmpp',Random.new.rand(100).to_s)
end
Thread.list.each { |t| t.join if t != Thread.main }
Good day. You can use callbacks without loop, see an examples. For example: in initialize add
#client.add_message_callback do |m|
if m.type != :error
m2 = Message.new(m.from, "You sent: #{m.body}")
m2.type = m.type
#client.send(m2)
end
end