Opticka 2.18.1
Opticka is an experiment manager for behavioral research.
Loading...
Searching...
No Matches
jzmqConnection Class Reference
Inheritance diagram for jzmqConnection:

Public Types

enum  Events { time }
 poll socket to identify whether we can send ('out') or receive ('in') More...
 

Public Member Functions

function jzmqConnection (in varargin)
 
function open (in me, in context)
 Class constructor for jzmqConnection.
 
function poll (in me, in events, in time)
 Opens the ØMQ socket connection.
 
function sendCommand (in me, in command, in data, in getReply)
 
function receiveCommand (in me, in sendReply)
 Sends a command and optional data, then waits for a reply.
 
function flush (in me)
 Receives a command and associated data, optionally sending an 'ok' reply.
 
function get (in me, in option)
 Flushes the receive buffer of the socket.
 
function set (in me, in option, in value)
 Gets the value of a ØMQ socket option.
 
function send (in me, in data)
 Sets the value of a ØMQ socket option.
 
function receive (in me)
 Sends raw data over the socket.
 
function close (in me, in keepContext)
 Receives raw data from the socket.
 
function delete (in me)
 Closes the ØMQ socket and optionally the context.
 
function get endpoint (in me)
 Class destructor.
 
function set type (in me, in value)
 Gets the full endpoint string for the connection.
 
function sendObject (in me, in command, in data, in useJSON)
 Sets the socket type.
 
function receiveObject (in me, in useJSON, in options)
 (Private) Sends a command string and optional serialized MATLAB data.
 
function sendViaProxy (in me, in command, in data, in proxy)
 (Private) Receives a command string and optional serialized MATLAB data.
 
- Public Member Functions inherited from optickaCore
function optickaCore (in varargin)
 Class constructor.
 
function get fullName (in me)
 
function getALF (in me, in subject, in lab, in create)
 get the ALF path
 
function makeReport (in me, in rpt)
 Generate a detailed report for the opticka object.
 
function findAttributes (in me, in attrName, in attrValue)
 
function findAttributesandType (in me, in attrName, in attrValue, in type)
 find properties of object with specific attributes, for example all properties whose GetAcccess attribute is public and type is logical.
 
function findPropertyDefault (in me, in propName)
 Return the declared default value for a class property.
 
function clone (in me)
 Use this syntax to make a deep copy of the object, i.e. OBJ_OUT has the same field values, but will not behave as a handle-copy of me anymore.
 
function checkSuperclasses (in List)
 
function editProperties (in me, in properties)
 method to modify a set of properties
 
function setProp (in me, in property, in value)
 method to fast change a particular value. This is useful for use in anonymous functions, like in the state machine.
 
function initialiseSaveFile (in me, in varargin)
 just get date fragment for backwards compatibility
 
function checkPaths (in me)
 checks the paths are valid
 

Public Attributes

Property type
 ØMQ connection type, e.g. 'REQ', 'REP', 'PUB', 'SUB', etc.
 
Property transport
 transport for the socket, tcp | ipc | inproc
 
Property address
 the address to open, use * for a server to bind to all interfaces
 
Property port
 the port to open
 
Property frameSize
 default size of chunk to read/write for tcp
 
Property readTimeOut
 default read timeout in ms, -1 is blocking
 
Property writeTimeOut
 default write timeout in ms, -1 is blocking
 
Property verbose
 do we log to the command window?
 
Property alwaysPoll
 for sendCommand and receiveCommand use zmq.core.poll?
 
Property httpProxy
 use a http proxy to send message
 
Property endpoint
 connection endpoint
 
- Public Attributes inherited from optickaCore
Property name
 object name
 
Property comment
 comment
 
Property verbose
 verbose logging, subclasses must assign this. This is normally logical true/false
 
Property optickaVersion
 version number
 
Property dateStamp
 clock() dateStamp set on construction
 
Property uuid
 universal ID
 
Property paths
 storage of various paths
 
Property fullName
 The fullName is the object name combined with its uuid and class name.
 

Additional Inherited Members

- Static Public Member Functions inherited from optickaCore
static function initialiseGlobals (in doReset, in doOpen)
 
static function makeArgs (in args)
 Converts cell args to structure array.
 
static function addDefaults (in args, in defs)
 regularises and adds default options to arg input
 
static function hasKey (in in, in key)
 check if a struct / object has a propery / field
 
static function getKeys (in device)
 PTB Get key presses, stops key bouncing.
 
- Protected Member Functions inherited from optickaCore
function parseArgs (in me, in args, in allowedProperties)
 Sets properties from a structure or normal arguments pairs, ignores invalid or non-allowed properties.
 
