Basic Stamp 2

' =========================================================================
'
'   File....... uMP3-Music-Player.BS2
'   Purpose.... Random song player
'   Author..... Jon Williams -- Parallax, Inc.
'   E-mail..... jwilliams at parallax.com
'   Started.... 17 OCT 2005
'   Updated.... 21 OCT 2005
'
'   {$STAMP BS2}
'   {$PBASIC 2.5}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------
'
' Randomly plays files from a Rogue Robotics uMP3 player.  All songs on
' list will be played before any repeats occur.
'
' Note: Requires uMP3 firmware 110.11 or higher


' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------

TX              PIN     15                      ' to uMP3.RX pin
RX              PIN     14                      ' to uMP3.TX pin


' -----[ Constants ]-------------------------------------------------------

#SELECT $STAMP
  #CASE BS2, BS2E, BS2PE
    T9600       CON     84
  #CASE BS2SX, BS2P
    T9600       CON     240
  #CASE BS2PX
    T9600       CON     396
#ENDSELECT

SevenBit        CON     $2000
Inverted        CON     $4000
Open            CON     $8000
Baud            CON     Open | T9600


NumSongs        CON     16                      ' songs on uMP3 player
SongDelay       CON     0000                    ' 2 secs between songs


#DEFINE TestMode = 0                            ' 1 = song title to DEBUG


' -----[ Variables ]-------------------------------------------------------

idx             VAR     Byte                    ' loop counter
theSong         VAR     Byte                    ' song number to play
lastSong        VAR     Byte                    ' last played
zCount          VAR     Byte                    ' for fast-forward routine
eePntr          VAR     Word                    ' eeprom pointer
char            VAR     Byte
pos             VAR     Byte                    ' song position
loopNum         VAR     Byte                    ' song loop #
markers         VAR     Word                    ' played markers
lottery         VAR     Word                    ' random value


' -----[ EEPROM Data ]-----------------------------------------------------

MP3s            DATA    "Away in a Manger", 0
                DATA    "Choir of Bells", 0
                DATA    "Dreidel", 0
                DATA    "Frosty the Snowman", 0
                DATA    "Grandma Got Ran Over by a Reindeer", 0
                DATA    "Hark the Harold Angels Sing", 0
                DATA    "Jingle Bells", 0
                DATA    "Joy to the World", 0
                DATA    "Little Drummer Boy", 0
                DATA    "Let It Snow", 0
                DATA    "The First Noel", 0
                DATA    "O Holy Night", 0
                DATA    "Rudolf the Red Nose Reindeer", 0
                DATA    "Santa Claus Is Coming to Town", 0
                DATA    "Silent Night", 0
                DATA    "Winter Wonderland", 0


' -----[ Initialization ]--------------------------------------------------

Reset:
  PAUSE 2000                                    ' let uMP3 start-up

  #IF TestMode = 0 #THEN
    SEROUT TX, Baud, [CR]                       ' prod
    SERIN  RX, Baud, 250, Reset, [WAIT(">")]    ' verify presence
  #ENDIF

  lottery = 1225                                ' seed random generator
  GOSUB Reset_Markers                           ' clear available songs


' -----[ Program Code ]----------------------------------------------------

Main:
  RANDOM lottery                                ' toss random generator
  theSong = lottery // NumSongs                 ' get song #
  IF (markers.LOWBIT(theSong) = 1) THEN Main    ' retry if played
  IF (theSong = lastSong) THEN Main             ' no repeat on next cycle

Play_The_Song:
  markers.LOWBIT(theSong) = 1                   ' mark current song
  lastSong = theSong                            ' mark as last played
  GOSUB Play_MP3                                ' play it
  IF (markers = $FFFF) THEN                     ' all songs played?
    GOSUB Reset_Markers                         ' yes, reset
  ENDIF
  PAUSE SongDelay                               ' break between songs
  GOTO Main


' -----[ Subroutines ]-----------------------------------------------------

Play_MP3:
  eePntr = MP3s                                 ' start at beginnig
  IF (theSong > 0) THEN                         ' fast-fwd to song
    zCount = 0                                  ' reset counter
    DO
      READ eePntr, char                         ' read char
      eePntr = eePntr + 1                       ' update pointer
      IF (char = 0) THEN                        ' 0?
        zCount = zCount + 1                     ' yes, update count
      ENDIF
    LOOP UNTIL (zCount = theSong)
  ENDIF

  #IF (TestMode = 0) #THEN
    SEROUT TX, Baud, ["PC F /"]                 ' play file in root
    DO                                          ' send file name
      READ eePntr, char
      eePntr = eePntr + 1
      IF (char = 0) THEN EXIT
      SEROUT TX, Baud, [char]
    LOOP
    SEROUT TX, Baud, [".MP3", CR]               ' send extension
    PAUSE 500
    DO
      SEROUT TX, Baud, ["PC Z", CR]             ' get status
      SERIN  RX, Baud, [char, DEC pos, DEC loopNum]
    LOOP UNTIL (char = "S")
  #ELSE
    DEBUG DEC2 theSong, ": "
    DO
      READ eePntr, char
      eePntr = eePntr + 1
      IF (char = 0) THEN EXIT
      DEBUG char
    LOOP
    DEBUG CR
  #ENDIF
  RETURN

' -------------------------------------------------------------------------

' Resets the markers variable based on the number of declared songs
' -- up to 16

Reset_Markers:
  markers = $FFFF                               ' mark all played
  FOR idx = 1 TO NumSongs
    markers = markers << 1                      ' clear available songs
  NEXT
  RETURN