Skip to content
Snippets Groups Projects
Select Git revision
  • develop
  • 1.10/master default protected
2 results

Makefile.am

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    CommunicationInterface.m 75.43 KiB
    classdef CommunicationInterface < handle
        % Brick Interface to Lego Minstorms EV3 brick
        %
        % Methods::
        % brick                 Constructor, establishes communications
        % delete                Destructor, closes connection
        % send                  Send data to the brick
        % receive               Receive data from the brick
        % 
        %
        % uiReadVBatt           Returns battery level as a voltage
        % uiReadLBatt           Returns battery level as a percentage
        %
        % drawTest              Shows the drawing capabilities of the brick
        %
        %
        % soundTest     @MMI:   Returns state of speaker
        % soundReady	@MMI:   Halts the execution of commands on Brick until speakers are ready
        % soundPlayTone         Plays a tone at a volume with a frequency and duration
        % soundStopTone @MMI:   Stops current sound playback
        %
        % beep                  Plays a beep tone with volume and duration
        % playThreeTone         Plays three tones one after the other
        %
        %
        % inputDeviceList          @MMI:    Returns list of sensor types on each port
        % inputDeviceGetName                Returns the device name at a layer and NO
        % inputDeviceGetTypeMode   @MMI:    Returns type and mode of device at a layer and NO
        % inputDeviceSetTypeMode   @MMI:    Sets type and mode of device which is recognized by old
        %                                   type and mode.
        % inputDeviceGetModeName   @MMI:    Returns the device's mode at a layer and NO
        % inputDeviceGetConnection @MMI:	Returns the connection type (=sensor type) at a layer and NO
        % inputDeviceGetMinMax     @MMI:	Returns the min and max SI value of device at a layer and NO
        % inputDeviceGetChanges    @MMI:	Returns positive changes(=button releases) since last clear at a layer and NO
        % inputDeviceGetFormat     @MMI:	Returns no. of datasets, returned data type in
        %                                   active sensor mode, no. of sensor modes and no. of
        %                                   visible sensor modes at a layer and NO
        % inputDeviceGetBumps      @MMI:    Returns negatives changes (=button presses) since last clear at a layer and NO
        % inputDeviceSymbol                 Returns the symbol for the device at a layer, NO and mode
        % inputDeviceClrChanges    @MMI:    Clears changes(&bumps) at a layer and NO
        % inputDeviceClrAll                 Clears all the sensor data at a layer
        % inputReady               @MMI:    Halts the execution of commands on Brick until given devices are ready
        % inputTest                @MMI:    Returns the state of the device at a layer and NO
        % inputRead                @MMI:    Reads a connected sensor at a layer, NO, type and mode in percentage
        % inputReadSI                       Reads a connected sensor at a layer, NO, type and mode in SI units
        %
        % outputStop            Stops motor at a layer, NOS and brake
        % outputStopAll         Stops all the motors
        % outputPower           Sets motor output power at a layer, NOS and speed
        % outputSpeed     @MMI: Sets motor output speed at a layer, NOS and speed
        % outputStart           Starts motor at a layer, NOS and speed
        % outputTest            Returns the state of the motor at a layer and NOS
        % outputStepSpeed       Moves a motor to set position with layer, NOS, speed, 
        %                       ramp up angle, constant angle, ramp down angle and brake
        % outputStepPower @MMI: Moves a motor to set position with layer, NOS, power,
        %                       ramp up angle, constant angle, ramp down angle and brake
        % outputTimeSpeed @MMI: Moves a motor for set time at a layer, NOS, speed,
        %                       ramp up time, constant time, ramp down time and brake
        % outputTimePower @MMI: Moves a motor for set time at a layer, NOS, power,
        %                       ramp up time, constant time, ramp down time and brake
        % outputStepSync  @MMI: Moves two motors synchronized at a layer, NOS,
        %                       power, turn ratio, tacho limit, and brake 
        % outputTimeSync  @MMI: Moves two motors synchronized at a layer, NOS,
        %                       power, turn ratio, time limit, and brake 
        % outputClrCount        Clears a motor tachometer at a  layer and NOS
        % outputGetCount        Returns the tachometer at a layer and NO
        % outputReset     @MMI: 
        % outputRead      @MMI: 
        % outputPolarity  @MMI: Sets a motor's polarity ('rotational direction')
        % outputReady     @MMI: Halts the execution of commands on Brick until given
        %                       motors have stopped
        %
        %
        % comTest  @MMI:        Returns state of communication adapter of device.
        % comReady @MMI:        Halts the execution of commands of Brick until
        %                       communication adapter is ready
        % comGetBrickName       Returns the name of the brick
        % comSetBrickName       Sets the name of the brick
        % comGetMACAddress@MMI: Returns the MAC-address of the brick
        % comGetBTID      @MMI: Returns BT-address information
        %
        % mailBoxWrite          Writes a mailbox message from the brick to another device
        % fileUpload            Uploads a file to the brick
        % fileDownload          Downloads a file from the brick
        % listFiles             Lists files on the brick from a directory  
        % createDir             Creates a directory on the brick
        % deleteFile            Deletes a file from the brick
        % writeMailBox          Writes a mailbox message to the brick
        % readMailBox           Reads a mailbox message sent from the brick
        %
        %
        % threeToneByteCode     Generates the bytecode for the playThreeTone function 
        %
        % Example::
        %           b = Brick('ioType','usb')
        %           b = Brick('ioType','wifi','wfAddr','192.168.1.104','wfPort',5555,'wfSN','0016533dbaf5')
        %           b = Brick('ioType','bt','serPort','/dev/rfcomm0')
    
        properties
            % Debug 
            debug;
        end
        
        properties (Dependent)
            % Time-out period in seconds (if 0, no time-out)
            timeOut; 
        end
        
        properties (SetAccess = private)
            % IO connection type
            ioType;
        end
        
        properties (Hidden, Access = private)
            % Connection handle
            conn; 
        end
        
        methods
            %% Constructor, Destructor, Setter...
            function commInterface = CommunicationInterface(varargin) 
                 % CommunicationInterface.CommunicationInterface Create a CommunicationInterface object
                 %
                 % b = CommunicationInterface(...) is an object that represents a connection
                 % interface to a Lego Mindstorms EV3 brick.
                 %
                 % Notes::
                 % - Can connect through: usbBrickIO, btBrickIO
                 % - For USB connection:
                 %      b = CommunicationInterface('usb')
                 % - For BT connection on linux/mac:
                 %      b = CommunicationInterface('bt','serPort','/dev/rfcomm0')
                 % - For BT conenction on windows:
                 %      b = CommunicationInterface('bt','backend','instrumentControl,'channel',1,'deviceName','EV3')
                 
                 props = commInterface.evaluateProperties(varargin{:});
                 commInterface.ioType = props.ioType;
                 commInterface.debug = props.debug;
                 
                 try
                     if(strcmp(commInterface.ioType,'usb')) % USB
                        commInterface.conn = usbBrickIO(props.debug);
                     elseif(strcmp(commInterface.ioType,'bt')) % Bluetooth
                        if(strcmp(props.backend, 'serial'))
                           commInterface.conn = btBrickIO('debug', props.debug, 'serPort', props.serPort);
                        else
                           commInterface.conn = btBrickIO('debug', props.debug, 'backend', props.backend, 'channel', props.channel, 'deviceName', props.deviceName);
                        end
                     end
                 catch ME
                     commInterface.conn = [];
                     rethrow(ME);
                 end
            end
            
            function delete(brick)
                % Brick.delete Delete the Brick object
                %
                % delete(b) closes the connection to the brick
                
                if isa(brick.conn, 'handle') && isvalid(brick.conn)
                    brick.conn.delete();
                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 set.timeOut(brick, timeOut)
                if ~isnumeric(timeOut) || timeOut < 0
                    error(ID(), 'timeOut-period of USB-handle can only be set to positive numerical values.'); 
                end
                
                brick.conn.timeOut = timeOut;
            end
            function timeOut = get.timeOut(brick)
                timeOut = brick.conn.timeOut; 
            end
            
            function props = evaluateProperties(brick, varargin)
                p = inputParser();
                p.KeepUnmatched = true;
                
                % Set default values
                defaultIOType = 'usb';
                defaultSerPort = '/dev/rfcomm0';
                defaultBTDevice = 'EV3';
                defaultBTChannel = 1;
                if(ispc && license('test', 'instr_control_toolbox'))
                    defaultBackend = 'instrumentControl';
                else
                    defaultBackend = 'serial';
                end
                defaultDebug = false;
                
                % Define anonymous functions that will return whether given value in varargin is valid
                checkIOType = @(x) ismember(x, {'usb', 'bt'});
                checkDebug = @(x) isBool(x);
                checkBackend = @(x) ismember(x, {'serial', 'instrumentControl'});
                
                % Add parameters
                p.addRequired('ioType', checkIOType);
                p.addOptional('serPort', defaultSerPort);
                p.addOptional('debug', defaultDebug, checkDebug);
                p.addOptional('deviceName', defaultBTDevice);
                p.addOptional('channel', defaultBTChannel);
                p.addOptional('backend', defaultBackend, checkBackend);
                
                % Parse input...
                p.parse(varargin{:});
                
                props = p.Results;
            end
            
            %% Commands
            % Methods in this block each correspond to a certain opCode which is implemented in the
            % EV3 firmware -> each method creates one packet and sends it.
            function voltage = uiReadVbatt(brick)
                % Brick.uiReadVbatt Return battery level (voltage)
                % 
                % voltage = uiReadVbatt returns battery level as a voltage. (DATAF)
                %
                % Example::
                %           voltage = b.uiReadVbatt()
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,4,0);
                cmd.opUI_READ_GET_VBATT(0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                voltage = typecast(uint8(msg(6:9)),'single');           
                if brick.debug > 0
                    fprintf('Battery voltage: %.02fV\n', voltage);
                end
            end
            
            function level = uiReadLbatt(brick)
                % Brick.uiReadLbatt Return battery level (percentage)
                % 
                % Brick.uiReadLbatt() returns battery level as a
                % percentage from 0 to 100%. (DATA8)
                %
                % Example::
                %           level = b.uiReadLbatt()
              
                cmd = Command();
                cmd.addHeaderDirectReply(42,1,0);
                cmd.opUI_READ_GET_LBATT(0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                level = msg(6);
                if brick.debug > 0
                    fprintf('Battery level: %d%%\n', level);
                end
            end
            
            % Implemented @ MMI
            function state = soundTest(brick)
                % Brick.soundTest Test speaker
                %
                % Brick.soundTest tests, if a sound file or tone is beeing
                % played back.
                %
                % Notes::
                % - state is 0 when ready and 1 when busy (playing tone or
                %   sound file). (DATA8)
                %
                % Example::
                %           b.soundTest()
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,1,0);
                cmd.opSOUND_TEST(0);
                cmd.addLength();
                brick.send(cmd);
                % receive the state
                reply = brick.receive()';
                msg = reply.msg;
                % speaker state is the 6th byte
                state = msg(6);    
            end
            
            % Implemented @ MMI
            function soundReady(brick)
                % Brick.soundReady Wait for speaker
                %
                % Brick.soundReady(layer,nos) halts program until current 
                % sound playback is done by waiting until reply is received.
                %
                % Example::
                %           b.soundReady()
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,0,0);
                cmd.opSOUND_READY();
                cmd.addLength();
                brick.send(cmd);  
                % receive reply 
                brick.waitForReply();           
            end
            
            function soundPlayTone(brick, volume, frequency, duration)  
                % Brick.soundPlayTone Play a tone on the brick
                %
                % Brick.soundPlayTone(volume,frequency,duration) plays a tone at a
                % volume, frequency and duration.
                %
                % Notes::
                % - volume is the tone volume from 0 to 100. (DATA8)
                % - frequency is the tone frequency in Hz from 250 - 10000. (DATA16)
                % - duration is the tone duration in ms. (DATA16)
                %
                % Example:: 
                %           b.soundPlayTone(5,400,500)
    
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opSOUND_TONE(volume,frequency,duration);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function soundStopTone(brick)
                % Brick.soundStopTone Stop current sound playback
                %
                % Brick.soundStopTone() stops current sound playbacks.
                %
                % Example::
                %           b.soundStopTone()
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opSOUND_BREAK;
                cmd.addLength();
                brick.send(cmd);            
            end
              
            % Implemented @ MMI
            function types = inputDeviceList(brick)
                % Brick.inputDeviceList Get an array of sensor types 
                %
                % Brick.inputDeviceList() returns an array of sensor types on 
                % each sensor port.
                %
                % Notes::
                % - types is the 1x4-array of sensor types 
                %
                % Example::
                %           types = b.inputDeviceList();
                %
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,5,0);
                cmd.opINPUT_DEVICE_LIST(4,0,4);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the type array
                types = [msg(6), msg(7), msg(8), msg(9)];
            end
            
            function name = inputDeviceGetName(brick,layer,no)
                % Brick.inputDeviceGetName Get the input device name
                %
                % Brick.inputDeviceGetName(layer,no) returns the name of the
                % device connected.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or port
                %   number minus 1.
                % - name is the device's name (string)
                % 
                % Example::
                %           name = b.inputDeviceGetName(0,SensorPort.Sensor1)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,12,0);
                cmd.opINPUT_DEVICE_GET_NAME(layer,no,12,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the device name
                name = sscanf(char(msg(6:end)),'%s');
            end
            
            % Implemented @ MMI
            function [type, mode] = inputDeviceGetTypeMode(brick,layer,no)
                % Brick.inputDeviceGetTypeMode Get the input device's type and
                % mode
                %
                % Brick.inputDeviceGetTypeMode(layer,no) returns the input device's
                % type and mode, coded as in Device.m, at a layer and NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or port
                %   number minus 1.
                % - type,mode are the type and current mode of the device (each DATA8)
                %   -> refer to typedata.rcf for more information
                %
                % Example::
                %          [type,mode] = b.inputDeviceTypeMode(0,SensorPort.Sensor1)
                cmd = Command();
                cmd.addHeaderDirectReply(42,2,0);
                cmd.opINPUT_DEVICE_GET_TYPEMODE(layer,no,0,1);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the type and mode
                type = msg(6);
                mode = msg(7);
            end
            
            % Implemented @ MMI
            function inputDeviceSetTypeMode(brick,oldType,oldMode,newType,newMode)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,0,0);
                cmd.opINPUT_DEVICE_SET_TYPEMODE(oldType,oldMode,newType,newMode);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function mode = inputDeviceGetModeName(brick,layer,no,mode)
                % Brick.inputDeviceGetModeName Get the input device mode name
                %
                % Brick.inputDeviceGetModeName(layer,no,mode) returns the name of the
                % device's mode. (If expected sensor is connected, think of this as
                % an enum to string conversion.)
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or port
                %   number minus 1.
                % - mode is the name of the current sensor mode (string)
                %
                % Example::
                %           mode = b.inputDeviceGetModeName(0,SensorPort.Sensor1,Device.Bumps)
                %               -> mode = BUMPS afterwards, if touch sensor is connected.
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,12,0);
                cmd.opINPUT_DEVICE_GET_MODENAME(layer,no,mode,12,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the mode name
                mode = sscanf(char(msg(6:end)),'%s');
            end
            
            % Implemented @ MMI
            function conn = inputDeviceGetConnection(brick,layer,no)
                % Brick.inputDeviceGetConnection Get the input device
                % connection type
                %
                % Brick.inputDeviceGetConnection(layer,no) returns the connection
                % type at a layer and NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or port
                %   number minus 1.
                % - connection is the connection type of the sensor (DATA8)
                %   -> compare with Device.CONN_[..]
                %
                % Example::
                %           conn = b.inputDeviceGetConnection(0,SensorPort.Sensor1)
                %               -> conn = Device.CONN_NONE (if no sensor is detected at Port1)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,1,0);
                cmd.opINPUT_DEVICE_GET_CONNECTION(layer,no,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the connection type
                conn = msg(6);
            end
            
            % Implemented @ MMI
            function [min,max] = inputDeviceGetMinMax(brick,layer,no)
                % Brick.inputDeviceGetMinMax Get min&max SI or pct values.
                %
                % Brick.inputDeviceGetMinMax(layer,no) returns the min and
                % max SI or pct values at a layer and NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or port
                %   number minus 1.
                % - min,max are the minimum/maximum SI/pct values of a sensor (each DATAF)
                %
                % Example::
                %           [min,max] = brick.inputDeviceGetMinMax(0,SensorPort.Sensor1);
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,8,0);
                cmd.opINPUT_DEVICE_GET_MINMAX(layer,no,0,4);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the values
                min = typecast(uint8(msg(6:9)),'single');
                max = typecast(uint8(msg(10:13)),'single');
                
                if brick.debug > 0
                     fprintf('Minimum: %.02f\n', min);
                     fprintf('Maximum: %.02f\n', max);
                end
            end
            
            % Implemented @ MMI
            function changes = inputDeviceGetChanges(brick,layer,no)
                % Brick.inputDeviceGetChanges Get changes since last clear.
                %
                % Brick.inputDeviceGetChanges (layer,no) returns positive changes(=button releases) at a layer and NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or port
                %   number minus 1.
                % - changes are the button releases since last clear. (DATAF)
                %
                % Example::
                %       changes = brick.inputDeviceGetChanges(0,SensorPort.Sensor1)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,4,0);
                cmd.opINPUT_DEVICE_GET_CHANGES(layer,no,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the changes
                changes = typecast(uint8(msg(6:9)),'single');
                if brick.debug > 0
                     fprintf('Changes (button releases) since clear: %.02f\n', changes);
                end
            end
            
            % Implemented @ MMI
            function [datasets,format,modes,view] = inputDeviceGetFormat(brick,layer,no)
                % Brick.inputDeviceGetFormat Get format of sensor data.
                %
                % Brick.inputDeviceGetFormat (layer,no) returns no of
                % datasets, format, no of modes, no of 'visible' modes
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or port
                %   number minus 1.
                % - datasets equals no of returned datasets (usually 1). (DATA8)
                % - format equals format of returned data (0:8 Bit, 1:16 Bit,
                %   2: 32 Bit, 3: 32 Bit Float). (DATA8)
                % - modes equals no of sensor modes at NO (refer to types.html,
                %   typedata.rcf). (DATA8)
                % - view equals no of sensor modes visible within port view
                %   app on brick. (DATA8)
                %
                % Example::
                %       changes = brick.inputDeviceGetFormat(0,SensorPort.Sensor1)            
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,4,0);
                cmd.opINPUT_DEVICE_GET_FORMAT(layer,no,0,1,2,3);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the data
                datasets = msg(6);
                format = msg(7);
                modes = msg(8);
                view = msg(9);
            end
            
            % Implemented @ MMI
            function bumps = inputDeviceGetBumps(brick,layer,no)
                % Brick.inputDeviceGetBumps Get bumps since last clear.
                %
                % Brick.inputDeviceGetBumps (layer,no) returns bumps (button presses, = 'negative 
                % changes') at a layer and NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or port
                % number minus 1.
                % - bumps are the button presses since last clear. (DATAF)
                %
                % Example::
                %       changes = brick.inputDeviceGetBumps(0,SensorPort.Sensor1)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,4,0);
                cmd.opINPUT_DEVICE_GET_BUMPS(layer,no,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the bumps
                bumps = typecast(uint8(msg(6:9)),'single');
                if brick.debug > 0
                     fprintf('Bumps (button presses) since clear: %.02f\n', bumps);
                end
            end
            
            function name = inputDeviceSymbol(brick,layer,no)
                % Brick.inputDeviceSymbol Get the input device symbol
                %
                % Brick.inputDeviceSymbol(layer,no) returns the symbol used for
                % the device in its current mode.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or sensor port
                % number minus 1.
                % - name is the symbol of the sensor at NO (refer to types.html,
                %   typedata.rcf)
                %
                % Example::
                %           name = b.inputDeviceSymbol(0,SensorPort.Sensor1)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,5,0);
                cmd.opINPUT_DEVICE_GET_SYMBOL(layer,no,5,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the symbol name
                name = sscanf(char(msg(6:end)),'%s');
            end
            
            % Implemented @ MMI
            function inputDeviceClrChanges(brick,layer,no)
                % Brick.inputDeviceClrChanges Clear changes.
                %
                % Brick.inputDeviceClrChanges(layer,no) clear changes(&bumps)
                % at a layer and NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or sensor port
                % number minus 1.
                %
                % Example::
                %           name = b.inputDeviceClrChanges(0,SensorPort.Sensor1)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opINPUT_DEVICE_CLR_CHANGES(layer,no);
                cmd.addLength();
                brick.send(cmd);
            end
            
            function inputDeviceClrAll(brick,layer)
                % Brick.inputDeviceClrAll Clear the sensors
                %
                % Brick.inputDeviceClrAll(layer) clears the sensors connected
                % to layer. (@MMI: and tacho counts!)
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                %
                % Example::
                %           name = b.inputDeviceClrAll(0)
                
                cmd = Command();
    %             cmd.addHeaderDirectReply(42,5,0);
                cmd.addHeaderDirect(42,0,0);
                cmd.opINPUT_DEVICE_CLR_ALL(layer);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function inputReady(brick,layer,no)
                % Brick.inputReady Wait for device
                %
                % Brick.inputReady(layer,nos) halts program until device at no
                % is ready by waiting until reply is received
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or sensor port
                % number minus 1.            
                %
                % Example::
                %           b.inputReady(0,SensorPort.Sensor1)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,0,0);
                cmd.opINPUT_READY(layer,no);
                cmd.addLength();
                brick.send(cmd);
                % receive reply
                brick.waitForReply();            
            end
            
            % Implemented @ MMI
            function state = inputTest(brick,layer,no)
                % Brick.inputTest Test a device
                %
                % Brick.inputTest(layer,nos) tests a device state at a layer and
                % NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or sensor port
                % number minus 1.   
                % - state is 0 when ready and 1 when busy. (e.g. changing mode) (DATA8)s
                %
                % Example::
                %           state = b.inputTest(0,SensorPort.Sensor1)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,1,0);
                cmd.opINPUT_TEST(layer,no,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the state
                reply = brick.receive()';
                msg = reply.msg;
                % device state is the 6th (final) byte
                state = msg(6);
            end
            
            % Implemented @ MMI
            function reading = inputRead(brick,layer,no,mode)
                % Brick.inputRead Input read in percentage
                % 
                % reading = Brick.inputRead(layer,no,mode) reads a 
                % connected sensor at a layer, NO and mode in percentage of max
                % values. 
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or sensor port
                % number minus 1.
                % - mode is the sensor mode from types.html. (-1=don't change)
                % - reading is the read value in pct (DATA8)
                %
                % Example::
                %            reading = b.inputRead(0,SensorPort.Sensor1,Device.USDistCM)
                %            reading = b.inputRead(0,SensorPort.Sensor1,Device.ColReflect)
                %                 -> returns the same value as b.inputReadSI..
                %            reading = b.inputRead(0,SensorPort.Sensor1,Device.Bumps)
                %                 -> returns seemingly pointless values (as
                %                 expected)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,1,0);
                cmd.opINPUT_READ(layer,no,0,mode,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                reading = msg(6);
    %             if brick.debug > 0
    %                  fprintf('Sensor reading: %.02f\n', reading);
    %             end
            end
            
            function reading = inputReadSI(brick,layer,no,mode)
                % Brick.inputReadSI Input read in SI units
                % 
                % reading = Brick.inputReadSI(layer,no,mode) reads a 
                % connected sensor at a layer, NO and mode in SI units.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or sensor port
                % number minus 1.
                % - mode is the sensor mode from types.html. (-1=don't change)
                % - reading is the read value in SI units. (DATAF)
                %
                % Example::
                %            reading = b.inputReadSI(0,SensorPort.Sensor1,Device.USDistCM)
                %            reading = b.inputReadSI(0,SensorPort.Sensor1,Device.Pushed)
               
                cmd = Command();
                cmd.addHeaderDirectReply(42,4,0);
                cmd.opINPUT_READSI(layer,no,0,mode,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                reading = typecast(uint8(msg(6:9)),'single');
    %             if brick.debug > 0
    %                  fprintf('Sensor reading: %.02f\n', reading);
    %             end
            end
            
            function reading = inputReadSIType(brick,layer,no,type,mode)
                % Brick.inputReadSI Input read in SI units
                % 
                % reading = Brick.inputReadSI(layer,no,mode) reads a 
                % connected sensor at a layer, NO and mode in SI units.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is the output port number from [0..3] or sensor port
                % number minus 1.
                % - mode is the sensor mode from types.html. (-1=don't change)
                % - reading is the read value in SI units. (DATAF)
                %
                % Example::
                %            reading = b.inputReadSI(0,SensorPort.Sensor1,Device.USDistCM)
                %            reading = b.inputReadSI(0,SensorPort.Sensor1,Device.Pushed)
               
                cmd = Command();
                cmd.addHeaderDirectReply(42,4,0);
                cmd.opINPUT_READSI(layer,no,type,mode,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                reading = typecast(uint8(msg(6:9)),'single');
    %             if brick.debug > 0
    %                  fprintf('Sensor reading: %.02f\n', reading);
    %             end
            end
            
            function outputStop(brick,layer,nos,brake)
                % Brick.outputPower Stops a motor
                %
                % Brick.outputPower(layer,nos,brake) stops motor at a layer 
                % NOS and brake.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                % - brake is [0..1] (0=Coast,  1=Brake).
                %
                % Example::
                %           b.outputStop(0,MotorBitfield.MotorA,BrakeMode.Brake)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_STOP(layer,nos,brake)
                cmd.addLength();
                brick.send(cmd);
            end
            
            function outputPower(brick,layer,nos,power)
                % Brick.outputPower Set the motor output power
                % 
                % Brick.outputPower(layer,nos,power) sets motor output power at
                % a layer, NOS and power.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                % - power is the output power with [+-0..100%] range.
                %
                % Example::
                %           b.outputPower(0,MotorBitfield.MotorA,50)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_POWER(layer,nos,power);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function outputSpeed(brick,layer,nos,speed)
                % Brick.outputSpeed Set the motor output speed
                % 
                % Brick.outputSpeed(layer,nos,speed) sets motor output speed at
                % a layer, NOS and speed.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                % - speed is the output speed with [+-0..100%] range.
                % Example::
                %           b.outputSpeed(0,MotorBitfield.MotorA,50)            
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_SPEED(layer,nos,speed);
                cmd.addLength();
                brick.send(cmd);
            end
            
            function outputStart(brick,layer,nos)
                % Brick.outputStart Starts a motor
                %
                % Brick.outputStart(layer,nos) starts a motor at a layer and
                % NOS.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                %
                % Example::
                %           b.outputStart(0,MotorBitfield.MotorA)
              
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_START(layer,nos);
                cmd.addLength();
                brick.send(cmd);
            end 
            
            function state = outputTest(brick,layer,nos)
                % Brick.outputTest Test a motor
                %
                % Brick.outputTest(layer,nos) tests a motor state at a layer and
                % NOS.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                % - state is 0 when ready and 1 when busy. (DATA8)
                %
                % Example::
                %           state = b.outputTest(0,MotorBitfield.MotorA)
              
                cmd = Command();
                cmd.addHeaderDirectReply(42,1,0);
                cmd.opOUTPUT_TEST(layer,nos,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % motor state is the final byte
                state = msg(end);
            end
            
            % Implemented @ MMI
            function outputReady(brick,layer,nos)
                % Brick.outputReady Wait for motor
                %
                % Brick.outputReady(layer,nos) halts program until motor at nos
                % is ready by waiting until reply is received.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                %
                % Example::
                %           b.outputReady(0,MotorBitfield.MotorA)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,0,0);
                cmd.opOUTPUT_READY(layer,nos);
                cmd.addLength();
                brick.send(cmd);
                % receive reply
                brick.waitForReply();
            end
            
            % Implemented @ MMI
            function outputPolarity(brick, layer, nos, pol)
                % Brick.outputPolarity Set a motor's polarity
                %
                % Brick.outputPolarity(layer,nos,pol) sets a motor's polarity
                % to pol
                %
                % Notes::
                % - 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
                %   backwards, 1 makes the motor run forwards, 0 makes the motor
                %   run the opposite direction when starting next time
                %
                % Example::
                %           b.outputPolarity(0, MotorBitfield.MotorA, -1);
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_POLARITY(layer,nos,pol);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function outputStepPower(brick,layer,nos,power,step1,step2,step3,brake)
                % Brick.outputStepPower Output a step power 
                %
                % Brick.outputStepPower(layer,nos,power,step1,step2,step3,brake)
                % moves a motor to set position with layer, NOS, power, ramp up
                % angle, constant angle, ramp down angle and brake.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                % - power is the output power with [+-0..100%] range.
                % - step1 is the steps used to ramp up.
                % - step2 is the steps used for constant speed.
                % - step3 is the steps used for ramp down.
                % - brake is [0..1] (0=Coast,  1=Brake).
                %
                % Example::
                %           b.outputStepPower(0,MotorBitfield.MotorA,50,50,360,50,BrakeMode.Coast)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_STEP_POWER(layer,nos,power,step1,step2,step3,brake);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function outputTimePower(brick,layer,nos,power,step1,step2,step3,brake)
                % Brick.outputTimePower Output a time power 
                %
                % Brick.outputTimePower(layer,nos,power,step1,step2,step3,brake)
                % moves a motor for set time with layer, NOS, power, ramp up
                % angle, constant angle, ramp down angle and brake.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                % - power is the output power with [+-0..100%] range.
                % - step1 is the time in ms used for ramp up.
                % - step2 is the time in ms used for constant speed.
                % - step3 is the time in ms used for ramp down.
                % - brake is [0..1] (0=Coast,  1=Brake).
                %
                % Example::
                %           b.outputTimePower(0,MotorBitfield.MotorA,50,50,360,50,BrakeMode.Coast)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_TIME_POWER(layer,nos,power,step1,step2,step3,brake);
                cmd.addLength();
                brick.send(cmd);
            end
            
            function outputStepSpeed(brick,layer,nos,speed,step1,step2,step3,brake)
                % Brick.outputStepSpeed Output a step speed 
                %
                % Brick.outputStepSpeed(layer,nos,speed,step1,step2,step3,brake)
                % moves a motor to set position with layer, NOS, speed, ramp up
                % angle, constant angle, ramp down angle and brake.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                % - speed is the output speed with [+-0..100%] range.
                % - step1 is the steps used to ramp up.
                % - step2 is the steps used for constant speed.
                % - step3 is the steps used for ramp down.
                % - brake is [0..1] (0=Coast,  1=Brake).
                %
                % Example::
                %           b.outputStepSpeed(0,MotorBitfield.MotorA,50,50,360,50,BrakeMode.Coast)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_STEP_SPEED(layer,nos,speed,step1,step2,step3,brake);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function outputTimeSpeed(brick,layer,nos,speed,step1,step2,step3,brake)
                % Brick.outputTimeSpeed Output a time speed 
                %
                % Brick.outputTimeSpeed(layer,nos,speed,step1,step2,step3,brake)
                % moves a motor for set time with layer, NOS, speed, ramp up
                % angle, constant angle, ramp down angle and brake.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                % - speed is the output speed with [+-0..100%] range.
                % - step1 is the time in ms used for ramp up.
                % - step2 is the time in ms used for constant speed.
                % - step3 is the time in ms used for ramp down.
                % - brake is [0..1] (0=Coast,  1=Brake).
                %
                % Example::
                %           b.outputTimeSpeed(0,MotorBitfield.MotorA,50,50,360,50,BrakeMode.Coast)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_TIME_SPEED(layer,nos,speed,step1,step2,step3,brake);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function outputStepSync(brick,layer,nos,power,turn,step,brake)
                % Brick.outputStepSync Output a synced step power
                %
                % Brick.outputStepSync(brick,layer,nos,power,turn,step,brake) 
                % moves two motors synchronized to set position with layer,
                % NOS, power, turn ratio, tacho limit and brake
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                %   -> only works with output to multiple nos: e.g. 0x01+0x02
                % - power is the output power with [+-0..100%] range.
                % - (Excerpt of c_output.c): Turn ratio is how tight you turn and to what direction 
                %                            you turn (in [+-200]).
                %   -> 0 value is moving straight forward
                %   -> Negative values turns to the left
                %   -> Positive values turns to the right
                %   -> Value -100 stops the left motor
                %   -> Value +100 stops the right motor
                %   -> Values less than -100 makes the left motor run the opposite
                %       direction of the right motor (Spin)
                %   -> Values greater than +100 makes the right motor run the opposite
                %       direction of the left motor (Spin) (/end excerpt)
                % - step is the tacho limit (read on 'faster' motor) 0=Inf
                % - brake is [0..1] (0=Coast,  1=Brake).
                %
                % Example::
                %           b.outputStepSync(0,MotorBitfield.MotorA+MotorBitfield.MotorB,50,50,360,BrakeMode.Coast)           
               
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_STEP_SYNC(layer,nos,power,turn,step,brake);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function outputTimeSync(brick,layer,nos,power,turn,time,brake)
                % Brick.outputTimeSync Output a synced time power
                %
                % Brick.outputTimeSync(brick,layer,nos,power,turn,time,brake) 
                % moves two motors synchronized for set time with layer,
                % NOS, power, turn ratio, time limit and brake
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                %   -> output to multiple nos: e.g. 0x01+0x02
                % - power is the output power with [+-0..100%] range.
                % - (Excerpt of c_output.c): Turn ratio is how tight you turn and to what direction you turn
                %   -> 0 value is moving straight forward
                %   -> Negative values turns to the left
                %   -> Positive values turns to the right
                %   -> Value -100 stops the left motor
                %   -> Value +100 stops the right motor
                %   -> Values less than -100 makes the left motor run the opposite
                %       direction of the right motor (Spin)
                %   -> Values greater than +100 makes the right motor run the opposite
                %       direction of the left motor (Spin) (/end excerpt)
                % - time is the time limit in milliseconds, 0=Inf
                % - brake is [0..1] (0=Coast,  1=Brake).
                %
                % Example::
                %           b.outputTimeSync(0,MotorBitfield.MotorA+MotorBitfield.MotorB,50,50,360,BrakeMode.Coast)   
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_TIME_SYNC(layer,nos,power,turn,time,brake);
                cmd.addLength();
                brick.send(cmd);
            end    
            
            function outputClrCount(brick,layer,nos)
                % Brick.outputClrCount Clear output count
                % 
                % Brick.outputClrCount(layer,nos) clears a motor tachometer at a
                % layer and NOS.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                %
                % Example::
                %            b.outputClrCount(0,MotorBitfield.MotorA)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_CLR_COUNT(layer,nos);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Implemented @ MMI
            function outputReset(brick,layer,nos)
                % Brick.outputReset Resets internal tacho count
                %
                % Brick.outputReset(layer,nos) clears a second tachometer which is used internally
                % for, e.g., stopping with a tacholimit.
                %
                % Notes::
                % - layer is the usb chain layer (usuallly 0).
                % - NOS is a bit field representing output 1 to 4 (0x01, 0x02, 0x04, 0x08).
                %
                % Example::
                %             b.outputReset(0,MotorBitfield.MotorA)
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opOUTPUT_RESET(layer,nos);
                cmd.addLength();
                brick.send(cmd);
            end
            
            % Bugfix @ MMI
            function tacho = outputGetCount(brick,layer,no)
                % Brick.outputGetCount(layer,no) Get output count
                % 
                % tacho = Brick.outputGetCount(layer,no) returns the tachometer 
                % at a layer and NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is output motor number [0...3] ( != NOS)
                %   -> use MotorPort.MotorA
                % - tacho is the returned tachometer value. (DATA32)
                %
                % Example::
                %           tacho = b.outputGetCount(0,MotorPort.MotorA)
    
    
                cmd = Command();
                cmd.addHeaderDirectReply(42,4,0);
                cmd.opOUTPUT_GET_COUNT(layer,no,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                tacho = typecast(uint8(msg(6:9)),'int32');
    %             if brick.debug > 0
    %                 fprintf('Tacho: %d degrees\n', tacho);
    %             end
            end
            
            % Implemented @ MMI 
            % Still buggy (WIP)
            function [speed, tacho] = outputRead(brick,layer,no)
                % Brick.outputRead(layer,no) Get tacho count and speed.
                % 
                % [speed, tacho] = Brick.outputRead(layer,no) returns the tachometer 
                % and speed at a layer and NO.
                %
                % Notes::
                % - layer is the usb chain layer (usually 0).
                % - NO is output motor number [0...3] ( != NOS)
                % - tacho is the returned tachometer value. (DATA32)
                % - speed is the returned speed value. (DATA8)
                % 
                % TODO:: 
                % - returned tacho value is wrong/does not work.
                % - returned speed value is OK until about speed=82
                %   -> calling this function while motor is faster seems to even screw the motor
                %       itself: it won't get any faster after current speed.
                %
                % Example::
                %           [speed,tacho] = b.outputRead(0,MotorPort.MotorA)
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,5,0); 
                cmd.opOUTPUT_READ(layer,no,0,4); %%
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % Current thoughts: the bug could be in the firmware (DUNDUNDUN).
                % The docu states: "Offset in the response buffer (global variables) must be
                % aligned (float/32bits first and 8 bits last)." [/lms2012/doc/html/directcommands.html]
                %-> problem: the firmware
                % implementation of this function puts speed (DATA8) first and tacho (DATA32) second.
                % Furthermore, the speed is correct only if I, following the rule,
                % do what I do at '%%': I tell the brick that I need a DATA32 and THEN a DATA8.
                % This would fulfill the stated rule, but would only work if the
                % firmware would put tacho first and speed second.
                % If I tell the brick that I need a DATA8 and THEN a DATA32, ignoring the rule
                % and going with the firmware version, I get an error in the response. (error flag)
                %speed = msg(6);
                %tacho = typecast(uint8(msg(7:10)),'int32');
                tacho = typecast(uint8(msg(6:9)),'int32');
                try
                    speed = msg(10);
                catch
                    speed = 0;  % Sometimes, the response packet lacks the 10th byte...?!
                end
    %             if brick.debug > 0
    %                 fprintf('Speed: %d\n', speed);
    %                 fprintf('buggy Tacho: %d degrees\n', tacho);
    %             end
            end
            
            % Implemented @ MMI
            function state = comTest(brick,hardware,name)
                % Brick.comTest Get state of conn devices
                %
                % Brick.comTest(hardware,name) returns state of communication
                % adapter of device.
                %
                % Notes::
                % - hardware is the communication adapter to be tested. 
                %   -> 1: USB, 2: BT, 3: Wifi
                % - name is the name of the device ('0': own adapter) (?)
                % - state is 0 when ready and 1 when busy. (DATA8)
                %
                % Example::
                %           state = b.comTest(1, '0');
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,1,0);
                cmd.opCOM_TEST(hardware,name,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the state
                reply = brick.receive()';
                msg = reply.msg;
                % return the state
                state = msg(end);
            end
            
            % Implemented @ MMI
            function comReady(brick,hardware,name)
                % Brick.comReady Wait for adapter
                %
                % Brick.comReady(layer,nos) halts program until
                % communication adapter of device is ready.
                %
                % Notes::
                % - hardware is the communication adapter to be tested. 
                %   -> 1: USB, 2: BT, 3: Wifi
                % - name is the name of the device ('0': own adapter) (?)
                %
                % Example::
                %           b.comReady(2, '0');
                
                cmd = Command();
                cmd.addHeaderDirectReply(42,0,0);
                cmd.opCOM_READY(hardware,name);
                cmd.addLength();
                brick.send(cmd);
                % receive reply
                brick.waitForReply();
            end
            
            function name = comGetBrickName(brick)
                % Brick.comGetBrickName Get brick name
                %
                % Brick.comGetBrickName() returns the name of the brick.
                %
                % Example::
                %           name = b.comGetBrickName()
              
                cmd = Command();
                cmd.addHeaderDirectReply(42,10,0);
                cmd.opCOMGET_GET_BRICKNAME(10,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the brick name
                name = sscanf(char(msg(6:end)),'%s');
            end
            
            function comSetBrickName(brick,name)
                % Brick.comSetBrickName Set brick name
                %
                % Brick.comSetBrickName(name) sets the name of the brick.
                %
                % Example::
                %           b.comSetBrickName('EV3')
              
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opCOMSET_SET_BRICKNAME(name);
                cmd.addLength();
                brick.send(cmd);
            end
            
            function mac = comGetMACAddress(brick)
                % Brick.comGetMACAddress Get brick MAC address
                %
                % Brick.comGetMACAddress() returns the name of the brick.
                %
                % Example::
                %           mac = b.comGetMACAddress()
              
                cmd = Command();
                cmd.addHeaderDirectReply(42,36,0);
                cmd.opCOMGET_NETWORK(3,36,0,8,20);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the brick name
                mac = sscanf(char(msg(4:10)),'%s');
            end
            
            function id = comGetBTID(brick)
                % Brick.comGetBTID Get brick BT address
                %
                % Brick.comGetBTID() returns the BT address
                %
                % Example::
                %           mac = b.comGetBTID()
              
                cmd = Command();
                cmd.addHeaderDirectReply(42,12,0);
                cmd.opCOMGET_ID(2,12,0);
                cmd.addLength();
                brick.send(cmd);
                % receive the command
                reply = brick.receive()';
                msg = reply.msg;
                % return the brick name
                id = sscanf(char(msg(6:end)),'%s');
            end
            
            function mailBoxWrite(brick,brickname,boxname,type,msg)
                % Brick.mailBoxWrite Write a mailbox message
                %
                % Brick.mailBoxWrite(brickname,boxname,type,msg) writes a
                % mailbox message from the brick to a remote device.
                %
                % Notes::
                % - brickname is the name of the remote device.
                % - boxname is the name of the receiving mailbox.
                % - type is the sent message type being either 'text',
                % 'numeric' or 'logic'.
                % - msg is the message to be sent.
                %
                % Example::
                %           b.mailBoxWrite('T500','abc','logic',1)
                %           b.mailBoxWrite('T500','abc','numeric',4.24)
                %           b.mailBoxWrite('T500','abc','text','hello!')
                
                cmd = Command();
                cmd.addHeaderDirect(42,0,0);
                cmd.opMAILBOX_WRITE(brickname,boxname,type,msg);
                cmd.addLength();
                brick.send(cmd);
            end      
    
            function fileUpload(brick,filename,dest)
                % Brick.fileUpload Upload a file to the brick
                %
                % Brick.fileUpload(filename,dest) upload a file from the PC to
                % the brick.
                %
                % Notes::
                % - filename is the local PC file name for upload.
                % - dest is the remote destination on the brick relative to the
                % '/home/root/lms2012/sys' directory. Directories are created
                % in the path if they are not present.
                %
                % Example::
                %           b.fileUpload('prg.rbf','../apps/tst/tst.rbf')
                
                fid = fopen(filename,'r');
                % read in the file in and convert to uint8
                input = fread(fid,inf,'uint8=>uint8');
                fclose(fid); 
                % begin upload
                cmd = Command();
                cmd.addHeaderSystemReply(10);
                cmd.BEGIN_DOWNLOAD(length(input),dest);
                cmd.addLength();
                brick.send(cmd);
                % receive the sent response
                reply = brick.receive()';
                rmsg = reply.msg;
                handle = rmsg(end);
                pause(1)
                % send the file
                cmd.clear();
                cmd.addHeaderSystemReply(11);
                cmd.CONTINUE_DOWNLOAD(handle,input);
                cmd.addLength();
                brick.send(cmd);
                % receive the sent response
                reply = brick.receive()';
                rmsg = reply.msg;
                % print message 
                fprintf('%s uploaded\n',filename);
            end
            
            function fileDownload(brick,dest,filename,maxlength)
                % Brick.fileDownload Download a file from the brick
                %
                % Brick.fileDownload(dest,filename,maxlength) downloads a file 
                % from the brick to the PC.
                %
                % Notes::
                % - dest is the remote destination on the brick relative to the
                % '/home/root/lms2012/sys' directory.
                % - filename is the local PC file name for download e.g.
                % 'prg.rbf'.
                % - maxlength is the max buffer size used for download.
                % 
                % Example::
                %           b.fileDownload('../apps/tst/tst.rbf','prg.rbf',59)
                
                % begin download
                cmd = Command();
                cmd.addHeaderSystemReply(12);
                cmd.BEGIN_UPLOAD(maxlength,dest);
                cmd.addLength();
                brick.send(cmd);
                % receive the sent response
                reply = brick.receive()';
                rmsg = reply.msg;
                % extract payload
                payload = rmsg(13:end);
                % print to file
                fid = fopen(filename,'w');
                % read in the file in and convert to uint8
                fwrite(fid,payload,'uint8');
                fclose(fid); 
            end
            
            function listFiles(brick,pathname,maxlength)
                % Brick.listFiles List files on the brick
                %
                % Brick.listFiles(brick,pathname,maxlength) list files in a 
                % given directory.
                %
                % Notes::
                % - pathname is the absolute path required for file listing.
                % - maxlength is the max buffer size used for file listing.
                % - If it is a file:
                %   32 chars (hex) of MD5SUM + space + 8 chars (hex) of filesize + space + filename + new line is returned.
                % - If it is a folder:
                %   foldername + / + new line is returned.
                %
                % Example::
                %           b.listFiles('/home/root/lms2012/',100)
                
                cmd = Command();
                cmd.addHeaderSystemReply(13);
                cmd.LIST_FILES(maxlength,pathname);
                cmd.addLength();
                brick.send(cmd);
                reply = brick.receive()';
                rmsg = reply.msg;
                % print
                fprintf('%s',rmsg(13:end));
            end    
            
            function createDir(brick,pathname)
                % Brick.createDir Create a directory on the brick
                % 
                % Brick.createDir(brick,pathname) creates a diretory on the 
                % brick from the given pathname.
                %
                % Notes::
                % - pathname is the absolute path for directory creation.
                %
                % Example::
                %           b.createDir('/home/root/lms2012/newdir')
                
                cmd = Command();
                cmd.addHeaderSystemReply(14);
                cmd.CREATE_DIR(pathname);
                cmd.addLength();
                brick.send(cmd);
                brick.waitForReply();
            end
            
            function deleteFile(brick,pathname)
                % Brick.deleteFile Delete file on the brick
                % 
                % Brick.deleteFile(brick,pathname) deletes a file from the
                % brick with the given pathname. 
                %
                % Notes::
                % - pathname is the absolute file path for deletion.
                % - will only delete files or empty directories.
                %
                % Example::
                %           b.deleteFile('/home/root/lms2012/newdir')
                
                cmd = Command();
                cmd.addHeaderSystemReply(15);
                cmd.DELETE_FILE(pathname);
                cmd.addLength();
                brick.send(cmd);
                brick.waitForReply();
            end
            
            function writeMailBox(brick,title,type,msg)
                % Brick.writeMailBox Write a mailbox message
                %
                % Brick.writeMailBox(title,type,msg) writes a mailbox message to
                % the connected brick.
                %
                % Notes::
                % - title is the message title sent to the brick.
                % - type is the sent message type being either 'text',
                % 'numeric', or 'logic'.
                % - msg is the message to be sent to the brick.
                %
                % Example::
                %           b.writeMailBox('abc','text','hello!')
                
                cmd = Command();
                cmd.addHeaderSystem(16);
                cmd.WRITEMAILBOX(title,type,msg);
                cmd.addLength();
                brick.send(cmd);
            end
            
            function [title,msg] = readMailBox(brick,type)
                % Brick.readMailBox Read a mailbox message
                %
                % [title,msg] = Brick.readMailBox(type) reads a mailbox
                % message sent from the brick.
                %
                % Notes::
                % - type is the sent message type being either 'text',
                % 'numeric' or 'logic'.
                % - title is the message title sent from the brick.
                % - msg is the message sent from the brick.
                %
                % Example::
                %           [title,msg] = b.readMailBox('text')
                
                reply = brick.receive()';
                mailmsg = reply.msg;
                % extract message title (starts at pos 8, pos 7 is the size)
                title = char(mailmsg(8:7+mailmsg(7)));
                % parse message according to type
                switch type
                    case 'text'
                        msg = char(mailmsg(mailmsg(7)+10:end));
                    case 'numeric'
                        msg = typecast(uint8(mailmsg(mailmsg(7)+10:end)),'single');
                    case 'logic'
                        msg = mailmsg(mailmsg(7)+10:end);
                    otherwise
                        fprintf('Error! Type must be ''text'', ''numeric'' or ''logic''.\n');
                        msg = '';
                end
            end
                
            %% Bytecode test
            function threeToneByteCode(brick,filename)
                % Brick.threeToneByteCode Create three tone byte code
                %
                % Brick.threeToneByteCode() generates the byte code for the
                % play three tone function. This is an example of how byte code
                % can be generated as an rbf file which can be uploaded to the brick.
                %
                % Notes::
                % - filename is the name of the file to store the byte code in
                % (the rbf extension is added to the filename automatically)
                %
                % Example::
                %           b.threeToneByteCode('threetone')
                
                cmd = Command();
                % program header
                cmd.PROGRAMHeader(0,1,0);                   % VersionInfo,NumberOfObjects,GlobalBytes
                cmd.VMTHREADHeader(0,0);                    % OffsetToInstructions,LocalBytes
                % commands                                  % VMTHREAD1{
                cmd.opSOUND_TONE(5,440,500);                % opSOUND
                cmd.opSOUND_READY();                        % opSOUND_READY
                cmd.opSOUND_TONE(10,880,500);               % opSOUND
                cmd.opSOUND_READY();                        % opSOUND_READY
                cmd.opSOUND_TONE(15,1320,500);              % opSOUND
                cmd.opSOUND_READY();                        % opSOUND_READY
                cmd.opOBJECT_END;                           % }
                % add file size in header
                cmd.addFileSize;
                % generate the byte code
                cmd.GenerateByteCode(filename);
            end
            
            %% Utility
            % Methods in this block are composed of multiple commands and more logic for convenience
            function drawTest(brick)
                % Brick.drawTest Draw test shapes
                %
                % Brick.drawTest() shows the drawing capabilities of the brick.
                %
                % Example::
                %           b.drawTest()
                
                cmd = Command();
                cmd.addHeaderDirect(42,4,1);
                % save the UI screen
                cmd.opUI_DRAW_STORE(0);
                % change the led pattern
                cmd.opUI_WRITE_LED(Device.LedGreenFlash);
                % clear the screen (top line still remains with remote cmds)
                cmd.opUI_DRAW_FILLWINDOW(0,0,0);
                % draw four pixels
                cmd.opUI_DRAW_PIXEL(vmCodes.vmFGColor,12,15);
                cmd.opUI_DRAW_PIXEL(vmCodes.vmFGColor,12,20);
                cmd.opUI_DRAW_PIXEL(vmCodes.vmFGColor,18,15);
                cmd.opUI_DRAW_PIXEL(vmCodes.vmFGColor,18,20);
                % draw line
                cmd.opUI_DRAW_LINE(vmCodes.vmFGColor,0,25,vmCodes.vmLCDWidth,25);
                cmd.opUI_DRAW_LINE(vmCodes.vmFGColor,15,25,15,127);
                % draw circle
                cmd.opUI_DRAW_CIRCLE(1,40,40,10);
                % draw rectangle
                cmd.opUI_DRAW_RECT(vmCodes.vmFGColor,70,30,20,20);
                % draw filled cricle
                cmd.opUI_DRAW_FILLCIRCLE(vmCodes.vmFGColor,40,70,10);
                % draw filled rectangle
                cmd.opUI_DRAW_FILLRECT(vmCodes.vmFGColor,70,60,20,20);
                % draw inverse rectangle
                cmd.opUI_DRAW_INVERSERECT(30,90,60,20);
                % change font
                cmd.opUI_DRAW_SELECT_FONT(2);
                % draw text
                cmd.opUI_DRAW_TEXT(vmCodes.vmFGColor,100,40,'EV3');
                % change font
                cmd.opUI_DRAW_SELECT_FONT(1);
                % reprint
                cmd.opUI_DRAW_TEXT(vmCodes.vmFGColor,100,70,'EV3');
                % change font
                cmd.opUI_DRAW_SELECT_FONT(0);
                % reprint
                cmd.opUI_DRAW_TEXT(vmCodes.vmFGColor,100,90,'EV3');
                % voltage string
                cmd.opUI_DRAW_TEXT(vmCodes.vmFGColor,100,110,'v =');
                % store voltage
                cmd.opUI_READ_GET_VBATT(0);
                % print the voltage value (global)
                cmd.opUI_DRAW_VALUE(vmCodes.vmFGColor,130,110,0,5,3);
                % update the window
                cmd.opUI_DRAW_UPDATE;
                % 5 second timer (so you can see the changing LED pattern)
                cmd.opTIMER_WAIT(5000,0);
                % wait for timer
                cmd.opTIMER_READY(0);
                % reset the LED
                cmd.opUI_WRITE_LED(Device.LedGreen);
                % return UI screen
                cmd.opUI_DRAW_RESTORE(0);
                % return
                cmd.opUI_DRAW_UPDATE;
                cmd.addLength();
                brick.send(cmd)
            end
            
            function beep(brick,volume,duration)
                % Brick.beep Play a beep on the brick
                %
                % Brick.beep(volume,duration) plays a beep tone with volume and
                % duration.
                %
                % Notes::
                % - volume is the beep volume from 0 to 100, by default 10. (DATA8)
                % - duration is the beep duration in ms, by default 100. (DATA16)
                %
                % Example:: 
                %           b.beep(5,500)
                
                if nargin < 2
                    volume = 10;
                end
                if nargin < 3
                    duration = 100;
                end
                brick.soundPlayTone(volume, 1000, duration);
            end
        end
        
        methods (Access = private)
            function send(brick, cmd)
                % Brick.send Send data to the brick
                %
                % Brick.send(cmd) sends a command to the brick through the
                % connection handle.
                %
                % Notes::
                % - cmd is a command object.
                %
                % Example::
                %           b.send(cmd)
                
                % Send the message through the brickIO write function
                brick.conn.write(cmd.msg);
                
                % (MMI) When spamming the brick with commands, at some point, it will start
                % behaving 'strange'. Sometimes, commands will be executed only with 
                % 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);
                
                % Verbose output
                if brick.debug > 0
                   fprintf('\t(DEBUG) sent:  [ ');
                   for ii=1:length(cmd.msg)
                       fprintf('%s ',dec2hex(cmd.msg(ii)))
                   end
                   fprintf(']\n');
    %                fprintf('\t             (dec):    [ ');
    %                for ii=1:length(cmd.msg)
    %                    fprintf('%d ',cmd.msg(ii))
    %                end
    %                fprintf(']\n\n');
                end
            end
           
            function reply = receive(brick)
                % Brick.receive Receive data from the brick
                %
                % rmsg = Brick.receive() receives data from the brick through
                % the connection handle.
                %
                % Notes::
                %  - If received packet is corrupt, up to five new packets are read (if all are 
                %    corrupt, an error is thrown) 
                %
                % Example::
                %           rmsg = b.receive()
                %
    
                % Read the message through the brickIO read function
                rmsg = brick.conn.read();
                
                % Check if reply is corrupt or error byte is set
                try
                    reply = Command(rmsg);
                catch ME
                    corrupt = 1;
                    if ~isempty(strfind(ME.identifier, 'CorruptPacket'))
                        % Read packet was corrupt - retry
                        %id = [ID(), ':', 'CorruptPacket'];
                        %warning(id, 'Read corrupt packet. Retrying...');
                        if brick.debug
                            fprintf('received (corrupt) (hex):    [ ');
                            for ii=1:length(rmsg)
                                fprintf('%s ',dec2hex(rmsg(ii)))
                            end
                            fprintf(']\n');
                            fprintf('received (corrupt) (dec):    [ ');
                            for ii=1:length(rmsg)
                                fprintf('%d ',rmsg(ii))
                            end
                            fprintf(']\n');
                        end
                        
                        retries = 5;
                        while corrupt && retries
                            rmsg = brick.conn.read();
                            try
                                reply = Command(rmsg);
                                corrupt = 0;
                            catch
                                retries = retries-1;
                            end
                        end
                    end
                    
                    if corrupt
                        rethrow(ME);
                    end
                end
                
                if reply.checkForError()
                    msg = 'Error byte is set. The Brick couldn''t handle the last packet';
                    id = [ID(), ':', 'CommandError'];
                    warning(id, msg);
                end
                
                % Verbose output
                if brick.debug > 0
                   fprintf('\t(DEBUG) received:  [ ');
                   for ii=1:length(rmsg)
                       fprintf('%s ',dec2hex(rmsg(ii)))
                   end
                   fprintf(']\n');
    %                fprintf('\t                (dec):    [ ');
    %                for ii=1:length(rmsg)
    %                    fprintf('%d ',rmsg(ii))
    %                end
    %                fprintf(']\n\n');
                end      
            end
            
            function waitForReply(brick)
                oldTimeOut = brick.timeOut;
                brick.timeOut = 0;
                
                brick.receive();
                
                brick.timeOut = oldTimeOut;
            end
        end
    end