function addArgs (in me, in args)
 
function setPaths (in me)
 Sets properties from a structure or normal arguments pairs, ignores invalid or non-allowed properties.
 
function getFonts (in me)
 set paths for object
 
function toStructure (in me)
 Converts properties to a structure.
 
function getType (in me, in in)
 
function logOutput (in me, in in, in message, in override)
 Give a metaproperty return the likely property class.
 
function salutation (in me, in varargin)
 Prints messages dependent on verbosity.
 
- Protected Attributes inherited from optickaCore
Property cloning
 are we cloning this from another object
 
Property mversion
 Matlab version number, this is transient so it is not saved.
 
Property sansFont
 sans font
 
Property monoFont
 monoFont
 
Property className
 class name
 
Property savePrefix
 save prefix generated from clock time
 
Property fullName_
 cached full name
 

Member Enumeration Documentation

◆ Events

poll socket to identify whether we can send ('out') or receive ('in')

Parameters
eventsstring 'in' 'out' or 'both'
timein ms, 0 = no wait, -1 = block until response
Enumerator
time 
183 {}; end
184 if nargin < 2 || isempty(command); error('You must pass a command!'); end
185 try
186 [status, nbytes, msg] = sendObject(me, command, data, true);
187 if status ~= 0
188 warning(msg);
189 end
190 catch ME
191 t = sprintf('Receive status %i did not return any command: %s - %s...\n', status, ME.identifier, ME.message);
192 me.addMessage(t);
193 disp(t);
194 end
195 if status == 0 && getReply
196 [rep, dataOut, ~, t] = receiveObject(me);
197 if ~isempty(t); me.addMessage(t); end
198 if me.verbose
199 disp(t);
200 disp(dataOut);
201 end
202 end
203 end
204
205 % ===================================================================
206 function [command, data, msg] = receiveCommand(me, sendReply)
207 %> @brief Receives a command and associated data, optionally sending an 'ok' reply.
208 %> @details Calls `receiveObject` to get the command string and any
209 %> serialized data. If `sendReply` is true (default) and a command was
210 %> successfully received, it sends back an 'ok' command using `sendObject`.
211 %> @param sendReply (Optional) Logical flag. If true (default), sends an
212 %> 'ok' reply upon successful receipt of a command. If false, no reply
213 %> is sent by this function. Defaults to true.
214 %> @return command The received command string. Empty if receive failed or timed out.
215 %> @return data The deserialized MATLAB data received with the command. Empty if no data part or on error.
216 % ===================================================================
217 command = ''; data = []; msg = '';
218 if ~me.isOpen; return; end
219 if nargin < 2
220 sendReply = true; % Default behavior: send 'ok' reply
221 end
222 try
223 [command, data, msg] = receiveObject(me, true);
224 if isempty(command) && ~isempty(msg)
225 msg = sprintf('Receive problem: %s', msg); % Log if receiveObject reported an issue
226 me.addMessage(msg);
227 warning(msg)
228 elseif ~isempty(command)
229 if me.verbose
230 fprintf('Received command: «%s»\n', command);
231 if ~isempty(data)
232 disp('Received data:');
233 disp(data);
234 end
235 end
236 end
237 catch ME
238 fprintf('Error during receiveCommand: cmd: %s msg: %s err: %s - %s\n', command, msg, ME.identifier, ME.message);
239 command = ''; data = []; % Ensure empty return on error
240 return % Exit function on critical error
241 end
242
243 % Send 'ok' reply only if requested and a command was actually received
244 if sendReply && ~isempty(command)
245 status = sendObject(me, 'ok', {});
246 if status ~= 0
247 msg = sprintf('Default "ok" reply failed to be sent for command "%s"', command);
248 me.addMessage(msg);
249 warning(msg);
250 me.sendState = false; % Update state on send failure
251 end
252 elseif ~isempty(command)
253 % If reply is not sent here, the caller is responsible.
254 end
255 end
256
257 % ===================================================================
258 function flush(me)
259 %> @brief Flushes the receive buffer of the socket.
260 %> @details Temporarily sets the receive timeout (`ReceiveTimeOut`) to 0 (non-blocking)
261 %> and enters a loop calling `receive` until it returns a status of -1
262 %> (indicating no more messages or an error). It then restores the
263 %> original `readTimeOut`. This is useful for discarding any pending
264 %> messages in the socket's incoming queue.
265 % ===================================================================
266 try
267 me.set('ReceiveTimeOut', 0);
268 N = 1000;
269 while N > 0
270 status = 0;
271 if verifyEvent('in'); [~, status] = receive(me); end
272 if status == -1; N = 0; end
273 end
274 catch ME
275 if me.verbose; fprintf('Flush error: %s %s', ME.identifier, ME.message); end
276 end
277 me.set('ReceiveTimeOut', me.readTimeOut);
278 end
279
280 % ===================================================================
281 function value = get(me, option)
282 %> @brief Gets the value of a ØMQ socket option.
283 %> @details A wrapper around the `zmq.Socket.get` method.
284 %> @param option The name of the socket option to retrieve (e.g., 'Linger', 'ReceiveTimeOut').
285 %> Case-insensitive, 'ZMQ_' prefix is optional.
286 %> @return value The current value of the specified socket option.
287 %> @warning Issues a warning if `option` is not provided.
288 % ===================================================================
289 arguments (Input)
290 me
291 option string {mustBeMember(option,...
292 ["Linger","ReceiveBufferSize",...
293 "SendBufferSize","HWM",...
294 "ReceiveTimeOut","SendTimeOut",...
295 "SocketType","Type","Ctx"])}
296 end
297 arguments (Output)
298 value
299 end
300 value = me.socket.pointer.("get" + option);
301 end
302
303 % ===================================================================
304 function status = set(me, option, value)
305 %> @brief Sets the value of a ØMQ socket option.
306 %> @details A wrapper around the `zmq.Socket.set` method.
307 %> @param option The name of the socket option to set (e.g., 'ReceiveTimeOut', 'LINGER').
308 %> Case-insensitive, 'ZMQ_' prefix is optional.
309 %> @param value The value to assign to the socket option.
310 %> @return status 0 on success, non-zero on failure.
311 %> @warning Issues warnings if `option` or `value` are not provided.
312 % ===================================================================
313 arguments (Input)
314 me
315 option string {mustBeMember(option,...
316 ["Linger","ReceiveBufferSize",...
317 "SendBufferSize","HWM",...
318 "ReceiveTimeOut","SendTimeOut",...
319 "SocketType","Type","Ctx"])}
320 value
321 end
322 arguments (Output)
323 status
324 end
325 status = me.socket.pointer.("set" + option)(value);
326 if ~status
327 warning('zmqConnection:set:failure','Failed to set %s', option)
328 end
329 end
330
331 % ===================================================================
332 function status = send(me, data)
333 %> @brief Sends raw data over the socket.
334 %> @details Determines the type of data and calls the appropriate
335 %> `zmq.Socket` send method (`send_string` for char/string, `send` for
336 %> uint8). If the data type is different, it attempts to use the
337 %> private `sendObject` method (which might not be intended for raw data).
338 %> @param data The data to send. Can be a character array, string, or uint8 array.
339 %> @return status 0 on success, -1 on failure (e.g., timeout, incorrect socket state).
340 % ===================================================================
341 try
342 status = [];
343 if ischar(data) || isstring(data)
344 result = me.socket.send(uint8(data));
345 elseif isa(data,'uint8')
346 result = me.socket.send(data);
347 else
348 result = sendObject(me, data);
349 end
350 if result; status = 0; end
351 catch ME
352 status = -1;
353 t = sprintf('Couldn''t send, perhaps need to receive first: %s - %s', ME.identifier, ME.message);
354 me.addMessage(t);
355 warning(t);
356 end
357 end
358
359 % ===================================================================
360 function [data, status] = receive(me)
361 %> @brief Receives raw data from the socket.
362 %> @details Calls `zmq.Socket.recv_multipart` to receive data. If the
363 %> result is a single-element cell array, it extracts the content.
364 %> @return data The received data, typically as a uint8 array or potentially
365 %> a cell array for true multipart messages. Empty on failure or timeout.
366 %> @return status 0 on success (implied, not explicitly returned on success),
367 %> -1 on failure (e.g., timeout).
368 % ===================================================================
369 data = []; status = -1;
370 try
371 data = me.receiveMultipart();
372 if iscell(data) && isscalar(data)
373 data = data{:};
374 end
375 status = 0;
376 catch ME
377 t = sprintf('No data received: %s - %s...\n', ME.identifier, ME.message);
378 me.addMessage(t);
379 if me.verbose; disp(t); end
380 end
381 end
382
383 % ===================================================================
384 function close(me, keepContext)
385 %> @brief Closes the ØMQ socket and optionally the context.
386 %> @details Closes the underlying `zmq.Socket` if it's open. If
387 %> `keepContext` is false (default), it also closes the `zmq.Context`.
388 %> Sets the `isOpen` flag to false.
389 %> @param keepContext (Optional) Logical flag. If true, the ØMQ context
390 %> is kept open; otherwise (default), the context is also closed.
391 %> Defaults to false.
392 %> @note Uses `try...end` blocks to suppress errors during closure.
393 % ===================================================================
394 if ~exist('keepContext','var'); keepContext = false; end
395
396 try me.socket.close(); me.socket = []; end %#ok<*TRYNC>
397 try me.poller.close(); me.poller = []; end %#ok<*TRYNC>
398
399 if ~keepContext
400 me.context = [];
401 end
402
403 me.isOpen = false;
404 end
405 function delete(me)
406 %> @brief Class destructor.
407 %> @details Ensures the socket and context are closed by calling `close(me, false)`
408 %> when the object is destroyed.
409 % ===================================================================
410 close(me, false);
411 end
412
413 % ===================================================================
414 function endpoint = get.endpoint(me)
415 %> @brief Gets the full endpoint string for the connection.
416 %> @details Constructs the endpoint string (e.g., 'tcp://localhost:5555')
417 %> based on the `transport`, `address`, and `port` properties.
418 %> @return endpoint The formatted endpoint string.
419 % ===================================================================
420 endpoint = sprintf('%s://%s:%i',me.transport,me.address,me.port);
421 end
422
423 % ===================================================================
424 function set.type(me, value)
425 %> @brief Sets the socket type.
426 %> @details Validates the socket type against a list of allowed types
427 %> and sets the `type` property. Throws an error if the type is invalid.
428 %> @param value The socket type to set (e.g., 'REQ', 'REP', 'PUB', 'SUB').
429 %> @note Uses SocketType enum, defaults to 'REQ'.
430 % ===================================================================
431 arguments
433 value (1,1) jzmq.SocketType
434 end
435
436 try
437 me.type = value;
438 catch
439 me.type = 'REQ';
440 warning('Invalid socket type. Defaulting to REQ.');
441 end
442 end
443
444 % ===================================================================
445 function [status, nbytes, msg] = sendObject(me, command, data, useJSON)
446 %> @brief (Private) Sends a command string and optional serialized MATLAB data.
447 %> @details This is the core sending method used by public methods like
448 %> `sendCommand` and `receiveCommand` (for replies). It checks if the
449 %> socket is open, validates the command is a string, serializes the
450 %> `data` using `getByteStreamFromArray` (if provided), and sends the
451 %> command and data as a two-part message using `zmq.Socket.send` with
452 %> the 'sndmore' flag if both parts exist. Handles sending only command,
453 %> only data, or an empty message if both are empty.
454 %> @param command The command string to send. Must be char or string.
455 %>
456 %> @param data (Optional) MATLAB data to serialize and send.
457 %> @param useJSON (optional) wrap command and data with JSON
458 %>
459 %> @return status 0 on success, -1 on failure.
460 %> @return nbytes The total number of bytes sent across all parts.
461 %> @return msg An error message string if `status` is -1.
462 % ===================================================================
463
464 status = -1; nbytes = 0; msg = '';
465
466 % Check if the socket is open
467 if ~me.isOpen
468 error('Socket is not open. Please open the socket before sending data.');
469 end
470
471 % Check if the command is a string
472 if ~exist('command','var') || ~ischar(command) && ~isstring(command)
473 error('Command must be a string or character array.');
474 end
475
476 if nargin < 5
477 options = {};
478 end
479
480 if nargin < 4 || isempty(useJSON)
481 useJSON = true;
482 end
483
484 if nargin < 3
485 data = [];
486 end
487
488 % Serialize the object if it's not empty
489 if ~isempty(data)
490 serialData = getByteStreamFromArray(data);
491 else
492 % If no data, just send an empty array
493 serialData = uint8([]);
494 end
495
496 try
497 if useJSON
498 j.command = command;
499 j.dataType = 'byteStream';
500 j.data = serialData;
501 j = jsonencode(j);
502 b = unicode2native(j, 'UTF-8');
503 nbytes = me.socket.send(uint8(b), options{:});
504 elseif ~isempty(command) && ~isempty(serialData)
505 n1 = me.socket.send(uint8(command), 'sndmore');
506 n2 = me.socket.send(serialData, options{:});
507 nbytes = n1 + n2;
508 elseif ~isempty(command)
509 % Just send text
510 nbytes = me.socket.send(uint8(command), options{:});
511 elseif ~isempty(serialData)
512 % Just send data
513 nbytes = me.socket.send(serialData, options{:});
514 else
515 % Send empty message
516 nbytes = me.socket.send(uint8(''), options{:});
517 end
518 status = 0;
519 catch ME
520 status = -1;
521 msg = [ME.identifier, ME.message];
522 end
523 end
524
525 % ===================================================================
526 function [command, data, raw, msg] = receiveObject(me, useJSON, options)
527 %> @brief (Private) Receives a command string and optional serialized MATLAB data.
528 %> @details This is the core receiving method. It calls `zmq.Socket.recv`
529 %> to get the first part (expected to be the command string). It checks
530 %> the 'rcvmore' socket option to see if a second part (data) exists.
531 %> If so, it calls `zmq.Socket.recv_multipart` to get the remaining part(s),
532 %> concatenates them if necessary, and deserializes the result using
533 %> `getArrayFromByteStream`.
534 %> @param options (Optional) Cell array of flags for the initial `recv` call (e.g., {'ZMQ_DONTWAIT'}).
535 %> @return command The received command string. Empty on failure or timeout.
536 %> @return data The deserialized MATLAB data. Empty if no data part, deserialization fails, or on error.
537 %> @return raw the original structure
538 %> @return msg An error message string if receiving the command failed or deserialization failed.
539 %> @note This is a private method. Throws an error if the socket is not open. Logs deserialization errors.
540 % ===================================================================
541 % Check if the socket is open
542 if ~me.isOpen
543 error('Socket is not open. Please open the socket before sending data.');
544 end
545
546 if nargin < 3; options = {}; end
547
548 if nargin < 2 || isempty(useJSON); useJSON = true; end
549
550 command = ''; data = []; msg = ''; raw = []; frames = {};
551
552 try
553 frames = me.receiveMultipart();
554 catch ME
555 warning('Failed to get object: %s - %s', ME.identifier, ME.message);
556 if matches(ME.identifier,'zmq:core:recv:EFSM')
557 t = sprintf('EFSM error, let''s try to flush and send');
558 me.addMessage(t);
559 if me.verbose; disp(t); end
560 me.flush;
561 me.sendObject('error',{''});
562 end
563 end
564 if isempty(frames); return; end
565
566 if useJSON
567 try
568 if iscell(frames)
569 str = native2unicode([frames{1:end}], 'UTF-8');
570 else
571 str = native2unicode(frames, 'UTF-8');
572 end
573 src = jsondecode(str);
574 if isstruct(src)
575 command = src.command;
576 if isfield(src,'data') && ~isempty(src.data)
577 data = getArrayFromByteStream(uint8(src.data));
578 end
579 end
580 raw = src;
581 catch ME
582 msg = 'Cannot parse JSON...';
583 me.addMessage(msg);
584 getReport(ME)
585 return
586 end
587 else
588 command = frames{1};
589 if command == -1
590 msg = 'No data received...';
591 me.addMessage(msg);
592 command = '';
593 return
594 end
595 command = char(command);
596 if length(frames) > 1
597 data = frames{2:end};
598 if iscell(data)
599 data = [data{:}];
600 end
601 % Deserialize the object if it's not empty
602 if ~isempty(data)
603 try
604 data = getArrayFromByteStream(data);
605 catch ME
606 msg = sprintf('Failed to deserialize object: %s - %s', ME.identifier, ME.message);
607 me.addMessage(msg);
608 warning(msg);
609 data = [];
610 end
611 else
612 data = [];
613 end
614 else
615 % No object part in the message
616 data = [];
617 end
618 end
619 end
620
621
622 % ===================================================================
623 function [response, dataOut] = sendViaProxy(me, command, data, proxy)
624 %> @brief sendViaProxy - Sends data to a specified URL via a proxy
625 %>
626 %> This function sends the provided data to the specified URL using
627 %> a proxy server and returns the server's response.
628 %>
629 %> @param command A string specifying the command to be sent
630 %> @param data A MATLAB object containing the data to be sent in the request.
631 %>
632 %> @return response The response from the server after sending the data.
633 % ===================================================================
634 arguments(Input)
636 command string = 'echo'
637 data = []
638 proxy string = me.httpProxy
639 end
640 arguments(Output)
641 response struct
642 dataOut
643 end
644 response = []; dataOut = [];
645 opts = weboptions('TimeOut',2,'MediaType', 'application/json', 'ContentType', 'json', 'CharacterEncoding', 'UTF-8');
646 data = getByteStreamFromArray(data);
647 dataStruct = struct('command',command,'dataType','byteStream','data', data);
648 try
649 response = webwrite(proxy, dataStruct, opts);
650 fprintf('sendViaProxy send: "%s" - respone: \n%s\n', command, jsonencode(response));
651 if isstruct(response) && isfield(response,'dataType') && matches(response.dataType,'byteStream')
652 try dataOut = getArrayFromByteStream(uint8(response.data)); end
653 if ~isempty(dataOut)
654 disp(dataOut);
655 end
656 end
657 catch ME
658 response = struct('error',string(ME.identifier));
659 dataOut = struct('error',string(ME.identifier),'data', ME.message,'cause','Ensure cogmoteGO and theConductor are running!!!');
660 warning('sendViaProxy: "%s" failed - error: %s - %s\n', command, ME.identifier, ME.message);
661 end
662 end
663
664 end
665
666 methods (Access = private)
667
668 % ===================================================================
669 %> @brief Receives all parts of a multipart message from the socket.
670 %> @details Calls `recv` on the socket to get the first part, then
671 %> continues calling `recv` while `hasReceiveMore` is true, collecting
672 %> all parts into a cell array. If only one part is received, returns
673 %> it directly.
674 %> @return data Cell array of message parts, or the single part if only one.
675 % ===================================================================
676 function data = receiveMultipart(me)
677 data = {};
678 data{1} = me.socket.recv();
679 a = 2;
680 while me.socket.hasReceiveMore()
681 data{a} = me.socket.recv();
682 end
683 if iscell(data) && isscalar(data)
684 data = data{:};
685 end
686 end
687
688 % ===================================================================
689 %> @brief Adds a message to the object's message log.
690 %> @details Converts the input `msg` to a string if necessary, then
691 %> appends it to the `messages` property. Handles struct, object,
692 %> char, and string types. If `msg` is empty or not provided, does nothing.
693 %> @param msg The message to add (struct, object, char, string, or array).
694 % ===================================================================
695 function addMessage(me, msg)
696 if nargin < 2; return; end
697 if isstruct(msg) || isobject(msg)
698 msg = formattedDisplayText(msg,"NumericFormat","short","LineSpacing","compact");
699 elseif ischar(msg)
700 msg = string(msg);
701 elseif length(msg) > 1
702 msg = join(msg);
703 else
704 return;
705 end
706 if isempty(me.messages)
707 me.messages(1) = msg;
708 else
709 me.messages(end+1) = msg;
710 end
711 end
712
713 % ===================================================================
714 %> @brief Checks if the socket is ready for the specified event(s).
715 %> @details Uses polling to determine if the socket can send ('out'),
716 %> receive ('in'), or neither ('none'). If `alwaysPoll` is false,
717 %> always returns true.
718 %> @param events String: 'in', 'out', or 'none'.
719 %> @return out Logical true if the event is ready, false otherwise.
720 % ===================================================================
721 function out = verifyEvent(me, events)
722 if ~me.alwaysPoll; out = true; return; end
723 out = false;
724 r = poll(me,'both',0);
725 switch events
726 case 'in'
727 if matches(r,{'in','both'})
728 out = true;
729 end
730 case 'out'
731 if matches(r,{'out','both'})
732 out = true;
733 end
734 case 'none'
735 if matches(r,'none')
736 out = true;
737 end
738 end
739 end
740 end
741end
Definition jzmqConnection.m:2
function set(in me, in option, in value)
Gets the value of a ØMQ socket option.
Property transport
transport for the socket, tcp | ipc | inproc
Definition jzmqConnection.m:14
function send(in me, in data)
Sets the value of a ØMQ socket option.
Property httpProxy
use a http proxy to send message
Definition jzmqConnection.m:38
function sendObject(in me, in command, in data, in useJSON)
Sets the socket type.
function get(in me, in option)
Flushes the receive buffer of the socket.
function open(in me, in context)
Class constructor for jzmqConnection.
Property verbose
do we log to the command window?
Definition jzmqConnection.m:32
Property port
the port to open
Definition jzmqConnection.m:20
function close(in me, in keepContext)
Receives raw data from the socket.
function sendViaProxy(in me, in command, in data, in proxy)
(Private) Receives a command string and optional serialized MATLAB data.
function receive(in me)
Sends raw data over the socket.
function sendCommand(in me, in command, in data, in getReply)
function receiveObject(in me, in useJSON, in options)
(Private) Sends a command string and optional serialized MATLAB data.
function flush(in me)
Receives a command and associated data, optionally sending an 'ok' reply.
Property endpoint
connection endpoint
Definition jzmqConnection.m:44
Property type
ØMQ connection type, e.g. 'REQ', 'REP', 'PUB', 'SUB', etc.
Definition jzmqConnection.m:11
Property readTimeOut
default read timeout in ms, -1 is blocking
Definition jzmqConnection.m:26
Property address
the address to open, use * for a server to bind to all interfaces
Definition jzmqConnection.m:17
function receiveCommand(in me, in sendReply)
Sends a command and optional data, then waits for a reply.
Definition zmqConnection.m:2
function parse(in bytes, in idx)

