1 | %------------------------------------------------------------------------- |
---|
2 | % WARPLab Framework |
---|
3 | % |
---|
4 | % Copyright 2013, Mango Communications. All rights reserved. |
---|
5 | % Distributed under the WARP license (http://warpproject.org/license) |
---|
6 | % |
---|
7 | % Chris Hunter (chunter [at] mangocomm.com) |
---|
8 | % Patrick Murphy (murphpo [at] mangocomm.com) |
---|
9 | % Erik Welsh (welsh [at] mangocomm.com) |
---|
10 | %------------------------------------------------------------------------- |
---|
11 | |
---|
12 | classdef wl_transport_eth_udp_mex < wl_transport & handle_light |
---|
13 | % Mex physical layer Ethernet UDP Transport for unicast traffic |
---|
14 | % User code should not use this object directly-- the parent wl_node will |
---|
15 | % instantiate the appropriate transport object for the hardware in use |
---|
16 | |
---|
17 | %******************************** Properties ********************************** |
---|
18 | |
---|
19 | properties (SetAccess = public) |
---|
20 | timeout; % Maximum time spent waiting before retransmission |
---|
21 | end |
---|
22 | |
---|
23 | properties (SetAccess = protected, Hidden = true) |
---|
24 | sock; % UDP socket |
---|
25 | status; % Status of UDP socket |
---|
26 | maxSamples; % Maximum number of samples able to be transmitted (based on maxPayload) |
---|
27 | maxPayload; % Maximum payload size (e.g. MTU - ETH/IP/UDP headers) |
---|
28 | end |
---|
29 | |
---|
30 | properties (SetAccess = protected) |
---|
31 | address; % IP address of destination |
---|
32 | port; % Port of destination |
---|
33 | end |
---|
34 | |
---|
35 | properties (SetAccess = public) |
---|
36 | hdr; % Transport header object |
---|
37 | rxBufferSize; % OS's receive buffer size in bytes |
---|
38 | end |
---|
39 | |
---|
40 | properties(Hidden = true, Constant = true) |
---|
41 | % These constants define specific command IDs used by this object. |
---|
42 | % Their C counterparts are found in wl_transport.h |
---|
43 | GRP = 'transport'; |
---|
44 | CMD_PING = 1; % 0x000001 |
---|
45 | CMD_PAYLOADSIZETEST = 2; % 0x000002 |
---|
46 | |
---|
47 | CMD_NODEGRPID_ADD = 16; % 0x000010 |
---|
48 | CMD_NODEGRPID_CLEAR = 17; % 0x000011 |
---|
49 | |
---|
50 | TRANSPORT_NOT_READY_MAX_RETRY = 50; |
---|
51 | TRANSPORT_NOT_READY_WAIT_TIME = 0.1; |
---|
52 | |
---|
53 | REQUIRED_MEX_VERSION = '1.0.4a'; % Must match version in MEX transport |
---|
54 | end |
---|
55 | |
---|
56 | |
---|
57 | %********************************* Methods ************************************ |
---|
58 | |
---|
59 | methods |
---|
60 | |
---|
61 | function obj = wl_transport_eth_udp_mex() |
---|
62 | obj.hdr = wl_transport_header; |
---|
63 | obj.hdr.pktType = obj.hdr.PKTTYPE_HTON_MSG; |
---|
64 | obj.status = 0; |
---|
65 | obj.timeout = 1; |
---|
66 | obj.maxPayload = 1000; % Sane default. This gets overwritten by CMD_PAYLOADSIZETEST command. |
---|
67 | obj.port = 0; |
---|
68 | obj.address = '10.0.0.0'; |
---|
69 | |
---|
70 | obj.checkSetup(); |
---|
71 | end |
---|
72 | |
---|
73 | function checkSetup(obj) |
---|
74 | % Check to make sure wl_mex_udp_transport exists and is is configured |
---|
75 | % |
---|
76 | temp = which('wl_mex_udp_transport'); |
---|
77 | |
---|
78 | if(isempty(temp)) |
---|
79 | error('wl_transport_eth_udp_mex:constructor', 'WARPLab Mex UDP transport not found in Matlab''s path'); |
---|
80 | elseif(strcmp(temp((end-length(mexext)+1):end ), mexext) == 0) |
---|
81 | error('wl_transport_eth_udp_mex:constructor', 'WARPLab Mex UDP transport found, but it is not a compiled mex file'); |
---|
82 | end |
---|
83 | |
---|
84 | version = wl_mex_udp_transport('version'); |
---|
85 | version = sscanf(version, '%d.%d.%d%c'); |
---|
86 | version_req = sscanf(obj.REQUIRED_MEX_VERSION, '%d.%d.%d%c'); |
---|
87 | |
---|
88 | % Version must match required version |
---|
89 | if(~(version(1) == version_req(1) && version(2) == version_req(2) && version(3) == version_req(3) && version(4) >= version_req(4))) |
---|
90 | version = wl_mex_udp_transport('version'); |
---|
91 | version_req = obj.REQUIRED_MEX_VERSION; |
---|
92 | |
---|
93 | error('wl_transport_eth_udp_mex:constructor', 'MEX transport version mismatch.\nRequires version %s, found version %s', version_req, version); |
---|
94 | end |
---|
95 | end |
---|
96 | |
---|
97 | function setMaxPayload(obj, value) |
---|
98 | |
---|
99 | if (isempty(value)) |
---|
100 | error('wl_transport_eth_udp_mex:setMaxPayload', 'setMaxPayload requires a non-empty argument.'); |
---|
101 | else |
---|
102 | obj.maxPayload = value; |
---|
103 | |
---|
104 | % Compute the maximum number of samples in each Ethernet packet |
---|
105 | % - Start with maxPayload is the max number of bytes per packet (nominally the Ethernet MTU) |
---|
106 | % - Subtract sizes of the transport header, command header and samples header |
---|
107 | % - Due to DMA alignment issues in the node, the max samples must be 4 sample aligned. |
---|
108 | obj.maxSamples = double(bitand(((floor(double(obj.maxPayload)/4) - sizeof(obj.hdr)/4 - sizeof(wl_cmd)/4) - (sizeof(wl_samples)/4)), 4294967292)); |
---|
109 | |
---|
110 | % fprintf('Max samples: %d\n', obj.maxSamples); |
---|
111 | end |
---|
112 | end |
---|
113 | |
---|
114 | function out = getMaxPayload(obj) |
---|
115 | out = double(obj.maxPayload); |
---|
116 | end |
---|
117 | |
---|
118 | function setAddress(obj, value) |
---|
119 | if(ischar(value)) |
---|
120 | obj.address = value; |
---|
121 | else |
---|
122 | obj.address = obj.int2IP(value); |
---|
123 | end |
---|
124 | end |
---|
125 | |
---|
126 | function out = getAddress(obj) |
---|
127 | out = obj.address; |
---|
128 | end |
---|
129 | |
---|
130 | function setPort(obj, value) |
---|
131 | obj.port = value; |
---|
132 | end |
---|
133 | |
---|
134 | function out = getPort(obj) |
---|
135 | out = obj.port; |
---|
136 | end |
---|
137 | |
---|
138 | function open(obj,varargin) |
---|
139 | % varargin{1}: (optional) IP address |
---|
140 | % varargin{2}: (optional) port |
---|
141 | % |
---|
142 | if(nargin==3) |
---|
143 | obj.setAddress(varargin{1}); |
---|
144 | obj.port = varargin{2}; |
---|
145 | end |
---|
146 | |
---|
147 | REQUESTED_BUF_SIZE = 2^22; |
---|
148 | |
---|
149 | % Call to 'init_sockets' will internally call setReuseAddress and setBroadcast |
---|
150 | obj.sock = wl_mex_udp_transport('init_socket'); |
---|
151 | wl_mex_udp_transport('set_so_timeout', obj.sock, 1); |
---|
152 | wl_mex_udp_transport('set_send_buf_size', obj.sock, REQUESTED_BUF_SIZE); |
---|
153 | wl_mex_udp_transport('set_rcvd_buf_size', obj.sock, REQUESTED_BUF_SIZE); |
---|
154 | |
---|
155 | x = wl_mex_udp_transport('get_rcvd_buf_size', obj.sock); |
---|
156 | obj.rxBufferSize = x; |
---|
157 | |
---|
158 | if(x < REQUESTED_BUF_SIZE) |
---|
159 | fprintf('OS reduced recv buffer size to %d\n', x); |
---|
160 | end |
---|
161 | |
---|
162 | obj.status = 1; |
---|
163 | end |
---|
164 | |
---|
165 | function out = procCmd(obj,nodeInd,node,cmdStr,varargin) |
---|
166 | % wl_node procCmd(obj, nodeInd, node, varargin) |
---|
167 | % obj: Node object (when called using dot notation) |
---|
168 | % nodeInd: Index of the current node, when wl_node is iterating over nodes |
---|
169 | % node: Current node object |
---|
170 | % cmdStr: Command string of the interface command |
---|
171 | % varargin: |
---|
172 | % [1:N} Command arguments |
---|
173 | % |
---|
174 | out = []; |
---|
175 | |
---|
176 | cmdStr = lower(cmdStr); |
---|
177 | switch(cmdStr) |
---|
178 | |
---|
179 | %--------------------------------------------------------- |
---|
180 | case 'ping' |
---|
181 | % Test to make sure node can be accessed via this |
---|
182 | % transport |
---|
183 | % |
---|
184 | % Arguments: none |
---|
185 | % Returns: true if board responds; raises error otherwise |
---|
186 | % |
---|
187 | myCmd = wl_cmd(node.calcCmd(obj.GRP,obj.CMD_PING)); |
---|
188 | node.sendCmd(myCmd); |
---|
189 | out = true; % sendCmd will timeout and raise error if board doesn't respond |
---|
190 | |
---|
191 | %--------------------------------------------------------- |
---|
192 | case 'payload_size_test' |
---|
193 | % Determine objects maxPayload parameter |
---|
194 | % |
---|
195 | % Arguments: none |
---|
196 | % Returns: none |
---|
197 | % |
---|
198 | configFile = which('wl_config.ini'); |
---|
199 | |
---|
200 | if(isempty(configFile)) |
---|
201 | error('cannot find wl_config.ini. please run wl_setup.m'); |
---|
202 | end |
---|
203 | |
---|
204 | readKeys = {'network', '', 'max_transport_payload_size', ''}; |
---|
205 | max_transport_payload_size = inifile(configFile, 'read', readKeys); |
---|
206 | max_transport_payload_size = str2num(max_transport_payload_size{1}); |
---|
207 | |
---|
208 | % Determine the payloads to test |
---|
209 | payloadTestSizes = []; |
---|
210 | |
---|
211 | for i = [1000 1470 5000 8966] |
---|
212 | if (i < max_transport_payload_size) |
---|
213 | payloadTestSizes = [payloadTestSizes, i]; |
---|
214 | end |
---|
215 | end |
---|
216 | |
---|
217 | payloadTestSizes = [payloadTestSizes, max_transport_payload_size]; |
---|
218 | |
---|
219 | % WARPLab Header is (see http://warpproject.org/trac/wiki/WARPLab/Reference/Architecture/WireFormat ): |
---|
220 | % - 2 byte pad |
---|
221 | % - Transport header |
---|
222 | % - Command header |
---|
223 | payloadTestSizes = floor((payloadTestSizes - (sizeof(node.transport.hdr) + sizeof(wl_cmd) + 2)) / 4); |
---|
224 | |
---|
225 | for index = 1:length(payloadTestSizes) |
---|
226 | myCmd = wl_cmd(node.calcCmd(obj.GRP,obj.CMD_PAYLOADSIZETEST)); |
---|
227 | myCmd.addArgs(1:payloadTestSizes(index)); |
---|
228 | try |
---|
229 | resp = node.sendCmd(myCmd); |
---|
230 | obj.setMaxPayload(resp.getArgs); |
---|
231 | if(obj.getMaxPayload() < (payloadTestSizes(index) * 4)) |
---|
232 | break; |
---|
233 | end |
---|
234 | catch ME |
---|
235 | break |
---|
236 | end |
---|
237 | end |
---|
238 | |
---|
239 | %--------------------------------------------------------- |
---|
240 | case 'add_node_group_id' |
---|
241 | % Adds a Node Group ID to the node so that it can |
---|
242 | % process broadcast commands that are received from |
---|
243 | % that node group. |
---|
244 | % |
---|
245 | % Arguments: (uint32 NODE_GRP_ID) |
---|
246 | % Returns: none |
---|
247 | % |
---|
248 | % NODE_GRP_ID: ID provided by wl_node_grp |
---|
249 | % |
---|
250 | myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_NODEGRPID_ADD)); |
---|
251 | myCmd.addArgs(varargin{1}); |
---|
252 | node.sendCmd(myCmd); |
---|
253 | |
---|
254 | %--------------------------------------------------------- |
---|
255 | case 'clear_node_group_id' |
---|
256 | % Clears a Node Group ID from the node so it can ignore |
---|
257 | % broadcast commands that are received from that node |
---|
258 | % group. |
---|
259 | % |
---|
260 | % Arguments: (uint32 NODE_GRP_ID) |
---|
261 | % Returns: none |
---|
262 | % |
---|
263 | % NODE_GRP_ID: ID provided by wl_node_grp |
---|
264 | % |
---|
265 | myCmd = wl_cmd(node.calcCmd(obj.GRP, obj.CMD_NODEGRPID_CLEAR)); |
---|
266 | myCmd.addArgs(varargin{1}); |
---|
267 | node.sendCmd(myCmd); |
---|
268 | |
---|
269 | %--------------------------------------------------------- |
---|
270 | otherwise |
---|
271 | error('unknown command ''%s''',cmdStr); |
---|
272 | end |
---|
273 | |
---|
274 | if((iscell(out) == 0) && (numel(out) ~= 1)) |
---|
275 | out = {out}; |
---|
276 | end |
---|
277 | end |
---|
278 | |
---|
279 | function close(obj) |
---|
280 | if(~isempty(obj.sock)) |
---|
281 | try |
---|
282 | wl_mex_udp_transport('close', obj.sock); |
---|
283 | catch closeError |
---|
284 | warning( 'Error closing socket; mex error was %s', closeError.message) |
---|
285 | end |
---|
286 | end |
---|
287 | obj.status=0; |
---|
288 | end |
---|
289 | |
---|
290 | function delete(obj) |
---|
291 | obj.close(); |
---|
292 | end |
---|
293 | |
---|
294 | function flush(obj) |
---|
295 | % Currently not implemented |
---|
296 | end |
---|
297 | end % methods |
---|
298 | |
---|
299 | |
---|
300 | methods (Hidden = true) |
---|
301 | |
---|
302 | function reply = send(obj, send_data, response, varargin) |
---|
303 | % send_data : Data to be sent to the node |
---|
304 | % response : Does the transmission require a response from the node |
---|
305 | % varargin{1}: (optional) |
---|
306 | % - increment the transport header; defaults to true if not specified |
---|
307 | % |
---|
308 | |
---|
309 | % Initialize variables |
---|
310 | maxAttempts = 2; % Maximum times the transport will re-try a packet |
---|
311 | payload = uint32(send_data); % Change data to 32 bit unsigned integers for transmit |
---|
312 | obj.hdr.msgLength = ((length(payload)) * 4); % Length in bytes (4 bytes / sample) |
---|
313 | reply = []; % Initialize array for response from the node |
---|
314 | robust = response; |
---|
315 | |
---|
316 | % Process command line arguments |
---|
317 | increment_hdr = true; |
---|
318 | |
---|
319 | if (nargin == 4) |
---|
320 | increment_hdr = varargin{1}; |
---|
321 | end |
---|
322 | |
---|
323 | % Set the appropriate flags in the header |
---|
324 | if(robust) |
---|
325 | obj.hdr.flags = bitset(obj.hdr.flags, 1, 1); |
---|
326 | else |
---|
327 | obj.hdr.flags = bitset(obj.hdr.flags, 1, 0); |
---|
328 | end |
---|
329 | |
---|
330 | % Increment the header and serialize all the data into a uint32 array |
---|
331 | if (increment_hdr) |
---|
332 | obj.hdr.increment; |
---|
333 | end |
---|
334 | |
---|
335 | % Format the data / address arguments for transmission |
---|
336 | data = [obj.hdr.serialize, payload]; % Get a unified array with the header and data |
---|
337 | data8 = [zeros(1,2,'uint8') typecast(swapbytes(uint32(data)), 'uint8')]; % Change to uint8 and pad by 2 bytes so payload is 32 bit aligned w/ Eth header |
---|
338 | |
---|
339 | % Send the packet |
---|
340 | size = wl_mex_udp_transport('send', obj.sock, data8, length(data8), obj.address, obj.port); |
---|
341 | |
---|
342 | % Wait to receive reply from the board |
---|
343 | if(robust == 1) |
---|
344 | MAX_PKT_LEN = obj.getMaxPayload() + 100; |
---|
345 | hdr_length = obj.hdr.length; |
---|
346 | currTx = 1; |
---|
347 | numWaitRetries = 0; |
---|
348 | receivedResponse = 0; |
---|
349 | currTime = tic; |
---|
350 | |
---|
351 | while (receivedResponse == 0) |
---|
352 | try |
---|
353 | [recv_len, recv_data8] = wl_mex_udp_transport('receive', obj.sock, MAX_PKT_LEN); |
---|
354 | |
---|
355 | catch receiveError |
---|
356 | error('%s.m -- Failed to receive UDP packet.\nMEX transport error message follows:\n %s\n', mfilename, receiveError.message); |
---|
357 | end |
---|
358 | |
---|
359 | % If we have a packet, then process the contents |
---|
360 | if(recv_len > 0) |
---|
361 | reply8 = [recv_data8(3:recv_len) zeros(mod(-(recv_len - 2), 4), 1, 'uint8')]; |
---|
362 | reply = swapbytes(typecast(reply8, 'uint32')); |
---|
363 | |
---|
364 | % Check the header to see if this was a valid reply |
---|
365 | if(obj.hdr.isReply(reply(1:hdr_length))) |
---|
366 | |
---|
367 | % Check the header to see if we need to wait for the node to be ready |
---|
368 | if (obj.hdr.isNodeReady(reply(1:hdr_length))) |
---|
369 | |
---|
370 | % Strip off transport header to give response to caller |
---|
371 | reply = reply((hdr_length + 1):end); |
---|
372 | |
---|
373 | if(isempty(reply)) |
---|
374 | reply = []; |
---|
375 | end |
---|
376 | |
---|
377 | receivedResponse = 1; |
---|
378 | |
---|
379 | else |
---|
380 | % Node is not ready; Wait and try again |
---|
381 | pause(obj.TRANSPORT_NOT_READY_WAIT_TIME); |
---|
382 | numWaitRetries = numWaitRetries + 1; |
---|
383 | |
---|
384 | % Send packet packet again |
---|
385 | obj.sock.send(pkt_send); |
---|
386 | |
---|
387 | % Check that we have not spent a "long time" waiting for samples to be ready |
---|
388 | if (numWaitRetries > obj.TRANSPORT_NOT_READY_MAX_RETRY) |
---|
389 | error('wl_transport_eth_mex:send:isReady', 'Error: Timeout waiting for node to be ready. Please check the node operation.'); |
---|
390 | end |
---|
391 | |
---|
392 | reply = []; |
---|
393 | end |
---|
394 | end |
---|
395 | end |
---|
396 | |
---|
397 | % Look for timeout |
---|
398 | if ((toc(currTime) > obj.timeout) && (receivedResponse == 0)) |
---|
399 | if(currTx == maxAttempts) |
---|
400 | error('wl_transport_eth_mex:send:noReply', 'maximum number of retransmissions met without reply from node'); |
---|
401 | end |
---|
402 | |
---|
403 | % Retry the packet |
---|
404 | size = wl_mex_udp_transport('send', obj.sock, data8, length(data8), obj.address, obj.port); |
---|
405 | currTx = currTx + 1; |
---|
406 | currTime = tic; |
---|
407 | end |
---|
408 | end |
---|
409 | end |
---|
410 | end |
---|
411 | |
---|
412 | function resp = receive(obj) |
---|
413 | % Receive all packets from the Ethernet interface and pass array |
---|
414 | % of valid responses to the caller. |
---|
415 | % |
---|
416 | % NOTE: This function will strip off the transport header from the responses |
---|
417 | % NOTE: This function is non-blocking and will return an empty response if |
---|
418 | % there are no packets available. |
---|
419 | % |
---|
420 | |
---|
421 | % Initialize variables |
---|
422 | MAX_PKT_LEN = obj.getMaxPayload() + 100; |
---|
423 | hdr_length = obj.hdr.length; |
---|
424 | done = false; |
---|
425 | resp = []; |
---|
426 | |
---|
427 | while ~done |
---|
428 | try |
---|
429 | [recv_len, recv_data8] = wl_mex_udp_transport('receive', obj.sock, MAX_PKT_LEN); |
---|
430 | |
---|
431 | catch receiveError |
---|
432 | error('%s.m -- Failed to receive UDP packet.\nMEX transport error message follows:\n %s\n', mfilename, receiveError.message); |
---|
433 | end |
---|
434 | |
---|
435 | if(recv_len > 0) |
---|
436 | reply8 = [recv_data8(3:recv_len) zeros(mod(-(recv_len - 2), 4), 1, 'uint8')].'; |
---|
437 | reply = swapbytes(typecast(reply8, 'uint32')); |
---|
438 | |
---|
439 | if(obj.hdr.isReply(reply(1:hdr_length))) |
---|
440 | % Strip off transport header to give response to caller |
---|
441 | reply = reply((hdr_length + 1):end); |
---|
442 | |
---|
443 | if(isempty(reply)) |
---|
444 | reply = []; |
---|
445 | end |
---|
446 | |
---|
447 | resp = [resp, reply]; |
---|
448 | |
---|
449 | done = true; |
---|
450 | end |
---|
451 | else |
---|
452 | done = true; |
---|
453 | end |
---|
454 | end |
---|
455 | end |
---|
456 | |
---|
457 | function dottedIPout = int2IP(obj,intIn) |
---|
458 | addrChars(4) = mod(intIn, 2^8); |
---|
459 | addrChars(3) = mod(bitshift(intIn, -8), 2^8); |
---|
460 | addrChars(2) = mod(bitshift(intIn, -16), 2^8); |
---|
461 | addrChars(1) = mod(bitshift(intIn, -24), 2^8); |
---|
462 | dottedIPout = sprintf('%d.%d.%d.%d', addrChars); |
---|
463 | end |
---|
464 | |
---|
465 | function intOut = IP2int(obj,dottedIP) |
---|
466 | addrChars = sscanf(dottedIP, '%d.%d.%d.%d')'; |
---|
467 | intOut = 2^0 * addrChars(4) + 2^8 * addrChars(3) + 2^16 * addrChars(2) + 2^24 * addrChars(1); |
---|
468 | end |
---|
469 | |
---|
470 | function reply = print_cmd(obj, type, num_samples, start_sample, buffer_ids, command) |
---|
471 | fprintf('Command: %s \n', type); |
---|
472 | fprintf(' # samples = %d start sample = %d \n', num_samples, start_sample); |
---|
473 | fprintf(' buffer IDs = '); |
---|
474 | for index = 1:length(buffer_ids) |
---|
475 | fprintf('%d ', buffer_ids(index)); |
---|
476 | end |
---|
477 | fprintf('\n Command (%d bytes): ', length(command) ); |
---|
478 | for index = 1:length(command) |
---|
479 | switch(index) |
---|
480 | case 1 |
---|
481 | fprintf('\n Padding : '); |
---|
482 | case 3 |
---|
483 | fprintf('\n Dest ID : '); |
---|
484 | case 5 |
---|
485 | fprintf('\n Src ID : '); |
---|
486 | case 7 |
---|
487 | fprintf('\n Rsvd : '); |
---|
488 | case 8 |
---|
489 | fprintf('\n Pkt Type : '); |
---|
490 | case 9 |
---|
491 | fprintf('\n Length : '); |
---|
492 | case 11 |
---|
493 | fprintf('\n Seq Num : '); |
---|
494 | case 13 |
---|
495 | fprintf('\n Flags : '); |
---|
496 | case 15 |
---|
497 | fprintf('\n Command : '); |
---|
498 | case 19 |
---|
499 | fprintf('\n Length : '); |
---|
500 | case 21 |
---|
501 | fprintf('\n # Args : '); |
---|
502 | case 23 |
---|
503 | fprintf('\n Args : '); |
---|
504 | otherwise |
---|
505 | if ( index > 23 ) |
---|
506 | if ( ( mod( index + 1, 4 ) == 0 ) && not( index == length(command) ) ) |
---|
507 | fprintf('\n '); |
---|
508 | end |
---|
509 | end |
---|
510 | end |
---|
511 | fprintf('%2x ', command(index) ); |
---|
512 | end |
---|
513 | fprintf('\n\n'); |
---|
514 | |
---|
515 | reply = 0; |
---|
516 | end |
---|
517 | |
---|
518 | %----------------------------------------------------------------- |
---|
519 | % read_buffers |
---|
520 | % Command to utilize additional functionality in the wl_mex_udp_transport C code in order to |
---|
521 | % speed up processing of 'readIQ' and 'readRSSI' commands |
---|
522 | % |
---|
523 | % Supports the following calling conventions: |
---|
524 | % - start_sample -> must be a single value |
---|
525 | % - num_samples -> must be a single value |
---|
526 | % - buffer_ids -> Can be a vector of single RF interfaces |
---|
527 | % |
---|
528 | function reply = read_buffers(obj, func, num_samples, buffer_ids, start_sample, seq_num_tracker, seq_num_match_severity, node_id_str, wl_command, input_type) |
---|
529 | % func : Function within read_buffers to call |
---|
530 | % number_samples : Number of samples requested |
---|
531 | % buffer_ids : Array of Buffer IDs |
---|
532 | % start_sample : Start sample |
---|
533 | % seq_num_tracker : Sequence number tracker |
---|
534 | % seq_num_match_severity : Severity of message when sequence numbers match on reads |
---|
535 | % node_id_str : String representation of Node ID |
---|
536 | % wl_command : Ethernet WARPLab command |
---|
537 | % input_type : Type of sample array: |
---|
538 | % 0 ==> 'double' |
---|
539 | % 1 ==> 'single' |
---|
540 | % 2 ==> 'int16' |
---|
541 | % 3 ==> 'raw' |
---|
542 | |
---|
543 | % Get the lowercase version of the function |
---|
544 | func = lower(func); |
---|
545 | |
---|
546 | % Calculate how many transport packets are required |
---|
547 | numPktsRequired = ceil(double(num_samples)/double(obj.maxSamples)); |
---|
548 | |
---|
549 | % Arguments for the command will be set in the MEX function since it is faster |
---|
550 | % wl_command.setArgs(buffer_id, start_sample, num_samples, obj.maxSamples * 4, numPktsRequired); |
---|
551 | |
---|
552 | % Construct the minimal WARPLab command that will be used used to get the samples |
---|
553 | % NOTE: Since we did not add the arguments of the command thru setArgs, we need to pad the structure so that |
---|
554 | % the proper amount of memory is allocated to be available to the MEX |
---|
555 | payload = uint32( wl_command.serialize() ); % Convert command to uint32 |
---|
556 | cmd_args_pad = uint32( zeros(1, 5) ); % Padding for command args |
---|
557 | obj.hdr.flags = bitset(obj.hdr.flags,1,0); % We do not need a response for the sent command |
---|
558 | obj.hdr.msgLength = ( ( length( payload ) ) + 5) * 4; % Length in bytes |
---|
559 | |
---|
560 | data = [obj.hdr.serialize, payload, cmd_args_pad]; |
---|
561 | data8 = [zeros(1,2,'uint8') typecast(swapbytes(uint32(data)), 'uint8')]; |
---|
562 | |
---|
563 | % Pass all of the command arguments down to MEX |
---|
564 | switch(func) |
---|
565 | case 'iq' |
---|
566 | % Calls the MEX read_iq command |
---|
567 | % |
---|
568 | % obj.print_cmd('READ_IQ', num_samples, start_sample, buffer_ids, data8); |
---|
569 | |
---|
570 | [num_rcvd_samples, cmds_used, rx_samples] = wl_mex_udp_transport('read_iq', obj.sock, data8, length(data8), obj.address, obj.port, num_samples, buffer_ids, start_sample, obj.maxSamples * 4, numPktsRequired, input_type, seq_num_tracker, seq_num_match_severity, node_id_str); |
---|
571 | |
---|
572 | % Code to test higher level matlab code without invoking the MEX transport |
---|
573 | % |
---|
574 | % rx_samples = zeros( num_samples, 1 ); |
---|
575 | % cmds_used = 0; |
---|
576 | |
---|
577 | case 'rssi' |
---|
578 | % Calls the MEX read_rssi command |
---|
579 | % |
---|
580 | % obj.print_cmd('READ_RSSI', num_samples, start_sample, buffer_ids, data8); |
---|
581 | |
---|
582 | [num_rcvd_samples, cmds_used, rx_samples] = wl_mex_udp_transport('read_rssi', obj.sock, data8, length(data8), obj.address, obj.port, num_samples, buffer_ids, start_sample, obj.maxSamples * 4, numPktsRequired, input_type, seq_num_tracker, seq_num_match_severity, node_id_str); |
---|
583 | |
---|
584 | % Code to test higher level matlab code without invoking the MEX transport |
---|
585 | % |
---|
586 | % rx_samples = zeros( num_samples * 2, 1 ); |
---|
587 | % cmds_used = 0; |
---|
588 | |
---|
589 | otherwise |
---|
590 | error('unknown command ''%s''', cmdStr); |
---|
591 | end |
---|
592 | |
---|
593 | obj.hdr.increment(cmds_used); |
---|
594 | |
---|
595 | reply = rx_samples; |
---|
596 | end |
---|
597 | |
---|
598 | |
---|
599 | %----------------------------------------------------------------- |
---|
600 | % write_buffers |
---|
601 | % Command to utilize additional functionality in the wl_mex_udp_transport C code in order to |
---|
602 | % speed up processing of 'writeIQ' commands |
---|
603 | % |
---|
604 | function reply = write_buffers(obj, func, num_samples, samples, buffer_ids, start_sample, hw_ver, wl_command, check_chksum, input_type) |
---|
605 | % func : Function within read_buffers to call |
---|
606 | % number_samples : Number of samples requested |
---|
607 | % samples : Array of IQ samples |
---|
608 | % buffer_ids : Array of Buffer IDs |
---|
609 | % start_sample : Start sample |
---|
610 | % hw_ver : Hardware version of the Node |
---|
611 | % wl_command : Ethernet WARPLab command |
---|
612 | % check_chksum : Perform the WriteIQ checksum check inside the function |
---|
613 | % input_type : Type of sample array: |
---|
614 | % 0 ==> 'double' |
---|
615 | % 1 ==> 'single' |
---|
616 | % 2 ==> 'int16' |
---|
617 | % 3 ==> 'raw' |
---|
618 | |
---|
619 | % Calculate how many transport packets are required |
---|
620 | num_pkts_required = ceil(double(num_samples)/double(obj.maxSamples)); |
---|
621 | |
---|
622 | % Construct the WARPLab command that will be used used to write the samples |
---|
623 | payload = uint32( wl_command.serialize() ); % Convert command to uint32 |
---|
624 | obj.hdr.flags = bitset(obj.hdr.flags,1,0); % We do not need a response for the sent command |
---|
625 | obj.hdr.msgLength = ( length( payload ) ) * 4; % Length in bytes |
---|
626 | |
---|
627 | data = [obj.hdr.serialize, payload]; |
---|
628 | data8 = [zeros(1,2,'uint8') typecast(swapbytes(uint32(data)), 'uint8')]; |
---|
629 | |
---|
630 | socket = obj.sock; |
---|
631 | address = obj.address; |
---|
632 | port = obj.port; |
---|
633 | max_payload = obj.getMaxPayload(); |
---|
634 | max_samples = obj.maxSamples; |
---|
635 | |
---|
636 | |
---|
637 | func = lower(func); |
---|
638 | switch(func) |
---|
639 | case 'iq' |
---|
640 | % Calls the MEX read_iq command |
---|
641 | % |
---|
642 | [cmds_used, checksum] = wl_mex_udp_transport('write_iq', socket, data8, max_payload, address, port, num_samples, samples, buffer_ids, start_sample, num_pkts_required, max_samples, hw_ver, check_chksum, input_type); |
---|
643 | |
---|
644 | % Increment the transport header by cmds_used (ie number of commands used |
---|
645 | obj.hdr.increment(cmds_used); |
---|
646 | |
---|
647 | % Record the checksum for that Write IQ |
---|
648 | reply = checksum; |
---|
649 | |
---|
650 | otherwise |
---|
651 | error('unknown command ''%s''',cmdStr); |
---|
652 | end |
---|
653 | |
---|
654 | reply = checksum; |
---|
655 | end |
---|
656 | end |
---|
657 | end % classdef |
---|
658 | |
---|
659 | |
---|
660 | |
---|
661 | |
---|