Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ rebuildTags.sh

# caused py setup.py develop
pymatbridge.egg-info

# so vim-ers can use "YouCompleteMe"
.ycm_extra_conf.py
48 changes: 40 additions & 8 deletions pymatbridge/matlab/matlabserver.m
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
function matlabserver(socket_address)
function matlabserver(socket_address, exit_when_done)
%MATLABSERVER Take Commands from Python via ZMQ
% matlabserver(socket_address, exit_when_done)
% This function takes a socket address as input and initiates a ZMQ session
% over the socket. I then enters the listen-respond mode until it gets an
% "exit" command

json_startup
% over the socket. It then enters the listen-respond mode until it gets an
% "exit" command, at which point it returns (or exits if exit_when_done), or
% until it gets a "separate" command, at which point it launches the MATLAB
% desktop client and returns.
%

initialize_environment;
json_startup;
messenger('init', socket_address);

c=onCleanup(@()exit);
c = onCleanup(@stop_messenger);

while(1)
msg_in = messenger('listen');
Expand All @@ -17,15 +23,41 @@ function matlabserver(socket_address)
messenger('respond', 'connected');

case {'exit'}
messenger('exit');
break;

case {'eval'}
resp = pymat_eval(req);
messenger('respond', resp);

case {'separate'}
desktop; %no-op if desktop is already up
exit_when_done = false;
break;

otherwise
messenger('respond', 'i dont know what you want');
messenger('respond', 'Unknown command recieved by matlabserver via ZMQ.');

end
end

if nargin > 1 && exit_when_done
%c.task(); % already executed by "finish"
exit;
end

end %matlabserver

function stop_messenger()
if messenger('check')
messenger('exit');
end
end

function initialize_environment()
if ~exist('json_startup', 'file')
[pathstr, ~, ~] = fileparts(mfilename('fullpath'));
old_warning_state = warning('off','all');
addpath(genpath(pathstr));
warning(old_warning_state);
end
end
6 changes: 6 additions & 0 deletions pymatbridge/matlab/util/finish.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
% make sure socket gets closed no matter how MATLAB exists (sans crash)
if exist('messenger', 'file')
if messenger('check')
messenger('exit');
end
end
12 changes: 8 additions & 4 deletions pymatbridge/matlab/util/json_v0.2.2/json/json_dump.m
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
double_struct = struct;
double_struct.ndarray = 1;
value = double(value);
if isreal(value)
if isreal(value)
double_struct.data = base64encode(typecast(value(:), 'uint8'));
else
double_struct.real = base64encode(typecast(real(value(:)), 'uint8'));
Expand Down Expand Up @@ -142,9 +142,13 @@
obj.put(dump_data_(value{i}, options));
end
elseif isnumeric(value)
if isreal(value)
if ~isfinite(value)
json_non_finite = struct;
json_non_finite.json_non_finite = lower(num2str(value));
obj = dump_data_(json_non_finite, options);
elseif isreal(value)
obj = value;
% Encode complex number as a struct
% Encode finite complex number as a struct
else
complex_struct = struct;
complex_struct.real = real(value);
Expand All @@ -158,7 +162,7 @@
keys = fieldnames(value);
for i = 1:length(keys)
try
obj.put(keys{i},dump_data_(value.(keys{i}), options));
obj.put(keys{i}, dump_data_(value.(keys{i}), options));
catch ME
obj.put(keys{i}, dump_data_(ME.message, options))
end
Expand Down
2 changes: 1 addition & 1 deletion pymatbridge/matlab/util/pymat_eval.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function json_response = pymat_eval(req);
function json_response = pymat_eval(req)
% PYMAT_EVAL: Returns a json object of the result of calling the function
%
% json_response = pymat_eval(req);
Expand Down
8 changes: 4 additions & 4 deletions pymatbridge/matlab_magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from .compat import text_type


class MatlabInterperterError(RuntimeError):
class MatlabInterpreterError(RuntimeError):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

"""
Some error occurs while matlab is running
"""
Expand Down Expand Up @@ -87,7 +87,7 @@ def eval(self, line):
run_dict = self.Matlab.run_code(line)

if not run_dict['success']:
raise MatlabInterperterError(line, run_dict['content']['stdout'])
raise MatlabInterpreterError(line, run_dict['content']['stdout'])

# This is the matlab stdout:
return run_dict
Expand All @@ -99,7 +99,7 @@ def set_matlab_var(self, name, value):
run_dict = self.Matlab.set_variable(name, value)

if not run_dict['success']:
raise MatlabInterperterError(line, run_dict['content']['stdout'])
raise MatlabInterpreterError(line, run_dict['content']['stdout'])


@magic_arguments()
Expand Down Expand Up @@ -161,7 +161,7 @@ def matlab(self, line, cell=None, local_ns=None):