Constructor & Destructor Documentation

◆ jzmqConnection()

function jzmqConnection::jzmqConnection ( in  varargin)

Member Function Documentation

◆ close()

function jzmqConnection::close ( in  me,
in  keepContext 
)

Receives raw data from the socket.

Calls zmq.Socket.recv_multipart to receive data. If the result is a single-element cell array, it extracts the content.

Returns
data The received data, typically as a uint8 array or potentially a cell array for true multipart messages. Empty on failure or timeout.
status 0 on success (implied, not explicitly returned on success), -1 on failure (e.g., timeout).

◆ delete()

function jzmqConnection::delete ( in  me)

Closes the ØMQ socket and optionally the context.

Closes the underlying zmq.Socket if it's open. If keepContext is false (default), it also closes the zmq.Context. Sets the isOpen flag to false.

Parameters
keepContext(Optional) Logical flag. If true, the ØMQ context is kept open; otherwise (default), the context is also closed. Defaults to false.
Note
Uses try...end blocks to suppress errors during closure.

◆ endpoint()

function get jzmqConnection::endpoint ( in  me)

Class destructor.

Ensures the socket and context are closed by calling close(me, false) when the object is destroyed.

◆ flush()

function jzmqConnection::flush ( in  me)

Receives a command and associated data, optionally sending an 'ok' reply.

Calls receiveObject to get the command string and any serialized data. If sendReply is true (default) and a command was successfully received, it sends back an 'ok' command using sendObject.

Parameters
sendReply(Optional) Logical flag. If true (default), sends an 'ok' reply upon successful receipt of a command. If false, no reply is sent by this function. Defaults to true.
Returns
command The received command string. Empty if receive failed or timed out.
data The deserialized MATLAB data received with the command. Empty if no data part or on error.

◆ get()

function jzmqConnection::get ( in  me,
in  option 
)

Flushes the receive buffer of the socket.

Temporarily sets the receive timeout (ReceiveTimeOut) to 0 (non-blocking) and enters a loop calling receive until it returns a status of -1 (indicating no more messages or an error). It then restores the original readTimeOut. This is useful for discarding any pending messages in the socket's incoming queue.

◆ open()

function jzmqConnection::open ( in  me,
in  context 
)

Class constructor for jzmqConnection.

Initializes a jzmqConnection object, setting up default properties and parsing any provided arguments using the optickaCore superclass constructor and argument parsing.

Parameters
vararginOptional name-value pairs to override default properties. Allowed properties are defined in me.allowedProperties.
Returns
me An instance of the zmqConnection class.

◆ poll()

function jzmqConnection::poll ( in  me,
in  events,
in  time 
)

