Code covered by the BSD License  

Highlights from
Extended Brookshear Machine emulator and assembler

image thumbnail
from Extended Brookshear Machine emulator and assembler by David Young
Emulator and assembler for a simple computer, a teaching aid for computer science courses.

bm(varargin)
function varargout = bm(varargin)
%BM GUI for Brookshear Machine emulator
%      BM creates a new emulator and gui if none exists, or if there is an
%      existing instance, it raises it.
%
%      H = BM returns the handle to a new BM or the handle to
%      the existing singleton.
%
%      BM('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in BM.M with the given input arguments.
%
%      BM('Property','Value',...) creates a new BM or raises the
%      existing singleton.  Starting from the left, property value pairs are
%      applied to the GUI before bm_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to bm_OpeningFcn via varargin.
%
%   See also: BMACHINE, GUIDE, GUIDATA, GUIHANDLES

%   Copyright 2008 University of Sussex and David Young

% Last Modified by GUIDE v2.5 29-Dec-2008 18:08:06

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @bm_OpeningFcn, ...
                   'gui_OutputFcn',  @bm_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before bm is made visible.
function bm_OpeningFcn(hObject, eventdata, handles, varargin) %#ok<*INUSL>
% hObject    handle to figure
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to bm

% Choose default command line output for bm
handles.output = hObject;

% Create and store Brookshear machine
handles.machine = newbm;

% For bitmap display
handles.bitmapDisplay = get(handles.bitmappanel, 'UserData');
set(hObject, 'Colormap', handles.bitmapDisplay.colourmap);

% Update handles structure
guidata(hObject, handles);


% --- Outputs from this function are returned to the command line.
function varargout = bm_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;


% --- Executes when user attempts to close figure1.
function figure1_CloseRequestFcn(hObject, eventdata, handles) %#ok<*INUSD,*DEFNU>
% hObject    handle to figure1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

delete(hObject);        % closes the figure
% if not running desktop, assume BM is meant to be standalone, so quit
if ~desktop('-inuse')
    quit;
end


%---------------------- Memory panel --------------------------------------


function mempanel_CreateFcn(hObject, eventdata, handles)
% Main memory panel

% Would be nice to use uitable for this, but updating the table data always
% moves the focus to the top left table cell, so hopeless if the edit
% action updates other cells
defaultFontSize(hObject);

% Parameters for edit cell layout - panel size must accommodate
nrows = 32;     % rows to display
maxrows = 256;  % must agree with machine memory size
textcol = [0.9 0.9 1];
pccol = [1 0.75 0.75];
rows = [1 nrows];
headers = memstrings;
insttype = 'descriptive';
strings = memstrings([], rows, insttype);
ncols = length(headers);
units = 'characters'; 
width = 13;  % cell dimensions in units above
instrwidth = 40;
height = 1.25;
set(hObject, 'Units', units);
panelpos = get(hObject, 'Position');
l1 = 7;      % left side x coord of leftmost cell
b = panelpos(4) - 2 - height;     % bottom y coord of current cell
lpad = 0;   % extra spacing
bpad = 0.2;   % extra spacing

% array of data text/edit cells
uimemctls = zeros(nrows, ncols);

% create main text cells - first col and row not editable
for row = 0:nrows
    l = l1;
    for col = 1:ncols
        if row == 0
            str = headers{col};
        else
            str = strings{row, col};
        end
        if row == 0 || col == 1 || col == ncols
            style = 'text';
            if (row == 1 || row == 2) && col == 1
                bgcolour = pccol;
            else
                bgcolour = textcol;
            end
        else
            style = 'edit';
            bgcolour = 'w';
        end
        if col == ncols
            w = instrwidth;
            align = 'left';
        else
            w = width;
            align = 'center';
        end
        h = uicontrol(hObject, ...
            'Style', style, ...
            'Units', units, ...
            'Position', [l, b, w, height], ...
            'String', str, ...
            'Callback', @membox_Callback, ...
            'KeyPressFcn', @membox_KeyPressFcn, ...
            'Interruptible', 'on', ...  % must be on for stringready to work
            'BusyAction', 'queue', ...
            'BackgroundColor', bgcolour, ...
            'HorizontalAlignment', align, ...
            'UserData', [row col] ...
            );
        l = l + w + lpad;
        if row > 0
            uimemctls(row, col) = h;
        end
    end
    b = b - height - bpad;
end

% uicontrol used to force focus change when string in edit
% uicontrol needs to be read
ud.textcontrol = uicontrol(hObject, ...
    'Style', 'text', ...
    'Units', units, ...
    'Position', [0.1 0.1 0.1 0.1], ...
    'String', '', ...
    'Interruptible', 'off', ...
    'BusyAction', 'cancel', ...
    'BackgroundColor', get(hObject, 'BackgroundColor'), ...
    'Visible', 'on' ...   % needs to be "visible"
    );
   
% Data for callbacks
ud.rows = rows;
ud.maxrows = maxrows;
ud.ctls = uimemctls;
ud.textcol = textcol;
ud.pccol = pccol;
ud.pcrow = 1;
ud.insttype = insttype;
set(hObject, 'UserData', ud);


function membox_Callback(hObject, eventdata)

% fish out all the bits and pieces from the gui
panel = get(hObject, 'Parent');
ud = get(panel, 'UserData');
ctls = ud.ctls;
rows = ud.rows;
coords = get(hObject, 'UserData');
row = coords(1);
col = coords(2);
a = rows(1) + row - 2;      % machine address
handles = guidata(hObject);
machine = handles.machine;
str = get(hObject, 'String');

% Get new value, update machine if valid
try
    machine.memory(a+1) = string2val(col, str);
catch err
    if ~bmexception(err)
        rethrow(err);
    end
end

% update display and gui
strings = memstrings(machine, [a a]+1, ud.insttype);
ncols = length(strings);
for c = 2:ncols
    set(ctls(row, c), 'String', strings{1, c});
end;
if oddaddr(machine.pc, a) && row > 1    % show instruction on line above
    set(ctls(row-1, ncols), 'String', ...
        instr2string(ud.insttype, machine.memory(a), machine.memory(a+1)));
end
handles.machine = machine;
guidata(hObject, handles);

% update bitmap display
if a >= 128 && a <= 255 && handles.bitmapDisplay.on
    bitmapDisplay(hObject);
end


function membox_KeyPressFcn(hObject, eventdata, handles)
% eventdata  structure with the following fields (see UICONTROL)
%	Key: name of the key that was pressed, in lower case
%	Character: character interpretation of the key(s) that was pressed
%	Modifier: name(s) of the modifier key(s) (i.e., control, shift) pressed
%
% Used to move focus to next location and maybe scroll when enter or arrow
% keys pressed. Biggest problem is getting the string on an arbitrary key
% press - stringready is the nasty solution to this.

% Needs to lock itself to avoid acting on interrupts from repeating keys.
persistent running;
if ~isempty(running)
    return
end
running = true; %#ok<NASGU>

panel = get(hObject, 'Parent');
ud = get(panel, 'UserData');
ctls = ud.ctls;
rows = ud.rows;
maxrows = ud.maxrows;
coords = get(hObject, 'UserData');
row = coords(1);
col = coords(2);

switch eventdata.Key
    case {'return' 'downarrow'}
        if row < rows(2)-rows(1)+1
            uicontrol(ctls(row+1, col));   % give focus to next control down
        elseif rows(2) < maxrows          
            stringReady(hObject);
            ud.rows = rows + 1;
            set(panel, 'UserData', ud);
            updateMemDisplay(panel);
            setmemslider(panel);
        end
    case 'uparrow'
        if row > 1
            uicontrol(ctls(row-1, col));   % give focus to next control down
        elseif rows(1) > 1          
            stringReady(hObject);
            ud.rows = rows - 1;
            set(panel, 'UserData', ud);
            updateMemDisplay(panel);
            setmemslider(panel);
        end
    case 'pagedown'
        jumpsize = min(rows(2) - rows(1) + 1, maxrows - rows(2));
        if jumpsize
            stringReady(hObject);
            ud.rows = rows + jumpsize;
            set(panel, 'UserData', ud);
            updateMemDisplay(panel);
            setmemslider(panel);
        end
    case 'pageup'
        jumpsize = min(rows(2) - rows(1) + 1, rows(1) - 1);
        if jumpsize
            stringReady(hObject);
            ud.rows = rows -  jumpsize;
            set(panel, 'UserData', ud);
            updateMemDisplay(panel);
            setmemslider(panel);
        end
end

running = [];


function updateMemDisplay(panel)
% Updates the memory display given its containing panel object

ud = get(panel, 'UserData');
ctls = ud.ctls;
rows = ud.rows;
oldpcrow = ud.pcrow;
handles = guidata(panel);
machine = handles.machine;

strings = memstrings(machine, rows, ud.insttype);
for row = 1:rows(2)-rows(1)+1
    for col = 1:size(ctls, 2);
        set(ctls(row, col), 'String', strings{row, col});      
    end
end

pcrow = double(machine.pc) + 2 - rows(1);
if pcrow ~= oldpcrow
    disprows = diff(rows) + 1;
    oldrows = [oldpcrow oldpcrow+1];
    oldrows = oldrows(oldrows >= 1 & oldrows <= disprows);
    set(ctls(oldrows, 1), 'Background', ud.textcol);
    newrows = [pcrow pcrow+1];
    newrows = newrows(newrows >= 1 & newrows <= disprows);
    set(ctls(newrows, 1), 'Background', ud.pccol);
    ud.pcrow = pcrow;
    set(panel, 'UserData', ud);
end

if handles.bitmapDisplay.on
    bitmapDisplay(panel);
end


function stringReady(hObject)
% Forces an edit control to make its string available as if return had been
% pressed, by moving focus to a text child. Very clumsy - there should be a
% good way to do this
ud = get(get(hObject, 'Parent'), 'UserData');
uicontrol(ud.textcontrol);
drawnow;    % This is essential, as change of focus executes asynchronously
uicontrol(hObject);


function memresetbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);


