Skip to content
Snippets Groups Projects
Select Git revision
  • 0726e13a5f3e4b32722cf4d3ef191c95d1110b34
  • master default protected
  • dev_2022
  • patch-1
  • develop
  • 50-use-ubuntus-libhidapi
  • issue-highLevelDispatch
  • issue-highLevelDesign
  • issue-motorStartBug
  • issue-commandLayerDesign
  • v1.0
  • v0.4-rc.13
  • v0.4-rc.12
  • v0.4-rc.11
  • v0.4-rc.10
  • v0.4-rc.9
  • v0.3-rc.8
  • v0.3-rc.7
  • v0.3-rc.6
  • v0.3-rc.5
  • v0.3-rc.4
  • v0.3-rc.3
  • v0.3-rc.2
  • v0.3-rc.1
  • v0.3-rc
  • v0.2
  • v0.1.1
  • v0.1
28 results

Primitives.m

Blame
    • Tim Stadtmann's avatar
      b8547226
      Change mode of enumerations · b8547226
      Tim Stadtmann authored
      The python-doc-preprocess script will change the mode of the enum-files each time
      they are processed. In order to avoid a stuffed list of changed files in git,
      the file mode is now permanently changed.
      b8547226
      History
      Change mode of enumerations
      Tim Stadtmann authored
      The python-doc-preprocess script will change the mode of the enum-files each time
      they are processed. In order to avoid a stuffed list of changed files in git,
      the file mode is now permanently changed.
    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