Opens the ØMQ socket connection.

Creates the ØMQ context if it doesn't exist, creates the socket based on the type property, sets socket options like ReceiveTimeOut, SNDTIMEO, and LINGER, and then either binds (for server types like REP, PUB, PUSH) or connects (for client types) to the specified endpoint. Sets the isOpen flag to true.

Note
Does nothing if the connection isOpen is already true.

◆ receive()

function jzmqConnection::receive ( in  me)

Sends raw data over the socket.

Determines the type of data and calls the appropriate zmq.Socket send method (send_string for char/string, send for uint8). If the data type is different, it attempts to use the private sendObject method (which might not be intended for raw data).

Parameters
dataThe data to send. Can be a character array, string, or uint8 array.
Returns
status 0 on success, -1 on failure (e.g., timeout, incorrect socket state).

◆ receiveCommand()

function jzmqConnection::receiveCommand ( in  me,
in  sendReply 
)

Sends a command and optional data, then waits for a reply.

Primarily for REQ/REP patterns. Uses sendObject to send the command string and serialized data. If successful, it then calls receiveObject to wait for and receive the reply command and data.

Parameters
commandThe command string to send.
data(Optional) MATLAB data to serialize and send along with the command. Defaults to empty.
Returns
rep The reply command string received from the peer.
dataOut The deserialized MATLAB data received in the reply.
status 0 on success (send and receive completed), -1 on failure (send or receive failed).

