Skip to content

Commit

Permalink
i2saudio esp8266 plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
gemu2015 committed Aug 2, 2024
1 parent 67a642f commit 15eef92
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 13 deletions.
20 changes: 16 additions & 4 deletions tasmota/Plugins/module_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,15 @@ extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
#define jspecial_malloc(A) (( void * (*)(uint32_t)) jt[151])(A)
#define jResponseCmndChar(A) (( void (*)(char *)) jt[152])(A)
#define jstrtol(A,B,C) (( int32_t (*)(char *,char **,size_t )) jt[153])(A,B,C)
#define judp(A,B,C,D) (( unt32_t (*)(void *,uint32_t,uint32_t,uint32_t )) jt[154])(A,B,C,D)
#define ji2s(A,B,C,D,E,F) (( unt32_t (*)(uint32_t,uint32_t,uint32_t,uint32_t,uint32_t,uint32_t )) jt[155])(A,B,C,D,E,F)
#define jtaskc(A,B,C,D,E,F,G) (( unt32_t (*)(uint32_t,uint32_t,uint32_t,uint32_t,uint32_t,uint32_t,uint32_t )) jt[156])(A,B,C,D,E,F,G)
#define jtaskd(A) (( unt32_t (*)(uint32_t)) jt[157])(A)
#define judp(A,B,C,D) (( uint32_t (*)(void *,uint32_t,uint32_t,uint32_t )) jt[154])(A,B,C,D)
#define ji2s(A,B,C,D,E,F) (( uint32_t (*)(uint32_t,uint32_t,uint32_t,uint32_t,uint32_t,uint32_t )) jt[155])(A,B,C,D,E,F)
#define jtaskc(A,B,C,D,E,F,G) (( uint32_t (*)(uint32_t,uint32_t,uint32_t,uint32_t,uint32_t,uint32_t,uint32_t )) jt[156])(A,B,C,D,E,F,G)
#define jtaskd(A) (( uint32_t (*)(uint32_t)) jt[157])(A)
#define jPlugin_Get_SensorNames(A,B) (( char *(*)(char *,uint32_t)) jt[158])(A,B)
#define GetScriptSection(A) (( char *(*)(char *)) jt[159])(A)
#define jfile_size(A) (( uint32_t (*)(void*)) jt[160])(A)
#define jfile_getpos(A) (( uint32_t (*)(void*)) jt[161])(A)
#define jOsWatchLoop() (( void (*)(void)) jt[162])

