RSeries astromech firmware
VMusic.h
Go to the documentation of this file.
1 #ifndef VMusic_h
2 #define VMusic_h
3 
4 #include "ReelTwo.h"
5 #include "core/SetupEvent.h"
6 
16 class VMusic
17 {
18 public:
19  enum
20  {
21  kRegMode = 0x0,
22  kRegStatus = 0x1,
23  kRegBass = 0x2,
26  kRegAuData = 0x5,
27  kRegWRAM = 0x6,
28  kRegWRAMAddr = 0x7,
29  kRegHDAT0 = 0x8,
30  kRegHDAT1 = 0x9,
31  kRegAIAddr = 0xA,
32  kRegVolume = 0xB,
33  kRegAICtrl0 = 0xC,
34  kRegAICtrl1 = 0xD,
35  kRegAICtrl2 = 0xE,
37  };
38 
39  /*
40  * Base class for parseTextFile(). The process() function will be called
41  * for each character. Carriage return / line feed will be turned into
42  * just carriage return.
43  */
44  class Parser
45  {
46  public:
47  virtual void process(char ch) = 0;
48  };
49 
50  /*
51  * Read-only data returned from readDirectory()
52  */
53  struct DirEntry
54  {
55  const char* name;
56  bool dir;
57  };
58 
63  VMusic(Stream &stream) :
64  fStream(stream)
65  {
66  }
67 
68  /*
69  * Called once during initialization. Will return true if successful.
70  */
71  bool init()
72  {
73  uint32_t startMillis = millis();
74  sendCommand();
75  while (!fAvailable && millis() < startMillis + 3000)
76  {
77  while (fStream.available())
78  {
79  char ch = fStream.read();
80  if (ch == 0x0D)
81  {
82  fPos = 0;
83  if (*fBuffer != '\0')
84  {
85  // DEBUG_PRINTLN(fBuffer);
86  if (strcmp(fBuffer, "No Disk") == 0)
87  {
88  fAvailable = true;
89  fDriveInserted = false;
90  break;
91  }
92  if (strcmp(fBuffer, "Stopped") == 0 ||
93  strcmp(fBuffer, "D:\\>") == 0 ||
94  strcmp(fBuffer, "D:\\>Command Failed") == 0 ||
95  strcmp(fBuffer, "No Upgrade") == 0 ||
96  strcmp(fBuffer, "Bad Command") == 0 ||
97  strcmp(fBuffer, "Command Failed") == 0)
98  {
99  fAvailable = true;
100  fDriveInserted = true;
101  break;
102  }
103  }
104  }
105  else if (fPos < SizeOfArray(fBuffer)-1)
106  {
107  fBuffer[fPos++] = ch;
108  fBuffer[fPos] = '\0';
109  }
110  }
111  }
112  if (available())
113  {
114  stop();
115  return true;
116  }
117  return false;
118  }
119 
120  /*
121  * Call this from loop() to process any status VMusic sends inbetween commands
122  */
123  void process()
124  {
125  while (fStream.available())
126  {
127  size_t size;
128  char* str = (char*)getResponse(size);
129  if (*str == '\0')
130  {
131  /* ignore */
132  }
133  else if (strcmp(str, "Device Removed P2") == 0)
134  {
135  /* Drive removed event */
136  }
137  else if (strcmp(str, "No Disk") == 0)
138  {
139  fDriveInserted = false;
140  DEBUG_PRINTLN("DISK REMOVED");
141  }
142  else if (strcmp(str, "Device Detected P2") == 0)
143  {
144  /* Drive detected event */
145  }
146  else if (strcmp(str, "No Upgrade") == 0)
147  {
148  fDriveInserted = true;
149  DEBUG_PRINTLN("DISK INSERTED");
150  }
151  else if (strcmp(str, "Stopped") == 0)
152  {
153  fPlaying = false;
154  }
155  else
156  {
157  DEBUG_PRINT("[VMUSIC] "); DEBUG_PRINTLN(str);
158  }
159  }
160  }
161 
162  /*
163  * Returns true if a USB drive is currently inserted.
164  */
165  inline bool driveInserted() const
166  {
167  return fDriveInserted;
168  }
169 
170  /*
171  * Returns true if the init() function was successful.
172  */
173  inline bool moduleAvailable() const
174  {
175  return fAvailable;
176  }
177 
178  /*
179  * Returns true if currently playing audio
180  */
181  inline bool isPlaying() const
182  {
183  return fPlaying;
184  }
185 
186  /*
187  * Returns true if currently playing audio (more accurate than isPlaying)
188  */
189  bool isBusy()
190  {
191  if (available())
192  {
194  return (readCommandRegister(kRegDecodeTime) != 0);
195  }
196  return false;
197  }
198 
199  /*
200  * Returns true if init() was successful and a USB drive is available.
201  */
202  inline bool available() const
203  {
204  return moduleAvailable() && driveInserted();
205  }
206 
207  /*
208  * Delete subdirectory from current directory
209  */
210  bool deleteDirectory(const char* dir)
211  {
212  if (!available())
213  return false;
214 
215  sendCommand("DLD", dir);
216  return expectResponse();
217  }
218 
219  /*
220  * Return the disk label limited to buffer size. Disk labels are 11 characters long.
221  */
222  bool diskLabel(char* labelBuffer, size_t bufferSize)
223  {
224  if (!available())
225  return false;
226 
227  size_t size;
228  *labelBuffer = '\0';
229  sendCommand("DVL");
230  char* ret = (char*)readLine(size);
231  if (strcmp(ret, "No Disk") == 0)
232  return false;
233  snprintf(labelBuffer, bufferSize, "%s", ret);
234  return expectResponse();
235  }
236 
237  /*
238  * Returns the serial number of the USB volume.
239  */
240  bool diskSerialNumber(uint32_t &serialNumber)
241  {
242  if (!available())
243  return false;
244 
245  sendCommand("DSN");
246  uint8_t buf[5];
247 
248  for (unsigned i = 0; i < sizeof(buf); i++)
249  buf[i] = readByte();
250  if (buf[4] == '\r')
251  {
252  serialNumber = (uint32_t(buf[0])<<0 |
253  uint32_t(buf[1])<<8 |
254  uint32_t(buf[2])<<16 |
255  uint32_t(buf[3])<<24);
256  return true;
257  }
258  while (readByte() != '\r')
259  ;
260  return false;
261  }
262 
263  /*
264  * Delete a file in the current directory
265  */
266  bool deleteFile(const char* fname)
267  {
268  if (!available())
269  return false;
270  sendCommand("DLF", fname);
271  return expectResponse();
272  }
273 
274  /*
275  * Rename a file or directory
276  */
277  bool renameFile(const char* oldname, const char* newname)
278  {
279  if (!available())
280  return false;
281  sendCommand("REN", oldname, newname);
282  return expectResponse();
283  }
284 
285  /*
286  * Create a subdirectory in the current directory
287  */
288  bool makeDirectory(const char* dir)
289  {
290  sendCommand("MKD", dir);
291  return expectResponse();
292  }
293 
294  bool openFileRead(const char* fileName)
295  {
296  if (!available())
297  return false;
298  sendCommand("OPR", fileName);
299  return expectResponse();
300  }
301 
302  bool openFileAppend(const char* fileName)
303  {
304  if (!available())
305  return false;
306  sendCommand("OPW", fileName);
307  return expectResponse();
308  }
309 
310  bool closeFile(const char* fileName)
311  {
312  if (!available())
313  return false;
314  sendCommand("CLF", fileName);
315  return expectResponse();
316  }
317 
318  bool readFile(const char* fileName)
319  {
320  sendCommand("RD", fileName);
321  return expectResponse();
322  }
323 
324  bool getFileSize(const char* fileName, uint32_t &size)
325  {
326  uint8_t* str;
327  size_t bytesRead;
328  size = 0;
329  sendCommand("DIR", fileName);
330  // Read until first empty line
331  while ((str = readLine(bytesRead)) != nullptr && str[0] != '\0')
332  ;
333  str = getResponse(bytesRead);
334  size_t len = strlen(fileName);
335  if (bytesRead == len+5 && str[len] == ' ')
336  {
337  str += len+1;
338  size = (uint32_t(str[0])<<0 |
339  uint32_t(str[1])<<8 |
340  uint32_t(str[2])<<16 |
341  uint32_t(str[3])<<24);
342  return true;
343  }
344  return false;
345  }
346 
347  bool parseTextFile(Parser &parser, const char* fileName, const char* dir = nullptr)
348  {
349  if (!available())
350  return false;
351  if (!changeDirectory(dir))
352  return false;
353 
354  uint32_t fileSize = 0;
355  if (!available() || !getFileSize(fileName, fileSize) || fileSize == 0)
356  {
357  DEBUG_PRINT("Can't read ");
358  DEBUG_PRINT(fileName);
359  DEBUG_PRINTLN('.');
360  return false;
361  }
362 
363  process();
364  if (openFileRead(fileName))
365  {
366  bool newline = false;
367  char readCmd[9] = { 'R', 'D', 'F', ' ' };
368  uint8_t chunk[128];
369  uint32_t chunkSize = sizeof(chunk);
370  while (fileSize != 0)
371  {
372  if (fileSize < chunkSize)
373  chunkSize = fileSize;
374  readCmd[4] = (chunkSize>>24)&0xFF;
375  readCmd[5] = (chunkSize>>16)&0xFF;
376  readCmd[6] = (chunkSize>>8)&0xFF;
377  readCmd[7] = (chunkSize>>0)&0xFF;
378  readCmd[8] = '\r';
379 
380  fStream.write(readCmd, sizeof(readCmd));
381  if (!expectResponse())
382  break;
383 
384  uint8_t* ptr = getChunkResponse(chunk, chunkSize);
385  for (size_t i = 0; i < chunkSize; i++)
386  {
387  char ch = (char)ptr[i];
388  if (ch == '\n' || ch == '\r')
389  {
390  // ignore following new line characters
391  if (newline)
392  continue;
393  // turn all new line characters to carriage return
394  newline = (ch == '\n' || ch == '\r');
395  if (newline)
396  ch = '\r';
397  }
398  else
399  {
400  newline = false;
401  }
402  parser.process(ch);
403  }
404  // DEBUG_PRINTLN();
405  // DEBUG_PRINT("======= GOT CHUNK: ");
406  // DEBUG_PRINTLN(chunkSize);
407  fileSize -= chunkSize;
408  }
409  if (!newline)
410  {
411  parser.process('\r');
412  }
413  expectResponse();
414  return closeFile(fileName);
415  }
416  return false;
417  }
418 
419  bool seekFile(uint32_t pos)
420  {
421  if (!available())
422  return false;
423 
424  uint8_t seekCmd[9] = { 'S', 'E', 'K', ' ' };
425  seekCmd[4] = (pos>>24)&0xFF;
426  seekCmd[5] = (pos>>16)&0xFF;
427  seekCmd[6] = (pos>>8)&0xFF;
428  seekCmd[7] = (pos>>0)&0xFF;
429  seekCmd[8] = '\r';
430  fStream.write(seekCmd, sizeof(seekCmd));
431  return expectResponse();
432  }
433 
434  bool readOpenFile(uint8_t* ptr, uint32_t len)
435  {
436  uint8_t readCmd[9] = { 'R', 'D', 'F', ' ' };
437  readCmd[4] = (len>>24)&0xFF;
438  readCmd[5] = (len>>16)&0xFF;
439  readCmd[6] = (len>>8)&0xFF;
440  readCmd[7] = (len>>0)&0xFF;
441  readCmd[8] = '\r';
442  fStream.write(readCmd, sizeof(readCmd));
443  if (expectResponse())
444  {
445  getChunkResponse(ptr, len);
446  return true;
447  }
448  return false;
449  }
450 
451  bool writeToFile(uint8_t* ptr, uint32_t len)
452  {
453  if (!available())
454  return false;
455 
456  uint8_t writeCmd[9] = { 'W', 'R', 'F', ' ' };
457  writeCmd[4] = (len>>24)&0xFF;
458  writeCmd[5] = (len>>16)&0xFF;
459  writeCmd[6] = (len>>8)&0xFF;
460  writeCmd[7] = (len>>0)&0xFF;
461  writeCmd[8] = '\r';
462  fStream.write(writeCmd, sizeof(writeCmd));
463  fStream.write(ptr, len);
464  return expectResponse();
465  }
466 
467  bool writeStringToFile(const char* ptr)
468  {
469  return writeToFile((uint8_t*)ptr, strlen(ptr));
470  }
471 
472  /*
473  * Change current directory. If directory is omitted then assume root directory.
474  */
475  bool changeDirectory(const char* dir = nullptr)
476  {
477  if (!available())
478  return false;
479 
480  stop();
481  sendCommand("CD", "..");
482  expectResponse("Command Failed");
483  if (dir != nullptr)
484  {
485  sendCommand("CD", dir);
486  expectResponse();
487  }
488  return true;
489  }
490 
491  /*
492  * Automatically suspend disk devices when not in use
493  */
494  bool suspendDisk()
495  {
496  if (!available())
497  return false;
498 
499  sendCommand("SUD");
500  return expectResponse();
501  }
502 
503  /*
504  * Keep disks active when not in use
505  */
506  bool wakeDisk()
507  {
508  if (!available())
509  return false;
510 
511  sendCommand("WKD");
512  return expectResponse();
513  }
514 
515  /*
516  * Open directory for reading. Must call readDirectory() until it returns false.
517  */
518  bool openDirectory(const char* dir = nullptr)
519  {
520  if (!available())
521  return false;
522 
523  if (changeDirectory(dir))
524  {
525  size_t size;
526  uint8_t* ret;
527  sendCommand("DIR");
528  // Read until first empty line
529  while ((ret = readLine(size)) != nullptr && ret[0] != '\0')
530  ;
531  return (ret != nullptr && ret[0] == '\0');
532  }
533  return false;
534  }
535 
536  /*
537  * Read an open directory. Must call readDirectory() until it returns false.
538  * Cannot be nested to traverse subdirectories.
539  */
540  bool readDirectory(DirEntry &entry)
541  {
542  if (!available())
543  return false;
544 
545  size_t size;
546  uint8_t* ret;
547  while ((ret = readUntilPrompt(size)) != nullptr)
548  {
549  entry.dir = false;
550  if (size > 4 && strcmp((char*)&ret[size-4], " DIR") == 0)
551  {
552  ret[size-4] = '\0';
553  entry.dir = true;
554  }
555  /* Ignore navigation entries */
556  if (strcmp((char*)ret, ".") == 0)
557  continue;
558  if (strcmp((char*)ret, "..") == 0)
559  continue;
560  /* Ignore MacOS garbage */
561  if (strcmp((char*)ret, "~1.TRA") == 0)
562  continue;
563  if (strcmp((char*)ret, "TRASHE~1") == 0)
564  continue;
565  if (strcmp((char*)ret, "SPOTLI~1") == 0)
566  continue;
567  entry.name = (char*)ret;
568  return true;
569  }
570  return false;
571  }
572 
573  /*
574  * Play the specified file in the specified directory. If directory is omitted then assume current directory.
575  */
576  bool play(const char* snd, const char* dir = nullptr)
577  {
578  if (changeDirectory(dir))
579  {
580  size_t size;
581  sendCommand("VPF", snd);
582  char* str = (char*)getResponse(size);
583  if (strncmp(str, "Playing ", 8) == 0)
584  {
585  fPlaying = true;
586  return true;
587  }
588  }
589  return false;
590  }
591 
592  /*
593  * Play the specified file in the specified directory repeatedly. If directory is omitted then assume current directory.
594  */
595  bool playRepeatedly(const char* snd, const char* dir = nullptr)
596  {
597  if (changeDirectory(dir))
598  {
599  size_t size;
600  sendCommand("VRF", snd);
601  char* str = (char*)getResponse(size);
602  if (strncmp(str, "Playing ", 8) == 0)
603  {
604  fPlaying = true;
605  return true;
606  }
607  }
608  return false;
609  }
610 
611  /*
612  * Play all files sequentially in the specified directory and all sub-directories.
613  * If directory is omitted then assume current directory.
614  */
615  bool playAll(const char* dir = nullptr)
616  {
617  if (changeDirectory(dir))
618  {
619  size_t size;
620  sendCommand("V3A");
621  char* str = (char*)getResponse(size);
622  if (strncmp(str, "Playing ", 8) == 0)
623  {
624  fPlaying = true;
625  return true;
626  }
627  }
628  return false;
629  }
630 
631  /*
632  * Play all files sequentially in the specified directory and all sub-directories. Repeat forever.
633  * If directory is omitted then assume current directory.
634  */
635  bool playAllRepeatedly(const char* dir = nullptr)
636  {
637  if (changeDirectory(dir))
638  {
639  size_t size;
640  sendCommand("VRA");
641  char* str = (char*)getResponse(size);
642  if (strncmp(str, "Playing ", 8) == 0)
643  {
644  fPlaying = true;
645  return true;
646  }
647  }
648  return false;
649  }
650 
651  /*
652  * Play all files randomly in the specified directory and all sub-directories. Repeat forever.
653  * If directory is omitted then assume current directory.
654  */
655  bool playRandomRepeatedly(const char* dir = nullptr)
656  {
657  if (changeDirectory(dir))
658  {
659  size_t size;
660  sendCommand("VRR");
661  char* str = (char*)getResponse(size);
662  if (strncmp(str, "Playing ", 8) == 0)
663  {
664  fPlaying = true;
665  return true;
666  }
667  }
668  return false;
669  }
670 
671  /*
672  * Skip to the next track if playing files using playAll or playAllRepeatedly
673  */
674  bool nextTrack()
675  {
676  if (!available())
677  return false;
678  sendCommand("VSF");
679  return expectResponse();
680  }
681 
682  /*
683  * Skip to the previous track if playing files using playAll or playAllRepeatedly
684  */
686  {
687  if (!available())
688  return false;
689  sendCommand("VSB");
690  return expectResponse();
691  }
692 
693  /*
694  * Skip to next directory track if playing files using playAll or playAllRepeatedly
695  */
697  {
698  if (!available())
699  return false;
700  sendCommand("VSD");
701  return expectResponse();
702  }
703 
704  /*
705  * Pauses the current file if a file is currently playing or resumes playback if the
706  * playback is currently paused.
707  */
709  {
710  if (!available())
711  return;
712  sendCommand("VP");
713  expectResponse();
714  }
715 
716  /*
717  * Skip forwards 5 seconds through the currently playing file.
718  */
719  bool fastForward()
720  {
721  if (!available())
722  return false;
723  sendCommand("VF");
724  return expectResponse();
725  }
726 
727  /*
728  * Skip backwards 5 seconds through the currently playing file.
729  */
730  bool fastReverse()
731  {
732  if (!available())
733  return false;
734  sendCommand("VB");
735  return expectResponse();
736  }
737 
738  /*
739  * Stop playback of current file
740  */
741  bool stop()
742  {
743  if (!available())
744  return false;
745  fPlaying = false;
746  sendCommand("VST");
747  return expectResponse("Command Failed");
748  }
749 
750  /*
751  * Set the volume for both left and right channels (0 silent - 100 maximum)
752  * Volume settings is logarithmic. Every tic is 0.5db, quite reliably (ie, 20 tics is 10db, etc)
753  */
754  bool setVolume(uint8_t volumePercent)
755  {
756  if (!available())
757  return false;
758  sendByteCommand("VSV", map(min(volumePercent, 100), 0, 100, 100, 0));
759  return expectResponse();
760  }
761 
762  /*
763  * Reads from the command register on the VLSI VS1003.
764  */
765  uint16_t readCommandRegister(uint8_t commandRegister)
766  {
767  uint16_t ret;
768  sendByteCommand("VRD", commandRegister);
769  ret = (unsigned(readByte()) << 8 | unsigned(readByte()));
770  expectResponse();
771  return ret;
772  }
773 
774  /*
775  * Reads from the command register on the VLSI VS1003.
776  */
777  bool writeCommandRegister(uint8_t commandRegister, uint16_t value)
778  {
779  sendByteWordCommand("VWR", commandRegister, value);
780  return expectResponse();
781  }
782 
783  /*
784  * Send string to VMusic module
785  */
786  void outputString(const char* str)
787  {
788  size_t len = strlen(str);
789  while (len-- > 0)
790  fBuffer[fPos++] = *str++;
791  }
792 
793  /*
794  * Send upper case string to VMusic module
795  */
796  void outputUpperString(const char* str)
797  {
798  size_t len = strlen(str);
799  while (len-- > 0)
800  fBuffer[fPos++] = toupper(*str++);
801  }
802 
803  uint16_t getDecodeTime()
804  {
806  }
807 
808  uint32_t getSampleRate()
809  {
810  return readCommandRegister(kRegAuData) & ~1;
811  }
812 
813  bool isStereo()
814  {
815  return (readCommandRegister(kRegAuData) & 1);
816  }
817 
818  bool isMono()
819  {
820  return ((readCommandRegister(kRegAuData) & 1) == 0);
821  }
822 
823  /*
824  *
825  */
826  void setBassEnhancer(int trebleControl, int freqLimit, int bassEnhancer, int lowerLimit)
827  {
828  trebleControl = min(max(trebleControl, -8), 7);
829  if (trebleControl != 0)
830  trebleControl += 8;
831  freqLimit = min(max(freqLimit, 0), 15);
832  bassEnhancer = min(max(bassEnhancer, 0), 15);
833  lowerLimit = min(max(lowerLimit, 0), 15);
835  (trebleControl<<12) |
836  (freqLimit<<8) |
837  (bassEnhancer<<4) |
838  (lowerLimit<<0));
839  }
840 
841  /*
842  * Send optional command with optional arguments
843  */
844  void sendCommand(const char* cmd = nullptr, const char* arg1 = nullptr, const char* arg2 = nullptr)
845  {
846  process();
847 
848  fPos = 0;
849  if (cmd != nullptr)
850  {
851  // output command
852  outputString(cmd);
853  }
854  if (arg1 != nullptr)
855  {
856  // add space
857  fBuffer[fPos++] = ' ';
858  // output upper case string
859  outputUpperString(arg1);
860  }
861  if (arg2 != nullptr)
862  {
863  // add space
864  fBuffer[fPos++] = ' ';
865  // output upper case string
866  outputUpperString(arg2);
867  }
868  // append carriage return
869  fBuffer[fPos++] = '\r';
870  fStream.write(fBuffer, fPos);
871 
872  // DEBUG_PRINT("[SEND]: ");
873  // for (unsigned i = 0; i < fPos; i++)
874  // {
875  // DEBUG_PRINT_HEX((uint8_t)fBuffer[i]);
876  // DEBUG_PRINT(" ");
877  // }
878  // DEBUG_PRINTLN();
879  // for (unsigned i = 0; i < fPos; i++)
880  // {
881  // if ((uint8_t)fBuffer[i] >= 32 && (uint8_t)fBuffer[i] <= 127)
882  // DEBUG_PRINT(fBuffer[i]);
883  // else
884  // DEBUG_PRINT('.');
885  // DEBUG_PRINT(" ");
886  // }
887  // DEBUG_PRINTLN();
888 
889  fPos = 0;
890  }
891 
892  /*
893  * Send command with one byte argument
894  */
895  void sendByteCommand(const char* cmd, uint8_t arg)
896  {
897  process();
898 
899  // DEBUG_PRINTLN(cmd);
900  fPos = 0;
901  // output command
902  outputString(cmd);
903  // add space
904  fBuffer[fPos++] = ' ';
905  fBuffer[fPos++] = (char)arg;
906  // append carriage return
907  fBuffer[fPos++] = '\r';
908  fStream.write(fBuffer, fPos);
909  fPos = 0;
910  }
911 
912  /*
913  * Send command with one byte argument and one word argument
914  */
915  void sendByteWordCommand(const char* cmd, uint8_t arg, uint16_t word)
916  {
917  process();
918 
919  fPos = 0;
920  // output command
921  outputString(cmd);
922  // add space
923  fBuffer[fPos++] = ' ';
924  fBuffer[fPos++] = (char)arg;
925  fBuffer[fPos++] = (char)(word & 0xFF);
926  fBuffer[fPos++] = (char)(word >> 8);
927  // append carriage return
928  fBuffer[fPos++] = '\r';
929  fStream.write(fBuffer, fPos);
930  fPos = 0;
931  }
932 
933  /*
934  * Block until a single byte is read from the VMusic module
935  */
936  uint8_t readByte()
937  {
938  uint8_t data;
939  if (fStream.readBytes(&data, 1) == 1)
940  return data;
941  return 0;
942  }
943 
944  /*
945  * Expect response
946  */
947  bool expectResponse(const char* altresponse = nullptr)
948  {
949  size_t size;
950  uint8_t* str = getResponse(size);
951  if (size == 0)
952  return true;
953  if (altresponse != nullptr &&
954  (strlen(altresponse) == size &&
955  memcmp(altresponse, str, size) == 0))
956  {
957  return true;
958  }
959  DEBUG_PRINT("VMUSIC UNEXPECTED RESPONSE: \"");
960  DEBUG_PRINT("\"");
961  DEBUG_PRINT((char*)str);
962  DEBUG_PRINTLN('"');
963  return false;
964  }
965 
966  uint8_t* getChunkResponse(uint8_t* buffer, size_t size)
967  {
968  // char text[17];
969  // int cnt = 0;
970  size_t pos = 0;
971  while (pos < size)
972  {
973  if (fStream.available())
974  {
975  buffer[pos++] = fStream.read();
976  }
977  }
978  return buffer;
979  }
980 
981  uint8_t* getResponse(size_t& size)
982  {
983  size = 0;
984  bool skipPrompt = false;
985  while (fAvailable)
986  {
987  if (fStream.available())
988  {
989  int ch = fStream.read();
990  // DEBUG_PRINT("[VMUSIC2]: ");
991  // DEBUG_PRINT((int)ch);
992  // DEBUG_PRINT(" - ");
993  // DEBUG_PRINTLN((char)ch);
994  if (ch == 0x0D)
995  {
996  fBuffer[fPos] = '\0';
997  size = fPos;
998  fPos = 0;
999  if (*fBuffer != '\0')
1000  {
1001  // DEBUG_PRINT("[VMUSIC2]: ");
1002  // for (unsigned i = 0; i < size; i++)
1003  // {
1004  // DEBUG_PRINT_HEX((uint8_t)fBuffer[i]);
1005  // DEBUG_PRINT(" ");
1006  // }
1007  // DEBUG_PRINTLN(fBuffer);
1008  break;
1009  }
1010  if (skipPrompt)
1011  break;
1012  }
1013  else if (fPos < SizeOfArray(fBuffer)-1)
1014  {
1015  fBuffer[fPos++] = ch;
1016  fBuffer[fPos] = '\0';
1017  if (!skipPrompt && strcmp(fBuffer, "D:\\>") == 0)
1018  {
1019  skipPrompt = true;
1020  fBuffer[0] = '\0';
1021  fPos = 0;
1022  }
1023  }
1024  }
1025  }
1026  return (uint8_t*)fBuffer;
1027  }
1028 
1029  uint8_t* readLine(size_t& size)
1030  {
1031  size = 0;
1032  while (fAvailable)
1033  {
1034  if (fStream.available())
1035  {
1036  int ch = fStream.read();
1037  // DEBUG_PRINT("[VMUSIC3]: ");
1038  // DEBUG_PRINT((int)ch);
1039  // DEBUG_PRINT(" - ");
1040  // DEBUG_PRINTLN((char)ch);
1041  if (ch == 0x0D)
1042  {
1043  fBuffer[fPos] = '\0';
1044  size = fPos;
1045  fPos = 0;
1046  break;
1047  }
1048  else if (fPos < SizeOfArray(fBuffer)-1)
1049  {
1050  fBuffer[fPos++] = ch;
1051  fBuffer[fPos] = '\0';
1052  }
1053  }
1054  }
1055  return (uint8_t*)fBuffer;
1056  }
1057 
1058  uint8_t* readUntilPrompt(size_t& size)
1059  {
1060  size = 0;
1061  bool skipPrompt = false;
1062  while (fAvailable)
1063  {
1064  if (fStream.available())
1065  {
1066  int ch = fStream.read();
1067  // DEBUG_PRINT("[VMUSIC3]: ");
1068  // DEBUG_PRINT((int)ch);
1069  // DEBUG_PRINT(" - ");
1070  // DEBUG_PRINTLN((char)ch);
1071  if (ch == 0x0D)
1072  {
1073  fBuffer[fPos] = '\0';
1074  size = fPos;
1075  fPos = 0;
1076  if (*fBuffer != '\0')
1077  {
1078  // DEBUG_PRINT("[VMUSIC2]: ");
1079  // for (unsigned i = 0; i < size; i++)
1080  // {
1081  // DEBUG_PRINT_HEX((uint8_t)fBuffer[i]);
1082  // DEBUG_PRINT(" ");
1083  // }
1084  // DEBUG_PRINTLN(fBuffer);
1085  break;
1086  }
1087  if (skipPrompt)
1088  return nullptr;
1089  }
1090  else if (fPos < SizeOfArray(fBuffer)-1)
1091  {
1092  fBuffer[fPos++] = ch;
1093  fBuffer[fPos] = '\0';
1094  if (!skipPrompt && strcmp(fBuffer, "D:\\>") == 0)
1095  {
1096  skipPrompt = true;
1097  fBuffer[0] = '\0';
1098  fPos = 0;
1099  }
1100  }
1101  }
1102  }
1103  return (uint8_t*)fBuffer;
1104  }
1105 
1106 private:
1107  Stream& fStream;
1108  bool fAvailable = false;
1109  bool fDriveInserted = false;
1110  bool fPlaying = false;
1111  char fBuffer[32];
1112  unsigned fPos = 0;
1113 };
1114 
1115 #endif
VMusic::closeFile
bool closeFile(const char *fileName)
Definition: VMusic.h:310
VMusic::DirEntry::name
const char * name
Definition: VMusic.h:55
VMusic::nextTrack
bool nextTrack()
Definition: VMusic.h:674
VMusic::setBassEnhancer
void setBassEnhancer(int trebleControl, int freqLimit, int bassEnhancer, int lowerLimit)
Definition: VMusic.h:826
VMusic::kRegAICtrl0
@ kRegAICtrl0
Definition: VMusic.h:33
VMusic::fastReverse
bool fastReverse()
Definition: VMusic.h:730
VMusic::renameFile
bool renameFile(const char *oldname, const char *newname)
Definition: VMusic.h:277
VMusic::available
bool available() const
Definition: VMusic.h:202
VMusic::kRegAICtrl3
@ kRegAICtrl3
Definition: VMusic.h:36
DEBUG_PRINT
#define DEBUG_PRINT(s)
Definition: ReelTwo.h:180
ReelTwo.h
SetupEvent.h
VMusic::expectResponse
bool expectResponse(const char *altresponse=nullptr)
Definition: VMusic.h:947
VMusic::DirEntry
Definition: VMusic.h:53
VMusic::Parser::process
virtual void process(char ch)=0
VMusic::writeStringToFile
bool writeStringToFile(const char *ptr)
Definition: VMusic.h:467
VMusic::VMusic
VMusic(Stream &stream)
Default Constructor.
Definition: VMusic.h:63
VMusic::kRegAICtrl2
@ kRegAICtrl2
Definition: VMusic.h:35
VMusic::getDecodeTime
uint16_t getDecodeTime()
Definition: VMusic.h:803
VMusic::fastForward
bool fastForward()
Definition: VMusic.h:719
VMusic::seekFile
bool seekFile(uint32_t pos)
Definition: VMusic.h:419
DEBUG_PRINTLN
#define DEBUG_PRINTLN(s)
Definition: ReelTwo.h:178
VMusic::playRandomRepeatedly
bool playRandomRepeatedly(const char *dir=nullptr)
Definition: VMusic.h:655
VMusic::kRegDecodeTime
@ kRegDecodeTime
Definition: VMusic.h:25
VMusic::changeDirectory
bool changeDirectory(const char *dir=nullptr)
Definition: VMusic.h:475
VMusic::readOpenFile
bool readOpenFile(uint8_t *ptr, uint32_t len)
Definition: VMusic.h:434
VMusic::readCommandRegister
uint16_t readCommandRegister(uint8_t commandRegister)
Definition: VMusic.h:765
VMusic::togglePausePlay
void togglePausePlay()
Definition: VMusic.h:708
VMusic::DirEntry::dir
bool dir
Definition: VMusic.h:56
VMusic::sendByteWordCommand
void sendByteWordCommand(const char *cmd, uint8_t arg, uint16_t word)
Definition: VMusic.h:915
VMusic::init
bool init()
Definition: VMusic.h:71
VMusic::readDirectory
bool readDirectory(DirEntry &entry)
Definition: VMusic.h:540
VMusic::getChunkResponse
uint8_t * getChunkResponse(uint8_t *buffer, size_t size)
Definition: VMusic.h:966
VMusic::writeCommandRegister
bool writeCommandRegister(uint8_t commandRegister, uint16_t value)
Definition: VMusic.h:777
VMusic::openFileAppend
bool openFileAppend(const char *fileName)
Definition: VMusic.h:302
VMusic::sendCommand
void sendCommand(const char *cmd=nullptr, const char *arg1=nullptr, const char *arg2=nullptr)
Definition: VMusic.h:844
VMusic::process
void process()
Definition: VMusic.h:123
VMusic::openFileRead
bool openFileRead(const char *fileName)
Definition: VMusic.h:294
VMusic::Parser
Definition: VMusic.h:44
VMusic::getResponse
uint8_t * getResponse(size_t &size)
Definition: VMusic.h:981
VMusic::kRegWRAM
@ kRegWRAM
Definition: VMusic.h:27
VMusic::readFile
bool readFile(const char *fileName)
Definition: VMusic.h:318
VMusic::kRegWRAMAddr
@ kRegWRAMAddr
Definition: VMusic.h:28
VMusic::diskSerialNumber
bool diskSerialNumber(uint32_t &serialNumber)
Definition: VMusic.h:240
VMusic::isMono
bool isMono()
Definition: VMusic.h:818
VMusic::kRegBass
@ kRegBass
Definition: VMusic.h:23
VMusic::readUntilPrompt
uint8_t * readUntilPrompt(size_t &size)
Definition: VMusic.h:1058
VMusic::kRegHDAT0
@ kRegHDAT0
Definition: VMusic.h:29
VMusic::kRegAuData
@ kRegAuData
Definition: VMusic.h:26
VMusic::previousTrack
bool previousTrack()
Definition: VMusic.h:685
VMusic::getSampleRate
uint32_t getSampleRate()
Definition: VMusic.h:808
VMusic::outputString
void outputString(const char *str)
Definition: VMusic.h:786
VMusic::kRegHDAT1
@ kRegHDAT1
Definition: VMusic.h:30
VMusic::deleteFile
bool deleteFile(const char *fname)
Definition: VMusic.h:266
VMusic::setVolume
bool setVolume(uint8_t volumePercent)
Definition: VMusic.h:754
VMusic::driveInserted
bool driveInserted() const
Definition: VMusic.h:165
VMusic::readLine
uint8_t * readLine(size_t &size)
Definition: VMusic.h:1029
VMusic::stop
bool stop()
Definition: VMusic.h:741
VMusic::diskLabel
bool diskLabel(char *labelBuffer, size_t bufferSize)
Definition: VMusic.h:222
VMusic::kRegMode
@ kRegMode
Definition: VMusic.h:21
VMusic::play
bool play(const char *snd, const char *dir=nullptr)
Definition: VMusic.h:576
VMusic::playAllRepeatedly
bool playAllRepeatedly(const char *dir=nullptr)
Definition: VMusic.h:635
VMusic::deleteDirectory
bool deleteDirectory(const char *dir)
Definition: VMusic.h:210
VMusic::kRegAICtrl1
@ kRegAICtrl1
Definition: VMusic.h:34
VMusic::parseTextFile
bool parseTextFile(Parser &parser, const char *fileName, const char *dir=nullptr)
Definition: VMusic.h:347
VMusic
Definition: VMusic.h:16
VMusic::getFileSize
bool getFileSize(const char *fileName, uint32_t &size)
Definition: VMusic.h:324
VMusic::isStereo
bool isStereo()
Definition: VMusic.h:813
VMusic::wakeDisk
bool wakeDisk()
Definition: VMusic.h:506
VMusic::playRepeatedly
bool playRepeatedly(const char *snd, const char *dir=nullptr)
Definition: VMusic.h:595
VMusic::suspendDisk
bool suspendDisk()
Definition: VMusic.h:494
VMusic::isPlaying
bool isPlaying() const
Definition: VMusic.h:181
VMusic::openDirectory
bool openDirectory(const char *dir=nullptr)
Definition: VMusic.h:518
VMusic::playAll
bool playAll(const char *dir=nullptr)
Definition: VMusic.h:615
VMusic::writeToFile
bool writeToFile(uint8_t *ptr, uint32_t len)
Definition: VMusic.h:451
VMusic::nextDirectory
bool nextDirectory()
Definition: VMusic.h:696
VMusic::kRegVolume
@ kRegVolume
Definition: VMusic.h:32
VMusic::kRegClockFreq
@ kRegClockFreq
Definition: VMusic.h:24
VMusic::moduleAvailable
bool moduleAvailable() const
Definition: VMusic.h:173
VMusic::isBusy
bool isBusy()
Definition: VMusic.h:189
VMusic::sendByteCommand
void sendByteCommand(const char *cmd, uint8_t arg)
Definition: VMusic.h:895
VMusic::outputUpperString
void outputUpperString(const char *str)
Definition: VMusic.h:796
VMusic::makeDirectory
bool makeDirectory(const char *dir)
Definition: VMusic.h:288
SizeOfArray
#define SizeOfArray(arr)
Definition: ReelTwo.h:204
VMusic::kRegAIAddr
@ kRegAIAddr
Definition: VMusic.h:31
VMusic::readByte
uint8_t readByte()
Definition: VMusic.h:936
VMusic::kRegStatus
@ kRegStatus
Definition: VMusic.h:22