Improved Teensy SDIO, new features, bug fixes
This commit is contained in:
parent
cb5a7d2afb
commit
4582dd4d6c
45 changed files with 1571 additions and 1454 deletions
|
|
@ -1,8 +1,7 @@
|
|||
2019-12-10
|
||||
2021-01-06
|
||||
|
||||
Run the SdErrorCode example to produce an updated list.
|
||||
|
||||
C
|
||||
Code,Symbol - failed operation
|
||||
0X00,SD_CARD_ERROR_NONE - No error
|
||||
0X01,SD_CARD_ERROR_CMD0 - Card reset failed
|
||||
|
|
@ -35,16 +34,17 @@ Code,Symbol - failed operation
|
|||
0X1C,SD_CARD_ERROR_READ_START - Bad readStart argument
|
||||
0X1D,SD_CARD_ERROR_READ_TIMEOUT - Read data timeout
|
||||
0X1E,SD_CARD_ERROR_STOP_TRAN - Multiple block stop failed
|
||||
0X1F,SD_CARD_ERROR_WRITE_DATA - Write data not accepted
|
||||
0X20,SD_CARD_ERROR_WRITE_FIFO - SDIO fifo write timeout
|
||||
0X21,SD_CARD_ERROR_WRITE_START - Bad writeStart argument
|
||||
0X22,SD_CARD_ERROR_WRITE_PROGRAMMING - Flash programming
|
||||
0X23,SD_CARD_ERROR_WRITE_TIMEOUT - Write timeout
|
||||
0X24,SD_CARD_ERROR_DMA - DMA transfer failed
|
||||
0X25,SD_CARD_ERROR_ERASE - Card did not accept erase commands
|
||||
0X26,SD_CARD_ERROR_ERASE_SINGLE_SECTOR - Card does not support erase
|
||||
0X27,SD_CARD_ERROR_ERASE_TIMEOUT - Erase command timeout
|
||||
0X28,SD_CARD_ERROR_INIT_NOT_CALLED - Card has not been initialized
|
||||
0X29,SD_CARD_ERROR_INVALID_CARD_CONFIG - Invalid card config
|
||||
0X2A,SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED - Unsupported SDIO command
|
||||
0X2B,SD_CARD_ERROR_UNKNOWN - Unknown error
|
||||
0X1F,SD_CARD_ERROR_TRANSFER_COMPLETE - SDIO transfer complete
|
||||
0X20,SD_CARD_ERROR_WRITE_DATA - Write data not accepted
|
||||
0X21,SD_CARD_ERROR_WRITE_FIFO - SDIO fifo write timeout
|
||||
0X22,SD_CARD_ERROR_WRITE_START - Bad writeStart argument
|
||||
0X23,SD_CARD_ERROR_WRITE_PROGRAMMING - Flash programming
|
||||
0X24,SD_CARD_ERROR_WRITE_TIMEOUT - Write timeout
|
||||
0X25,SD_CARD_ERROR_DMA - DMA transfer failed
|
||||
0X26,SD_CARD_ERROR_ERASE - Card did not accept erase commands
|
||||
0X27,SD_CARD_ERROR_ERASE_SINGLE_SECTOR - Card does not support erase
|
||||
0X28,SD_CARD_ERROR_ERASE_TIMEOUT - Erase command timeout
|
||||
0X29,SD_CARD_ERROR_INIT_NOT_CALLED - Card has not been initialized
|
||||
0X2A,SD_CARD_ERROR_INVALID_CARD_CONFIG - Invalid card config
|
||||
0X2B,SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED - Unsupported SDIO command
|
||||
0X2C,SD_CARD_ERROR_UNKNOWN - Unknown error
|
||||
4
doc/ZipMsg/index.html
Normal file
4
doc/ZipMsg/index.html
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<h3>Replace the content of the html folder by unzipping html.zip.</h3>
|
||||
<h3>I have zipped the documentation since Doxygen changes every file each time it runs.</h3>
|
||||
<h3>This makes viewing changes on GitHub difficult.</h3>
|
||||
<p> </p>
|
||||
BIN
doc/html.zip
BIN
doc/html.zip
Binary file not shown.
|
|
@ -1,835 +1,4 @@
|
|||
<html xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
|
||||
xmlns="http://www.w3.org/TR/REC-html40">
|
||||
|
||||
<head>
|
||||
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
|
||||
<meta name=ProgId content=Word.Document>
|
||||
<meta name=Generator content="Microsoft Word 15">
|
||||
<meta name=Originator content="Microsoft Word 15">
|
||||
<link rel=File-List href="index_files/filelist.xml">
|
||||
<!--[if gte mso 9]><xml>
|
||||
<o:DocumentProperties>
|
||||
<o:Author>bill</o:Author>
|
||||
<o:LastAuthor>bill</o:LastAuthor>
|
||||
<o:Revision>6</o:Revision>
|
||||
<o:TotalTime>9</o:TotalTime>
|
||||
<o:Created>2020-12-26T14:24:00Z</o:Created>
|
||||
<o:LastSaved>2020-12-30T14:38:00Z</o:LastSaved>
|
||||
<o:Pages>1</o:Pages>
|
||||
<o:Words>35</o:Words>
|
||||
<o:Characters>201</o:Characters>
|
||||
<o:Lines>1</o:Lines>
|
||||
<o:Paragraphs>1</o:Paragraphs>
|
||||
<o:CharactersWithSpaces>235</o:CharactersWithSpaces>
|
||||
<o:Version>16.00</o:Version>
|
||||
</o:DocumentProperties>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml><![endif]-->
|
||||
<link rel=themeData href="index_files/themedata.thmx">
|
||||
<link rel=colorSchemeMapping href="index_files/colorschememapping.xml">
|
||||
<!--[if gte mso 9]><xml>
|
||||
<w:WordDocument>
|
||||
<w:SpellingState>Clean</w:SpellingState>
|
||||
<w:GrammarState>Clean</w:GrammarState>
|
||||
<w:TrackMoves>false</w:TrackMoves>
|
||||
<w:TrackFormatting/>
|
||||
<w:PunctuationKerning/>
|
||||
<w:ValidateAgainstSchemas/>
|
||||
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
|
||||
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
|
||||
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
|
||||
<w:DoNotPromoteQF/>
|
||||
<w:LidThemeOther>EN-US</w:LidThemeOther>
|
||||
<w:LidThemeAsian>X-NONE</w:LidThemeAsian>
|
||||
<w:LidThemeComplexScript>X-NONE</w:LidThemeComplexScript>
|
||||
<w:Compatibility>
|
||||
<w:BreakWrappedTables/>
|
||||
<w:SnapToGridInCell/>
|
||||
<w:WrapTextWithPunct/>
|
||||
<w:UseAsianBreakRules/>
|
||||
<w:UseWord2010TableStyleRules/>
|
||||
<w:DontGrowAutofit/>
|
||||
<w:SplitPgBreakAndParaMark/>
|
||||
<w:EnableOpenTypeKerning/>
|
||||
<w:DontFlipMirrorIndents/>
|
||||
<w:OverrideTableStyleHps/>
|
||||
</w:Compatibility>
|
||||
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
|
||||
<m:mathPr>
|
||||
<m:mathFont m:val="Cambria Math"/>
|
||||
<m:brkBin m:val="before"/>
|
||||
<m:brkBinSub m:val="--"/>
|
||||
<m:smallFrac m:val="off"/>
|
||||
<m:dispDef/>
|
||||
<m:lMargin m:val="0"/>
|
||||
<m:rMargin m:val="0"/>
|
||||
<m:defJc m:val="centerGroup"/>
|
||||
<m:wrapIndent m:val="1440"/>
|
||||
<m:intLim m:val="subSup"/>
|
||||
<m:naryLim m:val="undOvr"/>
|
||||
</m:mathPr></w:WordDocument>
|
||||
</xml><![endif]--><!--[if gte mso 9]><xml>
|
||||
<w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="false"
|
||||
DefSemiHidden="false" DefQFormat="false" DefPriority="99"
|
||||
LatentStyleCount="376">
|
||||
<w:LsdException Locked="false" Priority="0" QFormat="true" Name="Normal"/>
|
||||
<w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 1"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 2"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 3"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 4"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 5"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 6"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 7"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 8"/>
|
||||
<w:LsdException Locked="false" Priority="9" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="heading 9"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 6"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 7"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 8"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index 9"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 1"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 2"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 3"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 4"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 5"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 6"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 7"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 8"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="toc 9"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Normal Indent"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="footnote text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="annotation text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="header"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="footer"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="index heading"/>
|
||||
<w:LsdException Locked="false" Priority="35" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="caption"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="table of figures"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="envelope address"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="envelope return"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="footnote reference"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="annotation reference"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="line number"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="page number"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="endnote reference"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="endnote text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="table of authorities"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="macro"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="toa heading"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Bullet 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Number 5"/>
|
||||
<w:LsdException Locked="false" Priority="10" QFormat="true" Name="Title"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Closing"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Signature"/>
|
||||
<w:LsdException Locked="false" Priority="1" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="Default Paragraph Font"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text Indent"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="List Continue 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Message Header"/>
|
||||
<w:LsdException Locked="false" Priority="11" QFormat="true" Name="Subtitle"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Salutation"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Date"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text First Indent"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text First Indent 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Note Heading"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text Indent 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Body Text Indent 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Block Text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Hyperlink"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="FollowedHyperlink"/>
|
||||
<w:LsdException Locked="false" Priority="22" QFormat="true" Name="Strong"/>
|
||||
<w:LsdException Locked="false" Priority="20" QFormat="true" Name="Emphasis"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Document Map"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Plain Text"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="E-mail Signature"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Top of Form"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Bottom of Form"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Normal (Web)"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Acronym"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Address"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Cite"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Code"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Definition"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Keyboard"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Preformatted"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Sample"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Typewriter"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="HTML Variable"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Normal Table"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="annotation subject"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="No List"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Outline List 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Outline List 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Outline List 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Simple 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Simple 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Simple 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Classic 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Classic 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Classic 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Classic 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Colorful 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Colorful 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Colorful 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Columns 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 6"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 7"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Grid 8"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 4"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 5"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 6"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 7"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table List 8"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table 3D effects 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table 3D effects 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table 3D effects 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Contemporary"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Elegant"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Professional"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Subtle 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Subtle 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Web 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Web 2"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Web 3"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Balloon Text"/>
|
||||
<w:LsdException Locked="false" Priority="59" Name="Table Grid"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Table Theme"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" Name="Placeholder Text"/>
|
||||
<w:LsdException Locked="false" Priority="1" QFormat="true" Name="No Spacing"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 1"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" Name="Revision"/>
|
||||
<w:LsdException Locked="false" Priority="34" QFormat="true"
|
||||
Name="List Paragraph"/>
|
||||
<w:LsdException Locked="false" Priority="29" QFormat="true" Name="Quote"/>
|
||||
<w:LsdException Locked="false" Priority="30" QFormat="true"
|
||||
Name="Intense Quote"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="60" Name="Light Shading Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="61" Name="Light List Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="62" Name="Light Grid Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="63" Name="Medium Shading 1 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="64" Name="Medium Shading 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="65" Name="Medium List 1 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="66" Name="Medium List 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="67" Name="Medium Grid 1 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="68" Name="Medium Grid 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="69" Name="Medium Grid 3 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="70" Name="Dark List Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="71" Name="Colorful Shading Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="72" Name="Colorful List Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="73" Name="Colorful Grid Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="19" QFormat="true"
|
||||
Name="Subtle Emphasis"/>
|
||||
<w:LsdException Locked="false" Priority="21" QFormat="true"
|
||||
Name="Intense Emphasis"/>
|
||||
<w:LsdException Locked="false" Priority="31" QFormat="true"
|
||||
Name="Subtle Reference"/>
|
||||
<w:LsdException Locked="false" Priority="32" QFormat="true"
|
||||
Name="Intense Reference"/>
|
||||
<w:LsdException Locked="false" Priority="33" QFormat="true" Name="Book Title"/>
|
||||
<w:LsdException Locked="false" Priority="37" SemiHidden="true"
|
||||
UnhideWhenUsed="true" Name="Bibliography"/>
|
||||
<w:LsdException Locked="false" Priority="39" SemiHidden="true"
|
||||
UnhideWhenUsed="true" QFormat="true" Name="TOC Heading"/>
|
||||
<w:LsdException Locked="false" Priority="41" Name="Plain Table 1"/>
|
||||
<w:LsdException Locked="false" Priority="42" Name="Plain Table 2"/>
|
||||
<w:LsdException Locked="false" Priority="43" Name="Plain Table 3"/>
|
||||
<w:LsdException Locked="false" Priority="44" Name="Plain Table 4"/>
|
||||
<w:LsdException Locked="false" Priority="45" Name="Plain Table 5"/>
|
||||
<w:LsdException Locked="false" Priority="40" Name="Grid Table Light"/>
|
||||
<w:LsdException Locked="false" Priority="46" Name="Grid Table 1 Light"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark"/>
|
||||
<w:LsdException Locked="false" Priority="51" Name="Grid Table 6 Colorful"/>
|
||||
<w:LsdException Locked="false" Priority="52" Name="Grid Table 7 Colorful"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="Grid Table 1 Light Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="Grid Table 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="Grid Table 3 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="Grid Table 4 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="Grid Table 5 Dark Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="Grid Table 6 Colorful Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="Grid Table 7 Colorful Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="46" Name="List Table 1 Light"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark"/>
|
||||
<w:LsdException Locked="false" Priority="51" Name="List Table 6 Colorful"/>
|
||||
<w:LsdException Locked="false" Priority="52" Name="List Table 7 Colorful"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 1"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 2"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 3"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 4"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 5"/>
|
||||
<w:LsdException Locked="false" Priority="46"
|
||||
Name="List Table 1 Light Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="47" Name="List Table 2 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="48" Name="List Table 3 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="49" Name="List Table 4 Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="50" Name="List Table 5 Dark Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="51"
|
||||
Name="List Table 6 Colorful Accent 6"/>
|
||||
<w:LsdException Locked="false" Priority="52"
|
||||
Name="List Table 7 Colorful Accent 6"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Mention"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Smart Hyperlink"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Hashtag"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Unresolved Mention"/>
|
||||
<w:LsdException Locked="false" SemiHidden="true" UnhideWhenUsed="true"
|
||||
Name="Smart Link"/>
|
||||
</w:LatentStyles>
|
||||
</xml><![endif]-->
|
||||
<style>
|
||||
<!--
|
||||
/* Font Definitions */
|
||||
@font-face
|
||||
{font-family:"Cambria Math";
|
||||
panose-1:2 4 5 3 5 4 6 3 2 4;
|
||||
mso-font-charset:0;
|
||||
mso-generic-font-family:roman;
|
||||
mso-font-pitch:variable;
|
||||
mso-font-signature:3 0 0 0 1 0;}
|
||||
@font-face
|
||||
{font-family:Calibri;
|
||||
panose-1:2 15 5 2 2 2 4 3 2 4;
|
||||
mso-font-charset:0;
|
||||
mso-generic-font-family:swiss;
|
||||
mso-font-pitch:variable;
|
||||
mso-font-signature:-469750017 -1073732485 9 0 511 0;}
|
||||
/* Style Definitions */
|
||||
p.MsoNormal, li.MsoNormal, div.MsoNormal
|
||||
{mso-style-unhide:no;
|
||||
mso-style-qformat:yes;
|
||||
mso-style-parent:"";
|
||||
margin-top:0in;
|
||||
margin-right:0in;
|
||||
margin-bottom:10.0pt;
|
||||
margin-left:0in;
|
||||
line-height:115%;
|
||||
mso-pagination:widow-orphan;
|
||||
font-size:11.0pt;
|
||||
font-family:"Calibri",sans-serif;
|
||||
mso-ascii-font-family:Calibri;
|
||||
mso-ascii-theme-font:minor-latin;
|
||||
mso-fareast-font-family:Calibri;
|
||||
mso-fareast-theme-font:minor-latin;
|
||||
mso-hansi-font-family:Calibri;
|
||||
mso-hansi-theme-font:minor-latin;
|
||||
mso-bidi-font-family:"Times New Roman";
|
||||
mso-bidi-theme-font:minor-bidi;}
|
||||
p.MsoEnvelopeAddress, li.MsoEnvelopeAddress, div.MsoEnvelopeAddress
|
||||
{mso-style-noshow:yes;
|
||||
mso-style-priority:99;
|
||||
margin-top:0in;
|
||||
margin-right:0in;
|
||||
margin-bottom:0in;
|
||||
margin-left:2.0in;
|
||||
mso-pagination:widow-orphan;
|
||||
mso-element:frame;
|
||||
mso-element-frame-width:5.5in;
|
||||
mso-element-frame-height:99.0pt;
|
||||
mso-element-frame-hspace:9.0pt;
|
||||
mso-element-wrap:auto;
|
||||
mso-element-anchor-horizontal:page;
|
||||
mso-element-left:center;
|
||||
mso-element-top:bottom;
|
||||
font-size:14.0pt;
|
||||
mso-bidi-font-size:12.0pt;
|
||||
font-family:"Arial",sans-serif;
|
||||
mso-fareast-font-family:"Times New Roman";
|
||||
mso-fareast-theme-font:major-fareast;
|
||||
mso-bidi-font-family:"Times New Roman";
|
||||
mso-bidi-theme-font:major-bidi;}
|
||||
p.MsoEnvelopeReturn, li.MsoEnvelopeReturn, div.MsoEnvelopeReturn
|
||||
{mso-style-noshow:yes;
|
||||
mso-style-priority:99;
|
||||
margin:0in;
|
||||
mso-pagination:widow-orphan;
|
||||
font-size:11.0pt;
|
||||
mso-bidi-font-size:10.0pt;
|
||||
font-family:"Arial",sans-serif;
|
||||
mso-fareast-font-family:"Times New Roman";
|
||||
mso-fareast-theme-font:major-fareast;
|
||||
mso-bidi-font-family:"Times New Roman";
|
||||
mso-bidi-theme-font:major-bidi;}
|
||||
a:link, span.MsoHyperlink
|
||||
{mso-style-noshow:yes;
|
||||
mso-style-priority:99;
|
||||
color:blue;
|
||||
text-decoration:underline;
|
||||
text-underline:single;}
|
||||
a:visited, span.MsoHyperlinkFollowed
|
||||
{mso-style-noshow:yes;
|
||||
mso-style-priority:99;
|
||||
color:purple;
|
||||
text-decoration:underline;
|
||||
text-underline:single;}
|
||||
p.msonormal0, li.msonormal0, div.msonormal0
|
||||
{mso-style-name:msonormal;
|
||||
mso-style-unhide:no;
|
||||
mso-margin-top-alt:auto;
|
||||
margin-right:0in;
|
||||
mso-margin-bottom-alt:auto;
|
||||
margin-left:0in;
|
||||
mso-pagination:widow-orphan;
|
||||
font-size:12.0pt;
|
||||
font-family:"Times New Roman",serif;
|
||||
mso-fareast-font-family:"Times New Roman";
|
||||
mso-fareast-theme-font:minor-fareast;}
|
||||
span.SpellE
|
||||
{mso-style-name:"";
|
||||
mso-spl-e:yes;}
|
||||
.MsoChpDefault
|
||||
{mso-style-type:export-only;
|
||||
mso-default-props:yes;
|
||||
font-size:10.0pt;
|
||||
mso-ansi-font-size:10.0pt;
|
||||
mso-bidi-font-size:10.0pt;
|
||||
font-family:"Calibri",sans-serif;
|
||||
mso-ascii-font-family:Calibri;
|
||||
mso-ascii-theme-font:minor-latin;
|
||||
mso-fareast-font-family:Calibri;
|
||||
mso-fareast-theme-font:minor-latin;
|
||||
mso-hansi-font-family:Calibri;
|
||||
mso-hansi-theme-font:minor-latin;
|
||||
mso-bidi-font-family:"Times New Roman";
|
||||
mso-bidi-theme-font:minor-bidi;}
|
||||
@page WordSection1
|
||||
{size:8.5in 11.0in;
|
||||
margin:1.0in 1.0in 1.0in 1.0in;
|
||||
mso-header-margin:.5in;
|
||||
mso-footer-margin:.5in;
|
||||
mso-paper-source:0;}
|
||||
div.WordSection1
|
||||
{page:WordSection1;}
|
||||
-->
|
||||
</style>
|
||||
<!--[if gte mso 10]>
|
||||
<style>
|
||||
/* Style Definitions */
|
||||
table.MsoNormalTable
|
||||
{mso-style-name:"Table Normal";
|
||||
mso-tstyle-rowband-size:0;
|
||||
mso-tstyle-colband-size:0;
|
||||
mso-style-noshow:yes;
|
||||
mso-style-priority:99;
|
||||
mso-style-parent:"";
|
||||
mso-padding-alt:0in 5.4pt 0in 5.4pt;
|
||||
mso-para-margin:0in;
|
||||
mso-pagination:widow-orphan;
|
||||
font-size:10.0pt;
|
||||
font-family:"Calibri",sans-serif;
|
||||
mso-ascii-font-family:Calibri;
|
||||
mso-ascii-theme-font:minor-latin;
|
||||
mso-hansi-font-family:Calibri;
|
||||
mso-hansi-theme-font:minor-latin;
|
||||
mso-bidi-font-family:"Times New Roman";
|
||||
mso-bidi-theme-font:minor-bidi;}
|
||||
</style>
|
||||
<![endif]--><!--[if gte mso 9]><xml>
|
||||
<o:shapedefaults v:ext="edit" spidmax="1026"/>
|
||||
</xml><![endif]--><!--[if gte mso 9]><xml>
|
||||
<o:shapelayout v:ext="edit">
|
||||
<o:idmap v:ext="edit" data="1"/>
|
||||
</o:shapelayout></xml><![endif]-->
|
||||
</head>
|
||||
|
||||
<body lang=EN-US link=blue vlink=purple style='tab-interval:.5in;word-wrap:
|
||||
break-word'>
|
||||
|
||||
<div class=WordSection1>
|
||||
|
||||
<p class=MsoNormal><span style='font-size:18.0pt;line-height:115%'>Replace the
|
||||
content of the html folder by unzipping html.zip.<o:p></o:p></span></p>
|
||||
|
||||
<p class=MsoNormal><span style='font-size:18.0pt;line-height:115%'>I have
|
||||
zipped the documentation since <span class=SpellE>Doxygen</span> changes every
|
||||
file each time it runs.<o:p></o:p></span></p>
|
||||
|
||||
<p class=MsoNormal style='margin-bottom:0in;line-height:normal'><span
|
||||
style='font-size:18.0pt'>This makes viewing changes on GitHub difficult.</span><span
|
||||
style='font-size:12.0pt;font-family:"Times New Roman",serif;mso-fareast-font-family:
|
||||
"Times New Roman"'><a href="https://www.doxygen.nl/"><br>
|
||||
</a></span><span style='font-size:18.0pt'><o:p></o:p></span></p>
|
||||
|
||||
<p class=MsoNormal><span style='font-size:18.0pt;line-height:115%'><o:p> </o:p></span></p>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<h3>Replace the content of the html folder by unzipping html.zip.</h3>
|
||||
<h3>I have zipped the documentation since Doxygen changes every file each time it runs.</h3>
|
||||
<h3>This makes viewing changes on GitHub difficult.</h3>
|
||||
<p> </p>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<a:clrMap xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" bg1="lt1" tx1="dk1" bg2="lt2" tx2="dk2" accent1="accent1" accent2="accent2" accent3="accent3" accent4="accent4" accent5="accent5" accent6="accent6" hlink="hlink" folHlink="folHlink"/>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<xml xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
<o:MainFile HRef="../index.html"/>
|
||||
<o:File HRef="themedata.thmx"/>
|
||||
<o:File HRef="colorschememapping.xml"/>
|
||||
<o:File HRef="filelist.xml"/>
|
||||
</xml>
|
||||
Binary file not shown.
|
|
@ -1,85 +0,0 @@
|
|||
// Force exFAT formatting for all SD cards larger than 512MB.
|
||||
#include "SdFat.h"
|
||||
|
||||
/*
|
||||
Change the value of SD_CS_PIN if you are using SPI and
|
||||
your hardware does not use the default value, SS.
|
||||
Common values are:
|
||||
Arduino Ethernet shield: pin 4
|
||||
Sparkfun SD shield: pin 8
|
||||
Adafruit SD shields and modules: pin 10
|
||||
*/
|
||||
|
||||
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
|
||||
#ifndef SDCARD_SS_PIN
|
||||
const uint8_t SD_CS_PIN = SS;
|
||||
#else // SDCARD_SS_PIN
|
||||
// Assume built-in SD is used.
|
||||
const uint8_t SD_CS_PIN = SDCARD_SS_PIN;
|
||||
#endif // SDCARD_SS_PIN
|
||||
|
||||
// Select fastest interface.
|
||||
#if HAS_SDIO_CLASS
|
||||
// SD config for Teensy 3.6 SDIO.
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
//#define SD_CONFIG SdioConfig(DMA_SDIO)
|
||||
#elif ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI)
|
||||
#else // HAS_SDIO_CLASS
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI)
|
||||
#endif // HAS_SDIO_CLASS
|
||||
|
||||
SdExFat sd;
|
||||
//------------------------------------------------------------------------------
|
||||
void clearSerialInput() {
|
||||
uint32_t m = micros();
|
||||
do {
|
||||
if (Serial.read() >= 0) {
|
||||
m = micros();
|
||||
}
|
||||
} while (micros() - m < 10000);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void errorHalt() {
|
||||
sd.printSdError(&Serial);
|
||||
SysCall::halt();
|
||||
}
|
||||
#define error(s) (Serial.println(F(s)),errorHalt())
|
||||
//------------------------------------------------------------------------------
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {}
|
||||
Serial.println(F("Type any character to begin"));
|
||||
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
clearSerialInput();
|
||||
Serial.println();
|
||||
Serial.println(F(
|
||||
"Your SD will be formated exFAT.\r\n"
|
||||
"All data on the SD will be lost.\r\n"
|
||||
"Type 'Y' to continue.\r\n"));
|
||||
|
||||
while (!Serial.available()) {
|
||||
yield();
|
||||
}
|
||||
if (Serial.read() != 'Y') {
|
||||
Serial.println(F("Exiting, 'Y' not typed."));
|
||||
return;
|
||||
}
|
||||
if (!sd.cardBegin(SD_CONFIG)) {
|
||||
error("cardBegin failed");
|
||||
}
|
||||
if(!sd.format(&Serial)) {
|
||||
error("format failed");
|
||||
}
|
||||
if (!sd.volumeBegin()) {
|
||||
error("volumeBegin failed");
|
||||
}
|
||||
Serial.print(F("Bytes per cluster: "));
|
||||
Serial.println(sd.bytesPerCluster());
|
||||
Serial.println(F("Done"));
|
||||
}
|
||||
void loop() {
|
||||
}
|
||||
|
|
@ -14,7 +14,12 @@ FsFile file1;
|
|||
// Use mySPI2 since SPI2 is used in SPI.h as a different type.
|
||||
static SPIClass mySPI2(2);
|
||||
// Chip select PB21, dedicated SPI, 18 MHz, port 2.
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
#define SD2_CONFIG SdSpiConfig(PB12, DEDICATED_SPI, SD_SCK_MHZ(18), &mySPI2)
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
#define SD2_CONFIG SdSpiConfig(PB12, SHARED_SPI, SD_SCK_MHZ(18), &mySPI2)
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
|
||||
SdFs sd2;
|
||||
FsFile file2;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ const uint8_t SOFT_SCK_PIN = 13;
|
|||
// SdFat software SPI template
|
||||
SoftSpiDriver<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> softSpi;
|
||||
// Speed argument is ignored for software SPI.
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(0), &softSpi)
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(0), &softSpi)
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
|
||||
#if SD_FAT_TYPE == 0
|
||||
SdFat sd;
|
||||
|
|
|
|||
247
examples/TeensyDmaAdcLogger/TeensyDmaAdcLogger.ino
Normal file
247
examples/TeensyDmaAdcLogger/TeensyDmaAdcLogger.ino
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
// Test of Teensy exFAT DMA ADC logger.
|
||||
// This is mainly to test use of RingBuf in an ISR.
|
||||
// You should modify it for serious use as a data logger.
|
||||
//
|
||||
#include "DMAChannel.h"
|
||||
#include "SdFat.h"
|
||||
#include "FreeStack.h"
|
||||
#include "RingBuf.h"
|
||||
|
||||
// 400 sector RingBuf - could be larger on Teensy 4.1.
|
||||
const size_t RING_BUF_SIZE = 400*512;
|
||||
|
||||
// Preallocate 8GiB file.
|
||||
const uint64_t PRE_ALLOCATE_SIZE = 8ULL << 30;
|
||||
|
||||
// Use FIFO SDIO.
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
|
||||
DMAChannel dma(true);
|
||||
|
||||
SdFs sd;
|
||||
|
||||
FsFile file;
|
||||
//------------------------------------------------------------------------------
|
||||
// Ping-pong DMA buffer.
|
||||
DMAMEM static uint16_t __attribute__((aligned(32))) dmaBuf[2][256];
|
||||
size_t dmaCount;
|
||||
|
||||
// RingBuf for 512 byte sectors.
|
||||
RingBuf<FsFile, RING_BUF_SIZE> rb;
|
||||
|
||||
// Shared between ISR and background.
|
||||
volatile size_t maxBytesUsed;
|
||||
|
||||
volatile bool overrun;
|
||||
//------------------------------------------------------------------------------
|
||||
//ISR.
|
||||
static void isr() {
|
||||
if (rb.bytesFreeIsr() >= 512 && !overrun) {
|
||||
rb.memcpyIn(dmaBuf[dmaCount & 1], 512);
|
||||
dmaCount++;
|
||||
if (rb.bytesUsed() > maxBytesUsed) {
|
||||
maxBytesUsed = rb.bytesUsed();
|
||||
}
|
||||
} else {
|
||||
overrun = true;
|
||||
}
|
||||
dma.clearComplete();
|
||||
dma.clearInterrupt();
|
||||
#if defined(__IMXRT1062__)
|
||||
// Handle clear interrupt glitch in Teensy 4.x!
|
||||
asm("DSB");
|
||||
#endif // defined(__IMXRT1062__)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// Over-clocking will degrade quality - use only for stress testing.
|
||||
void overclock() {
|
||||
#if defined(__IMXRT1062__) // Teensy 4.0
|
||||
ADC1_CFG =
|
||||
// High Speed Configuration
|
||||
ADC_CFG_ADHSC |
|
||||
// Sample period 3 clocks
|
||||
ADC_CFG_ADSTS(0) |
|
||||
// Input clock
|
||||
ADC_CFG_ADIV(0) |
|
||||
// Not selected - Long Sample Time Configuration
|
||||
// ADC_CFG_ADLSMP |
|
||||
// 12-bit
|
||||
ADC_CFG_MODE(2) |
|
||||
// Asynchronous clock
|
||||
ADC_CFG_ADICLK(3);
|
||||
#else // defined(__IMXRT1062__)
|
||||
// Set 12 bit mode and max over-clock
|
||||
ADC0_CFG1 =
|
||||
// Clock divide select, 0=direct, 1=div2, 2=div4, 3=div8
|
||||
ADC_CFG1_ADIV(0) |
|
||||
// Sample time configuration, 0=Short, 1=Long
|
||||
// ADC_CFG1_ADLSMP |
|
||||
// Conversion mode, 0=8 bit, 1=12 bit, 2=10 bit, 3=16 bit
|
||||
ADC_CFG1_MODE(1) |
|
||||
// Input clock, 0=bus, 1=bus/2, 2=OSCERCLK, 3=async
|
||||
ADC_CFG1_ADICLK(0);
|
||||
|
||||
ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(3);
|
||||
#endif // defined(__IMXRT1062__)
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
#if defined(__IMXRT1062__) // Teensy 4.0
|
||||
#define SOURCE_SADDR ADC1_R0
|
||||
#define SOURCE_EVENT DMAMUX_SOURCE_ADC1
|
||||
#else
|
||||
#define SOURCE_SADDR ADC0_RA
|
||||
#define SOURCE_EVENT DMAMUX_SOURCE_ADC0
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
// Should replace ADC stuff with calls to Teensy ADC library.
|
||||
// https://github.com/pedvide/ADC
|
||||
static void init(uint8_t pin) {
|
||||
uint32_t adch;
|
||||
uint32_t i, sum = 0;
|
||||
// Actually, do many normal reads, to start with a nice DC level
|
||||
for (i=0; i < 1024; i++) {
|
||||
sum += analogRead(pin);
|
||||
}
|
||||
#if defined(__IMXRT1062__) // Teensy 4.0
|
||||
// save channel
|
||||
adch = ADC1_HC0 & 0x1F;
|
||||
// Continuous conversion , DMA enable
|
||||
ADC1_GC = ADC_GC_ADCO | ADC_GC_DMAEN;
|
||||
// start conversion
|
||||
ADC1_HC0 = adch;
|
||||
#else // defined(__IMXRT1062__) // Teensy 4.0
|
||||
// save channel
|
||||
adch = ADC0_SC1A & 0x1F;
|
||||
// DMA enable
|
||||
ADC0_SC2 |= ADC_SC2_DMAEN;
|
||||
// Continuous conversion enable
|
||||
ADC0_SC3 = ADC_SC3_ADCO;
|
||||
// Start ADC
|
||||
ADC0_SC1A = adch;
|
||||
#endif // defined(__IMXRT1062__) // Teensy 4.0
|
||||
// set up a DMA channel to store the ADC data
|
||||
dma.attachInterrupt(isr);
|
||||
dma.begin();
|
||||
dma.source((volatile const signed short &)SOURCE_SADDR);
|
||||
dma.destinationBuffer((volatile uint16_t*)dmaBuf, sizeof(dmaBuf));
|
||||
dma.interruptAtHalf();
|
||||
dma.interruptAtCompletion();
|
||||
dma.triggerAtHardwareEvent(SOURCE_EVENT);
|
||||
dma.enable();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void stopDma() {
|
||||
#if defined(__IMXRT1062__) // Teensy 4.0
|
||||
ADC1_GC = 0;
|
||||
#else // defined(__IMXRT1062__)
|
||||
ADC0_SC3 = 0;
|
||||
#endif // defined(__IMXRT1062__)
|
||||
dma.disable();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void printTest(Print* pr) {
|
||||
if (file.fileSize() < 1024*2) {
|
||||
return;
|
||||
}
|
||||
file.rewind();
|
||||
rb.begin(&file);
|
||||
// Could readIn RING_BUF_SIZE bytes and write to a csv file in a loop.
|
||||
if (rb.readIn(2048) != 2048) {
|
||||
sd.errorHalt("rb.readIn failed");
|
||||
}
|
||||
uint16_t data;
|
||||
for (size_t i = 0; i < 1024; i++) {
|
||||
pr->print(i);
|
||||
pr->print(',');
|
||||
rb.memcpyOut(&data, 2);
|
||||
pr->println(data);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void runTest(uint8_t pin) {
|
||||
dmaCount = 0;
|
||||
maxBytesUsed = 0;
|
||||
overrun = false;
|
||||
do {
|
||||
delay(10);
|
||||
} while (Serial.read() >= 0);
|
||||
|
||||
if (!file.open("IsrLoggerTest.bin", O_CREAT | O_TRUNC | O_RDWR)) {
|
||||
sd.errorHalt("file.open failed");
|
||||
}
|
||||
if (!file.preAllocate(PRE_ALLOCATE_SIZE)) {
|
||||
sd.errorHalt("file.preAllocate failed");
|
||||
}
|
||||
rb.begin(&file);
|
||||
Serial.println("Type any character to stop\n");
|
||||
|
||||
init(pin);
|
||||
uint32_t samplingTime = micros();
|
||||
while (!overrun && !Serial.available()) {
|
||||
size_t n = rb.bytesUsed();
|
||||
if ((n + file.curPosition()) >= (PRE_ALLOCATE_SIZE - 512)) {
|
||||
Serial.println("File full - stopping");
|
||||
break;
|
||||
}
|
||||
if (n >= 512) {
|
||||
if (rb.writeOut(512) != 512) {
|
||||
Serial.println("writeOut() failed");
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
stopDma();
|
||||
samplingTime = (micros() - samplingTime);
|
||||
if (!file.truncate()) {
|
||||
sd.errorHalt("truncate failed");
|
||||
}
|
||||
if (overrun) {
|
||||
Serial.println("Overrun ERROR!!");
|
||||
}
|
||||
Serial.print("RingBufSize ");
|
||||
Serial.println(RING_BUF_SIZE);
|
||||
Serial.print("maxBytesUsed ");
|
||||
Serial.println(maxBytesUsed);
|
||||
Serial.print("fileSize ");
|
||||
Serial.println((uint32_t)file.fileSize());
|
||||
Serial.print(0.000001*samplingTime);
|
||||
Serial.println(" seconds");
|
||||
Serial.print(1.0*file.fileSize()/samplingTime, 3);
|
||||
Serial.println(" MB/sec\n");
|
||||
printTest(&Serial);
|
||||
file.close();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void waitSerial(const char* msg) {
|
||||
uint32_t m = micros();
|
||||
do {
|
||||
if (Serial.read() >= 0) {
|
||||
m = micros();
|
||||
}
|
||||
} while (micros() - m < 10000);
|
||||
Serial.println(msg);
|
||||
while (!Serial.available()) {}
|
||||
Serial.println();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {
|
||||
yield();
|
||||
}
|
||||
waitSerial("Type any character to begin");
|
||||
Serial.print("FreeStack: ");
|
||||
Serial.println(FreeStack());
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void loop() {
|
||||
if (!sd.begin(SD_CONFIG)) {
|
||||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
//analogReadAveraging(1);
|
||||
//analogReadResolution(12);
|
||||
//overclock(); // 3 Msps on Teensy 3.6 - requires high quality card.
|
||||
runTest(A0);
|
||||
waitSerial("Type any character to run test again");
|
||||
}
|
||||
|
|
@ -197,10 +197,15 @@ void loop() {
|
|||
}
|
||||
Serial.println("\nDMA SDIO mode - slow for small transfers.");
|
||||
} else if (c == '3') {
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
if (!sd.begin(SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(50)))) {
|
||||
errorHalt("begin failed");
|
||||
}
|
||||
Serial.println("\nDedicated SPI mode.");
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
Serial.println("ENABLE_DEDICATED_SPI must be non-zero.");
|
||||
return;
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
} else if (c == '4') {
|
||||
if (!sd.begin(SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50)))) {
|
||||
errorHalt("begin failed");
|
||||
|
|
|
|||
148
examples/TeensySdioLogger/TeensySdioLogger.ino
Normal file
148
examples/TeensySdioLogger/TeensySdioLogger.ino
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
// Test Teensy SDIO with write busy in a data logger demo.
|
||||
//
|
||||
// The driver writes to the uSDHC controller's FIFO then returns
|
||||
// while the controller writes the data to the SD. The first sector
|
||||
// puts the controller in write mode and takes about 11 usec on a
|
||||
// Teensy 4.1. About 5 usec is required to write a sector when the
|
||||
// controller is in write mode.
|
||||
|
||||
#include "SdFat.h"
|
||||
#include "RingBuf.h"
|
||||
|
||||
// Use Teensy SDIO
|
||||
#define SD_CONFIG SdioConfig(FIFO_SDIO)
|
||||
|
||||
// Interval between points for 25 ksps.
|
||||
#define LOG_INTERVAL_USEC 40
|
||||
|
||||
// Size to log 10 byte lines at 25 kHz for more than ten minutes.
|
||||
#define LOG_FILE_SIZE 10*25000*600 // 150,000,000 bytes.
|
||||
|
||||
// Space to hold more than 800 ms of data for 10 byte lines at 25 ksps.
|
||||
#define RING_BUF_CAPACITY 400*512
|
||||
#define LOG_FILENAME "SdioLogger.csv"
|
||||
|
||||
SdFs sd;
|
||||
FsFile file;
|
||||
|
||||
// RingBuf for File type FsFile.
|
||||
RingBuf<FsFile, RING_BUF_CAPACITY> rb;
|
||||
|
||||
void logData() {
|
||||
// Initialize the SD.
|
||||
if (!sd.begin(SD_CONFIG)) {
|
||||
sd.initErrorHalt(&Serial);
|
||||
}
|
||||
// Open or create file - truncate existing file.
|
||||
if (!file.open(LOG_FILENAME, O_RDWR | O_CREAT | O_TRUNC)) {
|
||||
Serial.println("open failed\n");
|
||||
return;
|
||||
}
|
||||
// File must be pre-allocated to avoid huge
|
||||
// delays searching for free clusters.
|
||||
if (!file.preAllocate(LOG_FILE_SIZE)) {
|
||||
Serial.println("preAllocate failed\n");
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
// initialize the RingBuf.
|
||||
rb.begin(&file);
|
||||
Serial.println("Type any character to stop");
|
||||
|
||||
// Max RingBuf used bytes. Useful to understand RingBuf overrun.
|
||||
size_t maxUsed = 0;
|
||||
|
||||
// Min spare micros in loop.
|
||||
int32_t minSpareMicros = INT32_MAX;
|
||||
|
||||
// Start time.
|
||||
uint32_t logTime = micros();
|
||||
// Log data until Serial input or file full.
|
||||
while (!Serial.available()) {
|
||||
// Amount of data in ringBuf.
|
||||
size_t n = rb.bytesUsed();
|
||||
if ((n + file.curPosition()) > (LOG_FILE_SIZE - 20)) {
|
||||
Serial.println("File full - quiting.");
|
||||
break;
|
||||
}
|
||||
if (n > maxUsed) {
|
||||
maxUsed = n;
|
||||
}
|
||||
if (n >= 512 && !file.isBusy()) {
|
||||
// Not busy only allows one sector before possible busy wait.
|
||||
// Write one sector from RingBuf to file.
|
||||
if (512 != rb.writeOut(512)) {
|
||||
Serial.println("writeOut failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Time for next point.
|
||||
logTime += LOG_INTERVAL_USEC;
|
||||
int32_t spareMicros = logTime - micros();
|
||||
if (spareMicros < minSpareMicros) {
|
||||
minSpareMicros = spareMicros;
|
||||
}
|
||||
if (spareMicros <= 0) {
|
||||
Serial.print("Rate too fast ");
|
||||
Serial.println(spareMicros);
|
||||
break;
|
||||
}
|
||||
// Wait until time to log data.
|
||||
while (micros() < logTime) {}
|
||||
|
||||
// Read ADC0 - about 17 usec on Teensy 4, Teensy 3.6 is faster.
|
||||
uint16_t adc = analogRead(0);
|
||||
// Print spareMicros into the RingBuf as test data.
|
||||
rb.print(spareMicros);
|
||||
rb.write(',');
|
||||
// Print adc into RingBuf.
|
||||
rb.println(adc);
|
||||
if (rb.getWriteError()) {
|
||||
// Error caused by too few free bytes in RingBuf.
|
||||
Serial.println("WriteError");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Write any RingBuf data to file.
|
||||
rb.sync();
|
||||
file.truncate();
|
||||
file.rewind();
|
||||
// Print first twenty lines of file.
|
||||
Serial.println("spareMicros,ADC0");
|
||||
for (uint8_t n = 0; n < 20 && file.available();) {
|
||||
int c = file.read();
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
Serial.write(c);
|
||||
if (c == '\n') n++;
|
||||
}
|
||||
Serial.print("fileSize: ");
|
||||
Serial.println((uint32_t)file.fileSize());
|
||||
Serial.print("maxBytesUsed: ");
|
||||
Serial.println(maxUsed);
|
||||
Serial.print("minSpareMicros: ");
|
||||
Serial.println(minSpareMicros);
|
||||
file.close();
|
||||
}
|
||||
void clearSerialInput() {
|
||||
for (uint32_t m = micros(); micros() - m < 10000;) {
|
||||
if (Serial.read() >= 0) {
|
||||
m = micros();
|
||||
}
|
||||
}
|
||||
}
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {}
|
||||
// Go faster or log more channels. ADC quality will suffer.
|
||||
// analogReadAveraging(1);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
clearSerialInput();
|
||||
Serial.println("Type any character to start");
|
||||
while (!Serial.available()) {};
|
||||
clearSerialInput();
|
||||
logData();
|
||||
}
|
||||
|
|
@ -59,8 +59,11 @@ class MySpiClass : public SdSpiBaseClass {
|
|||
private:
|
||||
SPISettings m_spiSettings;
|
||||
} mySpi;
|
||||
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(50), &mySpi)
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50), &mySpi)
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
SdFat sd;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
name=SdFat
|
||||
version=2.0.4
|
||||
version=2.0.5
|
||||
license=MIT
|
||||
author=Bill Greiman <fat16lib@sbcglobal.net>
|
||||
maintainer=Bill Greiman <fat16lib@sbcglobal.net>
|
||||
|
|
|
|||
|
|
@ -405,7 +405,7 @@ bool ExFatPartition::printDir(print_t* pr, ExFatFile* file) {
|
|||
uint16_t calcHash = 0;
|
||||
uint16_t nameHash = 0;
|
||||
uint16_t setChecksum = 0;
|
||||
uint16_t calcChecksum = 0;;
|
||||
uint16_t calcChecksum = 0;
|
||||
uint8_t nameLength = 0;
|
||||
uint8_t setCount = 0;
|
||||
uint8_t nUnicode;
|
||||
|
|
|
|||
|
|
@ -156,10 +156,10 @@ size_t ExFatFile::getName(ExChar_t* name, size_t length) {
|
|||
goto fail;
|
||||
}
|
||||
for (uint8_t in = 0; in < 15; in++) {
|
||||
if ((n + 1) >= length) {
|
||||
uint16_t c = getLe16(dn->unicode + 2*in);
|
||||
if (c == 0 || (n + 1) >= length) {
|
||||
goto done;
|
||||
}
|
||||
uint16_t c = getLe16(dn->unicode + 2*in);
|
||||
name[n++] = sizeof(ExChar_t) > 1 || c < 0X7F ? c : '?';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,17 @@ struct ExFatPos_t {
|
|||
class ExFatFile {
|
||||
public:
|
||||
/** Create an instance. */
|
||||
ExFatFile() : m_attributes(FILE_ATTR_CLOSED), m_error(0), m_flags(0) {}
|
||||
ExFatFile() {}
|
||||
/** Create a file object and open it in the current working directory.
|
||||
*
|
||||
* \param[in] path A path for a file to be opened.
|
||||
*
|
||||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
|
||||
*/
|
||||
ExFatFile(const char* path, oflag_t oflag) {
|
||||
open(path, oflag);
|
||||
}
|
||||
|
||||
#if DESTRUCTOR_CLOSES_FILE
|
||||
~ExFatFile() {
|
||||
|
|
@ -108,12 +118,6 @@ class ExFatFile {
|
|||
operator bool() {
|
||||
return isOpen();
|
||||
}
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. Zero is returned for directory files.
|
||||
*/
|
||||
uint64_t available64() {
|
||||
return isFile() ? fileSize() - curPosition() : 0;
|
||||
}
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. INT_MAX is returned for very large files.
|
||||
*
|
||||
|
|
@ -126,6 +130,20 @@ class ExFatFile {
|
|||
uint64_t n = available64();
|
||||
return n > INT_MAX ? INT_MAX : n;
|
||||
}
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. Zero is returned for directory files.
|
||||
*/
|
||||
uint64_t available64() {
|
||||
return isFile() ? fileSize() - curPosition() : 0;
|
||||
}
|
||||
/** Clear all error bits. */
|
||||
void clearError() {
|
||||
m_error = 0;
|
||||
}
|
||||
/** Clear writeError. */
|
||||
void clearWriteError() {
|
||||
m_error &= ~WRITE_ERROR;
|
||||
}
|
||||
/** Close a file and force cached data and directory information
|
||||
* to be written to the storage device.
|
||||
*
|
||||
|
|
@ -200,22 +218,6 @@ class ExFatFile {
|
|||
void fsetpos(const fspos_t* pos);
|
||||
/** Arduino name for sync() */
|
||||
void flush() {sync();}
|
||||
/**
|
||||
* Get a file's name followed by a zero byte.
|
||||
*
|
||||
* \param[out] name An array of characters for the file's name.
|
||||
* \param[in] size The size of the array in characters.
|
||||
* \return the name length.
|
||||
*/
|
||||
size_t getName(ExChar_t* name, size_t size);
|
||||
/** Clear all error bits. */
|
||||
void clearError() {
|
||||
m_error = 0;
|
||||
}
|
||||
/** Clear writeError. */
|
||||
void clearWriteError() {
|
||||
m_error &= ~WRITE_ERROR;
|
||||
}
|
||||
/** Get a file's access date and time.
|
||||
*
|
||||
* \param[out] pdate Packed date for directory entry.
|
||||
|
|
@ -244,6 +246,14 @@ class ExFatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime);
|
||||
/**
|
||||
* Get a file's name followed by a zero byte.
|
||||
*
|
||||
* \param[out] name An array of characters for the file's name.
|
||||
* \param[in] size The size of the array in characters.
|
||||
* \return the name length.
|
||||
*/
|
||||
size_t getName(ExChar_t* name, size_t size);
|
||||
/** \return value of writeError */
|
||||
bool getWriteError() const {
|
||||
return isOpen() ? m_error & WRITE_ERROR : true;
|
||||
|
|
@ -266,12 +276,12 @@ class ExFatFile {
|
|||
bool isOpen() const {return m_attributes;}
|
||||
/** \return True if file is read-only */
|
||||
bool isReadOnly() const {return m_attributes & FILE_ATTR_READ_ONLY;}
|
||||
/** \return True if this is a subdirectory. */
|
||||
bool isSubDir() const {return m_attributes & FILE_ATTR_SUBDIR;}
|
||||
/** \return True if this is the root directory. */
|
||||
bool isRoot() const {return m_attributes & FILE_ATTR_ROOT;}
|
||||
/** \return True file is writable. */
|
||||
/** \return True file is readable. */
|
||||
bool isReadable() const {return m_flags & FILE_FLAG_READ;}
|
||||
/** \return True if this is a subdirectory. */
|
||||
bool isSubDir() const {return m_attributes & FILE_ATTR_SUBDIR;}
|
||||
/** \return True file is writable. */
|
||||
bool isWritable() const {return m_flags & FILE_FLAG_WRITE;}
|
||||
/** List directory contents.
|
||||
|
|
@ -381,6 +391,16 @@ class ExFatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool open(ExFatFile* dirFile, uint32_t index, oflag_t oflag);
|
||||
/** Open a file in the current working directory.
|
||||
*
|
||||
* \param[in] path A path with a valid name for a file to be opened.
|
||||
*
|
||||
* \param[in] oflag bitwise-inclusive OR of open flags.
|
||||
* See see ExFatFile::open(ExFatFile*, const char*, uint8_t).
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool open(const ExChar_t* path, int oflag = O_RDONLY);
|
||||
/** Open the next file or subdirectory in a directory.
|
||||
*
|
||||
* \param[in] dirFile An open instance for the directory
|
||||
|
|
@ -392,16 +412,6 @@ class ExFatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool openNext(ExFatFile* dirFile, oflag_t oflag = O_RDONLY);
|
||||
/** Open a file in the current working directory.
|
||||
*
|
||||
* \param[in] path A path with a valid name for a file to be opened.
|
||||
*
|
||||
* \param[in] oflag bitwise-inclusive OR of open flags.
|
||||
* See see ExFatFile::open(ExFatFile*, const char*, uint8_t).
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool open(const ExChar_t* path, int oflag = O_RDONLY);
|
||||
/** Open a volume's root directory.
|
||||
*
|
||||
* \param[in] vol The FAT volume containing the root directory to be opened.
|
||||
|
|
@ -425,6 +435,20 @@ class ExFatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool preAllocate(uint64_t length);
|
||||
/** Print a file's access date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printAccessDateTime(print_t* pr);
|
||||
/** Print a file's creation date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printCreateDateTime(print_t* pr);
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
|
|
@ -488,21 +512,6 @@ class ExFatFile {
|
|||
* \return The number of bytes printed.
|
||||
*/
|
||||
size_t printFileSize(print_t* pr);
|
||||
/** Print a file's access date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printAccessDateTime(print_t* pr);
|
||||
/** Print a file's creation date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printCreateDateTime(print_t* pr);
|
||||
|
||||
/** Print a file's modify date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
|
|
@ -780,9 +789,9 @@ class ExFatFile {
|
|||
ExFatVolume* m_vol;
|
||||
DirPos_t m_dirPos;
|
||||
uint8_t m_setCount;
|
||||
uint8_t m_attributes;
|
||||
uint8_t m_error;
|
||||
uint8_t m_flags;
|
||||
uint8_t m_attributes = FILE_ATTR_CLOSED;
|
||||
uint8_t m_error = 0;
|
||||
uint8_t m_flags = 0;
|
||||
};
|
||||
|
||||
#include "../common/ArduinoFiles.h"
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ size_t ExFatFile::printName(print_t* pr) {
|
|||
for (in = 0; in < 15; in++) {
|
||||
uint16_t c = getLe16(dn->unicode + 2*in);
|
||||
if (!c) {
|
||||
break;;
|
||||
break;
|
||||
}
|
||||
buf[in] = c < 0X7f ? c : '?';
|
||||
n++;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class ExFatFile;
|
|||
*/
|
||||
class ExFatPartition {
|
||||
public:
|
||||
ExFatPartition() : m_fatType(0) {}
|
||||
ExFatPartition() {}
|
||||
/** \return the number of bytes in a cluster. */
|
||||
uint32_t bytesPerCluster() const {return m_bytesPerCluster;}
|
||||
/** \return the power of two for bytesPerCluster. */
|
||||
|
|
@ -203,7 +203,7 @@ class ExFatPartition {
|
|||
uint32_t m_clusterMask;
|
||||
uint32_t m_bytesPerCluster;
|
||||
BlockDevice* m_blockDev;
|
||||
uint8_t m_fatType;
|
||||
uint8_t m_fatType = 0;
|
||||
uint8_t m_sectorsPerClusterShift;
|
||||
};
|
||||
#endif // ExFatPartition_h
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@
|
|||
*/
|
||||
class ExFatVolume : public ExFatPartition {
|
||||
public:
|
||||
ExFatVolume() {
|
||||
}
|
||||
ExFatVolume() {}
|
||||
/**
|
||||
* Initialize an FatVolume object.
|
||||
* \param[in] dev Device block driver.
|
||||
|
|
@ -49,7 +48,7 @@ class ExFatVolume : public ExFatPartition {
|
|||
if (!chdir()) {
|
||||
return false;
|
||||
}
|
||||
if (setCwv) {
|
||||
if (setCwv || !m_cwv) {
|
||||
m_cwv = this;
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ const uint8_t FNAME_FLAG_LC_EXT = FAT_CASE_LC_EXT;
|
|||
class FatFile {
|
||||
public:
|
||||
/** Create an instance. */
|
||||
FatFile() : m_attributes(FILE_ATTR_CLOSED), m_error(0), m_flags(0) {}
|
||||
|
||||
FatFile() {}
|
||||
/** Create a file object and open it in the current working directory.
|
||||
*
|
||||
* \param[in] path A path for a file to be opened.
|
||||
|
|
@ -120,11 +119,10 @@ class FatFile {
|
|||
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
|
||||
*/
|
||||
FatFile(const char* path, oflag_t oflag) {
|
||||
m_attributes = FILE_ATTR_CLOSED;
|
||||
m_error = 0;
|
||||
open(path, oflag);
|
||||
}
|
||||
#if DESTRUCTOR_CLOSES_FILE
|
||||
/** Destructor */
|
||||
~FatFile() {
|
||||
if (isOpen()) {
|
||||
close();
|
||||
|
|
@ -135,11 +133,25 @@ class FatFile {
|
|||
*
|
||||
* \return true if a file is open.
|
||||
*/
|
||||
operator bool() {
|
||||
return isOpen();
|
||||
operator bool() const {return isOpen();}
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. INT_MAX is returned for very large files.
|
||||
*
|
||||
* available32() is recomended for very large files.
|
||||
*
|
||||
* Zero is returned for directory files.
|
||||
*
|
||||
*/
|
||||
int available() const {
|
||||
uint32_t n = available32();
|
||||
return n > INT_MAX ? INT_MAX : n;
|
||||
}
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. Zero is returned for directory files.
|
||||
*/
|
||||
uint32_t available32() const {
|
||||
return isFile() ? fileSize() - curPosition() : 0;
|
||||
}
|
||||
/** Arduino name for sync() */
|
||||
void flush() {sync();}
|
||||
/** Clear all error bits. */
|
||||
void clearError() {
|
||||
m_error = 0;
|
||||
|
|
@ -148,8 +160,117 @@ class FatFile {
|
|||
void clearWriteError() {
|
||||
m_error &= ~WRITE_ERROR;
|
||||
}
|
||||
/** Close a file and force cached data and directory information
|
||||
* to be written to the storage device.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool close();
|
||||
/** Check for contiguous file and return its raw sector range.
|
||||
*
|
||||
* \param[out] bgnSector the first sector address for the file.
|
||||
* \param[out] endSector the last sector address for the file.
|
||||
*
|
||||
* Set the contiguous flag if the file is contiguous.
|
||||
* The parameters may be nullptr to only set the flag.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector);
|
||||
/** Create and open a new contiguous file of a specified size.
|
||||
*
|
||||
* \param[in] dirFile The directory where the file will be created.
|
||||
* \param[in] path A path with a valid file name.
|
||||
* \param[in] size The desired file size.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool createContiguous(FatFile* dirFile,
|
||||
const char* path, uint32_t size);
|
||||
/** Create and open a new contiguous file of a specified size.
|
||||
*
|
||||
* \param[in] path A path with a valid file name.
|
||||
* \param[in] size The desired file size.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool createContiguous(const char* path, uint32_t size);
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
uint32_t curCluster() const {return m_curCluster;}
|
||||
|
||||
/** \return The current position for a file or directory. */
|
||||
uint32_t curPosition() const {return m_curPosition;}
|
||||
/** Return a file's directory entry.
|
||||
*
|
||||
* \param[out] dir Location for return of the file's directory entry.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool dirEntry(DirFat_t* dir);
|
||||
/** \return Directory entry index. */
|
||||
uint16_t dirIndex() const {return m_dirIndex;}
|
||||
/** \return The number of bytes allocated to a directory or zero
|
||||
* if an error occurs.
|
||||
*/
|
||||
uint32_t dirSize();
|
||||
/** Dump file in Hex
|
||||
* \param[in] pr Print stream for list.
|
||||
* \param[in] pos Start position in file.
|
||||
* \param[in] n number of locations to dump.
|
||||
*/
|
||||
void dmpFile(print_t* pr, uint32_t pos, size_t n);
|
||||
/** Test for the existence of a file in a directory
|
||||
*
|
||||
* \param[in] path Path of the file to be tested for.
|
||||
*
|
||||
* The calling instance must be an open directory file.
|
||||
*
|
||||
* dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory
|
||||
* dirFile.
|
||||
*
|
||||
* \return True if the file exists.
|
||||
*/
|
||||
bool exists(const char* path) {
|
||||
FatFile file;
|
||||
return file.open(this, path, O_RDONLY);
|
||||
}
|
||||
/** get position for streams
|
||||
* \param[out] pos struct to receive position
|
||||
*/
|
||||
void fgetpos(fspos_t* pos) const;
|
||||
/**
|
||||
* Get a string from a file.
|
||||
*
|
||||
* fgets() reads bytes from a file into the array pointed to by \a str, until
|
||||
* \a num - 1 bytes are read, or a delimiter is read and transferred to
|
||||
* \a str, or end-of-file is encountered. The string is then terminated
|
||||
* with a null byte.
|
||||
*
|
||||
* fgets() deletes CR, '\\r', from the string. This insures only a '\\n'
|
||||
* terminates the string for Windows text files which use CRLF for newline.
|
||||
*
|
||||
* \param[out] str Pointer to the array where the string is stored.
|
||||
* \param[in] num Maximum number of characters to be read
|
||||
* (including the final null byte). Usually the length
|
||||
* of the array \a str is used.
|
||||
* \param[in] delim Optional set of delimiters. The default is "\n".
|
||||
*
|
||||
* \return For success fgets() returns the length of the string in \a str.
|
||||
* If no data is read, fgets() returns zero for EOF or -1 if an error
|
||||
* occurred.
|
||||
*/
|
||||
int fgets(char* str, int num, char* delim = nullptr);
|
||||
/** \return The total number of bytes in a file. */
|
||||
uint32_t fileSize() const {return m_fileSize;}
|
||||
/** \return first sector of file or zero for empty file. */
|
||||
uint32_t firstBlock() const {return firstSector();}
|
||||
/** \return Address of first sector or zero for empty file. */
|
||||
uint32_t firstSector() const;
|
||||
/** Arduino name for sync() */
|
||||
void flush() {sync();}
|
||||
/** set position for streams
|
||||
* \param[in] pos struct with value for new position
|
||||
*/
|
||||
void fsetpos(const fspos_t* pos);
|
||||
/** Get a file's access date.
|
||||
*
|
||||
* \param[out] pdate Packed date for directory entry.
|
||||
|
|
@ -191,139 +312,6 @@ class FatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool getModifyDateTime(uint16_t* pdate, uint16_t* ptime);
|
||||
/** \return value of writeError */
|
||||
bool getWriteError() const {
|
||||
return isOpen() ? m_error & WRITE_ERROR : true;
|
||||
}
|
||||
/** get position for streams
|
||||
* \param[out] pos struct to receive position
|
||||
*/
|
||||
void fgetpos(fspos_t* pos) const;
|
||||
/** set position for streams
|
||||
* \param[in] pos struct with value for new position
|
||||
*/
|
||||
void fsetpos(const fspos_t* pos);
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. Zero is returned for directory files.
|
||||
*/
|
||||
uint32_t available32() {
|
||||
return isFile() ? fileSize() - curPosition() : 0;
|
||||
}
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. INT_MAX is returned for very large files.
|
||||
*
|
||||
* available64() is recomended for very large files.
|
||||
*
|
||||
* Zero is returned for directory files.
|
||||
*
|
||||
*/
|
||||
int available() {
|
||||
uint32_t n = available32();
|
||||
return n > INT_MAX ? INT_MAX : n;
|
||||
}
|
||||
/** Close a file and force cached data and directory information
|
||||
* to be written to the storage device.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool close();
|
||||
/** Check for contiguous file and return its raw sector range.
|
||||
*
|
||||
* \param[out] bgnSector the first sector address for the file.
|
||||
* \param[out] endSector the last sector address for the file.
|
||||
*
|
||||
* Set the contiguous flag if the file is contiguous.
|
||||
* The parameters may be nullptr to only set the flag.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool contiguousRange(uint32_t* bgnSector, uint32_t* endSector);
|
||||
|
||||
/** Create and open a new contiguous file of a specified size.
|
||||
*
|
||||
* \param[in] dirFile The directory where the file will be created.
|
||||
* \param[in] path A path with a valid file name.
|
||||
* \param[in] size The desired file size.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool createContiguous(FatFile* dirFile,
|
||||
const char* path, uint32_t size);
|
||||
/** Create and open a new contiguous file of a specified size.
|
||||
*
|
||||
* \param[in] path A path with a valid file name.
|
||||
* \param[in] size The desired file size.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool createContiguous(const char* path, uint32_t size);
|
||||
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
uint32_t curCluster() const {return m_curCluster;}
|
||||
|
||||
/** \return The current position for a file or directory. */
|
||||
uint32_t curPosition() const {return m_curPosition;}
|
||||
|
||||
/** Return a file's directory entry.
|
||||
*
|
||||
* \param[out] dir Location for return of the file's directory entry.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool dirEntry(DirFat_t* dir);
|
||||
/** \return The number of bytes allocated to a directory or zero
|
||||
* if an error occurs.
|
||||
*/
|
||||
uint32_t dirSize();
|
||||
/** Dump file in Hex
|
||||
* \param[in] pr Print stream for list.
|
||||
* \param[in] pos Start position in file.
|
||||
* \param[in] n number of locations to dump.
|
||||
*/
|
||||
void dmpFile(print_t* pr, uint32_t pos, size_t n);
|
||||
/** Test for the existence of a file in a directory
|
||||
*
|
||||
* \param[in] path Path of the file to be tested for.
|
||||
*
|
||||
* The calling instance must be an open directory file.
|
||||
*
|
||||
* dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory
|
||||
* dirFile.
|
||||
*
|
||||
* \return True if the file exists.
|
||||
*/
|
||||
bool exists(const char* path) {
|
||||
FatFile file;
|
||||
return file.open(this, path, O_RDONLY);
|
||||
}
|
||||
/**
|
||||
* Get a string from a file.
|
||||
*
|
||||
* fgets() reads bytes from a file into the array pointed to by \a str, until
|
||||
* \a num - 1 bytes are read, or a delimiter is read and transferred to
|
||||
* \a str, or end-of-file is encountered. The string is then terminated
|
||||
* with a null byte.
|
||||
*
|
||||
* fgets() deletes CR, '\\r', from the string. This insures only a '\\n'
|
||||
* terminates the string for Windows text files which use CRLF for newline.
|
||||
*
|
||||
* \param[out] str Pointer to the array where the string is stored.
|
||||
* \param[in] num Maximum number of characters to be read
|
||||
* (including the final null byte). Usually the length
|
||||
* of the array \a str is used.
|
||||
* \param[in] delim Optional set of delimiters. The default is "\n".
|
||||
*
|
||||
* \return For success fgets() returns the length of the string in \a str.
|
||||
* If no data is read, fgets() returns zero for EOF or -1 if an error
|
||||
* occurred.
|
||||
*/
|
||||
int fgets(char* str, int num, char* delim = nullptr);
|
||||
|
||||
/** \return The total number of bytes in a file. */
|
||||
uint32_t fileSize() const {return m_fileSize;}
|
||||
/** \return first sector of file or zero for empty file. */
|
||||
uint32_t firstBlock() const {return firstSector();}
|
||||
/** \return Address of first sector or zero for empty file. */
|
||||
uint32_t firstSector() const;
|
||||
/**
|
||||
* Get a file's name followed by a zero byte.
|
||||
*
|
||||
|
|
@ -331,9 +319,9 @@ class FatFile {
|
|||
* \param[in] size The size of the array in bytes. The array
|
||||
* must be at least 13 bytes long. The file's name will be
|
||||
* truncated if the file's name is too long.
|
||||
* \return true for success or false for failure.
|
||||
* \return length for success or zero for failure.
|
||||
*/
|
||||
bool getName(char* name, size_t size);
|
||||
size_t getName(char* name, size_t size);
|
||||
/**
|
||||
* Get a file's Short File Name followed by a zero byte.
|
||||
*
|
||||
|
|
@ -341,7 +329,11 @@ class FatFile {
|
|||
* The array must be at least 13 bytes long.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool getSFN(char* name);
|
||||
size_t getSFN(char* name);
|
||||
/** \return value of writeError */
|
||||
bool getWriteError() const {
|
||||
return isOpen() ? m_error & WRITE_ERROR : true;
|
||||
}
|
||||
/**
|
||||
* Check for BlockDevice busy.
|
||||
*
|
||||
|
|
@ -362,21 +354,21 @@ class FatFile {
|
|||
bool isLFN() const {return m_lfnOrd;}
|
||||
/** \return True if this is an open file/directory. */
|
||||
bool isOpen() const {return m_attributes;}
|
||||
/** \return True file is readable. */
|
||||
bool isReadable() const {return m_flags & FILE_FLAG_READ;}
|
||||
/** \return True if file is read-only */
|
||||
bool isReadOnly() const {return m_attributes & FILE_ATTR_READ_ONLY;}
|
||||
/** \return True if this is the root directory. */
|
||||
bool isRoot() const {return m_attributes & FILE_ATTR_ROOT;}
|
||||
/** \return True if this is the FAT32 root directory. */
|
||||
bool isRoot32() const {return m_attributes & FILE_ATTR_ROOT32;}
|
||||
/** \return True if this is the FAT12 of FAT16 root directory. */
|
||||
bool isRootFixed() const {return m_attributes & FILE_ATTR_ROOT_FIXED;}
|
||||
/** \return True if file is read-only */
|
||||
bool isReadOnly() const {return m_attributes & FILE_ATTR_READ_ONLY;}
|
||||
/** \return True if this is a subdirectory. */
|
||||
bool isSubDir() const {return m_attributes & FILE_ATTR_SUBDIR;}
|
||||
/** \return True if this is a system file. */
|
||||
bool isSystem() const {return m_attributes & FILE_ATTR_SYSTEM;}
|
||||
/** \return True file is writable. */
|
||||
bool isReadable() const {return m_flags & FILE_FLAG_READ;}
|
||||
/** \return True file is writable. */
|
||||
bool isWritable() const {return m_flags & FILE_FLAG_WRITE;}
|
||||
/** Check for a legal 8.3 character.
|
||||
* \param[in] c Character to be checked.
|
||||
|
|
@ -430,7 +422,14 @@ class FatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool mkdir(FatFile* dir, const char* path, bool pFlag = true);
|
||||
|
||||
/** No longer implemented due to Long File Names.
|
||||
*
|
||||
* Use getName(char* name, size_t size).
|
||||
* \return a pointer to replacement suggestion.
|
||||
*/
|
||||
const char* name() const {
|
||||
return "use getName()";
|
||||
}
|
||||
/** Open a file in the volume root directory.
|
||||
*
|
||||
* \param[in] vol Volume where the file is located.
|
||||
|
|
@ -464,7 +463,7 @@ class FatFile {
|
|||
*
|
||||
* \param[in] path A path with a valid name for a file to be opened.
|
||||
*
|
||||
* \param[in] oflag Values for \a oflag are constructed by a
|
||||
* \param[in] oflag Values for \a oflag are constructed by a
|
||||
* bitwise-inclusive OR of flags from the following list.
|
||||
* Only one of O_RDONLY, O_READ, O_WRONLY, O_WRITE, or
|
||||
* O_RDWR is allowed.
|
||||
|
|
@ -536,7 +535,7 @@ class FatFile {
|
|||
* \return The byte if no error and not at eof else -1;
|
||||
*/
|
||||
int peek();
|
||||
/** Allocate contiguous clusters to an empty file.
|
||||
/** Allocate contiguous clusters to an empty file.
|
||||
*
|
||||
* The file must be empty with no clusters allocated.
|
||||
*
|
||||
|
|
@ -546,13 +545,29 @@ class FatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool preAllocate(uint32_t length);
|
||||
/** Print a file's access date
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return The number of characters printed.
|
||||
*/
|
||||
size_t printAccessDate(print_t* pr);
|
||||
/** Print a file's access date
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return The number of characters printed.
|
||||
*/
|
||||
size_t printAccessDateTime(print_t* pr) {
|
||||
return printAccessDate(pr);
|
||||
}
|
||||
/** Print a file's creation date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return The number of bytes printed.
|
||||
*/
|
||||
size_t printCreateDateTime(print_t* pr);
|
||||
size_t printCreateDateTime(print_t* pr);
|
||||
/** %Print a directory date field.
|
||||
*
|
||||
* Format is yyyy-mm-dd.
|
||||
|
|
@ -627,22 +642,14 @@ class FatFile {
|
|||
}
|
||||
return write(str, &buf[sizeof(buf)] - str);
|
||||
}
|
||||
/** Print a file's access date
|
||||
/** Print a file's size.
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return The number of characters printed.
|
||||
* \return The number of characters printed is returned
|
||||
* for success and zero is returned for failure.
|
||||
*/
|
||||
size_t printAccessDate(print_t* pr);
|
||||
/** Print a file's access date
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return The number of characters printed.
|
||||
*/
|
||||
size_t printAccessDateTime(print_t* pr) {
|
||||
return printAccessDate(pr);
|
||||
}
|
||||
size_t printFileSize(print_t* pr);
|
||||
/** Print a file's modify date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
|
|
@ -657,14 +664,7 @@ class FatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printName(print_t* pr);
|
||||
/** Print a file's size.
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return The number of characters printed is returned
|
||||
* for success and zero is returned for failure.
|
||||
*/
|
||||
size_t printFileSize(print_t* pr);
|
||||
|
||||
/** Print a file's Short File Name.
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
|
|
@ -731,10 +731,6 @@ class FatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool remove(const char* path);
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind() {
|
||||
seekSet(0);
|
||||
}
|
||||
/** Rename a file or subdirectory.
|
||||
* \note the renamed file will be moved to the current volume working
|
||||
* directory.
|
||||
|
|
@ -752,6 +748,10 @@ class FatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool rename(FatFile* dirFile, const char* newPath);
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind() {
|
||||
seekSet(0);
|
||||
}
|
||||
/** Remove a directory file.
|
||||
*
|
||||
* The directory file will be removed only if it is empty and is not the
|
||||
|
|
@ -802,14 +802,12 @@ class FatFile {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool seekSet(uint32_t pos);
|
||||
|
||||
/** The sync() call causes all modified data and directory fields
|
||||
* to be written to the storage device.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool sync();
|
||||
|
||||
/** Set a file's timestamps in its directory entry.
|
||||
*
|
||||
* \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
|
||||
|
|
@ -862,7 +860,6 @@ class FatFile {
|
|||
bool truncate(uint32_t length) {
|
||||
return seekSet(length) && truncate();
|
||||
}
|
||||
|
||||
/** Write a string to a file. Used by the Arduino Print class.
|
||||
* \param[in] str Pointer to the string.
|
||||
* Use getWriteError to check for errors.
|
||||
|
|
@ -980,9 +977,9 @@ class FatFile {
|
|||
static const uint8_t WRITE_ERROR = 0X1;
|
||||
static const uint8_t READ_ERROR = 0X2;
|
||||
|
||||
uint8_t m_attributes; // File attributes
|
||||
uint8_t m_error; // Error bits.
|
||||
uint8_t m_flags; // See above for definition of m_flags bits
|
||||
uint8_t m_attributes = FILE_ATTR_CLOSED;
|
||||
uint8_t m_error = 0; // Error bits.
|
||||
uint8_t m_flags = 0; // See above for definition of m_flags bits
|
||||
uint8_t m_lfnOrd;
|
||||
uint16_t m_dirIndex; // index of directory entry in dir file
|
||||
FatVolume* m_vol; // volume where file is located
|
||||
|
|
|
|||
|
|
@ -70,23 +70,22 @@ static uint16_t lfnGetChar(DirLfn_t* ldir, uint8_t i) {
|
|||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool lfnGetName(DirLfn_t* ldir, char* name, size_t n) {
|
||||
static size_t lfnGetName(DirLfn_t* ldir, char* name, size_t n) {
|
||||
uint8_t i;
|
||||
size_t k = 13*((ldir->order & 0X1F) - 1);
|
||||
for (i = 0; i < 13; i++) {
|
||||
uint16_t c = lfnGetChar(ldir, i);
|
||||
if (c == 0 || k >= n) {
|
||||
if (c == 0 || k >= (n - 1)) {
|
||||
break;
|
||||
}
|
||||
name[k++] = c >= 0X7F ? '?' : c;
|
||||
}
|
||||
// Terminate with zero byte if name fits.
|
||||
if (k < n && (ldir->order & FAT_ORDER_LAST_LONG_ENTRY)) {
|
||||
name[k] = 0;
|
||||
// Terminate with zero byte.
|
||||
if (k >= n) {
|
||||
k = n - 1;
|
||||
}
|
||||
// Truncate if name is too long.
|
||||
name[n - 1] = 0;
|
||||
return true;
|
||||
name[k] = '\0';
|
||||
return k;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline bool lfnLegalChar(uint8_t c) {
|
||||
|
|
@ -122,7 +121,8 @@ static void lfnPutName(DirLfn_t* ldir, const char* name, size_t n) {
|
|||
}
|
||||
}
|
||||
//==============================================================================
|
||||
bool FatFile::getName(char* name, size_t size) {
|
||||
size_t FatFile::getName(char* name, size_t size) {
|
||||
size_t n = 0;
|
||||
FatFile dirFile;
|
||||
DirLfn_t* ldir;
|
||||
if (!isOpen() || size < 13) {
|
||||
|
|
@ -154,20 +154,21 @@ bool FatFile::getName(char* name, size_t size) {
|
|||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
if (!lfnGetName(ldir, name, size)) {
|
||||
n = lfnGetName(ldir, name, size);
|
||||
if (n == 0) {
|
||||
DBG_FAIL_MACRO;
|
||||
goto fail;
|
||||
}
|
||||
if (ldir->order & FAT_ORDER_LAST_LONG_ENTRY) {
|
||||
return true;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
// Fall into fail.
|
||||
DBG_FAIL_MACRO;
|
||||
|
||||
fail:
|
||||
name[0] = 0;
|
||||
return false;
|
||||
name[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::openCluster(FatFile* file) {
|
||||
|
|
@ -643,7 +644,7 @@ bool FatFile::remove() {
|
|||
//------------------------------------------------------------------------------
|
||||
bool FatFile::lfnUniqueSfn(fname_t* fname) {
|
||||
const uint8_t FIRST_HASH_SEQ = 2; // min value is 2
|
||||
uint8_t pos = fname->seqPos;;
|
||||
uint8_t pos = fname->seqPos;
|
||||
DirFat_t* dir;
|
||||
uint16_t hex;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include "FatFile.h"
|
||||
#include "FatVolume.h"
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::getSFN(char* name) {
|
||||
size_t FatFile::getSFN(char* name) {
|
||||
uint8_t j = 0;
|
||||
uint8_t lcBit = FAT_CASE_LC_BASE;
|
||||
DirFat_t* dir;
|
||||
|
|
@ -40,7 +40,7 @@ bool FatFile::getSFN(char* name) {
|
|||
if (isRoot()) {
|
||||
name[0] = '/';
|
||||
name[1] = '\0';
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
// cache entry
|
||||
dir = reinterpret_cast<DirFat_t*>(cacheDirEntry(FsCache::CACHE_FOR_READ));
|
||||
|
|
@ -64,11 +64,12 @@ bool FatFile::getSFN(char* name) {
|
|||
}
|
||||
name[j++] = c;
|
||||
}
|
||||
name[j] = 0;
|
||||
return true;
|
||||
name[j] = '\0';
|
||||
return j;
|
||||
|
||||
fail:
|
||||
return false;
|
||||
name[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
size_t FatFile::printSFN(print_t* pr) {
|
||||
|
|
@ -84,7 +85,7 @@ size_t FatFile::printSFN(print_t* pr) {
|
|||
}
|
||||
#if !USE_LONG_FILE_NAMES
|
||||
//------------------------------------------------------------------------------
|
||||
bool FatFile::getName(char* name, size_t size) {
|
||||
size_t FatFile::getName(char* name, size_t size) {
|
||||
return size < 13 ? 0 : getSFN(name);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -67,26 +67,26 @@ class FatPartition {
|
|||
public:
|
||||
/** Create an instance of FatPartition
|
||||
*/
|
||||
FatPartition() : m_fatType(0) {}
|
||||
FatPartition() {}
|
||||
|
||||
/** \return The shift count required to multiply by bytesPerCluster. */
|
||||
uint8_t bytesPerClusterShift() {
|
||||
uint8_t bytesPerClusterShift() const {
|
||||
return m_sectorsPerClusterShift + m_bytesPerSectorShift;
|
||||
}
|
||||
/** \return Number of bytes in a cluster. */
|
||||
uint16_t bytesPerCluster() {
|
||||
uint16_t bytesPerCluster() const {
|
||||
return m_bytesPerSector << m_sectorsPerClusterShift;
|
||||
}
|
||||
/** \return Number of bytes per sector. */
|
||||
uint16_t bytesPerSector() {
|
||||
uint16_t bytesPerSector() const {
|
||||
return m_bytesPerSector;
|
||||
}
|
||||
/** \return The shift count required to multiply by bytesPerCluster. */
|
||||
uint8_t bytesPerSectorShift() {
|
||||
uint8_t bytesPerSectorShift() const {
|
||||
return m_bytesPerSectorShift;
|
||||
}
|
||||
/** \return Mask for sector offset. */
|
||||
uint16_t sectorMask() {
|
||||
uint16_t sectorMask() const {
|
||||
return m_sectorMask;
|
||||
}
|
||||
/** \return The volume's cluster size in sectors. */
|
||||
|
|
@ -120,7 +120,7 @@ class FatPartition {
|
|||
return m_dataStartSector;
|
||||
}
|
||||
/** \return The number of File Allocation Tables. */
|
||||
uint8_t fatCount() {
|
||||
uint8_t fatCount() const {
|
||||
return 2;
|
||||
}
|
||||
/** \return The logical sector number for the start of the first FAT. */
|
||||
|
|
@ -195,7 +195,7 @@ class FatPartition {
|
|||
uint8_t m_sectorsPerCluster; // Cluster size in sectors.
|
||||
uint8_t m_clusterSectorMask; // Mask to extract sector of cluster.
|
||||
uint8_t m_sectorsPerClusterShift; // Cluster count to sector count shift.
|
||||
uint8_t m_fatType; // Volume type (12, 16, OR 32).
|
||||
uint8_t m_fatType = 0; // Volume type (12, 16, OR 32).
|
||||
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
|
||||
uint32_t m_allocSearchStart; // Start cluster for alloc search.
|
||||
uint32_t m_sectorsPerFat; // FAT size in sectors
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class FatVolume : public FatPartition {
|
|||
if (!chdir()) {
|
||||
return false;
|
||||
}
|
||||
if (setCwv) {
|
||||
if (setCwv || !m_cwv) {
|
||||
m_cwv = this;
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ bool FsBaseFile::open(FsVolume* vol, const char* path, oflag_t oflag) {
|
|||
return true;
|
||||
}
|
||||
m_fFile = nullptr;
|
||||
return false;
|
||||
} else if (vol->m_xVol) {
|
||||
m_xFile = new (m_fileMem) ExFatFile;
|
||||
if (m_xFile && m_xFile->open(vol->m_xVol, path, oflag)) {
|
||||
|
|
@ -155,6 +154,27 @@ bool FsBaseFile::openNext(FsBaseFile* dir, oflag_t oflag) {
|
|||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FsBaseFile::openRoot(FsVolume* vol) {
|
||||
if (!vol) {
|
||||
return false;
|
||||
}
|
||||
close();
|
||||
if (vol->m_fVol) {
|
||||
m_fFile = new (m_fileMem) FatFile;
|
||||
if (m_fFile && m_fFile->openRoot(vol->m_fVol)) {
|
||||
return true;
|
||||
}
|
||||
m_fFile = nullptr;
|
||||
} else if (vol->m_xVol) {
|
||||
m_xFile = new (m_fileMem) ExFatFile;
|
||||
if (m_xFile && m_xFile->openRoot(vol->m_xVol)) {
|
||||
return true;
|
||||
}
|
||||
m_xFile = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool FsBaseFile::remove() {
|
||||
if (m_fFile) {
|
||||
if (m_fFile->remove()) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,18 @@
|
|||
*/
|
||||
class FsBaseFile {
|
||||
public:
|
||||
FsBaseFile() : m_fFile(nullptr), m_xFile(nullptr) {}
|
||||
/** Create an instance. */
|
||||
FsBaseFile() {}
|
||||
/** Create a file object and open it in the current working directory.
|
||||
*
|
||||
* \param[in] path A path for a file to be opened.
|
||||
*
|
||||
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
|
||||
* OR of open flags. see FatFile::open(FatFile*, const char*, uint8_t).
|
||||
*/
|
||||
FsBaseFile(const char* path, oflag_t oflag) {
|
||||
open(path, oflag);
|
||||
}
|
||||
|
||||
~FsBaseFile() {close();}
|
||||
/** Copy constructor.
|
||||
|
|
@ -58,11 +69,17 @@ class FsBaseFile {
|
|||
/** \return number of bytes available from the current position to EOF
|
||||
* or INT_MAX if more than INT_MAX bytes are available.
|
||||
*/
|
||||
int available() {
|
||||
int available() const {
|
||||
return m_fFile ? m_fFile->available() :
|
||||
m_xFile ? m_xFile->available() : 0;
|
||||
}
|
||||
|
||||
/** \return The number of bytes available from the current position
|
||||
* to EOF for normal files. Zero is returned for directory files.
|
||||
*/
|
||||
uint64_t available64() const {
|
||||
return m_fFile ? m_fFile->available32() :
|
||||
m_xFile ? m_xFile->available64() : 0;
|
||||
}
|
||||
/** Clear writeError. */
|
||||
void clearWriteError() {
|
||||
if (m_fFile) m_fFile->clearWriteError();
|
||||
|
|
@ -186,7 +203,7 @@ class FsBaseFile {
|
|||
m_xFile ? m_xFile->getCreateDateTime(pdate, ptime) : false;
|
||||
}
|
||||
/** \return All error bits. */
|
||||
uint8_t getError() {
|
||||
uint8_t getError() const {
|
||||
return m_fFile ? m_fFile->getError() :
|
||||
m_xFile ? m_xFile->getError() : 0XFF;
|
||||
}
|
||||
|
|
@ -248,6 +265,11 @@ class FsBaseFile {
|
|||
* \return true if the file is a directory.
|
||||
*/
|
||||
bool isDirectory() const {return isDir();}
|
||||
/** \return True if this is a normal file. */
|
||||
bool isFile() const {
|
||||
return m_fFile ? m_fFile->isFile() :
|
||||
m_xFile ? m_xFile->isFile() : false;
|
||||
}
|
||||
/** \return True if this is a hidden file else false. */
|
||||
bool isHidden() const {
|
||||
return m_fFile ? m_fFile->isHidden() :
|
||||
|
|
@ -255,11 +277,26 @@ class FsBaseFile {
|
|||
}
|
||||
/** \return True if this is an open file/directory else false. */
|
||||
bool isOpen() const {return m_fFile || m_xFile;}
|
||||
/** \return True file is readable. */
|
||||
bool isReadable() const {
|
||||
return m_fFile ? m_fFile->isReadable() :
|
||||
m_xFile ? m_xFile->isReadable() : false;
|
||||
}
|
||||
/** \return True if file is read-only */
|
||||
bool isReadOnly() const {
|
||||
return m_fFile ? m_fFile->isReadOnly() :
|
||||
m_xFile ? m_xFile->isReadOnly() : false;
|
||||
}
|
||||
/** \return True if this is a subdirectory file else false. */
|
||||
bool isSubDir() const {
|
||||
return m_fFile ? m_fFile->isSubDir() :
|
||||
m_xFile ? m_xFile->isSubDir() : false;
|
||||
}
|
||||
/** \return True file is writable. */
|
||||
bool isWritable() const {
|
||||
return m_fFile ? m_fFile->isWritable() :
|
||||
m_xFile ? m_xFile->isWritable() : false;
|
||||
}
|
||||
#if ENABLE_ARDUINO_SERIAL
|
||||
/** List directory contents.
|
||||
*
|
||||
|
|
@ -412,6 +449,15 @@ class FsBaseFile {
|
|||
* \return a file object.
|
||||
*/
|
||||
bool openNext(FsBaseFile* dir, oflag_t oflag = O_RDONLY);
|
||||
/** Open a volume's root directory.
|
||||
*
|
||||
* \param[in] vol The SdFs volume containing the root directory to be opened.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool openRoot(FsVolume* vol);
|
||||
/** \return the current file position. */
|
||||
uint64_t position() const {return curPosition();}
|
||||
/** Return the next available byte without consuming it.
|
||||
*
|
||||
* \return The byte if no error and not at eof else -1;
|
||||
|
|
@ -420,6 +466,21 @@ class FsBaseFile {
|
|||
return m_fFile ? m_fFile->peek() :
|
||||
m_xFile ? m_xFile->peek() : -1;
|
||||
}
|
||||
/** Allocate contiguous clusters to an empty file.
|
||||
*
|
||||
* The file must be empty with no clusters allocated.
|
||||
*
|
||||
* The file will contain uninitialized data for FAT16/FAT32 files.
|
||||
* exFAT files will have zero validLength and dataLength will equal
|
||||
* the requested length.
|
||||
*
|
||||
* \param[in] length size of the file in bytes.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool preAllocate(uint64_t length) {
|
||||
return m_fFile ? length < (1ULL << 32) && m_fFile->preAllocate(length) :
|
||||
m_xFile ? m_xFile->preAllocate(length) : false;
|
||||
}
|
||||
/** Print a file's access date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
|
|
@ -440,55 +501,7 @@ class FsBaseFile {
|
|||
return m_fFile ? m_fFile->printCreateDateTime(pr) :
|
||||
m_xFile ? m_xFile->printCreateDateTime(pr) : 0;
|
||||
}
|
||||
/** Print a file's modify date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printModifyDateTime(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printModifyDateTime(pr) :
|
||||
m_xFile ? m_xFile->printModifyDateTime(pr) : 0;
|
||||
}
|
||||
/** Print a file's name
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printName(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printName(pr) :
|
||||
m_xFile ? m_xFile->printName(pr) : 0;
|
||||
}
|
||||
/** Print a file's size.
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return The number of characters printed is returned
|
||||
* for success and zero is returned for failure.
|
||||
*/
|
||||
size_t printFileSize(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printFileSize(pr) :
|
||||
m_xFile ? m_xFile->printFileSize(pr) : 0;
|
||||
}
|
||||
/** Allocate contiguous clusters to an empty file.
|
||||
*
|
||||
* The file must be empty with no clusters allocated.
|
||||
*
|
||||
* The file will contain uninitialized data for FAT16/FAT32 files.
|
||||
* exFAT files will have zero validLength and dataLength will equal
|
||||
* the requested length.
|
||||
*
|
||||
* \param[in] length size of the file in bytes.
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool preAllocate(uint64_t length) {
|
||||
return m_fFile ? length < (1ULL << 32) && m_fFile->preAllocate(length) :
|
||||
m_xFile ? m_xFile->preAllocate(length) : false;
|
||||
}
|
||||
/** \return the current file position. */
|
||||
uint64_t position() const {return curPosition();}
|
||||
/** Print a number followed by a field terminator.
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
* \param[in] prec Number of digits after decimal point.
|
||||
|
|
@ -517,6 +530,37 @@ class FsBaseFile {
|
|||
return m_fFile ? m_fFile->printField(value, term) :
|
||||
m_xFile ? m_xFile->printField(value, term) : 0;
|
||||
}
|
||||
/** Print a file's size.
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return The number of characters printed is returned
|
||||
* for success and zero is returned for failure.
|
||||
*/
|
||||
size_t printFileSize(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printFileSize(pr) :
|
||||
m_xFile ? m_xFile->printFileSize(pr) : 0;
|
||||
}
|
||||
/** Print a file's modify date and time
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printModifyDateTime(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printModifyDateTime(pr) :
|
||||
m_xFile ? m_xFile->printModifyDateTime(pr) : 0;
|
||||
}
|
||||
/** Print a file's name
|
||||
*
|
||||
* \param[in] pr Print stream for output.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
size_t printName(print_t* pr) {
|
||||
return m_fFile ? m_fFile->printName(pr) :
|
||||
m_xFile ? m_xFile->printName(pr) : 0;
|
||||
}
|
||||
/** Read the next byte from a file.
|
||||
*
|
||||
* \return For success return the next byte in the file as an int.
|
||||
|
|
@ -698,7 +742,6 @@ class FsBaseFile {
|
|||
m_xFile->timestamp(flags, year, month, day, hour, minute, second) :
|
||||
false;
|
||||
}
|
||||
|
||||
/** Truncate a file to the current position.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
|
|
@ -746,8 +789,8 @@ class FsBaseFile {
|
|||
|
||||
private:
|
||||
newalign_t m_fileMem[FS_ALIGN_DIM(ExFatFile, FatFile)];
|
||||
FatFile* m_fFile;
|
||||
ExFatFile* m_xFile;
|
||||
FatFile* m_fFile = nullptr;
|
||||
ExFatFile* m_xFile = nullptr;
|
||||
};
|
||||
/**
|
||||
* \class FsFile
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class FsFile;
|
|||
*/
|
||||
class FsVolume {
|
||||
public:
|
||||
FsVolume() : m_fVol(nullptr), m_xVol(nullptr) {}
|
||||
FsVolume() {}
|
||||
|
||||
~FsVolume() {end();}
|
||||
|
||||
|
|
@ -49,42 +49,15 @@ class FsVolume {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool begin(BlockDevice* blockDev);
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
// Use sectorsPerCluster(). blocksPerCluster() will be removed in the future.
|
||||
uint32_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/** \return the number of bytes in a cluster. */
|
||||
uint32_t bytesPerCluster() const {
|
||||
return m_fVol ? m_fVol->bytesPerCluster() :
|
||||
m_xVol ? m_xVol->bytesPerCluster() : 0;
|
||||
}
|
||||
/** Change global working volume to this volume. */
|
||||
void chvol() {m_cwv = this;}
|
||||
/** \return The total number of clusters in the volume. */
|
||||
uint32_t clusterCount() const {
|
||||
return m_fVol ? m_fVol->clusterCount() :
|
||||
m_xVol ? m_xVol->clusterCount() : 0;
|
||||
}
|
||||
/** \return The logical sector number for the start of file data. */
|
||||
uint32_t dataStartSector() const {
|
||||
return m_fVol ? m_fVol->dataStartSector() :
|
||||
m_xVol ? m_xVol->clusterHeapStartSector() : 0;
|
||||
}
|
||||
/** \return The logical sector number for the start of the first FAT. */
|
||||
uint32_t fatStartSector() const {
|
||||
return m_fVol ? m_fVol->fatStartSector() :
|
||||
m_xVol ? m_xVol->fatStartSector() : 0;
|
||||
}
|
||||
/** \return the free cluster count. */
|
||||
uint32_t freeClusterCount() const {
|
||||
return m_fVol ? m_fVol->freeClusterCount() :
|
||||
m_xVol ? m_xVol->freeClusterCount() : 0;
|
||||
}
|
||||
/** \return The volume's cluster size in sectors. */
|
||||
uint32_t sectorsPerCluster() const {
|
||||
return m_fVol ? m_fVol->sectorsPerCluster() :
|
||||
m_xVol ? m_xVol->sectorsPerCluster() : 0;
|
||||
}
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
// Use sectorsPerCluster(). blocksPerCluster() will be removed in the future.
|
||||
uint32_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/**
|
||||
* Set volume working directory to root.
|
||||
* \return true for success or false for failure.
|
||||
|
|
@ -102,6 +75,18 @@ class FsVolume {
|
|||
return m_fVol ? m_fVol->chdir(path) :
|
||||
m_xVol ? m_xVol->chdir(path) : false;
|
||||
}
|
||||
/** Change global working volume to this volume. */
|
||||
void chvol() {m_cwv = this;}
|
||||
/** \return The total number of clusters in the volume. */
|
||||
uint32_t clusterCount() const {
|
||||
return m_fVol ? m_fVol->clusterCount() :
|
||||
m_xVol ? m_xVol->clusterCount() : 0;
|
||||
}
|
||||
/** \return The logical sector number for the start of file data. */
|
||||
uint32_t dataStartSector() const {
|
||||
return m_fVol ? m_fVol->dataStartSector() :
|
||||
m_xVol ? m_xVol->clusterHeapStartSector() : 0;
|
||||
}
|
||||
/** free dynamic memory and end access to volume */
|
||||
void end() {
|
||||
m_fVol = nullptr;
|
||||
|
|
@ -117,6 +102,11 @@ class FsVolume {
|
|||
return m_fVol ? m_fVol->exists(path) :
|
||||
m_xVol ? m_xVol->exists(path) : false;
|
||||
}
|
||||
/** \return The logical sector number for the start of the first FAT. */
|
||||
uint32_t fatStartSector() const {
|
||||
return m_fVol ? m_fVol->fatStartSector() :
|
||||
m_xVol ? m_xVol->fatStartSector() : 0;
|
||||
}
|
||||
/** \return Partition type, FAT_TYPE_EXFAT, FAT_TYPE_FAT32,
|
||||
* FAT_TYPE_FAT16, or zero for error.
|
||||
*/
|
||||
|
|
@ -124,6 +114,20 @@ class FsVolume {
|
|||
return m_fVol ? m_fVol->fatType() :
|
||||
m_xVol ? m_xVol->fatType() : 0;
|
||||
}
|
||||
/** \return the free cluster count. */
|
||||
uint32_t freeClusterCount() const {
|
||||
return m_fVol ? m_fVol->freeClusterCount() :
|
||||
m_xVol ? m_xVol->freeClusterCount() : 0;
|
||||
}
|
||||
/**
|
||||
* Check for BlockDevice busy.
|
||||
*
|
||||
* \return true if busy else false.
|
||||
*/
|
||||
bool isBusy() {
|
||||
return m_fVol ? m_fVol->isBusy() :
|
||||
m_xVol ? m_xVol->isBusy() : false;
|
||||
}
|
||||
/** List directory contents.
|
||||
*
|
||||
* \param[in] pr Print object.
|
||||
|
|
@ -227,6 +231,11 @@ class FsVolume {
|
|||
return m_fVol ? m_fVol->rmdir(path) :
|
||||
m_xVol ? m_xVol->rmdir(path) : false;
|
||||
}
|
||||
/** \return The volume's cluster size in sectors. */
|
||||
uint32_t sectorsPerCluster() const {
|
||||
return m_fVol ? m_fVol->sectorsPerCluster() :
|
||||
m_xVol ? m_xVol->sectorsPerCluster() : 0;
|
||||
}
|
||||
#if ENABLE_ARDUINO_SERIAL
|
||||
/** List directory contents.
|
||||
* \return true for success or false for failure.
|
||||
|
|
@ -369,8 +378,8 @@ class FsVolume {
|
|||
FsVolume& operator=(const FsVolume& from);
|
||||
|
||||
static FsVolume* m_cwv;
|
||||
FatVolume* m_fVol;
|
||||
ExFatVolume* m_xVol;
|
||||
FatVolume* m_fVol = nullptr;
|
||||
ExFatVolume* m_xVol = nullptr;
|
||||
BlockDevice* m_blockDev;
|
||||
};
|
||||
#endif // FsVolume_h
|
||||
|
|
|
|||
358
src/RingBuf.h
Normal file
358
src/RingBuf.h
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
/**
|
||||
* Copyright (c) 2011-2020 Bill Greiman
|
||||
* This file is part of the SdFat library for SD memory cards.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef RingBuf_h
|
||||
#define RingBuf_h
|
||||
/**
|
||||
* \file
|
||||
* \brief Ring buffer for data loggers.
|
||||
*/
|
||||
#include "Arduino.h"
|
||||
#include "common/FmtNumber.h"
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
// Teensy 3.5/3.6 has hard fault at 0x20000000 for unaligned memcpy.
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
inline bool is_aligned(const void* ptr, uintptr_t alignment) {
|
||||
auto iptr = reinterpret_cast<uintptr_t>(ptr);
|
||||
return !(iptr % alignment);
|
||||
}
|
||||
inline void memcpyBuf(void* dst, const void* src, size_t len) {
|
||||
const uint8_t* b = reinterpret_cast<const uint8_t*>(0X20000000UL);
|
||||
uint8_t* d = reinterpret_cast<uint8_t*>(dst);
|
||||
const uint8_t *s = reinterpret_cast<const uint8_t*>(src);
|
||||
if ((is_aligned(d, 4) && is_aligned(s, 4) && (len & 3) == 0) ||
|
||||
!((d < b && b <= (d + len)) || (s < b && b <= (s + len)))) {
|
||||
memcpy(dst, src, len);
|
||||
} else {
|
||||
while (len--) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
inline void memcpyBuf(void* dst, const void* src, size_t len) {
|
||||
memcpy(dst, src, len);
|
||||
}
|
||||
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
/**
|
||||
* \class RingBuf
|
||||
* \brief Ring buffer for data loggers.
|
||||
*
|
||||
* This ring buffer may be used in ISRs. bytesFreeIsr(), bytesUsedIsr(),
|
||||
* memcopyIn(), and memcopyOut() are ISR callable. For ISR use call
|
||||
* memcopyIn() in the ISR and use writeOut() in non-interrupt code
|
||||
* to write data to a file. readIn() and memcopyOut can be use in a
|
||||
* similar way to provide file data to an ISR.
|
||||
*
|
||||
* Print into a RingBuf in an ISR should also work but has not been verified.
|
||||
*/
|
||||
template<class F, size_t Size>
|
||||
class RingBuf : public Print {
|
||||
public:
|
||||
/**
|
||||
* RingBuf Constructor.
|
||||
*/
|
||||
RingBuf() {}
|
||||
/**
|
||||
* Initialize RingBuf.
|
||||
* \param[in] file Underlying file.
|
||||
*/
|
||||
void begin(F* file) {
|
||||
m_file = file;
|
||||
m_count = 0;
|
||||
m_head = 0;
|
||||
m_tail = 0;
|
||||
clearWriteError();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* \return the RingBuf free space in bytes. Not ISR callable.
|
||||
*/
|
||||
size_t bytesFree() const {
|
||||
size_t count;
|
||||
noInterrupts();
|
||||
count = m_count;
|
||||
interrupts();
|
||||
return Size - count;
|
||||
}
|
||||
/**
|
||||
* \return the RingBuf free space in bytes. ISR callable.
|
||||
*/
|
||||
size_t bytesFreeIsr() const {
|
||||
return Size - m_count;
|
||||
}
|
||||
/**
|
||||
* \return the RingBuf used space in bytes. Not ISR callable.
|
||||
*/
|
||||
size_t bytesUsed() const {
|
||||
size_t count;
|
||||
noInterrupts();
|
||||
count = m_count;
|
||||
interrupts();
|
||||
return count;
|
||||
}
|
||||
/**
|
||||
* \return the RingBuf used space in bytes. ISR callable.
|
||||
*/
|
||||
size_t bytesUsedIsr() const {
|
||||
return m_count;
|
||||
}
|
||||
/**
|
||||
* Copy data to the RingBuf from buf.
|
||||
* The number of bytes copied may be less than count if
|
||||
* count is greater than bytesFree.
|
||||
*
|
||||
* This function may be used in an ISR with writeOut()
|
||||
* in non-interrupt code.
|
||||
*
|
||||
* \param[in] buf Location of data to be copied.
|
||||
* \param[in] count number of bytes to be copied.
|
||||
* \return Number of bytes actually copied.
|
||||
*/
|
||||
size_t memcpyIn(const void* buf, size_t count) {
|
||||
const uint8_t* src = (const uint8_t*)buf;
|
||||
size_t n = Size - m_count;
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
size_t nread = 0;
|
||||
while (nread != count) {
|
||||
n = minSize(Size - m_head, count - nread);
|
||||
memcpyBuf(m_buf + m_head, src + nread, n);
|
||||
m_head = advance(m_head, n);
|
||||
nread += n;
|
||||
}
|
||||
m_count += nread;
|
||||
return nread;
|
||||
}
|
||||
/**
|
||||
* Copy date from the RingBuf to buf.
|
||||
* The number of bytes copied may be less than count if
|
||||
* bytesUsed is less than count.
|
||||
*
|
||||
* This function may be used in an ISR with readIn() in
|
||||
* non-interrupt code.
|
||||
*
|
||||
* \param[out] buf Location to receive the data.
|
||||
* \param[in] count number of bytes to be copied.
|
||||
* \return Number of bytes actually copied.
|
||||
*/
|
||||
size_t memcpyOut(void* buf, size_t count) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||
size_t nwrite = 0;
|
||||
size_t n = m_count;
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
while (nwrite != count) {
|
||||
n = minSize(Size - m_tail, count - nwrite);
|
||||
memcpyBuf(dst + nwrite, m_buf + m_tail, n);
|
||||
m_tail = advance(m_tail, n);
|
||||
nwrite += n;
|
||||
}
|
||||
m_count -= nwrite;
|
||||
return nwrite;
|
||||
}
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
* \param[in] prec Number of digits after decimal point.
|
||||
* \return The number of bytes written.
|
||||
*/
|
||||
size_t printField(double value, char term, uint8_t prec = 2) {
|
||||
char buf[24];
|
||||
char* str = buf + sizeof(buf);
|
||||
if (term) {
|
||||
*--str = term;
|
||||
if (term == '\n') {
|
||||
*--str = '\r';
|
||||
}
|
||||
}
|
||||
str = fmtDouble(str, value, prec, false);
|
||||
return write(str, buf + sizeof(buf) - str);
|
||||
}
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
* \param[in] prec Number of digits after decimal point.
|
||||
* \return The number of bytes written or -1 if an error occurs.
|
||||
*/
|
||||
size_t printField(float value, char term, uint8_t prec = 2) {
|
||||
return printField(static_cast<double>(value), term, prec);
|
||||
}
|
||||
/** Print a number followed by a field terminator.
|
||||
* \param[in] value The number to be printed.
|
||||
* \param[in] term The field terminator. Use '\\n' for CR LF.
|
||||
* \return The number of bytes written or -1 if an error occurs.
|
||||
*/
|
||||
template <typename Type>
|
||||
size_t printField(Type value, char term) {
|
||||
char sign = 0;
|
||||
char buf[3*sizeof(Type) + 3];
|
||||
char* str = buf + sizeof(buf);
|
||||
|
||||
if (term) {
|
||||
*--str = term;
|
||||
if (term == '\n') {
|
||||
*--str = '\r';
|
||||
}
|
||||
}
|
||||
if (value < 0) {
|
||||
value = -value;
|
||||
sign = '-';
|
||||
}
|
||||
if (sizeof(Type) < 4) {
|
||||
str = fmtBase10(str, (uint16_t)value);
|
||||
} else {
|
||||
str = fmtBase10(str, (uint32_t)value);
|
||||
}
|
||||
if (sign) {
|
||||
*--str = sign;
|
||||
}
|
||||
return write((const uint8_t*)str, &buf[sizeof(buf)] - str);
|
||||
}
|
||||
/**
|
||||
* Read data into the RingBuf from the underlying file.
|
||||
* the number of bytes read may be less than count if
|
||||
* bytesFree is less than count.
|
||||
*
|
||||
* This function may be used in non-interrupt code with
|
||||
* memcopyOut() in an ISR.
|
||||
*
|
||||
* \param[in] count number of bytes to be read.
|
||||
* \return Number of bytes actually read.
|
||||
*/
|
||||
size_t readIn(size_t count) {
|
||||
size_t nread = 0;
|
||||
size_t n = bytesFree(); // Protected from interrupts.
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
while (nread != count) {
|
||||
n = minSize(Size - m_head, count - nread);
|
||||
if ((size_t)m_file->read(m_buf + m_head, n) != n) {
|
||||
return nread;
|
||||
}
|
||||
m_head = advance(m_head, n);
|
||||
nread += n;
|
||||
}
|
||||
noInterrupts();
|
||||
m_count += nread;
|
||||
interrupts();
|
||||
return nread;
|
||||
}
|
||||
/**
|
||||
* Write all data in the RingBuf to the underlying file.
|
||||
* \param[in] data Byte to be written.
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
bool sync() {
|
||||
size_t n = bytesUsed();
|
||||
return writeOut(n) == n;
|
||||
}
|
||||
/**
|
||||
* Copy data to the RingBuf from buf.
|
||||
*
|
||||
* The number of bytes copied may be less than count if
|
||||
* count is greater than bytesFree.
|
||||
* Use getWriteError() to check for print errors and
|
||||
* clearWriteError() to clear error.
|
||||
*
|
||||
* \param[in] buf Location of data to be written.
|
||||
* \param[in] count number of bytes to be written.
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
size_t write(const void* buf, size_t count) {
|
||||
if (count > bytesFree()) {
|
||||
setWriteError();
|
||||
}
|
||||
return memcpyIn(buf, count);
|
||||
}
|
||||
/**
|
||||
* Override virtual function in Print for efficiency.
|
||||
*
|
||||
* \param[in] buf Location of data to be written.
|
||||
* \param[in] count number of bytes to be written.
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
size_t write(const uint8_t* buf, size_t count) override {
|
||||
return write((const void*)buf, count);
|
||||
}
|
||||
/**
|
||||
* Required function for Print.
|
||||
* \param[in] data Byte to be written.
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
size_t write(uint8_t data) override {
|
||||
return write(&data, 1);
|
||||
}
|
||||
/**
|
||||
* Write data to file from RingBuf buffer.
|
||||
* \param[in] count number of bytes to be written.
|
||||
*
|
||||
* The number of bytes written may be less than count if
|
||||
* bytesUsed is less than count or if an error occurs.
|
||||
*
|
||||
* This function may be used in non-interrupt code with
|
||||
* memcopyIn() in an ISR.
|
||||
*
|
||||
* \return Number of bytes actually written.
|
||||
*/
|
||||
size_t writeOut(size_t count) {
|
||||
size_t n = bytesUsed(); // Protected from interrupts;
|
||||
if (count > n) {
|
||||
count = n;
|
||||
}
|
||||
size_t nwrite = 0;
|
||||
while (nwrite != count) {
|
||||
n = minSize(Size - m_tail, count - nwrite);
|
||||
if (m_file->write(m_buf + m_tail, n) != n) {
|
||||
break;
|
||||
}
|
||||
m_tail = advance(m_tail, n);
|
||||
nwrite += n;
|
||||
}
|
||||
noInterrupts();
|
||||
m_count -= nwrite;
|
||||
interrupts();
|
||||
return nwrite;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t __attribute__((aligned(4))) m_buf[Size];
|
||||
F* m_file = nullptr;
|
||||
volatile size_t m_count;
|
||||
size_t m_head;
|
||||
size_t m_tail;
|
||||
|
||||
size_t advance(size_t index, size_t n) {
|
||||
index += n;
|
||||
return index < Size ? index : index - Size;
|
||||
}
|
||||
// avoid macro MIN
|
||||
size_t minSize(size_t a, size_t b) {return a < b ? a : b;}
|
||||
};
|
||||
#endif // RingBuf_h
|
||||
|
|
@ -71,6 +71,7 @@
|
|||
SD_CARD_ERROR(READ_START, "Bad readStart argument")\
|
||||
SD_CARD_ERROR(READ_TIMEOUT, "Read data timeout")\
|
||||
SD_CARD_ERROR(STOP_TRAN, "Multiple block stop failed")\
|
||||
SD_CARD_ERROR(TRANSFER_COMPLETE, "SDIO transfer complete")\
|
||||
SD_CARD_ERROR(WRITE_DATA, "Write data not accepted")\
|
||||
SD_CARD_ERROR(WRITE_FIFO, "SDIO fifo write timeout")\
|
||||
SD_CARD_ERROR(WRITE_START, "Bad writeStart argument")\
|
||||
|
|
@ -84,7 +85,6 @@
|
|||
SD_CARD_ERROR(INVALID_CARD_CONFIG, "Invalid card config")\
|
||||
SD_CARD_ERROR(FUNCTION_NOT_SUPPORTED, "Unsupported SDIO command")
|
||||
|
||||
|
||||
enum {
|
||||
#define SD_CARD_ERROR(e, m) SD_CARD_ERROR_##e,
|
||||
SD_ERROR_CODE_LIST
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
|
|||
//------------------------------------------------------------------------------
|
||||
bool SdSpiCard::begin(SdSpiConfig spiConfig) {
|
||||
SdMillis_t t0 = SysCall::curTimeMS();
|
||||
m_spiActive = false;
|
||||
m_errorCode = SD_CARD_ERROR_NONE;
|
||||
m_type = 0;
|
||||
m_csPin = spiConfig.csPin;
|
||||
|
|
@ -238,16 +239,12 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) {
|
|||
spiBegin(spiConfig);
|
||||
uint32_t arg;
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
m_sharedSpi = !(spiConfig.options & DEDICATED_SPI);
|
||||
m_spiActive = false;
|
||||
m_curState = IDLE_STATE;
|
||||
m_sharedSpi = spiOptionShared(spiConfig.options);
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
if (spiConfig.options & DEDICATED_SPI) {
|
||||
error(SD_CARD_ERROR_INVALID_CARD_CONFIG);
|
||||
goto fail;
|
||||
}
|
||||
// m_sharedSpi is a static const bool in this case.
|
||||
static_assert(m_sharedSpi == true, "m_sharedSpi bug");
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
|
||||
spiStart();
|
||||
|
||||
// must supply min of 74 clock cycles with CS high.
|
||||
|
|
@ -333,6 +330,11 @@ bool SdSpiCard::begin(SdSpiConfig spiConfig) {
|
|||
//------------------------------------------------------------------------------
|
||||
// send command and return error code. Return zero for OK
|
||||
uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
if (m_curState != IDLE_STATE && !syncDevice()) {
|
||||
return 0XFF;
|
||||
}
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
// select card
|
||||
if (!m_spiActive) {
|
||||
spiStart();
|
||||
|
|
@ -430,6 +432,11 @@ bool SdSpiCard::eraseSingleSectorEnable() {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdSpiCard::isBusy() {
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
if (m_curState == READ_STATE) {
|
||||
return false;
|
||||
}
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
bool rtn = true;
|
||||
bool spiActive = m_spiActive;
|
||||
if (!spiActive) {
|
||||
|
|
@ -508,7 +515,6 @@ bool SdSpiCard::readData(uint8_t* dst, size_t count) {
|
|||
//------------------------------------------------------------------------------
|
||||
bool SdSpiCard::readOCR(uint32_t* ocr) {
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(ocr);
|
||||
syncDevice();
|
||||
if (cardCommand(CMD58, 0)) {
|
||||
error(SD_CARD_ERROR_CMD58);
|
||||
goto fail;
|
||||
|
|
@ -527,7 +533,6 @@ bool SdSpiCard::readOCR(uint32_t* ocr) {
|
|||
/** read CID or CSR register */
|
||||
bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||
syncDevice();
|
||||
if (cardCommand(cmd, 0)) {
|
||||
error(SD_CARD_ERROR_READ_REG);
|
||||
goto fail;
|
||||
|
|
@ -599,33 +604,32 @@ bool SdSpiCard::readStatus(uint8_t* status) {
|
|||
bool SdSpiCard::readSectors(uint32_t sector, uint8_t* dst, size_t ns) {
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
if (m_curState != READ_STATE || sector != m_curSector) {
|
||||
if (!syncDevice()) {
|
||||
return false;
|
||||
}
|
||||
if (!SdSpiCard::readStart(sector)) {
|
||||
return false;
|
||||
if (!readStart(sector)) {
|
||||
goto fail;
|
||||
}
|
||||
m_curSector = sector;
|
||||
m_curState = READ_STATE;
|
||||
}
|
||||
for (size_t i = 0; i < ns; i++, dst += 512) {
|
||||
if (!readData(dst, 512)) {
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
m_curSector += ns;
|
||||
return m_sharedSpi ? syncDevice() : true;
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
if (!readStart(sector)) {
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
for (size_t i = 0; i < ns; i++, dst += 512) {
|
||||
if (!readData(dst, 512)) {
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return readStop();
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
fail:
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdSpiCard::readStop() {
|
||||
|
|
@ -665,16 +669,15 @@ void SdSpiCard::spiStop() {
|
|||
//------------------------------------------------------------------------------
|
||||
bool SdSpiCard::syncDevice() {
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
if (m_curState == READ_STATE) {
|
||||
if (!SdSpiCard::readStop()) {
|
||||
return false;
|
||||
}
|
||||
} else if (m_curState == WRITE_STATE) {
|
||||
if (!SdSpiCard::writeStop()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Insure no recursive loop with cardCommand().
|
||||
uint8_t state = m_curState;
|
||||
m_curState = IDLE_STATE;
|
||||
if (state == WRITE_STATE) {
|
||||
return writeStop();
|
||||
}
|
||||
if (state == READ_STATE) {
|
||||
return readStop();
|
||||
}
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
return true;
|
||||
}
|
||||
|
|
@ -780,20 +783,17 @@ bool SdSpiCard::writeSingle(uint32_t sector, const uint8_t* src) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdSpiCard::writeSectors(uint32_t sector, const uint8_t* src, size_t ns) {
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
if (m_curState != WRITE_STATE || m_curSector != sector) {
|
||||
if (!syncDevice()) {
|
||||
return false;
|
||||
}
|
||||
if (!writeStart(sector)) {
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
m_curSector = sector;
|
||||
m_curState = WRITE_STATE;
|
||||
}
|
||||
for (size_t i = 0; i < ns; i++, src += 512) {
|
||||
if (!writeData(src)) {
|
||||
return false;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
m_curSector += ns;
|
||||
|
|
@ -808,11 +808,11 @@ bool SdSpiCard::writeSectors(uint32_t sector, const uint8_t* src, size_t ns) {
|
|||
}
|
||||
}
|
||||
return writeStop();
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
|
||||
fail:
|
||||
spiStop();
|
||||
return false;
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdSpiCard::writeStart(uint32_t sector) {
|
||||
|
|
@ -831,7 +831,7 @@ bool SdSpiCard::writeStart(uint32_t sector) {
|
|||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
||||
bool SdSpiCard::writeStart(uint32_t sector, uint32_t eraseCount) {
|
||||
// send pre-erase count
|
||||
if (cardAcmd(ACMD23, eraseCount)) {
|
||||
error(SD_CARD_ERROR_ACMD23);
|
||||
|
|
@ -839,9 +839,9 @@ bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
|||
}
|
||||
// use address if not SDHC card
|
||||
if (type() != SD_CARD_TYPE_SDHC) {
|
||||
blockNumber <<= 9;
|
||||
sector <<= 9;
|
||||
}
|
||||
if (cardCommand(CMD25, blockNumber)) {
|
||||
if (cardCommand(CMD25, sector)) {
|
||||
error(SD_CARD_ERROR_CMD25);
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class SdSpiCard {
|
|||
#endif // HAS_SDIO_CLASS
|
||||
public:
|
||||
/** Construct an instance of SdSpiCard. */
|
||||
SdSpiCard() : m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {}
|
||||
SdSpiCard() {}
|
||||
/** Initialize the SD card.
|
||||
* \param[in] spiConfig SPI card configuration.
|
||||
* \return true for success or false for failure.
|
||||
|
|
@ -214,11 +214,11 @@ class SdSpiCard {
|
|||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool writeSector(uint32_t sector, const uint8_t* src) {
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
return writeSectors(sector, src, 1);
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
return writeSingle(sector, src);
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
if (m_sharedSpi) {
|
||||
return writeSingle(sector, src);
|
||||
} else {
|
||||
return writeSectors(sector, src, 1);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Writes a 512 byte sector to an SD card.
|
||||
|
|
@ -355,12 +355,14 @@ class SdSpiCard {
|
|||
static const uint8_t WRITE_STATE = 2;
|
||||
uint32_t m_curSector;
|
||||
uint8_t m_curState;
|
||||
bool m_sharedSpi;
|
||||
bool m_sharedSpi = true;
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
static const bool m_sharedSpi = true;
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
SdCsPin_t m_csPin;
|
||||
uint8_t m_errorCode;
|
||||
uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
|
||||
bool m_spiActive;
|
||||
uint8_t m_status;
|
||||
uint8_t m_type;
|
||||
uint8_t m_type = 0;
|
||||
};
|
||||
#endif // SdSpiCard_h
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
*/
|
||||
class SdioConfig {
|
||||
public:
|
||||
SdioConfig() : m_options(FIFO_SDIO) {}
|
||||
SdioConfig() {}
|
||||
/**
|
||||
* SdioConfig constructor.
|
||||
* \param[in] opt SDIO options.
|
||||
|
|
@ -46,7 +46,7 @@ class SdioConfig {
|
|||
/** \return true if DMA_SDIO. */
|
||||
bool useDma() {return m_options & DMA_SDIO;}
|
||||
private:
|
||||
uint8_t m_options;
|
||||
uint8_t m_options = FIFO_SDIO;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
|
|
@ -64,13 +64,7 @@ class SdioCard : public SdCardInterface {
|
|||
* \return false - not implemented.
|
||||
*/
|
||||
bool end() {return false;}
|
||||
/**
|
||||
* Determine the size of an SD flash memory card.
|
||||
*
|
||||
* \return The number of 512 byte data sectors in the card
|
||||
* or zero if an error occurs.
|
||||
*/
|
||||
uint32_t sectorCount();
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
// Use sectorCount(). cardSize() will be removed in the future.
|
||||
uint32_t cardSize() __attribute__ ((deprecated)) {return sectorCount();}
|
||||
|
|
@ -180,6 +174,21 @@ class SdioCard : public SdCardInterface {
|
|||
bool readStop();
|
||||
/** \return SDIO card status. */
|
||||
uint32_t status();
|
||||
/**
|
||||
* Determine the size of an SD flash memory card.
|
||||
*
|
||||
* \return The number of 512 byte data sectors in the card
|
||||
* or zero if an error occurs.
|
||||
*/
|
||||
uint32_t sectorCount();
|
||||
/**
|
||||
* Send CMD12 to stop read or write.
|
||||
*
|
||||
* \param[in] blocking If true, wait for command complete.
|
||||
*
|
||||
* \return true for success or false for failure.
|
||||
*/
|
||||
bool stopTransmission(bool blocking);
|
||||
/** \return success if sync successful. Not for user apps. */
|
||||
bool syncDevice();
|
||||
/** Return the card type: SD V1, SD V2 or SDHC
|
||||
|
|
@ -241,6 +250,6 @@ class SdioCard : public SdCardInterface {
|
|||
static const uint8_t WRITE_STATE = 2;
|
||||
uint32_t m_curSector;
|
||||
SdioConfig m_sdioConfig;
|
||||
uint8_t m_curState;
|
||||
uint8_t m_curState = IDLE_STATE;
|
||||
};
|
||||
#endif // SdioCard_h
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@
|
|||
#include "SdioCard.h"
|
||||
//==============================================================================
|
||||
// limit of K66 due to errata KINETIS_K_0N65N.
|
||||
const uint32_t MAX_SDHC_COUNT = 0XFFFF;
|
||||
|
||||
// Max RU is 1024 sectors.
|
||||
const uint32_t RU_MASK = 0X03FF;
|
||||
const uint32_t MAX_BLKCNT = 0XFFFF;
|
||||
//==============================================================================
|
||||
#define SDHC_PROCTL_DTW_4BIT 0x01
|
||||
const uint32_t FIFO_WML = 16;
|
||||
|
|
@ -201,6 +198,9 @@ static bool (*m_busyFcn)() = 0;
|
|||
static bool m_initDone = false;
|
||||
static bool m_version2;
|
||||
static bool m_highCapacity;
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
static bool m_transferActive = false;
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
|
||||
static uint32_t m_errorLine = 0;
|
||||
static uint32_t m_rca;
|
||||
|
|
@ -216,20 +216,53 @@ static csd_t m_csd;
|
|||
#if USE_DEBUG_MODE
|
||||
#define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\
|
||||
Serial.print(" IRQSTAT "); Serial.println(SDHC_IRQSTAT, HEX);}
|
||||
|
||||
static void printRegs(uint32_t line) {
|
||||
Serial.print(line);
|
||||
Serial.print(" SDHC_BLKATTR ");
|
||||
Serial.print(SDHC_BLKATTR, HEX);
|
||||
Serial.print(" XFERTYP ");
|
||||
Serial.print(SDHC_XFERTYP, HEX);
|
||||
Serial.print(" PRSSTAT ");
|
||||
Serial.print(SDHC_PRSSTAT, HEX);
|
||||
Serial.print(" PROCTL ");
|
||||
Serial.print(SDHC_PROCTL, HEX);
|
||||
Serial.print(" IRQSTAT ");
|
||||
Serial.print(SDHC_IRQSTAT, HEX);
|
||||
Serial.print(" m_irqstat ");
|
||||
uint32_t blkattr = SDHC_BLKATTR;
|
||||
uint32_t xfertyp = SDHC_XFERTYP;
|
||||
uint32_t prsstat = SDHC_PRSSTAT;
|
||||
uint32_t proctl = SDHC_PROCTL;
|
||||
uint32_t irqstat = SDHC_IRQSTAT;
|
||||
Serial.print("\nLINE: ");
|
||||
Serial.println(line);
|
||||
Serial.print("BLKATTR ");
|
||||
Serial.println(blkattr, HEX);
|
||||
Serial.print("XFERTYP ");
|
||||
Serial.print(xfertyp, HEX);
|
||||
Serial.print(" CMD");
|
||||
Serial.print(xfertyp >> 24);
|
||||
Serial.print(" TYP");
|
||||
Serial.print((xfertyp >> 2) & 3);
|
||||
if (xfertyp & SDHC_XFERTYP_DPSEL) {Serial.print(" DPSEL");}
|
||||
Serial.println();
|
||||
Serial.print("PRSSTAT ");
|
||||
Serial.print(prsstat, HEX);
|
||||
if (prsstat & SDHC_PRSSTAT_BREN) {Serial.print(" BREN");}
|
||||
if (prsstat & SDHC_PRSSTAT_BWEN) {Serial.print(" BWEN");}
|
||||
if (prsstat & SDHC_PRSSTAT_RTA) {Serial.print(" RTA");}
|
||||
if (prsstat & SDHC_PRSSTAT_WTA) {Serial.print(" WTA");}
|
||||
if (prsstat & SDHC_PRSSTAT_SDOFF) {Serial.print(" SDOFF");}
|
||||
if (prsstat & SDHC_PRSSTAT_PEROFF) {Serial.print(" PEROFF");}
|
||||
if (prsstat & SDHC_PRSSTAT_HCKOFF) {Serial.print(" HCKOFF");}
|
||||
if (prsstat & SDHC_PRSSTAT_IPGOFF) {Serial.print(" IPGOFF");}
|
||||
if (prsstat & SDHC_PRSSTAT_SDSTB) {Serial.print(" SDSTB");}
|
||||
if (prsstat & SDHC_PRSSTAT_DLA) {Serial.print(" DLA");}
|
||||
if (prsstat & SDHC_PRSSTAT_CDIHB) {Serial.print(" CDIHB");}
|
||||
if (prsstat & SDHC_PRSSTAT_CIHB) {Serial.print(" CIHB");}
|
||||
Serial.println();
|
||||
Serial.print("PROCTL ");
|
||||
Serial.print(proctl, HEX);
|
||||
if (proctl & SDHC_PROCTL_SABGREQ) Serial.print(" SABGREQ");
|
||||
Serial.print(" EMODE");
|
||||
Serial.print((proctl >>4) & 3);
|
||||
Serial.print(" DWT");
|
||||
Serial.print((proctl >>1) & 3);
|
||||
Serial.println();
|
||||
Serial.print("IRQSTAT ");
|
||||
Serial.print(irqstat, HEX);
|
||||
if (irqstat & SDHC_IRQSTAT_BGE) {Serial.print(" BGE");}
|
||||
if (irqstat & SDHC_IRQSTAT_TC) {Serial.print(" TC");}
|
||||
if (irqstat & SDHC_IRQSTAT_CC) {Serial.print(" CC");}
|
||||
Serial.print("\nm_irqstat ");
|
||||
Serial.println(m_irqstat, HEX);
|
||||
}
|
||||
#else // USE_DEBUG_MODE
|
||||
|
|
@ -299,7 +332,7 @@ static void gpioMux(uint8_t mode) {
|
|||
static void enableGPIO(bool enable) {
|
||||
const uint32_t CLOCK_MASK = IOMUXC_SW_PAD_CTL_PAD_PKE |
|
||||
#if defined(ARDUINO_TEENSY41)
|
||||
IOMUXC_SW_PAD_CTL_PAD_DSE(1) |
|
||||
IOMUXC_SW_PAD_CTL_PAD_DSE(7) |
|
||||
#else // defined(ARDUINO_TEENSY41)
|
||||
IOMUXC_SW_PAD_CTL_PAD_DSE(4) | ///// WHG
|
||||
#endif // defined(ARDUINO_TEENSY41)
|
||||
|
|
@ -402,7 +435,7 @@ static void initSDHC() {
|
|||
|
||||
#if defined (__IMXRT1062__)
|
||||
SDHC_MIX_CTRL |= 0x80000000;
|
||||
#endif
|
||||
#endif // (__IMXRT1062__)
|
||||
|
||||
// Reset SDHC. Use default Water Mark Level of 16.
|
||||
SDHC_SYSCTL |= SDHC_SYSCTL_RSTA | SDHC_SYSCTL_SDCLKFS(0x80);
|
||||
|
|
@ -433,11 +466,7 @@ static uint32_t statusCMD13() {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyCMD13() {
|
||||
if (!cardCommand(CMD13_XFERTYP, m_rca)) {
|
||||
// Caller will timeout.
|
||||
return true;
|
||||
}
|
||||
return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA);
|
||||
return !(statusCMD13() & CARD_STATUS_READY_FOR_DATA);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyCommandComplete() {
|
||||
|
|
@ -448,6 +477,10 @@ static bool isBusyCommandInhibit() {
|
|||
return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyDat() {
|
||||
return SDHC_PRSSTAT & (1 << 24) ? false : true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool isBusyDMA() {
|
||||
return m_dmaBusy;
|
||||
}
|
||||
|
|
@ -536,20 +569,26 @@ static void setSdclk(uint32_t kHzMax) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
static bool transferStop() {
|
||||
// This fix allows CDIHB to be cleared in Tennsy 3.x without a reset.
|
||||
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
|
||||
if (!cardCommand(CMD12_XFERTYP, 0)) {
|
||||
return sdError(SD_CARD_ERROR_CMD12);
|
||||
}
|
||||
if (yieldTimeout(isBusyCMD13)) {
|
||||
// if (yieldTimeout(isBusyCMD13)) {
|
||||
if (yieldTimeout(isBusyDat)) {
|
||||
return sdError(SD_CARD_ERROR_CMD13);
|
||||
}
|
||||
// Save registers before reset DAT lines.
|
||||
uint32_t irqsststen = SDHC_IRQSTATEN;
|
||||
uint32_t proctl = SDHC_PROCTL & ~SDHC_PROCTL_SABGREQ;
|
||||
// Do reset to clear CDIHB. Should be a better way!
|
||||
SDHC_SYSCTL |= SDHC_SYSCTL_RSTD;
|
||||
// Restore registers.
|
||||
SDHC_IRQSTATEN = irqsststen;
|
||||
SDHC_PROCTL = proctl;
|
||||
if (SDHC_PRSSTAT & SDHC_PRSSTAT_CDIHB) {
|
||||
// This should not happen after above fix.
|
||||
// Save registers before reset DAT lines.
|
||||
uint32_t irqsststen = SDHC_IRQSTATEN;
|
||||
uint32_t proctl = SDHC_PROCTL & ~SDHC_PROCTL_SABGREQ;
|
||||
// Do reset to clear CDIHB. Should be a better way!
|
||||
SDHC_SYSCTL |= SDHC_SYSCTL_RSTD;
|
||||
// Restore registers.
|
||||
SDHC_IRQSTATEN = irqsststen;
|
||||
SDHC_PROCTL = proctl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -585,6 +624,22 @@ static bool waitTimeout(bool (*fcn)()) {
|
|||
}
|
||||
return false; // Caller will set errorCode.
|
||||
}
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
//------------------------------------------------------------------------------
|
||||
static bool waitTransferComplete() {
|
||||
if (!m_transferActive) {
|
||||
return true;
|
||||
}
|
||||
bool timeOut = waitTimeout(isBusyTransferComplete);
|
||||
m_transferActive = false;
|
||||
m_irqstat = SDHC_IRQSTAT;
|
||||
SDHC_IRQSTAT = m_irqstat;
|
||||
if (timeOut || (m_irqstat & SDHC_IRQSTAT_ERROR)) {
|
||||
return sdError(SD_CARD_ERROR_TRANSFER_COMPLETE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
//==============================================================================
|
||||
// Start of SdioCard member functions.
|
||||
//==============================================================================
|
||||
|
|
@ -675,6 +730,11 @@ bool SdioCard::begin(SdioConfig sdioConfig) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector) {
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
if (m_curState != IDLE_STATE && !syncDevice()) {
|
||||
return false;
|
||||
}
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
// check for single sector erase
|
||||
if (!m_csd.v1.erase_blk_en) {
|
||||
// erase size mask
|
||||
|
|
@ -716,7 +776,31 @@ uint32_t SdioCard::errorLine() const {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::isBusy() {
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
if (m_sdioConfig.useDma()) {
|
||||
return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
|
||||
} else {
|
||||
if (m_transferActive) {
|
||||
if (isBusyTransferComplete()) {
|
||||
return true;
|
||||
}
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
if ((SDHC_BLKATTR & 0XFFFF0000) != 0) {
|
||||
return false;
|
||||
}
|
||||
m_transferActive = false;
|
||||
stopTransmission(false);
|
||||
return true;
|
||||
#else // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
return false;
|
||||
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
}
|
||||
// Use DAT0 low as busy.
|
||||
return SDHC_PRSSTAT & (1 << 24) ? false : true;
|
||||
}
|
||||
#else // ENABLE_TEENSY_SDIO_MOD
|
||||
return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint32_t SdioCard::kHzSdClk() {
|
||||
|
|
@ -781,6 +865,11 @@ bool SdioCard::readSector(uint32_t sector, uint8_t* dst) {
|
|||
memcpy(dst, aligned, 512);
|
||||
}
|
||||
} else {
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
if (!waitTransferComplete()) {
|
||||
return false;
|
||||
}
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
if (m_curState != READ_STATE || sector != m_curSector) {
|
||||
if (!syncDevice()) {
|
||||
return false;
|
||||
|
|
@ -841,7 +930,7 @@ bool SdioCard::readStart(uint32_t sector) {
|
|||
SDHC_BLKATTR = SDHC_BLKATTR_BLKSIZE(512);
|
||||
#else // defined(__IMXRT1062__)
|
||||
// Errata - can't do infinite transfer.
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(0XFFFF) | SDHC_BLKATTR_BLKSIZE(512);
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(MAX_BLKCNT) | SDHC_BLKATTR_BLKSIZE(512);
|
||||
#endif // defined(__IMXRT1062__)
|
||||
|
||||
if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) {
|
||||
|
|
@ -862,7 +951,30 @@ uint32_t SdioCard::status() {
|
|||
return statusCMD13();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::stopTransmission(bool blocking) {
|
||||
m_curState = IDLE_STATE;
|
||||
// This fix allows CDIHB to be cleared in Tennsy 3.x without a reset.
|
||||
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
|
||||
if (!cardCommand(CMD12_XFERTYP, 0)) {
|
||||
return sdError(SD_CARD_ERROR_CMD12);
|
||||
}
|
||||
if (blocking) {
|
||||
if (yieldTimeout(isBusyDat)) {
|
||||
return sdError(SD_CARD_ERROR_CMD13);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::syncDevice() {
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
if (!waitTransferComplete()) {
|
||||
return false;
|
||||
}
|
||||
if (m_curState != IDLE_STATE) {
|
||||
return stopTransmission(true);
|
||||
}
|
||||
#else // ENABLE_TEENSY_SDIO_MOD
|
||||
if (m_curState == READ_STATE) {
|
||||
m_curState = IDLE_STATE;
|
||||
if (!readStop()) {
|
||||
|
|
@ -874,6 +986,7 @@ bool SdioCard::syncDevice() {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -884,6 +997,11 @@ uint8_t SdioCard::type() const {
|
|||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::writeData(const uint8_t* src) {
|
||||
DBG_IRQSTAT();
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
if (!waitTransferComplete()) {
|
||||
return false;
|
||||
}
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
const uint32_t* p32 = reinterpret_cast<const uint32_t*>(src);
|
||||
if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_WTA)) {
|
||||
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
|
||||
|
|
@ -901,12 +1019,17 @@ bool SdioCard::writeData(const uint8_t* src) {
|
|||
}
|
||||
p32 += FIFO_WML;
|
||||
}
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
m_transferActive = true;
|
||||
return true;
|
||||
#else // ENABLE_TEENSY_SDIO_MOD
|
||||
if (waitTimeout(isBusyTransferComplete)) {
|
||||
return sdError(SD_CARD_ERROR_WRITE_TIMEOUT);
|
||||
}
|
||||
m_irqstat = SDHC_IRQSTAT;
|
||||
SDHC_IRQSTAT = m_irqstat;
|
||||
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
|
||||
|
|
@ -919,10 +1042,23 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
|
|||
} else {
|
||||
ptr = const_cast<uint8_t*>(src);
|
||||
}
|
||||
if (!rdWrSectors(CMD24_DMA_XFERTYP, sector, ptr, 1)) {
|
||||
if (!rdWrSectors(CMD24_DMA_XFERTYP, sector, ptr, 1)) {
|
||||
return sdError(SD_CARD_ERROR_CMD24);
|
||||
}
|
||||
} else {
|
||||
#if ENABLE_TEENSY_SDIO_MOD
|
||||
if (!waitTransferComplete()) {
|
||||
return false;
|
||||
}
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
// End transfer with CMD12 if required.
|
||||
if ((SDHC_BLKATTR & 0XFFFF0000) == 0) {
|
||||
if (!syncDevice()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#endif // ENABLE_TEENSY_SDIO_MOD
|
||||
if (m_curState != WRITE_STATE || m_curSector != sector) {
|
||||
if (!syncDevice()) {
|
||||
return false;
|
||||
|
|
@ -937,6 +1073,7 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
|
|||
return false;
|
||||
}
|
||||
m_curSector++;
|
||||
#if !ENABLE_TEENSY_SDIO_MOD
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
// End transfer with CMD12 if required.
|
||||
if ((SDHC_BLKATTR & 0XFFFF0000) == 0) {
|
||||
|
|
@ -945,6 +1082,7 @@ bool SdioCard::writeSector(uint32_t sector, const uint8_t* src) {
|
|||
}
|
||||
}
|
||||
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#endif // !ENABLE_TEENSY_SDIO_MOD
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -984,7 +1122,7 @@ bool SdioCard::writeStart(uint32_t sector) {
|
|||
SDHC_BLKATTR = SDHC_BLKATTR_BLKSIZE(512);
|
||||
#else // defined(__IMXRT1062__)
|
||||
// Errata - can't do infinite transfer.
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(0XFFFF) | SDHC_BLKATTR_BLKSIZE(512);
|
||||
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(MAX_BLKCNT) | SDHC_BLKATTR_BLKSIZE(512);
|
||||
#endif // defined(__IMXRT1062__)
|
||||
if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? sector : 512*sector)) {
|
||||
return sdError(SD_CARD_ERROR_CMD25);
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@
|
|||
#endif // INCLUDE_SDIOS
|
||||
//------------------------------------------------------------------------------
|
||||
/** SdFat version for cpp use. */
|
||||
#define SD_FAT_VERSION 20004
|
||||
#define SD_FAT_VERSION 20005
|
||||
/** SdFat version as string. */
|
||||
#define SD_FAT_VERSION_STR "2.0.4"
|
||||
#define SD_FAT_VERSION_STR "2.0.5"
|
||||
//==============================================================================
|
||||
/**
|
||||
* \class SdBase
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@
|
|||
/** For Debug - must be one */
|
||||
#define ENABLE_ARDUINO_STRING 1
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set zero to disable mod for non-blocking write. */
|
||||
#define ENABLE_TEENSY_SDIO_MOD 1
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set USE_BLOCK_DEVICE_INTERFACE nonzero to use generic block device */
|
||||
#define USE_BLOCK_DEVICE_INTERFACE 0
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -82,7 +85,7 @@
|
|||
#endif // defined(__AVR__) && FLASHEND < 0X8000
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Set ENABLE_DEDICATED_SPI to enable dedicated use of the SPI bus.
|
||||
* Set ENABLE_DEDICATED_SPI non-zero to enable dedicated use of the SPI bus.
|
||||
* Selecting dedicated SPI in SdSpiConfig() will produce better
|
||||
* performance by using very large multi-block transfers to and
|
||||
* from the SD card.
|
||||
|
|
@ -96,7 +99,7 @@
|
|||
// All other boards.
|
||||
#define ENABLE_DEDICATED_SPI 1
|
||||
#endif // defined(__AVR__) && FLASHEND < 0X8000
|
||||
//-----------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* If the symbol SPI_DRIVER_SELECT is:
|
||||
*
|
||||
|
|
@ -110,6 +113,13 @@
|
|||
* 3 - An external SPI driver derived from SdSpiBaseClass is always used.
|
||||
*/
|
||||
#define SPI_DRIVER_SELECT 0
|
||||
/**
|
||||
* If USE_SPI_ARRAY_TRANSFER is non-zero and the standard SPI library is
|
||||
* use, the array transfer function, transfer(buf, size), will be used.
|
||||
* This option will allocate up to a 512 byte temporary buffer for send.
|
||||
* This may be faster for some boards. Do not use this with AVR boards.
|
||||
*/
|
||||
#define USE_SPI_ARRAY_TRANSFER 0
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* SD_CHIP_SELECT_MODE defines how the functions
|
||||
|
|
@ -181,7 +191,7 @@ typedef uint8_t SdCsPin_t;
|
|||
* Some cards will not sleep in low power mode unless CHECK_FLASH_PROGRAMMING
|
||||
* is non-zero.
|
||||
*/
|
||||
#define CHECK_FLASH_PROGRAMMING 1
|
||||
#define CHECK_FLASH_PROGRAMMING 0
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters
|
||||
|
|
|
|||
|
|
@ -43,6 +43,24 @@ void sdCsInit(SdCsPin_t pin);
|
|||
*/
|
||||
void sdCsWrite(SdCsPin_t pin, bool level);
|
||||
//------------------------------------------------------------------------------
|
||||
/** SPI bus is share with other devices. */
|
||||
const uint8_t SHARED_SPI = 0;
|
||||
#if ENABLE_DEDICATED_SPI
|
||||
/** The SD is the only device on the SPI bus. */
|
||||
const uint8_t DEDICATED_SPI = 1;
|
||||
/**
|
||||
* \param[in] opt option field of SdSpiConfig.
|
||||
* \return true for shared SPI.
|
||||
*/
|
||||
inline bool spiOptionShared(uint8_t opt) {return !(opt & DEDICATED_SPI);}
|
||||
#else // ENABLE_DEDICATED_SPI
|
||||
/**
|
||||
* \param[in] opt option field of SdSpiConfig.
|
||||
* \return true for shared SPI.
|
||||
*/
|
||||
inline bool spiOptionShared(uint8_t opt) {(void)opt; return true;}
|
||||
#endif // ENABLE_DEDICATED_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
/** SPISettings for SCK frequency in Hz. */
|
||||
#define SD_SCK_HZ(maxSpeed) (maxSpeed)
|
||||
/** SPISettings for SCK frequency in MHz. */
|
||||
|
|
@ -63,10 +81,6 @@ void sdCsWrite(SdCsPin_t pin, bool level);
|
|||
/** Set SCK rate to 500 kHz for AVR. */
|
||||
#define SPI_SIXTEENTH_SPEED SD_SCK_HZ(500000)
|
||||
//------------------------------------------------------------------------------
|
||||
/** The SD is the only device on the SPI bus. */
|
||||
#define DEDICATED_SPI 0X80
|
||||
/** SPI bus is share with other devices. */
|
||||
#define SHARED_SPI 0
|
||||
#if SPI_DRIVER_SELECT < 2
|
||||
#include "SPI.h"
|
||||
/** Port type for Arduino SPI hardware driver. */
|
||||
|
|
@ -106,29 +120,27 @@ class SdSpiConfig {
|
|||
* \param[in] maxSpeed Maximum SCK frequency.
|
||||
*/
|
||||
SdSpiConfig(SdCsPin_t cs, uint8_t opt, uint32_t maxSpeed) :
|
||||
csPin(cs), options(opt), maxSck(maxSpeed), spiPort(nullptr) {}
|
||||
csPin(cs), options(opt), maxSck(maxSpeed) {}
|
||||
/** SdSpiConfig constructor.
|
||||
*
|
||||
* \param[in] cs Chip select pin.
|
||||
* \param[in] opt Options.
|
||||
*/
|
||||
SdSpiConfig(SdCsPin_t cs, uint8_t opt) :
|
||||
csPin(cs), options(opt), maxSck(SD_SCK_MHZ(50)), spiPort(nullptr) {}
|
||||
SdSpiConfig(SdCsPin_t cs, uint8_t opt) : csPin(cs), options(opt) {}
|
||||
/** SdSpiConfig constructor.
|
||||
*
|
||||
* \param[in] cs Chip select pin.
|
||||
*/
|
||||
explicit SdSpiConfig(SdCsPin_t cs) : csPin(cs), options(SHARED_SPI),
|
||||
maxSck(SD_SCK_MHZ(50)), spiPort(nullptr) {}
|
||||
explicit SdSpiConfig(SdCsPin_t cs) : csPin(cs) {}
|
||||
|
||||
/** Chip select pin. */
|
||||
const SdCsPin_t csPin;
|
||||
/** Options */
|
||||
const uint8_t options;
|
||||
const uint8_t options = 0;
|
||||
/** Max SCK frequency */
|
||||
const uint32_t maxSck;
|
||||
const uint32_t maxSck = SD_SCK_MHZ(50);
|
||||
/** SPI port */
|
||||
SpiPort_t* spiPort;
|
||||
SpiPort_t* spiPort = nullptr;
|
||||
};
|
||||
#if SPI_DRIVER_SELECT < 2
|
||||
#include "SdSpiArduinoDriver.h"
|
||||
|
|
|
|||
|
|
@ -28,46 +28,54 @@
|
|||
#define ESP_UNALIGN_OK 1
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::activate() {
|
||||
SPI.beginTransaction(m_spiSettings);
|
||||
m_spi->beginTransaction(m_spiSettings);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::begin(SdSpiConfig spiConfig) {
|
||||
(void)spiConfig;
|
||||
SPI.begin();
|
||||
if (spiConfig.spiPort) {
|
||||
m_spi = spiConfig.spiPort;
|
||||
#if defined(SDCARD_SPI) && defined(SDCARD_SS_PIN)
|
||||
} else if (spiConfig.csPin == SDCARD_SS_PIN) {
|
||||
m_spi = &SDCARD_SPI;
|
||||
#endif // defined(SDCARD_SPI) && defined(SDCARD_SS_PIN)
|
||||
} else {
|
||||
m_spi = &SPI;
|
||||
}
|
||||
m_spi->begin();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::deactivate() {
|
||||
SPI.endTransaction();
|
||||
m_spi->endTransaction();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdSpiArduinoDriver::receive() {
|
||||
return SPI.transfer(0XFF);
|
||||
return m_spi->transfer(0XFF);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
||||
#if ESP_UNALIGN_OK
|
||||
SPI.transferBytes(nullptr, buf, count);
|
||||
m_spi->transferBytes(nullptr, buf, count);
|
||||
#else // ESP_UNALIGN_OK
|
||||
// Adjust to 32-bit alignment.
|
||||
while ((reinterpret_cast<uintptr_t>(buf) & 0X3) && count) {
|
||||
*buf++ = SPI.transfer(0xff);
|
||||
*buf++ = m_spi->transfer(0xff);
|
||||
count--;
|
||||
}
|
||||
// Do multiple of four byte transfers.
|
||||
size_t n4 = 4*(count/4);
|
||||
if (n4) {
|
||||
SPI.transferBytes(nullptr, buf, n4);
|
||||
m_spi->transferBytes(nullptr, buf, n4);
|
||||
}
|
||||
// Transfer up to three remaining bytes.
|
||||
for (buf += n4, count -= n4; count; count--) {
|
||||
*buf++ = SPI.transfer(0xff);
|
||||
*buf++ = m_spi->transfer(0xff);
|
||||
}
|
||||
#endif // ESP_UNALIGN_OK
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::send(uint8_t data) {
|
||||
SPI.transfer(data);
|
||||
m_spi->transfer(data);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
|
||||
|
|
@ -78,6 +86,7 @@ void SdSpiArduinoDriver::send(const uint8_t* buf , size_t count) {
|
|||
count--;
|
||||
}
|
||||
#endif // #if ESP_UNALIGN_OK
|
||||
SPI.transferBytes(const_cast<uint8_t*>(buf), nullptr, count);
|
||||
|
||||
m_spi->transferBytes(const_cast<uint8_t*>(buf), nullptr, count);
|
||||
}
|
||||
#endif // defined(SD_USE_CUSTOM_SPI) && defined(ESP8266)
|
||||
#endif // defined(SD_USE_CUSTOM_SPI) && (defined(ESP8266) || defined(ESP32))
|
||||
|
|
|
|||
|
|
@ -55,9 +55,14 @@ inline uint8_t SdSpiArduinoDriver::receive() {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline uint8_t SdSpiArduinoDriver::receive(uint8_t* buf, size_t count) {
|
||||
#if USE_SPI_ARRAY_TRANSFER
|
||||
memset(buf, 0XFF, count);
|
||||
m_spi->transfer(buf, count);
|
||||
#else // USE_SPI_ARRAY_TRANSFER
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
buf[i] = m_spi->transfer(0XFF);
|
||||
}
|
||||
#endif // USE_SPI_ARRAY_TRANSFER
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -66,6 +71,14 @@ inline void SdSpiArduinoDriver::send(uint8_t data) {
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline void SdSpiArduinoDriver::send(const uint8_t* buf, size_t count) {
|
||||
#if USE_SPI_ARRAY_TRANSFER
|
||||
if (count <= 512) {
|
||||
uint8_t tmp[count]; // NOLINT
|
||||
memcpy(tmp, buf, count);
|
||||
m_spi->transfer(tmp, count);
|
||||
return;
|
||||
}
|
||||
#endif // USE_SPI_ARRAY_TRANSFER
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
m_spi->transfer(buf[i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ static void dbgPrint(uint16_t line) {
|
|||
|
||||
#define DBG_PRINT_IF(b) if (b) {Serial.print(F(__FILE__));\
|
||||
Serial.println(__LINE__);}
|
||||
#define DBG_HALT_IF(b) if (b) { Serial.print(F("DBG_HALT "));\
|
||||
#define DBG_HALT_IF(b) if (b) {Serial.print(F("DBG_HALT "));\
|
||||
Serial.print(F(__FILE__)); Serial.println(__LINE__);\
|
||||
while (true) {}}
|
||||
#define DBG_FAIL_MACRO dbgPrint(__LINE__);
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ int vmprintf(F* file, const char *fmt, va_list ap) {
|
|||
break;
|
||||
|
||||
default:
|
||||
*--str = c;;
|
||||
*--str = c;
|
||||
break;
|
||||
}
|
||||
ns = ptr - str;
|
||||
|
|
@ -468,7 +468,7 @@ int vmprintf(F file, const __FlashStringHelper *ifsh, va_list ap) {
|
|||
break;
|
||||
|
||||
default:
|
||||
*--str = c;;
|
||||
*--str = c;
|
||||
break;
|
||||
}
|
||||
ns = ptr - str;
|
||||
|
|
|
|||
|
|
@ -114,11 +114,7 @@ class StdioStream : private StreamBaseFile {
|
|||
/** Constructor
|
||||
*
|
||||
*/
|
||||
StdioStream() {
|
||||
m_w = m_r = 0;
|
||||
m_p = m_buf;
|
||||
m_status = 0;
|
||||
}
|
||||
StdioStream() {}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Clear the stream's end-of-file and error indicators. */
|
||||
void clearerr() {
|
||||
|
|
@ -657,11 +653,11 @@ class StdioStream : private StreamBaseFile {
|
|||
static const uint8_t S_EOF = 0x10; // found EOF
|
||||
static const uint8_t S_ERR = 0x20; // found error
|
||||
//----------------------------------------------------------------------------
|
||||
uint8_t m_status;
|
||||
uint8_t* m_p;
|
||||
uint8_t m_r;
|
||||
uint8_t m_w;
|
||||
uint8_t m_buf[STREAM_BUF_SIZE];
|
||||
uint8_t m_status = 0;
|
||||
uint8_t* m_p = m_buf;
|
||||
uint8_t m_r = 0;
|
||||
uint8_t m_w;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#endif // StdioStream_h
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
class ibufstream : public istream {
|
||||
public:
|
||||
/** Constructor */
|
||||
ibufstream() : m_buf(nullptr), m_len(0) {}
|
||||
ibufstream() {}
|
||||
/** Constructor
|
||||
* \param[in] str pointer to string to be parsed
|
||||
* Warning: The string will not be copied so must stay in scope.
|
||||
|
|
@ -89,8 +89,8 @@ class ibufstream : public istream {
|
|||
}
|
||||
/// @endcond
|
||||
private:
|
||||
const char* m_buf;
|
||||
size_t m_len;
|
||||
const char* m_buf = nullptr;
|
||||
size_t m_len = 0;
|
||||
size_t m_pos;
|
||||
};
|
||||
//==============================================================================
|
||||
|
|
@ -101,7 +101,7 @@ class ibufstream : public istream {
|
|||
class obufstream : public ostream {
|
||||
public:
|
||||
/** constructor */
|
||||
obufstream() : m_in(0) {}
|
||||
obufstream() {}
|
||||
/** Constructor
|
||||
* \param[in] buf buffer for formatted string
|
||||
* \param[in] size buffer size
|
||||
|
|
@ -131,7 +131,7 @@ class obufstream : public ostream {
|
|||
protected:
|
||||
/// @cond SHOW_PROTECTED
|
||||
void putch(char c) {
|
||||
if (m_in >= (m_size - 1)) {
|
||||
if ((m_in + 1) >= m_size) {
|
||||
setstate(badbit);
|
||||
return;
|
||||
}
|
||||
|
|
@ -159,14 +159,13 @@ class obufstream : public ostream {
|
|||
bool sync() {
|
||||
return true;
|
||||
}
|
||||
|
||||
pos_type tellpos() {
|
||||
return m_in;
|
||||
}
|
||||
/// @endcond
|
||||
private:
|
||||
char *m_buf;
|
||||
size_t m_size;
|
||||
size_t m_in;
|
||||
char *m_buf = nullptr;
|
||||
size_t m_size = 0;
|
||||
size_t m_in = 0;
|
||||
};
|
||||
#endif // bufstream_h
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ inline ios_base& uppercase(ios_base& str) {
|
|||
class ios : public ios_base {
|
||||
public:
|
||||
/** Create ios with no error flags set */
|
||||
ios() : m_iostate(0) {}
|
||||
ios() {}
|
||||
|
||||
/** \return null pointer if fail() is true. */
|
||||
operator const void*() const {
|
||||
|
|
@ -443,6 +443,6 @@ class ios : public ios_base {
|
|||
}
|
||||
|
||||
private:
|
||||
iostate m_iostate;
|
||||
iostate m_iostate = 0;
|
||||
};
|
||||
#endif // ios_h
|
||||
|
|
|
|||
Loading…
Reference in a new issue