diff --git a/ports/gprs_a9/Makefile b/ports/gprs_a9/Makefile index 72110df05be70..ed1b204794d55 100644 --- a/ports/gprs_a9/Makefile +++ b/ports/gprs_a9/Makefile @@ -139,6 +139,7 @@ SRC_C = \ modgps.c \ modusocket.c \ modi2c.c \ + modaudio.c \ machine_adc.c \ machine_uart.c \ machine_rtc.c diff --git a/ports/gprs_a9/main.c b/ports/gprs_a9/main.c index 012029e09e2e3..bec8b8b79eb55 100644 --- a/ports/gprs_a9/main.c +++ b/ports/gprs_a9/main.c @@ -242,6 +242,14 @@ void EventDispatch(API_Event_t* pEvent) modmachine_notify_power_on(pEvent); break; + case API_EVENT_ID_KEY_DOWN: + modmachine_notify_power_key_down(pEvent); + break; + + case API_EVENT_ID_KEY_UP: + modmachine_notify_power_key_up(pEvent); + break; + // Network // ======= diff --git a/ports/gprs_a9/modaudio.c b/ports/gprs_a9/modaudio.c new file mode 100644 index 0000000000000..ae48dacb5ade6 --- /dev/null +++ b/ports/gprs_a9/modaudio.c @@ -0,0 +1,197 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * Development of the code in this file was sponsored by Microbric Pty Ltd + * + * The MIT License (MIT) + * + * Copyright (c) 2020 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "timeout.h" +#include "api_os.h" +#include "api_audio.h" +#include "api_fs.h" +#include "py/runtime.h" + +uint8_t audioVolume = 5; +int audioRecordFd = -1; + + +STATIC mp_obj_t modaudio_record_start(size_t n_args, const mp_obj_t *args) { + // ======================================== + // Audio Record. + // Args: + // filename (str): output file name with full path + // channel (int): audio channel (default 2, AUDIO_MODE_LOUDSPEAKER) + // type (int): audio type (default 3, AUDIO_TYPE_AMR) + // mode (int): audio mode (default 7, AUDIO_RECORD_MODE_AMR122) + // ======================================== + + const char* filename; + int channel = AUDIO_MODE_LOUDSPEAKER; + int type = AUDIO_TYPE_AMR; + int mode = AUDIO_RECORD_MODE_AMR122; + + if (n_args > 0) { + filename = mp_obj_str_get_str(args[0]); + } else { + mp_raise_ValueError("filename is mandatory"); + return mp_const_none; + } + if (n_args >= 2) { + channel = mp_obj_get_int(args[1]); + } + if (n_args >= 3) { + type = mp_obj_get_int(args[2]); + } + if (n_args >= 4) { + mode = mp_obj_get_int(args[3]); + } + Trace(1,"audio record start, filename: %s, channel: %d, type: %d, mode: %d", filename, channel, type, mode); + audioRecordFd = API_FS_Open(filename,FS_O_WRONLY|FS_O_CREAT|FS_O_TRUNC,0); + if (audioRecordFd < 0) { + Trace(1,"audio open file error"); + mp_raise_ValueError("file open error"); + return mp_const_none; + } + AUDIO_SetMode(channel); + AUDIO_Error_t result = AUDIO_RecordStart(type, mode, audioRecordFd, NULL, NULL); + if (result != AUDIO_ERROR_NO) { + Trace(1,"audio record start fail: %d",result); + API_FS_Close(audioRecordFd); + audioRecordFd = -1; + mp_raise_ValueError("cannot record audio file"); + return mp_const_none; + } + Trace(1,"recording"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modaudio_record_start_obj, 1, 4, modaudio_record_start); + + +STATIC mp_obj_t modaudio_record_stop(void) { + //Stop recording audio + AUDIO_RecordStop(); + API_FS_Close(audioRecordFd); + audioRecordFd = -1; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modaudio_record_stop_obj, modaudio_record_stop); + + +void audioPlayCallback(AUDIO_Error_t result) { + Trace(1,"audio play callback result: %d",result); + AUDIO_Stop(); +} + + +STATIC mp_obj_t modaudio_play_start(size_t n_args, const mp_obj_t *args) { + // ======================================== + // Audio Play. + // Args: + // filename (str): input file name with full path + // volume (int): (default 5) + // channel (int): audio channel (default 2, AUDIO_MODE_LOUDSPEAKER) + // type (int): audio type (default 3, AUDIO_TYPE_AMR) + // ======================================== + + const char* filename; + int volume = audioVolume; + int channel = AUDIO_MODE_LOUDSPEAKER; + int type = AUDIO_TYPE_AMR; + + if (n_args > 0) { + filename = mp_obj_str_get_str(args[0]); + } else { + mp_raise_ValueError("filename is mandatory"); + return mp_const_none; + } + if (n_args >= 2) { + volume = mp_obj_get_int(args[1]); + } + if (n_args >= 3) { + channel = mp_obj_get_int(args[2]); + } + if (n_args >= 4) { + type = mp_obj_get_int(args[3]); + } + Trace(1,"play start, filename: %s, volume: %d, channel: %d, type: %d", filename, volume, channel, type); + AUDIO_Error_t result = AUDIO_Play(filename, type, audioPlayCallback); + if (result != AUDIO_ERROR_NO) { + AUDIO_Stop(); + Trace(1,"play fail: %d", result); + mp_raise_ValueError("cannot play audio file"); + return mp_const_none; + } else { + Trace(1,"playing"); + } + OS_Sleep(200); + AUDIO_SetMode(channel); + AUDIO_SpeakerOpen(); + AUDIO_SpeakerSetVolume(volume); + Trace(1,"playing"); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modaudio_play_start_obj, 1, 4, modaudio_play_start); + + +STATIC mp_obj_t modaudio_play_pause(void) { + //Pause audio play + AUDIO_Pause(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modaudio_play_pause_obj, modaudio_play_pause); + + +STATIC mp_obj_t modaudio_play_resume(void) { + //Resume playing after pause + //AUDIO_Resume(fileFd); //?AUDIO_Play doesn't have nor return a fileFd + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modaudio_play_resume_obj, modaudio_play_resume); + + +STATIC mp_obj_t modaudio_play_stop(void) { + //Stop playing audio + AUDIO_Stop(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modaudio_play_stop_obj, modaudio_play_stop); + + +STATIC const mp_map_elem_t mp_module_audio_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_audio) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_record_start), (mp_obj_t)&modaudio_record_start_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_record_stop), (mp_obj_t)&modaudio_record_stop_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_play_start), (mp_obj_t)&modaudio_play_start_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_play_stop), (mp_obj_t)&modaudio_play_stop_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_play_pause), (mp_obj_t)&modaudio_play_pause_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_play_resume), (mp_obj_t)&modaudio_play_resume_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_audio_globals, mp_module_audio_globals_table); + + +const mp_obj_module_t audio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_audio_globals, +}; diff --git a/ports/gprs_a9/modmachine.c b/ports/gprs_a9/modmachine.c index 40082c022a66f..2fa1071a255b0 100644 --- a/ports/gprs_a9/modmachine.c +++ b/ports/gprs_a9/modmachine.c @@ -41,12 +41,14 @@ #include "api_hal_adc.h" STATIC mp_obj_t modmachine_watchdog_off(void); +STATIC mp_obj_t power_key = mp_const_none; void modmachine_init0(void) { PM_SetSysMinFreq(PM_SYS_FREQ_312M); modmachine_watchdog_off(); modmachine_pin_init0(); modmachine_uart_init0(); + power_key = mp_const_none; } // ------ @@ -203,6 +205,30 @@ STATIC mp_obj_t modmachine_watchdog_reset(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_0(modmachine_watchdog_reset_obj, modmachine_watchdog_reset); +void modmachine_notify_power_key_down(API_Event_t* event) { + if (power_key && power_key != mp_const_none) { + mp_sched_schedule(power_key, mp_obj_new_int(1)); + } +} + +void modmachine_notify_power_key_up(API_Event_t* event) { + if (power_key && power_key != mp_const_none) { + mp_sched_schedule(power_key, mp_obj_new_int(0)); + } +} + +STATIC mp_obj_t modmachine_on_power_key(mp_obj_t callable) { + // ======================================== + // Sets a callback on power key press. + // Args: + // callback (Callable): a callback to + // execute on power key press. + // ======================================== + power_key = callable; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modmachine_on_power_key_obj, modmachine_on_power_key); + STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, @@ -213,6 +239,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_set_idle), (mp_obj_t)&modmachine_set_idle_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_set_min_freq), (mp_obj_t)&modmachine_set_min_freq_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_power_on_cause), (mp_obj_t)&modmachine_power_on_cause_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_on_power_key), (mp_obj_t)&modmachine_on_power_key_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_off), (mp_obj_t)&modmachine_off_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_get_input_voltage), (mp_obj_t)&modmachine_get_input_voltage_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_watchdog_on), (mp_obj_t)&modmachine_watchdog_on_obj }, diff --git a/ports/gprs_a9/modmachine.h b/ports/gprs_a9/modmachine.h index abcfc12559758..2cd34d5a4cea0 100644 --- a/ports/gprs_a9/modmachine.h +++ b/ports/gprs_a9/modmachine.h @@ -51,3 +51,5 @@ void modmachine_uart_init0(void); void modmachine_init0(void); void modmachine_notify_power_on(API_Event_t* event); +void modmachine_notify_power_key_down(API_Event_t* event); +void modmachine_notify_power_key_up(API_Event_t* event); \ No newline at end of file diff --git a/ports/gprs_a9/mpconfigport.h b/ports/gprs_a9/mpconfigport.h index d3d0cbb24b324..84ab9618fe0c0 100644 --- a/ports/gprs_a9/mpconfigport.h +++ b/ports/gprs_a9/mpconfigport.h @@ -212,6 +212,7 @@ extern const struct _mp_obj_module_t cellular_module; extern const struct _mp_obj_module_t gps_module; extern const struct _mp_obj_module_t usocket_module; extern const struct _mp_obj_module_t i2c_module; +extern const struct _mp_obj_module_t audio_module; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ @@ -222,6 +223,7 @@ extern const struct _mp_obj_module_t i2c_module; { MP_OBJ_NEW_QSTR(MP_QSTR_gps), (mp_obj_t)&gps_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&usocket_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_i2c), (mp_obj_t)&i2c_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_audio), (mp_obj_t)&audio_module }, \ // type definitions for the specific machine