floppyemu/floppy_emu_arduino

This commit is contained in:
Sin Shimozono 2014-07-15 08:48:56 +09:00
parent 0a8a67e352
commit b58b3da080
28 changed files with 386 additions and 2632 deletions

View File

@ -1,7 +1,8 @@
avrtarget/ClockFrequency=16000000 avrtarget/ClockFrequency=16000000
avrtarget/ExtRAMSize=0 avrtarget/ExtRAMSize=0
avrtarget/ExtendedRAM=false avrtarget/ExtendedRAM=false
avrtarget/MCUType=atmega1284p avrtarget/MCUType=atmega2560
avrtarget/UseEEPROM=false avrtarget/UseEEPROM=false
avrtarget/UseExtendedRAMforHeap=true avrtarget/UseExtendedRAMforHeap=true
avrtarget/perConfig=false
eclipse.preferences.version=1 eclipse.preferences.version=1

View File

@ -4,5 +4,4 @@ avrtarget/ExtendedRAM=false
avrtarget/MCUType=atmega1284p avrtarget/MCUType=atmega1284p
avrtarget/UseEEPROM=false avrtarget/UseEEPROM=false
avrtarget/UseExtendedRAMforHeap=true avrtarget/UseExtendedRAMforHeap=true
avrtarget/perConfig=false
eclipse.preferences.version=1 eclipse.preferences.version=1

View File

@ -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}}

View File

@ -1,21 +1,16 @@
eclipse.preferences.version=1 eclipse.preferences.version=1
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/LANG/delimiter=\: environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/LANG/delimiter=\:
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/LANG/operation=append environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/LANG/operation=append
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/LANG/value=en-US environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/LANG/value=en-US
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/append=true environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/append=true
environment/project/de.innot.avreclipse.configuration.app.debug.225132627/appendContributed=true environment/project/de.innot.avreclipse.configuration.app.debug.1718737082/appendContributed=true
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/LANG/delimiter=\: environment/project/de.innot.avreclipse.configuration.app.debug.674828633/LANG/delimiter=\:
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/LANG/operation=append environment/project/de.innot.avreclipse.configuration.app.debug.674828633/LANG/operation=append
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/LANG/value=en-US environment/project/de.innot.avreclipse.configuration.app.debug.674828633/LANG/value=en-US
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/append=true environment/project/de.innot.avreclipse.configuration.app.debug.674828633/append=true
environment/project/de.innot.avreclipse.configuration.app.debug.276225876/appendContributed=true environment/project/de.innot.avreclipse.configuration.app.debug.674828633/appendContributed=true
environment/project/de.innot.avreclipse.configuration.app.release.472085903/LANG/delimiter=\: environment/project/de.innot.avreclipse.configuration.app.release.1024470171/LANG/delimiter=\:
environment/project/de.innot.avreclipse.configuration.app.release.472085903/LANG/operation=append environment/project/de.innot.avreclipse.configuration.app.release.1024470171/LANG/operation=append
environment/project/de.innot.avreclipse.configuration.app.release.472085903/LANG/value=en-US environment/project/de.innot.avreclipse.configuration.app.release.1024470171/LANG/value=en-US
environment/project/de.innot.avreclipse.configuration.app.release.472085903/append=true environment/project/de.innot.avreclipse.configuration.app.release.1024470171/append=true
environment/project/de.innot.avreclipse.configuration.app.release.472085903/appendContributed=true environment/project/de.innot.avreclipse.configuration.app.release.1024470171/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

View File

@ -38,7 +38,6 @@
#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];})) #define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];}))
#endif #endif
#define STATUS_LED_PORT B #define STATUS_LED_PORT B
#define STATUS_LED_PIN 3 #define STATUS_LED_PIN 3

736
floppy_emu_arduino/diskmenu.cpp Normal file → Executable file
View File

