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