function memresetbutton_Callback(hObject, eventdata, handles)
panel = get(hObject, 'Parent');
handles.machine.memory(:) = 0;
guidata(hObject, handles);
updateMemDisplay(panel);


function savemem_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);
ud.file = '';
set(hObject, 'UserData', ud);

function savemem_Callback(hObject, eventdata, handles)
ud = get(hObject, 'UserData');
[filename, pathname] = uiputfile('*.txt', 'Save memory as', ud.file);
errDisplay(hObject, '');

if ~isequal(filename, 0) && ~isequal(pathname, 0)
    file = fullfile(pathname, filename);
    ud.file = file;
    set(hObject, 'UserData', ud);
    try
        panelud = get(handles.mempanel, 'UserData');
        savemem(handles.machine, file, panelud.insttype);
    catch ME
        errDisplay(hObject, ['Memory save failed:' ME.message]);
        return;
    end
end
    

function loadmem_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);
ud.file = '';
set(hObject, 'UserData', ud);

function loadmem_Callback(hObject, eventdata, handles)
ud = get(hObject, 'UserData');
[filename, pathname] = uigetfile('*.txt', 'Load memory from', ud.file);
errDisplay(hObject, '');

if ~isequal(filename, 0) && ~isequal(pathname, 0)
    file = fullfile(pathname, filename);
    ud.file = file;
    set(hObject, 'UserData', ud);
    try
        handles.machine = loadmem(handles.machine, readtext(file));
    catch ME
        errDisplay(hObject, ['Memory load failed:' ME.message]);
        return;
    end
    guidata(hObject, handles);
    updateMemDisplay(handles.mempanel);
end


function assembbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);
ud.file = '';
set(hObject, 'UserData', ud);

function assembbutton_Callback(hObject, eventdata, handles)
ud = get(hObject, 'UserData');
[filename, pathname] = uigetfile('*.txt', 'Assemble from', ud.file);
errDisplay(hObject, '');

if ~isequal(filename, 0) && ~isequal(pathname, 0)
    file = fullfile(pathname, filename);
    ud.file = file;
    set(hObject, 'UserData', ud);
    try
        handles.machine = loadmem(handles.machine, assembler(file));
    catch ME
        errDisplay(hObject, ['Assembly/load failed:' ME.message]);
        return;
    end
    guidata(hObject, handles);
    updateMemDisplay(handles.mempanel);
end

function assembfilebutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);
ud.filein = '';
ud.fileout = '';
set(hObject, 'UserData', ud);

function assembfilebutton_Callback(hObject, eventdata, handles)
ud = get(hObject, 'UserData');
[filenamein, pathnamein] = uigetfile('*.txt', 'Assemble from', ud.filein);
errDisplay(hObject, '');

if ~isequal(filenamein, 0) && ~isequal(pathnamein, 0)
    filein = fullfile(pathnamein, filenamein);
    ud.filein = filein;
    set(hObject, 'UserData', ud);
    try
        machcode = assembler(filein);
    catch ME
        errDisplay(hObject, ['Assembly failed:' ME.message]);
        return;
    end

    [filenameout, pathnameout] = uiputfile('*.txt', 'Save machine code as', ud.fileout);
    if ~isequal(filenameout, 0) && ~isequal(pathnameout, 0)
        fileout = fullfile(pathnameout, filenameout);
        ud.fileout = fileout;
        set(hObject, 'UserData', ud);
        try
            writetext(machcode, fileout);
        catch ME
            errDisplay(hObject, ['Memory save failed:' ME.message]);
            return;
        end
    end
