; -*- coding: utf-8 -*-
; DTCforthMSP430FR5xxxSD_RW.asm
+; and only for FR5xxx and FR6xxx with RTC_B or RTC_C hardware if you want write file with date and time.
+
+; Tested with MSP-EXP430FR5969 launchpad
+; Copyright (C) <2015> <J.M. THOORENS>
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+
; ======================================================================
; READ" primitive as part of OpenPathName
; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
; ======================================================================
; ----------------------------------;
-OPEN_QREAD ;
+OPEN_1W ;
CMP #1,W ; open_type = READ" ?
- JNZ OPEN_QWRITE ; no : goto next step
+ JNZ OPEN_2W ; no : goto next step
; ----------------------------------;
OPEN_READ ;
; ----------------------------------;
CMP #0,S ; open file happy end ?
JNZ OPEN_Error ; no
- MOV @IP+,PC ;
+ MOV @IP+,PC ; no more to do
; ----------------------------------;
;Z READ -- f
; sectors are loaded in SD_BUF and BufferLen leave the count of loaded bytes.
; when the last sector of file is loaded in buffer, the handle is automatically closed and flag is true (<>0).
-; ----------------------------------;
+; ==================================;
FORTHWORD "READ" ; -- fl closed flag
-; ----------------------------------;
+; ==================================;
READ
SUB #2,PSP ;
MOV TOS,0(PSP) ;
MOV &CurrentHdl,TOS ;
CALL #Read_File ;SWX
-READ_END
- SUB &CurrentHdl,TOS ; -- fl if fl <>0 (if Z=0) handle is closed
- MOV @IP+,PC ;
+ SUB &CurrentHdl,TOS ; -- fl if fl<>0 (if Z=0) handle is closed
+ MOV @IP+,PC ;
; ----------------------------------;
-;-----------------------------------------------------------------------
-; WRITE" (CREATE part) subroutines
-;-----------------------------------------------------------------------
-
-; parse all FAT sectors until free cluster is found
-; this NewCluster is marked as the end's one (-1)
+; ==================================;
+SaveSectorWtoFATs ;SWXY W = FATsector loaded in SD_buf
+; ==================================;
+ MOV W,Y ; Y = W
+ ADD &OrgFAT1,W ; update FAT#1
+ CALL #WriteFATsectorW ;SWX
+ MOV Y,W ; W = FATsector
+ ADD &OrgFAT2,W ; update FAT#2
+WriteFATsectorW ;
+ MOV #0,X ;
+ MOV #WriteSectorWX,PC ;SWX then RET
+; ----------------------------------;
+; parse all FAT sectors until free cluster is found
+; this New Cluster is marked as the end's one (-1)
-; input : CurFATsector
+; input : W = FATSector, Y = FAToffset
; use SWX registers
-; output: W = new FATsector, SD_BUF = [new FATsector], NewCluster
-; SectorL is unchanged, FATS are not updated.
+; output: updated (ClusterHL, FATsector, W = FATsector), SD_BUF = [new FATsector]
+; SectorHL is unchanged, FATS are updated.
; S = 2 --> Disk FULL error
+; ==================================;
+SearchMarkNewClusterHL ;SWXY <== WRITE_FILE, OPEN_WRITE_CREATE, OPEN_OVERWRITE
+; ==================================;
+ MOV #8,S ; preset disk full return error
+ PUSH W ;3 R-- FATsector
; ----------------------------------;
-SearchNewCluster ; <== CREATE file, WRITE_File
-; ----------------------------------;
- MOV #2,S ; preset disk full return error
- PUSH &CurFATsector ; last known free cluster sector
- MOV &FATtype,Y ;
- ADD Y,Y ; Y = bytes size of Cluster number (2 or 4)
-; ----------------------------------;
-LoadFATsectorInBUF ; <== IncrementFATsector
+LoadFATsectorLoop ;
; ----------------------------------;
- MOV @RSP,W ; W = FATsector
- CMP W,&FATSize ;
- JZ OPW_Error ; FATsector = FATSize ===> abort disk full
- ADD &OrgFAT1,W ;
- MOV #0,X ;
- CALL #ReadSectorWX ;SWX (< 65536)
- MOV #0,X ; init FAToffset
+ MOV @RSP,W ;2
+ CMP W,&FATSize ;3
+ JZ OPWC_DiskFull ;2 FATsector = FATSize ===> abort disk full
+ CALL #ReadFAT1SectorW ;SWX load FAT_buf with (new) FATsector
; ----------------------------------;
-SearchFreeClustInBUF ; <== SearchNextCluster
+SearchFreeClusterLoop ;
; ----------------------------------;
- CMP #2,Y ; FAT16 Cluster size ?
- JZ ClusterLowWordTest ; yes
ClusterHighWordTest ;
- CMP #0,SD_BUF+2(X) ; cluster address hi word = 0 ?
- JNZ SearchNextNewCluster ;
+ CMP #0,SD_BUF+2(Y) ;3 cluster address hi word = 0 ?
+ JNZ SearchNextNewCluster ;2
ClusterLowWordTest ;
- CMP #0,SD_BUF(X) ; Cluster address lo word = 0 ?
- JZ GNC_FreeClusterFound ;
+ CMP #0,SD_BUF(Y) ;3 Cluster address lo word = 0 ?
+ JZ FreeClusterFound ;2
SearchNextNewCluster ;
- ADD Y,X ; increment SD_BUF offset by size of Cluster address
- CMP #BytsPerSec,X ;
- JNE SearchFreeClustInBUF ; loopback while X < BytsPerSec
-IncrementFATsector ;
- ADD #1,0(RSP) ; increment FATsector
- JMP LoadFATsectorInBUF ; loopback
+ ADD #4,Y ;1 increment SD_BUF offset by size of Cluster address
+ CMP #BytsPerSec,Y ;2
+ JNC SearchFreeClusterLoop ;2 18/15~ loopback while X U< BytsPerSec
+IncrementFATsector ;1
+ ADD #1,0(RSP) ;3 increment FATsector
+ MOV #0,Y ; clear FAToffset
+ JMP LoadFATsectorLoop ;5 34/23~ loopback
+; ----------------------------------;
+FreeClusterFound ; X = cluster number low word in SD_BUF = FAToffset
; ----------------------------------;
-GNC_FreeClusterFound ; Y = cluster number low word in SD_BUF = FATsector
+ MOV @RSP,&LastFATsector ;
+ MOV Y,&LastFAToffset ;
; ----------------------------------;
MOV #0,S ; clear error
+ MOV #-1,SD_BUF(Y) ; mark New Cluster low word as end cluster (0xFFFF) in SD_BUF
MOV.B @RSP,W ; W = 0:FATsectorLo
- MOV #-1,SD_BUF(X) ; mark NewCluster low word as end cluster (0xFFFF) in SD_BUF
- CMP #2,Y ; Y = FAT16 size of Cluster number ?
- JZ FAT16EntryToClusterNum ; yes
- MOV #0FFFh,SD_BUF+2(X) ; no: mark NewCluster high word as end cluster (0x0FFF) in SD_BUF
+ MOV #0FFFh,SD_BUF+2(Y) ; mark New Cluster high word as end cluster (0x0FFF) in SD_BUF
; ----------------------------------;
-FAT32EntryToClusterNum ; convert FAT32 cluster address to cluster number
+FAT32ClustAdrToClustNum ; convert FAT32 cluster address to cluster number (CluNum = CluAddr / 4)
; ----------------------------------;
- RRA X ; X = FATOffset>>1, FAToffset is byte size
+ RRA Y ; Y = FATOffset>>1, (bytes to words conversion)
SWPB W ; W = FATsectorLo:0
- ADD W,X ; X = FATsectorLo:FATOffset>>1
+ ADD W,Y ; Y = FATsectorLo:FATOffset>>1
MOV.B 1(RSP),W ; W = FATsectorHi
RRA W ; W = FATsectorHi>>1
- RRC X ; X = (FATsectorLo:FAToffset>>1)>>1 = FATsectorLo>>1:FAToffset>>2
- MOV W,&NewClusterH ; NewClusterH = FATsectorHi>>1
- MOV X,&NewClusterL ; NewClusterL = FATsectorLo>>1:FAToffset>>2
- JMP SearchNewClusterEnd ; max cluster = 7FFFFF ==> 1FFFFFFF sectors ==> 256 GB
+ RRC Y ; Y = (FATsectorLo:FAToffset>>1)>>1 = FATsectorLo>>1:FAToffset>>2
+ MOV W,&ClusterH ; ClusterH = FATsectorHi>>1
+ MOV Y,&ClusterL ; ClusterL = FATsectorLo>>1:FAToffset>>2
+; ----------------------------------;
+ MOV @RSP,W ; W = FATsector of new cluster
+ CALL #SaveSectorWtoFATs ;SWXY W = FATsector loaded in SD_buf
+ MOV @RSP+,W ; W = FATsector of New Cluster
+ MOV @RSP+,PC ; RET
+; ----------------------------------;
+
+
+; ==================================;
+FreeAllClusters ;SWXY input: HDLL_FirstClus(T), output:
+; ==================================;FATs are updated
+ MOV HDLL_FirstClus(T),ClusterL ;
+ MOV HDLH_FirstClus(T),ClusterH ;
+ CALL #ClusterHLtoFAT1sectWofstY ;WXY output: W = FATsector, Y=FAToffset
+ MOV W,&LastFATsector ;
+ MOV Y,&LastFAToffset ;
+ PUSH W ; R-- FATsector ptr
+; ----------------------------------;
+LoadFAT1sectorWloop ;
+; ----------------------------------;
+ CALL #ReadFAT1SectorW ;SWX
+; ----------------------------------;
+GetAndFreeCluster ;
+; ----------------------------------;
+ MOV SD_BUF(Y),W ; get [clusterLO]
+ MOV #0,SD_BUF(Y) ; free CLusterLO
+GetAndFreeClusterHi ;
+ MOV SD_BUF+2(Y),X ; get [clusterHI]
+ MOV #0,SD_BUF+2(Y) ; free CLusterHI
+ClusterHiTest
+ AND #00FFFh,X ; select 12 bits significant
+ CMP #00FFFh,X ; [ClusterHI] was = 0FFFh?
+ JNE SearchNextCluster2free ; no
+ClusterLoTest ;
+ CMP #-1,W ; [ClusterLO] was = FFFFh? last cluster used for this file
+ JZ EndOfFileCluster ; yes
; ----------------------------------;
-FAT16EntryToClusterNum ; convert FAT16 address of Cluster in cluster number
+SearchNextCluster2free ;
; ----------------------------------;
- RRA X ; X = Offset>>1, offset is word < 256
- MOV.B X,&NewClusterL ; X = NewCluster numberLO (byte)
- MOV.B W,&NewClusterL+1 ; W = NewCluster numberHI (byte)
- MOV #0,&NewClusterH ;
+ MOV W,&ClusterL ;
+ MOV X,&ClusterH ;
+ CALL #ClusterHLtoFAT1sectWofstY ;WXY W = new FATsector, new FAToffset
+ CMP @RSP,W ; new FATsector = FATsector ptr ?
+ JZ GetAndFreeCluster ; yes loop back
+ MOV W,X ; no: swap previous new FATsectors:
+ MOV @RSP,W ; W = previous FATsector
+ MOV X,0(RSP) ; R-- new FATsector
+ CALL #SaveSectorWtoFATs ;SWXY update FATs from SD_BUF to W = previous FATsector
+ MOV @RSP,W ; W = new FATsector
+ JMP LoadFAT1sectorWloop ; loop back with W = new FATsector, new FAToffset
+; ----------------------------------;
+EndOfFileCluster ;
; ----------------------------------;
-SearchNewClusterEnd ;
+ MOV @RSP+,W ;
+ MOV #SaveSectorWtoFATs,PC ; update FATs
; ----------------------------------;
- MOV @RSP+,W ; W = FATsector
- MOV W,&CurFATsector ; refresh CurrentFATsector
- MOV @RSP+,PC ;
+
+; this subroutine is called by Write_File (bufferPtr=512) and CloseHandle (0 =< BufferPtr =< 512)
+; ==================================;
+WriteSD_Buf ;SWX input: T = CurrentHDL
+; ==================================;
+ ADD &BufferPtr,HDLL_CurSize(T) ; update handle CurrentSizeL
+ ADDC #0,HDLH_CurSize(T) ;
+; ==================================;
+WriteSectorHL ;SWX
+; ==================================;
+ MOV &SectorL,W ; Low
+ MOV &SectorH,X ; High
+ MOV #WriteSectorWX,PC ; ...then RET
; ----------------------------------;
-; update FATs with SD_BUF content.
-; input : FATsector, FAToffset, SD_BUF = [FATsector]
-; use : SWX registers
-; ----------------------------------; else update FATsector of the old cluster
-UpdateFATsSectorW ;
+; ======================================================================
+; DEL" primitive as part of OpenPathName
+; All "DEL"eted clusters are freed
+; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
+; Buffer = [DIRsector], ClusterHL = FirstClusterHL
+; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
+; output: nothing (no message if open error)
+; ======================================================================
+OPEN_2W ;
+ CMP #2,W ; open_type = DEL ?
+ JNZ OPEN_4W ; no : goto next step
; ----------------------------------;
- PUSH W ;
- ADD &OrgFAT1,W ; update FAT#1
- MOV #0,X ;
- CALL #WriteSectorWX ; write a logical sector
- MOV @RSP+,W ;
- ADD &OrgFAT2,W ; update FAT#2
- MOV #0,X ;
- CALL #WriteSectorWX ; write a logical sector
+; 1- open file ; done
+; ----------------------------------;
+ CMP #0,S ; open file happy end ?
+ JNE DEL_END ; no: don't send message, don't abort
+; ----------------------------------;
+; 2- Delete DIR entry ;
+; ----------------------------------;
+ MOV.B #0E5h,SD_BUF(Y) ;
+ CALL #WriteSectorHL ;SWX write SectorHL=DIRsector
+; ----------------------------------;
+; 3- free all file clusters ;
+; ----------------------------------;
+ CALL #FreeAllClusters ;SWXY input: HDLL_FirstClus(T), output: FATS are updated
+; ----------------------------------;
+; 4- Close Handle ;
+; ----------------------------------;
+ CALL #CloseHandle ;
; ----------------------------------;
+DEL_END ;
+ MOV @IP+,PC ;4
+; ----------------------------------;
+
+;-----------------------------------------------------------------------
+; WRITE" (CREATE part) subroutines
+;-----------------------------------------------------------------------
; modified time : ofsset 16h = 0bhhhhhmmmmmmsssss, with : s=seconds*2, m=minutes, h=hours
; dates : offset 10, 12, 18 = 0byyyyyyymmmmddddd, with : y=year-1980, m=month, d=day
-; ----------------------------------; input:
-GetYMDHMSforDIR ;X=date, W=TIME
-; ----------------------------------;
+; ==================================;
+GetYMDHMSforDIR ; output: X=date, W=TIME
+; ==================================;
.IFDEF LF_XTAL ;
.IFNDEF RTC ; RTC_B or RTC_C select
; ----------------------------------;
MOV #512,&OP2 ;
ADD &RES0,X ;
.ELSEIF
- MOV #0,X ; X=DATE
+ MOV #0,X ; X=DATE
MOV #0,W ; W=TIME
.ENDIF
.ENDIF
SD_RW_RET ;
- MOV @RSP+,PC ;
+ MOV @RSP+,PC ;
; ----------------------------------;
ForbiddenChars ; 15 forbidden chars table + dot char
.byte '"','*','+',',','/',':',';','<','=','>','?','[','\\',']','|','.'
-; ----------------------------------;
+; ==================================;
OPWC_SkipDot ;
-; ----------------------------------;
+; ==================================;
CMP #4,X ;
- JL FillDIRentryName ; X < 4 : no need spaces to complete name entry
+ JNC FillDIRentryName ; X U< 4 : no need spaces to complete name entry
SUB #3,X ;
- CALL #OPWC_CompleteWithSpaces; complete name entry
- MOV #3,X ;
-; ----------------------------------;
-
-; ----------------------------------;
+ CALL #OPWC_CompleteWithSpaces; complete name entry
+ MOV #3,X ;
+; ==================================;
FillDIRentryName ;SWXY use
-; ----------------------------------;
+; ==================================;
MOV.B @T+,W ; W = char of pathname
MOV.B W,SD_BUF(Y) ; to DIRentry
; CMP #0,W ; end of stringZ ?
; JZ OPWC_CompleteWithSpaces ;
- CMP T,&EndOfPath ; EOS < PTR ?
+ CMP T,&PathName_END ; EOS < PTR ?
JNC OPWC_CompleteWithSpaces ; yes
; ----------------------------------;
SkipForbiddenChars ;
; ----------------------------------;
OPWC_CompleteWithSpaces ; 0 to n spaces !
; ----------------------------------;
- CMP #0,X ;
+ CMP #0,X ;
JZ OPWC_CWS_End ;
; ----------------------------------;
OPWC_CompleteWithSpaceloop ;
; ----------------------------------;
MOV.B #' ',SD_BUF(Y) ; remplace dot by char space
- ADD #1,Y ; increment DIRentry ptr in buffer
+ ADD #1,Y ; increment DIRentry ptr in buffer
SUB #1,X ; dec countdown of chars space
JNZ OPWC_CompleteWithSpaceloop ;
OPWC_CWS_End ;
- MOV @RSP+,PC ;
+ MOV @RSP+,PC ;
; ----------------------------------;
+; ==================================;
+LoadUpdateSaveDirEntry ;SWXY
+; ==================================;
+ MOV HDLL_DIRsect(T),W ;
+ MOV HDLH_DIRsect(T),X ;
+ CALL #readSectorWX ;SWX SD_buffer = DIRsector
+ MOV HDLW_DIRofst(T),Y ; Y = DirEntryOffset
+ CALL #GetYMDHMSforDIR ; X=DATE, W=TIME
+ MOV X,SD_BUF+18(Y) ; access date
+ MOV W,SD_BUF+22(Y) ; modified time
+ MOV X,SD_BUF+24(Y) ; modified date
+ MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
+ MOV HDLH_CurSize(T),SD_BUF+30(Y);
+ MOV HDLL_DIRsect(T),W ;
+ MOV HDLH_DIRsect(T),X ;
+ MOV #WriteSectorWX,PC ;SWX then RET
+; ----------------------------------;
+;-----------------------------------------------------------------------
+; WRITE" subroutines
+;-----------------------------------------------------------------------
+
+
+; write sequentially the buffer in the post incremented SectorHL.
+; The first time, SectorHL is initialized by WRITE".
+; All used registers must be initialized.
+; ==================================;
+Write_File ;STWXY <== WRITE, SD_EMIT, TERM2SD"
+; ==================================;
+ MOV #BytsPerSec,&BufferPtr ; write always all the buffer
+ MOV &CurrentHdl,T ;
+ CALL #WriteSD_Buf ;SWX write SD_BUF and update Handle informations only for DIRentry update
+ MOV #0,&BufferPtr ; reset buffer pointer
+; ----------------------------------;
+PostIncrementSector ;
+; ----------------------------------;
+ ADD.B #1,HDLB_ClustOfst(T) ; increment current Cluster offset
+ CMP.B &SecPerClus,HDLB_ClustOfst(T) ; out of bound ?
+ JNC Write_File_End ; no,
+; ----------------------------------;
+ CALL #HDLcurClus2FATsecWofstY;WXY Output: FATsector W=FATsector, Y=FAToffset
+ PUSH Y ; push previous FAToffset
+ PUSH W ; push previous FATsector
+; ----------------------------------;
+GetNewCluster ; input : T=CurrentHdl
+; ----------------------------------;
+ CALL #SearchMarkNewClusterHL ;SWXY input: W = FATsector Y = FAToffset, output: ClusterHL, W = FATsector of New cluster
+ CMP @RSP,W ; previous and new clusters are in same FATsector?
+ JZ LinkClusters ; yes
+; ----------------------------------;
+UpdateNewClusterFATs ;
+; ----------------------------------;
+; CALL #SaveSectorWtoFATs ;SWXY no: already done by SearchMarkNewClusterHL
+ MOV @RSP,W ; W = previous FATsector
+ CALL #ReadFAT1SectorW ;SWX reload previous FATsector in buffer to link clusters
+; ----------------------------------;
+LinkClusters ;
+; ----------------------------------;
+ MOV @RSP+,W ; W = previous FATsector
+ MOV @RSP+,Y ; Y = previous FAToffset
+ MOV &ClusterL,SD_BUF(Y) ; store new cluster to current cluster address in previous FATsector buffer
+ MOV &ClusterH,SD_BUF+2(Y) ;
+ CALL #SaveSectorWtoFATs ;SWXY update FATs from SD_BUF to W = previous FATsector
+; ==================================;
+HDLSetCurClustSetFrstSect ;
+; ==================================;
+ MOV #4,HDLB_Token(T) ; and clear ClustOfst
+; ==================================;
+HDLSetCurClustSetCurSect ;
+; ==================================;
+ MOV &ClusterL,HDLL_CurClust(T) ; update handle with new cluster
+ MOV &ClusterH,HDLH_CurClust(T) ;
+Write_File_End
+ MOV #ClusterHL2sectorHL,PC ;W set current SectorHL to be written then RET
+; ----------------------------------;
+
+;Z WRITE --
+; sequentially write the entire SD_BUF in a file opened by WRITE"
+; ==================================;
+ FORTHWORD "WRITE" ; in assembly : CALL #WRITE,X CALL 2(X)
+; ==================================;
+ CALL #Write_File ;STWXY
+ MOV @IP+,PC ;
+; ----------------------------------;
; ======================================================================
; WRITE" primitive as part of OpenPathName
; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
; Buffer = [DIRsector], ClusterHL = FirstClusterHL
; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
-; output: nothing else abort on error
-; error 1 : PathNameNotFound
-; error 2 : NoSuchFile
-; error 4 : DirectoryFull
-; error 8 : AlreadyOpen
-; error 16 : NomoreHandle
+; output: Current Sector is set else abort on WRITE error
+; error 4 : InvalidPathname
+; error 8 : DiskFull
; ======================================================================
-
-; ----------------------------------;
-OPEN_QWRITE ;
- CMP #2,W ; open_type = WRITE" ?
- JNZ OPEN_QDEL ; no : goto next step
+OPEN_4W ;
+ CMP #4,W ; open_type = WRITE" ?
+ JNZ OPEN_8W ; no : goto next step
; ----------------------------------;
; 1 try to open ; done
; ----------------------------------;
; 2 select error "no such file" ;
; ----------------------------------;
CMP #2,S ; "no such file" error ?
- JZ OPEN_WRITE_CREATE ; yes
- CMP #0,S ; no open file error ?
- JZ OPEN_WRITE_APPEND ; yes
+ JZ OPEN_WRITE_CREATE ; yes, Handle is to be created !
+ CMP #0,S ; well opened file ?
+ JZ OPEN_OVERWRITE ; yes
; ----------------------------------;
-; Write errors ;
+OPWC_Write_Errors ;
; ----------------------------------;
-OPWC_InvalidPathname ; S = 1
-OPWC_DiskFull ; S = 2
-OPWC_DirectoryFull ; S = 4
-OPWC_AlreadyOpen ; S = 8
-OPWC_NomoreHandle ; S = 16
+OPWC_InvalidPathname ; S = 4
+OPWC_DiskFull ; S = 8
; ----------------------------------;
OPW_Error ; set ECHO, type Pathname, type #error, type "< WriteError"; no return
mDOCOL ;
.word BRAN,ABORT_SD ; to insert S error as flag, no return
; ----------------------------------;
-
; ======================================================================
-; WRITE" (CREATE part) primitive as part of OpenPathName
-; input from open: S = NoSuchFile, W = open_type, SectorHL = DIRsectorHL,
-; Buffer = [DIRsector], ClusterHL = FirstClusterHL
-; output: nothing else abort on error:
-; error 1 : InvalidPathname
-; error 2 : DiskFull
-; error 4 : DirectoryFull
-; error 8 : AlreadyOpen
-; error 16 : NomoreHandle
+; WRITE" primitive as part of OpenPathName
+; All "DEL"eted clusters are freed
+; input from open: W = open_type, SectorHL = DIRsectorHL,
+; Buffer = [DIRsector], ClusterHL = FirstCluster
+; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl,
+; output: nothing (no message if open error)
; ======================================================================
+
+; ==================================;
+OPEN_WRITE_CREATE ; a new Handle is to be created
+; ==================================;
+; 1- open file ; done
; ----------------------------------;
-OPEN_WRITE_CREATE ;
-; ----------------------------------;
-; 3 get free cluster ;
-; ----------------------------------; input: FATsector
- CALL #SearchNewCluster ;SWXY output: W = new FATsector loaded in buffer,NewCluster
- MOV &NewClusterL,&ClusterL ;
- MOV &NewClusterH,&ClusterH ;
- CALL #UpdateFATsSectorW ;SWX update FATs with buffer
+; 2 get free cluster ;
; ----------------------------------;
- CALL #ReadSector ; reload DIRsector
- MOV &EntryOfst,Y ; reload entry offset (first free entry in DIR)
+ MOV #0,W ; init FATsector = 0, search new cluster
+ MOV #0,Y ; init FAToffset
+ CALL #SearchMarkNewClusterHL ;WXY output: updated (ClusterHL, FATsector, W = FATsector), SD_BUF = [new FATsector]
; ----------------------------------;
-; 4 init DIRentryAttributes ;
+; 3 init DIRentryAttributes ;
; ----------------------------------;
-OPWC_SetEntryAttribute ; (cluster=DIRcluster!)
+ CALL #ReadSectorHL ; reload DIRsector
+ MOV &DIREntryOfst,Y ; Y = entry offset (first free entry in DIR)
MOV.B #20h,SD_BUF+11(Y) ; file attribute = file
CALL #GetYMDHMSforDIR ;WX X=DATE, W=TIME
MOV #0,SD_BUF+12(Y) ; nt reserved = 0 and centiseconds are 0
MOV W,SD_BUF+14(Y) ; time of creation
MOV X,SD_BUF+16(Y) ; date of creation 20/08/2001
- MOV X,SD_BUF+18(Y) ; date of access 20/08/2001
- MOV &ClusterH,SD_BUF+20(Y) ; as first Cluster Hi
- MOV &ClusterL,SD_BUF+26(Y) ; as first cluster LO
- MOV #0,SD_BUF+28(Y) ; file lenghtLO = 0
- MOV #0,SD_BUF+30(Y) ; file lenghtHI = 0
-; ----------------------------------;
-; 5 create DIRentryName ;
-; ----------------------------------;
- MOV #1,S ; preset pathname error
- MOV &Pathname,T ; here, pathname is "xxxxxxxx.yyy" format
-; CMP.B #0,0(T) ; forbidden null string
- CMP T,&EndOfPath ;
- JZ OPWC_InvalidPathname ; write error 1
+; MOV X,SD_BUF+18(Y) ; date of access 20/08/2001
+ MOV &ClusterH,SD_BUF+20(Y) ; as first Cluster Hi
+ MOV &ClusterL,SD_BUF+26(Y) ; as first cluster LO
+ MOV #0,SD_BUF+28(Y) ; set file_sizeLO = 0
+ MOV #0,SD_BUF+30(Y) ; set file_sizeHI = 0
+; ----------------------------------;
+; 4 create DIRentryName ; file name format "xxxxxxxx.yyy"
+; ----------------------------------;
+ MOV #4,S ; preset pathname error
+ MOV &PathName_PTR,T ; here, PathName_PTR is set to file name
+ CMP T,&PathName_END ; end of string reached ?
+ JZ OPWC_InvalidPathname ; yes write error 1
CMP.B #'.',0(T) ; forbidden "." in first
JZ OPWC_InvalidPathname ; write error 1
MOV #11,X ; X=countdown of chars entry
CALL #FillDIRentryName ;STWXY
; ----------------------------------;
-; 6 save DIRsector ;
+; 5 update DIRsector ;
; ----------------------------------;
- CALL #WriteSector ;SWX update DIRsector
+ CALL #WriteSectorHL ;SWX update DIRsector
; ----------------------------------;
; 7 Get free handle ;
; ----------------------------------;
- MOV #2,W ;
- CALL #GetFreeHandle ; output : S = handle error, CurCluster and CurSector are set
-; ----------------------------------;
- CMP #0,S ; no error ?
- JNZ OPWC_NomoreHandle ; ==> abort with error 16
- MOV @IP+,PC ; --
-; ----------------------------------;
-
-;-----------------------------------------------------------------------
-; WRITE" subroutines
-;-----------------------------------------------------------------------
-
-; SectorL is unchanged
-; ----------------------------------;
-OPWW_UpdateDirectory ; <== CloseHandleT
-; ----------------------------------; Input : current Handle
- MOV HDLL_DIRsect(T),W ;
- MOV HDLH_DIRsect(T),X ;
- CALL #readSectorWX ;SWX buffer = DIRsector
- CALL #GetYMDHMSforDIR ; X=DATE, W=TIME
- MOV HDLW_DIRofst(T),Y ; Y = DirEntryOffset
- MOV X,SD_BUF+18(Y) ; access date
- MOV W,SD_BUF+22(Y) ; modified time
- MOV X,SD_BUF+24(Y) ; modified date
-OPWW_UpdateEntryFileSize ;
- MOV HDLL_CurSize(T),SD_BUF+28(Y); save new filesize
- MOV HDLH_CurSize(T),SD_BUF+30(Y);
- MOV HDLL_DIRsect(T),W ;
- MOV HDLH_DIRsect(T),X ;
- MOV #WriteSectorWX,PC ;SWX then RET
-; ----------------------------------;
-
-; this subroutine is called by Write_File (bufferPtr=512) and CloseHandleT (0 =< BufferPtr =< 512)
-; ==================================;
-WriteBuffer ;STWXY input: T = CurrentHDL
-; ==================================;
- ADD &BufferPtr,HDLL_CurSize(T) ; update handle CurrentSizeL
- ADDC #0,HDLH_CurSize(T) ;
-; ==================================;
-WriteSector ;SWX
-; ==================================;
- MOV &SectorL,W ; Low
- MOV &SectorH,X ; High
- MOV #WriteSectorWX,PC ; ...then RET
+ MOV #4,W ; get handle for write
+ CALL #GetFreeHandle ; output : CurCluster and CurSector are set
+ MOV @IP+,PC ; --
; ----------------------------------;
-
-
-; write sequentially the buffer in the post incremented SectorHL.
-; The first time, SectorHL is initialized by WRITE".
-; All used registers must be initialized.
; ==================================;
-Write_File ; <== WRITE, SD_EMIT, TERM2SD"
+OPEN_OVERWRITE ; handle exists
; ==================================;
- MOV #BytsPerSec,&BufferPtr ; write always all the buffer
- MOV &CurrentHdl,T ;
- CALL #WriteBuffer ; write SD_BUF and update Handle informations only for DIRentry update
- MOV #0,&BufferPtr ; reset buffer pointer
-; ----------------------------------;
-PostIncrementSector ;
-; ----------------------------------;
- ADD.B #1,HDLB_ClustOfst(T) ; increment current Cluster offset
- CMP.B &SecPerClus,HDLB_ClustOfst(T) ; out of bound ?
- JNZ Write_File_End ; no,
-; ----------------------------------;
-GetNewCluster ; input : T=CurrentHdl
-; ----------------------------------;
- MOV.B #0,HDLB_ClustOfst(T) ; reset handle ClusterOffset
- CALL #HDLCurClusToFAT1sectWofstY;WXY Output: W=FATsector, Y=FAToffset, Cluster=HDL_CurCluster
- PUSH Y ; push current FAToffset
- PUSH W ; push current FATsector
- CALL #SearchNewCluster ;SWXY output: W = new FATsector loaded in buffer, NewCluster
- CMP @RSP,W ; current and new clusters are in same FATsector?
- JZ LinkClusters ; yes
-UpdateNewClusterFATs ;
- CALL #UpdateFATsSectorW ;SWX no: UpdateFATsSectorW with buffer of new FATsector
- MOV @RSP,W ; W = current FATsector
- ADD &OrgFAT1,W ;
- MOV #0,X ;
- CALL #ReadSectorWX ;SWX (< 65536)
-LinkClusters ;
- MOV @RSP+,W ; W = current FATsector
- MOV @RSP+,Y ; pop current FAToffset
- MOV &NewClusterL,SD_BUF(Y) ; store new cluster to current cluster address in current FATsector buffer
- CMP #1,&FATtype ; FAT16?
- JZ UpdatePreviousClusterFATs ; yes
- MOV &NewClusterH,SD_BUF+2(Y);
-UpdatePreviousClusterFATs ;
- CALL #UpdateFATsSectorW ;SWX update FATS with current FATsector buffer
-UpdateHandleCurCluster ;
- MOV &NewClusterL,HDLL_CurClust(T) ; update handle with new cluster
- MOV &NewClusterH,HDLH_CurClust(T) ;
-; CALL #ComputeHDLcurrentSector ; set Cluster first Sector as next Sector to be written
-; MOV #OPWW_UpdateDirectory,PC ; update DIRentry to avoid cluster lost, then RET
-Write_File_End
- MOV #ComputeHDLcurrentSector,PC ; set current Cluster Sector as next Sector to be written then RET
-; ----------------------------------;
-
-;Z WRITE --
-; sequentially write the entire SD_BUF in a file opened by WRITE"
+; free all file clusters ;
; ----------------------------------;
- FORTHWORD "WRITE" ; in assembly : CALL &WRITE+2
-; ----------------------------------;
- CALL #Write_File ;
- MOV @IP+,PC ;
+ CALL #FreeAllClusters ;SWXY input: HDLL_FirstClus(T), output: FATS are updated
+ MOV #0,HDLL_CurSize(T) ; clear currentSize
+ MOV #0,HDLH_CurSize(T) ;
+ MOV HDLL_FirstClus(T),ClusterL ; Set ClusterHL
+ MOV HDLH_FirstClus(T),ClusterH ;
+ CALL #ClusterHLtoFAT1sectWofstY ;WXY output: W = FATsector, Y=FAToffset
+ CALL #SearchMarkNewClusterHL ;SWXY input: W = FATsector, Y = FAToffset output: ClusterHL, W = updated new FATsector loaded in SD_BUF
+ CALL #HDLSetCurClustSetFrstSect ;
+ MOV @IP+,PC ; --
; ----------------------------------;
; ======================================================================
-; WRITE" (APPEND part) primitive as part of OpenPathName
-; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
+; APPEND" primitive as part of OpenPathName
+; input from open: SectorHL = DIRsectorHL,
; Buffer = [DIRsector], ClusterHL = FirstClusterHL
; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
; output: nothing else abort on error
-; error 2 : DiskFull
+; error 2 : DiskFull
; ======================================================================
-
-; ----------------------------------;
-OPEN_WRITE_APPEND ;
-; ----------------------------------;
+OPEN_8W ;
+ CMP #2,S ; "no such file" error ?
+ JZ OPEN_WRITE_CREATE ; yes
+ CMP #0,S ; well opened file ?
+ JNZ OPWC_Write_Errors ; no
+; ==================================;
+OPEN_WRITE_APPEND ; yes
+; ==================================;
; 1- open file ; done
; ----------------------------------;
-; 2- compute missing Handle infos ;
+ MOV.B #4,HDLB_Token(T) ; update HDLB_Token(T)
; ----------------------------------;
; 2.1- Compute Sectors count ; Sectors = HDLL_CurSize/512
; ----------------------------------;
- MOV.B HDLL_CurSize+1(T),Y ;Y = 0:CurSizeLOHi
- MOV.B HDLH_CurSize(T),X ;X = 0:CurSizeHILo
- SWPB X ;X = CurSizeHIlo:0
+ MOV.B HDLL_CurSize+1(T),Y ;Y = 0:CurSizeLOHi (bytes)
+ MOV.B HDLH_CurSize(T),X ;X = 0:CurSizeHILo
+ SWPB X ;X = CurSizeHIlo:0
ADD Y,X ;X = CurSizeHIlo:CurSizeLOhi
- MOV.B HDLH_CurSize+1(T),Y ;Y:X = CurSize / 256
+ MOV.B HDLH_CurSize+1(T),Y ;Y:X = CurSize / 256 (bytes)
; ----------------------------------;
; 2.2 Compute Clusters Count ;
; ----------------------------------;
SUB #1,S ;1 CNT-1
JGE DIVSECPERSPC2 ;2 4~ loopback Wlo = OFFSET, X = CLU_LO, Y = CLU_HI
; ----------------------------------;
- MOV &CurrentHDL,T ;3 reload Handle ptr
-; ----------------------------------;
-; 2.3- Compute last Cluster ; X = Clusters numberLO, Y = Clusters numberHI
+; 2.3- Compute Current Cluster ; X = ClusterCountLO, Y = ClusterCountHI
; ----------------------------------;
+ MOV &CurrentHDL,T ;3 reload Handle ptr
ADD HDLL_FirstClus(T),X ;
ADDC HDLH_FirstClus(T),Y ;
MOV X,HDLL_CurClust(T) ; update handle
MOV Y,HDLH_CurClust(T) ;
; ----------------------------------;
-; 2.4- Compute Sectors offset ;
+; 2.4- load current sectorHL ;
; ----------------------------------;
- MOV.B W,HDLB_ClustOfst(T) ;3 update handle with W = REMlo = sectors offset in last cluster
+ MOV.B W,HDLB_ClustOfst(T) ;3 update handle with W = REM8 = sectors offset in last cluster
+ CALL #LoadCurSectorHL ;SWX in SD_buf
; ----------------------------------;
-; 3- load last sector in SD_BUF ;
+; 2.5- Compute SD_Buf ptr ;
; ----------------------------------;
- MOV HDLL_CurSize(T),W ; example : W = 1013
- BIC #01FFh,HDLL_CurSize(T) ; substract 13 from HDLL_CurSize, because loaded in buffer
- AND #01FFh,W ; W = 13
- MOV W,&BufferPtr ; init Buffer Pointer with 13
- CALL #LoadHDLcurrentSector ;SWX
- MOV @IP+,PC ; BufferPtr = first free byte offset
+ MOV HDLL_CurSize(T),W ; example : W = $A313 bytes
+ BIC #01FFh,HDLL_CurSize(T) ; HDLL_CurSize = $A200 bytes
+ AND #01FFh,W ; remainder W = $0113 bytes
+ MOV W,&BufferPtr ; init Buffer Pointer with $0113
; ----------------------------------;
-
-
-; ======================================================================
-; DEL" primitive as part of OpenPathName
-; All "DEL"eted clusters are freed
-; If next DIRentry in same sector is free, DIRentry is freed, else hidden.
-; input from open: S = OpenError, W = open_type, SectorHL = DIRsectorHL,
-; Buffer = [DIRsector], ClusterHL = FirstClusterHL
-; from open(GetFreeHandle): Y = DIRentry, T = CurrentHdl
-; output: nothing (no message if open error)
-; ======================================================================
-
-
-OPEN_QDEL ;
-; CMP #4,W ; open_type = DEL"
-; JNZ OPEN_8W ;
-; ----------------------------------;
-OPEN_DEL ;
-; ----------------------------------;
-; 1- open file ; done
-; ----------------------------------;
- CMP #0,S ; open file happy end ?
- JNE DEL_END ; no: don't send message
-; ----------------------------------;
-; 2- Delete DIR entry ; "delete" entry with 00h if next entry in same DIRsector is free, else "hide" entry with 05Eh
-; ----------------------------------;
-SelectFreeEntry ; nothing to do: S = 0 ready for free entry!
-; ----------------------------------;
- CMP #BytsPerSec-32,Y ; Entry >= last entry in DIRsector ?
- JC SelectHideEntry ; yes: next DIR entry is out of sector
- CMP.B #0,SD_BUF+32(Y) ; no: next DIR entry in DIRsector is free?
- JZ WriteDelEntry ; yes
-; ----------------------------------;
-SelectHideEntry ; no
-; ----------------------------------;
- MOV.B #0E5h,S ;
-; ----------------------------------;
-WriteDelEntry
-; ----------------------------------;
- MOV.B S,SD_BUF(Y) ;
- CALL #WriteSector ;SWX write SectorHL=DIRsector
-; ----------------------------------;
-; 3- free all file clusters ; Cluster = FirstCluster
-; ----------------------------------;
-ComputeClusterSectWofstY ;
- CALL #ClusterToFAT1sectWofstY;WXY W = FATsector, Y=FAToffset
- MOV W,&CurFATsector ; update CurrentFATsector
-; ----------------------------------;
-LoadFAT1sector
-; ----------------------------------;
- MOV W,T ; T = W = current FATsector memory
- ADD &OrgFAT1,W ;
- MOV #0,X ;
- CALL #ReadSectorWX ;SWX (< 65536)
-; ----------------------------------;
-GetAndFreeClusterLo ;
-; ----------------------------------;
- MOV SD_BUF(Y),W ; get [clusterLO]
- MOV #0,SD_BUF(Y) ; free CLusterLO
-ClusterTestSelect ;
- CMP #1,&FATtype ; FAT16 ?
- JZ ClusterLoTest ; yes
-GetAndFreeClusterHi ;
- MOV SD_BUF+2(Y),X ; get [clusterHI]
- MOV #0,SD_BUF+2(Y) ; free CLusterHI
-ClusterHiTest
- AND #00FFFh,X ; select 12 bits significant
- CMP #00FFFh,X ; [ClusterHI] was = 0FFFh?
- JNE SearchNextCluster2free ; no
-ClusterLoTest
- CMP #-1,W ; [ClusterLO] was = FFFFh?
- JZ EndOfFileClusters ; yes
-; ----------------------------------;
-SearchNextCluster2free
-; ----------------------------------;
- MOV W,&ClusterL ;
- MOV X,&ClusterH ;
- CALL #ClusterToFAT1sectWofstY;WXY
- CMP W,T ; new FATsector = current FATsector memory ?
- JZ GetAndFreeClusterLo ; yes loop back
- PUSH W ; no: save new FATsector...
- MOV T,W ; ...before update current FATsector
- CALL #UpdateFATsSectorW ;SWX
- MOV @RSP+,W ; restore new current FATsector
- JMP LoadFAT1sector ; loop back with Y = FAToffset
-; ----------------------------------;
-EndOfFileClusters ;
-; ----------------------------------;
- MOV T,W ; T = W = current FATsector
- CALL #UpdateFATsSectorW ;SWX
-; ----------------------------------;
-; 3- Close Handle ;
-; ----------------------------------;
- CALL #CloseHandleT ;
-; ----------------------------------;
-DEL_END ;
- MOV @IP+,PC ;4
+ MOV @IP+,PC ; BufferPtr = first free byte offset
; ----------------------------------;
-
.IFNDEF TERMINAL_I2C ; if UART_TERMINAL
; first TERATERM sends the command TERM2SD" file.ext" to FastForth which returns XOFF at the end of the line.
; then when XON is sent below, TERATERM sends "file.ext" up to XOFF sent by TERM2SD" (slices of 512 bytes),
; then TERATERM sends char EOT that closes the file on SD_CARD.
- FORTHWORD "TERM2SD\34"
- mDOCOL
- .word DELDQ ; DEL file if already exist
- .word lit,2 ; -- open_type
- .word HERE,COUNT ; -- open_type addr cnt
- .word PARENOPEN ; reopen same filepath but as write
- .word $+2 ;
- MOV @RSP+,IP ;
+; ==================================;
+ FORTHWORD "TERM2SD\34" ;
+; ==================================;
+ mDOCOL ;
+ .word WRITEDQ ; if already exist FreeAllClusters else create it as WRITE file
+ mNEXTADR ;
; ----------------------------------;
-T2S_GetSliceLoop ; tranfert by slices of 512 bytes terminal input to file on SD_CARD via SD_BUF
+T2S_GetSliceLoop ; tranfert by slices of 512 bytes from terminal input to file on SD_CARD via SD_BUF
; ----------------------------------;
MOV #0,W ;1 reset W = BufferPtr
CALL #RXON ; use no registers
; ----------------------------------;
-T2S_FillBufferLoop ;
+T2S_Get_a_Char_Loop ;
; ----------------------------------;
BIT #RX_TERM,&TERM_IFG ;3 new char in TERMRXBUF ?
- JZ T2S_FillBufferLoop ;2
+ JZ T2S_Get_a_Char_Loop ;2
MOV.B &TERM_RXBUF,X ;3
MOV.B X,&TERM_TXBUF
CMP.B #4,X ;1 EOT sent by TERATERM ?
MOV.B X,SD_BUF(W) ;3
ADD #1,W ;1
CMP #BytsPerSec-1,W ;2
- JNC T2S_FillBufferLoop ;2 W < BytsPerSec-1 21 cycles char loop
JZ T2S_XOFF ;2 W = BytsPerSec-1 send XOFF after RX 511th char
+ JNC T2S_Get_a_Char_Loop ;2 W < BytsPerSec-1 21 cycles char loop (476 kBds/MHz)
; ----------------------------------;
T2S_WriteFile ;2 W = BytsPerSec
; ----------------------------------;
- CALL #Write_File ;TSWXY write all the buffer
- JMP T2S_GetSliceLoop ;2
+ CALL #Write_File ;STWXY write all the buffer
+ JMP T2S_GetSliceLoop ;2
; ----------------------------------;
T2S_XOFF ; 27 cycles between XON and XOFF
; ----------------------------------;
CALL #RXOFF ;4 use no registers
- JMP T2S_FillBufferLoop ;2 loop back once to get last char
+ JMP T2S_Get_a_Char_Loop ;2 loop back once to get char sent by TERMINAL during XOFF time
; ----------------------------------;
-T2S_End_Of_File ;
+T2S_End_Of_File ; wait CR before sending XOFF
+; ----------------------------------;
+T2S_Wait_CR ; warning! EOT must be followed by CR+LF (TERM2SD" used with I2C_FastForth)
+; ----------------------------------;
+ CMP.B #0Dh,&TERM_RXBUF ; also clears RX_IFG !
+ JZ T2S_Wait_CR ; wait CR
; ----------------------------------;
CALL #RXOFF ;4 use no registers
+; ----------------------------------;
+T2S_Wait_LF ; warning! EOT must be followed by CR+LF (TERM2SD" used with I2C_FastForth)
+; ----------------------------------;
+ CMP.B #0Ah,&TERM_RXBUF ; also clears RX_IFG !
+ JZ T2S_Wait_LF ; wait LF
+; ----------------------------------;
MOV W,&BufferPtr ;3
- CALL #CloseHandleT ;4
- MOV @IP+,PC ;4
+ CALL #CloseHandle ;4
+; ----------------------------------;
+ MOV @RSP+,IP ;
+ MOV @IP+,PC ;4
; ----------------------------------;
.ELSE ; if I2C_TERMINAL
; then when RXON is sent below, I2C_Master sends "file.ext" line by line
; then TERATERM sends char EOT that closes the file on SD_CARD.
+; ==================================;
FORTHWORD "TERM2SD\34" ; here, I2C_Master is reSTARTed in RX mode
- mDOCOL
- .word DELDQ ; DEL file if already exist
- .word lit,2 ; -- open_type
- .word HERE,COUNT ; -- open_type addr cnt
- .word PARENOPEN ; reopen same filepath but as write
- .word $+2 ;
+; ==================================;
+ mDOCOL ;
+ .word WRITEDQ ; if already exist FreeAllClusters else create it as WRITE file
+ mNEXTADR ;
; ----------------------------------;
- CALL #RXON ; send I2C Ctrl_Char $00 to I2C_Master
+ MOV #0,W ; reset W = SD_Buf_Ptr
+ MOV.B #0Ah,IP ; IP = char 'LF'
; ----------------------------------;
-T2S_ClearBuffer ;
+T2S_GetLineLoop ; tranfert line by line from terminal input to SD_BUF
; ----------------------------------;
- MOV #0,W ;1 reset W = BufferPtr
+ CALL #RXON ; use Y reg; send I2C Ctrl_Char $00 to request I2C_Master to switch from RX to TX
+; ----------------------------------;
+T2S_Get_a_Char_Loop ;
; ----------------------------------;
-T2S_FillBufferLoop ; move by slices of 512 bytes from TERMINAL input to file on SD_CARD via SD_BUF
+T2S_Q_BufferFull ; test it before to take data in RX buffer and so to do SCL strech low during Write_File !!!!
+; ----------------------------------;
+ CMP #BytsPerSec,W ;2 buffer full ?
+ JNC T2S_Get_a_Char ;2 no
+; ----------------------------------;
+T2S_WriteFile ; tranfert all 512 bytes of SD_BUF to the opened file in SD_CARD
+; ----------------------------------; SCL is stretched low by Slave (it's my)
+ CALL #Write_File ;STWXY Write_File write always all the buffer
+ MOV #0,W ; reset SD_Buf_Ptr
+; ----------------------------------;
+T2S_Get_a_Char ;
; ----------------------------------;
BIT #RX_TERM,&TERM_IFG ;3 new char in TERMRXBUF ?
- JZ T2S_FillBufferLoop ;2 no
- MOV.B &TERM_RXBUF,X ;3
- CMP.B #4,X ;1 EOT sent by TERMINAL (teraterm.exe) ?
+ JZ T2S_Get_a_Char ;2 no
+ MOV.B &TERM_RXBUF,X ;3 SCL is released here
+; ----------------------------------;
+T2S_Q_EOF ;
+; ----------------------------------;
+ CMP.B #4,X ;1 EOF sent by TERMINAL (teraterm.exe) ?
JZ T2S_End_Of_File ;2 yes
MOV.B X,SD_BUF(W) ;3
ADD #1,W ;1
- CMP.B #0Ah,X ;2 Char LF ?
- JNZ T2S_Q_BufferFull ;2 no
; ----------------------------------;
-T2S_GetNewLine ; here I2C_Master automatically (re)START in RX mode, one char must be sent to
-; ----------------------------------; clear I2C_Slave UCSTTIFG, so we must send LF a minima
- ASMtoFORTH ;
- .word CR ; (CR+LF instead of LF is sent to beautify TERMINAL display, if ECHO is ON obviously)
- .word $+2 ;
- CALL #RXON ; send I2C Ctrl_Char $00 to I2C_Master
+T2S_Q_Char_LF ; when Master send the Ack on char 'LF', it reStarts automatically in RX mode
; ----------------------------------;
-T2S_Q_BufferFull ;
+ CMP.B IP,X ;1 Char LF received ?
+ JNZ T2S_Get_a_Char_Loop ;2 no, 22 cycles loop back (< 1us @ 24 MHz)
; ----------------------------------;
- CMP #BytsPerSec,W ;2 buffer full ?
- JNC T2S_FillBufferLoop ;2 no 21 cycles char loop
+T2S_Send_CR ; because I2C_Master doesn't echo it on TERMINAL
+; ----------------------------------;
+ BIT #TX_TERM,&TERM_IFG ;
+ JZ T2S_Send_CR ; wait TX buffer empty
+ MOV.B #0Dh,&TERM_TXBUF ; send CR to beautify TERMINAL display (if ECHO is ON, obviously)
+; ----------------------------------;
+T2S_Send_LF ; because I2C_Master doesn't echo it on TERMINAL
; ----------------------------------;
-T2S_WriteFile ;2 yes
+ BIT #TX_TERM,&TERM_IFG ;
+ JZ T2S_Send_LF ; wait TX buffer empty
+ MOV.B IP,&TERM_TXBUF ; send LF to beautify TERMINAL display (if ECHO is ON, obviously)
; ----------------------------------;
- CALL #Write_File ;4 TSWXY write all the buffer
- JMP T2S_ClearBuffer ;2
+ JMP T2S_GetLineLoop ;
; ----------------------------------;
T2S_End_Of_File ;
; ----------------------------------;
- BIT #RX_TERM,&TERM_IFG ;3 new char in TERMRXBUF ?
- JZ T2S_End_Of_File ;2 no
- CMP.B #0Ah,&TERM_RXBUF ;4 Char LF ?
- JNZ T2S_End_Of_File ;
+T2S_Wait_LF ; warning! EOT is followed by CR+LF, because I2C_Master uses LF to switch from TX to RX
; ----------------------------------;
- MOV W,&BufferPtr ;3
- CALL #CloseHandleT ;4
- MOV @RSP+,IP ; moved here because ASMtoFORTH use above
+ CMP.B IP,&TERM_RXBUF ; and also clears RX_IFG !
+ JNZ T2S_Wait_LF ;
+; ----------------------------------; here I2C_Master switches from TX to RX
+ MOV W,&BufferPtr ; to add it to HDLL_CurSize
+ CALL #CloseHandle ; tranfert SD_BUF to last sector of opened file in SD_CARD then close it
+; ----------------------------------;
+ MOV @RSP+,IP ;
MOV @IP+,PC ;
; ----------------------------------;