@ -1,368 +1,368 @@
/* /*
Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved. 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 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 license. (CC BY-NC 3.0) The terms of the license may be viewed at
http://creativecommons.org/licenses/by-nc/3.0/ http://creativecommons.org/licenses/by-nc/3.0/
Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/ 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 Permissions beyond the scope of this license may be available at www.bigmessowires.com
or from mailto:steve@bigmessowires.com. or from mailto:steve@bigmessowires.com.
*/ */
#include <math.h> #include <math.h>
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
#include <util/atomic.h> #include <util/atomic.h>
#include <util/delay.h> #include <util/delay.h>
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "diskmenu.h" #include "diskmenu.h"
#include "SdFat.h" #include "SdFat.h"
#include "SdBaseFile.h" #include "SdBaseFile.h"
#include "noklcd.h" #include "noklcd.h"
#define SECTORBUF_SIZE (23 * 512) // use the 24th buffer for directory breadcrumbs #define SECTORBUF_SIZE (23 * 512) // use the 24th buffer for directory breadcrumbs
extern uint8_t sectorBuf[24][512]; extern uint8_t sectorBuf[24][512];
extern uint8_t extraBuf[512]; extern uint8_t extraBuf[512];
typedef struct FileEntry typedef struct FileEntry
{ {
char longName[FILENAME_LEN+1]; char longName[FILENAME_LEN+1];
char shortName[SHORTFILENAME_LEN+1]; char shortName[SHORTFILENAME_LEN+1];
eImageType imageFileType; eImageType imageFileType;
} FileEntry; } FileEntry;
bool dirLfnNext(SdFat& sd, dir_t& dir, char* lfn) 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 offset[] = {1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30};
uint8_t lfnIn = 130; uint8_t lfnIn = 130;
uint8_t i; uint8_t i;
uint8_t ndir=0; uint8_t ndir=0;
uint8_t sum; uint8_t sum;
uint8_t test=0; uint8_t test=0;
bool haveLong = false; bool haveLong = false;
while( sd.vwd()->read( &dir, 32 ) == 32 ) while( sd.vwd()->read( &dir, 32 ) == 32 )
{ {
if( DIR_IS_LONG_NAME( &dir ) ) if( DIR_IS_LONG_NAME( &dir ) )
{ {
if( ! haveLong ) if( ! haveLong )
{ {
if(( dir.name[0] & 0XE0 ) != 0X40 ) if(( dir.name[0] & 0XE0 ) != 0X40 )
continue; continue;
ndir = dir.name[0] & 0X1F; ndir = dir.name[0] & 0X1F;
test = dir.creationTimeTenths; test = dir.creationTimeTenths;
haveLong = true; haveLong = true;
lfnIn = 130; lfnIn = 130;
lfn[ lfnIn ] = 0; lfn[ lfnIn ] = 0;
} }
else if( dir.name[0] != --ndir || test != dir.creationTimeTenths ) else if( dir.name[0] != --ndir || test != dir.creationTimeTenths )
{ {
haveLong = false; haveLong = false;
continue; continue;
} }
char *p = (char*) & dir; char *p = (char*) & dir;
if( lfnIn > 0 ) if( lfnIn > 0 )
{ {
lfnIn -= 13; lfnIn -= 13;
for( i = 0; i < 13; i++ ) for( i = 0; i < 13; i++ )
lfn[lfnIn + i] = p[offset[i]]; lfn[lfnIn + i] = p[offset[i]];
} }
} }
else if( DIR_IS_FILE_OR_SUBDIR( &dir ) else if( DIR_IS_FILE_OR_SUBDIR( &dir )
&& dir.name[0] != DIR_NAME_DELETED && dir.name[0] != DIR_NAME_DELETED
&& dir.name[0] != DIR_NAME_FREE && dir.name[0] != DIR_NAME_FREE
&& dir.name[0] != '.') && dir.name[0] != '.')
{ {
if( haveLong ) if( haveLong )
{ {
for( sum = i = 0; i < 11; i++ ) for( sum = i = 0; i < 11; i++ )
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir.name[i]; sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir.name[i];
if( sum != test || ndir != 1 ) if( sum != test || ndir != 1 )
haveLong = false; haveLong = false;
} }
if( haveLong ) if( haveLong )
{ {
for( i = 0; lfnIn + i <= 130 ; i++ ) for( i = 0; lfnIn + i <= 130 ; i++ )
lfn[i] = lfn[lfnIn + i]; lfn[i] = lfn[lfnIn + i];
return true; return true;
} }
// else if( dir.reservedNT ) // else if( dir.reservedNT )
// return "Reserved NT"; // return "Reserved NT";
else else
{ {
SdBaseFile::dirName( dir, lfn ); SdBaseFile::dirName( dir, lfn );
return true; return true;
} }
} }
else else
{ {
if( dir.name[0] == DIR_NAME_FREE ) if( dir.name[0] == DIR_NAME_FREE )
break; break;
haveLong = false; haveLong = false;
} }
} }
lfn[ 0 ] = 0; lfn[ 0 ] = 0;
return false; return false;
} }
eImageType DiskImageFileType(dir_t& dir, const char *filename) eImageType DiskImageFileType(dir_t& dir, const char *filename)
{ {
if (filename[0] == '.') if (filename[0] == '.')
return DISK_IMAGE_NONE; return DISK_IMAGE_NONE;
if (DIR_IS_SUBDIR(&dir)) if (DIR_IS_SUBDIR(&dir))
return DISK_IMAGE_DIRECTORY; return DISK_IMAGE_DIRECTORY;
if (!DIR_IS_FILE(&dir)) if (!DIR_IS_FILE(&dir))
return DISK_IMAGE_NONE; return DISK_IMAGE_NONE;
uint32_t size = dir.fileSize; uint32_t size = dir.fileSize;
if (size == (unsigned long)1024 * 400) if (size == (unsigned long)1024 * 400)
return DISK_IMAGE_400K; return DISK_IMAGE_400K;
else if (size == (unsigned long)1024 * 800) else if (size == (unsigned long)1024 * 800)
return DISK_IMAGE_800K; return DISK_IMAGE_800K;
else if (size == (unsigned long)1024 * 1440) else if (size == (unsigned long)1024 * 1440)
return DISK_IMAGE_1440K; return DISK_IMAGE_1440K;
else if (size > (unsigned long)1024 * 400 && else if (size > (unsigned long)1024 * 400 &&
size < (unsigned long)1024 * 1500) size < (unsigned long)1024 * 1500)
{ {
// get the 8.3 filename // get the 8.3 filename
char shortName[SHORTFILENAME_LEN+1]; char shortName[SHORTFILENAME_LEN+1];
SdBaseFile::dirName(dir, shortName); SdBaseFile::dirName(dir, shortName);
// read the first sector of the file // read the first sector of the file
SdBaseFile f; SdBaseFile f;
if (f.open(shortName, O_RDONLY)) if (f.open(shortName, O_RDONLY))
{ {
f.read(extraBuf, 512); f.read(extraBuf, 512);
f.close(); f.close();
// is it a DiskCopy 4.2 image? // is it a DiskCopy 4.2 image?
if (extraBuf[0x52] == 0x01 && if (extraBuf[0x52] == 0x01 &&
extraBuf[0x53] == 0x00) extraBuf[0x53] == 0x00)
{ {
size = ((unsigned long)extraBuf[0x41] * 65536 + (unsigned long)extraBuf[0x42] * 256 + (unsigned long)extraBuf[0x43]) / 1024; size = ((unsigned long)extraBuf[0x41] * 65536 + (unsigned long)extraBuf[0x42] * 256 + (unsigned long)extraBuf[0x43]) / 1024;
if (size == 400) if (size == 400)
return DISK_IMAGE_DISKCOPY_400K; return DISK_IMAGE_DISKCOPY_400K;
else if (size == 800) else if (size == 800)
return DISK_IMAGE_DISKCOPY_800K; return DISK_IMAGE_DISKCOPY_800K;
else if (size == 1440) else if (size == 1440)
return DISK_IMAGE_DISKCOPY_1440K; return DISK_IMAGE_DISKCOPY_1440K;
} }
} }
} }
return DISK_IMAGE_NONE; return DISK_IMAGE_NONE;
} }
uint16_t diskMenuEntryCount; uint16_t diskMenuEntryCount;
uint16_t diskMenuOffset = 0; uint16_t diskMenuOffset = 0;
uint16_t diskMenuSelection = 0; uint16_t diskMenuSelection = 0;
char selectedFile[FILENAME_LEN+1]; char selectedFile[FILENAME_LEN+1];
char selectedLongFile[FILENAME_LEN+1]; char selectedLongFile[FILENAME_LEN+1];
eImageType selectedFileType; eImageType selectedFileType;
uint8_t subdirDepth = 0; uint8_t subdirDepth = 0;
#define LONGFILENAME_LEN 130 #define LONGFILENAME_LEN 130
void InitDiskMenu(SdFat& sd) void InitDiskMenu(SdFat& sd)
{ {
dir_t dir; dir_t dir;
char name[LONGFILENAME_LEN+1]; char name[LONGFILENAME_LEN+1];
diskMenuEntryCount = 0; diskMenuEntryCount = 0;
// use the sector buffers to hold the filenames // use the sector buffers to hold the filenames
uint16_t maxEntries = SECTORBUF_SIZE / sizeof(FileEntry); uint16_t maxEntries = SECTORBUF_SIZE / sizeof(FileEntry);
FileEntry* pFileEntries = (FileEntry*)sectorBuf; FileEntry* pFileEntries = (FileEntry*)sectorBuf;
sd.vwd()->rewind(); sd.vwd()->rewind();
while (dirLfnNext(sd, dir, name) && diskMenuEntryCount < maxEntries) while (dirLfnNext(sd, dir, name) && diskMenuEntryCount < maxEntries)
{ {
eImageType imageType; eImageType imageType;
if ((imageType = DiskImageFileType(dir, name)) != DISK_IMAGE_NONE) if ((imageType = DiskImageFileType(dir, name)) != DISK_IMAGE_NONE)
{ {
strncpy(pFileEntries[diskMenuEntryCount].longName, name, FILENAME_LEN+1); strncpy(pFileEntries[diskMenuEntryCount].longName, name, FILENAME_LEN+1);
SdBaseFile::dirName(dir, pFileEntries[diskMenuEntryCount].shortName); SdBaseFile::dirName(dir, pFileEntries[diskMenuEntryCount].shortName);
pFileEntries[diskMenuEntryCount].imageFileType = imageType; pFileEntries[diskMenuEntryCount].imageFileType = imageType;
diskMenuEntryCount++; diskMenuEntryCount++;
} }
} }
// add up directory, if not at the root // add up directory, if not at the root
if (!sd.vwd()->isRoot()) if (!sd.vwd()->isRoot())
{ {
strncpy(pFileEntries[diskMenuEntryCount].longName, "..", FILENAME_LEN+1); strncpy(pFileEntries[diskMenuEntryCount].longName, "..", FILENAME_LEN+1);
strncpy(pFileEntries[diskMenuEntryCount].shortName, "..", SHORTFILENAME_LEN+1); strncpy(pFileEntries[diskMenuEntryCount].shortName, "..", SHORTFILENAME_LEN+1);
pFileEntries[diskMenuEntryCount].imageFileType = DISK_IMAGE_UP_DIRECTORY; pFileEntries[diskMenuEntryCount].imageFileType = DISK_IMAGE_UP_DIRECTORY;
diskMenuEntryCount++; diskMenuEntryCount++;
} }
char file1[FILENAME_LEN+1], file2[FILENAME_LEN+1], temp[FILENAME_LEN+1]; char file1[FILENAME_LEN+1], file2[FILENAME_LEN+1], temp[FILENAME_LEN+1];
eImageType tempType; eImageType tempType;
// sort the names by longname // sort the names by longname
for (uint16_t i=0; i<diskMenuEntryCount; i++) for (uint16_t i=0; i<diskMenuEntryCount; i++)
{ {
for (uint16_t j=i+1; j<diskMenuEntryCount; j++) for (uint16_t j=i+1; j<diskMenuEntryCount; j++)
{ {
// convert filenames to upper case, for comparison purposes // convert filenames to upper case, for comparison purposes
strncpy(file1, pFileEntries[i].longName, FILENAME_LEN+1); strncpy(file1, pFileEntries[i].longName, FILENAME_LEN+1);
for (uint8_t x=0; x<strlen(file1); x++) for (uint8_t x=0; x<strlen(file1); x++)
file1[x] = toupper(file1[x]); file1[x] = toupper(file1[x]);
strncpy(file2, pFileEntries[j].longName, FILENAME_LEN+1); strncpy(file2, pFileEntries[j].longName, FILENAME_LEN+1);
for (uint8_t x=0; x<strlen(file2); x++) for (uint8_t x=0; x<strlen(file2); x++)
file2[x] = toupper(file2[x]); file2[x] = toupper(file2[x]);
// sort directories before regular files // sort directories before regular files
int diff = strncmp(file1, file2, FILENAME_LEN+1); int diff = strncmp(file1, file2, FILENAME_LEN+1);
if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY || if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY ||
pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY) pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY)
diff -= 1000; diff -= 1000;
if (pFileEntries[j].imageFileType == DISK_IMAGE_DIRECTORY || if (pFileEntries[j].imageFileType == DISK_IMAGE_DIRECTORY ||
pFileEntries[j].imageFileType == DISK_IMAGE_UP_DIRECTORY) pFileEntries[j].imageFileType == DISK_IMAGE_UP_DIRECTORY)
diff += 1000; diff += 1000;
// if file1 > file2, swap them // if file1 > file2, swap them
if (diff > 0) if (diff > 0)
{ {
strncpy(temp, pFileEntries[i].longName, FILENAME_LEN+1); strncpy(temp, pFileEntries[i].longName, FILENAME_LEN+1);
strncpy(pFileEntries[i].longName, pFileEntries[j].longName, FILENAME_LEN+1); strncpy(pFileEntries[i].longName, pFileEntries[j].longName, FILENAME_LEN+1);
strncpy(pFileEntries[j].longName, temp, FILENAME_LEN+1); strncpy(pFileEntries[j].longName, temp, FILENAME_LEN+1);
strncpy(temp, pFileEntries[i].shortName, SHORTFILENAME_LEN+1); strncpy(temp, pFileEntries[i].shortName, SHORTFILENAME_LEN+1);
strncpy(pFileEntries[i].shortName, pFileEntries[j].shortName, SHORTFILENAME_LEN+1); strncpy(pFileEntries[i].shortName, pFileEntries[j].shortName, SHORTFILENAME_LEN+1);
strncpy(pFileEntries[j].shortName, temp, SHORTFILENAME_LEN+1); strncpy(pFileEntries[j].shortName, temp, SHORTFILENAME_LEN+1);
tempType = pFileEntries[i].imageFileType; tempType = pFileEntries[i].imageFileType;
pFileEntries[i].imageFileType = pFileEntries[j].imageFileType; pFileEntries[i].imageFileType = pFileEntries[j].imageFileType;
pFileEntries[j].imageFileType = tempType; pFileEntries[j].imageFileType = tempType;
} }
} }
} }
} }
void DrawDiskMenu(SdFat& sd) void DrawDiskMenu(SdFat& sd)
{ {
// scroll menu if necessary // scroll menu if necessary
if (diskMenuSelection < diskMenuOffset) if (diskMenuSelection < diskMenuOffset)
diskMenuOffset = diskMenuSelection; diskMenuOffset = diskMenuSelection;
if (diskMenuSelection > diskMenuOffset+4) if (diskMenuSelection > diskMenuOffset+4)
diskMenuOffset = diskMenuSelection-4; diskMenuOffset = diskMenuSelection-4;
LcdGoto(0,0); LcdGoto(0,0);
LcdWrite(LCD_DATA, 0x7F); LcdWrite(LCD_DATA, 0x7F);
for (int i=0; i<19; i++) for (int i=0; i<19; i++)
LcdWrite(LCD_DATA, 0x40); LcdWrite(LCD_DATA, 0x40);
LcdTinyStringFramed("Select Disk"); LcdTinyStringFramed("Select Disk");
for (int i=0; i<19; i++) for (int i=0; i<19; i++)
LcdWrite(LCD_DATA, 0x40); LcdWrite(LCD_DATA, 0x40);
LcdWrite(LCD_DATA, 0x7F); LcdWrite(LCD_DATA, 0x7F);
if (diskMenuEntryCount == 0) if (diskMenuEntryCount == 0)
{ {
LcdGoto(0, 1); LcdGoto(0, 1);
LcdTinyString("no image files found", TEXT_NORMAL); LcdTinyString("no image files found", TEXT_NORMAL);
} }
else else
{ {
FileEntry* pFileEntries = (FileEntry*)sectorBuf; FileEntry* pFileEntries = (FileEntry*)sectorBuf;
int row = 0; int row = 0;
for (uint16_t i=diskMenuOffset; i<diskMenuOffset+5 && i<diskMenuEntryCount; i++) for (uint16_t i=diskMenuOffset; i<diskMenuOffset+5 && i<diskMenuEntryCount; i++)
{ {
bool selected = (i == diskMenuSelection); bool selected = (i == diskMenuSelection);
LcdGoto(0, row+1); LcdGoto(0, row+1);
for (int j=0; j<LCD_WIDTH; j++) for (int j=0; j<LCD_WIDTH; j++)
{ {
LcdWrite(LCD_DATA, selected ? 0x7F : 0x00); LcdWrite(LCD_DATA, selected ? 0x7F : 0x00);
} }
// show the image name // show the image name
LcdGoto(1, row+1); LcdGoto(1, row+1);
LcdTinyString(pFileEntries[i].longName, selected ? TEXT_INVERSE : TEXT_NORMAL, LCD_WIDTH-1); LcdTinyString(pFileEntries[i].longName, selected ? TEXT_INVERSE : TEXT_NORMAL, LCD_WIDTH-1);
// draw a folder icon for subdirectories // draw a folder icon for subdirectories
if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY || if (pFileEntries[i].imageFileType == DISK_IMAGE_DIRECTORY ||
pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY) pFileEntries[i].imageFileType == DISK_IMAGE_UP_DIRECTORY)
{ {
LcdGoto(73, row+1); LcdGoto(73, row+1);
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00); LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00);
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C); 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 ^ 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 ^ 0x24): 0x24); LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x24): 0x24);
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C); LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x3C): 0x3C);
LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00); LcdWrite(LCD_DATA, selected ? (0x7F ^ 0x00): 0x00);
} }
if (selected) if (selected)
{ {
strncpy(selectedLongFile, pFileEntries[i].longName, FILENAME_LEN+1); strncpy(selectedLongFile, pFileEntries[i].longName, FILENAME_LEN+1);
strncpy(selectedFile, pFileEntries[i].shortName, SHORTFILENAME_LEN+1); strncpy(selectedFile, pFileEntries[i].shortName, SHORTFILENAME_LEN+1);
selectedFileType = pFileEntries[i].imageFileType; selectedFileType = pFileEntries[i].imageFileType;
} }
row++; row++;
} }
// draw the scrollbar // draw the scrollbar
if (diskMenuEntryCount <= 5) if (diskMenuEntryCount <= 5)
{ {
// no scrollbar // no scrollbar
for (uint8_t r=1; r<6; r++) for (uint8_t r=1; r<6; r++)
{ {
LcdGoto(82, r); LcdGoto(82, r);
LcdWrite(LCD_DATA, 0x00); LcdWrite(LCD_DATA, 0x00);
LcdWrite(LCD_DATA, 0x00); LcdWrite(LCD_DATA, 0x00);
} }
} }
else else
{ {
uint8_t barEnd = 8 + (uint16_t)39 * (diskMenuOffset + 5) / diskMenuEntryCount; uint8_t barEnd = 8 + (uint16_t)39 * (diskMenuOffset + 5) / diskMenuEntryCount;
uint8_t barSize = (uint16_t)39 * 5 / diskMenuEntryCount; uint8_t barSize = (uint16_t)39 * 5 / diskMenuEntryCount;
uint8_t barStart = barEnd - barSize; uint8_t barStart = barEnd - barSize;
for (uint8_t r=1; r<6; r++) for (uint8_t r=1; r<6; r++)
{ {
LcdGoto(82, r); LcdGoto(82, r);
LcdWrite(LCD_DATA, 0x00); LcdWrite(LCD_DATA, 0x00);
uint8_t b = 0; uint8_t b = 0;
for (uint8_t y=r*8; y<=r*8+7; y++) for (uint8_t y=r*8; y<=r*8+7; y++)
{ {
if (y >= barStart && y <= barEnd) if (y >= barStart && y <= barEnd)
b = 0x80 | (b >> 1); b = 0x80 | (b >> 1);
else else
b = (b >> 1); b = (b >> 1);
} }
LcdWrite(LCD_DATA, b); LcdWrite(LCD_DATA, b);
} }
} }
// prevent moving selection past end of list // prevent moving selection past end of list
if (diskMenuSelection >= diskMenuOffset + row) if (diskMenuSelection >= diskMenuOffset + row)
{ {
diskMenuSelection = diskMenuOffset + row - 1; diskMenuSelection = diskMenuOffset + row - 1;
if (row == 4 && diskMenuOffset > 0) if (row == 4 && diskMenuOffset > 0)
{ {
diskMenuOffset--; // scroll backwards diskMenuOffset--; // scroll backwards
} }
DrawDiskMenu(sd); // draw again DrawDiskMenu(sd); // draw again
} }
} }
} }

View File

@ -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

View File

@ -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_ */

View File

@ -306,7 +306,7 @@ void LcdClear(void)
void LcdReset(void) void LcdReset(void)
{ {
lcd_vop = 0xBF; lcd_vop = 0xa4; //0xBF;
lcd_bias = 0x14; lcd_bias = 0x14;
lcd_tempCoef = 0x04; lcd_tempCoef = 0x04;