Code covered by the BSD License  

Highlights from
ECRobotInstaller – Simplified installation of tools for Embedded Coder Robot

image thumbnail

ECRobotInstaller – Simplified installation of tools for Embedded Coder Robot

by

 

02 Sep 2009 (Updated )

Simplifies the installation of ECRobot, a Simulink platform for LEGO Mindstorms NXT code generation

update_nxt_firmware(whatToDo)
function update_nxt_firmware(whatToDo)
% UPDATE_NXT_FIRMWARE
%
%   UPDATE_NXT_FIRMWARE is a gui that helps the user to transfer the 
%   enhanced firmware to the LEGO NXT. 
%
%   This function assumes that you have already done the following:
%
%   * Downloaded and installed all the required tools (by running
%     DOWNLOAD_ECROBOT_TOOLS and INSTALL_ECROBOT_TOOLS), and
%
%   * Rebooted the PC (this ensures that the LEGO Mindstorms NXT 
%     Driver is active)
%
%   Notes on usage:
%
%   1) UPDATE_NXT_FIRMWARE reads the configuration information (download
%      directories, filenames, etc.) from ECROBOT_INSTALL_CONFIG.M. 
%
%   2) It is safe to run UPDATE_NXT_FIRMWARE multiple times (i.e., it is
%      safe to transfer the enhanced firmware to the NXT multiple times).

%   Copyright 2009 The MathWorks, Inc.

% ECRobotInstaller version 1.2: (dec-11-2009)
%   * fantom.dll existence is checked using windows registry (instead of
%     just looking for c:\winnt\system32\fantom.dll)
%   * Instead of hardcoded RFW file, we now look for lowest version >= 1.06
%     user also has the option to override and specify another file. This
%     is done before the GUI starts up
%   * When checking the firmware version on the NXT, we now check if
%     version >= 1.06 instead of exact match to ver 1.06
%   * Initial checks are now done before GUI startup
%   * input argument is now 'test' (for simulation mode) instead of a boolean
%
% ECRobotInstaller version 1.37: (Jan-01-2011)
%   * In DEBUG mode, checks for LEGO USB Driver and firmware files are no longer fatal

global UPDATE_NXT_FIRMWARE_DEBUG 

if nargin > 0 && strcmp(whatToDo, 'test')
    UPDATE_NXT_FIRMWARE_DEBUG = true;
    fprintf('Operating in test mode\n');
else
    UPDATE_NXT_FIRMWARE_DEBUG = false;
end

if ~(exist('ecrobot_install_config', 'file') == 2)
    fprintf('Unable to find ecrobot_install_config.m\n');
    return;
end

config = ecrobot_install_config;
try
    verifyConfig(config, 'installation_dirs', @visibleLog);
catch %#ok<CTCH>
    return;
end

% check that lego nxt driver is installed
if ~check_lego_usb_driver()
    fprintf('LEGO NXT Driver USB driver is not installed\n');
    if ~UPDATE_NXT_FIRMWARE_DEBUG
        return;
    end
end

% check that nexttool and .rfw file are present
firmwareFile = get_firmware_filename(config);
if isempty(firmwareFile)
    fprintf('Unable to find LEGO NXT firmware file\n');
    if ~UPDATE_NXT_FIRMWARE_DEBUG
        return;
    end    
end

if ~check_nexttool(config)
    fprintf('Unable to find NeXTTool.exe\n');
    return;
end


hfig = figure('color', get(0,'DefaultUicontrolBackgroundColor'), ...
            'name', 'Download enhanced firmware to the LEGO NXT', ...
            'MenuBar', 'None', ...
            'NumberTitle', 'off', ...
            'Resize', 'off', ...
            'IntegerHandle', 'off', ...
            'DeleteFcn', @(obj,event) exitProgram(), ...
            'WindowStyle', 'modal', ...
            'visible', 'off');
        
figpos = get(hfig,'position');
set(hfig, 'position', [figpos(1:2) 700 500]);
movegui(hfig, 'center');
set(hfig, 'visible', 'on');

hback = uicontrol('style','pushbutton', ...
                  'string', '< Back', ...
                  'units', 'pixels', ...
                  'position', [10 10 90 25], ...
                  'callback', @backBtnCallback, ...
                  'parent', hfig);
hnext = uicontrol('style','pushbutton', ...
                  'string', 'Continue >', ...
                  'units', 'pixels', ...
                  'position', [110 10 90 25], ...
                  'callback', @nextBtnCallback, ...
                  'parent', hfig);
hcancel = uicontrol('style','pushbutton', ...
                  'string', 'Cancel', ...
                  'units', 'pixels', ...
                  'position', [210 10 90 25], ...
                  'callback', @(obj,event) exitProgram(), ...                  
                  'parent', hfig);
              
hprompt = uicontrol('style', 'text', ...
                  'string', {'', ''}, ...
                  'fontsize', 12, ...
                  'fontweight', 'bold', ...
                  'HorizontalAlignment', 'left', ...
                  'units', 'norm', ...
                  'position', [.05 .2 .3 .6], ...
                  'parent', hfig);
              
htitle = uicontrol('style', 'text', ...
                  'string', {''}, ...
                  'fontsize', 16, ...
                  'units', 'norm', ...
                  'position', [.05 .9 .8 .08], ...
                  'parent', hfig);

haxes = axes('parent', hfig, ...
             'units', 'norm', ...
             'position', [.45 .2 .5 .6]);
         
previousScreen = [];
nextScreen = [];
nextScreenCheck = @() true;    

screen1();

%% ----------------------------------------------------

    function visibleLog(varargin)
        fprintf(1, varargin{:});
    end

    function backBtnCallback(obj,evnt) %#ok<INUSD>
        if ~isempty(previousScreen)
            nextScreenCheck = @() true;
            previousScreen(); %#ok<NOEFF>
        end
    end

    function nextBtnCallback(obj,evnt) %#ok<INUSD>
        if ~isempty(nextScreen)
            if nextScreenCheck()
                nextScreenCheck = @() true;                
                nextScreen(); %#ok<NOEFF>
            end
        end        
    end

    function exitProgram
        delete(hfig);
        clear global UPDATE_NXT_FIRMWARE_DEBUG;
    end
    
    function setNextScreen(fcnHandle, str)
       nextScreen = fcnHandle;
       if isempty(fcnHandle)
           set(hnext, 'enable', 'off');
       else
           set(hnext, 'enable', 'on');
       end
       if exist('str', 'var')
           set(hnext, 'string', str);
       else
           set(hnext, 'string', 'Continue >');
       end
    end
    
    function setPrevScreen(fcnHandle, str)
       previousScreen = fcnHandle;
       if isempty(fcnHandle)
           set(hback, 'enable', 'off');
       else
           set(hback, 'enable', 'on');
       end
       if exist('str', 'var')
           set(hback, 'string', str);
       else
            set(hback, 'string', '< Back');
       end
    end  
    
    %%
    % turn nxt on, and connect to pc via usb cable
    function screen1
        setPrevScreen([]);
        setNextScreen(@screen2);

        set(htitle, 'string', 'Step 1. Connect the LEGO NXT to the PC');
        
        set(hprompt, 'string', {'Turn on the LEGO NXT, and connect it to the host PC using the USB cable'});
        showimage('nxt-usb-1.jpg', haxes);                    
        nextScreenCheck = @myNextScreenCheck;
        
        function usbOK = myNextScreenCheck
            [usbOK,versionNum] = check_usb_connection(config);
            if ~usbOK
                errordlg({'Unable to talk to the LEGO NXT.' ...
                           '' ...
                           'Check that the LEGO NXT is turned on and connected to the host PC'}, ...
                           'Verify USB connection', 'modal');
            else
                fprintf('Version of existing firmware on the NXT = %g\n', versionNum);
            end
        end
    end
    
    function screen2
        setPrevScreen(@screen1);
        setNextScreen(@screen3);        
        set(htitle, 'string', 'Step 2. Reset the LEGO NXT');
        
        set(hprompt, 'string', {'Find a stiff rod or wire (a straightened paper clip works nicely)'});
        showimage('nxt-reset-1.jpg', haxes);
    end
    
    function screen3
        setPrevScreen(@screen2);
        setNextScreen(@screen4);
        
        set(htitle, 'string', 'Step 2. Reset the LEGO NXT');
        
        set(hprompt, 'string', {...
            'The reset button is in the top-left hole on the back of the NXT.' ...
            '' ...
            'Using the wire, press and hold down the reset button for ~ 5 seconds.' ...
            '' ...
            '(The NXT screen should blank out when you press the reset button)'
            });
        
        showimage('nxt-reset-2.jpg', haxes);              
    end
    
    function screen4
        setPrevScreen(@screen3);
        setNextScreen(@screen5);
        
        set(htitle, 'string', 'Step 3. Start the LEGO NXT');
        
        set(hprompt, 'string', {...
            'Start the LEGO NXT by pressing the square orange button.' ...
            '' ...
            'The NXT should emit a soft ticking sound, indicating that it is in firmware update mode' ...
            '' ...
            '(If you don''t hear the ticking, you did not hold down the reset button long enough)' ...
            });
        
        showimage('nxt-orange-button-1.jpg', haxes);
    end    
  
    %   download firmware
    % download_to_nxt(config)    
    function screen5
        setPrevScreen([]);
        setNextScreen([]);
        
        set(htitle, 'string', 'Step 4. Download firmware');
        
        set(hprompt, 'string', {...
            'Please wait while the new firmware is downloaded to the NXT ...' ...
            '' ...
            '(This will take 15-30 seconds)' ...
            });
        
        set(hcancel, 'enable', 'off');
        download_to_nxt(config, firmwareFile);
        % pause(2); % for debugging
        set(hcancel, 'enable', 'on');
        
        confirmDownload();
    end        
    
    function confirmDownload
        setPrevScreen([]);
        setNextScreen([]);
        
        [connOk,versionNum] = check_usb_connection(config);

        if connOk && ~isnan(versionNum) && versionNum >= 1.06
            newstr1 = sprintf('Firmware successfully downloaded (version = %g)', versionNum);
            newstr2 = '';
            showimage('nxt-screen-ok.jpg', haxes);           
            setNextScreen(@exitProgram, 'Finish');
            set(hcancel, 'enable', 'off');
        else
            if ~connOk || isnan(versionNum)
                newstr1 = 'Possible problem with firmware download (unable to talk to LEGO NXT). ';
                newstr2 = 'Press the reset button on the back of the NXT and click on "Check NXT"';
                
            elseif versionNum < 1.06
                newstr1 = sprintf('Problem with firmware download (current version on NXT = %g)', versionNum);
                newstr2 = 'Try the download again';
            end
            
            setPrevScreen(@screen3);
            setNextScreen(@confirmDownload, 'Check NXT');
        end
        
        set(hprompt, 'string', {...
            newstr1 ...
            '' ...
            newstr2 ...
            });                      
        
    end
end

function showimage(imagename, ax)
    img = imread(['private/' imagename]);
    imagesc(img, 'parent', ax);
    axis(ax, 'equal', 'off');
end


function [isInstalled,versionStr] = check_lego_usb_driver
    try
        versionStr = winqueryreg('HKEY_LOCAL_MACHINE', ...
                                 'SOFTWARE\National Instruments\NI-VISA for Windows 95/NT', ...
                                 'CurrentVersion');                             
    catch  %#ok<CTCH>
        versionStr = '';
    end
    
    % do a more thorough check (this requires the computer to have been rebooted)
    dllnames = winqueryreg('name', 'HKEY_LOCAL_MACHINE', 'SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDlls');
    foundIndices = find(~cellfun('isempty', regexpi(dllnames, 'fantom\.dll')));
    driverFound = numel(foundIndices) > 0;

    isInstalled = ~isempty(versionStr) && driverFound;
end

%%
% The filename is expected to be of the form lms_arm_nbcnxc_nnn
% Get mininum version >= 1.06
function chosenFile = get_firmware_filename(config)
    d = dir(fullfile(config.NXTEnhancedFirmware_InstallationDirectory,'lms_arm_nbcnxc_*.rfw'));
    rfw_files = {d.name};
    versions = zeros(1,length(rfw_files));
    matches = regexp(rfw_files, 'lms_arm_nbcnxc_(?<ver>[0-9]+).rfw', 'names');
    for i=1:numel(matches)
        if numel(matches{i}) > 0
            versions(i) = str2double( matches{i}(1).ver ) / 100;
        end
    end
        
    indices = find(versions >= 1.06);
    versions = versions(indices); % remove pre-106 versions
    rfw_files = rfw_files(indices);
    if isempty(versions)
        autoChosenFile = '';
    else
        [ignore,minIndex] = min(versions); %#ok<ASGLU>
        autoChosenFile = fullfile(config.NXTEnhancedFirmware_InstallationDirectory, ...
                                  rfw_files{minIndex});
    end
    
    if isempty(autoChosenFile)
        selectedBtn = questdlg('Unable to find a LEGO NXT firmware (.rfw) file', ...
            'Problem with LEGO NXT firmware', ...
            'Select a file ...', 'Cancel', 'Select a file ...');
    else        
        selectedBtn = questdlg({'Recommended LEGO NXT firmware file:', autoChosenFile}, ...
            'Confirm LEGO NXT Firmware', ...
            'Proceed', 'Select another file ...', 'Cancel', ...
            'Proceed');
    end

    switch selectedBtn
        case {'', 'Cancel'}
            chosenFile = '';
        
        case 'Proceed'
            chosenFile = autoChosenFile;
        
        case {'Select a file ...', 'Select another file ...'}
            [fileName, pathName] = uigetfile('*.rfw', 'Choose a LEGO NXT firmware file', autoChosenFile);
            if isnumeric(fileName) && fileName==0
                chosenFile = ''; % nothing selected
            elseif isempty(regexpi(fileName, '\.rfw$'))
                fprintf('"%s" is not a LEGO NXT firmware file\n', fullfile(pathName, fileName));
                chosenFile = ''; % wrong selection
            else
                chosenFile = fullfile(pathName, fileName); % guaranteed to exist by UIGETFILE
            end     
            
        otherwise
            error('Internal error');
    end
    
end

%%
function foundNextTool = check_nexttool(config)
    nexttool_exe = fullfile(config.NXTTOOL_InstallationDirectory,'NeXTTool.exe');
    foundNextTool = exist(nexttool_exe, 'file')==2;
    if ~foundNextTool
        fprintf('"%s" does not exist\n', nexttool_exe);
    end
end

function [out,versionNum] = check_usb_connection(config)
    nxtTool_exe = fullfile(config.NXTTOOL_InstallationDirectory,'NeXTTool.exe');
    cmdstr = ['"' nxtTool_exe '"' ' /COM=usb -versions'];
    [resp,status] = systemWrapper(cmdstr); %#ok<ASGLU>
    tok = regexp(status, 'Firmware version = ([\d\.]+)', 'tokens');
    out = numel(tok)==1;
    if out
        versionNum = str2double(tok{1}{1});
    else
        versionNum = nan;
    end
end


function download_to_nxt(config, firmwareFile)
    nxtTool_exe = fullfile(config.NXTTOOL_InstallationDirectory,'NeXTTool.exe');
    cmdstr = ['"' nxtTool_exe '"' ' /COM=usb -firmware="' firmwareFile '"'];
    [resp,status] = systemWrapper(cmdstr);
end

%%
function [resp,status] = systemWrapper(cmdstr)
    global UPDATE_NXT_FIRMWARE_DEBUG 
    if ~isempty(UPDATE_NXT_FIRMWARE_DEBUG) && UPDATE_NXT_FIRMWARE_DEBUG
        fprintf('Simulating: %s\n', cmdstr);
        resp = 0; status = 'Firmware version = 1.06 *** DEBUGGING STUB FOR SYSTEM() ***';
    else
        [resp,status] = system(cmdstr);
    end
end

Contact us