◆ receiveObject()

function jzmqConnection::receiveObject ( in  me,
in  useJSON,
in  options 
)

(Private) Sends a command string and optional serialized MATLAB data.

This is the core sending method used by public methods like sendCommand and receiveCommand (for replies). It checks if the socket is open, validates the command is a string, serializes the data using getByteStreamFromArray (if provided), and sends the command and data as a two-part message using zmq.Socket.send with the 'sndmore' flag if both parts exist. Handles sending only command, only data, or an empty message if both are empty.

Parameters
commandThe command string to send. Must be char or string.
data(Optional) MATLAB data to serialize and send.
useJSON(optional) wrap command and data with JSON
Returns
status 0 on success, -1 on failure.
nbytes The total number of bytes sent across all parts.
msg An error message string if status is -1.

◆ send()

function jzmqConnection::send ( in  me,
in  data 
)

Sets the value of a ØMQ socket option.

A wrapper around the zmq.Socket.set method.

Parameters
optionThe name of the socket option to set (e.g., 'ReceiveTimeOut', 'LINGER'). Case-insensitive, 'ZMQ_' prefix is optional.
valueThe value to assign to the socket option.
Returns
status 0 on success, non-zero on failure.
Warning
Issues warnings if option or value are not provided.

◆ sendCommand()