end


function assembhelpbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

function assembhelpbutton_Callback(hObject, eventdata, handles)
showhelp('assembhelp');


function instrTextPanel_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

function descriptivetext_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

function descriptivetext_Callback(hObject, eventdata, handles)
panel = handles.mempanel;
ud = get(panel, 'UserData');
ud.insttype = 'descriptive';
set(panel, 'UserData', ud);
updateMemDisplay(panel);

function assembtext_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

function assembtext_Callback(hObject, eventdata, handles)
panel = handles.mempanel;
ud = get(panel, 'UserData');
ud.insttype = 'assembler';
set(panel, 'UserData', ud);
updateMemDisplay(panel);


function memslider_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end
set(hObject, ...
    'Value', 1, ...
    'SliderStep', [1/112 1/7], ...
    'Interruptible', 'off', ...
    'BusyAction', 'cancel');
set(hObject, 'UserData', false);        % indicates whether slider being changed by program


function memslider_Callback(hObject, eventdata, handles)
if ~get(hObject, 'UserData')     % avoid recursion
    v = get(hObject, 'Value');  % default puts 0 at the bottom
    panel = get(hObject, 'Parent');
    ud = get(panel, 'UserData');
    newrows = memsliderval2rows(v, ud.maxrows, ud.rows);

    if ~isequal(newrows, ud.rows)
        ud.rows = newrows;
        set(panel, 'UserData', ud);
        updateMemDisplay(panel);
    end
end


function setmemslider(panel)
% Set the memory slider according to the current rows
handles = guidata(panel);
ud = get(panel, 'UserData');
v = memsliderrows2val(ud.rows, ud.maxrows);
slider = handles.memslider;
set(slider, 'Value', v);


function rows = memsliderval2rows(v, maxrows, rows)
% Convert slider value in range 0 to 1 to row range to display
disprows = diff(rows) + 1;
rows(1) = 1 + round((1-v) * (maxrows-disprows));
rows(2) = rows(1) + disprows - 1;

function v = memsliderrows2val(rows, maxrows)
% Inverse of above
v = 1 - (rows(1) - 1) / (maxrows - (diff(rows) + 1));


%---------------------- Register panel ------------------------------------


function regpanel_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

headers = regstrings;
strings = regstrings([]);
[nrows, ncols] = size(strings);
units = 'characters'; 
set(hObject, 'Units', units);
width = 12.5;  % cell dimensions in units above
height = 1.25;
panelpos = get(hObject, 'Position');
l1 = 1;      % left side x coord of leftmost cell
b = panelpos(4) - 2 - height;     % bottom y coord of current cell
lpad = 0.2;   % extra spacing
bpad = 0.75;   % extra spacing

% array of data text/edit cells
uiregctls = zeros(nrows, ncols);

% create main text cells - not editable
for row = 0:nrows
    l = l1;
    for col = 1:ncols
        if row == 0
            str = headers{col};
        else
            str = strings{row, col};
        end
        h = uicontrol(hObject, ...
            'Style', 'text', ...
            'Units', units, ...
            'Position', [l, b, width, height], ...
            'String', str, ...
            'BackgroundColor', [0.9 1 0.9] ...
            );
        l = l + width + lpad;
        if row > 0
            uiregctls(row, col) = h;
        end
    end
    b = b - height - bpad;
end
   
% Data for callbacks
ud.ctls = uiregctls;

% Program counter
l = l1;
uicontrol(hObject, ...
    'Style', 'text', ...
    'Units', units, ...
    'Position', [l, b, 2*width + lpad, height], ...
    'String', 'Program counter', ...
    'BackgroundColor', [1 0.8 0.8] ...
    );
l = l + 2*(width + lpad);
ud.pcctl = uicontrol(hObject, ...
    'Style', 'edit', ...
    'Units', units, ...
    'Position', [l, b, width, height], ...
    'BackgroundColor', [1 0.8 0.8], ...
    'String', strings{1, 3}, ...
    'Callback', @pcedit_Callback ...
    );

set(hObject, 'UserData', ud);


function updateRegDisplay(panel)
% Updates the register display, given its panel
ud = get(panel, 'UserData');
ctls = ud.ctls;
handles = guidata(panel);
machine = handles.machine;

strings = regstrings(machine);
for row = 1:size(strings, 1)
    for col = 1:size(strings, 2);
        set(ctls(row, col), 'String', strings{row, col});      
    end
end

pcstr = bits2strings(0, machine.pc);
set(ud.pcctl, 'String', pcstr{3});


function pcedit_Callback(hObject, eventdata, handles)

handles = guidata(hObject);

inp = get(hObject, 'String');
try
    handles.machine.pc = string2val(3, inp);
catch err
    if ~bmexception(err)
        rethrow(err);
    end
end
pcstr = bits2strings(0, handles.machine.pc);
set(hObject, 'String', pcstr{3});

% update
guidata(hObject, handles);
updateMemDisplay(handles.mempanel);


function resetbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);


function resetbutton_Callback(hObject, eventdata, handles)
machine = resetReg(handles.machine);
machine.pc = 0;
handles.machine = machine;
guidata(hObject, handles);
updateDisplays(handles);
errDisplay(hObject, '');

%---------------------- Information panel ---------------------------------

function infopanel_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);


function instrucbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

function instrucbutton_Callback(hObject, eventdata, handles)
showinstructions;


function helpbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

function helpbutton_Callback(hObject, eventdata, handles)
showhelp('bmhelp');


function assembhelp2_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

function assembhelp2_Callback(hObject, eventdata, handles)
showhelp('assembhelp');


function errortext_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);

function errDisplay(hObject, message)
handles = guidata(hObject);
set(handles.errortext, 'String', message);

%---------------------- Control panel -------------------------------------


function controlpanel_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);
ud.maxdelay = 4; 
ud.delay = ud.maxdelay;
set(hObject, 'UserData', ud);


function running = stepDisplay(hObject)
handles = guidata(hObject);
errDisplay(hObject, '');
try
    handles.machine = step(handles.machine);
catch err
    if ~bmexception(err)
        rethrow(err);
    end
    handles.machine.running = false;
    errDisplay(hObject, err.message);
end    
running = handles.machine.running;
guidata(hObject, handles);
updateDisplays(handles);


function updateDisplays(handles)
updateMemDisplay(handles.mempanel);
updateRegDisplay(handles.regpanel);

%---------------------- Step button ---------------------------------------

function stepbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);


function stepbutton_Callback(hObject, eventdata, handles)
stepDisplay(hObject);

%---------------------- Reset & Run button --------------------------------

function resetrunbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);
ud.background1 = get(hObject, 'BackgroundColor');
ud.string1 = get(hObject, 'String');
ud.background2 = ud.background1*0.7;
ud.string2 = 'Halt';
set(hObject, 'UserData', ud);


function resetrunbutton_Callback(hObject, eventdata, handles)
runcpu(hObject, handles, true);


function runcpu(hObject, handles, reset)
runbutton = handles.resetrunbutton;
buttonud = get(runbutton, 'UserData');
if handles.machine.running
    if reset    % only take notice of run/reset/halt button
        handles.machine.running = false;
        guidata(hObject, handles);
    end
else
    if reset
        machine = resetReg(handles.machine);
        machine.pc = 0;
        handles.machine = machine;
        guidata(hObject, handles);
        updateDisplays(handles);
    end
    errDisplay(hObject, '');
    handles.machine.running = true;
    guidata(hObject, handles);
    ud = get(get(hObject, 'Parent'), 'UserData');
    set(runbutton, 'BackgroundColor', buttonud.background2, ...
        'String', buttonud.string2);
    pause(ud.delay);
    while stepDisplay(hObject)
        drawnow;
        ud = get(get(hObject, 'Parent'), 'UserData');
        pause(ud.delay);
    end
    set(runbutton, 'BackgroundColor', buttonud.background1, ...
        'String', buttonud.string1);
end

%---------------------- Continue button -----------------------------------

function contbutton_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);


function contbutton_Callback(hObject, eventdata, handles)
runcpu(hObject, handles, false);

%---------------------- Speed slider --------------------------------------

function speedtext_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);


function slider1_Callback(hObject, eventdata, handles)
panel = get(hObject, 'Parent');
ud = get(panel, 'UserData');
ud.delay = ud.maxdelay * (1 - get(hObject, 'Value'));
set(panel, 'UserData', ud);


function slider1_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end
% min and max set to 0 and 1 in Guide
ud = get(get(hObject, 'Parent'), 'UserData');
value = 1 - ud.delay/ud.maxdelay;
set(hObject, 'Value', value);


%---------------------- Bitmap display ------------------------------------


function bitmappanel_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);
set(hObject, 'Units', 'pixels');
pos = get(hObject, 'Position');
panelsize = pos(3:4) - [150 20];  % allow for title encroachment and buttons
margin = 10;
imsize = 32 * floor((min(panelsize)-margin)/32);
impos = [(panelsize-imsize)/2 imsize imsize];
a = axes( ...
    'Parent', hObject, ...
    'Visible', 'off', ...
    'Units', 'pixels', ...
    'Position', impos, ...
    'Xlim', [0.5 32.5], ...
    'Ylim', [0.5 32.5]);
ud.image = image( ...
    'Parent', a, ...
    'Clipping', 'off', ...
    'CData', 2 + zeros(32, 32, 'uint8'), ...
    'Xdata', [1 32], ...
    'YData', [32 1]);
ud.colourmap = [0 0 0; 1 1 1; 0.8 0.8 0.8];
ud.on = false;
set(hObject, 'UserData', ud);  % figure puts this into gui handles


function bitmaptoggle_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);


function bitmaptoggle_Callback(hObject, eventdata, handles)
if isequal(get(hObject, 'Value'), get(hObject, 'Max'))
    handles.bitmapDisplay.on = true;
    guidata(hObject, handles);
    bitmapDisplay(hObject);
else
    handles.bitmapDisplay.on = false;
    im = get(handles.bitmapDisplay.image, 'CData');
    im(:) = 2;
    set(handles.bitmapDisplay.image, 'CData', im);
    guidata(hObject, handles);
end


function saveDisplay_CreateFcn(hObject, eventdata, handles)
defaultFontSize(hObject);
ud.file = '';
set(hObject, 'UserData', ud);


function saveDisplay_Callback(hObject, eventdata, handles)
if handles.bitmapDisplay.on
    errDisplay(hObject, '');
    try
        saveDisplay(hObject);
    catch ME
        errDisplay(hObject, ['Display save failed:' ME.message]);
        return;
    end
else
    errDisplay(hObject, 'Display not switched on');
end

%---------------------- Utilities -----------------------------------------


function b = bmexception(err)
b = isequal(1, strmatch('bmachine', err.identifier));


function defaultFontSize(hObject)
% because guide insists on setting a fixed value
set(hObject, 'FontSize', 'default');    % because guide sets it to a fixed value

Contact us at files@mathworks.com