1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-12-25 13:41:23 +01:00

Preliminary working version of I2CDFPlayer

Working, need some endurance testing and testing at scale
This commit is contained in:
kempe63 2023-11-12 12:14:02 +00:00
parent 22b066c400
commit 44ce1c0cfa

View File

@ -100,6 +100,8 @@ private:
uint8_t _requestedVolumeLevel = MAXVOLUME; uint8_t _requestedVolumeLevel = MAXVOLUME;
uint8_t _currentVolume = MAXVOLUME; uint8_t _currentVolume = MAXVOLUME;
int _requestedSong = -1; // -1=none, 0=stop, >0=file number int _requestedSong = -1; // -1=none, 0=stop, >0=file number
uint8_t _repeat;
uint8_t _previousCmd = true;
// SC16IS752 defines // SC16IS752 defines
I2CAddress _I2CAddress; I2CAddress _I2CAddress;
I2CRB _rb; I2CRB _rb;
@ -113,6 +115,7 @@ private:
uint8_t PRESCALER = 0x01; // Value MCR bit 7 uint8_t PRESCALER = 0x01; // Value MCR bit 7
uint8_t TEMP_REG_VAL = 0x00; uint8_t TEMP_REG_VAL = 0x00;
uint8_t FIFO_RX_LEVEL = 0x00; uint8_t FIFO_RX_LEVEL = 0x00;
uint8_t RX_BUFFER = 0x00; // nr of bytes copied into _inbuffer
uint8_t FIFO_TX_LEVEL = 0x00; uint8_t FIFO_TX_LEVEL = 0x00;
uint8_t _outbuffer [11]; // DFPlayer command is 10 bytes + 1 byte register address & UART channel uint8_t _outbuffer [11]; // DFPlayer command is 10 bytes + 1 byte register address & UART channel
uint8_t _inbuffer[10]; // expected DFPlayer return 10 bytes uint8_t _inbuffer[10]; // expected DFPlayer return 10 bytes
@ -128,10 +131,8 @@ public:
_I2CAddress = i2cAddress; _I2CAddress = i2cAddress;
_UART_CH = UART_CH; _UART_CH = UART_CH;
addDevice(this); addDevice(this);
} }
public: public:
static void create(VPIN firstVpin, int nPins, I2CAddress i2cAddress, uint8_t UART_CH) { static void create(VPIN firstVpin, int nPins, I2CAddress i2cAddress, uint8_t UART_CH) {
if (checkNoOverlap(firstVpin, nPins, i2cAddress)) new I2CDFPlayer(firstVpin, nPins, i2cAddress, UART_CH); if (checkNoOverlap(firstVpin, nPins, i2cAddress)) new I2CDFPlayer(firstVpin, nPins, i2cAddress, UART_CH);
@ -140,7 +141,7 @@ public:
void _begin() override { void _begin() override {
// check if SC16IS752 exist first, initialize and then resume DFPlayer init via SC16IS752 // check if SC16IS752 exist first, initialize and then resume DFPlayer init via SC16IS752
I2CManager.begin(); I2CManager.begin();
//I2CManager.setClock(1000000); I2CManager.setClock(1000000);
if (I2CManager.exists(_I2CAddress)){ if (I2CManager.exists(_I2CAddress)){
DIAG(F("SC16IS752 I2C:%s UART detected"), _I2CAddress.toString()); DIAG(F("SC16IS752 I2C:%s UART detected"), _I2CAddress.toString());
Init_SC16IS752(); // Initialize UART Init_SC16IS752(); // Initialize UART
@ -158,15 +159,16 @@ public:
_deviceState = DEVSTATE_INITIALISING; _deviceState = DEVSTATE_INITIALISING;
sendPacket(0x42); sendPacket(0x42);
_timeoutTime = micros() + 5000000UL; // 5 second timeout _timeoutTime = micros() + 5000000UL; // 5 second timeout
//_timeoutTime = micros() + 10000000UL; // 5 second timeout
_awaitingResponse = true; _awaitingResponse = true;
} }
void _loop(unsigned long currentMicros) override { void _loop(unsigned long currentMicros) override {
// Read responses from device // Read responses from device
uint8_t status = _rb.status;
processIncoming(); if (status == I2C_STATUS_PENDING) return; // Busy, so don't do anything
if (status == I2C_STATUS_OK) {
processIncoming(currentMicros);
// Check if a command sent to device has timed out. Allow 0.5 second for response // Check if a command sent to device has timed out. Allow 0.5 second for response
if (_awaitingResponse && (int32_t)(currentMicros - _timeoutTime) > 0) { if (_awaitingResponse && (int32_t)(currentMicros - _timeoutTime) > 0) {
DIAG(F("I2CDFPlayer:%s, DFPlayer not responding on UART channel: 0x%x"), _I2CAddress.toString(), _UART_CH); DIAG(F("I2CDFPlayer:%s, DFPlayer not responding on UART channel: 0x%x"), _I2CAddress.toString(), _UART_CH);
@ -174,29 +176,54 @@ public:
_awaitingResponse = false; _awaitingResponse = false;
_playing = false; _playing = false;
} }
}
status = _rb.status;
if (status == I2C_STATUS_PENDING) return; // Busy, try next time
if (status == I2C_STATUS_OK) {
// Send any commands that need to go. // Send any commands that need to go.
processOutgoing(currentMicros); processOutgoing(currentMicros);
}
delayUntil(currentMicros + 10000); // Only enter every 10ms delayUntil(currentMicros + 10000); // Only enter every 10ms
} }
// Check for incoming data on _serial, and update busy flag and other state accordingly // Check for incoming data on _serial, and update busy flag and other state accordingly
void processIncoming() { void processIncoming(unsigned long currentMicros) {
// Expected message is in the form "7E FF 06 3D xx xx xx xx xx EF" // Expected message is in the form "7E FF 06 3D xx xx xx xx xx EF"
RX_fifo_lvl(); RX_fifo_lvl();
if (FIFO_RX_LEVEL >= 10) { if (FIFO_RX_LEVEL >= 10) {
#ifdef DIAG_I2CDFplayer #ifdef DIAG_I2CDFplayer
DIAG(F("I2CDFPlayer: %s Retrieving data from RX Fifo on UART_CH: 0x%x"),_I2CAddress.toString(), _UART_CH); DIAG(F("I2CDFPlayer: %s Retrieving data from RX Fifo on UART_CH: 0x%x FIFO_RX_LEVEL: %d"),_I2CAddress.toString(), _UART_CH, FIFO_RX_LEVEL);
#endif
_outbuffer[0] = REG_RHR << 3 | _UART_CH << 1;
// Only copy 10 bytes from RX FIFO, there maybe additional partial return data after a track is finished playing in the RX FIFO
I2CManager.read(_I2CAddress, _inbuffer, 10, _outbuffer, 1); // inbuffer[] has the data now
//delayUntil(currentMicros + 10000); // Allow time to get the data
RX_BUFFER = 10; // We have copied 10 bytes from RX FIFO to _inbuffer
#ifdef DIAG_I2CDFplayer_data
DIAG(F("SC16IS752: At I2C: %s, UART channel: 0x%x, RX FIFO Data"), _I2CAddress.toString(), _UART_CH);
for (int i = 0; i < sizeof _inbuffer; i++){
DIAG(F("SC16IS752: Data _inbuffer[0x%x]: 0x%x"), i, _inbuffer[i]);
}
#endif #endif
ReceiveI2CData();
} else { } else {
FIFO_RX_LEVEL = 0; //set to 0, we'll read a fresh FIFO_RX_LEVEL next time
return; // No data or not enough data in rx fifo, check again next time around return; // No data or not enough data in rx fifo, check again next time around
} }
/*
#ifdef DIAG_I2CDFplayer
if (FIFO_RX_LEVEL > 10) {
DIAG(F("I2CDFPlayer: %s FIFO_RX_LEVEL: %d"),_I2CAddress.toString(), FIFO_RX_LEVEL);
}
#endif
*/
bool ok = false; bool ok = false;
while (FIFO_RX_LEVEL != 0) { //DIAG(F("I2CDFPlayer: RX_BUFFER: %d"), RX_BUFFER);
while (RX_BUFFER != 0) {
int c = _inbuffer[_inputIndex]; // Start at 0, increment to FIFO_RX_LEVEL int c = _inbuffer[_inputIndex]; // Start at 0, increment to FIFO_RX_LEVEL
switch (_inputIndex) { switch (_inputIndex) {
case 0: case 0:
@ -214,6 +241,7 @@ public:
break; break;
case 6: case 6:
switch (_recvCMD) { switch (_recvCMD) {
DIAG(F("I2CDFPlayer: %s, _recvCMD: 0x%x _awaitingResponse: 0x0%x"),_I2CAddress.toString(), _recvCMD, _awaitingResponse);
case 0x42: case 0x42:
// Response to status query // Response to status query
_playing = (c != 0); _playing = (c != 0);
@ -259,12 +287,13 @@ public:
} }
if (ok){ if (ok){
_inputIndex++; // character as expected, so increment index _inputIndex++; // character as expected, so increment index
FIFO_RX_LEVEL --; // Decrease FIFO_RX_LEVEL with each character read from _inbuffer[_inputIndex] RX_BUFFER --; // Decrease FIFO_RX_LEVEL with each character read from _inbuffer[_inputIndex]
} else { } else {
_inputIndex = 0; // otherwise reset. _inputIndex = 0; // otherwise reset.
FIFO_RX_LEVEL = 0; RX_BUFFER = 0;
} }
} }
RX_BUFFER = 0; //Set to 0, we'll read a new RX FIFO level again
} }
// Send any commands that need to be sent // Send any commands that need to be sent
@ -328,14 +357,13 @@ public:
// If value is zero, the player stops playing. // If value is zero, the player stops playing.
// WriteAnalogue on second pin sets the output volume. // WriteAnalogue on second pin sets the output volume.
// //
void _writeAnalogue(VPIN vpin, int value, uint8_t volume=0, uint16_t=0) override { //void _writeAnalogue(VPIN vpin, int value, uint8_t volume=0, uint16_t=0) override {
void _writeAnalogue(VPIN vpin, int value, uint8_t volume=0, uint16_t cmd=0) override {
if (_deviceState == DEVSTATE_FAILED) return; if (_deviceState == DEVSTATE_FAILED) return;
uint8_t pin = vpin - _firstVpin; uint8_t pin = vpin - _firstVpin;
#ifdef DIAG_IO #ifdef DIAG_IO
DIAG(F("I2CDFPlayer: VPIN:%u FileNo:%d Volume:%d"), vpin, value, volume); DIAG(F("I2CDFPlayer: VPIN:%u FileNo:%d Volume:%d Repeat:0x0%x"), vpin, value, volume, cmd);
#endif #endif
// Validate parameter. // Validate parameter.
if (volume > MAXVOLUME) volume = MAXVOLUME; if (volume > MAXVOLUME) volume = MAXVOLUME;
@ -345,6 +373,11 @@ public:
if (volume > 0) if (volume > 0)
_requestedVolumeLevel = volume; _requestedVolumeLevel = volume;
_requestedSong = value; _requestedSong = value;
if (cmd = 1){ // check for Repeat playback of song
_repeat = true;
} else {
_repeat = false;
}
_playing = true; _playing = true;
} else { } else {
_requestedSong = 0; // stop playing _requestedSong = 0; // stop playing
@ -410,8 +443,8 @@ private:
TX_fifo_lvl(); TX_fifo_lvl();
if(FIFO_TX_LEVEL > 0){ //FIFO is empty if(FIFO_TX_LEVEL > 0){ //FIFO is empty
//I2CManager.write(_I2CAddress, _outbuffer, sizeof(_outbuffer), &_rb); I2CManager.write(_I2CAddress, _outbuffer, sizeof(_outbuffer), &_rb);
I2CManager.write(_I2CAddress, _outbuffer, sizeof(_outbuffer)); //I2CManager.write(_I2CAddress, _outbuffer, sizeof(_outbuffer));
#ifdef DIAG_I2CDFplayer #ifdef DIAG_I2CDFplayer
DIAG(F("SC16IS752: I2C: %s data transmit complete on UART: 0x%x"), _I2CAddress.toString(), _UART_CH); DIAG(F("SC16IS752: I2C: %s data transmit complete on UART: 0x%x"), _I2CAddress.toString(), _UART_CH);
#endif #endif
@ -472,13 +505,13 @@ private:
TEMP_REG_VAL = _inbuffer[0] & 0x7F; // Disable Divisor latch enabled bit TEMP_REG_VAL = _inbuffer[0] & 0x7F; // Disable Divisor latch enabled bit
UART_WriteRegister(REG_LCR, TEMP_REG_VAL); // Divisor latch disabled UART_WriteRegister(REG_LCR, TEMP_REG_VAL); // Divisor latch disabled
uint8_t status = _rb.wait(); uint8_t status = _rb.status;
if (status != I2C_STATUS_OK) { if (status != I2C_STATUS_OK) {
DIAG(F("SC16IS752: I2C: %s failed %S"), _I2CAddress.toString(), I2CManager.getErrorMessage(status)); DIAG(F("SC16IS752: I2C: %s failed %S"), _I2CAddress.toString(), I2CManager.getErrorMessage(status));
_deviceState = DEVSTATE_FAILED; _deviceState = DEVSTATE_FAILED;
} else { } else {
#ifdef DIAG_IO #ifdef DIAG_IO
DIAG(F("SC16IS752: I2C: %s, _deviceState == I2C_STATUS_OK"), _I2CAddress.toString()); DIAG(F("SC16IS752: I2C: %s, _deviceState: %S"), _I2CAddress.toString(), I2CManager.getErrorMessage(status));
#endif #endif
_deviceState = DEVSTATE_NORMAL; // If I2C state is OK, then proceed to initialize DFPlayer _deviceState = DEVSTATE_NORMAL; // If I2C state is OK, then proceed to initialize DFPlayer
} }
@ -493,7 +526,7 @@ private:
FIFO_RX_LEVEL = _inbuffer[0]; FIFO_RX_LEVEL = _inbuffer[0];
#ifdef DIAG_I2CDFplayer #ifdef DIAG_I2CDFplayer
if (FIFO_RX_LEVEL > 0){ if (FIFO_RX_LEVEL > 0){
DIAG(F("SC16IS752: At I2C: %s, UART channel: 0x%x, RX FIFO Level: 0d%d"), _I2CAddress.toString(), _UART_CH, _inbuffer[0]); // DIAG(F("SC16IS752: At I2C: %s, UART channel: 0x%x, FIFO_RX_LEVEL: 0d%d"), _I2CAddress.toString(), _UART_CH, _inbuffer[0]);
} }
#endif #endif
} }
@ -506,25 +539,10 @@ private:
UART_ReadRegister(REG_TXLV); UART_ReadRegister(REG_TXLV);
FIFO_TX_LEVEL = _inbuffer[0]; FIFO_TX_LEVEL = _inbuffer[0];
#ifdef DIAG_I2CDFplayer #ifdef DIAG_I2CDFplayer
DIAG(F("SC16IS752: At I2C: %s, UART channel: 0x%x, TX FIFO Level: 0d%d"), _I2CAddress.toString(), _UART_CH, FIFO_TX_LEVEL); // DIAG(F("SC16IS752: At I2C: %s, UART channel: 0x%x, FIFO_TX_LEVEL: 0d%d"), _I2CAddress.toString(), _UART_CH, FIFO_TX_LEVEL);
#endif #endif
} }
// Read from RX FIFO, we know the register REG_RHR
void ReceiveI2CData(){
//_inbuffer[0] = 0x00;
_outbuffer[0] = REG_RHR << 3 | _UART_CH << 1;
//I2CManager.read(_I2CAddress, _inbuffer, FIFO_RX_LEVEL, _outbuffer, 1, &_rb); // inbuffer[] has the data now
I2CManager.read(_I2CAddress, _inbuffer, FIFO_RX_LEVEL, _outbuffer, 1); // _inbuffer[] has the data now
#ifdef DIAG_I2CDFplayer_data
DIAG(F("SC16IS752: At I2C: %s, UART channel: 0x%x, RX FIFO Data"), _I2CAddress.toString(), _UART_CH);
for (int i = 0; i < sizeof _inbuffer; i++){
DIAG(F("SC16IS752: Data _inbuffer[0x%x]: 0x%x"), i, _inbuffer[i]);
}
#endif
}
//void UART_WriteRegister(I2CAddress _I2CAddress, uint8_t _UART_CH, uint8_t UART_REG, uint8_t Val, I2CRB &_rb){ //void UART_WriteRegister(I2CAddress _I2CAddress, uint8_t _UART_CH, uint8_t UART_REG, uint8_t Val, I2CRB &_rb){
void UART_WriteRegister(uint8_t UART_REG, uint8_t Val){ void UART_WriteRegister(uint8_t UART_REG, uint8_t Val){