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