diff --git a/source/Brick.m b/source/CommunicationInterface.m similarity index 95% rename from source/Brick.m rename to source/CommunicationInterface.m index 6927b8a298b77dacd7bd1a517597063c3418efbf..34fcecbba2c408920a57cdb7df1a596c4bf98f7a 100644 --- a/source/Brick.m +++ b/source/CommunicationInterface.m @@ -99,31 +99,37 @@ % b = Brick('ioType','bt','serPort','/dev/rfcomm0') -classdef Brick < handle +classdef CommunicationInterface < handle properties - % Connection handle - conn; % Debug debug; + end + + properties (SetAccess = 'private') % IO connection type ioType; % Bluetooth brick device name - btDevice; + btDevice = ''; % Bluetooth brick communication channel - btChannel; + btChannel = 0; % Wifi brick IP address - wfAddr; + wfAddr = ''; % Wifi brick TCP port - wfPort; + wfPort = ''; % Brick serial number - wfSN; + wfSN = ''; % Bluetooth serial port serPort; end - + + properties (Hidden, Access = 'private') + % Connection handle + conn; + end + methods - function brick = Brick(varargin) + function commInterface = CommunicationInterface(varargin) % Brick.Brick Create a Brick object % % b = Brick(OPTIONS) is an object that represents a connection @@ -153,53 +159,49 @@ classdef Brick < handle % - For instrBrickIO (bluetooth) % b = Brick('ioType','instrbt','btDevice','EV3','btChannel',1) - % Init the properties - opt.debug = 0; - opt.btDevice = 'EV3'; - opt.btChannel = 1; - opt.wfAddr = '192.168.1.104'; - opt.wfPort = 5555; - opt.wfSN = '0016533dbaf5'; - opt.ioType = 'usb'; - opt.serPort = '/dev/rfcomm0'; - - % Read in the options - opt = tb_optparse(opt, varargin); - brick.debug = opt.debug; - brick.ioType = opt.ioType; + commInterface.setProperties(varargin{:}); +% % Init the properties +% opt.debug = 0; +% opt.btDevice = 'EV3'; +% opt.btChannel = 1; +% opt.wfAddr = '192.168.1.104'; +% opt.wfPort = 5555; +% opt.wfSN = '0016533dbaf5'; +% opt.ioType = 'usb'; +% opt.serPort = '/dev/rfcomm0'; +% +% % Read in the options +% opt = tb_optparse(opt, varargin); +% commInterface.debug = opt.debug; +% commInterface.ioType = opt.ioType; + try - if(strcmp(opt.ioType,'usb')) % USB - brick.conn = usbBrickIO(brick.debug); - elseif(strcmp(opt.ioType,'wifi')) % WiFi - brick.wfAddr = opt.wfAddr; - brick.wfPort = opt.wfPort; - brick.wfSN = opt.wfSN; - brick.conn = wfBrickIO(brick.debug,brick.wfAddr,brick.wfPort,brick.wfSN); - elseif(strcmp(opt.ioType,'bt')) % Bluetooth - brick.serPort = opt.serPort; - brick.conn = btBrickIO(brick.debug,brick.serPort); - elseif(strcmp(opt.ioType,'instrwifi')) % Instrumentation and Control: WiFi - brick.wfAddr = opt.wfAddr; - brick.wfPort = opt.wfPort; - brick.wfSN = opt.wfSN; - brick.conn = instrBrickIO(brick.debug,'wf',brick.wfAddr,brick.wfPort,brick.wfSN); - elseif(strcmp(opt.ioType,'instrbt')) % Instrumentation and Control: Bluetooth - brick.btDevice = opt.btDevice; - brick.btChannel = opt.btChannel; - brick.conn = instrBrickIO(brick.debug,'bt',brick.btDevice,brick.btChannel); + if(strcmp(commInterface.ioType,'usb')) % USB + commInterface.conn = usbBrickIO(commInterface.debug); + elseif(strcmp(commInterface.ioType,'wifi')) % WiFi + commInterface.wfAddr = opt.wfAddr; + commInterface.wfPort = opt.wfPort; + commInterface.wfSN = opt.wfSN; + commInterface.conn = wfBrickIO(commInterface.debug,commInterface.wfAddr,commInterface.wfPort,commInterface.wfSN); + elseif(strcmp(commInterface.ioType,'bt')) % Bluetooth +% commInterface.serPort = opt.serPort; + commInterface.conn = btBrickIO(commInterface.debug,commInterface.serPort); + elseif(strcmp(commInterface.ioType,'instrwifi')) % Instrumentation and Control: WiFi + commInterface.wfAddr = opt.wfAddr; + commInterface.wfPort = opt.wfPort; + commInterface.wfSN = opt.wfSN; + commInterface.conn = instrBrickIO(commInterface.debug,'wf',commInterface.wfAddr,commInterface.wfPort,commInterface.wfSN); + elseif(strcmp(commInterface.ioType,'instrbt')) % Instrumentation and Control: Bluetooth + commInterface.btDevice = opt.btDevice; + commInterface.btChannel = opt.btChannel; + commInterface.conn = instrBrickIO(commInterface.debug,'bt',commInterface.btDevice,commInterface.btChannel); end catch ME - brick.conn = []; + commInterface.conn = []; rethrow(ME); end end - function set.debug(brick, debug) - % If debug is set in this layer, also set BrickIO.debug in lower layer - brick.debug = debug; - brick.conn.debug = debug; - end - function delete(brick) % Brick.delete Delete the Brick object % @@ -208,7 +210,40 @@ classdef Brick < handle if isa(brick.conn, 'handle') && isvalid(brick.conn) brick.conn.delete(); end - end + end + + function set.debug(brick, debug) + % If debug is set in this layer, also set BrickIO.debug in lower layer + brick.debug = debug; + brick.conn.debug = debug; + end + + function setProperties(brick, varargin) + p = inputParser(); + + % Set default values + defaultIOType = 'usb'; + defaultSerPort = '/dev/rfcomm0'; + defaultDebug = false; + + % Define anonymous function that will return whether given value in varargin is valid + %validTypes = ; + checkIOType = @(x) ismember(x, {'usb', 'bt'}); + checkDebug = @(x) isBool(x); + + % Add parameters + p.addRequired('ioType', checkIOType); + p.addOptional('serPort', defaultSerPort); + p.addOptional('debug', defaultDebug, checkDebug); + + % Parse input... + p.parse(varargin{:}); + + % Set properties + brick.ioType = p.Results.ioType; + brick.serPort = p.Results.serPort; + brick.debug = p.Results.debug; + end function send(brick, cmd) % Brick.send Send data to the brick @@ -230,7 +265,7 @@ classdef Brick < handle % a delay, some commands may even be bypassed. % (Maybe too many commands screw up the brick's internal command queue?..) % Temporary workaround: Wait 5ms after each sent packet. - pause(0.005); + % pause(0.005); % Verbose output if brick.debug > 0 @@ -629,7 +664,6 @@ classdef Brick < handle % % Example:: % [type,mode] = b.inputDeviceTypeMode(0,SensorPort.Sensor1) - cmd = Command(); cmd.addHeaderDirectReply(42,2,0); cmd.opINPUT_DEVICE_GET_TYPEMODE(layer,no,0,1); @@ -1316,7 +1350,7 @@ classdef Brick < handle % - layer is the usb chain layer (usually 0) % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08) % - pol is the polarity [-1,0,1], -1 makes the motor run - % backward, 1 makes the motor run forward, 0 makes the motor + % backwards, 1 makes the motor run forwards, 0 makes the motor % run the opposite direction when starting next time % % Example:: diff --git a/source/EV3.m b/source/EV3.m index 2c9032c15b3cc1cf37b0db909e742e64203424cc..0cbb62d727041203f65cc761303cf4eff5b4888a 100644 --- a/source/EV3.m +++ b/source/EV3.m @@ -15,7 +15,7 @@ classdef EV3 < handle % batteryValue - Current battery charge level % get-only % isConnected - Is virtual brick connected to physical one? - % brick - Brick object from sublayer class Brick -> used as interface to the physical brick. + % commInterface - Brick object from sublayer class Brick -> used as interface to the physical brick. % % Methods: % Standard @@ -80,8 +80,8 @@ classdef EV3 < handle end properties (SetAccess = 'private') % Read-only properties that are set internally - isConnected = 0; % Is virtual brick currently connected to physical brick? - brick = 0; % Brick object from sub-layer class Brick -> used as interface to the + isConnected = false; % Is virtual brick currently connected to physical brick? + commInterface = 0; % Brick object from sub-layer class Brick -> used as interface to the % physical brick. %% Motors and Sensors @@ -113,99 +113,99 @@ classdef EV3 < handle ev3.setProperties(varargin{:}); - ev3.motorA = Motor('A', 'Debug', ev3.debug); - ev3.motorB = Motor('B', 'Debug', ev3.debug); - ev3.motorC = Motor('C', 'Debug', ev3.debug); - ev3.motorD = Motor('D', 'Debug', ev3.debug); + ev3.motorA = Motor('A', 'Debug', ev3.debug>=1); + ev3.motorB = Motor('B', 'Debug', ev3.debug>=1); + ev3.motorC = Motor('C', 'Debug', ev3.debug>=1); + ev3.motorD = Motor('D', 'Debug', ev3.debug>=1); - ev3.sensor1 = Sensor('1', 'Debug', ev3.debug); - ev3.sensor2 = Sensor('2', 'Debug', ev3.debug); - ev3.sensor3 = Sensor('3', 'Debug', ev3.debug); - ev3.sensor4 = Sensor('4', 'Debug', ev3.debug); + ev3.sensor1 = Sensor('1', 'Debug', ev3.debug>=1); + ev3.sensor2 = Sensor('2', 'Debug', ev3.debug>=1); + ev3.sensor3 = Sensor('3', 'Debug', ev3.debug>=1); + ev3.sensor4 = Sensor('4', 'Debug', ev3.debug>=1); - ev3.init = 0; + ev3.init = false; end function delete(ev3) - if ev3.isConnected - ev3.disconnect(); - end + %delete Disconnects from physical brick and deletes this instance + + if ev3.isConnected + ev3.disconnect(); + end end + %% Connection function connect(ev3, varargin) %connect Connects EV3-object and its Motors and Sensors to physical brick. % % Arguments - % * 'beep', 'on'/'off': EV3 beeps if connection has been established. - % * 'ioType', 'bt'/'usb': Connection type - % * ['ioType', 'bt'] 'serPort', '/dev/rfcommx': Path to serial port + % * 'bt'/'usb': Connection type + % * 'serPort', '/dev/rfcommx': Path to serial port (if 'bt'), where x = 0...9 + % * 'beep', bool: EV3 beeps if connection has been established. % % Examples - % b = EV3(); b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0'); - % b = EV3(); b.connect('beep', 'on', ''ioType', 'usb'); + % b = EV3(); b.connect('bt', 'serPort', '/dev/rfcomm0'); + % b = EV3(); b.connect('usb', 'beep', 'on', ); % % Check connection if ev3.isConnected - if isBrickValid(ev3.brick) + if isCommInterfaceValid(ev3.commInterface) error('EV3::connect: Already connected.'); else warning(['EV3::connect: EV3.isConnected is set to ''True'', but ',... - 'brick handle is invalid. Deleting invalid handle and ' ,... + 'comm handle is invalid. Deleting invalid handle and ' ,... 'resetting EV3.isConnected now...']); - ev3.brick = 0; - ev3.isConnected = 0; + ev3.commInterface = 0; + ev3.isConnected = false; end end - % Interpret arguments - if nargin < 3 + if nargin < 2 error('EV3::connect: Wrong number of input arguments.'); end - beep = 0; - if strcmpi(varargin{1}, 'beep') - if strcmpi(varargin{2}, 'on') - beep = 1; - elseif ~strcmpi(varargin{2}, 'off') - % First argument was beep, but second one was neither 'true' nor - % 'false' - warning(['EV3::connect: The parameter after "beep" has to be either ',... - '"true" or "false"']); - error('EV3::connect: Wrong input arguments.'); + + idxes = strcmpi('beep', varargin); + idx = find([0, idxes(1:end-1)]); + if ~isempty(idx) + beep = varargin{idx}; %#ok<FNDSB> + if ~isBool(beep) + error('EV3::connect: Argument after ''beep'' has to be a bool.'); end - varargin = varargin(3:end); % Cut beep-part off + else + beep = false; end % Try to connect try % Connect to physical brick - % -> Creating Brick-object implicitly establishes connection - ev3.brick = Brick('debug', ev3.debug>=2, varargin{1:end}); - ev3.isConnected = 1; + % -> Creating communication-handle implicitly establishes connection + ev3.commInterface = CommunicationInterface(varargin{:}, 'debug', ev3.debug>=2); + ev3.isConnected = true; if beep ev3.beep(); end % Connect motors - ev3.motorA.connect(ev3.brick); - ev3.motorB.connect(ev3.brick); - ev3.motorC.connect(ev3.brick); - ev3.motorD.connect(ev3.brick); + ev3.motorA.connect(ev3.commInterface); + ev3.motorB.connect(ev3.commInterface); + ev3.motorC.connect(ev3.commInterface); + ev3.motorD.connect(ev3.commInterface); % Connect sensors - ev3.sensor1.connect(ev3.brick); - ev3.sensor2.connect(ev3.brick); - ev3.sensor3.connect(ev3.brick); - ev3.sensor4.connect(ev3.brick); + ev3.sensor1.connect(ev3.commInterface); + ev3.sensor2.connect(ev3.commInterface); + ev3.sensor3.connect(ev3.commInterface); + ev3.sensor4.connect(ev3.commInterface); catch ME % Something went wrong... - ev3.isConnected = 0; - if isBrickValid(ev3.brick) && ev3.brick ~= 0 - ev3.brick.delete(); - ev3.brick = 0; + ev3.isConnected = false; + if isCommInterfaceValid(ev3.commInterface) && ev3.commInterface ~= 0 + ev3.commInterface.delete(); + ev3.commInterface = 0; end rethrow(ME); @@ -372,11 +372,11 @@ classdef EV3 < handle %beep Plays a 'beep' tone on brick. % % Notes - % * This equals playTone(10, 1000, 100). (Wraps the same opCode in comm-layer) + % * This equals playTone(10, 1000, 100) (Wraps the same opCode in comm-layer) % % Example % b = EV3(); - % b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0'); + % b.connect('bt', 'serPort', '/dev/rfcomm0'); % b.beep(); % @@ -385,7 +385,7 @@ classdef EV3 < handle 'You have to call ev3.connect(...) first!']); end - ev3.brick.beep(); + ev3.commInterface.beep(); if ev3.debug fprintf('(DEBUG) EV3::beep: Called beep on brick\n'); @@ -398,11 +398,11 @@ classdef EV3 < handle % Arguments % * volume (0...100) % * frequency (250...10000) - % * duration (in milliseconds) + % * duration (>0, in milliseconds) % % Example % b = EV3(); - % b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0'); + % b.connect('bt', 'serPort', '/dev/rfcomm0'); % b.playTone(50, 5000, 1000); % Plays tone with 50% volume and 5000Hz for 1 % % second. % @@ -412,7 +412,7 @@ classdef EV3 < handle 'You have to call ev3.connect(...) first!']); end - ev3.brick.soundPlayTone(volume, frequency, duration); + ev3.commInterface.soundPlayTone(volume, frequency, duration); if ev3.debug fprintf('(DEBUG) EV3::beep: Called soundPlayTone on brick\n'); @@ -424,7 +424,7 @@ classdef EV3 < handle % % Example % b = EV3(); - % b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0'); + % b.connect('bt', 'serPort', '/dev/rfcomm0'); % b.playTone(10,100,100000000); % Accidentally given wrong tone duration. % b.stopTone(); % Stops tone immediately. % @@ -434,7 +434,7 @@ classdef EV3 < handle 'You have to call ev3.connect(...) first!']); end - ev3.brick.soundStopTone(); + ev3.commInterface.soundStopTone(); if ev3.debug fprintf('(DEBUG) EV3::beep: Called soundStopTone on brick\n'); @@ -445,11 +445,11 @@ classdef EV3 < handle %tonePlayed Tests if tone is currently played. % % Output - % * status: Returns 0 if a tone is being played, 1 if not. + % * status: True for a tone being played % % Example % b = EV3(); - % b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0'); + % b.connect('bt', 'serPort', '/dev/rfcomm0'); % b.playTone(10, 100, 1000); % pause(0.5); % b.tonePlayed() -> Outputs 1 to console. @@ -460,7 +460,7 @@ classdef EV3 < handle 'You have to call ev3.connect(...) first!']); end - status = ev3.brick.soundTest; + status = ev3.commInterface.soundTest; if ev3.debug fprintf('(DEBUG) EV3::beep: Called soundTest on brick\n'); @@ -468,13 +468,11 @@ classdef EV3 < handle end %% Setter - function set.brick(ev3, brick) - % Check if brick is valid and set ev3.brick if it is. - - if ~isBrickValid(brick) - error('EV3::set.brick: Handle to Brick-object not valid.'); + function set.commInterface(ev3, comm) + if ~isCommInterfaceValid(comm) + error('EV3::set.commInterface: Handle to Brick-object not valid.'); else - ev3.brick = brick; + ev3.commInterface = comm; end end @@ -504,14 +502,10 @@ classdef EV3 < handle error('EV3::set.debug: Given parameter is not a bool.'); end - if ischar(debug) - ev3.debug = str2bool(debug); - else - ev3.debug = debug; - end + ev3.debug = str2bool(debug); - if ev3.isConnected() - ev3.brick.debug = (ev3.debug >= 2); + if ev3.isConnected + ev3.commInterface.debug = (ev3.debug >= 2); end end @@ -581,20 +575,17 @@ classdef EV3 < handle end if strcmpi(ev3.batteryMode, 'Percentage') - bat = ev3.brick.uiReadLbatt(); + bat = ev3.commInterface.uiReadLbatt(); if ev3.debug fprintf('(DEBUG) EV3::getBattery: Called uiReadLBatt.\n'); end elseif strcmpi(ev3.batteryMode, 'Voltage') - bat = ev3.brick.uiReadVbatt(); + bat = ev3.commInterface.uiReadVbatt(); if ev3.debug fprintf('(DEBUG) EV3::getBattery: Called uiReadVBatt.\n'); end - else - warning('EV3:getBattery: Mode has to be Percentage or Voltage!'); - error('EV3::getBattery: Mode not valid.'); end end end diff --git a/source/Sensor.m b/source/Sensor.m index f794ae8663cfdca07813e7aacc0e91dc47abcef2..fe0c983f61c0d45079ab9e891aa2aec09a8458d4 100644 --- a/source/Sensor.m +++ b/source/Sensor.m @@ -27,7 +27,7 @@ classdef Sensor < handle % % b = EV3(); % b = EV3('debug', 'on', 'batteryMode', 'Voltage'); - % b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0'); + % b.connect('bt', 'serPort', '/dev/rfcomm0'); % b.sensor1.mode = DeviceMode.Touch.Bumps; % while value < 10 % pause(0.1); @@ -40,226 +40,120 @@ classdef Sensor < handle % Signature % Author: Tim Stadtmann % Date: 2016/05/20 + % Updated: 2016/08/15 properties % Standard properties to be set by user + %mode - Sensor mode in which the value will be read + % -> DeviceMode.[...] (except for DeviceMode.Motor.[...]) + mode; + %debug - Debug turned on or off % In debug mode, everytime a command is passed to the sublayer ('communication layer'), % there is feedback in the console about what command has been called, etc. % -> Any valid boolean (0/1/'on'/'off'/'true'/'false') debug; - - %mode - Sensor mode in which the value will be read - % -> DeviceMode.[...] (except for DeviceMode.Motor.[...]) - mode; end - properties (Dependent) % Parameters to be read directly from physical brick - value % Value read from sensor - end - - properties (SetAccess = 'private') % Read-only properties that are set internally or in init-phase - %sensorAtPort - Is physical sensor actually connected to port? - % This property will be changed by Sensor.update() if changes have happened on the - % physical brick, depending on status, type and mode values. - % See also STATUS, TYPE, MODE, UPDATE - sensorAtPort = 0; - - %brick - Brick object from sublayer class Brick -> used as interface to the physical brick. - % See also BRICK - brick = 0; - + properties (SetAccess = 'private') %port - Sensor port % This is only the string representation of the sensor port to work with. - % Internally, SensorPort-enums are used. (This is a bit inconvenient but more - % consistent compared with Motor) + % Internally, SensorPort-enums are used. % -> '1' / '2' / '3' / '4' - port; + port; + end + + properties (Dependent) % Parameters to be read directly from physical brick + value; % Value read from sensor + type; % Physical sensor connected to this port? + end + + properties (Hidden, Access = 'private') % Hidden properties for internal use only + commInterface = 0; % Communication interface - %status - Connection status at port - % This property will be changed by Sensor.update() if changes have happened on the - % physical brick. - % See also CONNECTIONTYPE, UPDATE - status = DeviceMode.Error.Undefined; + %% Miscallenous flags - %type - Device type at port - % This property will be changed by Sensor.update() if changes have happened on the - % physical brick. - % See also DEVICEMODE.ERROR, UPDATE - type = DeviceMode.Error.Undefined; + connectedToBrick = false; % Does (virtual) sensor-object have a valid brick-handle? + init = true; % Indicates 'init-phase' (True as long as constructor is running) end - properties (Hidden, Access = 'private') % Hidden properties for internal use only - init = 1; % Is set to zero after initial 'creating' phase is done. - isConnected = 0; % Does (virtual) sensor-object have a valid brick-handle? - - %% Equivalent for Sensor.port in enumeration SensorPort - % Port is an actual parameter on the physical brick. To avoid using string - % comparisons each time it is used, the corresponding value (i.e. '1' -> SensorPort.Sensor1) - % to the given strings is saved (hidden from the user). - port_; + properties (Hidden, Dependent, Access = 'private') + physicalSensorConnected; % Physical sensor connected to this port? end methods % Standard methods %% Constructor function sensor = Sensor(varargin) sensor.setProperties(varargin{1:end}); - sensor.init = 0; - end - - %% Connection - function connect(sensor,brick) - %connect Connects Sensor-object to physical brick - if sensor.isConnected - if isBrickValid(sensor.brick) - error('Sensor::connect: Sensor-Object already has a brick handle.'); - else - warning(['Sensor::connect: Sensor.isConnected is set to ''True'', but ',... - 'brick handle is invalid. Deleting invalid handle and ' ,... - 'resetting Sensor.isConnected now...']); - - sensor.brick = 0; - sensor.isConnected = 0; - - error('Sensor::connect: Aborted connection.'); - end - end - - sensor.brick = brick; - sensor.isConnected = 1; - - if sensor.debug - fprintf('(DEBUG) Sensor-Object connected to brick handle.\n'); - end - - sensor.update(); - end - - function disconnect(sensor) - %disconnect Disconnects Sensor-object from physical brick -% if ~sensor.isConnected -% error('Sensor::disconnect: No brick connected.'); -% end - - sensor.brick = 0; % Note: actual deleting is done in EV3::disconnect. - sensor.isConnected = 0; - sensor.sensorAtPort = 0; - - sensor.status = DeviceMode.Error.Undefined; - sensor.type = DeviceMode.Error.Undefined; - end - - function update(sensor) - %update Updates Sensor-object to current status at its port. - if ~sensor.isConnected - error(['Sensor::update: Sensor-Object not connected to brick handle.',... - 'You have to call sensor.connect(brick) first!']); - end - - oldMode = sensor.mode; - - sensor.status = sensor.getStatus(); - [sensor.type, newMode] = sensor.getTypeMode(); - - if strcmp(class(oldMode),class(newMode)) && oldMode~=newMode - if ~strcmp(class(oldMode), 'DeviceMode.Error') && ... - ~strcmp(class(newMode), 'DeviceMode.Error') - %warning(['Sensor::update: Physical sensor''s mode was not ',... - % 'the specified one. Changing...']); - - sensor.setMode(oldMode); - sensor.mode = oldMode; - end - else - sensor.mode = newMode; - end - - validStatus = [ConnectionType.NXTColor, ConnectionType.NXTDumb, ConnectionType.NXTIIC, ... - ConnectionType.InputDumb, ConnectionType.InputUART]; - validTypes = [DeviceType.NXTTouch, DeviceType.NXTColor, ... - DeviceType.NXTLight, DeviceType.NXTSound, ... - DeviceType.NXTTemperature, DeviceType.NXTUltraSonic, ... - DeviceType.Color, DeviceType.Gyro, DeviceType.InfraRed, ... - DeviceType.Touch, DeviceType.UltraSonic]; - - sensor.sensorAtPort = 1; - if ~ismember(sensor.status, validStatus) || ~ismember(sensor.type, validTypes) || ... - strcmp(class(sensor.mode), 'DeviceMode.Error') - sensor.sensorAtPort = 0; - end + sensor.init = false; end %% Brick functions function reset(sensor) %reset Resets value on sensor % Note: This clears ALL the sensors right now, no other Op-Code available... :( - if ~sensor.isConnected - error(['Sensor::reset: Sensor-Object not connected to brick handle.',... - 'You have to call sensor.connect(brick) first!']); - elseif ~sensor.sensorAtPort - error('Sensor::reset: No physical sensor connected to Port %s.',... - sensor.port); + if ~sensor.connectedToBrick + error(['Sensor::reset: Sensor-Object not connected to comm handle.',... + 'You have to call sensor.connect(commInterface) first!']); + elseif ~sensor.physicalSensorConnected + error('Sensor::reset: No physical sensor connected to Port %d.',... + sensor.port+1); end warning(['Sensor::reset: Current version of reset resets ALL devices, that is, ',... 'all motor tacho counts and all other sensor counters!']); - sensor.brick.inputDeviceClrAll(0); + sensor.commInterface.inputDeviceClrAll(0); if sensor.debug - fprintf('(DEBUG) Sensor::reset: Called inputReadSI on Port %s.\n',... - sensor.port); + fprintf('(DEBUG) Sensor::reset: Called inputReadSI on Port %d.\n',... + sensor.port+1); end end %% Setter - function set.brick(sensor, brick) - if ~isBrickValid(brick) - error('Sensor::set.brick: Handle to brick not valid.'); - else - sensor.brick = brick; - end - end - - function set.port(sensor, port) - if ~isPortValid(class(sensor),port) - error('Sensor::set.port: Given port is not a valid port.'); + function set.mode(sensor, mode) + if strcmp(class(mode),'DeviceMode.Default') && ~sensor.physicalSensorConnected + sensor.mode = mode; + return; end - if ischar(port) - sensor.port = port; - sensor.port_ = str2PortParam(class(sensor), port); + type = sensor.type; + if ~isModeValid(mode, type) + error('Sensor::set.mode: Sensor mode is not valid for connected sensor type.'); else - error('Sensor::set.port: Port has to be a string.'); + sensor.mode = mode; + + if ~strcmp(class(mode),'DeviceMode.Default') && sensor.connectedToBrick + try + sensor.setMode(mode); % Update physical brick's mode parameter + catch + % Ignore + end + end end end - + function set.debug(sensor, debug) % Check if debug is valid and set sensor.debug if it is. if ~isBool(debug) error('Sensor::set.debug: Given parameter is not a bool.'); end - if ischar(debug) - sensor.debug = str2bool(debug); + sensor.debug = str2bool(debug); + end + + function set.port(sensor, port) + if ~isPortStrValid(class(sensor),port) + error('Sensor::set.port: Given port is not a valid port.'); else - sensor.debug = debug; + sensor.port = str2PortParam(class(sensor), port); end end - - function set.mode(sensor, mode) - if strcmp(class(mode),'DeviceMode.Error') && ~sensor.sensorAtPort - sensor.mode = mode; - return; - end - - if strcmp(class(mode), 'uint8') || strcmp(class(mode), 'double') - mode = DeviceMode(sensor.type, uint8(mode)); - end - - if ~isModeValid(mode, sensor.type) - error('Sensor::set.mode: Sensor mode is not valid.'); + + function set.commInterface(sensor, comm) + if ~isCommInterfaceValid(comm) + error('Sensor::set.commInterface: Handle to commInterface not valid.'); else - sensor.mode = mode; - sensor.setMode(mode); + sensor.commInterface = comm; end end @@ -272,7 +166,7 @@ classdef Sensor < handle % % Example % b = EV3(); - % b.connect('ioType', 'bt', 'serPort', '/dev/rfcomm0'); + % b.connect('bt', 'serPort', '/dev/rfcomm0'); % b.sensor1.setProperties('debug', 'on', 'mode', DeviceMode.Color.Ambient); % % Instead of: b.sensor1.debug = 'on'; % % b.sensor1.mode = DeviceMode.Color.Ambient; @@ -369,7 +263,7 @@ classdef Sensor < handle if isnan(val) pause(0.01); - val = sensor.brick.inputReadSI(0, sensor.port_, sensor.mode); + val = sensor.commInterface.inputReadSI(0, sensor.port, sensor.mode); if isnan(val) warning('Sensor::getValue: Brick returned invalid value (NaN). Try again...'); end @@ -377,39 +271,78 @@ classdef Sensor < handle if sensor.debug fprintf('(DEBUG) Sensor::getValue: Called inputReadSI on Port %d.\n',... - sensor.port); + sensor.port+1); end end function status = getStatus(sensor) - if ~sensor.isConnected - error(['Sensor::getStatus: Sensor-Object not connected to brick handle.',... - 'You have to call sensor.connect(brick) first!']); + if ~sensor.connectedToBrick + error(['Sensor::getStatus: Sensor-Object not connected to comm handle.',... + 'You have to call sensor.connect(commInterface) first!']); end - statusNo = sensor.brick.inputDeviceGetConnection(0, sensor.port_); + statusNo = sensor.commInterface.inputDeviceGetConnection(0, sensor.port); status = ConnectionType(statusNo); if sensor.debug - fprintf('(DEBUG) Sensor::getStatus: Called inputDeviceGetConnection on Port %s\n',... - sensor.port); + fprintf(['(DEBUG) Sensor::getStatus: Called inputDeviceGetConnection on ' ,... + 'Port %d.\n'], sensor.port+1); end end function [type,mode] = getTypeMode(sensor) - if ~sensor.isConnected - error(['Sensor::getTypeMode: Sensor-Object not connected to brick handle.',... - 'You have to call sensor.connect(brick) first!']); + if ~sensor.connectedToBrick + error(['Sensor::getTypeMode: Sensor-Object not connected to comm handle.',... + 'You have to call sensor.connect(commInterface) first!']); end - [typeNo,modeNo] = sensor.brick.inputDeviceGetTypeMode(0, sensor.port_); + [typeNo,modeNo] = sensor.commInterface.inputDeviceGetTypeMode(0, sensor.port); type = DeviceType(typeNo); - mode = DeviceMode(type,modeNo); + try + mode = DeviceMode(type,modeNo); + catch ME + mode = DeviceMode.Default.Undefined; + end if sensor.debug - fprintf('(DEBUG) Sensor::getTypeMode: Called inputDeviceGetConnection on Port %s\n',... - sensor.port); + fprintf(['(DEBUG) Sensor::getStatus: Called inputDeviceGetConnection on ' ,... + 'Port %d.\n'], sensor.port+1); + end + end + end + + methods (Access = {?EV3}) + function connect(sensor,commInterface) + %connect Connects Sensor-object to physical brick + + if sensor.connectedToBrick + if isCommInterfaceValid(sensor.commInterface) + error('Sensor::connect: Sensor-Object already has a comm handle.'); + else + warning(['Sensor::connect: Sensor.connectedToBrick is set to ''True'', but ',... + 'comm handle is invalid. Deleting invalid handle and ' ,... + 'resetting Sensor.connectedToBrick now...']); + + sensor.commInterface = 0; + sensor.connectedToBrick = false; + + error('Sensor::connect: Disconnected due to internal error.'); + end end + + sensor.commInterface = commInterface; + sensor.connectedToBrick = true; + + if sensor.debug + fprintf('(DEBUG) Sensor-Object connected to comm handle.\n'); + end + end + + function disconnect(sensor) + %disconnect Disconnects Sensor-object from physical brick + + sensor.commInterface = 0; % Note: actual deleting is done in EV3::disconnect. + sensor.connectedToBrick = false; end end end diff --git a/source/isBrickValid.m b/source/isCommInterfaceValid.m similarity index 54% rename from source/isBrickValid.m rename to source/isCommInterfaceValid.m index 24447ec6f346555416f553e895b6f00c334f8afd..77d7dc2195b732f57c11cbee25378b75f98ffb0f 100644 --- a/source/isBrickValid.m +++ b/source/isCommInterfaceValid.m @@ -1,10 +1,10 @@ -function isValid = isBrickValid(testBrick) +function isValid = isCommInterfaceValid(comm) % Returns whether given brick object is valid or not. isValid = 0; - if ~isempty(testBrick) + if ~isempty(comm) % The second case (after the '||') is allowed as a default value (think of it as a nullptr). - if (isa(testBrick, 'Brick') && testBrick.isvalid) || ... - (isnumeric(testBrick) && testBrick==0) + if (isa(comm, 'CommunicationInterface') && comm.isvalid) || ... + (isnumeric(comm) && comm==0) isValid = 1; end end