//tmod_udp,
//tmod_i2s,
Expand Down Expand Up @@ -762,6 +765,15 @@ typedef struct {

#define fread(A,B,C,D) jfile_read(D,A,B*C)
#define fwrite(A,B,C,D) jfile_write(D,A,B*C)
#define fsize(A) jfile_size(A)
#define fpos(A) jfile_getpos(A)
#define OsWatchLoop jOsWatchLoop

#define i2s_begin(A) ji2s(0,0,0,0,0,0)
#define i2s_end(A) ji2s(1,0,0,0,0,0)
#define i2s_set_rate(A) ji2s(2,A,0,0,0,0)
#define i2s_write_sample(A) ji2s(5,A,0,0,0,0)


#define CharToFloat jCharToFloat
#define AddLogData jAddLogData
Expand Down
181 changes: 181 additions & 0 deletions tasmota/Plugins/xdrv_42_i2s.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
xdrv_42_i2s.cpp - I2S audio support for Tasmota
Copyright (C) 2024 gemu2015
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "tasmota_options.h"

#ifdef USE_I2S_MOD
#define XDRV_42 42

#include "module.h"
#include "module_defines.h"

#define I2S_REV 1 << 16 | 4


PUSH_OPTIONS

MODULE_DESCRIPTOR("I2SAUDIO", MODULE_TYPE_DRIVER, I2S_REV, "", 0, "", 0, "", 0, "", 0)

// all functions must be declared MUDULE_PART
MODULE_PART int32_t I2SAudio_Init();
MODULE_PART void I2S_PlayWave(void);
MODULE_PART void I2SAudio_Deinit();
MODULE_PART int32_t mod_func_execute(uint32_t sel);
MODULE_END


typedef struct {
uint16_t dummy;
} MODULE_MEMORY;

int32_t I2SAudio_Init() {
ALLOCMEM

initialized = true;
return 0;
}

// RIFF header
typedef struct {
uint32_t ChunkID; //"RIFF"
uint32_t ChunkSize; //"36 + sizeof(wav_data_t) + data"
uint32_t Format; // "WAV"
} wav_riff_t;

// FMT header
typedef struct {
uint32_t Subchunk1ID; //"fmt "
uint32_t Subchunk1Size; //16 (PCM)
uint16_t AudioFormat; // 1 'cause PCM
uint16_t NumChannels; // mono = 1; stereo = 2
uint32_t SampleRate; // 8000, 44100, etc.
uint32_t ByteRate; //== SampleRate * NumChannels * byte
uint16_t BlockAlign; //== NumChannels * bytePerSample
uint16_t BytesPerSample; //8 byte = 8, 16 byte = 16, etc.
} wav_fmt_t;

// Data header
typedef struct {
uint32_t Subchunk2ID; //"data"
uint32_t Subchunk2Size; //== NumSamples * NumChannels * bytePerSample/8
} wav_data_t;


// complete header
typedef struct {
wav_riff_t Riff;
wav_fmt_t Fmt;
wav_data_t Data;
} wav_header_t;

const char S_JSON_FNF[] PROGMEM = "{\"File %s not found\"}";
const char S_JSON_ILLF[] PROGMEM = "{\"Illegal File format\"}";

void I2S_PlayWave(void) {
SETREGS

char *cp = XdrvMailbox->data;
while (*cp == ' ') cp++;

File_p *wf;
wf = fopen(cp, 'r');

if (!wf) {
// file not found
Response_P(GSTR(S_JSON_FNF), cp);
return;
}

int16_t buffer[512];

uint32_t fsize = fsize(wf);

// check for RIFF
fread((char*)buffer, 1, sizeof(wav_header_t), wf);

wav_header_t *wh = (wav_header_t *)buffer;
// 0x52494646
if (wh->Riff.ChunkID != 0x46464952 && wh->Fmt.NumChannels != 1) {
fclose(wf);
Response_P(GSTR(S_JSON_ILLF));
return;
}

// read rest of header we assume 1 channel 8 khz
fsize -= sizeof(wav_header_t);

i2s_begin();

i2s_set_rate(wh->Fmt.SampleRate);

//while (fpos(wf) < fsize) {
while (1) {
uint32_t bytesread = fread((char*)buffer, 1, sizeof(buffer), wf);
if (!bytesread) {
break;
}
for (uint32_t i = 0; i < bytesread / 2; i++) {
i2s_write_sample(buffer[i]);
OsWatchLoop();
}
}

i2s_end();

fclose(wf);

ResponseCmndDone();

return;
}



const char I2S_Commands[] PROGMEM =
"I2S|" // Prefix
"pw";
void (*const I2S_Command[])(void) PROGMEM = {&I2S_PlayWave};

void I2SAudio_Deinit() {
SETREGS
RETMEM
}

/*********************************************************************************************\
* Interface
\*********************************************************************************************/

static int32_t mod_func_execute(uint32_t sel) {
SETREGS
bool result = false;
switch (sel) {
case FUNC_INIT:
result = I2SAudio_Init();
break;
case FUNC_COMMAND:
result = DecodeCommand(I2S_Commands, I2S_Command);
break;
case FUNC_DEINIT:
I2SAudio_Deinit();
break;
}
return result;
}
PULL_OPTIONS
#endif // USE_I2S_MOD
32 changes: 23 additions & 9 deletions tasmota/tasmota_xdrv_driver/xdrv_123_plugins.ino
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ void tmod_file_close(class File *fp);
int32_t tmod_file_seek(class File *fp, uint32_t pos, uint32_t mode);
int32_t tmod_file_read(class File *fp, uint8_t *buff, uint32_t size);
int32_t tmod_file_write(class File *fp, uint8_t *buff, uint32_t size);
uint32_t tmod_file_size(class File *fp);
void tmod_AddLogData(uint32_t loglevel, const char* log_data);
char *Plugin_Get_SensorNames(char *type, uint32_t index);
char *tmod_Run_Scripter(char *sect);
Expand Down Expand Up @@ -368,7 +369,10 @@ void (* const MODULE_JUMPTABLE[])(void) PROGMEM = {
JMPTBL&tmod_dummy,
#endif
JMPTBL&Plugin_Get_SensorNames,
JMPTBL&tmod_Run_Scripter
JMPTBL&tmod_Run_Scripter,
JMPTBL&tmod_file_size,
JMPTBL&tmod_file_pos,
JMPTBL&OsWatchLoop
};


Expand Down Expand Up @@ -434,7 +438,7 @@ uint32_t tmod_i2s(uint32_t sel, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t
break;
case 2:
#ifdef ESP8266
i2s_set_rate(p2);
i2s_set_rate(p1);
#else
#if ESP_IDF_VERSION_MAJOR >= 5
#else
Expand Down Expand Up @@ -473,13 +477,7 @@ uint32_t tmod_i2s(uint32_t sel, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t
#endif
case 5:
#ifdef ESP8266
{
int16_t *mono = (int16_t*)p2;
for (uint32_t cnt = 0; cnt < (p3 >> 1); cnt++) {
i2s_write_sample(*mono++);
}
*(uint32_t*)p4 = (p3 << 1);
}
i2s_write_sample(p1);
#endif // ESP8266
break;
}
Expand Down Expand Up @@ -614,6 +612,22 @@ int32_t tmod_file_write(class File *fp, uint8_t *buff, uint32_t size) {
#endif
}

uint32_t tmod_file_size(class File *fp) {
#ifdef USE_UFILESYS
return fp->size();
#else
return 0;
#endif
}

uint32_t tmod_file_pos(class File *fp) {
#ifdef USE_UFILESYS
return fp->position();
#else
return 0;
#endif
}


SPIClass *tmod_getspi(uint8_t sel) {
if (!sel) {
Expand Down

0 comments on commit 15eef92

Please sign in to comment.