
- Überarbeitung der Routine zum mounten der SD-Card. Da verschiedene Karten unterschiedliches Timing haben, wird jetzt solange versucht zu mounten, bis ein Erfolg eintritt, was zusätzlich akustisch durch einen leise anschwellenden Ton angezeigt wird. Das Verfahren ist jetzt wesentlich robuster. - rtc.setSQWOUTState(1) --> rtc.setSQWOUTState(0) deaktiviert den Frequenzausgang, verringert damit lt. DS1307-Datenblatt den Pufferstrom von 480 auf 300 nA und erhöht somit die Pufferdauer der Batterie auf das 1,6-fache. - Plexbus-Funktionen entfernt - Screeninterface-Funktionen zugefügt flash\bellatrix\belflash.spin - Anpassung für verschiedene Zeilenumbrüche in print_char eingefügt. flash\regnatix\regflash.spin - Der Loader hat fälschlicherweise das Warmstartflag für die Ramdisk gesetzt, wodurch sie nicht resetfest war. forth\fib.mod - Fibonacci-Benchmark (iterativ) in Forth. lib\adm-fat.spin - Fehler in setCharacterPosition: Bei einem Wechsel von einer Position > 0 auf Position = 0 wurde der erste Sektor mit falschen Daten überschrieben. lib\reg-ios.spin - Funktionsset für Grafikmodus 0 eingefügt - sfx_keyoff, sfx_stop eingefügt - printq zugefügt: Ausgabe einer Zeichenkette ohne Steuerzeichen - Korrektur char_ter_bs - Plexbus-Funktionen entfernt - Screeninterface-Funktionen eingefügt - Bellatrix-Funktionen blktrans, bmgr_load eingefügt - Funktion os_error zugefügt für zentrale Ausgabe von Fehlern - Korrektur BS in input-Funktion - Funktion printblk für schnellen Blocktransfer - Div. Fehler in den Ramdisk-Funktionen, welche jetzt auch resetfest ist. - Funktion rd_getback um Zeichen rückwärts aus der Ramdisk zu lesen. - Funktion ram_getfree liefert freien Speicher im eRAM system\regnatix\eram.spin - Korrektur BS-Steuercode system\regnatix\hplay.spin - Der HSS-Player hat seine Daten fals im SYS-Modus im eRAM abgelegt und so die Ramdisk beschädigt. Korrektur der Speichernutzung. system\regnatix\regime.spin - Korrekte Initialisierung der Ramdisk (resetfest) - Korrektur der Bisldschirminitialisierung nach dem Laden von Bellatrix-Code - Verwendung von ios.os_error für die Fehlerausgabe - Fehler im Kommando "reboot" beim Kaltstart behoben - Korrektur Ausgabe von "cogs" system\regnatix\time.spin - Korrektur Tipfehler system\regnatix\basic.spin Ich habe Femto Basic entfernt, da es nicht integraler Bestandteil von TriOS ist und mir die Zeit fehlt es an den aktuelen Stand anzupassen.
2451 lines
306 KiB
Plaintext
2451 lines
306 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. │
|
|
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
}}
|