diff --git a/esp32/dfplayer.py b/esp32/dfplayer.py new file mode 100644 index 0000000..11f8363 --- /dev/null +++ b/esp32/dfplayer.py @@ -0,0 +1,201 @@ +#Driver for DFPlayer mini, MP3 player with SD card slot, using serial communication. + +#See documentation at: +# https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299 + +#0 Each command starts with byte 0x7E +#1 Version # (set to 0xFF) +#2 The number of bytes which follow (6, Not including checksum and termination) +#3 The command to execute +#4 Feedback indicator (0: no, 1: yes) +#5 Argument high byte +#6 Argument low byte +#7-8 2 byte checksum +#9 Termination byte 0xEF + +#Commands +#The next and prev commands wrap when they hit the end of the list. +#0x01 next +#0x02 prev +#0x03 Track # 0-2999 +#0x04 volume + +#0x05 volume - +#0x06 volume #0-30 +#0x07 equalizer 0-5 (Normal, Pop, Rock, Jazz, Classical, Base) +#0x08 playback mode 0-3 (Repeat, folder repeat, single repeat, random) +#0x09 playback source 0-3 (U, TF, AUX, SLEEP, FLASH) +#0x0A sleep mode +#0x0B Normal mode +#0x0C reset +#0x0D play/resume +#0x0E pause +#0x0F specify folder 1-10 +#0x10 volume adjust (High byte = Open volume adjust, Low byte = volume gain 0-31) +#0x11 repeat 0 = stop, 1 = repeat. + +#Query commands +#0x3F Send init parameters 0-0x0F. +#0x41 Reply. The command byte is set to this on a reply read from the dfplayer as a reply if +# the the feedback indicator was set on the command. Not very useful. +#0x42 status +#0x43 volume +#0x44 eq +#0x45 playback mode +#0x46 software version +#0x47 # of TF card files +#0x48 # of SD card files +#0x49 # of flash files +#0x4A Keep on ? +#0x4B Current TF card track +#0x4C Current SD card track +#0x4D Current flash track + +#Results - These are sent as replies to certain commands. +#0x3D Result of play, next, prev (param hi/lo is current file index) + +# Folders are named 01, 02..99. Files 001, 002 ... 999. + +from machine import UART +from time import sleep_ms + +class dfplayer(UART) : + + _WAIT = const(10) + + '''Initialize dfplayer at given UART 0-2''' + def __init__(self, aUART, aBaud = 9600) : + super(dfplayer, self).__init__(aUART, aBaud) + self._buffer = bytearray(10) + self._buffer[0] = 0x7E #commands always start with these bytes. + self._buffer[1] = 0xFF #Version # + self._buffer[2] = 6 #Commands are always 6 bytes + self._buffer[4] = 0 #We never want results returned. (0x41) This is just an ack we don't use. + self._buffer[9] = 0xEF #Command terminator. + self._readbuffer = bytearray(20) + + def _clear( self ) : + while self.any() : + self.readinto(self._readbuffer) + + def _cmd( self, aCommand, aArg = 0 ) : + '''Send aCommand to hc05 with given argument.''' + self._buffer[3] = aCommand + self._buffer[5] = aArg >> 8 + self._buffer[6] = aArg + + cs = 0 + for i in range(1, 7) : + cs -= self._buffer[i] + + #Set the checksum. + self._buffer[7] = cs >> 8 + self._buffer[8] = cs + + self._clear() #Make sure return buffer is empty. + self.write(self._buffer) + + @property + def readbuffer( self ): + return self._readbuffer + + def result( self ) : + '''Wait for result and return # of bytes read. Result is in _readbuffer.''' + for i in range(1, 100) : + if self.any() : + return self.readinto(self._readbuffer) + sleep_ms(_WAIT) + + return 0 + + def resultnum( self ) : + '''Read result, then pull 16 bit # from it.''' + res = self.result() + if res >= 10 : + return (self._readbuffer[5] << 8 | self._readbuffer[6]) + return 0 + + def printres( self ) : + '''Print result as string of hex values.''' + b = self.result() + for i in range(0, b) : + print(str(hex(self._readbuffer[i])) + ',', end='') + print('/') + + def next( self ) : + '''Play next song.''' + self._cmd(1) + + def prev( self ) : + '''Play previous song.''' + self._cmd(2) + + def play( self, aIndex ) : + '''Play song at given index.''' + self._cmd(3, aIndex) + + def volume( self, aLevel ) : + '''Set volume to absolute value.''' + self._cmd(6, aLevel & 0x1E) + + def qvolume( self ) : + self._cmd(0x43) + return self.resultnum() + + def equalizer( self, aArg ) : + '''Set equalizer type. (Normal, Pop, Rock, Jazz, Classical, Base)''' + self._cmd(7, aArg) + + def qequalizer( self ) : + self._cmd(0x44) + return self.resultnum() + + def qsdfiles( self ) : + '''return # of files on sd card.''' + self._cmd(0x48) + return self.resultnum() + + def qsdtrack( self ) : + '''return current sd card track #.''' + self._cmd(0x4C) + return self.resultnum() + + def qflashfiles( self ) : + '''return # of files in flash memory.''' + self._cmd(0x49) + return self.resultnum() + + def qflashtrack( self ) : + '''return current flash track #.''' + self._cmd(0x4D) + return self.resultnum() + + def sleep( self, abSleep ) : + '''Set/clear low power mode.''' + self._cmd(0xA if abSleep else 0xB) + + def reset( self ) : + '''Reset the device.''' + self._cmd(0x0C) + + def pause( self, abTF ) : + '''Pause or resume play.''' + p = 0x0E if abTF else 0x0D + self._cmd(0x0E) + + def folder( self, aDir ) : + '''Specify folder.''' + self._cmd(0x0F, aDir) + + def folderandfile( self, aFolder, aFile ) : + '''Play specified file in specified folder.''' + self._cmd(0x12, (aFolder << 8) | aFile) + + def playback( self, aMode ) : + '''Set playback mode: 0-Repeat, 1-Folder repeat, 2-Single repeat, 3-Random''' + self._cmd(8, aMode) + + def source( self, aSource ) : + '''Set play source, 0-SD, 1-TF, 2-AUX, 3-SLEEP, 4-FLASH. + I don't know what TF, AUX or SLEEP are.''' + self._cmd(9, aSource) + diff --git a/esp32/jq6500.py b/esp32/jq6500.py new file mode 100644 index 0000000..825f462 --- /dev/null +++ b/esp32/jq6500.py @@ -0,0 +1,101 @@ +#Driver for JQ6500 MP3 player, using serial communication. + +#See documentation at: +# https://www.elecfreaks.com/wiki/index.php?title=JQ6500_Mini_MP3_Module +# http://sparks.gogo.co.nz/jq6500/index.html + +#Each command starts with byte 0x7E +#Followed by a byte indicating the number of bytes which follow including the terminating byte (including termination) +#Followed by a byte indicating the command to execute +#Followed by an optional first argument byte +#Followed by an optional second argument byte +#Followed by the byte 0xEF as the termination byte + +#The next and prev commands wrap when they hit the end of the list. +#next (play next song) 0x7E 02 01 EF +#prev (play prev song) 0x7E 02 02 EF +#play song at index nn = 1-?? 0x7E 04 03 nn nn EF. +#volume+ 0x7E 02 04 EF +#volume- 0x7E 02 05 EF +#assigned volume nn = 0-30 0x7E 03 06 nn EF +#assigned eq nn (0-5) 0x7E 03 07 nn EF +# Eq values are Normal, Pop, Rock, Jazz, Classical, Base +#sleep mode 0x7E 02 0A EF +#chip reset 0x7E 02 0C EF +#play 0x7E 02 0D EF +#pause 0x7E 02 0E EF +#next/pref folder 1 = next, 0 = prev 0x7E 03 0F nn EF +#play folder/file (mm,nn) 0x7E 04 12 mm nn EF +# Folders are named 01, 02..99. Files 001, 002 ... 999. + +from machine import UART + +class jq6500(UART): + '''Initialize jq6500 at given UART 0-2''' + def __init__(self, aUART, aBaud = 9600): + super(jq6500, self).__init__(aUART, aBaud) + self._buffer = bytearray(8) + self._buffer[0] = 0x7E #commands always start with this. + + def _write( self, *aCommand ) : + '''Write command bytes to device.''' + i = 2 #Commands are always at least 2 in length. + for v in aCommand : + self._buffer[i] = v + i += 1 + + self._buffer[1] = i - 1 #Set length of command string. + self._buffer[i] = 0xEF #Put terminator at end of command string. + self.write(self._buffer) + +# def next( self ) : +# '''Play next song.''' +# self._write(01) +# +# def prev( self ) : +# '''Play previous song.''' +# self._write(02) + + def play( self, aIndex ) : + '''Play song at given index.''' + self._write(03, aIndex >> 8, aIndex) + +# def volumechange( self, aDir ) : +# '''Adjust volume up/down by given amount.''' +# if aDir < 0 : +# d = 4 +# aDir = -aDir +# else: +# d = 5 +# for x in range(0, aDir): +# self._write(d) + + def volume( self, aLevel ) : + '''Set volume to absolute value.''' + self._write(06, aLevel & 0x1E) + + def equalizer( self, aArg ) : + '''Set equalizer type. (Normal, Pop, Rock, Jazz, Classical, Base)''' + self._write(07, aArg) + + def sleep( self ) : + '''Go into low power mode.''' + self._write(0x0A) + +# def reset( self ) : +# '''Reset the device.''' +# self._write(0x0C) +# +# def pause( self, abTF ) : +# '''Pause or resume play.''' +# p = 0x0E if abTF else 0x0D +# self._write(0x0E) +# +# def nextfolder( self, aDir ) : +# '''Next folder.''' +# self.write(0x0F, 1 if aDir else 0) +# +# def folderandfile( self, aFolder, aFile ) : +# '''Play specified file in specified folder.''' +# self.write(12, aFolder, aFile) + diff --git a/esp32/quicrun.py b/esp32/quicrun.py new file mode 100644 index 0000000..01dbab1 --- /dev/null +++ b/esp32/quicrun.py @@ -0,0 +1,64 @@ +# Controller for the quicrun 1060 Electronic Speed Control (ESP) +#This controller works through the pca9865 servo controller. + +from time import sleep_ms + +#todo: May need to move speed values over time if the battery cannot handle it. + +class quicrun(object): + '''docstring for quicrun''' + _STOP = const(50) + _FORWARD_MAX = const(68) + _FORWARD_MIN = const(52) + _BACKWARD_MAX = const(30) + _BACKWARD_MIN = const(48) + _BACKWARD_INIT = const(45) + + @staticmethod + def getperc( aMin, aMax, aPerc ) : + return (((aMax - aMin) * aPerc) // 100) + aMin + + def __init__(self, aPCA, aIndex): + '''aPCA = pca9865 object to use for PWM control of the ESC. + aIndex = Servo index on pca9865 (0-15). + ''' + super(quicrun, self).__init__() + self._pca = aPCA + self._index = aIndex + self.reset() + + def reset( self ) : + self._pca.set(self._index, 75) + sleep_ms(500) + self._pca.set(self._index, 100) + sleep_ms(500) + self._pca.set(self._index, _STOP) + self._curspeed = 0 + + def _set( self, aValue ) : + self._pca.set(self._index, aValue) + + def _reverse( self ) : + if self._currspeed >= 0 : + self._set(_STOP) + sleep_ms(100) + self._set(_BACKWARD_INIT) + sleep_ms(100) + self._set(_STOP) + sleep_ms(100) + + def speed( self, aSpeed ) : + '''Set speed -100 to 100.''' + aSpeed = max(min(100, aSpeed), -100) + + if aSpeed == 0 : + self._set(_STOP) + else: + if aSpeed > 0 : + self._set(quicrun.getperc(_FORWARD_MIN, _FORWARD_MAX, aSpeed)) + else: + self._reverse() + self._set(quicrun.getperc(_BACKWARD_MAX, _BACKWARD_MIN, 100 + aSpeed)) + + self._currspeed = aSpeed +