mirror of
https://github.com/una1veritas/mac-floppy-emu.git
synced 2025-03-22 12:33:36 +00:00
floppyemu/floppy_emu_arduino
This commit is contained in:
parent
0a8a67e352
commit
b58b3da080
@ -1,7 +1,8 @@
|
||||
avrtarget/ClockFrequency=16000000
|
||||
avrtarget/ExtRAMSize=0
|
||||
avrtarget/ExtendedRAM=false
|
||||
avrtarget/MCUType=atmega1284p
|
||||
avrtarget/MCUType=atmega2560
|
||||
avrtarget/UseEEPROM=false
|
||||
avrtarget/UseExtendedRAMforHeap=true
|
||||
avrtarget/perConfig=false
|
||||
eclipse.preferences.version=1
|
||||
|
@ -4,5 +4,4 @@ avrtarget/ExtendedRAM=false
|
||||
avrtarget/MCUType=atmega1284p
|
||||
avrtarget/UseEEPROM=false
|
||||
avrtarget/UseExtendedRAMforHeap=true
|
||||
avrtarget/perConfig=false
|
||||
eclipse.preferences.version=1
|
||||
|
@ -1,67 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.cdt.codan.checkers.errnoreturn=Warning
|
||||
org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
|
||||
org.eclipse.cdt.codan.checkers.errreturnvalue=Error
|
||||
org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.checkers.noreturn=Error
|
||||
org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true}
|
||||
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
|
||||
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")}
|
||||
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
@ -1,21 +1,16 @@
|
||||
eclipse.preferences.version=1
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/LANG/delimiter=\:
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/LANG/operation=append
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/LANG/value=en-US
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/append=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/appendContributed=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/LANG/delimiter=\:
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/LANG/operation=append
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/LANG/value=en-US
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/append=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/appendContributed=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.472085903/LANG/delimiter=\:
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.472085903/LANG/operation=append
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.472085903/LANG/value=en-US
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.472085903/append=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.472085903/appendContributed=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.924927447/LANG/delimiter=\:
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.924927447/LANG/operation=append
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.924927447/LANG/value=en-US
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.924927447/append=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.924927447/appendContributed=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/LANG/delimiter=\:
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/LANG/operation=append
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/LANG/value=en-US
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/append=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/appendContributed=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.674828633/LANG/delimiter=\:
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.674828633/LANG/operation=append
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.674828633/LANG/value=en-US
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.674828633/append=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.debug.674828633/appendContributed=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.1024470171/LANG/delimiter=\:
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.1024470171/LANG/operation=append
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.1024470171/LANG/value=en-US
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.1024470171/append=true
|
||||
environment/project/de.innot.avreclipse.configuration.app.release.1024470171/appendContributed=true
|
||||
|
@ -38,7 +38,6 @@
|
||||
#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];}))
|
||||
#endif
|
||||
|
||||
|
||||
#define STATUS_LED_PORT B
|
||||
#define STATUS_LED_PIN 3
|
||||
|
736
floppy_emu_arduino/diskmenu.cpp
Normal file → Executable file
736
floppy_emu_arduino/diskmenu.cpp
Normal file → Executable file
@ -1,368 +1,368 @@
|
||||
/*
|
||||
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||
|
||||
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||
http://creativecommons.org/licenses/by-nc/3.0/
|
||||
|
||||
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||
|
||||
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||
or from mailto:steve@bigmessowires.com.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <util/atomic.h>
|
||||
#include <util/delay.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "diskmenu.h"
|
||||
#include "SdFat.h"
|
||||
#include "SdBaseFile.h"
|
||||
#include "noklcd.h"
|
||||
|
||||
#define SECTORBUF_SIZE (23 * 512) // use the 24th buffer for directory breadcrumbs
|
||||
extern uint8_t sectorBuf[24][512];
|
||||
extern uint8_t extraBuf[512];
|
||||
|
||||
typedef struct FileEntry
|
||||
{
|
||||
char longName[FILENAME_LEN+1];
|
||||
char shortName[SHORTFILENAME_LEN+1];
|
||||
eImageType imageFileType;
|
||||
} FileEntry;
|
||||
|
||||
bool dirLfnNext(SdFat& sd, dir_t& dir, char* lfn)
|
||||
{
|
||||
uint8_t offset[] = {1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30};
|
||||
uint8_t lfnIn = 130;
|
||||
uint8_t i;
|
||||
uint8_t ndir=0;
|
||||
uint8_t sum;
|
||||
uint8_t test=0;
|
||||
bool haveLong = false;
|
||||
|
||||
while( sd.vwd()->read( &dir, 32 ) == 32 )
|
||||
{
|
||||
if( DIR_IS_LONG_NAME( &dir ) )
|
||||
{
|
||||
if( ! haveLong )
|
||||
{
|
||||
if(( dir.name[0] & 0XE0 ) != 0X40 )
|
||||
continue;
|
||||
ndir = dir.name[0] & 0X1F;
|
||||
test = dir.creationTimeTenths;
|
||||
haveLong = true;
|
||||
lfnIn = 130;
|
||||
lfn[ lfnIn ] = 0;
|
||||
}
|
||||
else if( dir.name[0] != --ndir || test != dir.creationTimeTenths )
|
||||
{
|
||||
haveLong = false;
|
||||
continue;
|
||||
}
|
||||
char *p = (char*) & dir;
|
||||
if( lfnIn > 0 )
|
||||
{
|
||||
lfnIn -= 13;
|
||||
for( i = 0; i < 13; i++ )
|
||||
lfn[lfnIn + i] = p[offset[i]];
|
||||
}
|
||||
}
|
||||
else if( DIR_IS_FILE_OR_SUBDIR( &dir )
|
||||
&& dir.name[0] != DIR_NAME_DELETED
|
||||
&& dir.name[0] != DIR_NAME_FREE
|
||||
&& dir.name[0] != '.')
|
||||
{
|
||||
if( haveLong )
|
||||
{
|
||||
for( sum = i = 0; i < 11; i++ )
|
||||
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir.name[i];
|
||||
if( sum != test || ndir != 1 )
|
||||
haveLong = false;
|
||||
}
|
||||
if( haveLong )
|
||||
{
|
||||
for( i = 0; lfnIn + i <= 130 ; i++ )
|
||||
lfn[i] = lfn[lfnIn + i];
|
||||
return true;
|
||||
}
|
||||
// else if( dir.reservedNT )
|
||||
// return "Reserved NT";
|
||||
else
|
||||
{
|
||||
SdBaseFile::dirName( dir, lfn );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( dir.name[0] == DIR_NAME_FREE )
|
||||
break;
|
||||
haveLong = false;
|
||||
}
|
||||
}
|
||||
lfn[ 0 ] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
eImageType DiskImageFileType(dir_t& dir, const char *filename)
|
||||
{
|
||||
if (filename[0] == '.')
|
||||
return DISK_IMAGE_NONE;
|
||||
|
||||
if (DIR_IS_SUBDIR(&dir))
|
||||
return DISK_IMAGE_DIRECTORY;
|
||||
|
||||
if (!DIR_IS_FILE(&dir))
|
||||
return DISK_IMAGE_NONE;
|
||||
|
||||
uint32_t size = dir.fileSize;
|
||||
|
||||
if (size == (unsigned long)1024 * 400)
|
||||
return DISK_IMAGE_400K;
|
||||
else if (size == (unsigned long)1024 * 800)
|
||||
return DISK_IMAGE_800K;
|
||||
else if (size == (unsigned long)1024 * 1440)
|
||||
return DISK_IMAGE_1440K;
|
||||
else if (size > (unsigned long)1024 * 400 &&
|
||||
size < (unsigned long)1024 * 1500)
|
||||
{
|
||||
// get the 8.3 filename
|
||||
char shortName[SHORTFILENAME_LEN+1];
|
||||
SdBaseFile::dirName(dir, shortName);
|
||||
|
||||
// read the first sector of the file
|
||||
SdBaseFile f;
|
||||
if (f.open(shortName, O_RDONLY))
|
||||
{
|
||||
f.read(extraBuf, 512);
|
||||
f.close();
|
||||
|
||||
// is it a DiskCopy 4.2 image?
|
||||
if (extraBuf[0x52] == 0x01 &&
|
||||
extraBuf[0x53] == 0x00)
|
||||
{
|
||||
size = ((unsigned long)extraBuf[0x41] * 65536 + (unsigned long)extraBuf[0x42] * 256 + (unsigned long)extraBuf[0x43]) / 1024;
|
||||
|
||||
if (size == 400)
|
||||
return DISK_IMAGE_DISKCOPY_400K;
|
||||
else if (size == 800)
|
||||
return DISK_IMAGE_DISKCOPY_800K;
|
||||
else if (size == 1440)
|
||||
return DISK_IMAGE_DISKCOPY_1440K;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DISK_IMAGE_NONE;
|
||||
}
|
||||
|
||||
uint16_t diskMenuEntryCount;
|
||||
uint16_t diskMenuOffset = 0;
|
||||
uint16_t diskMenuSelection = 0;
|
||||
char selectedFile[FILENAME_LEN+1];
|
||||
char selectedLongFile[FILENAME_LEN+1];
|
||||
eImageType selectedFileType;
|
||||
uint8_t subdirDepth = 0;
|
||||
|
||||
#define LONGFILENAME_LEN 130
|
||||
|
||||
void InitDiskMenu(SdFat& sd)
|
||||
{
|
||||
dir_t dir;
|
||||
char name[LONGFILENAME_LEN+1];
|
||||
|
||||
diskMenuEntryCount = 0;
|
||||
|
||||
// use the sector buffers to hold the filenames
|
||||
uint16_t maxEntries = SECTORBUF_SIZE / sizeof(FileEntry);
|
||||
FileEntry* pFileEntries = (FileEntry*)sectorBuf;
|
||||
|
||||
sd.vwd()->rewind();
|
||||
while (dirLfnNext(sd, dir, name) && diskMenuEntryCount < maxEntries)
|
||||
{
|
||||
eImageType imageType;
|
||||
|
||||
if ((imageType = DiskImageFileType(dir, name)) != DISK_IMAGE_NONE)
|
||||
{
|
||||
strncpy(pFileEntries[diskMenuEntryCount].longName, name, FILENAME_LEN+1);
|
||||
SdBaseFile::dirName(dir, pFileEntries[diskMenuEntryCount].shortName);
|
||||
pFileEntries[diskMenuEntryCount].imageFileType = imageType;
|
||||
diskMenuEntryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// add up directory, if not at the root
|
||||
if (!sd.vwd()->isRoot())
|
||||
{
|
||||
strncpy(pFileEntries[diskMenuEntryCount].longName, "..", FILENAME_LEN+1);
|
||||
strncpy(pFileEntries[diskMenuEntryCount].shortName, "..", SHORTFILENAME_LEN+1);
|
||||
pFileEntries[diskMenuEntryCount].imageFileType = DISK_IMAGE_UP_DIRECTORY;
|
||||
diskMenuEntryCount++;
|
||||
}
|
||||
|
||||
char file1[FILENAME_LEN+1], file2[FILENAME_LEN+1], temp[FILENAME_LEN+1];
|
||||
eImageType tempType;
|
||||
|
||||
// sort the names by longname
|
||||
for (uint16_t i=0; i<diskMenuEntryCount; i++)
|
||||
{
|
||||
for (uint16_t j=i+1; j<diskMenuEntryCount; j++)
|
||||
{
|
||||
// convert filenames to upper case, for comparison purposes
|
||||
strncpy(file1, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||
for (uint8_t x=0; x<strlen(file1); x++)
|
||||
file1[x] = toupper(file1[x]);
|
||||
|
||||
strncpy(file2, pFileEntries[j].longName, FILENAME_LEN+1);
|
||||
for (uint8_t x=0; x<strlen(file2); x++)
|
||||
file2[x] = toupper(file2[x]);
|
||||
|
||||
// sort directories before regular files
|
||||
int diff = strncmp(file1, file2, FILENAME_LEN+1);
|
||||
if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||
pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||
diff -= 1000;
|
||||
if (pFileEntries[j].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||
pFileEntries[j].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||
diff += 1000;
|
||||
|
||||
// if file1 > file2, swap them
|
||||
if (diff > 0)
|
||||
{
|
||||
strncpy(temp, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||
strncpy(pFileEntries[i].longName, pFileEntries[j].longName, FILENAME_LEN+1);
|
||||
strncpy(pFileEntries[j].longName, temp, FILENAME_LEN+1);
|
||||
|
||||
strncpy(temp, pFileEntries[i].shortName, SHORTFILENAME_LEN+1);
|
||||
strncpy(pFileEntries[i].shortName, pFileEntries[j].shortName, SHORTFILENAME_LEN+1);
|
||||
strncpy(pFileEntries[j].shortName, temp, SHORTFILENAME_LEN+1);
|
||||
|
||||
tempType = pFileEntries[i].imageFileType;
|
||||
pFileEntries[i].imageFileType = pFileEntries[j].imageFileType;
|
||||
pFileEntries[j].imageFileType = tempType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawDiskMenu(SdFat& sd)
|
||||
{
|
||||
// scroll menu if necessary
|
||||
if (diskMenuSelection < diskMenuOffset)
|
||||
diskMenuOffset = diskMenuSelection;
|
||||
if (diskMenuSelection > diskMenuOffset+4)
|
||||
diskMenuOffset = diskMenuSelection-4;
|
||||
|
||||
LcdGoto(0,0);
|
||||
LcdWrite(LCD_DATA, 0x7F);
|
||||
for (int i=0; i<19; i++)
|
||||
LcdWrite(LCD_DATA, 0x40);
|
||||
|
||||
LcdTinyStringFramed("Select Disk");
|
||||
|
||||
for (int i=0; i<19; i++)
|
||||
LcdWrite(LCD_DATA, 0x40);
|
||||
LcdWrite(LCD_DATA, 0x7F);
|
||||
|
||||
if (diskMenuEntryCount == 0)
|
||||
{
|
||||
LcdGoto(0, 1);
|
||||
LcdTinyString("no image files found", TEXT_NORMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileEntry* pFileEntries = (FileEntry*)sectorBuf;
|
||||
|
||||
int row = 0;
|
||||
for (uint16_t i=diskMenuOffset; i<diskMenuOffset+5 && i<diskMenuEntryCount; i++)
|
||||
{
|
||||
bool selected = (i == diskMenuSelection);
|
||||
|
||||
LcdGoto(0, row+1);
|
||||
for (int j=0; j<LCD_WIDTH; j++)
|
||||
{
|
||||
LcdWrite(LCD_DATA, selected ? 0x7F : 0x00);
|
||||
}
|
||||
|
||||
// show the image name
|
||||
LcdGoto(1, row+1);
|
||||
LcdTinyString(pFileEntries[i].longName, selected ? TEXT_INVERSE : TEXT_NORMAL, LCD_WIDTH-1);
|
||||
|
||||
// draw a folder icon for subdirectories
|
||||
if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||
pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||
{
|
||||
LcdGoto(73, row+1);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x24): 0x24);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x24): 0x24);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00);
|
||||
}
|
||||
|
||||
if (selected)
|
||||
{
|
||||
strncpy(selectedLongFile, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||
strncpy(selectedFile, pFileEntries[i].shortName, SHORTFILENAME_LEN+1);
|
||||
selectedFileType = pFileEntries[i].imageFileType;
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
|
||||
// draw the scrollbar
|
||||
if (diskMenuEntryCount <= 5)
|
||||
{
|
||||
// no scrollbar
|
||||
for (uint8_t r=1; r<6; r++)
|
||||
{
|
||||
LcdGoto(82, r);
|
||||
LcdWrite(LCD_DATA, 0x00);
|
||||
LcdWrite(LCD_DATA, 0x00);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t barEnd = 8 + (uint16_t)39 * (diskMenuOffset + 5) / diskMenuEntryCount;
|
||||
uint8_t barSize = (uint16_t)39 * 5 / diskMenuEntryCount;
|
||||
uint8_t barStart = barEnd - barSize;
|
||||
|
||||
for (uint8_t r=1; r<6; r++)
|
||||
{
|
||||
LcdGoto(82, r);
|
||||
LcdWrite(LCD_DATA, 0x00);
|
||||
|
||||
uint8_t b = 0;
|
||||
for (uint8_t y=r*8; y<=r*8+7; y++)
|
||||
{
|
||||
if (y >= barStart && y <= barEnd)
|
||||
b = 0x80 | (b >> 1);
|
||||
else
|
||||
b = (b >> 1);
|
||||
}
|
||||
|
||||
LcdWrite(LCD_DATA, b);
|
||||
}
|
||||
}
|
||||
|
||||
// prevent moving selection past end of list
|
||||
if (diskMenuSelection >= diskMenuOffset + row)
|
||||
{
|
||||
diskMenuSelection = diskMenuOffset + row - 1;
|
||||
if (row == 4 && diskMenuOffset > 0)
|
||||
{
|
||||
diskMenuOffset--; // scroll backwards
|
||||
}
|
||||
DrawDiskMenu(sd); // draw again
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved.
|
||||
|
||||
Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported
|
||||
license. (CC BY-NC 3.0) The terms of the license may be viewed at
|
||||
http://creativecommons.org/licenses/by-nc/3.0/
|
||||
|
||||
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/
|
||||
|
||||
Permissions beyond the scope of this license may be available at www.bigmessowires.com
|
||||
or from mailto:steve@bigmessowires.com.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <util/atomic.h>
|
||||
#include <util/delay.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "diskmenu.h"
|
||||
#include "SdFat.h"
|
||||
#include "SdBaseFile.h"
|
||||
#include "noklcd.h"
|
||||
|
||||
#define SECTORBUF_SIZE (23 * 512) // use the 24th buffer for directory breadcrumbs
|
||||
extern uint8_t sectorBuf[24][512];
|
||||
extern uint8_t extraBuf[512];
|
||||
|
||||
typedef struct FileEntry
|
||||
{
|
||||
char longName[FILENAME_LEN+1];
|
||||
char shortName[SHORTFILENAME_LEN+1];
|
||||
eImageType imageFileType;
|
||||
} FileEntry;
|
||||
|
||||
bool dirLfnNext(SdFat& sd, dir_t& dir, char* lfn)
|
||||
{
|
||||
uint8_t offset[] = {1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30};
|
||||
uint8_t lfnIn = 130;
|
||||
uint8_t i;
|
||||
uint8_t ndir=0;
|
||||
uint8_t sum;
|
||||
uint8_t test=0;
|
||||
bool haveLong = false;
|
||||
|
||||
while( sd.vwd()->read( &dir, 32 ) == 32 )
|
||||
{
|
||||
if( DIR_IS_LONG_NAME( &dir ) )
|
||||
{
|
||||
if( ! haveLong )
|
||||
{
|
||||
if(( dir.name[0] & 0XE0 ) != 0X40 )
|
||||
continue;
|
||||
ndir = dir.name[0] & 0X1F;
|
||||
test = dir.creationTimeTenths;
|
||||
haveLong = true;
|
||||
lfnIn = 130;
|
||||
lfn[ lfnIn ] = 0;
|
||||
}
|
||||
else if( dir.name[0] != --ndir || test != dir.creationTimeTenths )
|
||||
{
|
||||
haveLong = false;
|
||||
continue;
|
||||
}
|
||||
char *p = (char*) & dir;
|
||||
if( lfnIn > 0 )
|
||||
{
|
||||
lfnIn -= 13;
|
||||
for( i = 0; i < 13; i++ )
|
||||
lfn[lfnIn + i] = p[offset[i]];
|
||||
}
|
||||
}
|
||||
else if( DIR_IS_FILE_OR_SUBDIR( &dir )
|
||||
&& dir.name[0] != DIR_NAME_DELETED
|
||||
&& dir.name[0] != DIR_NAME_FREE
|
||||
&& dir.name[0] != '.')
|
||||
{
|
||||
if( haveLong )
|
||||
{
|
||||
for( sum = i = 0; i < 11; i++ )
|
||||
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir.name[i];
|
||||
if( sum != test || ndir != 1 )
|
||||
haveLong = false;
|
||||
}
|
||||
if( haveLong )
|
||||
{
|
||||
for( i = 0; lfnIn + i <= 130 ; i++ )
|
||||
lfn[i] = lfn[lfnIn + i];
|
||||
return true;
|
||||
}
|
||||
// else if( dir.reservedNT )
|
||||
// return "Reserved NT";
|
||||
else
|
||||
{
|
||||
SdBaseFile::dirName( dir, lfn );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( dir.name[0] == DIR_NAME_FREE )
|
||||
break;
|
||||
haveLong = false;
|
||||
}
|
||||
}
|
||||
lfn[ 0 ] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
eImageType DiskImageFileType(dir_t& dir, const char *filename)
|
||||
{
|
||||
if (filename[0] == '.')
|
||||
return DISK_IMAGE_NONE;
|
||||
|
||||
if (DIR_IS_SUBDIR(&dir))
|
||||
return DISK_IMAGE_DIRECTORY;
|
||||
|
||||
if (!DIR_IS_FILE(&dir))
|
||||
return DISK_IMAGE_NONE;
|
||||
|
||||
uint32_t size = dir.fileSize;
|
||||
|
||||
if (size == (unsigned long)1024 * 400)
|
||||
return DISK_IMAGE_400K;
|
||||
else if (size == (unsigned long)1024 * 800)
|
||||
return DISK_IMAGE_800K;
|
||||
else if (size == (unsigned long)1024 * 1440)
|
||||
return DISK_IMAGE_1440K;
|
||||
else if (size > (unsigned long)1024 * 400 &&
|
||||
size < (unsigned long)1024 * 1500)
|
||||
{
|
||||
// get the 8.3 filename
|
||||
char shortName[SHORTFILENAME_LEN+1];
|
||||
SdBaseFile::dirName(dir, shortName);
|
||||
|
||||
// read the first sector of the file
|
||||
SdBaseFile f;
|
||||
if (f.open(shortName, O_RDONLY))
|
||||
{
|
||||
f.read(extraBuf, 512);
|
||||
f.close();
|
||||
|
||||
// is it a DiskCopy 4.2 image?
|
||||
if (extraBuf[0x52] == 0x01 &&
|
||||
extraBuf[0x53] == 0x00)
|
||||
{
|
||||
size = ((unsigned long)extraBuf[0x41] * 65536 + (unsigned long)extraBuf[0x42] * 256 + (unsigned long)extraBuf[0x43]) / 1024;
|
||||
|
||||
if (size == 400)
|
||||
return DISK_IMAGE_DISKCOPY_400K;
|
||||
else if (size == 800)
|
||||
return DISK_IMAGE_DISKCOPY_800K;
|
||||
else if (size == 1440)
|
||||
return DISK_IMAGE_DISKCOPY_1440K;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DISK_IMAGE_NONE;
|
||||
}
|
||||
|
||||
uint16_t diskMenuEntryCount;
|
||||
uint16_t diskMenuOffset = 0;
|
||||
uint16_t diskMenuSelection = 0;
|
||||
char selectedFile[FILENAME_LEN+1];
|
||||
char selectedLongFile[FILENAME_LEN+1];
|
||||
eImageType selectedFileType;
|
||||
uint8_t subdirDepth = 0;
|
||||
|
||||
#define LONGFILENAME_LEN 130
|
||||
|
||||
void InitDiskMenu(SdFat& sd)
|
||||
{
|
||||
dir_t dir;
|
||||
char name[LONGFILENAME_LEN+1];
|
||||
|
||||
diskMenuEntryCount = 0;
|
||||
|
||||
// use the sector buffers to hold the filenames
|
||||
uint16_t maxEntries = SECTORBUF_SIZE / sizeof(FileEntry);
|
||||
FileEntry* pFileEntries = (FileEntry*)sectorBuf;
|
||||
|
||||
sd.vwd()->rewind();
|
||||
while (dirLfnNext(sd, dir, name) && diskMenuEntryCount < maxEntries)
|
||||
{
|
||||
eImageType imageType;
|
||||
|
||||
if ((imageType = DiskImageFileType(dir, name)) != DISK_IMAGE_NONE)
|
||||
{
|
||||
strncpy(pFileEntries[diskMenuEntryCount].longName, name, FILENAME_LEN+1);
|
||||
SdBaseFile::dirName(dir, pFileEntries[diskMenuEntryCount].shortName);
|
||||
pFileEntries[diskMenuEntryCount].imageFileType = imageType;
|
||||
diskMenuEntryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// add up directory, if not at the root
|
||||
if (!sd.vwd()->isRoot())
|
||||
{
|
||||
strncpy(pFileEntries[diskMenuEntryCount].longName, "..", FILENAME_LEN+1);
|
||||
strncpy(pFileEntries[diskMenuEntryCount].shortName, "..", SHORTFILENAME_LEN+1);
|
||||
pFileEntries[diskMenuEntryCount].imageFileType = DISK_IMAGE_UP_DIRECTORY;
|
||||
diskMenuEntryCount++;
|
||||
}
|
||||
|
||||
char file1[FILENAME_LEN+1], file2[FILENAME_LEN+1], temp[FILENAME_LEN+1];
|
||||
eImageType tempType;
|
||||
|
||||
// sort the names by longname
|
||||
for (uint16_t i=0; i<diskMenuEntryCount; i++)
|
||||
{
|
||||
for (uint16_t j=i+1; j<diskMenuEntryCount; j++)
|
||||
{
|
||||
// convert filenames to upper case, for comparison purposes
|
||||
strncpy(file1, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||
for (uint8_t x=0; x<strlen(file1); x++)
|
||||
file1[x] = toupper(file1[x]);
|
||||
|
||||
strncpy(file2, pFileEntries[j].longName, FILENAME_LEN+1);
|
||||
for (uint8_t x=0; x<strlen(file2); x++)
|
||||
file2[x] = toupper(file2[x]);
|
||||
|
||||
// sort directories before regular files
|
||||
int diff = strncmp(file1, file2, FILENAME_LEN+1);
|
||||
if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||
pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||
diff -= 1000;
|
||||
if (pFileEntries[j].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||
pFileEntries[j].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||
diff += 1000;
|
||||
|
||||
// if file1 > file2, swap them
|
||||
if (diff > 0)
|
||||
{
|
||||
strncpy(temp, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||
strncpy(pFileEntries[i].longName, pFileEntries[j].longName, FILENAME_LEN+1);
|
||||
strncpy(pFileEntries[j].longName, temp, FILENAME_LEN+1);
|
||||
|
||||
strncpy(temp, pFileEntries[i].shortName, SHORTFILENAME_LEN+1);
|
||||
strncpy(pFileEntries[i].shortName, pFileEntries[j].shortName, SHORTFILENAME_LEN+1);
|
||||
strncpy(pFileEntries[j].shortName, temp, SHORTFILENAME_LEN+1);
|
||||
|
||||
tempType = pFileEntries[i].imageFileType;
|
||||
pFileEntries[i].imageFileType = pFileEntries[j].imageFileType;
|
||||
pFileEntries[j].imageFileType = tempType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawDiskMenu(SdFat& sd)
|
||||
{
|
||||
// scroll menu if necessary
|
||||
if (diskMenuSelection < diskMenuOffset)
|
||||
diskMenuOffset = diskMenuSelection;
|
||||
if (diskMenuSelection > diskMenuOffset+4)
|
||||
diskMenuOffset = diskMenuSelection-4;
|
||||
|
||||
LcdGoto(0,0);
|
||||
LcdWrite(LCD_DATA, 0x7F);
|
||||
for (int i=0; i<19; i++)
|
||||
LcdWrite(LCD_DATA, 0x40);
|
||||
|
||||
LcdTinyStringFramed("Select Disk");
|
||||
|
||||
for (int i=0; i<19; i++)
|
||||
LcdWrite(LCD_DATA, 0x40);
|
||||
LcdWrite(LCD_DATA, 0x7F);
|
||||
|
||||
if (diskMenuEntryCount == 0)
|
||||
{
|
||||
LcdGoto(0, 1);
|
||||
LcdTinyString("no image files found", TEXT_NORMAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileEntry* pFileEntries = (FileEntry*)sectorBuf;
|
||||
|
||||
int row = 0;
|
||||
for (uint16_t i=diskMenuOffset; i<diskMenuOffset+5 && i<diskMenuEntryCount; i++)
|
||||
{
|
||||
bool selected = (i == diskMenuSelection);
|
||||
|
||||
LcdGoto(0, row+1);
|
||||
for (int j=0; j<LCD_WIDTH; j++)
|
||||
{
|
||||
LcdWrite(LCD_DATA, selected ? 0x7F : 0x00);
|
||||
}
|
||||
|
||||
// show the image name
|
||||
LcdGoto(1, row+1);
|
||||
LcdTinyString(pFileEntries[i].longName, selected ? TEXT_INVERSE : TEXT_NORMAL, LCD_WIDTH-1);
|
||||
|
||||
// draw a folder icon for subdirectories
|
||||
if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY ||
|
||||
pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||
{
|
||||
LcdGoto(73, row+1);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x22): 0x22);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x24): 0x24);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x24): 0x24);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C);
|
||||
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00);
|
||||
}
|
||||
|
||||
if (selected)
|
||||
{
|
||||
strncpy(selectedLongFile, pFileEntries[i].longName, FILENAME_LEN+1);
|
||||
strncpy(selectedFile, pFileEntries[i].shortName, SHORTFILENAME_LEN+1);
|
||||
selectedFileType = pFileEntries[i].imageFileType;
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
|
||||
// draw the scrollbar
|
||||
if (diskMenuEntryCount <= 5)
|
||||
{
|
||||
// no scrollbar
|
||||
for (uint8_t r=1; r<6; r++)
|
||||
{
|
||||
LcdGoto(82, r);
|
||||
LcdWrite(LCD_DATA, 0x00);
|
||||
LcdWrite(LCD_DATA, 0x00);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t barEnd = 8 + (uint16_t)39 * (diskMenuOffset + 5) / diskMenuEntryCount;
|
||||
uint8_t barSize = (uint16_t)39 * 5 / diskMenuEntryCount;
|
||||
uint8_t barStart = barEnd - barSize;
|
||||
|
||||
for (uint8_t r=1; r<6; r++)
|
||||
{
|
||||
LcdGoto(82, r);
|
||||
LcdWrite(LCD_DATA, 0x00);
|
||||
|
||||
uint8_t b = 0;
|
||||
for (uint8_t y=r*8; y<=r*8+7; y++)
|
||||
{
|
||||
if (y >= barStart && y <= barEnd)
|
||||
b = 0x80 | (b >> 1);
|
||||
else
|
||||
b = (b >> 1);
|
||||
}
|
||||
|
||||
LcdWrite(LCD_DATA, b);
|
||||
}
|
||||
}
|
||||
|
||||
// prevent moving selection past end of list
|
||||
if (diskMenuSelection >= diskMenuOffset + row)
|
||||
{
|
||||
diskMenuSelection = diskMenuOffset + row - 1;
|
||||
if (row == 4 && diskMenuOffset > 0)
|
||||
{
|
||||
diskMenuOffset--; // scroll backwards
|
||||
}
|
||||
DrawDiskMenu(sd); // draw again
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,471 +0,0 @@
|
||||
/*
|
||||
* floppy_emu_arduino.ino
|
||||
*
|
||||
* Created on: 2014/07/12
|
||||
* Author: sin
|
||||
*/
|
||||
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SdFat.h>
|
||||
|
||||
#include "portmacros.h"
|
||||
|
||||
#include "millitimer.h"
|
||||
#include "diskmenu.h"
|
||||
#include "noklcd.h"
|
||||
|
||||
#include "floppyemu.h"
|
||||
|
||||
SdFat sd;
|
||||
|
||||
void setup() {
|
||||
millitimerInit();
|
||||
ResetDiskState();
|
||||
|
||||
ShowVersion();
|
||||
|
||||
LcdClear();
|
||||
|
||||
sei();
|
||||
_delay_ms(100); // wait for pending interrupts??
|
||||
|
||||
millitimerOn();
|
||||
_delay_ms(100); // wait for pending interrupts??
|
||||
|
||||
// if select and next are both held down, enter contrast adjust mode
|
||||
if (bit_is_set(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) &&
|
||||
bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) &&
|
||||
bit_is_clear(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN))
|
||||
{
|
||||
AdjustContrast();
|
||||
}
|
||||
|
||||
//SdFat sd;
|
||||
if (!sd.init(SPI_FULL_SPEED))
|
||||
{
|
||||
snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData());
|
||||
error(textBuf);
|
||||
}
|
||||
|
||||
millitimerOff();
|
||||
|
||||
// if prev and next are both held down, enter firmware update mode
|
||||
if (bit_is_clear(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) &&
|
||||
bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) &&
|
||||
bit_is_set(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN))
|
||||
{
|
||||
PromptForFirmwareUpdate();
|
||||
}
|
||||
|
||||
InitDiskMenu(sd);
|
||||
DrawDiskMenu(sd);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// main loop
|
||||
void loop() {
|
||||
if (writeError)
|
||||
{
|
||||
// report error encounted in the interrupt routine
|
||||
error(textBuf);
|
||||
}
|
||||
|
||||
cli();
|
||||
uint8_t trackNumber = currentTrack; // save track in a local var, since currentTrack is volatile
|
||||
uint8_t sideNumber = currentSide; // save side in a local var, since currentSide is volatile
|
||||
restartDisk = false;
|
||||
sei();
|
||||
|
||||
if (diskInserted)
|
||||
{
|
||||
// show the current track and side
|
||||
snprintf(textBuf, TEXTBUF_SIZE, "%02d", trackNumber);
|
||||
LcdGoto(24,4);
|
||||
LcdTinyString(textBuf, TEXT_NORMAL);
|
||||
snprintf(textBuf, TEXTBUF_SIZE, "%d ", sideNumber);
|
||||
LcdGoto(56,4);
|
||||
LcdTinyString(textBuf, TEXT_NORMAL);
|
||||
|
||||
// sync RAM buffer with SD card when switching tracks, or also when switching sides for mfmMode
|
||||
if (prevTrack != trackNumber || (mfmMode && (prevSide != sideNumber)))
|
||||
{
|
||||
// write any dirty sectors from the previous track/side back to the SD card
|
||||
FlushDirtySectors(sd, prevTrack);
|
||||
prevTrack = trackNumber;
|
||||
prevSide = sideNumber;
|
||||
|
||||
// Also mark all the buffers on this track as invalid, since they don't contain valid data for the new track.
|
||||
for (uint8_t i=0; i<NUM_BUFFERS; i++)
|
||||
bufferState[i] &= ~BUFFER_DATA_VALID;
|
||||
}
|
||||
// continuously replay sectors from this track/side until interrupted
|
||||
while (!restartDisk)
|
||||
{
|
||||
if (writeMode)
|
||||
{
|
||||
// do nothing: incoming data is processed by the interrupt handler
|
||||
|
||||
// show write state
|
||||
LcdGoto(64,4);
|
||||
LcdTinyStringP(PSTR("Write"), TEXT_NORMAL);
|
||||
|
||||
while (!restartDisk)
|
||||
{
|
||||
}
|
||||
}
|
||||
else if (trackNumber <= 79)
|
||||
{
|
||||
uint8_t trackLen = trackLength(trackNumber);
|
||||
|
||||
// when stepping from a track with more sectors to one with fewer, current sector number could potentially
|
||||
// end up out of range
|
||||
if (currentSector >= trackLen)
|
||||
currentSector = 0;
|
||||
|
||||
bool prevMotorOn = !bit_is_clear(PIN(CPLD_STEP_DIR_MOTOR_ON_PORT), CPLD_STEP_DIR_MOTOR_ON_PIN);
|
||||
|
||||
while (true)
|
||||
{
|
||||
// check for disk eject
|
||||
if (bit_is_set(PIN(CPLD_EJECT_REQ_PORT), CPLD_EJECT_REQ_PIN))
|
||||
{
|
||||
PORT(CPLD_RD_READY_TK0_PORT) &= ~(1<<CPLD_RD_READY_TK0_PIN);
|
||||
PORT(CPLD_STEP_ACK_DISK_IN_PORT) |= (1<<CPLD_STEP_ACK_DISK_IN_PIN);
|
||||
diskInserted = false;
|
||||
|
||||
// write any dirty sectors from the current track
|
||||
FlushDirtySectors(sd, trackNumber);
|
||||
|
||||
_delay_ms(100);
|
||||
ResetDiskState();
|
||||
InitDiskMenu(sd);
|
||||
DrawDiskMenu(sd);
|
||||
|
||||
goto restart;
|
||||
}
|
||||
|
||||
// show read/idle state
|
||||
bool motorOn = bit_is_clear(PIN(CPLD_STEP_DIR_MOTOR_ON_PORT), CPLD_STEP_DIR_MOTOR_ON_PIN);
|
||||
|
||||
if (!motorOn)
|
||||
{
|
||||
// write any dirty sectors from the current track, when idle
|
||||
FlushDirtySectors(sd, trackNumber);
|
||||
}
|
||||
|
||||
if (prevMotorOn != motorOn)
|
||||
{
|
||||
prevMotorOn = motorOn;
|
||||
LcdGoto(64,4);
|
||||
if (motorOn)
|
||||
LcdTinyStringP(PSTR(" Read"), TEXT_NORMAL);
|
||||
else
|
||||
{
|
||||
LcdTinyStringP(PSTR(" Idle"), TEXT_NORMAL);
|
||||
// turn LED off when idle
|
||||
PORT(STATUS_LED_PORT) |= (1<<STATUS_LED_PIN);
|
||||
|
||||
writeDisplayTimer = 1; // clear old write alerts when going idle
|
||||
}
|
||||
}
|
||||
|
||||
// remove old write alerts when writeDisplayTimer reaches 1
|
||||
if (writeDisplayTimer == 1)
|
||||
{
|
||||
writeDisplayTimer = 0;
|
||||
LcdGoto(0,5);
|
||||
LcdTinyStringP(PSTR(" "), TEXT_NORMAL);
|
||||
}
|
||||
|
||||
uint8_t bufferNumber = mfmMode ? currentSector : (sideNumber * trackLen + currentSector);
|
||||
|
||||
bool shouldReadSector = false;
|
||||
|
||||
// atomic check and acquire of buffer lock
|
||||
cli();
|
||||
if ((bufferState[bufferNumber] & BUFFER_DATA_VALID) == 0 &&
|
||||
(bufferState[bufferNumber] & BUFFER_LOCKED) == 0)
|
||||
{
|
||||
// lock the buffer, so the Mac won't write to it while we're reading it from SD
|
||||
bufferState[bufferNumber] |= BUFFER_LOCKED;
|
||||
shouldReadSector = true;
|
||||
}
|
||||
sei();
|
||||
|
||||
// read the sector from the SD card, if necessary
|
||||
if (shouldReadSector)
|
||||
{
|
||||
uint32_t blockToRead = imageFirstBlock + ((uint32_t)trackStart(trackNumber) * numberOfDiskSides + sideNumber * trackLen + currentSector);
|
||||
|
||||
millitimerOn();
|
||||
|
||||
if (selectedFileIsDiskCopyFormat)
|
||||
{
|
||||
ReadDiskCopy42Block(sd, blockToRead, bufferNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sd.card()->readBlock(blockToRead, sectorBuf[bufferNumber]))
|
||||
error("SD read error R");
|
||||
}
|
||||
|
||||
millitimerOff();
|
||||
|
||||
bufferState[bufferNumber] |= BUFFER_DATA_VALID;
|
||||
bufferState[bufferNumber] &= ~BUFFER_LOCKED;
|
||||
}
|
||||
|
||||
if (currentSector == 0)
|
||||
{
|
||||
if (motorOn)
|
||||
{
|
||||
// toggle LED during drive activity
|
||||
PORT(STATUS_LED_PORT) ^= (1<<STATUS_LED_PIN);
|
||||
|
||||
if (writeDisplayTimer > 1)
|
||||
writeDisplayTimer--;
|
||||
}
|
||||
|
||||
// "Flutter" the drive's TACH speed slightly, every time we pass sector 0 (about every 100-150ms). This avoids a bug
|
||||
// in P_Sony_MakeSpdTbl in the 64K ROM (used in the Mac 128K and Mac 512K) where
|
||||
// the Mac will crash if two successive TACH measurements see the exact same speed.
|
||||
tachFlutter += 25;
|
||||
if (tachFlutter >= 125)
|
||||
tachFlutter = 0;
|
||||
|
||||
// Set the timeout. OC1A will toggle after this many counts. New timeout threshold won't take effect until the next timeout.
|
||||
OCR1A = driveTachHalfPeriod - tachFlutter;
|
||||
}
|
||||
|
||||
if (mfmMode)
|
||||
{
|
||||
// insert sector-to-sector gap bytes
|
||||
for (uint8_t i=0; i<50; i++)
|
||||
{
|
||||
SendMFMAndCheckRestart(0x4E);
|
||||
}
|
||||
|
||||
// insert sync bytes
|
||||
for (uint8_t i=0; i<12; i++)
|
||||
{
|
||||
SendMFMAndCheckRestart(0x00);
|
||||
}
|
||||
|
||||
// send the address block
|
||||
crc = 0xFFFF; // reset CRC
|
||||
SendMFMSync();
|
||||
SendMFMSync();
|
||||
SendMFMSync();
|
||||
SendMFMAndCheckRestart(0xFE);
|
||||
SendMFMAndCheckRestart(trackNumber);
|
||||
SendMFMAndCheckRestart(sideNumber);
|
||||
SendMFMAndCheckRestart(currentSector+1); // MFM sector numbers are 1-based
|
||||
SendMFMAndCheckRestart(2); // size = 128 * 2^N bytes, so 2 means 512
|
||||
uint8_t crc0 = (crc >> 8) & 0xFF;
|
||||
uint8_t crc1 = crc & 0xFF;
|
||||
SendMFMAndCheckRestart(crc0);
|
||||
SendMFMAndCheckRestart(crc1);
|
||||
|
||||
// insert Address to Data gap bytes
|
||||
for (uint8_t i=0; i<22; i++)
|
||||
{
|
||||
SendMFMAndCheckRestart(0x4E);
|
||||
}
|
||||
|
||||
// insert sync bytes
|
||||
for (uint8_t i=0; i<12; i++)
|
||||
{
|
||||
SendMFMAndCheckRestart(0x00);
|
||||
}
|
||||
|
||||
// send the data block
|
||||
crc = 0xFFFF; // reset CRC
|
||||
SendMFMSync();
|
||||
SendMFMSync();
|
||||
SendMFMSync();
|
||||
SendMFMAndCheckRestart(0xFB);
|
||||
|
||||
for (uint16_t i=0; i<SECTOR_DATA_SIZE; i++)
|
||||
{
|
||||
uint8_t d = sectorBuf[bufferNumber][i];
|
||||
SendMFMAndCheckRestart(d);
|
||||
}
|
||||
|
||||
crc0 = (crc >> 8) & 0xFF;
|
||||
crc1 = crc & 0xFF;
|
||||
SendMFMAndCheckRestart(crc0);
|
||||
SendMFMAndCheckRestart(crc1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ensure a short gap between sectors - otherwise once they're all cached, one sector will appear
|
||||
// to immediately follow another on disk, which may cause problems for the Mac.
|
||||
// Bad voodoo here:
|
||||
// 1. In the Finder StuffIt copy test that sometimes dies after the first 18 tracks, the length of delay here
|
||||
// seems to affect what track it will freeze on.
|
||||
// 2. With a longer delay here, the first ~10 sectors of copying seem to have fewer or no "long writes".
|
||||
// 3. Depending on the delay here, the Transcend 2GB SD card sometimes gets "writeStop fail" when saving tracks.
|
||||
for (uint16_t i=0; i<INTER_SECTOR_GAP_SIZE; i++)
|
||||
{
|
||||
SendByteAndCheckRestart(0xFF);
|
||||
}
|
||||
|
||||
// send the address block
|
||||
uint8_t format = (numberOfDiskSides == 2) ? 0x22 : 0x02; // 0x22 = MacOS double-sided, 0x02 = single sided
|
||||
uint8_t trackLow = (uint8_t)(trackNumber & 0x3F);
|
||||
uint8_t trackHigh = (uint8_t)((sideNumber << 5) | (trackNumber >> 6));
|
||||
uint8_t checksum = (uint8_t)((trackLow ^ currentSector ^ trackHigh ^ format) & 0x3F);
|
||||
|
||||
SendByteAndCheckRestart(0xD5);
|
||||
SendByteAndCheckRestart(0xAA);
|
||||
SendByteAndCheckRestart(0x96);
|
||||
SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[trackLow]));
|
||||
SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[currentSector]));
|
||||
SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[trackHigh]));
|
||||
SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[format]));
|
||||
SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[checksum]));
|
||||
SendByteAndCheckRestart(0xDE);
|
||||
SendByteAndCheckRestart(0xAA);
|
||||
|
||||
// insert sync bytes between the address and data blocks
|
||||
for (uint8_t i=0; i<ADDRESS_DATA_GAP_SIZE; i++)
|
||||
{
|
||||
SendByteAndCheckRestart(0xFF);
|
||||
}
|
||||
|
||||
// send the data block
|
||||
SendByteAndCheckRestart(0xD5);
|
||||
SendByteAndCheckRestart(0xAA);
|
||||
SendByteAndCheckRestart(0xAD);
|
||||
SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[currentSector]));
|
||||
|
||||
SendGCRSectorData((const uint8_t*)sectorBuf[bufferNumber]);
|
||||
|
||||
SendByteAndCheckRestart(0xDE);
|
||||
SendByteAndCheckRestart(0xAA);
|
||||
SendByteAndCheckRestart(0xFF);
|
||||
}
|
||||
|
||||
currentSector = NextInterleavedSector(trackNumber, currentSector);
|
||||
}
|
||||
}
|
||||
}
|
||||
restart:
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!restartDisk)
|
||||
{
|
||||
// check for disk eject. This shouldn't normally happen, but if the CPLD and AVR get out of sync
|
||||
// and the CPLD thinks there's a disk while the AVR doesn't, it could.
|
||||
// But don't do this is ALL the CPLD inputs are asserted - that means you're probably midway
|
||||
// through building the hardware, and the CPLD isn't there yet.
|
||||
if (bit_is_set(PIN(CPLD_EJECT_REQ_PORT), CPLD_EJECT_REQ_PIN) &&
|
||||
!(bit_is_set(PIN(CPLD_RD_ACK_WR_TICK_PORT), CPLD_RD_ACK_WR_TICK_PIN) &&
|
||||
bit_is_set(PIN(CPLD_STEP_REQ_PORT), CPLD_STEP_REQ_PIN) &&
|
||||
bit_is_set(PIN(CPLD_WR_REQ_PORT), CPLD_WR_REQ_PIN) &&
|
||||
bit_is_set(PIN(CPLD_CURRENT_SIDE_PORT), CPLD_CURRENT_SIDE_PIN)))
|
||||
{
|
||||
// reboot
|
||||
((void(*)(void))0)();
|
||||
}
|
||||
|
||||
if (bit_is_clear(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN))
|
||||
{
|
||||
if (diskMenuSelection > 0)
|
||||
{
|
||||
diskMenuSelection--;
|
||||
DrawDiskMenu(sd);
|
||||
_delay_ms(200);
|
||||
}
|
||||
}
|
||||
else if (bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN))
|
||||
{
|
||||
diskMenuSelection++;
|
||||
DrawDiskMenu(sd);
|
||||
_delay_ms(200);
|
||||
}
|
||||
else if (bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN))
|
||||
{
|
||||
if (selectedFileType == DISK_IMAGE_DIRECTORY)
|
||||
{
|
||||
// remember where we came from, so we can get back later
|
||||
char* pSubdirName = ((char*)sectorBuf[23]) + ((SHORTFILENAME_LEN+1) * subdirDepth);
|
||||
strncpy(pSubdirName, selectedFile, SHORTFILENAME_LEN+1);
|
||||
subdirDepth++;
|
||||
|
||||
sd.chdir(selectedFile, true);
|
||||
|
||||
diskMenuSelection = 0;
|
||||
LcdClear();
|
||||
InitDiskMenu(sd);
|
||||
DrawDiskMenu(sd);
|
||||
_delay_ms(400);
|
||||
}
|
||||
else if (selectedFileType == DISK_IMAGE_UP_DIRECTORY)
|
||||
{
|
||||
subdirDepth--;
|
||||
sd.chdir(true); // go to root directory
|
||||
|
||||
for (uint8_t i=0; i<subdirDepth; i++)
|
||||
{
|
||||
char* pSubdirName = ((char*)sectorBuf[23]) + ((SHORTFILENAME_LEN+1) * i);
|
||||
sd.chdir(pSubdirName, true);
|
||||
}
|
||||
|
||||
diskMenuSelection = 0;
|
||||
LcdClear();
|
||||
InitDiskMenu(sd);
|
||||
DrawDiskMenu(sd);
|
||||
_delay_ms(400);
|
||||
}
|
||||
else
|
||||
{
|
||||
// enable the interrupts
|
||||
PCICR |= (1<<CPLD_STEP_REQ_INT_ENABLE);
|
||||
PCICR |= (1<<CPLD_CURRENT_SIDE_INT_ENABLE);
|
||||
PCICR |= (1<<CPLD_WR_REQ_INT_ENABLE);
|
||||
PCICR |= (1<<CPLD_RD_ACK_WR_TICK_INT_ENABLE);
|
||||
|
||||
currentTrack = 0;
|
||||
LcdReset(); // also resets the CPLD, ensures it knows we're now at track 0
|
||||
LcdClear();
|
||||
|
||||
// "insert" the disk
|
||||
if (OpenImageFile())
|
||||
{
|
||||
// tell the CPLD whether the disk is read-only (bit 0, active low)
|
||||
uint8_t configByte = 0;
|
||||
|
||||
if (!readOnly)
|
||||
configByte |= 0x01;
|
||||
|
||||
if (!mfmMode)
|
||||
configByte |= 0x02;
|
||||
|
||||
PORT(CPLD_DATA_PORT) = configByte;
|
||||
// asserting RD_READY without DISK_IN causes the CPLD to load config options from the data bus
|
||||
PORT(CPLD_RD_READY_TK0_PORT) |= (1<<CPLD_RD_READY_TK0_PIN);
|
||||
_delay_ms(1);
|
||||
PORT(CPLD_RD_READY_TK0_PORT) &= ~(1<<CPLD_RD_READY_TK0_PIN);
|
||||
_delay_us(10);
|
||||
|
||||
// tell the CPLD there is a disk
|
||||
PORT(CPLD_STEP_ACK_DISK_IN_PORT) &= ~(1<<CPLD_STEP_ACK_DISK_IN_PIN);
|
||||
diskInserted = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* floppyemu.h
|
||||
*
|
||||
* Created on: 2014/07/12
|
||||
* Author: sin
|
||||
*/
|
||||
|
||||
#ifndef FLOPPYEMU_H_
|
||||
#define FLOPPYEMU_H_
|
||||
|
||||
// I/O pin assignments
|
||||
#define CPLD_RESET_PORT B
|
||||
#define CPLD_RESET_PIN 0
|
||||
|
||||
#define CPLD_STEP_DIR_MOTOR_ON_PORT C
|
||||
#define CPLD_STEP_DIR_MOTOR_ON_PIN 7
|
||||
|
||||
#define CPLD_STEP_REQ_PORT D
|
||||
#define CPLD_STEP_REQ_PIN 0 // PCINT24
|
||||
#define CPLD_STEP_REQ_INT_MSK PCMSK3
|
||||
#define CPLD_STEP_REQ_INT_PIN PCINT24
|
||||
#define CPLD_STEP_REQ_INT_ENABLE PCIE3
|
||||
|
||||
#define CPLD_CURRENT_SIDE_PORT C
|
||||
#define CPLD_CURRENT_SIDE_PIN 1 // PCINT17
|
||||
#define CPLD_CURRENT_SIDE_INT_MSK PCMSK2
|
||||
#define CPLD_CURRENT_SIDE_INT_PIN PCINT17
|
||||
#define CPLD_CURRENT_SIDE_INT_ENABLE PCIE2
|
||||
|
||||
#define CPLD_EJECT_REQ_PORT D
|
||||
#define CPLD_EJECT_REQ_PIN 3
|
||||
|
||||
#define CPLD_STEP_ACK_DISK_IN_PORT C
|
||||
#define CPLD_STEP_ACK_DISK_IN_PIN 2
|
||||
|
||||
#define CPLD_WR_REQ_PORT C
|
||||
#define CPLD_WR_REQ_PIN 0 // PCINT16
|
||||
#define CPLD_WR_REQ_INT_MSK PCMSK2
|
||||
#define CPLD_WR_REQ_INT_PIN PCINT16
|
||||
#define CPLD_WR_REQ_INT_ENABLE PCIE2
|
||||
|
||||
#define CPLD_RD_READY_TK0_PORT C
|
||||
#define CPLD_RD_READY_TK0_PIN 5
|
||||
|
||||
#define CPLD_RD_ACK_WR_TICK_PORT A
|
||||
#define CPLD_RD_ACK_WR_TICK_PIN 7 // PCINT7
|
||||
#define CPLD_RD_ACK_WR_TICK_INT_MSK PCMSK0
|
||||
#define CPLD_RD_ACK_WR_TICK_INT_PIN PCINT7
|
||||
#define CPLD_RD_ACK_WR_TICK_INT_ENABLE PCIE0
|
||||
|
||||
#define CPLD_DATA_PORT A
|
||||
|
||||
#define CPLD_DATA_HIZ_PORT C
|
||||
#define CPLD_DATA_HIZ_PIN 6
|
||||
|
||||
#define CPLD_TACH_PORT D
|
||||
#define CPLD_TACH_PIN 5
|
||||
|
||||
#define CPLD_TMS_PORT C
|
||||
#define CPLD_TMS_PIN 3
|
||||
|
||||
#define SELECT_BUTTON_PORT D
|
||||
#define SELECT_BUTTON_PIN 4
|
||||
|
||||
#define PREV_BUTTON_PORT D
|
||||
#define PREV_BUTTON_PIN 1
|
||||
|
||||
#define NEXT_BUTTON_PORT D
|
||||
#define NEXT_BUTTON_PIN 2
|
||||
|
||||
#define STATUS_LED_PORT B
|
||||
#define STATUS_LED_PIN 3
|
||||
|
||||
#define CARD_WPROT_PORT D
|
||||
#define CARD_WPROT_PIN 7
|
||||
|
||||
// global variables predefinitions
|
||||
|
||||
#define TEXTBUF_SIZE 22
|
||||
char textBuf[TEXTBUF_SIZE];
|
||||
|
||||
volatile uint8_t currentTrack;
|
||||
volatile uint8_t prevTrack;
|
||||
volatile uint8_t currentSide;
|
||||
volatile uint8_t prevSide;
|
||||
volatile uint8_t writeMode;
|
||||
volatile bool restartDisk;
|
||||
volatile bool writeError;
|
||||
|
||||
bool diskInserted;
|
||||
bool readOnly;
|
||||
bool mfmMode;
|
||||
uint16_t crc;
|
||||
uint8_t numberOfDiskSides;
|
||||
uint8_t currentSector;
|
||||
uint16_t driveTachHalfPeriod;
|
||||
uint8_t tachFlutter;
|
||||
|
||||
uint8_t writeDisplayTimer;
|
||||
uint8_t cpldFirmwareVersion;
|
||||
|
||||
// public functions predefinitions
|
||||
|
||||
void ResetDiskState();
|
||||
void ShowVersion();
|
||||
void AdjustContrast(void);
|
||||
void error(const char* msg);
|
||||
void PromptForFirmwareUpdate();
|
||||
|
||||
#endif /* FLOPPYEMU_H_ */
|
@ -306,7 +306,7 @@ void LcdClear(void)
|
||||
|
||||
void LcdReset(void)
|
||||
{
|
||||
lcd_vop = 0xBF;
|
||||
lcd_vop = 0xa4; //0xBF;
|
||||
lcd_bias = 0x14;
|
||||
lcd_tempCoef = 0x04;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user