try:
result_dict = self.eval(code)
except MatlabInterperterError:
except MatlabInterpreterError:
raise
except:
raise RuntimeError('\n'.join([
Expand Down
8 changes: 4 additions & 4 deletions pymatbridge/messenger/make.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def get_config():


def do_build(make_cmd, messenger_exe):
print('Building %s...' % messenger_exe)
print('Building {}...'.format(messenger_exe))
print(make_cmd)
messenger_dir = get_messenger_dir()
subprocess.check_output(shlex.split(make_cmd), shell=use_shell)
Expand All @@ -188,7 +188,7 @@ def do_build(make_cmd, messenger_exe):
def build_octave():
paths = "-L%(octave_lib)s -I%(octave_inc)s -L%(zmq_lib)s -I%(zmq_inc)s"
paths = paths % get_config()
make_cmd = "mkoctfile --mex %s -lzmq ./src/messenger.c" % paths
make_cmd = "mkoctfile --mex {} -lzmq ./src/messenger.c".format(paths)
do_build(make_cmd, 'messenger.mex')


Expand Down Expand Up @@ -264,10 +264,10 @@ def build_matlab(static=False):
# Build the mex file
mex = esc(os.path.join(matlab_bin, "mex"))
paths = "-L%(zmq_lib)s -I%(zmq_inc)s" % cfg
make_cmd = '%s -O %s -lzmq ./src/messenger.c' % (mex, paths)
make_cmd = '{} -O {} -lzmq ./src/messenger.c'.format(mex, paths)
if static:
make_cmd += ' -DZMQ_STATIC'
do_build(make_cmd, 'messenger.%s' % extension)
do_build(make_cmd, 'messenger.{}'.format(extension))


if __name__ == '__main__':
Expand Down
Binary file modified pymatbridge/messenger/mexa64/messenger.mexa64
Binary file not shown.
62 changes: 29 additions & 33 deletions pymatbridge/messenger/src/messenger.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,61 +48,58 @@ void cleanup (void) {
mexPrintf("Socket closed\n");
zmq_term(ctx);
mexPrintf("Context terminated\n");
initialized = 0;
}


/* Gateway function with Matlab */
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]) {
char *cmd;
mxLogical *p;
/* If no input argument, print out the usage */
if (nrhs == 0) {
mexErrMsgTxt("Usage: messenger('init|listen|respond', extra1, extra2, ...)");
}

if (nlhs > 1) {
mexErrMsgTxt("messenger: too many outputs, I return a single bool");
}
/* Get the input command */
if(!(cmd = mxArrayToString(prhs[0]))) {
mexErrMsgTxt("Cannot read the command");
}

/* we'll return true on completion of valid command, else false */
plhs[0] = mxCreateLogicalMatrix(1, 1);
p = mxGetLogicals(plhs[0]);
p[0] = false;
/* Initialize a new server session */
if (strcmp(cmd, "init") == 0) {
char *socket_addr;
mxLogical *p;

/* Check if the input format is valid */
if (nrhs != 2) {
mexErrMsgTxt("Missing argument: socket address");
mexErrMsgTxt("Usage: messenger('init', socket_addr)");
}
if (!(socket_addr = mxArrayToString(prhs[1]))) {
mexErrMsgTxt("Cannot read socket address");
}

plhs[0] = mxCreateLogicalMatrix(1, 1);
p = mxGetLogicals(plhs[0]);

if (!initialized) {
if (!initialize(socket_addr)) {
p[0] = 1;
p[0] = true;
mexPrintf("Socket created at: %s\n", socket_addr);
} else {
p[0] = 0;
mexErrMsgTxt("Socket creation failed.");
}
} else {
mexErrMsgTxt("One socket has already been initialized.");
}

return;

/* Listen over an existing socket */
} else if (strcmp(cmd, "listen") == 0) {
int byte_recvd;
char *recv_buffer = mxCalloc(BUFLEN, sizeof(char));
zmq_pollitem_t polls[] = {{socket_ptr, 0, ZMQ_POLLIN, 0}};

if (!checkInitialized()) return;

/* allow MATLAB to draw its graphics every 20ms */
while (zmq_poll(polls, 1, 20000) == 0) {
mexEvalString("drawnow");
Expand All @@ -116,17 +113,14 @@ void mexFunction(int nlhs, mxArray *plhs[],
} else if (byte_recvd > BUFLEN){
mexErrMsgTxt("Receiver buffer overflow. Message truncated");
} else {
sprintf(recv_buffer, "Failed to receive a message due to ZMQ error %s", strerror(errno));
sprintf(recv_buffer, "Failed to receive a message due to ZMQ error %s", strerror(errno));
mexErrMsgTxt(recv_buffer);
}

return;

p[0] = true;
/* Send a message out */
} else if (strcmp(cmd, "respond") == 0) {
size_t msglen;
char *msg_out;
mxLogical *p;

/* Check if the input format is valid */
if (nrhs != 2) {
Expand All @@ -138,24 +132,26 @@ void mexFunction(int nlhs, mxArray *plhs[],
msglen = mxGetNumberOfElements(prhs[1]);
msg_out = mxArrayToString(prhs[1]);

plhs[0] = mxCreateLogicalMatrix(1, 1);
p = mxGetLogicals(plhs[0]);

if (msglen == zmq_send(socket_ptr, msg_out, msglen, 0)) {
p[0] = 1;
if (msglen == (size_t) zmq_send(socket_ptr, msg_out, msglen, 0)) {
p[0] = true;
} else {
p[0] = 0;
mexErrMsgTxt("Failed to send message due to ZMQ error");
}

return;

/* Close the socket and context */
} else if (strcmp(cmd, "exit") == 0) {
cleanup();

return;
if (initialized) {
cleanup();
p[0] = true;
initialized = 0;
} else {
mexErrMsgTxt("No open socket to exit.");
}
} else if (strcmp(cmd, "check") == 0) {
if (initialized) {
p[0] = true;
}
} else {
mexErrMsgTxt("Unidentified command");
}
return;
}
Loading