function jzmqConnection::sendCommand ( in  me,
in  command,
in  data,
in  getReply 
)

◆ sendObject()

function jzmqConnection::sendObject ( in  me,
in  command,
in  data,
in  useJSON 
)

Sets the socket type.

Validates the socket type against a list of allowed types and sets the type property. Throws an error if the type is invalid.

Parameters
valueThe socket type to set (e.g., 'REQ', 'REP', 'PUB', 'SUB').
Note
Uses SocketType enum, defaults to 'REQ'.

◆ sendViaProxy()

function jzmqConnection::sendViaProxy ( in  me,
in  command,
in  data,
in  proxy 
)

(Private) Receives a command string and optional serialized MATLAB data.

This is the core receiving method. It calls zmq.Socket.recv to get the first part (expected to be the command string). It checks the 'rcvmore' socket option to see if a second part (data) exists. If so, it calls zmq.Socket.recv_multipart to get the remaining part(s), concatenates them if necessary, and deserializes the result using getArrayFromByteStream.

Parameters
options(Optional) Cell array of flags for the initial recv call (e.g., {'ZMQ_DONTWAIT'}).
Returns
command The received command string. Empty on failure or timeout.
data The deserialized MATLAB data. Empty if no data part, deserialization fails, or on error.
raw the original structure
msg An error message string if receiving the command failed or deserialization failed.
Note
This is a private method. Throws an error if the socket is not open. Logs deserialization errors.

◆ set()

function jzmqConnection::set ( in  me,
in  option,
in  value 
)

Gets the value of a ØMQ socket option.

A wrapper around the zmq.Socket.get method.

Parameters
optionThe name of the socket option to retrieve (e.g., 'Linger', 'ReceiveTimeOut'). Case-insensitive, 'ZMQ_' prefix is optional.
Returns
value The current value of the specified socket option.
Warning
Issues a warning if option is not provided.

◆ type()

function set jzmqConnection::type ( in  me,
in  value 
)

Gets the full endpoint string for the connection.

Constructs the endpoint string (e.g., 'tcp://localhost:5555') based on the transport, address, and port properties.

Returns
endpoint The formatted endpoint string.

Member Data Documentation

◆ address

Property jzmqConnection::address

the address to open, use * for a server to bind to all interfaces

◆ alwaysPoll

Property jzmqConnection::alwaysPoll

for sendCommand and receiveCommand use zmq.core.poll?

◆ endpoint

Property jzmqConnection::endpoint

connection endpoint

◆ frameSize

Property jzmqConnection::frameSize

default size of chunk to read/write for tcp

◆ httpProxy

Property jzmqConnection::httpProxy

use a http proxy to send message

◆ port

Property jzmqConnection::port

the port to open

◆ readTimeOut

Property jzmqConnection::readTimeOut

default read timeout in ms, -1 is blocking

◆ transport

Property jzmqConnection::transport

transport for the socket, tcp | ipc | inproc

◆ type

Property jzmqConnection::type

ØMQ connection type, e.g. 'REQ', 'REP', 'PUB', 'SUB', etc.

jzmqConnection is a class to handle ØMQ connections for opticka class communication. We use JeroMQ wrapper jzmq, a pure Java implementation of ØMQ.

◆ verbose

Property jzmqConnection::verbose

do we log to the command window?

◆ writeTimeOut

Property jzmqConnection::writeTimeOut

default write timeout in ms, -1 is blocking


The documentation for this class was generated from the following file: