libraries / Mitov / Mitov_MicroSDCard.hon commit Added link to project report (97a3ba0)
   1////////////////////////////////////////////////////////////////////////////////
   2//                                                                            //
   3//     This software is supplied under the terms of a license agreement or    //
   4//     nondisclosure agreement with Mitov Software and may not be copied      //
   5//     or disclosed except in accordance with the terms of that agreement.    //
   6//         Copyright(c) 2002-2016 Mitov Software. All Rights Reserved.        //
   7//                                                                            //
   8////////////////////////////////////////////////////////////////////////////////
   9
  10#ifndef _MITOV_MICRO_SD_CARD_h
  11#define _MITOV_MICRO_SD_CARD_h
  12
  13#include <Mitov.h>
  14
  15#include <SPI.h>
  16#include <SD.h>
  17
  18namespace Mitov
  19{
  20        class MicroSDCard_Intf
  21        {
  22        public:
  23                virtual bool DoExists( String APathName ) = 0;
  24                virtual bool DoCreate( String APathName ) = 0;
  25                virtual bool DoRemove( String APathName ) = 0;
  26                virtual bool DoOpen( String APathName, uint8_t mode, File &AFile ) = 0;
  27
  28        };
  29//---------------------------------------------------------------------------
  30        class MicroSDCardElementBasic : public OpenWire::Object
  31        {
  32                typedef OpenWire::Object inherited;
  33
  34        public:
  35                String  PathName;
  36
  37        protected:
  38                Mitov::MicroSDCard_Intf &FOwner;
  39
  40        public:
  41                MicroSDCardElementBasic( Mitov::MicroSDCard_Intf &AOwner ) :
  42                        FOwner( AOwner )
  43                {
  44                }
  45
  46        };
  47//---------------------------------------------------------------------------
  48        class MicroSDCardElementOperation : public OpenWire::Object
  49        {
  50        public:
  51                OpenWire::SinkPin       ClockInputPin;
  52                OpenWire::SourcePin     OutputPin;
  53
  54        };
  55//---------------------------------------------------------------------------
  56        class MicroSDCardElementDirectory : public MicroSDCardElementBasic, public MicroSDCard_Intf
  57        {
  58                typedef Mitov::MicroSDCardElementBasic inherited;
  59
  60        public:
  61                MicroSDCardElementOperation     CheckExists;
  62                MicroSDCardElementOperation     Create;
  63                MicroSDCardElementOperation     Remove;
  64
  65        public:
  66                virtual bool DoExists( String APathName ) override
  67                {
  68                        return FOwner.DoExists( JoinPath( APathName ));
  69                }
  70
  71                virtual bool DoCreate( String APathName ) override
  72                {
  73                        return FOwner.DoCreate( JoinPath( APathName ));
  74                }
  75
  76                virtual bool DoRemove( String APathName ) override
  77                {
  78                        return FOwner.DoRemove( JoinPath( APathName ));
  79                }
  80
  81                virtual bool DoOpen( String APathName, uint8_t mode, File &AFile ) override
  82                {
  83                        return FOwner.DoOpen( JoinPath( APathName ), mode, AFile );
  84                }
  85
  86        protected:
  87                String JoinPath( String AValue )
  88                {
  89                        String APath = PathName;
  90                        if( ! APath.endsWith( "/" ) )
  91                                APath = APath + "/";
  92
  93                        if( AValue.startsWith( "/" ) )
  94                                AValue.remove( 0, 1 );
  95
  96                        return APath + AValue;
  97                }
  98
  99        protected:
 100                void DoCheckExistsClockReceive( void *_Data )
 101                {
 102                        CheckExists.OutputPin.SendValue( FOwner.DoExists( PathName ));
 103                }
 104
 105                void DoCreateClockReceive( void *_Data )
 106                {
 107                        Create.OutputPin.SendValue( FOwner.DoCreate( PathName ));
 108                }
 109
 110                void DoRemoveClockReceive( void *_Data )
 111                {
 112                        Remove.OutputPin.SendValue( FOwner.DoRemove( PathName ));
 113                }
 114
 115        public:
 116                MicroSDCardElementDirectory( Mitov::MicroSDCard_Intf &AOwner ) :
 117                        inherited( AOwner )
 118                {
 119                        CheckExists.ClockInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MicroSDCardElementDirectory::DoCheckExistsClockReceive );
 120                        Create.ClockInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MicroSDCardElementDirectory::DoCreateClockReceive );
 121                        Remove.ClockInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MicroSDCardElementDirectory::DoRemoveClockReceive );
 122                }
 123
 124        };
 125//---------------------------------------------------------------------------
 126        class MicroSDCardElementClocked : public MicroSDCardElementBasic
 127        {
 128                typedef Mitov::MicroSDCardElementBasic inherited;
 129
 130    public:
 131                OpenWire::SinkPin       ClockInputPin;
 132
 133        protected:
 134                virtual void DoClockReceive( void *_Data ) = 0;
 135
 136        public:
 137                MicroSDCardElementClocked( Mitov::MicroSDCard_Intf &AOwner ) :
 138                        inherited( AOwner )
 139                {
 140                        ClockInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MicroSDCardElementClocked::DoClockReceive );
 141                }
 142
 143        };
 144//---------------------------------------------------------------------------
 145        class MicroSDCardElementClockedResult : public MicroSDCardElementClocked
 146        {
 147                typedef Mitov::MicroSDCardElementClocked inherited;
 148
 149        public:
 150                OpenWire::SourcePin     OutputPin;
 151
 152        public:
 153                using inherited::inherited;
 154
 155        };
 156//---------------------------------------------------------------------------
 157        class MicroSDCardElementList : public MicroSDCardElementClockedResult
 158        {
 159                typedef Mitov::MicroSDCardElementClockedResult inherited;
 160
 161        public:
 162                OpenWire::SourcePin     FailedOutputPin;
 163
 164        public:
 165                bool    Recursive = false;
 166
 167        protected:
 168                void ProcessLevel( String APath, String APrefix )
 169                {
 170                        File AFile;
 171                        if( ! FOwner.DoOpen( APath, FILE_READ, AFile ))
 172                        {
 173                                FailedOutputPin.Notify( NULL );
 174                                return;
 175                        }
 176
 177                        if( APath.endsWith( "/" ))
 178                                APath = APath.substring( 0, APath.length() - 1 );
 179
 180                        while (true) 
 181                        {
 182                                File AEntry =  AFile.openNextFile();
 183                                if (! AEntry) 
 184                                  // no more files
 185                                  break;
 186
 187                                String AItemName = APrefix + AEntry.name(); 
 188                                OutputPin.Notify( (char *)AItemName.c_str() );
 189
 190                                if( Recursive )
 191                                        if( AEntry.isDirectory())
 192                                                ProcessLevel( APath + '/' + AEntry.name(), AItemName + '/' );
 193
 194                                AEntry.close();
 195                          }
 196
 197                        AFile.close();
 198                }
 199
 200        protected:
 201                virtual void DoClockReceive( void *_Data )
 202                {
 203//                      Serial.println( "" );
 204//                      Serial.println( PathName );
 205//                      Serial.println( "" );
 206                        if( PathName = "" )
 207                                ProcessLevel( "/", "" );
 208
 209                        else
 210                                ProcessLevel( PathName, "" );
 211/*
 212                        File AFile;
 213                        if( ! FOwner.DoOpen( PathName, FILE_READ, AFile ))
 214                        {
 215                                FailedOutputPin.Notify( NULL );
 216                                return;
 217                        }
 218
 219                        while (true) 
 220                        {
 221                                File AEntry =  AFile.openNextFile();
 222                                if (! AEntry) 
 223                                  // no more files
 224                                  break;
 225
 226                                OutputPin.Notify( AEntry.name() );
 227                                AEntry.close();
 228                          }
 229
 230                        AFile.close();
 231*/
 232                }
 233
 234        public:
 235                using inherited::inherited;
 236
 237        };
 238//---------------------------------------------------------------------------
 239        class MicroSDCardElementFile : public MicroSDCardElementBasic
 240        {
 241                typedef Mitov::MicroSDCardElementBasic inherited;
 242
 243        public:
 244                OpenWire::SourcePin     ReadPositionOutputPin;
 245                OpenWire::SourcePin     WritePositionOutputPin;
 246
 247                OpenWire::SinkPin       CloseInputPin;
 248                OpenWire::SinkPin       FlushInputPin;
 249
 250        public:
 251                bool Enabled : 1;
 252                bool NewLine : 1;
 253                bool KeepFlushed : 1;
 254                bool KeepClosed : 1;
 255
 256        public:
 257                bool FHasWrite : 1;
 258
 259        protected:
 260                bool        FWriteMoved : 1;
 261                bool        FReadMoved : 1;
 262
 263                uint32_t        FWritePosition = 0;
 264                uint32_t        FReadPosition = 0;
 265
 266        public:
 267                File FFile;
 268
 269        public:
 270                template<typename T> void Print( T AValue )
 271                {
 272                        if( ! TryOpen() )
 273                                return;
 274
 275                        PrepareWrite();
 276
 277//                      Serial.println( "TEST2" );
 278                        if( NewLine )
 279                                FFile.println( AValue );
 280
 281                        else
 282                                FFile.print( AValue );
 283
 284                        UpdateWrite();
 285                }
 286
 287                void Write( void *_Data, size_t ASize )
 288                {
 289                        if( ! TryOpen() )
 290                                return;
 291
 292                        PrepareWrite();
 293                        FFile.write( (uint8_t *)_Data, ASize );
 294                        UpdateWrite();
 295                }
 296
 297                void BeginRead()
 298                {
 299                        if( ! FWriteMoved )
 300                        {
 301                                FWritePosition = FFile.position();
 302                                FWriteMoved = true;
 303                        }
 304
 305                        if( FReadMoved )
 306                        {
 307                                FFile.seek( FReadPosition );
 308                                FReadMoved = false;
 309                        }
 310                }
 311
 312                inline void ResetReadPosition()
 313                {
 314                        FFile.seek( FReadPosition );
 315                }
 316
 317        protected:
 318                void PrepareWrite()
 319                {
 320                        if( ! FReadMoved )
 321                        {
 322                                FReadPosition = FFile.position();
 323                                FReadMoved = true;
 324                        }
 325
 326                        if( FWriteMoved )
 327                        {
 328                                FFile.seek( FWritePosition );
 329                                FWriteMoved = false;
 330                        }
 331                }
 332
 333                void UpdateWrite()
 334                {
 335                        if( KeepFlushed )
 336                                FFile.flush();
 337
 338                        if( KeepClosed )
 339                                FFile.close();
 340                        
 341                        UpdateWritePosition();
 342                }
 343
 344        public:
 345                bool TryOpen()
 346                {
 347                        if( FFile )
 348                                return true;
 349
 350//                      Serial.println( "OPEN1" );
 351                        if( ! Enabled )
 352                                return false;
 353
 354                        if( PathName == "" )
 355                                return false;
 356
 357//                      Serial.println( PathName );
 358//                      Serial.println( FHasWrite );
 359                        if( FHasWrite )
 360                                return FOwner.DoOpen( PathName, FILE_WRITE, FFile );
 361
 362                        else
 363                                return FOwner.DoOpen( PathName, FILE_READ, FFile );
 364                }
 365
 366        protected:
 367                void UpdateWritePosition()
 368                {
 369                        if( WritePositionOutputPin.IsConnected() )
 370                                WritePositionOutputPin.SendValue( FFile.position() );
 371                }
 372
 373        protected:
 374                void DoCloseReceive( void *_Data )
 375                {
 376                        FFile.close();
 377                }
 378
 379                void DoFlushReceive( void *_Data )
 380                {
 381                        FFile.flush();
 382                }
 383
 384        public:
 385                MicroSDCardElementFile( Mitov::MicroSDCard_Intf &AOwner, bool AHasWrite ) :
 386                        inherited( AOwner ),
 387                        Enabled( true ),
 388                        NewLine( true ),
 389                        KeepFlushed( true ),
 390                        KeepClosed( true ),
 391                        FHasWrite( AHasWrite ),
 392                        FReadMoved( false ),
 393                        FWriteMoved( false )
 394                {
 395                        CloseInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MicroSDCardElementFile::DoCloseReceive );
 396                        FlushInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MicroSDCardElementFile::DoFlushReceive );
 397                }
 398
 399        };
 400//---------------------------------------------------------------------------
 401        class MicroSDCardFileElementBasic : public OpenWire::Object
 402        {
 403                typedef OpenWire::Object inherited;
 404
 405        protected:
 406                MicroSDCardElementFile  &FOwner;
 407
 408        public:
 409                MicroSDCardFileElementBasic( Mitov::MicroSDCardElementFile &AOwner ) :
 410                        FOwner( AOwner )
 411                {
 412                }
 413
 414        };
 415//---------------------------------------------------------------------------
 416        class MicroSDCardFileElementBasicClocked : public MicroSDCardFileElementBasic
 417        {
 418                typedef MicroSDCardFileElementBasic inherited;
 419
 420    public:
 421                OpenWire::SinkPin       ClockInputPin;
 422                OpenWire::SourcePin     OutputPin;
 423
 424        protected:
 425                virtual void DoClockReceive( void *_Data ) = 0;
 426
 427        public:
 428                MicroSDCardFileElementBasicClocked( Mitov::MicroSDCardElementFile &AOwner ) :
 429                        inherited( AOwner )
 430                {
 431                        ClockInputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MicroSDCardFileElementBasicClocked::DoClockReceive );
 432                }
 433
 434        };
 435//---------------------------------------------------------------------------
 436        class MicroSDCardFileElementReadTextLine : public MicroSDCardFileElementBasicClocked
 437        {
 438                typedef MicroSDCardFileElementBasicClocked inherited;
 439
 440        protected:
 441                bool readStringLine( String &AResult )
 442                {
 443//                      AResult = "";
 444                        int c = FOwner.FFile.read();
 445//                      Serial.println( c );
 446                        if( c < 0 )
 447                                return false;
 448
 449//                      Serial.println( "R1" );
 450                        while (c >= 0 && c != '\n' && c != '\r' )
 451                        {
 452                                AResult += (char)c;
 453                                c = FOwner.FFile.read();
 454                        }
 455
 456                        while ( c >= 0 )
 457                        {
 458                                c = FOwner.FFile.peek();
 459                                if( c != '\n' && c != '\r' )
 460                                        break;
 461
 462                                FOwner.FFile.read();
 463                        }
 464/*
 465                        while ( c >= 0 && ( c == '\n' || c == '\r' ))
 466                                c = FOwner.FFile.read();
 467*/
 468                        return true;
 469                }
 470
 471        protected:
 472                virtual void DoClockReceive( void *_Data ) override
 473                {
 474                        if( ! FOwner.TryOpen() )
 475                                return;
 476
 477                        String ALine;                   
 478                        FOwner.BeginRead();
 479//                      Serial.println( "READ1" );
 480                        if( readStringLine( ALine ))
 481                                OutputPin.Notify( (void *)ALine.c_str() );
 482
 483                }
 484
 485        public:
 486                using inherited::inherited;
 487
 488        };
 489//---------------------------------------------------------------------------
 490        template<typename T> class MicroSDCardFileElementReadTyped : public MicroSDCardFileElementBasicClocked
 491        {
 492                typedef MicroSDCardFileElementBasicClocked inherited;
 493
 494        protected:
 495                virtual void DoClockReceive( void *_Data )
 496                {
 497                        if( ! FOwner.TryOpen() )
 498                                return;
 499
 500                        FOwner.BeginRead();
 501
 502                        T AData;
 503                        size_t AReadSize = FOwner.FFile.readBytes( (uint8_t *)&AData, sizeof( AData ));
 504                        if( AReadSize == sizeof( AData ) )
 505                                OutputPin.Notify( &AData );
 506
 507//                      else
 508//                              FOwner.ResetReadPosition();
 509                }
 510
 511        public:
 512                using inherited::inherited;
 513
 514        };
 515//---------------------------------------------------------------------------
 516        template<typename T> class MicroSDCardFileElementWriteTyped : public MicroSDCardFileElementBasic
 517        {
 518                typedef MicroSDCardFileElementBasic inherited;
 519
 520    public:
 521                OpenWire::SinkPin       InputPin;
 522
 523        protected:
 524                void DoDataReceive( void *_Data )
 525                {
 526                        FOwner.Write( _Data, sizeof( T ));
 527                }
 528
 529        public:
 530                MicroSDCardFileElementWriteTyped( Mitov::MicroSDCardElementFile &AOwner ) :
 531                        inherited( AOwner )
 532                {
 533                        AOwner.FHasWrite = true;
 534
 535                        InputPin.SetCallback( this, (OpenWire::TOnPinReceive)&MicroSDCardFileElementWriteTyped::DoDataReceive );
 536                }
 537
 538        };
 539//---------------------------------------------------------------------------
 540        class MicroSDCardElementExists : public MicroSDCardElementClockedResult
 541        {
 542                typedef Mitov::MicroSDCardElementClockedResult inherited;
 543
 544        protected:
 545                virtual void DoClockReceive( void *_Data ) override
 546                {
 547                        OutputPin.SendValue( FOwner.DoExists( PathName ));
 548                }
 549
 550        public:
 551                using inherited::inherited;
 552
 553        };
 554//---------------------------------------------------------------------------
 555//      MicroSDCardElementDirectory
 556        template<int PIN_NUMBER> class MicroSDCard : public Mitov::EnabledComponent, public MicroSDCard_Intf
 557        {
 558                typedef Mitov::EnabledComponent inherited;
 559
 560        public:
 561                OpenWire::SourcePin     FailedOutputPin;
 562                OpenWire::SourcePin     SuccessOutputPin;
 563
 564        public:
 565                void SetEnabled( bool AValue )
 566                {
 567                        if( Enabled == AValue )
 568                                return;
 569
 570                        Enabled = AValue;
 571                        UpdateEnabled();
 572                }
 573
 574        public:
 575                virtual bool DoExists( String APathName )
 576                {
 577                        if( !FCard )
 578                                return false;
 579
 580//                      Serial.println( "COOL1" );
 581//                      Serial.println( APathName );
 582                        char *ATmp = new char[ APathName.length() + 1 ];
 583                        memcpy( ATmp, APathName.c_str(), APathName.length() + 1 );
 584
 585                        bool AResult = FCard->exists( ATmp );
 586
 587                        delete [] ATmp;
 588
 589                        return AResult;
 590                }
 591
 592                virtual bool DoCreate( String APathName )
 593                {
 594                        if( !FCard )
 595                                return false;
 596
 597                        char *ATmp = new char[ APathName.length() + 1 ];
 598                        memcpy( ATmp, APathName.c_str(), APathName.length() + 1 );
 599
 600                        bool AResult = FCard->mkdir( ATmp );
 601
 602                        delete [] ATmp;
 603
 604                        return AResult;
 605                }
 606
 607                virtual bool DoRemove( String APathName )
 608                {
 609                        if( !FCard )
 610                                return false;
 611
 612                        char *ATmp = new char[ APathName.length() + 1 ];
 613                        memcpy( ATmp, APathName.c_str(), APathName.length() + 1 );
 614
 615                        bool AResult = FCard->rmdir( ATmp );
 616
 617                        delete [] ATmp;
 618
 619                        return AResult;
 620                }
 621
 622                virtual bool DoOpen( String APathName, uint8_t mode, File &AFile )
 623                {
 624//                      Serial.print( "O1 :" );
 625                        if( !FCard )
 626                                return false;
 627
 628                        if( ! APathName.startsWith( "/" ))
 629                                APathName = String( "/" ) + APathName;
 630
 631                        char *ATmp = new char[ APathName.length() + 1 ];
 632                        memcpy( ATmp, APathName.c_str(), APathName.length() + 1 );
 633
 634//                      Serial.print( "T1 :" );
 635//                      Serial.println( ATmp );
 636                        AFile = FCard->open( ATmp, mode );
 637                        delete [] ATmp;
 638
 639                        return AFile;
 640                }
 641
 642        protected:
 643                SDClass *FCard = nullptr;
 644                
 645        protected:
 646                void UpdateEnabled()
 647                {
 648                        if( Enabled )
 649                        {
 650//                              Serial.println( "TEST1" );
 651                                FCard = new SDClass;                            
 652                                if( FCard->begin( PIN_NUMBER ) )
 653                                        SuccessOutputPin.Notify( NULL );
 654
 655                                else
 656                                {
 657//                                      Serial.println( "FAIL" );
 658                                        FailedOutputPin.Notify( NULL );
 659                                        Enabled = false;
 660                                        UpdateEnabled();
 661                                }
 662//                              Serial.println( "COOL" );
 663                        }
 664                        else
 665                        {
 666                                delete FCard;
 667                                FCard = nullptr;
 668                        }
 669                }
 670
 671        protected:
 672                virtual void SystemInit()
 673                {
 674                        UpdateEnabled();
 675                        inherited::SystemInit();
 676                }
 677/*
 678                virtual void SystemStart() 
 679                {
 680//                      FServo.attach( PIN_NUMBER );
 681                        inherited::SystemStart();
 682                }
 683*/
 684
 685/*
 686                virtual ~MicroSDCard()
 687                {
 688                        if( FCard )
 689                                delete FCard;
 690                }
 691*/
 692        };
 693}
 694
 695#endif