2451 lines
177 KiB
Plaintext
2451 lines
177 KiB
Plaintext
|
{{
|
||
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
│ File Allocation Table Engine │
|
||
|
│ │
|
||
|
│ Author: Kwabena W. Agyeman │
|
||
|
│ Updated: 1/18/2009 │
|
||
|
│ Designed For: P8X32A │
|
||
|
│ │
|
||
|
│ Copyright (c) 2009 Kwabena W. Agyeman │
|
||
|
│ See end of file for terms of use. │
|
||
|
│ │
|
||
|
│ Driver Info: │
|
||
|
│ │
|
||
|
│ The FATEngine runs a SD/SDHC/MMC driver in the next free cog on the propeller chip when called. │
|
||
|
│ │
|
||
|
│ The driver, is only guaranteed and tested to work at an 80Mhz system clock or higher. The driver is designed for the P8X32A │
|
||
|
│ so port B will not be operational. │
|
||
|
│ │
|
||
|
│ Nyamekye, │
|
||
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
}}
|
||
|
|
||
|
{{
|
||
|
|
||
|
ANPASSUNGEN HIVE-PROJECT
|
||
|
|
||
|
Informationen : hive-project.de
|
||
|
Kontakt : drohne235@googlemail.com
|
||
|
System : TriOS
|
||
|
Name : Komponente von Administra-Flash
|
||
|
Chip : Administra
|
||
|
Version : 00
|
||
|
Subversion : 01
|
||
|
|
||
|
Hinweise :
|
||
|
|
||
|
Alle Änderungen am Originalquelltext sind mit der Marke "@hive" gekennzeichnet. Die unveränderte
|
||
|
Originalquelle wird nur auskommentiert.
|
||
|
|
||
|
Logbuch :
|
||
|
|
||
|
25-03-2010-dr235 - änderung der fehlerstrings in fehlernummern für eine bessere auswertung
|
||
|
27-03-2010-dr235 - listVolumeLabel eingefügt
|
||
|
28-03-2010-dr235 - änderung des openFile parameters "modus" von 0-term-string zu 8bit-parameter
|
||
|
12-04-2010-dr235 - getDirCluster & setDirCluster für dir-marker system zugefügt
|
||
|
09-06-2010-dr085 - frida hat den fehler gefunden, welcher eine korrekte funktion der fatengine
|
||
|
nach einem bootvorgang von administra verhinderte :)
|
||
|
14-06-2010-dr085 - löschen der semaphore vor dem bootvorgang
|
||
|
10-07-2010 - provisorische behebung eines fehlers in readData (siehe admsid)
|
||
|
02-02-2012-dr235 - fehler in setCharacterPosition: bei einem wechsel von einer position > 0
|
||
|
auf position = 0 wurde der erste sektor mit falschen daten überschrieben
|
||
|
|
||
|
Notizen :
|
||
|
|
||
|
|
||
|
}}
|
||
|
CON
|
||
|
''
|
||
|
Data_Out_Pin = 10 '' ─ Data Out - To SD Card DO Pin.
|
||
|
''
|
||
|
Clock_Pin = 11 '' ─ Clock - To SD Card CLK Pin.
|
||
|
''
|
||
|
Data_In_Pin = 12 '' ─ Data In - To SD Card DI Pin.
|
||
|
''
|
||
|
Chip_Select_Pin = 13 '' ─ Chip Select - To SD Card CS.
|
||
|
|
||
|
'frida HUB_Lock = 0 ' Hub Lock To use for multiple files open with multiple copies of this object at once.
|
||
|
|
||
|
' FEHLERNUMMERN '@hive
|
||
|
|
||
|
err_noError = 0
|
||
|
err_fsysUnmounted = 1
|
||
|
err_fsysCorrupted = 2
|
||
|
err_fsysUnsupported = 3
|
||
|
err_notFound = 4
|
||
|
err_fileNotFound = 5
|
||
|
err_dirNotFound = 6
|
||
|
err_fileReadOnly = 7
|
||
|
err_endOfFile = 8
|
||
|
err_endOfDirectory = 9
|
||
|
err_endOfRoot = 10
|
||
|
err_dirIsFull = 11
|
||
|
err_dirIsNotEmpty = 12
|
||
|
err_checksumError = 13
|
||
|
err_rebootError = 14
|
||
|
err_bpbCorrupt = 15
|
||
|
err_fsiCorrupt = 16
|
||
|
err_dirAlreadyExist = 17
|
||
|
err_fileAlreadyExist = 18
|
||
|
err_outOfDiskFreeSpace = 19
|
||
|
err_diskIOError = 20
|
||
|
|
||
|
|
||
|
OBJ
|
||
|
|
||
|
rtc : "adm-rtc.spin"
|
||
|
' debugx : "pterm" 'debug
|
||
|
|
||
|
VAR
|
||
|
|
||
|
byte dataBlock[512]
|
||
|
|
||
|
word cardTime
|
||
|
word cardDate
|
||
|
|
||
|
byte cardUniqueIDCopy[17]
|
||
|
byte partitionMountedFlag
|
||
|
|
||
|
byte fileOpenFlag
|
||
|
byte fileReadWriteFlag
|
||
|
|
||
|
long partitionStart
|
||
|
long partitionSize
|
||
|
|
||
|
byte sectorsPerCluster
|
||
|
byte numberOfFATs
|
||
|
word reservedSectorCount
|
||
|
|
||
|
long FATSectorSize
|
||
|
|
||
|
word rootDirectorySectors
|
||
|
word rootDirectorySectorNumber
|
||
|
|
||
|
long hiddenSectors
|
||
|
|
||
|
long firstDataSector
|
||
|
long countOfClusters
|
||
|
|
||
|
long FATType
|
||
|
long rootCluster
|
||
|
|
||
|
word fileSystemInfo
|
||
|
word backupBootSector
|
||
|
|
||
|
long freeClusterCount
|
||
|
long nextFreeCluster
|
||
|
|
||
|
long volumeIdentification
|
||
|
|
||
|
word externalFlags
|
||
|
byte mediaType
|
||
|
byte unformatedNameBuffer[13]
|
||
|
byte formatedNameBuffer[12]
|
||
|
|
||
|
byte directoryEntryName[12]
|
||
|
byte directoryEntry[32]
|
||
|
|
||
|
long currentDirectory
|
||
|
long currentFile
|
||
|
|
||
|
long currentCluster
|
||
|
long currentByte
|
||
|
|
||
|
' long previousDirectory
|
||
|
long currentSize
|
||
|
|
||
|
long previousCluster
|
||
|
long previousByte
|
||
|
|
||
|
byte sdvolumeLabel[12] 'frida
|
||
|
|
||
|
PUB readShort '' 28 Stack Longs
|
||
|
|
||
|
readData(@result, 2)
|
||
|
|
||
|
PUB readLong '' 28 Stack Longs
|
||
|
|
||
|
readData(@result, 4)
|
||
|
|
||
|
PUB writeShort(value) '' 29 Stack Longs
|
||
|
|
||
|
writeData(@value, 2)
|
||
|
|
||
|
PUB writeLong(value) '' 29 Stack Longs
|
||
|
|
||
|
writeData(@value, 4)
|
||
|
|
||
|
PUB readData(addressToPut, count) | index '' 25 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Reads data from the file that is currently open for reading and advances the position by that amount of data. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if a file is not currently open or if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ AddressToPut - A pointer to the start of a data buffer to read to from disk. │
|
||
|
'' │ Count - The amount of data to read from disk. The data buffer must be atleast this large. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
count #>= 0
|
||
|
|
||
|
'#####################################################################
|
||
|
' repeat while((count > 0) and readWriteCurrentCluster("R", "F"))
|
||
|
|
||
|
repeat while (count > 0) ' änderung um 4096-Fehler im dmp-player
|
||
|
if(readWriteCurrentCluster("R", "F")) ' zu beheben
|
||
|
|
||
|
'#####################################################################
|
||
|
|
||
|
index := (currentByte & $1FF)
|
||
|
result := (count <# (512 - index))
|
||
|
|
||
|
bytemove(addressToPut, @dataBlock[index], result)
|
||
|
|
||
|
count -= result
|
||
|
currentByte += result
|
||
|
addressToPut += result
|
||
|
currentByte <#= (currentSize - 1)
|
||
|
|
||
|
PUB writeData(addressToGet, count) | index '' 25 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Writes data to the file that is currently open for writing and advances the position by that amount of data. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if a file is not currently open or if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ This throws an error if the file is open for reading only. │
|
||
|
'' │ │
|
||
|
'' │ Max writable file size is 2,147,483,136 bytes. Exceeding this throws an error. │
|
||
|
'' │ │
|
||
|
'' │ AddressToGet - A pointer to the start of a data buffer to write to disk. │
|
||
|
'' │ Count - The amount of data to write to disk. The data buffer must be atleast this large. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
count #>= 0
|
||
|
repeat while((count > 0) and readWriteCurrentCluster("W", "F"))
|
||
|
|
||
|
index := (currentByte & $1FF)
|
||
|
result := (count <# (512 - index))
|
||
|
|
||
|
bytemove(@dataBlock[index], addressToGet, result)
|
||
|
flushCharacters
|
||
|
|
||
|
count -= result
|
||
|
currentByte += result
|
||
|
addressToGet += result
|
||
|
currentSize #>= currentByte
|
||
|
|
||
|
PUB readCharacter '' 22 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Reads a character from the file that is currently open for reading and advances the position by one. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if a file is not currently open or if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ Returns the next character to read from the file. At the end of file returns the last character in the file repeatedly. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
if(readWriteCurrentCluster("R", "F"))
|
||
|
|
||
|
result := blockToByte(currentByte++)
|
||
|
currentByte <#= (currentSize - 1)
|
||
|
|
||
|
PUB writeCharacter(character) '' 23 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Writes a character to the file that is currently open for writing and advances the position by one. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if a file is not currently open or if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ This throws an error if the file is open for reading only. │
|
||
|
'' │ │
|
||
|
'' │ Max writable file size is 2,147,483,136 bytes. Exceeding this throws an error. │
|
||
|
'' │ │
|
||
|
'' │ Character - A character to write to the file. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
if(readWriteCurrentCluster("W", "F"))
|
||
|
|
||
|
byteToBlock(currentByte++, character)
|
||
|
|
||
|
ifnot($1FF & currentByte--)
|
||
|
flushCharacters
|
||
|
|
||
|
currentSize #>= ++currentByte
|
||
|
|
||
|
PUB writeCharacters(characters) '' 27 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Writes a string of characters to the file that is currently open for writing and advances the position by string length. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if a file is not currently open or if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ This throws an error if the file is open for reading only. │
|
||
|
'' │ │
|
||
|
'' │ Max writable file size is 2,147,483,136 bytes. Exceeding this throws an error. │
|
||
|
'' │ │
|
||
|
'' │ Characters - A pointer to a string of characters to write to the file. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
repeat strsize(characters)
|
||
|
writeCharacter(byte[characters++])
|
||
|
|
||
|
PUB flushCharacters '' 12 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Writes buffered data to disk. All file writes are buffered and are not written to disk immediantly. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
if(partitionMountedFlag and fileOpenFlag and fileReadWriteFlag)
|
||
|
readWriteCurrentSector("W")
|
||
|
|
||
|
PUB getEOF
|
||
|
|
||
|
result := currentByte => currentSize-1
|
||
|
|
||
|
PUB getCharacterPosition '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the current character position within a file for reading and writing. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (currentByte & (partitionMountedFlag and fileOpenFlag))
|
||
|
|
||
|
PUB setCharacterPosition(position) | backUpPosition '' 17 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Sets the current character position within a file for reading and writing. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ Position - A character position in the file. Set to false to go to the begining of the file and true to go to the end. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
if(partitionMountedFlag and fileOpenFlag)
|
||
|
|
||
|
position := ((position <# (currentSize - 1)) #> 0)
|
||
|
backUpPosition := position
|
||
|
|
||
|
if(position <> currentByte) '@hive: fehlerkorrektur vom originalcode
|
||
|
flushCharacters
|
||
|
|
||
|
currentByte >>= 9
|
||
|
position >>= 9
|
||
|
|
||
|
' if(position <> currentByte) 'dieser abschnitt muss nach oben verschoben werden
|
||
|
' flushCharacters 'da flashCharacter in sonderfällen auf currentByte zugreift!
|
||
|
|
||
|
currentByte /= sectorsPerCluster
|
||
|
position /= sectorsPerCluster
|
||
|
|
||
|
if(position <> currentByte)
|
||
|
if(position < currentByte)
|
||
|
currentByte := 0
|
||
|
currentCluster := currentFile
|
||
|
|
||
|
repeat until(position == currentByte++)
|
||
|
|
||
|
readWriteFATBlock(currentCluster, "R")
|
||
|
currentCluster := readFATEntry(currentCluster)
|
||
|
|
||
|
if((currentCluster =< 1) or (FATEndOfClusterValue =< currentCluster))
|
||
|
partitionMountedFlag := false
|
||
|
' abort @FSCorrupted '@hive
|
||
|
abort err_fsysCorrupted
|
||
|
|
||
|
result := true
|
||
|
|
||
|
currentByte := backUpPosition
|
||
|
|
||
|
if(result)
|
||
|
readWriteCurrentSector("R")
|
||
|
|
||
|
PUB closeFile '' 15 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Closes the currently open file in the current directory. Files opened for writing that are not closed will be corrupted. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
flushCharacters
|
||
|
if(partitionMountedFlag and fileOpenFlag~)
|
||
|
|
||
|
currentByte := previousByte
|
||
|
currentCluster := previousCluster
|
||
|
|
||
|
readWriteCurrentSector("R")
|
||
|
|
||
|
wordToBlock((currentByte + 18), readClock)
|
||
|
|
||
|
if(fileReadWriteFlag)
|
||
|
|
||
|
wordToBlock((currentByte + 22), cardTime)
|
||
|
wordToBlock((currentByte + 24), cardDate)
|
||
|
longToBlock((currentByte + 28), currentSize)
|
||
|
|
||
|
dataBlock[(currentByte + 11) & $1FF] |= $20
|
||
|
|
||
|
readWriteCurrentSector("W")
|
||
|
|
||
|
PUB openFile(fileName, mode) '' 33 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Opens a file in the current directory for reading or writing. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ The "." and ".." entries are ignored by this function. │
|
||
|
'' │ │
|
||
|
'' │ Returns a pointer to the name of the file. │
|
||
|
'' │ │
|
||
|
'' │ FileName - The name of the file to open for reading or writing. │
|
||
|
'' │ Mode - A string of characters containing the mode to open the file in. R-Read, W-Write, A-Append. Default read. │
|
||
|
'' │ │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
' result := unformatName(listFind(formatName(fileName), @fileNotFound))
|
||
|
result := unformatName(listFind(formatName(fileName), err_fileNotFound)) '@hive
|
||
|
|
||
|
if(listIsDirectory)
|
||
|
' abort @fileNotFound '@hive
|
||
|
abort err_fileNotFound
|
||
|
|
||
|
currentFile := listCluster
|
||
|
|
||
|
ifnot(currentFile)
|
||
|
currentFile := createClusterChain(0)
|
||
|
|
||
|
readWriteCurrentSector("R")
|
||
|
dataBlock[(currentByte + 11) & $1FF] |= $20
|
||
|
wordToBlock((currentByte + 18), readClock)
|
||
|
wordToBlock((currentByte + 26), (currentFile & $FFFF))
|
||
|
wordToBlock((currentByte + 20), (currentFile >> 16))
|
||
|
readWriteCurrentSector("W")
|
||
|
|
||
|
' fileReadWriteFlag := findCharacter(mode, "W") '@hive
|
||
|
fileReadWriteFlag := mode == "W"
|
||
|
|
||
|
if(listIsReadOnly and fileReadWriteFlag)
|
||
|
' abort string("File Read Only") '@hive
|
||
|
abort err_fileReadOnly
|
||
|
|
||
|
currentSize := listSize
|
||
|
previousByte := currentByte
|
||
|
previousCluster := currentCluster
|
||
|
' currentByte := ((findCharacter(mode, "A") and fileReadWriteFlag) & currentSize) '@hive
|
||
|
currentByte := (( (mode == "A") and fileReadWriteFlag) & currentSize)
|
||
|
currentCluster := currentFile
|
||
|
|
||
|
readWriteCurrentSector("R")
|
||
|
fileOpenFlag := true
|
||
|
|
||
|
PUB newFile(fileName) '' 40 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Creates a new file in the current directory. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ Returns a pointer to the name of the file. List functions are not valid after calling this function. │
|
||
|
'' │ │
|
||
|
'' │ FileName - The name of the new file to create. Must be a new unique name in the current directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
' result := unformatName(listNew(formatName(fileName), $20, readClock, cardTime, 0, "F")) '@hive
|
||
|
unformatName(listNew(formatName(fileName), $20, readClock, cardTime, 0, "F")) '@hive
|
||
|
listReset
|
||
|
|
||
|
PUB newDirectory(directoryName) '' 40 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Creates a new directory in the current directory. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ Returns a pointer to the name of the directory. List functions are not valid after calling this function. │
|
||
|
'' │ │
|
||
|
'' │ DirectoryName - The name of the new directory to create. Must be a new unique name in the current directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
' result := unformatName(listNew(formatName(directoryName), $30, readClock, cardTime, 0, "D")) '@hive
|
||
|
unformatName(listNew(formatName(directoryName), $30, readClock, cardTime, 0, "D"))
|
||
|
|
||
|
directoryName := currentDirectory
|
||
|
currentDirectory := currentFile
|
||
|
|
||
|
listNew(@dot, $10, cardDate, cardTime, currentDirectory, "F")
|
||
|
listNew(@dotdot, $10, cardDate, cardTime, directoryName, "F")
|
||
|
|
||
|
currentDirectory := directoryName
|
||
|
listReset
|
||
|
|
||
|
PUB deleteEntry(entryName) '' 32 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Deletes a file or directory in the current directory. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ Cannot delete non empty directories. This throws and error. │
|
||
|
'' │ │
|
||
|
'' │ The "." and ".." entries are ignored by this function. │
|
||
|
'' │ │
|
||
|
'' │ Returns a pointer to the name of the file or directory. List functions are not valid after calling this function. │
|
||
|
'' │ │
|
||
|
'' │ EntryName - The name of the file or directory to delete. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
' result := unformatName(listFind(formatName(entryName), @fileOrDirectoryNotFound)) '@hive
|
||
|
result := unformatName(listFind(formatName(entryName), err_notFound))
|
||
|
|
||
|
if(listIsDirectory)
|
||
|
|
||
|
previousByte := currentByte~
|
||
|
previousCluster := currentCluster
|
||
|
currentCluster := listCluster
|
||
|
|
||
|
repeat
|
||
|
entryName := listDirectory("R")
|
||
|
|
||
|
ifnot(entryName)
|
||
|
quit
|
||
|
|
||
|
if(byte[entryName] <> ".")
|
||
|
' abort string("Directory Is Not Empty") '@hive
|
||
|
abort err_dirIsNotEmpty
|
||
|
|
||
|
currentByte := previousByte
|
||
|
currentCluster := previousCluster
|
||
|
|
||
|
readWriteCurrentSector("R")
|
||
|
|
||
|
byteToBlock(currentByte, $E5)
|
||
|
readWriteCurrentSector("W")
|
||
|
|
||
|
destroyClusterChain(listCluster)
|
||
|
listReset
|
||
|
|
||
|
PUB renameEntry(entryNameToChange, entryNameToChangeTo) '' 33 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Renames a file or directory in the current directory. The new name must be unique in the current directory. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ The "." and ".." entries are ignored by this function. │
|
||
|
'' │ │
|
||
|
'' │ Returns a pointer to the name of the file or directory. List functions are not valid after calling this function. │
|
||
|
'' │ │
|
||
|
'' │ EntryNameToChange - The name of the file or directory to change. │
|
||
|
'' │ EntryNameToChangeTo - The name of the file or directory to change to. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
listDuplicate(formatName(entryNameToChangeTo))
|
||
|
' result := unformatName(listFind(formatName(entryNameToChange), @fileOrDirectoryNotFound)) '@hive
|
||
|
result := unformatName(listFind(formatName(entryNameToChange), err_notFound))
|
||
|
|
||
|
bytemove(@dataBlock[currentByte & $1FF], formatName(entryNameToChangeTo), 11)
|
||
|
|
||
|
wordToBlock((currentByte + 18), readClock)
|
||
|
wordToBlock((currentByte + 22), cardTime)
|
||
|
wordToBlock((currentByte + 24), cardDate)
|
||
|
dataBlock[(currentByte + 11) & $1FF] |= $20
|
||
|
|
||
|
readWriteCurrentSector("W")
|
||
|
listReset
|
||
|
|
||
|
PUB changeAttributes(entryName, newAttributes) '' 33 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Changes the attributes of a file or directory in the current directory. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ The "." and ".." entries are ignored by this function. │
|
||
|
'' │ │
|
||
|
'' │ Returns a pointer to the name of the file or directory. List functions are not valid after calling this function. │
|
||
|
'' │ │
|
||
|
'' │ EntryName - The name of the file or directory to change the attributes of. │
|
||
|
'' │ NewAttributes - A string of characters containing the new set of attributes. A-Archive, S-System, H-Hidden, R-Read Only. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
' result := unformatName(listFind(formatName(entryName), @fileOrDirectoryNotFound)) '@hive
|
||
|
result := unformatName(listFind(formatName(entryName), err_notFound))
|
||
|
|
||
|
byteToBlock((currentByte + 11), (($20 & findCharacter(newAttributes, "A")) | (listIsDirectory & $10) | ($4 & findCharacter(newAttributes, "S")) | ($2 & findCharacter(newAttributes, "H")) | ($1 & findCharacter(newAttributes, "R"))))
|
||
|
wordToBlock((currentByte + 18), readClock)
|
||
|
wordToBlock((currentByte + 22), cardTime)
|
||
|
wordToBlock((currentByte + 24), cardDate)
|
||
|
|
||
|
readWriteCurrentSector("W")
|
||
|
' listReset '@hive
|
||
|
|
||
|
PUB changeDirectory(directoryName) '' 32 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Searches the current directory for the specified directory and enters that directory. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ Returns a pointer to the name of the direcotry. List functions are not valid after calling this function. │
|
||
|
'' │ │
|
||
|
'' │ DirectoryName - The name of the directory to search for in the current directory and enter into. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
' result := unformatName(listFind(listCase(directoryName, formatName(directoryName)), @directoryNotFound)) '@hive
|
||
|
result := unformatName(listFind(listCase(directoryName, formatName(directoryName)), err_dirNotFound))
|
||
|
|
||
|
ifnot(listIsDirectory)
|
||
|
' abort @directoryNotFound '@hive
|
||
|
abort err_dirNotFound
|
||
|
|
||
|
currentDirectory := listCluster
|
||
|
listReset
|
||
|
|
||
|
PUB getDirCluster:cluster
|
||
|
|
||
|
result := currentDirectory
|
||
|
|
||
|
PUB setDirCluster(cluster)
|
||
|
|
||
|
currentDirectory := cluster
|
||
|
listReset
|
||
|
|
||
|
PUB listSearch(entryName) '' 32 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns a pointer to the name of the serached for file or direcotry in the current directory. │
|
||
|
'' │ │
|
||
|
'' │ Additionally this function validates the other listing functions to get information about the next file or directory. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ EntryName - The name of the file or directory to search for in the current directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
' return unformatName(listFind(listCase(entryName, formatName(entryName)), @fileOrDirectoryNotFound)) '@hive
|
||
|
return unformatName(listFind(listCase(entryName, formatName(entryName)), err_notFound))
|
||
|
|
||
|
PUB listName '' 26 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns a pointer to the name of the next file or direcotry in the current directory. Returns zero on wrap arround. │
|
||
|
'' │ │
|
||
|
'' │ Additionally this function validates the other listing functions to get information about the next file or directory. │
|
||
|
'' │ │
|
||
|
'' │ If the partition is not mounted or an error occurs this function will abort and return a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ After listing the last file or directory "listReset" must be called to to list from the first file or direcotry again. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return unformatName(listDirectory("R"))
|
||
|
|
||
|
PUB listReset '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Resets "listName" to list from the first file or directory in the current directory. │
|
||
|
'' │ │
|
||
|
'' │ List functions are not valid after calling this function. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
ifnot(fileOpenFlag)
|
||
|
|
||
|
currentByte := 0
|
||
|
currentCluster := currentDirectory
|
||
|
|
||
|
bytefill(@directoryEntry, 0, 32)
|
||
|
bytefill(@directoryEntryName, 0, 12)
|
||
|
|
||
|
PUB listSize '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the size of current file or directory pointed to by "listName". Directories have no size. │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that files information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the size of the file or directory in bytes. Maximum file size is 2,147,483,136 bytes. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (((directoryEntry[28] | (directoryEntry[29] << 8) | (directoryEntry[30] << 16) | (directoryEntry[31] << 24)) <# $7FFFFE00) #> 0)
|
||
|
|
||
|
PUB listCreationDay '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the creation day of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the creation day of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (directoryEntry[16] & $1F)
|
||
|
|
||
|
PUB listCreationMonth '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the creation month of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the creation month of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (((directoryEntry[17] & $1) << 3) | (directoryEntry[16] >> 5))
|
||
|
|
||
|
PUB listCreationYear '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the creation year of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the creation year of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return ((directoryEntry[17] >> 1) + 1980)
|
||
|
|
||
|
PUB listCreationSeconds '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the creation second of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the creation second of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (((directoryEntry[14] & $1F) << 1) + (directoryEntry[13] / 100))
|
||
|
|
||
|
PUB listCreationMinutes '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the creation minute of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the creation minute of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (((directoryEntry[15] & $7) << 3) | (directoryEntry[14] >> 5))
|
||
|
|
||
|
PUB listCreationHours '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the creation hour of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the creation hour of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (directoryEntry[15] >> 3)
|
||
|
|
||
|
PUB listAccessDay '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last day of access of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the last acess day of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (directoryEntry[18] & $1F)
|
||
|
|
||
|
PUB listAccessMonth '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last month of access of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the last acess month of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (((directoryEntry[19] & $1) << 3) | (directoryEntry[18] >> 5))
|
||
|
|
||
|
PUB listAccessYear '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last year of access of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the last acess year of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return ((directoryEntry[19] >> 1) + 1980)
|
||
|
|
||
|
PUB listModificationDay '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last day of modification of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the modification day of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (directoryEntry[24] & $1F)
|
||
|
|
||
|
PUB listModificationMonth '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last month of modification of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the modification month of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (((directoryEntry[25] & $1) << 3) | (directoryEntry[24] >> 5))
|
||
|
|
||
|
PUB listModificationYear '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last year of modification of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the modification year of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return ((directoryEntry[25] >> 1) + 1980)
|
||
|
|
||
|
PUB listModificationSeconds '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last second of modification of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the modification second of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return ((directoryEntry[22] & $1F) << 1)
|
||
|
|
||
|
PUB listModificationMinutes '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last minute of modification of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the modification minute of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (((directoryEntry[23] & $7) << 3) | (directoryEntry[22] >> 5))
|
||
|
|
||
|
PUB listModificationHours '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Gets the last hour of modification of the current file or directory pointed to by "listName". │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns the modification hour of the file or directory. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
return (directoryEntry[23] >> 3)
|
||
|
|
||
|
PUB listIsReadOnly '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns whether or not the current file or directory pointed to by "listName" is read only. │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns true or false. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
result or= (directoryEntry[11] & $1)
|
||
|
|
||
|
PUB listIsHidden '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns whether or not the current file or directory pointed to by "listName" is hidden. │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns true or false. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
result or= (directoryEntry[11] & $2)
|
||
|
|
||
|
PUB listIsSystem '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns whether or not the current file or directory pointed to by "listName" is a system file. │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns true or false. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
result or= (directoryEntry[11] & $4)
|
||
|
|
||
|
PUB listIsDirectory '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns whether or not the current file or directory pointed to by "listName" is a directory. │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns true or false. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
result or= (directoryEntry[11] & $10)
|
||
|
|
||
|
PUB listIsArchive '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns whether or not the current file or directory pointed to by "listName" has been modified since the last backup. │
|
||
|
'' │ │
|
||
|
'' │ If a file is currently open this function will retrieve that file's information. │
|
||
|
'' │ │
|
||
|
'' │ If "listName" did not succed or was not previously called the value returned is invalid. │
|
||
|
'' │ │
|
||
|
'' │ Returns true or false. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
result or= (directoryEntry[11] & $20)
|
||
|
|
||
|
PUB listVolumeLabel
|
||
|
'' return: zeiger auf string mit volume-label
|
||
|
|
||
|
'return unformatName(listDirectory("V")) 'frida
|
||
|
if(partitionMountedFlag) 'frida
|
||
|
return @sdvolumeLabel 'frida
|
||
|
|
||
|
|
||
|
PUB checkPartitionMounted '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns true if the file system is still currently mounted and false if not. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
result or= partitionMountedFlag
|
||
|
|
||
|
PUB checkFileOpen '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns true if a file is still currently open and false if not. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
result or= fileOpenFlag
|
||
|
|
||
|
PUB checkUsedSectorCount(mode) '' 18 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns the current used sector count on this partition. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if a file is currently open or if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ In fast mode this function will return the last valid used sector count if avialable. This is an estimate value. │
|
||
|
'' │ │
|
||
|
'' │ In slow mode this function will compute the used sector count by scanning the entire FAT. This can take a long time. │
|
||
|
'' │ │
|
||
|
'' │ One sector is equal to 512 bytes. Multiply the used sector count by 512 to determine the number of used bytes. │
|
||
|
'' │ │
|
||
|
'' │ This function also finds the next free cluster for creating new files and directories. │
|
||
|
'' │ │
|
||
|
'' │ Call this function when running out of disk space to find the next free cluster if available. │
|
||
|
'' │ │
|
||
|
'' │ If the last valid used sector count is not avialable when using fast mode this function will enter slow mode, │
|
||
|
'' │ │
|
||
|
'' │ Mode - A character specifing the mode to use. F-Fast, S-Slow. Default slow. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
if(partitionMountedFlag)
|
||
|
return ((countOfClusters * sectorsPerCluster) - checkFreeSectorCount(mode))
|
||
|
|
||
|
PUB checkFreeSectorCount(mode) '' 14 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Returns the current free sector count on this partition. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if a file is currently open or if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ In fast mode this function will return the last valid free sector count if avialable. This is an estimate value. │
|
||
|
'' │ │
|
||
|
'' │ In slow mode this function will compute the free sector count by scanning the entire FAT. This can take a long time. │
|
||
|
'' │ │
|
||
|
'' │ One sector is equal to 512 bytes. Multiply the free sector count by 512 to determine the number of free bytes. │
|
||
|
'' │ │
|
||
|
'' │ This function also finds the next free cluster for creating new files and directories. │
|
||
|
'' │ │
|
||
|
'' │ Call this function when running out of disk space to find the next free cluster if available. │
|
||
|
'' │ │
|
||
|
'' │ If the last valid free sector count is not avialable when using fast mode this function will enter slow mode, │
|
||
|
'' │ │
|
||
|
'' │ Mode - A character specifing the mode to use. F-Fast, S-Slow. Default slow. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
if(partitionMountedFlag)
|
||
|
flushCharacters
|
||
|
|
||
|
if(findByte(mode, "f", "F") and (freeClusterCount <> $FFFFFFFF))
|
||
|
result := freeClusterCount
|
||
|
|
||
|
else
|
||
|
repeat mode from 0 to (countOfClusters + 1)
|
||
|
|
||
|
ifnot(FATEntryNumber(mode))
|
||
|
readWriteFATBlock(mode, "R")
|
||
|
|
||
|
result -= (not(readFATEntry(mode)))
|
||
|
|
||
|
ifnot(result)
|
||
|
nextFreeCluster := ((mode + 1) <# (countOfClusters + 1))
|
||
|
|
||
|
freeClusterCount := result
|
||
|
readWriteCurrentSector("R")
|
||
|
|
||
|
result *= sectorsPerCluster
|
||
|
|
||
|
PUB bootPartition(fileName, checkDisk) | bootSectors[64] '' 102 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Reboots the propeller chip to run the selected file from memory. The file should be a valid spin BIN or EEPROM file. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ FileName - The name of the file to reboot from. │
|
||
|
'' │ CheckDisk - Unmounts the partition before booting if "C". │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
longfill(@bootSectors, 0, 64)
|
||
|
openFile(fileName~, string("R"))
|
||
|
|
||
|
repeat (listSize <# 32768)
|
||
|
result += readCharacter
|
||
|
|
||
|
ifnot($1FF & fileName++)
|
||
|
bootSectors[fileName >> 9] := (partitionStart + FATFirstSectorInCluster(currentCluster) + FATWorkingSectorInCluster)
|
||
|
|
||
|
result &= $FF
|
||
|
setCharacterPosition(6)
|
||
|
fileName := readShort
|
||
|
closeFile
|
||
|
|
||
|
if((result and (result <> $14)) or (fileName <> $10))
|
||
|
' abort string("Checksum Error") '@hive
|
||
|
abort err_checksumError
|
||
|
|
||
|
if(findByte(checkDisk, "c", "C"))
|
||
|
unmountPartition
|
||
|
|
||
|
readWriteBlock(@bootSectors, "B")
|
||
|
' abort string("Reboot Error") '@hive
|
||
|
abort err_rebootError
|
||
|
|
||
|
PUB formatPartition(partition, volumeLabel, checkDisk) '' 34 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Permanetly deletes all information on the loaded FAT16/32 file system. Unloads the loaded FAT16/32 file system. │
|
||
|
'' │ │
|
||
|
'' │ Will do nothing if the card is not mounted. This throws an error. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
mountPartition(partition, checkdisk)
|
||
|
|
||
|
repeat while(readWriteCurrentCluster("R", "D"))
|
||
|
bytefill(@dataBlock, 0, 512)
|
||
|
readWriteCurrentSector("W")
|
||
|
currentByte += 512
|
||
|
|
||
|
' result := unformatName(listNew(formatName(volumeLabel), $8, readClock, cardTime, 0, 0)) '@hive
|
||
|
unformatName(listNew(formatName(volumeLabel), $8, readClock, cardTime, 0, 0)) '@hive
|
||
|
|
||
|
bytefill(@dataBlock, 0, 512)
|
||
|
repeat volumeLabel from reservedSectorCount to (rootDirectorySectorNumber - 1)
|
||
|
readWriteBlock(volumeLabel, "W")
|
||
|
|
||
|
readWriteFATBlock(0, "R")
|
||
|
writeFATEntry(0, ($0FFFFF00 | mediaType))
|
||
|
writeFATEntry(1, $0FFFFFFF)
|
||
|
readWriteFATBlock(0, "W")
|
||
|
|
||
|
listReset
|
||
|
|
||
|
PUB mountPartition(partition, checkDisk) '' 28 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Loads a FAT16/32 file system with up to 1,099,511,627,776 bytes for use. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' │ │
|
||
|
'' │ File sizes up to 2,147,483,136 bytes are supported. │
|
||
|
'' │ │
|
||
|
'' │ Directory sizes up to 65,536 entries are supported. │
|
||
|
'' │ │
|
||
|
'' │ Additionally check disk flags can be setup so that check disk is called on any improperly unmounted partition. │
|
||
|
'' │ │
|
||
|
'' │ Returns a pointer to the volume label. │
|
||
|
'' │ │
|
||
|
'' │ Parition - Partition number to mount (between 0 and 3). The default partition number is 0. │
|
||
|
'' │ CheckDisk - Raises the check disk flag upon mounting. C-Raise Flag │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
'' @hive:
|
||
|
'' return: fehlernummer
|
||
|
|
||
|
unmountPartition
|
||
|
|
||
|
partitionStart := 0
|
||
|
readWriteBlock(0, "M")
|
||
|
|
||
|
bytemove(@cardUniqueIDCopy, @cardUniqueID, 17)
|
||
|
readWriteBlock(0, "R")
|
||
|
|
||
|
if(blockToWord(510) <> $AA55)
|
||
|
' abort @FSCorrupted '@hive
|
||
|
abort err_fsysCorrupted
|
||
|
|
||
|
partition := (((partition <# 3) #> 0) << 4)
|
||
|
if((blockToByte(0) <> $EB) and (blockToByte(0) <> $E9))
|
||
|
|
||
|
'case(blockToByte(450 + partition) & $F)
|
||
|
' $0 .. $3, $5, $7 .. $A, $D, $F: abort @FSUnsupported
|
||
|
|
||
|
'volumeIdentification := blockToLong(440)
|
||
|
'partitionSize := blockToLong(458 + partition)
|
||
|
|
||
|
partitionStart := blockToLong(454 + partition)
|
||
|
readWriteBlock(0, "R")
|
||
|
|
||
|
if(blockToWord(510) <> $AA55)
|
||
|
' abort string("BPB Corrupt") '@hive
|
||
|
abort err_bpbCorrupt
|
||
|
|
||
|
|
||
|
|
||
|
if(blockToWord(11) <> 512)
|
||
|
' abort @FSUnsupported '@hive
|
||
|
abort err_fsysUnsupported
|
||
|
|
||
|
sectorsPerCluster := blockToByte(13)
|
||
|
reservedSectorCount := blockToWord(14)
|
||
|
numberOfFATs := blockToByte(16)
|
||
|
externalFlags := 0
|
||
|
|
||
|
partitionSize := blockToWord(19)
|
||
|
ifnot(partitionSize)
|
||
|
partitionSize := blockToLong(32)
|
||
|
|
||
|
FATSectorSize := blockToWord(22)
|
||
|
ifnot(FATSectorSize)
|
||
|
FATSectorSize := blockToLong(36)
|
||
|
|
||
|
mediaType := blockToByte(21)
|
||
|
hiddenSectors := blockToLong(28)
|
||
|
|
||
|
rootDirectorySectors := (blockToWord(17) >> 4)
|
||
|
rootDirectorySectorNumber := (reservedSectorCount + (numberOfFATs * FATSectorSize))
|
||
|
|
||
|
firstDataSector := (rootDirectorySectorNumber + rootDirectorySectors)
|
||
|
countOfClusters := ((partitionSize - firstDataSector) / sectorsPerCluster)
|
||
|
|
||
|
nextFreeCluster := 2
|
||
|
freeClusterCount := $FFFFFFFF
|
||
|
|
||
|
if(countOfClusters < 4085)
|
||
|
' abort @FSUnsupported '@hive
|
||
|
abort err_fsysUnsupported
|
||
|
|
||
|
FATType := false
|
||
|
if(countOfClusters => 65525)
|
||
|
FATType := true
|
||
|
|
||
|
volumeIdentification := blockToLong(39 + (28 & FATType))
|
||
|
dataBlock[37 + (28 & FATType)] |= ($3 & findByte(checkDisk, "c", "C"))
|
||
|
readWriteBlock(0, "W")
|
||
|
|
||
|
if(FATType)
|
||
|
if(blockToWord(40) & $80)
|
||
|
numberOfFATs := 1
|
||
|
externalFlags := (blockToWord(40) & $F)
|
||
|
|
||
|
if(blockToWord(42))
|
||
|
' abort @FSUnsupported '@hive
|
||
|
abort err_fsysUnsupported
|
||
|
|
||
|
rootCluster := blockToLong(44)
|
||
|
fileSystemInfo := blockToWord(48)
|
||
|
backupBootSector := blockToWord(50)
|
||
|
|
||
|
readWriteBlock(fileSystemInfo, "R")
|
||
|
|
||
|
if(blockToWord(510) <> $AA55)
|
||
|
' abort string("FSI Corrupt") '@hive
|
||
|
abort err_fsiCorrupt
|
||
|
|
||
|
freeClusterCount := blockToLong(488)
|
||
|
nextFreeCluster := blockToLong(492)
|
||
|
|
||
|
if(nextFreeCluster == $FFFFFFFF)
|
||
|
nextFreeCluster := 2
|
||
|
|
||
|
partitionMountedFlag := true
|
||
|
|
||
|
currentDirectory := 0
|
||
|
listReset
|
||
|
|
||
|
' return unformatName(listDirectory("V")) '@hive
|
||
|
result := listDirectory("V") 'frida
|
||
|
bytemove(@sdvolumeLabel, result, 12) 'frida
|
||
|
return 0
|
||
|
|
||
|
PUB unmountPartition '' 18 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Unloads the loaded FAT16/32 file system. Closes the currently open file in the current directory. │
|
||
|
'' │ │
|
||
|
'' │ If an error occurs this function will abort and return a pointer to a string describing that error. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
closeFile
|
||
|
if(partitionMountedFlag~)
|
||
|
|
||
|
currentDirectory := 0
|
||
|
listReset
|
||
|
|
||
|
readWriteBlock(0, "R")
|
||
|
dataBlock[37 + (28 & FATType)] &= $FC
|
||
|
readWriteBlock(0, "W")
|
||
|
|
||
|
if(FATType)
|
||
|
readWriteBlock(fileSystemInfo, "R")
|
||
|
longToBlock(freeClusterCount, 488)
|
||
|
longToBlock(nextFreeCluster, 492)
|
||
|
readWriteBlock(fileSystemInfo, "W")
|
||
|
|
||
|
PUB FATEngine '' 3 Stack Longs
|
||
|
|
||
|
'' ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
'' │ Initializes the file system driver to run on a new cog. │
|
||
|
'' │ │
|
||
|
'' │ Returns the new cog's ID on sucess or -1 on failure. │
|
||
|
'' └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
|
||
|
cardLockID := locknew 'frida
|
||
|
|
||
|
'debugverbindung
|
||
|
'debugx.start(115200) ' Start des Debug-Terminals
|
||
|
|
||
|
slowTiming := ((constant(250_000 << 12) / clkfreq) << 20)
|
||
|
fastTiming := ((constant(2_500_000 << 8) / clkfreq) << 24)
|
||
|
|
||
|
CCFAddress := @cardCommandFlag
|
||
|
CEFAddress := @cardErrorFlag
|
||
|
|
||
|
CDBAddress := @cardDataBlockAddress
|
||
|
CSAAddress := @cardSectorAddress
|
||
|
|
||
|
CUIDAddress := @cardUniqueID
|
||
|
return cognew(@initialization, @cardSectorCount)
|
||
|
|
||
|
PRI listDuplicate(entryName) ' 27 Stack Longs
|
||
|
|
||
|
closeFile
|
||
|
listReset
|
||
|
|
||
|
repeat
|
||
|
|
||
|
result := listDirectory("R")
|
||
|
|
||
|
if(strcomp(result, entryName))
|
||
|
|
||
|
if(listIsDirectory)
|
||
|
' abort string("Directory Already Exist") '@hive
|
||
|
abort err_dirAlreadyExist
|
||
|
|
||
|
' abort string("File Already Exist") '@hive
|
||
|
abort err_fileAlreadyExist
|
||
|
|
||
|
while(result)
|
||
|
|
||
|
{
|
||
|
PRI listFind(entryName, errorMessage) ' 28 Stack Longs '@hive
|
||
|
|
||
|
closeFile
|
||
|
listReset
|
||
|
|
||
|
repeat
|
||
|
|
||
|
result := listDirectory("R")
|
||
|
|
||
|
ifnot(result)
|
||
|
abort errorMessage
|
||
|
|
||
|
until(strcomp(entryName, result))
|
||
|
|
||
|
currentByte -= 32
|
||
|
}
|
||
|
|
||
|
PRI listFind(entryName, errorMessage) | strptr ' 28 Stack Longs
|
||
|
|
||
|
closeFile
|
||
|
listReset
|
||
|
|
||
|
repeat
|
||
|
result := err_noError
|
||
|
strptr := listDirectory("R")
|
||
|
|
||
|
ifnot(strptr)
|
||
|
abort errorMessage
|
||
|
|
||
|
until(strcomp(entryName, strptr))
|
||
|
|
||
|
currentByte -= 32
|
||
|
|
||
|
PRI listNew(entryName, entryAttributes, entryDate, entryTime, entryCluster, entryType) ' 36 Stack Longs
|
||
|
|
||
|
listDuplicate(entryName)
|
||
|
listReset
|
||
|
|
||
|
repeat while(readWriteCurrentCluster("W", "D"))
|
||
|
|
||
|
if((blockToByte(currentByte) <> $E5) and blockToByte(currentByte))
|
||
|
currentByte += 32
|
||
|
|
||
|
else
|
||
|
|
||
|
if(entryType == "D")
|
||
|
entryCluster := createClusterChain(0)
|
||
|
currentFile := entryCluster
|
||
|
readWriteCurrentSector("R")
|
||
|
|
||
|
bytefill(@dataBlock[currentByte & $1FF], 0, 32)
|
||
|
bytemove(@dataBlock[currentByte & $1FF], entryName, 11)
|
||
|
|
||
|
byteToBlock((currentByte + 11), entryAttributes)
|
||
|
|
||
|
wordToBlock((currentByte + 14), entryTime)
|
||
|
wordToBlock((currentByte + 16), entryDate)
|
||
|
wordToBlock((currentByte + 18), entryDate)
|
||
|
wordToBlock((currentByte + 22), entryTime)
|
||
|
wordToBlock((currentByte + 24), entryDate)
|
||
|
|
||
|
wordToBlock((currentByte + 26), (entryCluster & $FFFF))
|
||
|
wordToBlock((currentByte + 20), (entryCluster >> 16))
|
||
|
|
||
|
readWriteCurrentSector("W")
|
||
|
return entryName
|
||
|
|
||
|
' abort string("Directory Is Full") '@hive
|
||
|
abort err_dirIsFull
|
||
|
|
||
|
PRI listDirectory(volumeIDAttribute) ' 23 Stack Longs
|
||
|
|
||
|
if(fileOpenFlag)
|
||
|
closeFile
|
||
|
'listReset 'frida
|
||
|
|
||
|
repeat while(readWriteCurrentCluster("R", "D") and blockToByte(currentByte))
|
||
|
|
||
|
if((blockToByte(currentByte) == $E5) or (((volumeIDAttribute == "V") ^ blockToByte(currentByte + 11)) & $8))
|
||
|
currentByte += 32
|
||
|
|
||
|
else
|
||
|
|
||
|
bytemove(@directoryEntry, @dataBlock[currentByte & $1FF], 32)
|
||
|
bytemove(@directoryEntryName, @directoryEntry, 11)
|
||
|
|
||
|
if(directoryEntryName == $5)
|
||
|
directoryEntryName := $E5
|
||
|
|
||
|
currentByte += 32
|
||
|
return @directoryEntryName
|
||
|
|
||
|
listReset
|
||
|
|
||
|
PRI listCluster ' 3 Stack Longs
|
||
|
|
||
|
result := directoryEntry[26]
|
||
|
result.byte[1] := directoryEntry[27]
|
||
|
result.byte[2] := directoryEntry[20]
|
||
|
result.byte[3] := directoryEntry[21]
|
||
|
|
||
|
if((result == 1) or (FATEndOfClusterValue =< result))
|
||
|
' abort @FSCorrupted '@hive
|
||
|
abort err_fsysCorrupted
|
||
|
|
||
|
PRI listCase(unformatedName, formatedName) ' 5 Stack Longs
|
||
|
|
||
|
if(byte[unformatedName++] == ".")
|
||
|
result := @dot
|
||
|
|
||
|
if(byte[unformatedName++] == ".")
|
||
|
result := @dotdot
|
||
|
|
||
|
repeat strsize(unformatedName)
|
||
|
case byte[unformatedName++]
|
||
|
9 .. 10, 13, 32:
|
||
|
other:
|
||
|
result := formatedName
|
||
|
quit
|
||
|
|
||
|
PRI readWriteCurrentCluster(readWrite, fileOrDirectory) ' 19 Stack Longs
|
||
|
|
||
|
ifnot((fileOrDirectory <> "D") or partitionMountedFlag)
|
||
|
' abort @FSUnmounted '@hive
|
||
|
abort err_fsysUnmounted
|
||
|
|
||
|
'Needs to return true if it got the data and false if it didn't.
|
||
|
|
||
|
ifnot(currentByte & $1FF)
|
||
|
|
||
|
if(fileOpenFlag and (currentByte => $7FFFFE00))
|
||
|
return false 'abort string("End of File")
|
||
|
|
||
|
ifnot(fileOpenFlag or (currentByte < constant(65536 * 32)))
|
||
|
return false 'abort string("End of Directory")
|
||
|
|
||
|
ifnot(currentcluster or FATType or ((currentByte >> 9) < rootDirectorySectors))
|
||
|
return false 'abort string("End of Root")
|
||
|
|
||
|
if(currentByte and (not(FATWorkingSectorInCluster)) and (FATType or currentcluster))
|
||
|
|
||
|
result := currentCluster
|
||
|
ifnot(result)
|
||
|
result := rootCluster
|
||
|
|
||
|
readWriteFATBlock(result, "R")
|
||
|
fileOrDirectory := readFATEntry(result)
|
||
|
|
||
|
if(fileOrDirectory =< 1)
|
||
|
partitionMountedFlag := false
|
||
|
' abort @FSCorrupted '@hive
|
||
|
abort err_fsysCorrupted
|
||
|
|
||
|
if(fileOrDirectory => FATEndOfClusterValue)
|
||
|
'if(fileOpenFlag and (currentByte < (currentSize - 1)))
|
||
|
' partitionMountedFlag := false
|
||
|
' abort @FSCorrupted
|
||
|
|
||
|
if(readWrite == "R")
|
||
|
ifnot(fileOpenFlag)
|
||
|
ifnot(currentCluster)
|
||
|
' abort string("End of Root") '@hive
|
||
|
abort err_endOfRoot
|
||
|
|
||
|
' abort string("End of Directory") '@hive
|
||
|
abort err_endOfDirectory
|
||
|
|
||
|
else
|
||
|
' abort string("End of File") '@hive
|
||
|
abort err_endOfFile
|
||
|
|
||
|
fileOrDirectory := createClusterChain(result)
|
||
|
currentCluster := fileOrDirectory
|
||
|
readWriteCurrentSector("R")
|
||
|
|
||
|
return true
|
||
|
|
||
|
PRI readWriteCurrentSector(readWrite) ' 9 Stack Longs
|
||
|
|
||
|
result := FATFirstSectorInCluster(currentCluster) + FATWorkingSectorInCluster
|
||
|
|
||
|
ifnot(currentCluster)
|
||
|
result := rootDirectorySectorNumber + (currentByte >> 9)
|
||
|
|
||
|
if(FATType)
|
||
|
result := FATFirstSectorInCluster(rootCluster) + FATWorkingSectorInCluster
|
||
|
|
||
|
readWriteBlock(result, readWrite)
|
||
|
|
||
|
PRI findByte(byteToCompare, thisByte, thatByte) ' 6 Stack Longs
|
||
|
|
||
|
if((byteToCompare == thisByte) or (byteToCompare == thatByte))
|
||
|
return true
|
||
|
|
||
|
PRI findCharacter(charactersToSearch, characterToFind) | convertedCharacter ' 6 Stack Longs
|
||
|
|
||
|
repeat strsize(charactersToSearch)
|
||
|
|
||
|
convertedCharacter := byte[charactersToSearch++]
|
||
|
case convertedCharacter
|
||
|
"a" .. "z": convertedCharacter -= 32
|
||
|
|
||
|
if(convertedCharacter == characterToFind)
|
||
|
return true
|
||
|
|
||
|
PRI unformatName(name) ' 4 Stack Longs
|
||
|
|
||
|
if(name)
|
||
|
|
||
|
unformatedNameBuffer[12] := 0
|
||
|
|
||
|
bytefill(@unformatedNameBuffer, " ", 12)
|
||
|
bytemove(@unformatedNameBuffer, name, 8)
|
||
|
|
||
|
repeat while(unformatedNameBuffer[++result] <> " ")
|
||
|
unformatedNameBuffer[result++] := "."
|
||
|
|
||
|
bytemove(@unformatedNameBuffer[result], @byte[name][8], 3)
|
||
|
|
||
|
if(unformatedNameBuffer[result] == " ")
|
||
|
unformatedNameBuffer[--result] := " "
|
||
|
|
||
|
return @unformatedNameBuffer
|
||
|
|
||
|
PRI formatName(name) ' 4 Stack Longs
|
||
|
|
||
|
formatedNameBuffer[11] := 0
|
||
|
|
||
|
bytefill(@formatedNameBuffer, " ", 11)
|
||
|
|
||
|
repeat strsize(name--)
|
||
|
|
||
|
if(byte[++name] == ".")
|
||
|
result := 0
|
||
|
|
||
|
repeat strsize(++name)
|
||
|
|
||
|
if((result < 3) and (byte[name] > 31))
|
||
|
formatedNameBuffer[8 + result++] := byte[name++]
|
||
|
|
||
|
quit
|
||
|
|
||
|
if((result < 8) and (byte[name] > 31))
|
||
|
formatedNameBuffer[result++] := byte[name]
|
||
|
|
||
|
repeat result from 0 to 10
|
||
|
|
||
|
case formatedNameBuffer[result]
|
||
|
"a" .. "z": formatedNameBuffer[result] -= 32
|
||
|
$22, "*" .. ",", "." .. "/", ":" .. "?", "[" .. "]", "|", $7F: formatedNameBuffer[result] := "_"
|
||
|
|
||
|
if(formatedNameBuffer == " ")
|
||
|
formatedNameBuffer := "_"
|
||
|
|
||
|
if(formatedNameBuffer == $E5)
|
||
|
formatedNameBuffer := $5
|
||
|
|
||
|
return @formatedNameBuffer
|
||
|
|
||
|
PRI createClusterChain(clusterToLink) ' 14 Stack Longs
|
||
|
|
||
|
readWriteFATBlock(nextFreeCluster, "R")
|
||
|
repeat result from nextFreeCluster to (countOfClusters + 1)
|
||
|
|
||
|
ifnot(FATEntryNumber(result))
|
||
|
readWriteFATBlock(result, "R")
|
||
|
|
||
|
ifnot(readFATEntry(result))
|
||
|
|
||
|
writeFATEntry(result, true)
|
||
|
readWriteFATBlock(result, "W")
|
||
|
|
||
|
nextFreeCluster := ((result + 1) <# (countOfClusters + 1))
|
||
|
|
||
|
if(clusterToLink)
|
||
|
|
||
|
readWriteFATBlock(clusterToLink, "R")
|
||
|
writeFATEntry(clusterToLink, result)
|
||
|
readWriteFATBlock(clusterToLink, "W")
|
||
|
|
||
|
bytefill(@dataBlock, 0, 512)
|
||
|
|
||
|
repeat clusterToLink from 0 to (sectorsPerCluster - 1)
|
||
|
readWriteBlock((FATFirstSectorInCluster(result) + clusterToLink), "W")
|
||
|
|
||
|
quit
|
||
|
|
||
|
if(result => (countOfClusters + 1))
|
||
|
' abort string("Out Of Disk Free Space") '@hive
|
||
|
abort err_outOfDiskFreeSpace
|
||
|
|
||
|
PRI destroyClusterChain(clusterToDestroy) ' 14 Stack Longs
|
||
|
|
||
|
repeat while((1 < clusterToDestroy) and (clusterToDestroy < FATEndOfClusterValue))
|
||
|
|
||
|
ifnot(result and (FATBlockNumber(result) == FATBlockNumber(clusterToDestroy)))
|
||
|
readWriteFATBlock(clusterToDestroy, "R")
|
||
|
|
||
|
result := clusterToDestroy
|
||
|
clusterToDestroy := readFATEntry(clusterToDestroy)
|
||
|
writeFATEntry(result, false)
|
||
|
|
||
|
if(FATBlockNumber(result) <> FATBlockNumber(clusterToDestroy))
|
||
|
readWriteFATBlock(result, "W")
|
||
|
|
||
|
if(result)
|
||
|
readWriteFATBlock(result, "W")
|
||
|
|
||
|
PRI readFATEntry(cluster) ' 8 Stack Longs
|
||
|
|
||
|
cluster := FATEntryNumber(cluster)
|
||
|
|
||
|
ifnot(FATType)
|
||
|
return blockToWord(cluster)
|
||
|
|
||
|
return (blockTolong(cluster) & $0FFFFFFF)
|
||
|
|
||
|
PRI writeFATEntry(cluster, value) ' 10 Stack Longs
|
||
|
|
||
|
cluster := FATEntryNumber(cluster)
|
||
|
|
||
|
ifnot(FATType)
|
||
|
wordToBlock(cluster, value)
|
||
|
else
|
||
|
longToBlock(cluster, ((value & $0FFFFFFF) | (blockTolong(cluster) & $F0000000)))
|
||
|
|
||
|
PRI readWriteFATBlock(cluster, readWrite) ' 10 Stack Longs
|
||
|
|
||
|
cluster := FATBlockNumber(cluster)
|
||
|
result := externalFlags
|
||
|
|
||
|
repeat ((numberOfFATs & (readWrite == "W")) | (-(readWrite == "R")))
|
||
|
readWriteBlock((reservedSectorCount + cluster + (FATSectorSize * result++)), readWrite)
|
||
|
|
||
|
PRI FATBlockNumber(cluster) ' 4 Stack Longs
|
||
|
|
||
|
return (cluster >> (8 + FATType))
|
||
|
|
||
|
PRI FATEntryNumber(cluster) ' 4 Stack Longs
|
||
|
|
||
|
return ((cluster & ($FF >> (-FATType))) << (1 - FATType))
|
||
|
|
||
|
PRI FATEndOfClusterValue ' 3 Stack Longs
|
||
|
|
||
|
return ($FFF0 | (FATType & $0FFFFFF0))
|
||
|
|
||
|
PRI FATWorkingSectorInCluster ' 3 Stack Longs
|
||
|
|
||
|
return ((currentByte >> 9) // sectorsPerCluster)
|
||
|
|
||
|
PRI FATFirstSectorInCluster(cluster) ' 4 Stack Longs
|
||
|
|
||
|
return (((cluster - 2) * sectorsPerCluster) + firstDataSector)
|
||
|
|
||
|
PRI blockToLong(index) ' 4 Stack Longs
|
||
|
|
||
|
bytemove(@result, @dataBlock[index & $1FF], 4)
|
||
|
|
||
|
PRI blockToWord(index) ' 4 Stack Longs
|
||
|
|
||
|
bytemove(@result, @dataBlock[index & $1FF], 2)
|
||
|
|
||
|
PRI blockToByte(index) ' 4 Stack Longs
|
||
|
|
||
|
return dataBlock[index & $1FF]
|
||
|
|
||
|
PRI longToBlock(index, value) ' 5 Stack Longs
|
||
|
|
||
|
bytemove(@dataBlock[index & $1FF], @value, 4)
|
||
|
|
||
|
PRI wordToBlock(index, value) ' 5 Stack Longs
|
||
|
|
||
|
bytemove(@dataBlock[index & $1FF], @value, 2)
|
||
|
|
||
|
PRI byteToBlock(index, value) ' 5 Stack Longs
|
||
|
|
||
|
dataBlock[index & $1FF] := value
|
||
|
|
||
|
PRI readClock ' 3 + 11 Stack Longs
|
||
|
|
||
|
repeat while(lockset(cardLockID))
|
||
|
cardTime := ((rtc.getSeconds >> 1) | (rtc.getMinutes << 5) | (rtc.getHours << 11))
|
||
|
cardDate := (rtc.getDate | (rtc.getMonth << 5) | ((rtc.getYear - 1980) << 9))
|
||
|
|
||
|
lockclr(cardLockID)
|
||
|
return cardDate
|
||
|
|
||
|
PRI readWriteBlock(address, command) ' 5 Stack Longs
|
||
|
|
||
|
if(strcomp(@cardUniqueID, @cardUniqueIDCopy) or (command == "M"))
|
||
|
repeat while(lockset(cardLockID))
|
||
|
|
||
|
if command == "B" 'frida
|
||
|
lockclr(cardLockID) 'frida
|
||
|
lockret(cardLockID) 'frida
|
||
|
|
||
|
cardSectorAddress := (address + (partitionStart & (command <> "B")))
|
||
|
cardDataBlockAddress := (@dataBlock & (command <> "B"))
|
||
|
cardCommandFlag := command
|
||
|
repeat while(cardCommandFlag)
|
||
|
|
||
|
command := cardErrorFlag~
|
||
|
lockclr(cardLockID)
|
||
|
|
||
|
if(command)
|
||
|
partitionMountedFlag := false
|
||
|
' abort string("Disk I/O Error") '@hive
|
||
|
abort err_diskIOError
|
||
|
|
||
|
DAT 'ASM-Code
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' SD/SDHC/MMC Driver
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
org
|
||
|
|
||
|
' //////////////////////Initialization/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
initialization neg phsa, #1 ' Setup clock counter.
|
||
|
movs ctra, #((Clock_Pin <# 31) #> 0) '
|
||
|
movi ctra, #%0_00100_000 '
|
||
|
|
||
|
mov outa, chipSelectPin ' Setup I/O Pins.
|
||
|
or outa, dataInPin '
|
||
|
mov dira, chipSelectPin '
|
||
|
or dira, dataInPin '
|
||
|
or dira, clockPin '
|
||
|
|
||
|
mov cardCounter, fiveHundredAndTwelve ' Skip to instruction handle.
|
||
|
jmp #instructionWait '
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Command Center
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
instructionRetry cmp cardBuffer, #"M" wc, wz ' Try at most 8 more times to mount the card.
|
||
|
if_c cmp cardBuffer, #"F" wc, wz '
|
||
|
if_nc_or_z djnz cardBuffer, #mountCard '
|
||
|
|
||
|
cmp cardBuffer, #"R" wz ' Try at most twice to read the specified block.
|
||
|
if_z djnz cardBuffer, #readBlock '
|
||
|
|
||
|
cmp cardBuffer, #"W" wz ' Try at most twice to write the specified block.
|
||
|
if_z djnz cardBuffer, #writeBlock '
|
||
|
|
||
|
cmp cardBuffer, #"B" wz ' Reboot the chip if booting failure.
|
||
|
if_z mov buffer, #$80 '
|
||
|
if_z clkset buffer '
|
||
|
|
||
|
instructionError wrbyte maxPositiveInteger, CEFAddress ' Assert Error Flag and unmount card.
|
||
|
instructionUnmount mov cardMounted, #0 '
|
||
|
|
||
|
' //////////////////////Instruction Handle/////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
instructionLoop wrbyte fiveHundredAndTwelve, CCFAddress ' Wait for a command to come.
|
||
|
instructionWait rdbyte cardBuffer, CCFAddress '
|
||
|
test cardMounted, maxPositiveInteger wc '
|
||
|
|
||
|
cmp cardBuffer, #"B" wz ' If rebooting was requested do it.
|
||
|
if_z_and_nc jmp #instructionError '
|
||
|
if_z_and_c jmp #rebootChip '
|
||
|
|
||
|
cmp cardBuffer, #"R" wz ' If read block was requested do it.
|
||
|
if_z_and_nc jmp #instructionError '
|
||
|
if_z_and_c jmp #readBlock '
|
||
|
|
||
|
cmp cardBuffer, #"W" wz ' If write block was requested do it.
|
||
|
if_z_and_nc jmp #instructionError '
|
||
|
if_z_and_c jmp #writeBlock '
|
||
|
|
||
|
djnz cardCounter, #instructionSkip ' Poll the card every so often.
|
||
|
mov cardCounter, fiveHundredAndTwelve '
|
||
|
if_nc jmp #instructionSkip '
|
||
|
call #cardStatus '
|
||
|
|
||
|
instructionSkip cmp cardBuffer, #"M" wz ' If mounting was requested do it.
|
||
|
if_nz jmp #instructionWait '
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Mount Card
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mountCard mov SPITiming, slowTiming ' Setup SPI parameters.
|
||
|
|
||
|
mov counter, #80 ' Send out for more than 1 millisecond.
|
||
|
seventyFourClocks call #readSPI '
|
||
|
djnz counter, #seventyFourClocks '
|
||
|
|
||
|
' //////////////////////Go Idle State//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov counter, #80 ' Setup counter to try a few times.
|
||
|
|
||
|
enterIdleStateLoop mov SPICommandOut, #($40 | 0) ' Send out command 0.
|
||
|
mov SPIParameterOut, #0 '
|
||
|
movs commandSPICRC, #$95 '
|
||
|
call #commandSPI '
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
cmp SPIResponceIn, #1 wz ' Try a few times.
|
||
|
if_nz djnz counter, #enterIdleStateLoop '
|
||
|
tjz counter, #instructionRetry '
|
||
|
|
||
|
' //////////////////////Send Interface Condition///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov SPICommandOut, #($40 | 8) ' Send out command 8.
|
||
|
mov SPIParameterOut, #$1AA '
|
||
|
movs commandSPICRC, #$87 '
|
||
|
call #commandSPI '
|
||
|
call #longSPI '
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
test SPIResponceIn, #$7E wz ' If failure goto SD 1.X initialization.
|
||
|
if_nz jmp #exitIdleState_SD '
|
||
|
|
||
|
and SPILongIn, #$1FF ' SD 2.0 initialization.
|
||
|
cmp SPILongIn, #$1AA wz '
|
||
|
if_nz jmp #instructionRetry '
|
||
|
|
||
|
' //////////////////////Send Operating Condition///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
exitIdleState_SD mov cardType, #0 ' Card type is MMC.
|
||
|
|
||
|
mov counter, #80 ' Setup counter to try a few times.
|
||
|
|
||
|
exitIdleStateLoop_SD mov SPICommandOut, #($40 | 55) ' Send out command 55.
|
||
|
mov SPIParameterOut, #0 '
|
||
|
call #commandSPI '
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
test SPIResponceIn, #$7E wz ' If failure goto MMC initialization. '
|
||
|
if_nz jmp #exitIdleState_MMC '
|
||
|
|
||
|
mov SPICommandOut, #($40 | 41) ' Send out command 41 with HCS bit set.
|
||
|
mov SPIParameterOut, HCSBitMask '
|
||
|
call #commandSPI '
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
cmp SPIResponceIn, #0 wz ' Try a few times.
|
||
|
if_nz djnz counter, #exitIdleStateLoop_SD '
|
||
|
tjz counter, #instructionRetry '
|
||
|
|
||
|
djnz cardType, #readOCR ' Card type is SD and skip MMC initialization.
|
||
|
|
||
|
' //////////////////////Send Operating Condition///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
exitIdleState_MMC mov counter, #80 ' Setup counter to try a few times.
|
||
|
|
||
|
exitIdleStateLoop_MMC mov SPICommandOut, #($40 | 1) ' Send out command 1.
|
||
|
mov SPIParameterOut, #0 '
|
||
|
call #commandSPI '
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
cmp SPIResponceIn, #0 wz ' Try a few times.
|
||
|
if_nz djnz counter, #exitIdleStateLoop_MMC '
|
||
|
tjz counter, #instructionRetry '
|
||
|
|
||
|
' //////////////////////Read OCR Register//////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
readOCR mov SPICommandOut, #($40 | 58) ' Ask the card for its OCR register.
|
||
|
mov SPIParameterOut, #0 '
|
||
|
call #commandSPI '
|
||
|
call #longSPI '
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
tjnz SPIResponceIn, #instructionRetry ' If failure abort.
|
||
|
|
||
|
test SPILongIn, OCRCheckMask wz ' If voltage not supported abort.
|
||
|
shl SPILongIn, #1 wc '
|
||
|
if_z_or_nc jmp #instructionRetry '
|
||
|
|
||
|
shl SPILongIn, #1 wc ' SDHC supported or not.
|
||
|
if_c mov SPIShift, #0 '
|
||
|
if_nc mov SPIShift, #9 '
|
||
|
|
||
|
' //////////////////////Set Block Length///////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov SPICommandOut, #($40 | 16) ' Send out command 16.
|
||
|
mov SPIParameterOut, fiveHundredAndTwelve '
|
||
|
call #commandSPI '
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
tjnz SPIResponceIn, #instructionRetry ' If failure abort.
|
||
|
|
||
|
' //////////////////////Read CSD Register//////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov SPICommandOut, #($40 | 9) ' Ask the card for its CSD register.
|
||
|
mov SPIParameterOut, #0 '
|
||
|
call #commandSPI '
|
||
|
|
||
|
tjnz SPIResponceIn, #instructionRetry ' If failure abort.
|
||
|
call #repsonceSPI '
|
||
|
cmp SPIResponceIn, #$FE wz '
|
||
|
if_nz jmp #instructionRetry '
|
||
|
|
||
|
mov counter, #16 ' Setup to read the CSD register.
|
||
|
movd readCSDModify, #CSDRegister '
|
||
|
|
||
|
readCSDLoop call #readSPI ' Read the CSD register in.
|
||
|
readCSDModify mov 0, SPIDataIn '
|
||
|
add readCSDModify, fiveHundredAndTwelve '
|
||
|
djnz counter, #readCSDLoop '
|
||
|
|
||
|
call #wordSPI ' Shutdown SPI clock.
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
' //////////////////////Read CID Register//////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov SPICommandOut, #($40 | 10) ' Ask the card for its CID register.
|
||
|
mov SPIParameterOut, #0 '
|
||
|
call #commandSPI '
|
||
|
|
||
|
tjnz SPIResponceIn, #instructionRetry ' If failure abort.
|
||
|
call #repsonceSPI '
|
||
|
cmp SPIResponceIn, #$FE wz '
|
||
|
if_nz jmp #instructionRetry '
|
||
|
|
||
|
mov counter, #16 ' Setup to read the CID register.
|
||
|
mov buffer, CUIDAddress '
|
||
|
|
||
|
readCIDLoop call #readSPI ' Read the CID register in.
|
||
|
wrbyte SPIDataIn, buffer '
|
||
|
add buffer, #1 '
|
||
|
djnz counter, #readCIDLoop '
|
||
|
|
||
|
wrbyte fiveHundredAndTwelve, buffer ' Clear the last byte for string compare.
|
||
|
|
||
|
call #wordSPI ' Shutdown SPI clock.
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
' //////////////////////Setup Card Variables///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov SPITiming, fastTiming ' Setup SPI parameters.
|
||
|
|
||
|
testn cardType, #0 wz, wc ' Determine CSD structure version.
|
||
|
if_nz test CSDRegister, #$40 wc '
|
||
|
if_nz test CSDRegister, #$80 wz '
|
||
|
|
||
|
if_nc_and_z mov counter, (CSDRegister + 6) ' Extract card size.
|
||
|
if_nc_and_z and counter, #$3 '
|
||
|
if_nc_and_z shl counter, #10 '
|
||
|
if_nc_and_z mov buffer, (CSDRegister + 7) '
|
||
|
if_nc_and_z shl buffer, #2 '
|
||
|
if_nc_and_z mov cardSize, (CSDRegister + 8) '
|
||
|
if_nc_and_z shr cardSize, #6 '
|
||
|
if_nc_and_z or cardSize, counter '
|
||
|
if_nc_and_z or cardSize, buffer '
|
||
|
|
||
|
if_c_and_z mov counter, (CSDRegister + 7) ' Extract card size.
|
||
|
if_c_and_z and counter, #$3F '
|
||
|
if_c_and_z shl counter, #16 '
|
||
|
if_c_and_z mov buffer, (CSDRegister + 8) '
|
||
|
if_c_and_z shl buffer, #8 '
|
||
|
if_c_and_z mov cardSize, (CSDRegister + 9) '
|
||
|
if_c_and_z or cardSize, counter '
|
||
|
if_c_and_z or cardSize, buffer '
|
||
|
|
||
|
if_nc_and_z mov buffer, (CSDRegister + 9) ' Extract card size multiplier.
|
||
|
if_nc_and_z and buffer, #$3 '
|
||
|
if_nc_and_z shl buffer, #1 '
|
||
|
if_nc_and_z mov cardSizeMultiplier, (CSDRegister + 10) '
|
||
|
if_nc_and_z shr cardSizeMultiplier, #7 '
|
||
|
if_nc_and_z or cardSizeMultiplier, buffer '
|
||
|
|
||
|
if_nc_and_z mov cardReadBlockLength, (CSDRegister + 5) ' Extract read block length.
|
||
|
if_nc_and_z and cardReadBlockLength, #$F '
|
||
|
|
||
|
if_nc_and_z sub cardReadBlockLength, #9 ' Compute card sector count for version 1.0 CSD.
|
||
|
if_nc_and_z add cardSizeMultiplier, #2 '
|
||
|
if_z add cardSize, #1 '
|
||
|
if_nc_and_z shl cardSize, cardReadBlockLength '
|
||
|
if_nc_and_z shl cardSize, cardSizeMultiplier '
|
||
|
|
||
|
if_c_and_z shl cardSize, #10 ' Compute card sector count for version 2.0 CSD.
|
||
|
|
||
|
max cardSize, maxPositiveInteger ' Limit maximum partition size.
|
||
|
|
||
|
if_nz neg cardSize, #1 ' Unknown CSD structure. Card size to -1.
|
||
|
|
||
|
wrlong cardSize, par ' Update Card Size.
|
||
|
|
||
|
mov cardSizeMinusOne, cardSize ' Compute maximum allowed addressable sector.
|
||
|
sub cardSizeMinusOne, #1 '
|
||
|
|
||
|
neg cardMounted, #1 ' Return.
|
||
|
jmp #instructionLoop '
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Read Block
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
readBlock rdlong SPIParameterOut, CSAAddress ' Read a block.
|
||
|
max SPIParameterOut, cardSizeMinusOne '
|
||
|
shl SPIParameterOut, SPIShift '
|
||
|
mov SPICommandOut, #($40 | 17) '
|
||
|
call #commandSPI '
|
||
|
|
||
|
tjnz SPIResponceIn, #instructionRetry ' If failure abort.
|
||
|
call #repsonceSPI '
|
||
|
cmp SPIResponceIn, #$FE wz '
|
||
|
if_nz jmp #instructionRetry '
|
||
|
|
||
|
mov counter, fiveHundredAndTwelve ' Setup loop.
|
||
|
readBlockModify rdlong buffer, CDBAddress '
|
||
|
|
||
|
readBlockLoop call #readSPI ' Read data into memory.
|
||
|
wrbyte SPIDataIn, buffer '
|
||
|
add buffer, #1 '
|
||
|
djnz counter, #readBlockLoop '
|
||
|
|
||
|
call #wordSPI ' Shutdown SPI clock.
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
readBlock_ret jmp #instructionLoop ' Return. Become RET instruction when rebooting.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Write Block
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
writeBlock rdlong SPIParameterOut, CSAAddress ' Write a block.
|
||
|
max SPIParameterOut, cardSizeMinusOne '
|
||
|
shl SPIParameterOut, SPIShift '
|
||
|
mov SPICommandOut, #($40 | 24) '
|
||
|
call #commandSPI '
|
||
|
|
||
|
tjnz SPIResponceIn, #instructionRetry ' If failure abort.
|
||
|
|
||
|
mov SPIDataOut, #$FE ' Send start of data token.
|
||
|
call #writeSPI '
|
||
|
|
||
|
mov counter, fiveHundredAndTwelve ' Setup loop.
|
||
|
rdlong buffer, CDBAddress '
|
||
|
|
||
|
writeBlockLoop rdbyte SPIDataOut, buffer ' Write data out from memory.
|
||
|
add buffer, #1 '
|
||
|
call #writeSPI '
|
||
|
djnz counter, #writeBlockLoop '
|
||
|
|
||
|
call #wordSPI ' Write out the 16 bit CRC.
|
||
|
|
||
|
call #repsonceSPI ' If failure abort.
|
||
|
and SPIDataIn, #$1F '
|
||
|
cmp SPIDataIn, #$5 wz '
|
||
|
if_nz jmp #instructionRetry '
|
||
|
|
||
|
call #cardBusy ' Shutdown SPI clock.
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
jmp #instructionLoop ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Reboot Chip
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
rebootChip rdlong buffer, CDBAddress ' Check to make sure a reboot was requested.
|
||
|
tjnz buffer, #instructionError '
|
||
|
|
||
|
' //////////////////////Shutdown Cogs//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov counter, #8 ' Setup cog stop loop.
|
||
|
cogid buffer '
|
||
|
|
||
|
rebootCogLoop sub counter, #1 ' Stop all cogs but this one.
|
||
|
cmp counter, buffer wz '
|
||
|
if_nz cogstop counter '
|
||
|
tjnz counter, #rebootCogLoop '
|
||
|
|
||
|
' //////////////////////Setup Memory///////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov counter, #64 ' Setup to grab all sector addresses.
|
||
|
rdlong buffer, CSAAddress '
|
||
|
|
||
|
rebootSectorLoadLoop rdlong cardRebootSectors, buffer ' Get all addresses of the 64 sectors of new code into memory.
|
||
|
add buffer, #4 '
|
||
|
add rebootSectorLoadLoop, fiveHundredAndTwelve '
|
||
|
djnz counter, #rebootSectorLoadLoop '
|
||
|
|
||
|
' //////////////////////Clear Memory///////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov counter, fiveHundredAndTwelve ' Clear all memory. Leave buffer the pointer at 0.
|
||
|
shl counter, #6 '
|
||
|
mov buffer, #0 '
|
||
|
rebootCodeClearLoop sub counter, #4 '
|
||
|
wrlong buffer, counter '
|
||
|
tjnz counter, #rebootCodeClearLoop '
|
||
|
|
||
|
' //////////////////////Fill Memory////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
mov readBlock, #0 ' Fill these two commands with NOPs.
|
||
|
mov readBlockModify, #0 '
|
||
|
|
||
|
mov cardCounter, #64 ' Ready to fill all memory. Pointer already at 0.
|
||
|
|
||
|
rebootCodeFillLoop mov SPIParameterOut, cardRebootSectors ' Reuse read block code. Finish if next sector is 0.
|
||
|
tjz SPIParameterOut, #rebootReady '
|
||
|
add rebootCodeFillLoop, #1 '
|
||
|
call #readBlock '
|
||
|
djnz cardCounter, #rebootCodeFillLoop '
|
||
|
|
||
|
' //////////////////////Boot Interpreter///////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
rebootReady rdword buffer, #$A ' Setup the stack markers.
|
||
|
sub buffer, #4 '
|
||
|
wrlong rebootStackMark, buffer '
|
||
|
sub buffer, #4 '
|
||
|
wrlong rebootStackMark, buffer '
|
||
|
|
||
|
rdbyte buffer, #$4 ' Switch to new clock mode.
|
||
|
clkset buffer '
|
||
|
|
||
|
coginit rebootInterpreter ' Restart running new code.
|
||
|
|
||
|
cogid buffer ' Shutdown.
|
||
|
cogstop buffer '
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Card Status
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
cardStatus mov SPICommandOut, #($40 | 13) ' Send out command 13.
|
||
|
mov SPIParameterOut, #0 '
|
||
|
call #commandSPI '
|
||
|
call #byteSPI '
|
||
|
call #shutdownSPI '
|
||
|
|
||
|
tjnz SPIResponceIn, #instructionUnmount ' If failure abort.
|
||
|
tjnz SPILongIn, #instructionUnmount '
|
||
|
|
||
|
cardStatus_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Card Busy
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
cardBusy mov counter, writeTimeout ' Setup loop.
|
||
|
|
||
|
cardBusyLoop call #readSPI ' Wait until card is not busy.
|
||
|
cmp SPIDataIn, #0 wz '
|
||
|
if_z djnz counter, #cardBusyLoop '
|
||
|
tjz counter, #instructionRetry '
|
||
|
|
||
|
cardBusy_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Command SPI
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
commandSPI andn outa, chipSelectPin ' Activate the SPI bus.
|
||
|
call #readSPI '
|
||
|
|
||
|
mov SPIDataOut, SPICommandOut ' Send out command.
|
||
|
call #writeSPI '
|
||
|
|
||
|
movs writeSPI, #32 ' Send out parameter.
|
||
|
mov SPIDataOut, SPIParameterOut '
|
||
|
call #writeSPI '
|
||
|
movs writeSPI, #8 '
|
||
|
|
||
|
commandSPICRC mov SPIDataOut, #0 ' Send out CRC token.
|
||
|
call #writeSPI '
|
||
|
|
||
|
call #repsonceSPI ' Read in responce.
|
||
|
|
||
|
commandSPI_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Responce SPI
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
repsonceSPI mov SPIResponceIn, readTimeout ' Setup responce poll counter.
|
||
|
|
||
|
repsonceSPILoop call #readSPI ' Poll for responce.
|
||
|
cmp SPIDataIn, #$FF wz '
|
||
|
if_z djnz SPIResponceIn, #repsonceSPILoop '
|
||
|
|
||
|
mov SPIResponceIn, SPIDataIn ' Move responce into return value.
|
||
|
|
||
|
repsonceSPI_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Long SPI
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
longSPI add readSPI, #16 ' Read in 32, 16, or 8 bits.
|
||
|
wordSPI add readSPI, #8 '
|
||
|
byteSPI call #readSPI '
|
||
|
movs readSPI, #8 '
|
||
|
|
||
|
mov SPILongIn, SPIDataIn ' Move long into return value.
|
||
|
|
||
|
byteSPI_ret ' Return.
|
||
|
wordSPI_ret '
|
||
|
longSPI_ret ret '
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Shutdown SPI
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
shutdownSPI call #readSPI ' Shutdown SPI bus.
|
||
|
or outa, chipSelectPin '
|
||
|
call #readSPI '
|
||
|
|
||
|
shutdownSPI_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Read SPI
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
readSPI mov SPICounter, #8 ' Setup counter to read in 1 - 32 bits. Default 8.
|
||
|
mov SPIDataIn, #0 wc '
|
||
|
|
||
|
mov phsa, #0 ' Start clock low.
|
||
|
mov frqa, SPITiming '
|
||
|
|
||
|
readSPILoop waitpne clockPin, clockPin ' Get bit.
|
||
|
rcl SPIDataIn, #1 '
|
||
|
waitpeq clockPin, clockPin '
|
||
|
test dataOutPin, ina wc '
|
||
|
|
||
|
djnz SPICounter, #readSPILoop ' Loop
|
||
|
|
||
|
mov frqa, #0 ' Stop clock high.
|
||
|
rcl SPIDataIn, #1 '
|
||
|
|
||
|
readSPI_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Write SPI
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
writeSPI mov SPICounter, #8 ' Setup counter to write out 1 - 32 bits. Default 8.
|
||
|
ror SPIDataOut, SPICounter '
|
||
|
|
||
|
mov phsa, #0 ' Start clock low.
|
||
|
mov frqa, SPITiming '
|
||
|
|
||
|
writeSPILoop shl SPIDataOut, #1 wc ' Set bit.
|
||
|
waitpne clockPin, clockPin '
|
||
|
muxc outa, dataInPin '
|
||
|
waitpeq clockPin, clockPin '
|
||
|
|
||
|
djnz SPICounter, #writeSPILoop ' Loop.
|
||
|
|
||
|
mov frqa, #0 ' Stop clock high.
|
||
|
or outa, dataInPin '
|
||
|
|
||
|
writeSPI_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' CRC7 Augmentation
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
CRC7 mov CRCCounter, #7 ' Get variables ready.
|
||
|
|
||
|
CRC7Loop shl CRCBuffer, #1 ' Do the CRC7 calculation.
|
||
|
test CRCBuffer, #$80 wc '
|
||
|
if_c xor CRCBuffer, #$9 '
|
||
|
djnz CRCCounter, #CRC7Loop '
|
||
|
|
||
|
CRC7_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' CRC16 Augmentation
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
CRC16 mov CRCCounter, #16 ' Get variables ready.
|
||
|
|
||
|
CRC16Loop shl CRCBuffer, #1 ' Do the CRC16 calculation.
|
||
|
test CRCBuffer, CRC16TestBit wc '
|
||
|
if_c xor CRCBuffer, CRC16Polynomial '
|
||
|
djnz CRCCounter, #CRC16Loop '
|
||
|
|
||
|
CRC16_ret ret ' Return.
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
' Data
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
cardMounted long 0
|
||
|
|
||
|
' //////////////////////Constants//////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
fiveHundredAndTwelve long $200 ' Constant 512.
|
||
|
maxPositiveInteger long $7FFFFFFF ' Constant 2,147,483,647.
|
||
|
|
||
|
CRC16TestBit long $10000 ' The CRC16 test bit mask.
|
||
|
CRC16Polynomial long $1021 ' The CRC16 polynomial bit mask.
|
||
|
|
||
|
OCRCheckMask long %00_000000_00110000_00000000_00000000 ' Parameter check mask for OCR bits.
|
||
|
HCSBitMask long %01_000000_00000000_00000000_00000000 ' Parameter bit mask for HCS bit.
|
||
|
|
||
|
rebootInterpreter long ($0001 << 18) | ($3C01 << 4) ' Spin interpreter boot information.
|
||
|
rebootStackMark long $FFF9FFFF ' Stack mark used for spin code.
|
||
|
|
||
|
' //////////////////////Configuration Settings/////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
slowTiming long 0 ' 250KHz Clock speed.
|
||
|
fastTiming long 0 ' 2.5MHz Clock speed.
|
||
|
|
||
|
readTimeout long 250_000 ' Read timeout of 100 milliseconds at 2.5Mhz clock.
|
||
|
writeTimeout long 625_000 ' Write timeout of 250 milliseconds at 2.5Mhz clock.
|
||
|
|
||
|
' //////////////////////Pin Masks//////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
dataOutPin long (|<((Data_Out_Pin <# 31) #> 0))
|
||
|
clockPin long (|<((Clock_Pin <# 31) #> 0))
|
||
|
dataInPin long (|<((Data_In_Pin <# 31) #> 0))
|
||
|
chipSelectPin long (|<((Chip_Select_Pin <# 31) #> 0))
|
||
|
dataOutOff long 0
|
||
|
|
||
|
' //////////////////////Addresses//////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
CCFAddress long 0
|
||
|
CEFAddress long 0
|
||
|
|
||
|
CUIDAddress long 0
|
||
|
|
||
|
CDBAddress long 0
|
||
|
CSAAddress long 0
|
||
|
|
||
|
|
||
|
DAT 'Variable Array
|
||
|
|
||
|
' //////////////////////Variable Array/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
cardCommandFlag byte 0
|
||
|
cardErrorFlag byte 0
|
||
|
|
||
|
cardLockID byte 0 'frida ((HUB_Lock <# 7) #> 0)
|
||
|
cardUniqueID byte 0[17]
|
||
|
|
||
|
cardDataBlockAddress long 0
|
||
|
cardSectorAddress long 0
|
||
|
cardSectorCount long 0
|
||
|
|
||
|
DAT 'String Array
|
||
|
|
||
|
' //////////////////////String Array///////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
dot byte ". ", 0
|
||
|
dotdot byte ".. ", 0
|
||
|
|
||
|
{ '@hive
|
||
|
FSUnmounted byte "File System Unmounted", 0
|
||
|
FSCorrupted byte "File System Corrupted", 0
|
||
|
FSUnsupported byte "File System Unsupported", 0
|
||
|
|
||
|
fileOrDirectoryNotFound byte "File Or Directory Not Found", 0
|
||
|
fileNotFound byte "File Not Found", 0
|
||
|
directoryNotFound byte "Directory Not Found", 0
|
||
|
}
|
||
|
|
||
|
' //////////////////////Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
buffer res 1
|
||
|
counter res 1
|
||
|
|
||
|
' //////////////////////Card Variables/////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
cardBuffer res 1
|
||
|
cardCounter res 1
|
||
|
|
||
|
cardType res 1
|
||
|
cardSize res 1
|
||
|
|
||
|
cardSizeMultiplier res 1
|
||
|
cardSizeMinusOne res 1
|
||
|
|
||
|
cardReadBlockLength res 1
|
||
|
cardWriteBlockLength res 1
|
||
|
|
||
|
CSDRegister res 16
|
||
|
CIDRegister res 16
|
||
|
|
||
|
cardRebootSectors res 64
|
||
|
|
||
|
' //////////////////////SPI Variables//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
SPICommandOut res 1
|
||
|
SPIParameterOut res 1
|
||
|
SPIResponceIn res 1
|
||
|
SPILongIn res 1
|
||
|
|
||
|
SPIShift res 1
|
||
|
SPITiming res 1
|
||
|
|
||
|
SPIDataIn res 1
|
||
|
SPIDataOut res 1
|
||
|
|
||
|
SPIBuffer res 1
|
||
|
SPICounter res 1
|
||
|
|
||
|
' //////////////////////CRC Variables//////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
CRCBuffer res 1
|
||
|
CRCCounter res 1
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
fit 496
|
||
|
|
||
|
' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
{{
|
||
|
|
||
|
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
|
│ TERMS OF USE: MIT License │
|
||
|
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||
|
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
|
||
|
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
|
||
|
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the │
|
||
|
│Software is furnished to do so, subject to the following conditions: │
|
||
|
│ │
|
||
|
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the │
|
||
|
│Software. │
|
||
|
│ │
|
||
|
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
|
||
|
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
|
||
|
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
||
|
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
||
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
|
}}
|