Advertisement
AnatolySharapov

DFMiniMp3.h

Sep 13th, 2021
282
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.38 KB | None | 0 0
  1. /*-------------------------------------------------------------------------
  2. DFMiniMp3 library
  3.  
  4. Written by Michael C. Miller.
  5.  
  6. I invest time and resources providing this open source code,
  7. please support me by dontating (see https://github.com/Makuna/DFMiniMp3)
  8.  
  9. -------------------------------------------------------------------------
  10. This file is part of the Makuna/DFMiniMp3 library.
  11.  
  12. DFMiniMp3 is free software: you can redistribute it and/or modify
  13. it under the terms of the GNU Lesser General Public License as
  14. published by the Free Software Foundation, either version 3 of
  15. the License, or (at your option) any later version.
  16.  
  17. DFMiniMp3 is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. GNU Lesser General Public License for more details.
  21.  
  22. You should have received a copy of the GNU Lesser General Public
  23. License along with DFMiniMp3.  If not, see
  24. <http://www.gnu.org/licenses/>.
  25. -------------------------------------------------------------------------*/
  26. #pragma once
  27.  
  28. enum DfMp3_Error
  29. {
  30.     // from device
  31.     DfMp3_Error_Busy = 1,
  32.     DfMp3_Error_Sleeping,
  33.     DfMp3_Error_SerialWrongStack,
  34.     DfMp3_Error_CheckSumNotMatch,
  35.     DfMp3_Error_FileIndexOut,
  36.     DfMp3_Error_FileMismatch,
  37.     DfMp3_Error_Advertise,
  38.     // from library
  39.     DfMp3_Error_RxTimeout = 0x81,
  40.     DfMp3_Error_PacketSize,
  41.     DfMp3_Error_PacketHeader,
  42.     DfMp3_Error_PacketChecksum,
  43.     DfMp3_Error_General = 0xff
  44. };
  45.  
  46.  
  47. enum DfMp3_PlaybackMode
  48. {
  49.     DfMp3_PlaybackMode_Repeat,
  50.     DfMp3_PlaybackMode_FolderRepeat,
  51.     DfMp3_PlaybackMode_SingleRepeat,
  52.     DfMp3_PlaybackMode_Random
  53. };
  54.  
  55.  
  56. enum DfMp3_Eq
  57. {
  58.     DfMp3_Eq_Normal,
  59.     DfMp3_Eq_Pop,
  60.     DfMp3_Eq_Rock,
  61.     DfMp3_Eq_Jazz,
  62.     DfMp3_Eq_Classic,
  63.     DfMp3_Eq_Bass
  64. };
  65.  
  66. enum DfMp3_PlaySource // value - only one can be set
  67. {
  68.     DfMp3_PlaySource_Usb = 1,
  69.     DfMp3_PlaySource_Sd,
  70.     DfMp3_PlaySource_Aux,
  71.     DfMp3_PlaySource_Sleep,
  72.     DfMp3_PlaySource_Flash
  73. };
  74.  
  75. enum DfMp3_PlaySources // bitfield - more than one can be set
  76. {
  77.     DfMp3_PlaySources_Usb = 0x01,
  78.     DfMp3_PlaySources_Sd = 0x02,
  79.     DfMp3_PlaySources_Pc = 0x04,
  80.     DfMp3_PlaySources_Flash = 0x08,
  81. };
  82.  
  83.  
  84. template<class T_SERIAL_METHOD, class T_NOTIFICATION_METHOD> class DFMiniMp3
  85. {
  86. public:
  87.     explicit DFMiniMp3(T_SERIAL_METHOD& serial) :
  88.         _serial(serial),
  89.         _lastSendSpace(c_msSendSpace),
  90.         _isOnline(false)
  91.     {
  92.     }
  93.  
  94.     void begin(unsigned long baud = 9600)
  95.     {
  96.         _serial.begin(baud);
  97.         _serial.setTimeout(10000);
  98.         _lastSend = millis();
  99.     }
  100.  
  101.     void loop()
  102.     {
  103.         while (_serial.available() >= DfMp3_Packet_SIZE)
  104.         {
  105.             listenForReply(0x00);
  106.         }
  107.     }
  108.  
  109.     // Does not work with all models.
  110.     // YX5200-24SS - sends reply
  111.     // MH2024K-24SS - sends NO reply --> results in error notification
  112.     DfMp3_PlaySources getPlaySources()
  113.     {
  114.         drainResponses();
  115.         sendPacket(0x3f);
  116.         return static_cast<DfMp3_PlaySources>(listenForReply(0x3f));
  117.     }
  118.  
  119.     // the track as enumerated across all folders
  120.     void playGlobalTrack(uint16_t track = 0)
  121.     {
  122.         sendPacket(0x03, track);
  123.     }
  124.  
  125.     // sd:/mp3/####track name
  126.     void playMp3FolderTrack(uint16_t track)
  127.     {
  128.         sendPacket(0x12, track);
  129.     }
  130.  
  131.     // older devices: sd:/###/###track name
  132.     // newer devices: sd:/##/###track name
  133.     // folder and track numbers are zero padded
  134.     void playFolderTrack(uint8_t folder, uint8_t track)
  135.     {
  136.         uint16_t arg = (folder << 8) | track;
  137.         sendPacket(0x0f, arg);
  138.     }
  139.  
  140.     // sd:/##/####track name
  141.     // track number must be four digits, zero padded
  142.     void playFolderTrack16(uint8_t folder, uint16_t track)
  143.     {
  144.         uint16_t arg = (((uint16_t)folder) << 12) | track;
  145.         sendPacket(0x14, arg);
  146.     }
  147.  
  148.     void playRandomTrackFromAll()
  149.     {
  150.         sendPacket(0x18);
  151.     }
  152.  
  153.     void nextTrack()
  154.     {
  155.         sendPacket(0x01);
  156.     }
  157.  
  158.     void prevTrack()
  159.     {
  160.         sendPacket(0x02);
  161.     }
  162.  
  163.     uint16_t getCurrentTrack(DfMp3_PlaySource source = DfMp3_PlaySource_Sd)
  164.     {
  165.         drainResponses();
  166.  
  167.         uint8_t command;
  168.         uint16_t reply;
  169.  
  170.         switch (source)
  171.         {
  172.         case DfMp3_PlaySource_Usb:
  173.             command = 0x4b;
  174.             break;
  175.         case DfMp3_PlaySource_Sd:
  176.             command = 0x4c;
  177.             break;
  178.         case DfMp3_PlaySource_Flash:
  179.             command = 0x4d;
  180.             break;
  181.         default:
  182.             command = 0x4c;
  183.             break;
  184.         }
  185.  
  186.         sendPacket(command);
  187.         Serial.print("getCurrentTrack sent command = ");
  188.         Serial.print(command);        
  189.         reply = listenForReply(command);
  190.         Serial.print(" and received reply = ");
  191.         Serial.println(reply);
  192.         return reply;    
  193.        
  194.     }
  195.  
  196.     // 0- 30
  197.     void setVolume(uint8_t volume)
  198.     {
  199.         sendPacket(0x06, volume);
  200.     }
  201.  
  202.     uint8_t getVolume()
  203.     {
  204.         drainResponses();
  205.         sendPacket(0x43);
  206.         return static_cast<uint8_t>(listenForReply(0x43));
  207.     }
  208.  
  209.     void increaseVolume()
  210.     {
  211.         sendPacket(0x04);
  212.     }
  213.  
  214.     void decreaseVolume()
  215.     {
  216.         sendPacket(0x05);
  217.     }
  218.  
  219.     void loopGlobalTrack(uint16_t globalTrack)
  220.     {
  221.         sendPacket(0x08, globalTrack);
  222.     }
  223.  
  224.     // sd:/##/*
  225.     // 0-99
  226.     void loopFolder(uint8_t folder)
  227.     {
  228.         sendPacket(0x17, folder);
  229.     }
  230.  
  231.     DfMp3_PlaybackMode getPlaybackMode()
  232.     {
  233.         drainResponses();
  234.         sendPacket(0x45);
  235.         return static_cast<DfMp3_PlaybackMode>(listenForReply(0x45));
  236.     }
  237.  
  238.     void setRepeatPlayAllInRoot(bool repeat)
  239.     {
  240.         sendPacket(0x11, !!repeat);
  241.     }
  242.  
  243.     void setRepeatPlayCurrentTrack(bool repeat)
  244.     {
  245.         sendPacket(0x19, !repeat);
  246.     }
  247.  
  248.     void setEq(DfMp3_Eq eq)
  249.     {
  250.         sendPacket(0x07, eq);
  251.     }
  252.  
  253.     DfMp3_Eq getEq()
  254.     {
  255.         drainResponses();
  256.         sendPacket(0x44);
  257.         return static_cast<DfMp3_Eq>(listenForReply(0x44));
  258.     }
  259.  
  260.  
  261.     void setPlaybackSource(DfMp3_PlaySource source)
  262.     {
  263.         sendPacket(0x09, source, 200);
  264.     }
  265.  
  266.     void sleep()
  267.     {
  268.         sendPacket(0x0a);
  269.     }
  270.  
  271.     void reset()
  272.     {
  273.         sendPacket(0x0c, 0, 600);
  274.         _isOnline = false;
  275.     }
  276.  
  277.     void start()
  278.     {
  279.         sendPacket(0x0d);
  280.     }
  281.  
  282.     void pause()
  283.     {
  284.         sendPacket(0x0e);
  285.     }
  286.  
  287.     void stop()
  288.     {
  289.         sendPacket(0x16);
  290.     }
  291.  
  292.     uint16_t getStatus()
  293.     {
  294.         drainResponses();
  295.         sendPacket(0x42);
  296.         return listenForReply(0x42);
  297.     }
  298.  
  299.     uint16_t getFolderTrackCount(uint16_t folder)
  300.     {
  301.         drainResponses();
  302.         sendPacket(0x4e, folder);
  303.         return listenForReply(0x4e);
  304.     }
  305.  
  306.     uint16_t getTotalTrackCount(DfMp3_PlaySource source)
  307.     {
  308.         drainResponses();
  309.  
  310.         uint8_t command;
  311.  
  312.         switch (source)
  313.         {
  314.         case DfMp3_PlaySource_Usb:
  315.             command = 0x47;
  316.             break;
  317.         case DfMp3_PlaySource_Sd:
  318.             command = 0x48;
  319.             break;
  320.         case DfMp3_PlaySource_Flash:
  321.             command = 0x49;
  322.             break;
  323.         default:
  324.             command = 0x48;
  325.             break;
  326.         }
  327.  
  328.         sendPacket(command);
  329.         return listenForReply(command);
  330.     }
  331.  
  332.     uint16_t getTotalFolderCount()
  333.     {
  334.         drainResponses();
  335.         sendPacket(0x4F);
  336.         return listenForReply(0x4F);
  337.     }
  338.  
  339.     // sd:/advert/####track name
  340.     void playAdvertisement(uint16_t track)
  341.     {
  342.         sendPacket(0x13, track);
  343.     }
  344.  
  345.     void stopAdvertisement()
  346.     {
  347.         sendPacket(0x15);
  348.     }
  349.  
  350.     void enableDac()
  351.     {
  352.         sendPacket(0x1A, 0x00);
  353.     }
  354.  
  355.     void disableDac()
  356.     {
  357.         sendPacket(0x1A, 0x01);
  358.     }
  359.  
  360.     bool isOnline() const
  361.     {
  362.         return _isOnline;
  363.     }
  364.  
  365. private:
  366.     static const uint16_t c_msSendSpace = 50;
  367.  
  368.     // 7E FF 06 0F 00 01 01 xx xx EF
  369.     // 0    ->  7E is start code
  370.     // 1    ->  FF is version
  371.     // 2    ->  06 is length
  372.     // 3    ->  0F is command
  373.     // 4    ->  00 is no receive
  374.     // 5~6  ->  01 01 is argument
  375.     // 7~8  ->  checksum = 0 - ( FF+06+0F+00+01+01 )
  376.     // 9    ->  EF is end code
  377.     enum DfMp3_Packet
  378.     {
  379.         DfMp3_Packet_StartCode,
  380.         DfMp3_Packet_Version,
  381.         DfMp3_Packet_Length,
  382.         DfMp3_Packet_Command,
  383.         DfMp3_Packet_RequestAck,
  384.         DfMp3_Packet_HiByteArgument,
  385.         DfMp3_Packet_LowByteArgument,
  386.         DfMp3_Packet_HiByteCheckSum,
  387.         DfMp3_Packet_LowByteCheckSum,
  388.         DfMp3_Packet_EndCode,
  389.         DfMp3_Packet_SIZE
  390.     };
  391.  
  392.  
  393.     T_SERIAL_METHOD& _serial;
  394.     uint32_t _lastSend; // not initialized as agreed in issue #63
  395.     uint16_t _lastSendSpace;
  396.     bool _isOnline;
  397.  
  398.     void drainResponses()
  399.     {
  400.         while (_serial.available() > 0)
  401.         {
  402.             listenForReply(0x00);
  403.         }
  404.     }
  405.  
  406.     void sendPacket(uint8_t command, uint16_t arg = 0, uint16_t sendSpaceNeeded = c_msSendSpace)
  407.     {
  408.         uint8_t out[DfMp3_Packet_SIZE] = { 0x7E,
  409.             0xFF,
  410.             06,
  411.             command,
  412.             00,
  413.             static_cast<uint8_t>(arg >> 8),
  414.             static_cast<uint8_t>(arg & 0x00ff),
  415.             00,
  416.             00,
  417.             0xEF };
  418.  
  419.         setChecksum(out);
  420.  
  421.         // wait for spacing since last send
  422.         while (((millis() - _lastSend) < _lastSendSpace))
  423.         {
  424.             // check for event messages from the device while
  425.             // we wait
  426.             loop();
  427.             delay(1);
  428.         }
  429.  
  430.         _lastSendSpace = sendSpaceNeeded;
  431.         _serial.write(out, DfMp3_Packet_SIZE);
  432.  
  433.         _lastSend = millis();
  434.     }
  435.  
  436.     bool readPacket(uint8_t* command, uint16_t* argument)
  437.     {
  438.         uint8_t in[DfMp3_Packet_SIZE] = { 0 };
  439.         uint8_t read;
  440.  
  441.         // init our out args always
  442.         *command = 0;
  443.         *argument = 0;
  444.  
  445.         // try to sync our reads to the packet start
  446.         do
  447.         {
  448.             // we use readBytes as it gives us the standard timeout
  449.             read = _serial.readBytes(&(in[DfMp3_Packet_StartCode]), 1);
  450.  
  451.             if (read != 1)
  452.             {
  453.                 // nothing read
  454.                 *argument = DfMp3_Error_RxTimeout;
  455.  
  456.                 return false;
  457.             }
  458.         } while (in[DfMp3_Packet_StartCode] != 0x7e);
  459.  
  460.         read += _serial.readBytes(in + 1, DfMp3_Packet_SIZE - 1);
  461.         if (read < DfMp3_Packet_SIZE)
  462.         {
  463.             // not enough bytes, corrupted packet
  464.             *argument = DfMp3_Error_PacketSize;
  465.             return false;
  466.         }
  467.  
  468.         if (in[DfMp3_Packet_Version] != 0xFF ||
  469.             in[DfMp3_Packet_Length] != 0x06 ||
  470.             in[DfMp3_Packet_EndCode] != 0xef)
  471.         {
  472.             // invalid version or corrupted packet
  473.             *argument = DfMp3_Error_PacketHeader;
  474.             return false;
  475.         }
  476.  
  477.         if (!validateChecksum(in))
  478.         {
  479.             // checksum failed, corrupted packet
  480.             *argument = DfMp3_Error_PacketChecksum;
  481.             return false;
  482.         }
  483.  
  484.         *command = in[DfMp3_Packet_Command];
  485.         *argument = ((in[DfMp3_Packet_HiByteArgument] << 8) | in[DfMp3_Packet_LowByteArgument]);
  486.  
  487.         return true;
  488.     }
  489.  
  490.     uint16_t listenForReply(uint8_t command)
  491.     {
  492.         uint8_t replyCommand = 0;
  493.         uint16_t replyArg = 0;
  494.  
  495.         do
  496.         {
  497.             if (readPacket(&replyCommand, &replyArg))
  498.             {
  499.                 if (command != 0 && command == replyCommand)
  500.                 {
  501.                     return replyArg;
  502.                 }
  503.                 else
  504.                 {
  505.                     switch (replyCommand)
  506.                     {
  507.                     case 0x3c: // usb
  508.                         T_NOTIFICATION_METHOD::OnPlayFinished(*this, DfMp3_PlaySources_Usb, replyArg);
  509.                         break;
  510.  
  511.                     case 0x3d: // micro sd
  512.                         T_NOTIFICATION_METHOD::OnPlayFinished(*this, DfMp3_PlaySources_Sd, replyArg);
  513.                         break;
  514.  
  515.                     case 0x3e: // flash
  516.                         T_NOTIFICATION_METHOD::OnPlayFinished(*this, DfMp3_PlaySources_Flash, replyArg);
  517.                         break;
  518.  
  519.                     case 0x3F:
  520.                         _isOnline = true;
  521.                         T_NOTIFICATION_METHOD::OnPlaySourceOnline(*this, static_cast<DfMp3_PlaySources>(replyArg));
  522.                         break;
  523.  
  524.                     case 0x3A:
  525.                         _isOnline = true;
  526.                         T_NOTIFICATION_METHOD::OnPlaySourceInserted(*this, static_cast<DfMp3_PlaySources>(replyArg));
  527.                         break;
  528.  
  529.                     case 0x3B:
  530.                         _isOnline = true;
  531.                         T_NOTIFICATION_METHOD::OnPlaySourceRemoved(*this, static_cast<DfMp3_PlaySources>(replyArg));
  532.                         break;
  533.  
  534.                     case 0x40:
  535.                         T_NOTIFICATION_METHOD::OnError(*this, replyArg);
  536.                         return 0;
  537.                         break;
  538.  
  539.                     default:
  540.                         // unknown/unsupported command reply
  541.                         break;
  542.                     }
  543.                 }
  544.             }
  545.             else
  546.             {
  547.                 if (replyArg != 0)
  548.                 {
  549.                     T_NOTIFICATION_METHOD::OnError(*this, replyArg);
  550.                     if (_serial.available() == 0)
  551.                     {
  552.                         return 0;
  553.                     }
  554.                 }
  555.             }
  556.         } while (command != 0);
  557.  
  558.         return 0;
  559.     }
  560.  
  561.     uint16_t calcChecksum(uint8_t* packet)
  562.     {
  563.         uint16_t sum = 0;
  564.         for (int i = DfMp3_Packet_Version; i < DfMp3_Packet_HiByteCheckSum; i++)
  565.         {
  566.             sum += packet[i];
  567.         }
  568.         return -sum;
  569.     }
  570.  
  571.     void setChecksum(uint8_t* out)
  572.     {
  573.         uint16_t sum = calcChecksum(out);
  574.  
  575.         out[DfMp3_Packet_HiByteCheckSum] = (sum >> 8);
  576.         out[DfMp3_Packet_LowByteCheckSum] = (sum & 0xff);
  577.     }
  578.  
  579.     bool validateChecksum(uint8_t* in)
  580.     {
  581.         uint16_t sum = calcChecksum(in);
  582.         return (sum == static_cast<uint16_t>((in[DfMp3_Packet_HiByteCheckSum] << 8) | in[DfMp3_Packet_LowByteCheckSum]));
  583.     }
  584. };
  585.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement