From 008799dc520218ecb96a782feb145b37b842862a Mon Sep 17 00:00:00 2001 From: dean Date: Wed, 31 Oct 2018 18:27:08 -0400 Subject: DM: adding mixer gain --- shared-module/audioio/Mixer.c | 84 +++++++++++++++++++++++++++++++++++++++++++ shared-module/audioio/Mixer.h | 1 + 2 files changed, 85 insertions(+) (limited to 'shared-module') diff --git a/shared-module/audioio/Mixer.c b/shared-module/audioio/Mixer.c index 8020a621e..a6ce1937b 100644 --- a/shared-module/audioio/Mixer.c +++ b/shared-module/audioio/Mixer.c @@ -61,6 +61,7 @@ void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, for (uint8_t i = 0; i < self->voice_count; i++) { self->voice[i].sample = NULL; + self->voice[i].gain = ((1<<15)-1); } } @@ -131,6 +132,11 @@ void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, } } +void common_hal_audioio_mixer_set_gain(audioio_mixer_obj_t* self, uint8_t voice, float gain) { + audioio_mixer_voice_t* v = &self->voice[voice]; + v->gain = gain * ((1 << 15)-1); +} + uint32_t add8signed(uint32_t a, uint32_t b) { #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) return __QADD8(a, b); @@ -215,6 +221,68 @@ uint32_t add16unsigned(uint32_t a, uint32_t b) { #endif } +//TODO: +static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return val; + val = __USUB8(val, 0x80808080); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 4; i++) { + int8_t ai = (val >> (sizeof(uint8_t) * 8 * i)) - 128; + } + return result; + #endif +} + +//TODO: +static inline uint32_t mult8signed(uint32_t val, int32_t mul) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return val; + #else + uint32_t result = 0; + for (int8_t i = 0; i < 4; i++) { + int8_t ai = val >> (sizeof(int8_t) * 8 * i); + } + return result; + #endif +} + +//TODO: +static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return val; + val = __USUB16(val, 0x80008000); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 2; i++) { + int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + } + return result; + #endif +} + +static inline uint32_t mult16signed(uint32_t val, int32_t mul) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + int32_t hi, lo; + int32_t bits = 16; // saturate to 16 bits + int32_t shift = 0; // shift is done automatically + asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); + asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); + asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack + return val; + #else + uint32_t result = 0; + //TODO: + for (int8_t i = 0; i < 2; i++) { + int16_t ai = val >> (sizeof(int16_t) * 8 * i); + } + return result; + #endif +} + audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, bool single_channel, uint8_t channel, @@ -285,6 +353,22 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, sample_value = voice->remaining_buffer[j]; } + // apply the mixer gain + if (!self->samples_signed) { + if (self->bits_per_sample == 8) { + sample_value = mult8unsigned(sample_value, voice->gain); + } else { + sample_value = mult16unsigned(sample_value, voice->gain); + } + } + else{ + if (self->bits_per_sample == 8) { + sample_value = mult8signed(sample_value, voice->gain); + } else { + sample_value = mult16signed(sample_value, voice->gain); + } + } + if (!voices_active) { word_buffer[i] = sample_value; } else { diff --git a/shared-module/audioio/Mixer.h b/shared-module/audioio/Mixer.h index 6a88fe0bd..a48793a8f 100644 --- a/shared-module/audioio/Mixer.h +++ b/shared-module/audioio/Mixer.h @@ -37,6 +37,7 @@ typedef struct { bool more_data; uint32_t* remaining_buffer; uint32_t buffer_length; + int16_t gain; } audioio_mixer_voice_t; typedef struct { -- cgit v1.2.3 From 59c6ed34fdb7312de4747110d6a40f67a8787f13 Mon Sep 17 00:00:00 2001 From: dean Date: Wed, 14 Nov 2018 18:05:29 -0500 Subject: DM: mixer voice object skeleton --- .../boards/trellis_m4_express/mpconfigboard.mk | 2 +- shared-bindings/audioio/Mixer.c | 242 ++++++++++++++++++--- shared-bindings/audioio/Mixer.h | 10 + shared-module/audioio/Mixer.c | 6 +- shared-module/audioio/Mixer.h | 4 +- 5 files changed, 231 insertions(+), 33 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/trellis_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/trellis_m4_express/mpconfigboard.mk index 3841a87c7..4d923bafd 100644 --- a/ports/atmel-samd/boards/trellis_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/trellis_m4_express/mpconfigboard.mk @@ -1,4 +1,4 @@ -LD_FILE = boards/samd51x19-bootloader-external-flash.ld +LD_FILE = boards/samd51x19-external-flash.ld USB_VID = 0x239A USB_PID = 0x8030 USB_PRODUCT = "Trellis M4 Express" diff --git a/shared-bindings/audioio/Mixer.c b/shared-bindings/audioio/Mixer.c index a20e95b3b..c07c05bc1 100644 --- a/shared-bindings/audioio/Mixer.c +++ b/shared-bindings/audioio/Mixer.c @@ -106,7 +106,7 @@ STATIC mp_obj_t audioio_mixer_make_new(const mp_obj_type_t *type, size_t n_args, if (bits_per_sample != 8 && bits_per_sample != 16) { mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); } - audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, audioio_mixer_voice_t, voice_count); + audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, audioio_mixer_voice_obj_t, voice_count); self->base.type = &audioio_mixer_type; common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); @@ -190,13 +190,190 @@ STATIC mp_obj_t audioio_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *pos_ } MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_stop_voice_obj, 1, audioio_mixer_obj_stop_voice); +//| .. attribute:: playing +//| +//| True when any voice is being output. (read-only) +//| +STATIC mp_obj_t audioio_mixer_obj_get_playing(mp_obj_t self_in) { + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_playing_obj, audioio_mixer_obj_get_playing); + +const mp_obj_property_t audioio_mixer_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixer_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: sample_rate +//| +//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). +//| +STATIC mp_obj_t audioio_mixer_obj_get_sample_rate(mp_obj_t self_in) { + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_mixer_get_sample_rate(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_sample_rate_obj, audioio_mixer_obj_get_sample_rate); + +const mp_obj_property_t audioio_mixer_sample_rate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixer_get_sample_rate_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. currentmodule:: audioio +//| +//| :class:`Mixer` -- Mixes one or more audio samples together +//| =========================================================== +//| +//| Mixer mixes multiple samples into one sample. +//| +//| .. class:: Mixer(channel_count=2, buffer_size=1024) +//| +//| Create a Mixer object that can mix multiple channels with the same sample rate. +//| +//| :param int channel_count: The maximum number of samples to mix at once +//| :param int buffer_size: The total size in bytes of the buffers to mix into +//| +STATIC mp_obj_t audioio_mixer_voice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { +#if 0 + mp_arg_check_num(n_args, n_kw, 0, 2, true); + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + enum { ARG_voice_count, ARG_buffer_size, ARG_channel_count, ARG_bits_per_sample, ARG_samples_signed, ARG_sample_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t voice_count = args[ARG_voice_count].u_int; + if (voice_count < 1 || voice_count > 255) { + mp_raise_ValueError(translate("Invalid voice count")); + } + + mp_int_t channel_count = args[ARG_channel_count].u_int; + if (channel_count < 1 || channel_count > 2) { + mp_raise_ValueError(translate("Invalid channel count")); + } + mp_int_t sample_rate = args[ARG_sample_rate].u_int; + if (sample_rate < 1) { + mp_raise_ValueError(translate("Sample rate must be positive")); + } + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); + } + audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, audioio_mixer_voice_obj_t, voice_count); + self->base.type = &audioio_mixer_type; + common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + + return MP_OBJ_FROM_PTR(self); +#endif + return mp_const_none; +} + +//| .. method:: deinit() +//| +//| Deinitialises the Voice and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audioio_mixer_voice_deinit(mp_obj_t self_in) { +#if 0 + audioio_mixer_voice_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audioio_mixer_voice_deinit(self); +#endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_voice_deinit_obj, audioio_mixer_voice_deinit); + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audioio_mixer_voice_obj___exit__(size_t n_args, const mp_obj_t *args) { +#if 0 + (void)n_args; + common_hal_audioio_mixer_voice_deinit(args[0]); +#endif + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer_voice___exit___obj, 4, 4, audioio_mixer_voice_obj___exit__); + + +//| .. method:: play(sample, *, loop=False) +//| +//| Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. +//| +//| The sample must match the Mixer's encoding settings given in the constructor. +//| +STATIC mp_obj_t audioio_mixer_voice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +#if 0 + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audioio_mixer_voice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + raise_error_if_deinited(common_hal_audioio_mixer_voice_deinited(self)); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audioio_mixer_play(self, sample, self->u_int, args[ARG_loop].u_ool); +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_voice_play_obj, 1, audioio_mixer_voice_obj_play); + +//| .. method:: stop_voice() +//| +//| Stops playback of the sample on this voice. +//| +STATIC mp_obj_t audioio_mixer_voice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +#if 0 + enum { ARG_voice }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, + }; + audioio_mixer_voice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_voice_stop_obj, 1, audioio_mixer_voice_obj_stop); + //| .. method:: set_gain(voice, gain) //| //| Set the gain of a voice. //| //| gain must be a floating point number between 0 and 1 //| -STATIC mp_obj_t audioio_mixer_obj_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +STATIC mp_obj_t audioio_mixer_voice_obj_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +#if 0 enum { ARG_voice, ARG_gain }; static const mp_arg_t allowed_args[] = { { MP_QSTR_voice, MP_ARG_INT | MP_ARG_REQUIRED }, @@ -218,44 +395,35 @@ STATIC mp_obj_t audioio_mixer_obj_set_gain(size_t n_args, const mp_obj_t *pos_ar } common_hal_audioio_mixer_set_gain(self,args[ARG_voice].u_int, gain); - +#endif return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_set_gain_obj, 1, audioio_mixer_obj_set_gain); +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_voice_set_gain_obj, 1, audioio_mixer_voice_obj_set_gain); -//| .. attribute:: playing -//| -//| True when any voice is being output. (read-only) -//| -STATIC mp_obj_t audioio_mixer_obj_get_playing(mp_obj_t self_in) { - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_playing_obj, audioio_mixer_obj_get_playing); - -const mp_obj_property_t audioio_mixer_playing_obj = { +const mp_obj_property_t audioio_mixer_voice_gain_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_get_playing_obj, - (mp_obj_t)&mp_const_none_obj, + .proxy = {(mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&audioio_mixer_voice_set_gain_obj, (mp_obj_t)&mp_const_none_obj}, }; -//| .. attribute:: sample_rate +//| .. attribute:: playing //| -//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). +//| True when any voice is being output. (read-only) //| -STATIC mp_obj_t audioio_mixer_obj_get_sample_rate(mp_obj_t self_in) { +STATIC mp_obj_t audioio_mixer_voice_obj_get_playing(mp_obj_t self_in) { +#if 0 audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_mixer_get_sample_rate(self)); + return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); +#endif + return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_sample_rate_obj, audioio_mixer_obj_get_sample_rate); - +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_voice_get_playing_obj, audioio_mixer_voice_obj_get_playing); -const mp_obj_property_t audioio_mixer_sample_rate_obj = { +const mp_obj_property_t audioio_mixer_voice_playing_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_get_sample_rate_obj, + .proxy = {(mp_obj_t)&audioio_mixer_voice_get_playing_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; @@ -267,7 +435,6 @@ STATIC const mp_rom_map_elem_t audioio_mixer_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixer___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixer_play_obj) }, { MP_ROM_QSTR(MP_QSTR_stop_voice), MP_ROM_PTR(&audioio_mixer_stop_voice_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_gain), MP_ROM_PTR(&audioio_mixer_set_gain_obj) }, // Properties { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_playing_obj) }, @@ -281,3 +448,24 @@ const mp_obj_type_t audioio_mixer_type = { .make_new = audioio_mixer_make_new, .locals_dict = (mp_obj_dict_t*)&audioio_mixer_locals_dict, }; + +STATIC const mp_rom_map_elem_t audioio_mixer_voice_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixer_voice_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixer_voice___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixer_voice_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_mixer_voice_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_voice_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_gain), MP_ROM_PTR(&audioio_mixer_voice_gain_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audioio_mixer_voice_locals_dict, audioio_mixer_voice_locals_dict_table); + +const mp_obj_type_t audioio_mixer_voice_type = { + { &mp_type_type }, + .name = MP_QSTR_Mixer_Voice, + .make_new = audioio_mixer_voice_make_new, + .locals_dict = (mp_obj_dict_t*)&audioio_mixer_voice_locals_dict, +}; diff --git a/shared-bindings/audioio/Mixer.h b/shared-bindings/audioio/Mixer.h index 11ca2aac5..52fb9bdc9 100644 --- a/shared-bindings/audioio/Mixer.h +++ b/shared-bindings/audioio/Mixer.h @@ -32,6 +32,7 @@ #include "shared-bindings/audioio/RawSample.h" extern const mp_obj_type_t audioio_mixer_type; +extern const mp_obj_type_t audioio_mixer_voice_type; void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, uint8_t voice_count, @@ -47,7 +48,16 @@ void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, u void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice); void common_hal_audioio_mixer_set_gain(audioio_mixer_obj_t* self, uint8_t voice, float gain); + bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self); +void common_hal_audioio_mixer_voice_deinit(audioio_mixer_voice_obj_t* self); +bool common_hal_audioio_mixer_voice_deinited(audioio_mixer_voice_obj_t* self); +void common_hal_audioio_mixer_voice_play(audioio_mixer_voice_obj_t* self, mp_obj_t sample, bool loop); +void common_hal_audioio_mixer_voice_stop_voice(audioio_mixer_voice_obj_t* self); +void common_hal_audioio_mixer_voice_set_gain(audioio_mixer_voice_obj_t* self, float gain); + +bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H diff --git a/shared-module/audioio/Mixer.c b/shared-module/audioio/Mixer.c index a6ce1937b..5125574ef 100644 --- a/shared-module/audioio/Mixer.c +++ b/shared-module/audioio/Mixer.c @@ -100,7 +100,7 @@ void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, u if (samples_signed != self->samples_signed) { mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); } - audioio_mixer_voice_t* voice = &self->voice[v]; + audioio_mixer_voice_obj_t* voice = &self->voice[v]; voice->sample = sample; voice->loop = loop; @@ -133,7 +133,7 @@ void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, } void common_hal_audioio_mixer_set_gain(audioio_mixer_obj_t* self, uint8_t voice, float gain) { - audioio_mixer_voice_t* v = &self->voice[voice]; + audioio_mixer_voice_obj_t* v = &self->voice[voice]; v->gain = gain * ((1 << 15)-1); } @@ -311,7 +311,7 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, self->use_first_buffer = !self->use_first_buffer; bool voices_active = false; for (int32_t v = 0; v < self->voice_count; v++) { - audioio_mixer_voice_t* voice = &self->voice[v]; + audioio_mixer_voice_obj_t* voice = &self->voice[v]; uint32_t j = 0; bool voice_done = voice->sample == NULL; diff --git a/shared-module/audioio/Mixer.h b/shared-module/audioio/Mixer.h index a48793a8f..3451aa25d 100644 --- a/shared-module/audioio/Mixer.h +++ b/shared-module/audioio/Mixer.h @@ -38,7 +38,7 @@ typedef struct { uint32_t* remaining_buffer; uint32_t buffer_length; int16_t gain; -} audioio_mixer_voice_t; +} audioio_mixer_voice_obj_t; typedef struct { mp_obj_base_t base; @@ -56,7 +56,7 @@ typedef struct { uint32_t right_read_count; uint8_t voice_count; - audioio_mixer_voice_t voice[]; + audioio_mixer_voice_obj_t voice[]; } audioio_mixer_obj_t; -- cgit v1.2.3 From dd05aafb9bcbfeae77ce8b21b425b26e67891082 Mon Sep 17 00:00:00 2001 From: dean Date: Thu, 15 Nov 2018 14:11:45 -0500 Subject: DM: adding mixer voice API --- shared-bindings/audioio/Mixer.c | 223 ++--------------------------------- shared-bindings/audioio/Mixer.h | 10 +- shared-bindings/audioio/MixerVoice.c | 196 ++++++++++++++++++++++++++++++ shared-bindings/audioio/MixerVoice.h | 38 ++++++ shared-module/audioio/Mixer.c | 9 +- shared-module/audioio/Mixer.h | 12 +- shared-module/audioio/MixerVoice.c | 18 +++ shared-module/audioio/MixerVoice.h | 12 ++ 8 files changed, 279 insertions(+), 239 deletions(-) create mode 100644 shared-bindings/audioio/MixerVoice.c create mode 100644 shared-bindings/audioio/MixerVoice.h create mode 100644 shared-module/audioio/MixerVoice.c create mode 100644 shared-module/audioio/MixerVoice.h (limited to 'shared-module') diff --git a/shared-bindings/audioio/Mixer.c b/shared-bindings/audioio/Mixer.c index c07c05bc1..baf86c803 100644 --- a/shared-bindings/audioio/Mixer.c +++ b/shared-bindings/audioio/Mixer.c @@ -106,7 +106,7 @@ STATIC mp_obj_t audioio_mixer_make_new(const mp_obj_type_t *type, size_t n_args, if (bits_per_sample != 8 && bits_per_sample != 16) { mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); } - audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, audioio_mixer_voice_obj_t, voice_count); + audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, mp_obj_t, voice_count); self->base.type = &audioio_mixer_type; common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); @@ -226,208 +226,25 @@ const mp_obj_property_t audioio_mixer_sample_rate_obj = { (mp_obj_t)&mp_const_none_obj}, }; -//| .. currentmodule:: audioio -//| -//| :class:`Mixer` -- Mixes one or more audio samples together -//| =========================================================== -//| -//| Mixer mixes multiple samples into one sample. -//| -//| .. class:: Mixer(channel_count=2, buffer_size=1024) -//| -//| Create a Mixer object that can mix multiple channels with the same sample rate. -//| -//| :param int channel_count: The maximum number of samples to mix at once -//| :param int buffer_size: The total size in bytes of the buffers to mix into -//| -STATIC mp_obj_t audioio_mixer_voice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { -#if 0 - mp_arg_check_num(n_args, n_kw, 0, 2, true); - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); - enum { ARG_voice_count, ARG_buffer_size, ARG_channel_count, ARG_bits_per_sample, ARG_samples_signed, ARG_sample_rate }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, - { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, - { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, - { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, - { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, - { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_int_t voice_count = args[ARG_voice_count].u_int; - if (voice_count < 1 || voice_count > 255) { - mp_raise_ValueError(translate("Invalid voice count")); - } - - mp_int_t channel_count = args[ARG_channel_count].u_int; - if (channel_count < 1 || channel_count > 2) { - mp_raise_ValueError(translate("Invalid channel count")); - } - mp_int_t sample_rate = args[ARG_sample_rate].u_int; - if (sample_rate < 1) { - mp_raise_ValueError(translate("Sample rate must be positive")); - } - mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; - if (bits_per_sample != 8 && bits_per_sample != 16) { - mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); - } - audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, audioio_mixer_voice_obj_t, voice_count); - self->base.type = &audioio_mixer_type; - common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); - - return MP_OBJ_FROM_PTR(self); -#endif - return mp_const_none; -} - -//| .. method:: deinit() -//| -//| Deinitialises the Voice and releases any hardware resources for reuse. -//| -STATIC mp_obj_t audioio_mixer_voice_deinit(mp_obj_t self_in) { -#if 0 - audioio_mixer_voice_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audioio_mixer_voice_deinit(self); -#endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_voice_deinit_obj, audioio_mixer_voice_deinit); - -//| .. method:: __enter__() -//| -//| No-op used by Context Managers. -//| -// Provided by context manager helper. - -//| .. method:: __exit__() -//| -//| Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info. -//| -STATIC mp_obj_t audioio_mixer_voice_obj___exit__(size_t n_args, const mp_obj_t *args) { -#if 0 - (void)n_args; - common_hal_audioio_mixer_voice_deinit(args[0]); -#endif - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer_voice___exit___obj, 4, 4, audioio_mixer_voice_obj___exit__); - - -//| .. method:: play(sample, *, loop=False) -//| -//| Plays the sample once when loop=False and continuously when loop=True. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. -//| -//| The sample must match the Mixer's encoding settings given in the constructor. -//| -STATIC mp_obj_t audioio_mixer_voice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { -#if 0 - enum { ARG_sample, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - audioio_mixer_voice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audioio_mixer_voice_deinited(self)); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_audioio_mixer_play(self, sample, self->u_int, args[ARG_loop].u_ool); -#endif - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_voice_play_obj, 1, audioio_mixer_voice_obj_play); - -//| .. method:: stop_voice() +//| .. attribute:: voice //| -//| Stops playback of the sample on this voice. -//| -STATIC mp_obj_t audioio_mixer_voice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { -#if 0 - enum { ARG_voice }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, - }; - audioio_mixer_voice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); -#endif - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_voice_stop_obj, 1, audioio_mixer_voice_obj_stop); - -//| .. method:: set_gain(voice, gain) +//| tuple of voice objects //| -//| Set the gain of a voice. -//| -//| gain must be a floating point number between 0 and 1 -//| -STATIC mp_obj_t audioio_mixer_voice_obj_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { -#if 0 - enum { ARG_voice, ARG_gain }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_gain, MP_ARG_OBJ | MP_ARG_REQUIRED }, - }; - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - #if MICROPY_PY_BUILTINS_FLOAT - float gain = mp_obj_get_float(args[ARG_gain].u_obj); - #else - #error "floating point not supported" - #endif - - if (gain > 1 || gain < 0) { - mp_raise_ValueError(translate("gain must be between 0 and 1")); - } - - common_hal_audioio_mixer_set_gain(self,args[ARG_voice].u_int, gain); -#endif - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_voice_set_gain_obj, 1, audioio_mixer_voice_obj_set_gain); - -const mp_obj_property_t audioio_mixer_voice_gain_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&audioio_mixer_voice_set_gain_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: playing -//| -//| True when any voice is being output. (read-only) -//| -STATIC mp_obj_t audioio_mixer_voice_obj_get_playing(mp_obj_t self_in) { -#if 0 +STATIC mp_obj_t audioio_mixer_obj_get_voice(mp_obj_t self_in) { audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); -#endif - return mp_const_none; + return mp_obj_new_tuple(self->voice_count, self->voice); } -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_voice_get_playing_obj, audioio_mixer_voice_obj_get_playing); +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_voice_obj, audioio_mixer_obj_get_voice); -const mp_obj_property_t audioio_mixer_voice_playing_obj = { +const mp_obj_property_t audioio_mixer_voice_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_voice_get_playing_obj, + .proxy = {(mp_obj_t)&audioio_mixer_obj_get_voice, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; + STATIC const mp_rom_map_elem_t audioio_mixer_locals_dict_table[] = { // Methods { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixer_deinit_obj) }, @@ -439,6 +256,7 @@ STATIC const mp_rom_map_elem_t audioio_mixer_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_mixer_sample_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_voice), MP_ROM_PTR(&audioio_mixer_voice_obj) } }; STATIC MP_DEFINE_CONST_DICT(audioio_mixer_locals_dict, audioio_mixer_locals_dict_table); @@ -448,24 +266,3 @@ const mp_obj_type_t audioio_mixer_type = { .make_new = audioio_mixer_make_new, .locals_dict = (mp_obj_dict_t*)&audioio_mixer_locals_dict, }; - -STATIC const mp_rom_map_elem_t audioio_mixer_voice_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixer_voice_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixer_voice___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixer_voice_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_mixer_voice_stop_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_voice_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_gain), MP_ROM_PTR(&audioio_mixer_voice_gain_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(audioio_mixer_voice_locals_dict, audioio_mixer_voice_locals_dict_table); - -const mp_obj_type_t audioio_mixer_voice_type = { - { &mp_type_type }, - .name = MP_QSTR_Mixer_Voice, - .make_new = audioio_mixer_voice_make_new, - .locals_dict = (mp_obj_dict_t*)&audioio_mixer_voice_locals_dict, -}; diff --git a/shared-bindings/audioio/Mixer.h b/shared-bindings/audioio/Mixer.h index 52fb9bdc9..1769f3bb7 100644 --- a/shared-bindings/audioio/Mixer.h +++ b/shared-bindings/audioio/Mixer.h @@ -32,7 +32,7 @@ #include "shared-bindings/audioio/RawSample.h" extern const mp_obj_type_t audioio_mixer_type; -extern const mp_obj_type_t audioio_mixer_voice_type; +extern const mp_obj_type_t audioio_mixervoice_type; void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, uint8_t voice_count, @@ -52,12 +52,4 @@ void common_hal_audioio_mixer_set_gain(audioio_mixer_obj_t* self, uint8_t voice, bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self); -void common_hal_audioio_mixer_voice_deinit(audioio_mixer_voice_obj_t* self); -bool common_hal_audioio_mixer_voice_deinited(audioio_mixer_voice_obj_t* self); -void common_hal_audioio_mixer_voice_play(audioio_mixer_voice_obj_t* self, mp_obj_t sample, bool loop); -void common_hal_audioio_mixer_voice_stop_voice(audioio_mixer_voice_obj_t* self); -void common_hal_audioio_mixer_voice_set_gain(audioio_mixer_voice_obj_t* self, float gain); - -bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); - #endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H diff --git a/shared-bindings/audioio/MixerVoice.c b/shared-bindings/audioio/MixerVoice.c new file mode 100644 index 000000000..9cc8a6339 --- /dev/null +++ b/shared-bindings/audioio/MixerVoice.c @@ -0,0 +1,196 @@ +/* + * MixerVoice.c + * + * Created on: Nov 15, 2018 + * Author: dean + */ +#include "shared-bindings/audioio/Mixer.h" + +#include + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audioio +//| +//| :class:`Mixer` -- Mixes one or more audio samples together +//| =========================================================== +//| +//| Mixer mixes multiple samples into one sample. +//| +//| .. class:: Mixer(channel_count=2, buffer_size=1024) +//| +//| Create a Mixer object that can mix multiple channels with the same sample rate. +//| +//| :param int channel_count: The maximum number of samples to mix at once +//| :param int buffer_size: The total size in bytes of the buffers to mix into +//| +// TODO: support mono or stereo voices +STATIC mp_obj_t audioio_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + audioio_mixervoice_obj_t *self = m_new(audioio_mixervoice_obj_t, 1); + self->base.type = &audioio_mixervoice_type; + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the Voice and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audioio_mixervoice_deinit(mp_obj_t self_in) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_deinit_obj, audioio_mixervoice_deinit); + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audioio_mixervoice_obj___exit__(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixervoice___exit___obj, 4, 4, audioio_mixervoice_obj___exit__); + + +//| .. method:: play(sample, *, loop=False) +//| +//| Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. +//| +//| The sample must match the Mixer's encoding settings given in the constructor. +//| +STATIC mp_obj_t audioio_mixervoice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +#if 0 + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + raise_error_if_deinited(common_hal_audioio_mixervoice_deinited(self)); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audioio_mixer_play(self, sample, self->u_int, args[ARG_loop].u_ool); +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_play_obj, 1, audioio_mixervoice_obj_play); + +//| .. method:: stop_voice() +//| +//| Stops playback of the sample on this voice. +//| +STATIC mp_obj_t audioio_mixervoice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +#if 0 + enum { ARG_voice }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, + }; + audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_stop_obj, 1, audioio_mixervoice_obj_stop); + +//| .. method:: set_gain(voice, gain) +//| +//| Set the gain of a voice. +//| +//| gain must be a floating point number between 0 and 1 +//| +STATIC mp_obj_t audioio_mixervoice_obj_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_gain }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_gain, MP_ARG_OBJ | MP_ARG_REQUIRED }, + }; + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + #if MICROPY_PY_BUILTINS_FLOAT + float gain = mp_obj_get_float(args[ARG_gain].u_obj); + #else + #error "floating point not supported" + #endif + + if (gain > 1 || gain < 0) { + mp_raise_ValueError(translate("gain must be between 0 and 1")); + } + + common_hal_audioio_mixervoice_set_gain(self, gain); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_set_gain_obj, 1, audioio_mixervoice_obj_set_gain); + +const mp_obj_property_t audioio_mixervoice_gain_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&audioio_mixervoice_set_gain_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: playing +//| +//| True when any voice is being output. (read-only) +//| +STATIC mp_obj_t audioio_mixervoice_obj_get_playing(mp_obj_t self_in) { +#if 0 + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_get_playing_obj, audioio_mixervoice_obj_get_playing); + +const mp_obj_property_t audioio_mixervoice_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixervoice_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t audioio_mixervoice_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixervoice_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixervoice___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixervoice_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_mixervoice_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixervoice_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_gain), MP_ROM_PTR(&audioio_mixervoice_gain_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audioio_mixervoice_locals_dict, audioio_mixervoice_locals_dict_table); + +const mp_obj_type_t audioio_mixervoice_type = { + { &mp_type_type }, + .name = MP_QSTR_mixervoice, + .make_new = audioio_mixervoice_make_new, + .locals_dict = (mp_obj_dict_t*)&audioio_mixervoice_locals_dict, +}; + diff --git a/shared-bindings/audioio/MixerVoice.h b/shared-bindings/audioio/MixerVoice.h new file mode 100644 index 000000000..f4c868a0e --- /dev/null +++ b/shared-bindings/audioio/MixerVoice.h @@ -0,0 +1,38 @@ +/* + * MixerVoice.h + * + * Created on: Nov 15, 2018 + * Author: dean + */ + +#ifndef SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ +#define SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ + +#include "py/obj.h" + +#include "shared-module/audioio/__init__.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/audioio/Mixer.h" +#include "shared-bindings/audioio/RawSample.h" + +typedef struct { + mp_obj_t sample; + bool loop; + bool more_data; + uint32_t* remaining_buffer; + uint32_t buffer_length; + int16_t gain; +} audioio_mixervoice_obj_t; + +extern const mp_obj_type_t audioio_mixer_type; +extern const mp_obj_type_t audioio_mixervoice_type; + +void common_hal_audioio_mixervoice_deinit(audioio_mixervoice_obj_t* self); +void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop); +void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self); +void common_hal_audioio_mixervoice_set_gain(audioio_mixervoice_obj_t* self, float gain); + +bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self); + +#endif /* SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ */ diff --git a/shared-module/audioio/Mixer.c b/shared-module/audioio/Mixer.c index 5125574ef..4797f4adc 100644 --- a/shared-module/audioio/Mixer.c +++ b/shared-module/audioio/Mixer.c @@ -100,7 +100,7 @@ void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, u if (samples_signed != self->samples_signed) { mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); } - audioio_mixer_voice_obj_t* voice = &self->voice[v]; + audioio_mixervoice_obj_t* voice = &self->voice[v]; voice->sample = sample; voice->loop = loop; @@ -132,11 +132,6 @@ void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, } } -void common_hal_audioio_mixer_set_gain(audioio_mixer_obj_t* self, uint8_t voice, float gain) { - audioio_mixer_voice_obj_t* v = &self->voice[voice]; - v->gain = gain * ((1 << 15)-1); -} - uint32_t add8signed(uint32_t a, uint32_t b) { #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) return __QADD8(a, b); @@ -311,7 +306,7 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, self->use_first_buffer = !self->use_first_buffer; bool voices_active = false; for (int32_t v = 0; v < self->voice_count; v++) { - audioio_mixer_voice_obj_t* voice = &self->voice[v]; + audioio_mixervoice_obj_t* voice = &self->voice[v]; uint32_t j = 0; bool voice_done = voice->sample == NULL; diff --git a/shared-module/audioio/Mixer.h b/shared-module/audioio/Mixer.h index 3451aa25d..40b6df2fe 100644 --- a/shared-module/audioio/Mixer.h +++ b/shared-module/audioio/Mixer.h @@ -30,15 +30,7 @@ #include "py/obj.h" #include "shared-module/audioio/__init__.h" - -typedef struct { - mp_obj_t sample; - bool loop; - bool more_data; - uint32_t* remaining_buffer; - uint32_t buffer_length; - int16_t gain; -} audioio_mixer_voice_obj_t; +#include "shared-bindings/audioio/MixerVoice.h" typedef struct { mp_obj_base_t base; @@ -56,7 +48,7 @@ typedef struct { uint32_t right_read_count; uint8_t voice_count; - audioio_mixer_voice_obj_t voice[]; + mp_obj_t voice[]; } audioio_mixer_obj_t; diff --git a/shared-module/audioio/MixerVoice.c b/shared-module/audioio/MixerVoice.c new file mode 100644 index 000000000..ff40da34c --- /dev/null +++ b/shared-module/audioio/MixerVoice.c @@ -0,0 +1,18 @@ +/* + * MixerVoice.c + * + * Created on: Nov 15, 2018 + * Author: dean + */ + +#include "shared-bindings/audioio/Mixer.h" + +#include + +#include "py/runtime.h" +#include "shared-module/audioio/__init__.h" +#include "shared-module/audioio/RawSample.h" + +void common_hal_audioio_mixervoice_set_gain(audioio_mixer_obj_t* self, float gain) { + self->gain = gain * ((1 << 15)-1); +} diff --git a/shared-module/audioio/MixerVoice.h b/shared-module/audioio/MixerVoice.h new file mode 100644 index 000000000..c04e8ef24 --- /dev/null +++ b/shared-module/audioio/MixerVoice.h @@ -0,0 +1,12 @@ +/* + * MixerVoice.h + * + * Created on: Nov 15, 2018 + * Author: dean + */ + +#ifndef SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ +#define SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ + + +#endif /* SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ */ -- cgit v1.2.3 From feef1778581e0811bc07da3aa3dc39744187b05b Mon Sep 17 00:00:00 2001 From: dean Date: Thu, 15 Nov 2018 15:04:11 -0500 Subject: DM: in progress mixer voice --- ports/atmel-samd/Makefile | 1 + shared-bindings/audioio/Mixer.c | 8 +++++++- shared-bindings/audioio/MixerVoice.c | 3 ++- shared-bindings/audioio/MixerVoice.h | 14 +------------- shared-module/audioio/Mixer.c | 13 +++++++++++++ shared-module/audioio/Mixer.h | 2 ++ shared-module/audioio/MixerVoice.c | 2 +- shared-module/audioio/MixerVoice.h | 14 ++++++++++++++ 8 files changed, 41 insertions(+), 16 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 7861f4235..e628129a6 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -434,6 +434,7 @@ ifneq ($(CHIP_VARIANT),SAMR21G18A) SRC_SHARED_MODULE += \ audioio/__init__.c \ audioio/Mixer.c \ + audioio/MixerVoice.c \ audioio/RawSample.c \ audioio/WaveFile.c endif diff --git a/shared-bindings/audioio/Mixer.c b/shared-bindings/audioio/Mixer.c index baf86c803..b447ab277 100644 --- a/shared-bindings/audioio/Mixer.c +++ b/shared-bindings/audioio/Mixer.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ #include "shared-bindings/audioio/Mixer.h" +#include "shared-module/audioio/MixerVoice.h" #include @@ -110,6 +111,11 @@ STATIC mp_obj_t audioio_mixer_make_new(const mp_obj_type_t *type, size_t n_args, self->base.type = &audioio_mixer_type; common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + for(int v=0; vvoice[v] = audioio_mixervoice_type.make_new(&audioio_mixervoice_type, 0, 0, NULL); + } + self->voice_tuple = mp_obj_new_tuple(self->voice_count, self->voice); + return MP_OBJ_FROM_PTR(self); } @@ -233,7 +239,7 @@ const mp_obj_property_t audioio_mixer_sample_rate_obj = { STATIC mp_obj_t audioio_mixer_obj_get_voice(mp_obj_t self_in) { audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - return mp_obj_new_tuple(self->voice_count, self->voice); + return self->voice_tuple; } MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_voice_obj, audioio_mixer_obj_get_voice); diff --git a/shared-bindings/audioio/MixerVoice.c b/shared-bindings/audioio/MixerVoice.c index 9cc8a6339..d1680fa71 100644 --- a/shared-bindings/audioio/MixerVoice.c +++ b/shared-bindings/audioio/MixerVoice.c @@ -5,6 +5,7 @@ * Author: dean */ #include "shared-bindings/audioio/Mixer.h" +#include "shared-bindings/audioio/MixerVoice.h" #include @@ -125,7 +126,7 @@ STATIC mp_obj_t audioio_mixervoice_obj_set_gain(size_t n_args, const mp_obj_t *p static const mp_arg_t allowed_args[] = { { MP_QSTR_gain, MP_ARG_OBJ | MP_ARG_REQUIRED }, }; - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); diff --git a/shared-bindings/audioio/MixerVoice.h b/shared-bindings/audioio/MixerVoice.h index f4c868a0e..4eb588e6e 100644 --- a/shared-bindings/audioio/MixerVoice.h +++ b/shared-bindings/audioio/MixerVoice.h @@ -8,22 +8,10 @@ #ifndef SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ #define SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ -#include "py/obj.h" - -#include "shared-module/audioio/__init__.h" - #include "common-hal/microcontroller/Pin.h" #include "shared-module/audioio/Mixer.h" #include "shared-bindings/audioio/RawSample.h" - -typedef struct { - mp_obj_t sample; - bool loop; - bool more_data; - uint32_t* remaining_buffer; - uint32_t buffer_length; - int16_t gain; -} audioio_mixervoice_obj_t; +#include "shared-module/audioio/MixerVoice.h" extern const mp_obj_type_t audioio_mixer_type; extern const mp_obj_type_t audioio_mixervoice_type; diff --git a/shared-module/audioio/Mixer.c b/shared-module/audioio/Mixer.c index 4797f4adc..28815470d 100644 --- a/shared-module/audioio/Mixer.c +++ b/shared-module/audioio/Mixer.c @@ -59,10 +59,12 @@ void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, self->sample_rate = sample_rate; self->voice_count = voice_count; +#if 0 for (uint8_t i = 0; i < self->voice_count; i++) { self->voice[i].sample = NULL; self->voice[i].gain = ((1<<15)-1); } +#endif } void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self) { @@ -100,6 +102,7 @@ void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, u if (samples_signed != self->samples_signed) { mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); } +#if 0 audioio_mixervoice_obj_t* voice = &self->voice[v]; voice->sample = sample; voice->loop = loop; @@ -109,27 +112,35 @@ void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, u // Track length in terms of words. voice->buffer_length /= sizeof(uint32_t); voice->more_data = result == GET_BUFFER_MORE_DATA; + +#endif } void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice) { +#if 0 self->voice[voice].sample = NULL; +#endif } bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self) { +#if 0 for (int32_t v = 0; v < self->voice_count; v++) { if (self->voice[v].sample != NULL) { return true; } } +#endif return false; } void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, bool single_channel, uint8_t channel) { +#if 0 for (int32_t i = 0; i < self->voice_count; i++) { self->voice[i].sample = NULL; } +#endif } uint32_t add8signed(uint32_t a, uint32_t b) { @@ -283,6 +294,7 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, uint8_t channel, uint8_t** buffer, uint32_t* buffer_length) { +#if 0 if (!single_channel) { channel = 0; } @@ -403,6 +415,7 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, self->right_read_count += 1; *buffer = *buffer + self->bits_per_sample / 8; } +#endif return GET_BUFFER_MORE_DATA; } diff --git a/shared-module/audioio/Mixer.h b/shared-module/audioio/Mixer.h index 40b6df2fe..083a3ce7e 100644 --- a/shared-module/audioio/Mixer.h +++ b/shared-module/audioio/Mixer.h @@ -28,6 +28,7 @@ #define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H #include "py/obj.h" +#include "py/objtuple.h" #include "shared-module/audioio/__init__.h" #include "shared-bindings/audioio/MixerVoice.h" @@ -48,6 +49,7 @@ typedef struct { uint32_t right_read_count; uint8_t voice_count; + mp_obj_tuple_t *voice_tuple; mp_obj_t voice[]; } audioio_mixer_obj_t; diff --git a/shared-module/audioio/MixerVoice.c b/shared-module/audioio/MixerVoice.c index ff40da34c..28df1c5d1 100644 --- a/shared-module/audioio/MixerVoice.c +++ b/shared-module/audioio/MixerVoice.c @@ -13,6 +13,6 @@ #include "shared-module/audioio/__init__.h" #include "shared-module/audioio/RawSample.h" -void common_hal_audioio_mixervoice_set_gain(audioio_mixer_obj_t* self, float gain) { +void common_hal_audioio_mixervoice_set_gain(audioio_mixervoice_obj_t* self, float gain) { self->gain = gain * ((1 << 15)-1); } diff --git a/shared-module/audioio/MixerVoice.h b/shared-module/audioio/MixerVoice.h index c04e8ef24..b917829dd 100644 --- a/shared-module/audioio/MixerVoice.h +++ b/shared-module/audioio/MixerVoice.h @@ -8,5 +8,19 @@ #ifndef SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ #define SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ +#include "py/obj.h" + +#include "shared-module/audioio/__init__.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t sample; + bool loop; + bool more_data; + uint32_t* remaining_buffer; + uint32_t buffer_length; + int16_t gain; +} audioio_mixervoice_obj_t; + #endif /* SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ */ -- cgit v1.2.3 From 1bf6c588e7e1ea11c865c33f660ec126f752b1dc Mon Sep 17 00:00:00 2001 From: dean Date: Tue, 20 Nov 2018 14:14:22 -0500 Subject: DM: mixer voice stuff --- shared-bindings/audioio/Mixer.c | 54 ++------------------------------- shared-bindings/audioio/Mixer.h | 4 --- shared-bindings/audioio/MixerVoice.c | 18 +++++------ shared-bindings/audioio/MixerVoice.h | 2 ++ shared-module/audioio/Mixer.c | 58 ++---------------------------------- shared-module/audioio/Mixer.h | 1 - shared-module/audioio/MixerVoice.c | 42 ++++++++++++++++++++++++++ shared-module/audioio/MixerVoice.h | 2 ++ 8 files changed, 60 insertions(+), 121 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/audioio/Mixer.c b/shared-bindings/audioio/Mixer.c index b447ab277..e962ed0cf 100644 --- a/shared-bindings/audioio/Mixer.c +++ b/shared-bindings/audioio/Mixer.c @@ -25,6 +25,7 @@ */ #include "shared-bindings/audioio/Mixer.h" #include "shared-module/audioio/MixerVoice.h" +#include "shared-bindings/audioio/MixerVoice.h" #include @@ -113,6 +114,7 @@ STATIC mp_obj_t audioio_mixer_make_new(const mp_obj_type_t *type, size_t n_args, for(int v=0; vvoice[v] = audioio_mixervoice_type.make_new(&audioio_mixervoice_type, 0, 0, NULL); + common_hal_audioio_mixervoice_set_parent(self->voice[v], self); } self->voice_tuple = mp_obj_new_tuple(self->voice_count, self->voice); @@ -148,54 +150,6 @@ STATIC mp_obj_t audioio_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer___exit___obj, 4, 4, audioio_mixer_obj___exit__); - -//| .. method:: play(sample, *, voice=0, loop=False) -//| -//| Plays the sample once when loop=False and continuously when loop=True. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. -//| -//| The sample must match the Mixer's encoding settings given in the constructor. -//| -STATIC mp_obj_t audioio_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_voice, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_voice, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_audioio_mixer_play(self, sample, args[ARG_voice].u_int, args[ARG_loop].u_bool); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_play_obj, 1, audioio_mixer_obj_play); - -//| .. method:: stop_voice(voice=0) -//| -//| Stops playback of the sample on the given voice. -//| -STATIC mp_obj_t audioio_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_voice }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, - }; - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_stop_voice_obj, 1, audioio_mixer_obj_stop_voice); - //| .. attribute:: playing //| //| True when any voice is being output. (read-only) @@ -245,7 +199,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_voice_obj, audioio_mixer_obj_get_voi const mp_obj_property_t audioio_mixer_voice_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_obj_get_voice, + .proxy = {(mp_obj_t)&audioio_mixer_get_voice_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; @@ -256,8 +210,6 @@ STATIC const mp_rom_map_elem_t audioio_mixer_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixer_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixer___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixer_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop_voice), MP_ROM_PTR(&audioio_mixer_stop_voice_obj) }, // Properties { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_playing_obj) }, diff --git a/shared-bindings/audioio/Mixer.h b/shared-bindings/audioio/Mixer.h index 1769f3bb7..2e5adddf7 100644 --- a/shared-bindings/audioio/Mixer.h +++ b/shared-bindings/audioio/Mixer.h @@ -44,10 +44,6 @@ void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self); bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self); -void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, uint8_t voice, bool loop); -void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice); -void common_hal_audioio_mixer_set_gain(audioio_mixer_obj_t* self, uint8_t voice, float gain); - bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self); diff --git a/shared-bindings/audioio/MixerVoice.c b/shared-bindings/audioio/MixerVoice.c index d1680fa71..5cddb291c 100644 --- a/shared-bindings/audioio/MixerVoice.c +++ b/shared-bindings/audioio/MixerVoice.c @@ -36,7 +36,8 @@ STATIC mp_obj_t audioio_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { audioio_mixervoice_obj_t *self = m_new(audioio_mixervoice_obj_t, 1); self->base.type = &audioio_mixervoice_type; - + self->sample = NULL; + self->gain = ((1 << 15)-1); return MP_OBJ_FROM_PTR(self); } @@ -76,41 +77,38 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixervoice___exit___obj, 4, 4 //| The sample must match the Mixer's encoding settings given in the constructor. //| STATIC mp_obj_t audioio_mixervoice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { -#if 0 enum { ARG_sample, ARG_loop }; static const mp_arg_t allowed_args[] = { { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audioio_mixervoice_deinited(self)); + //raise_error_if_deinited(common_hal_audioio_mixervoice_deinited(self)); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_audioio_mixer_play(self, sample, self->u_int, args[ARG_loop].u_ool); -#endif + common_hal_audioio_mixervoice_play(self, sample, args[ARG_loop].u_bool); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_play_obj, 1, audioio_mixervoice_obj_play); -//| .. method:: stop_voice() +//| .. method:: stop() //| //| Stops playback of the sample on this voice. //| STATIC mp_obj_t audioio_mixervoice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { -#if 0 enum { ARG_voice }; static const mp_arg_t allowed_args[] = { { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, }; audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + //raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); -#endif + common_hal_audioio_mixervoice_stop(self); + return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_stop_obj, 1, audioio_mixervoice_obj_stop); diff --git a/shared-bindings/audioio/MixerVoice.h b/shared-bindings/audioio/MixerVoice.h index 4eb588e6e..1320773ec 100644 --- a/shared-bindings/audioio/MixerVoice.h +++ b/shared-bindings/audioio/MixerVoice.h @@ -12,11 +12,13 @@ #include "shared-module/audioio/Mixer.h" #include "shared-bindings/audioio/RawSample.h" #include "shared-module/audioio/MixerVoice.h" +#include "shared-module/audioio/Mixer.h" extern const mp_obj_type_t audioio_mixer_type; extern const mp_obj_type_t audioio_mixervoice_type; void common_hal_audioio_mixervoice_deinit(audioio_mixervoice_obj_t* self); +void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent); void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop); void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self); void common_hal_audioio_mixervoice_set_gain(audioio_mixervoice_obj_t* self, float gain); diff --git a/shared-module/audioio/Mixer.c b/shared-module/audioio/Mixer.c index 28815470d..ea53140ab 100644 --- a/shared-module/audioio/Mixer.c +++ b/shared-module/audioio/Mixer.c @@ -25,6 +25,7 @@ */ #include "shared-bindings/audioio/Mixer.h" +#include "shared-bindings/audioio/MixerVoice.h" #include @@ -58,13 +59,6 @@ void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, self->channel_count = channel_count; self->sample_rate = sample_rate; self->voice_count = voice_count; - -#if 0 - for (uint8_t i = 0; i < self->voice_count; i++) { - self->voice[i].sample = NULL; - self->voice[i].gain = ((1<<15)-1); - } -#endif } void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self) { @@ -80,56 +74,12 @@ uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self) { return self->sample_rate; } -void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, uint8_t v, bool loop) { - if (v >= self->voice_count) { - mp_raise_ValueError(translate("Voice index too high")); - } - if (audiosample_sample_rate(sample) != self->sample_rate) { - mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); - } - if (audiosample_channel_count(sample) != self->channel_count) { - mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); - } - if (audiosample_bits_per_sample(sample) != self->bits_per_sample) { - mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); - } - bool single_buffer; - bool samples_signed; - uint32_t max_buffer_length; - uint8_t spacing; - audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, - &max_buffer_length, &spacing); - if (samples_signed != self->samples_signed) { - mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); - } -#if 0 - audioio_mixervoice_obj_t* voice = &self->voice[v]; - voice->sample = sample; - voice->loop = loop; - - audiosample_reset_buffer(sample, false, 0); - audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); - // Track length in terms of words. - voice->buffer_length /= sizeof(uint32_t); - voice->more_data = result == GET_BUFFER_MORE_DATA; - -#endif -} - -void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice) { -#if 0 - self->voice[voice].sample = NULL; -#endif -} - bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self) { -#if 0 for (int32_t v = 0; v < self->voice_count; v++) { - if (self->voice[v].sample != NULL) { + if (common_hal_audioio_mixervoice_get_playing(MP_OBJ_TO_PTR(self->voice[v]))) { return true; } } -#endif return false; } @@ -294,7 +244,6 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, uint8_t channel, uint8_t** buffer, uint32_t* buffer_length) { -#if 0 if (!single_channel) { channel = 0; } @@ -318,7 +267,7 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, self->use_first_buffer = !self->use_first_buffer; bool voices_active = false; for (int32_t v = 0; v < self->voice_count; v++) { - audioio_mixervoice_obj_t* voice = &self->voice[v]; + audioio_mixervoice_obj_t* voice = MP_OBJ_TO_PTR(self->voice[v]); uint32_t j = 0; bool voice_done = voice->sample == NULL; @@ -415,7 +364,6 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, self->right_read_count += 1; *buffer = *buffer + self->bits_per_sample / 8; } -#endif return GET_BUFFER_MORE_DATA; } diff --git a/shared-module/audioio/Mixer.h b/shared-module/audioio/Mixer.h index 083a3ce7e..db5c6ce6f 100644 --- a/shared-module/audioio/Mixer.h +++ b/shared-module/audioio/Mixer.h @@ -31,7 +31,6 @@ #include "py/objtuple.h" #include "shared-module/audioio/__init__.h" -#include "shared-bindings/audioio/MixerVoice.h" typedef struct { mp_obj_base_t base; diff --git a/shared-module/audioio/MixerVoice.c b/shared-module/audioio/MixerVoice.c index 28df1c5d1..3579d500f 100644 --- a/shared-module/audioio/MixerVoice.c +++ b/shared-module/audioio/MixerVoice.c @@ -12,7 +12,49 @@ #include "py/runtime.h" #include "shared-module/audioio/__init__.h" #include "shared-module/audioio/RawSample.h" +#include "shared-module/audioio/MixerVoice.h" + +void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent) { + self->parent = parent; +} void common_hal_audioio_mixervoice_set_gain(audioio_mixervoice_obj_t* self, float gain) { self->gain = gain * ((1 << 15)-1); } + +void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop) { + if (audiosample_sample_rate(sample) != self->parent->sample_rate) { + mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); + } + if (audiosample_channel_count(sample) != self->parent->channel_count) { + mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); + } + if (audiosample_bits_per_sample(sample) != self->parent->bits_per_sample) { + mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); + } + bool single_buffer; + bool samples_signed; + uint32_t max_buffer_length; + uint8_t spacing; + audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, + &max_buffer_length, &spacing); + if (samples_signed != self->parent->samples_signed) { + mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); + } + self->sample = sample; + self->loop = loop; + + audiosample_reset_buffer(sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &self->remaining_buffer, &self->buffer_length); + // Track length in terms of words. + self->buffer_length /= sizeof(uint32_t); + self->more_data = result == GET_BUFFER_MORE_DATA; +} + +bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self) { + return self->sample != NULL; +} + +void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self) { + self->sample = NULL; +} diff --git a/shared-module/audioio/MixerVoice.h b/shared-module/audioio/MixerVoice.h index b917829dd..1cf686a38 100644 --- a/shared-module/audioio/MixerVoice.h +++ b/shared-module/audioio/MixerVoice.h @@ -11,9 +11,11 @@ #include "py/obj.h" #include "shared-module/audioio/__init__.h" +#include "shared-module/audioio/Mixer.h" typedef struct { mp_obj_base_t base; + audioio_mixer_obj_t *parent; mp_obj_t sample; bool loop; bool more_data; -- cgit v1.2.3 From 7aa0840b730279f33c769849e9fa3065a2eeaf79 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Tue, 12 Mar 2019 10:24:54 -0500 Subject: change voice 'gain' to 'level' --- shared-bindings/audioio/MixerVoice.c | 24 ++++++++++++------------ shared-bindings/audioio/MixerVoice.h | 2 +- shared-module/audioio/Mixer.c | 10 +++++----- shared-module/audioio/MixerVoice.c | 4 ++-- shared-module/audioio/MixerVoice.h | 2 +- 5 files changed, 21 insertions(+), 21 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/audioio/MixerVoice.c b/shared-bindings/audioio/MixerVoice.c index 2bcafaae0..02f57d419 100644 --- a/shared-bindings/audioio/MixerVoice.c +++ b/shared-bindings/audioio/MixerVoice.c @@ -37,7 +37,7 @@ STATIC mp_obj_t audioio_mixervoice_make_new(const mp_obj_type_t *type, size_t n_ audioio_mixervoice_obj_t *self = m_new_obj(audioio_mixervoice_obj_t); self->base.type = &audioio_mixervoice_type; self->sample = NULL; - self->gain = ((1 << 15)-1); + self->level = ((1 << 15)-1); return MP_OBJ_FROM_PTR(self); } @@ -119,35 +119,35 @@ MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_stop_obj, 1, audioio_mixervoice_ob //| //| gain must be a floating point number between 0 and 1 //| -STATIC mp_obj_t audioio_mixervoice_obj_set_gain(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_gain }; +STATIC mp_obj_t audioio_mixervoice_obj_set_level(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_level }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_gain, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_level, MP_ARG_OBJ | MP_ARG_REQUIRED }, }; audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); #if MICROPY_PY_BUILTINS_FLOAT - float gain = mp_obj_get_float(args[ARG_gain].u_obj); + float level = mp_obj_get_float(args[ARG_level].u_obj); #else #error "floating point not supported" #endif - if (gain > 1 || gain < 0) { - mp_raise_ValueError(translate("gain must be between 0 and 1")); + if (level > 1 || level < 0) { + mp_raise_ValueError(translate("level must be between 0 and 1")); } - common_hal_audioio_mixervoice_set_gain(self, gain); + common_hal_audioio_mixervoice_set_level(self, level); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_set_gain_obj, 1, audioio_mixervoice_obj_set_gain); +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_set_level_obj, 1, audioio_mixervoice_obj_set_level); -const mp_obj_property_t audioio_mixervoice_gain_obj = { +const mp_obj_property_t audioio_mixervoice_level_obj = { .base.type = &mp_type_property, .proxy = {(mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&audioio_mixervoice_set_gain_obj, + (mp_obj_t)&audioio_mixervoice_set_level_obj, (mp_obj_t)&mp_const_none_obj}, }; @@ -182,7 +182,7 @@ STATIC const mp_rom_map_elem_t audioio_mixervoice_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixervoice_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_gain), MP_ROM_PTR(&audioio_mixervoice_gain_obj) }, + { MP_ROM_QSTR(MP_QSTR_level), MP_ROM_PTR(&audioio_mixervoice_level_obj) }, }; STATIC MP_DEFINE_CONST_DICT(audioio_mixervoice_locals_dict, audioio_mixervoice_locals_dict_table); diff --git a/shared-bindings/audioio/MixerVoice.h b/shared-bindings/audioio/MixerVoice.h index 1320773ec..a67a5ec90 100644 --- a/shared-bindings/audioio/MixerVoice.h +++ b/shared-bindings/audioio/MixerVoice.h @@ -21,7 +21,7 @@ void common_hal_audioio_mixervoice_deinit(audioio_mixervoice_obj_t* self); void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent); void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop); void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self); -void common_hal_audioio_mixervoice_set_gain(audioio_mixervoice_obj_t* self, float gain); +void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float gain); bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self); diff --git a/shared-module/audioio/Mixer.c b/shared-module/audioio/Mixer.c index ea53140ab..dc92ce1da 100644 --- a/shared-module/audioio/Mixer.c +++ b/shared-module/audioio/Mixer.c @@ -309,19 +309,19 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, sample_value = voice->remaining_buffer[j]; } - // apply the mixer gain + // apply the mixer level if (!self->samples_signed) { if (self->bits_per_sample == 8) { - sample_value = mult8unsigned(sample_value, voice->gain); + sample_value = mult8unsigned(sample_value, voice->level); } else { - sample_value = mult16unsigned(sample_value, voice->gain); + sample_value = mult16unsigned(sample_value, voice->level); } } else{ if (self->bits_per_sample == 8) { - sample_value = mult8signed(sample_value, voice->gain); + sample_value = mult8signed(sample_value, voice->level); } else { - sample_value = mult16signed(sample_value, voice->gain); + sample_value = mult16signed(sample_value, voice->level); } } diff --git a/shared-module/audioio/MixerVoice.c b/shared-module/audioio/MixerVoice.c index 3579d500f..024460af1 100644 --- a/shared-module/audioio/MixerVoice.c +++ b/shared-module/audioio/MixerVoice.c @@ -18,8 +18,8 @@ void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, au self->parent = parent; } -void common_hal_audioio_mixervoice_set_gain(audioio_mixervoice_obj_t* self, float gain) { - self->gain = gain * ((1 << 15)-1); +void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float level) { + self->level = level * ((1 << 15)-1); } void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop) { diff --git a/shared-module/audioio/MixerVoice.h b/shared-module/audioio/MixerVoice.h index 1cf686a38..2811a741a 100644 --- a/shared-module/audioio/MixerVoice.h +++ b/shared-module/audioio/MixerVoice.h @@ -21,7 +21,7 @@ typedef struct { bool more_data; uint32_t* remaining_buffer; uint32_t buffer_length; - int16_t gain; + int16_t level; } audioio_mixervoice_obj_t; -- cgit v1.2.3 From a498bcd94d7f869e2cb2e992babacb981de688c0 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Tue, 12 Mar 2019 16:10:54 -0500 Subject: add voice level getter --- shared-bindings/audioio/MixerVoice.c | 18 +++++++++++++++++- shared-bindings/audioio/MixerVoice.h | 1 + shared-module/audioio/MixerVoice.c | 4 ++++ 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-bindings/audioio/MixerVoice.c b/shared-bindings/audioio/MixerVoice.c index 02f57d419..cba82feb2 100644 --- a/shared-bindings/audioio/MixerVoice.c +++ b/shared-bindings/audioio/MixerVoice.c @@ -113,6 +113,22 @@ STATIC mp_obj_t audioio_mixervoice_obj_stop(size_t n_args, const mp_obj_t *pos_a } MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_stop_obj, 1, audioio_mixervoice_obj_stop); +//| .. method:: get_gain(voice, gain) +//| +//| Get the gain of a voice. +//| +//| Returns as a floating point number between 0 and 1 +//| +STATIC mp_obj_t audioio_mixervoice_obj_get_level(mp_obj_t self_in) { + + #if !MICROPY_PY_BUILTINS_FLOAT + #error "floating point not supported" + #endif + + return mp_obj_new_float(common_hal_audioio_mixervoice_get_level(self_in)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_get_level_obj, audioio_mixervoice_obj_get_level); + //| .. method:: set_gain(voice, gain) //| //| Set the gain of a voice. @@ -146,7 +162,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_set_level_obj, 1, audioio_mixervoi const mp_obj_property_t audioio_mixervoice_level_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&mp_const_none_obj, + .proxy = {(mp_obj_t)&audioio_mixervoice_get_level_obj, (mp_obj_t)&audioio_mixervoice_set_level_obj, (mp_obj_t)&mp_const_none_obj}, }; diff --git a/shared-bindings/audioio/MixerVoice.h b/shared-bindings/audioio/MixerVoice.h index a67a5ec90..641a0faf2 100644 --- a/shared-bindings/audioio/MixerVoice.h +++ b/shared-bindings/audioio/MixerVoice.h @@ -21,6 +21,7 @@ void common_hal_audioio_mixervoice_deinit(audioio_mixervoice_obj_t* self); void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent); void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop); void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self); +float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self); void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float gain); bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self); diff --git a/shared-module/audioio/MixerVoice.c b/shared-module/audioio/MixerVoice.c index 024460af1..3e8aaff89 100644 --- a/shared-module/audioio/MixerVoice.c +++ b/shared-module/audioio/MixerVoice.c @@ -18,6 +18,10 @@ void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, au self->parent = parent; } +float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self) { + return self->level; +} + void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float level) { self->level = level * ((1 << 15)-1); } -- cgit v1.2.3 From 040acc3a3228c4204d8154656a1249171b68c75a Mon Sep 17 00:00:00 2001 From: Hierophect Date: Mon, 1 Jul 2019 19:47:10 -0400 Subject: remove dependencies for stable build --- ports/stm32f4/Makefile | 28 +++++++++++++--------------- ports/stm32f4/startup_stm32f411xe.s | 2 +- ports/stm32f4/supervisor/port.c | 2 +- ports/stm32f4/tick.c | 33 ++++++++++++++++----------------- shared-module/usb_hid/Device.c | 1 + supervisor/shared/memory.c | 2 +- supervisor/shared/usb/usb.c | 2 +- 7 files changed, 34 insertions(+), 36 deletions(-) (limited to 'shared-module') diff --git a/ports/stm32f4/Makefile b/ports/stm32f4/Makefile index 142973f53..90e81291f 100755 --- a/ports/stm32f4/Makefile +++ b/ports/stm32f4/Makefile @@ -62,18 +62,13 @@ CROSS_COMPILE = arm-none-eabi- INC += -I. INC += -I../.. INC += -I$(BUILD) -#keep? INC += -I$(BUILD)/genhdr -#HAL SPECIFIC -INC += -IcubeMXInc -INC += -IcubeMXDrivers/STM32F4xx_HAL_Driver/Inc -INC += -IcubeMXDrivers/STM32F4xx_HAL_Driver/Inc/Legacy -INC += -IcubeMXDrivers/CMSIS/Device/ST/STM32F4xx/Include -INC += -IcubeMXDrivers/CMSIS/Include -INC += -IcubeMXDrivers/CMSIS/Include -#does order matter? -INC += -Iboards/$(BOARD) -#INC += -I./peripherals +INC += -I./cubeMXInc +INC += -I./cubeMXDrivers/STM32F4xx_HAL_Driver/Inc +INC += -I./cubeMXDrivers/STM32F4xx_HAL_Driver/Inc/Legacy +INC += -I./cubeMXDrivers/CMSIS/Device/ST/STM32F4xx/Include +INC += -I./cubeMXDrivers/CMSIS/Include +INC += -I./boards/$(BOARD) INC += -I../../lib/mp-readline INC += -I../../lib/tinyusb/src INC += -I../../supervisor/shared/usb @@ -118,7 +113,7 @@ CFLAGS += -D__START=main #TODO: add LD file? -LDFLAGS = $(CFLAGS) -nostartfiles -fshort-enums -Wl,-nostdlib -Wl,-T,$(LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nano.specs +LDFLAGS = $(CFLAGS) -fshort-enums -Wl,-nostdlib -Wl,-T,$(LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nano.specs LIBS := -lgcc -lc LDFLAGS += -mthumb -mcpu=cortex-m4 @@ -138,9 +133,10 @@ CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_STM32F4 -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD # source ###################################### +#cubeMXsrc/stm32f4xx_it.c \ +#cubeMXsrc/stm32f4xx_hal_msp.c \ + SRC_STM32 = \ - cubeMXsrc/stm32f4xx_it.c \ - cubeMXsrc/stm32f4xx_hal_msp.c \ cubeMXDrivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim.c \ cubeMXDrivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_tim_ex.c \ cubeMXDrivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c \ @@ -164,6 +160,7 @@ SRC_C += \ background.c \ fatfs_port.c \ mphalport.c \ + tick.c \ boards/$(BOARD)/board.c \ lib/libc/string0.c \ lib/mp-readline/readline.c \ @@ -176,7 +173,8 @@ SRC_C += \ lib/utils/pyexec.c \ lib/utils/stdout_helpers.c \ lib/utils/sys_stdio_mphal.c \ - supervisor/shared/memory.c + supervisor/shared/memory.c \ + lib/tinyusb/src/portable/st/stm32f4/dcd_stm32f4.c # diff --git a/ports/stm32f4/startup_stm32f411xe.s b/ports/stm32f4/startup_stm32f411xe.s index 6079df95e..3aac640cb 100644 --- a/ports/stm32f4/startup_stm32f411xe.s +++ b/ports/stm32f4/startup_stm32f411xe.s @@ -108,7 +108,7 @@ LoopFillZerobss: /* Call the clock system intitialization function.*/ bl SystemInit /* Call static constructors */ - bl __libc_init_array +/* bl __libc_init_array */ /* Call the application's entry point.*/ bl main bx lr diff --git a/ports/stm32f4/supervisor/port.c b/ports/stm32f4/supervisor/port.c index df0019c06..93a297d0f 100644 --- a/ports/stm32f4/supervisor/port.c +++ b/ports/stm32f4/supervisor/port.c @@ -136,7 +136,7 @@ safe_mode_t port_init(void) { // huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; // huart2.Init.OverSampling = UART_OVERSAMPLING_16; - HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); + HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); return NO_SAFE_MODE; } diff --git a/ports/stm32f4/tick.c b/ports/stm32f4/tick.c index 6d8fd13e0..41fdac6ff 100644 --- a/ports/stm32f4/tick.c +++ b/ports/stm32f4/tick.c @@ -30,7 +30,6 @@ #include "supervisor/filesystem.h" #include "shared-module/gamepad/__init__.h" #include "shared-bindings/microcontroller/Processor.h" -#include "nrf.h" // Global millisecond tick count volatile uint64_t ticks_ms = 0; @@ -54,31 +53,31 @@ void SysTick_Handler(void) { } void tick_init() { - uint32_t ticks_per_ms = common_hal_mcu_processor_get_frequency() / 1000; - SysTick_Config(ticks_per_ms); // interrupt is enabled + uint32_t ticks_per_ms = 16000000/ 1000; + //SysTick_Config(ticks_per_ms); // interrupt is enabled } void tick_delay(uint32_t us) { - uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000; - uint32_t us_between_ticks = SysTick->VAL / ticks_per_us; - uint64_t start_ms = ticks_ms; - while (us > 1000) { - while (ticks_ms == start_ms) {} - us -= us_between_ticks; - start_ms = ticks_ms; - us_between_ticks = 1000; - } - while (SysTick->VAL > ((us_between_ticks - us) * ticks_per_us)) {} + // uint32_t ticks_per_us = 16000000 / 1000 / 1000; + // uint32_t us_between_ticks = SysTick->VAL / ticks_per_us; + // uint64_t start_ms = ticks_ms; + // while (us > 1000) { + // while (ticks_ms == start_ms) {} + // us -= us_between_ticks; + // start_ms = ticks_ms; + // us_between_ticks = 1000; + // } + //while (SysTick->VAL > ((us_between_ticks - us) * ticks_per_us)) {} } // us counts down! void current_tick(uint64_t* ms, uint32_t* us_until_ms) { - uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000; + uint32_t ticks_per_us = 16000000 / 1000 / 1000; *ms = ticks_ms; - *us_until_ms = SysTick->VAL / ticks_per_us; + //*us_until_ms = SysTick->VAL / ticks_per_us; } void wait_until(uint64_t ms, uint32_t us_until_ms) { - uint32_t ticks_per_us = common_hal_mcu_processor_get_frequency() / 1000 / 1000; - while(ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {} + uint32_t ticks_per_us = 16000000 / 1000 / 1000; + //while(ticks_ms <= ms && SysTick->VAL / ticks_per_us >= us_until_ms) {} } diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index 0e256cb5e..a2a4c30ac 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -47,6 +47,7 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t* // Wait until interface is ready, timeout = 2 seconds uint64_t end_ticks = ticks_ms + 2000; + while ( (ticks_ms < end_ticks) && !tud_hid_generic_ready() ) { } if ( !tud_hid_generic_ready() ) { diff --git a/supervisor/shared/memory.c b/supervisor/shared/memory.c index 11133415d..c9c4bc2d5 100755 --- a/supervisor/shared/memory.c +++ b/supervisor/shared/memory.c @@ -118,5 +118,5 @@ supervisor_allocation* allocate_memory(uint32_t length, bool high) { } void supervisor_move_memory(void) { - supervisor_display_move_memory(); + //supervisor_display_move_memory(); } diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index 0678a3a3f..ec778e91c 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -41,7 +41,7 @@ extern uint16_t usb_serial_number[1 + COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2]; void load_serial_number(void) { // create serial number based on device unique id uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH]; - common_hal_mcu_processor_get_uid(raw_id); + //common_hal_mcu_processor_get_uid(raw_id); static const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; -- cgit v1.2.3 From 43e8a4110f86a5d0b449d406ba33e27cc88978b0 Mon Sep 17 00:00:00 2001 From: Hierophect Date: Wed, 17 Jul 2019 14:18:01 -0400 Subject: Add missing files for DigitalIO --- ports/nrf/common-hal/microcontroller/Pin.c | 2 +- ports/nrf/tick.c | 2 +- shared-bindings/board/__init__.c | 122 ++++++++++++++--------------- shared-module/board/__init__.c | 12 +-- supervisor/shared/usb/usb.c | 4 +- supervisor/supervisor.mk | 1 + 6 files changed, 73 insertions(+), 70 deletions(-) (limited to 'shared-module') diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index b9c0ecaca..49b3c15ca 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -105,7 +105,7 @@ void reset_pin_number(uint8_t pin_number) { #ifdef SPEAKER_ENABLE_PIN if (pin_number == SPEAKER_ENABLE_PIN->number) { speaker_enable_in_use = false; - common_hal_digitalio_digitalinout_switch_to_output( + common_hal_digitalio_digitalinout_switch_to_output(); nrf_gpio_pin_dir_set(pin_number, NRF_GPIO_PIN_DIR_OUTPUT); nrf_gpio_pin_write(pin_number, false); } diff --git a/ports/nrf/tick.c b/ports/nrf/tick.c index f4cc9b1ec..6d8fd13e0 100644 --- a/ports/nrf/tick.c +++ b/ports/nrf/tick.c @@ -54,7 +54,7 @@ void SysTick_Handler(void) { } void tick_init() { - //uint32_t ticks_per_ms = common_hal_mcu_processor_get_frequency() / 1000; + uint32_t ticks_per_ms = common_hal_mcu_processor_get_frequency() / 1000; SysTick_Config(ticks_per_ms); // interrupt is enabled } diff --git a/shared-bindings/board/__init__.c b/shared-bindings/board/__init__.c index 47e2d64bc..ccf9ec5ab 100644 --- a/shared-bindings/board/__init__.c +++ b/shared-bindings/board/__init__.c @@ -46,72 +46,72 @@ //| Returns the `busio.I2C` object for the board designated SDA and SCL pins. It is a singleton. //| -#if BOARD_I2C -mp_obj_t board_i2c(void) { - mp_obj_t singleton = common_hal_board_get_i2c(); - if (singleton != NULL) { - return singleton; - } - assert_pin_free(DEFAULT_I2C_BUS_SDA); - assert_pin_free(DEFAULT_I2C_BUS_SCL); - return common_hal_board_create_i2c(); -} -#else -mp_obj_t board_i2c(void) { - mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_I2C); - return NULL; -} -#endif -MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); +// #if BOARD_I2C +// mp_obj_t board_i2c(void) { +// mp_obj_t singleton = common_hal_board_get_i2c(); +// if (singleton != NULL) { +// return singleton; +// } +// assert_pin_free(DEFAULT_I2C_BUS_SDA); +// assert_pin_free(DEFAULT_I2C_BUS_SCL); +// return common_hal_board_create_i2c(); +// } +// #else +// mp_obj_t board_i2c(void) { +// mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_I2C); +// return NULL; +// } +// #endif +// MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); -//| .. function:: SPI() -//| -//| Returns the `busio.SPI` object for the board designated SCK, MOSI and MISO pins. It is a -//| singleton. -//| -#if BOARD_SPI -mp_obj_t board_spi(void) { - mp_obj_t singleton = common_hal_board_get_spi(); - if (singleton != NULL) { - return singleton; - } - assert_pin_free(DEFAULT_SPI_BUS_SCK); - assert_pin_free(DEFAULT_SPI_BUS_MOSI); - assert_pin_free(DEFAULT_SPI_BUS_MISO); - return common_hal_board_create_spi(); -} -#else -mp_obj_t board_spi(void) { - mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); - return NULL; -} -#endif -MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi); +// //| .. function:: SPI() +// //| +// //| Returns the `busio.SPI` object for the board designated SCK, MOSI and MISO pins. It is a +// //| singleton. +// //| +// #if BOARD_SPI +// mp_obj_t board_spi(void) { +// mp_obj_t singleton = common_hal_board_get_spi(); +// if (singleton != NULL) { +// return singleton; +// } +// assert_pin_free(DEFAULT_SPI_BUS_SCK); +// assert_pin_free(DEFAULT_SPI_BUS_MOSI); +// assert_pin_free(DEFAULT_SPI_BUS_MISO); +// return common_hal_board_create_spi(); +// } +// #else +// mp_obj_t board_spi(void) { +// mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); +// return NULL; +// } +// #endif +// MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi); -//| .. function:: UART() -//| -//| Returns the `busio.UART` object for the board designated TX and RX pins. It is a singleton. -//| -#if BOARD_UART -mp_obj_t board_uart(void) { - mp_obj_t singleton = common_hal_board_get_uart(); - if (singleton != NULL) { - return singleton; - } +// //| .. function:: UART() +// //| +// //| Returns the `busio.UART` object for the board designated TX and RX pins. It is a singleton. +// //| +// #if BOARD_UART +// mp_obj_t board_uart(void) { +// mp_obj_t singleton = common_hal_board_get_uart(); +// if (singleton != NULL) { +// return singleton; +// } - assert_pin_free(DEFAULT_UART_BUS_RX); - assert_pin_free(DEFAULT_UART_BUS_TX); +// assert_pin_free(DEFAULT_UART_BUS_RX); +// assert_pin_free(DEFAULT_UART_BUS_TX); - return common_hal_board_create_uart(); -} -#else -mp_obj_t board_uart(void) { - mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); - return NULL; -} -#endif -MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); +// return common_hal_board_create_uart(); +// } +// #else +// mp_obj_t board_uart(void) { +// mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); +// return NULL; +// } +// #endif +// MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); const mp_obj_module_t board_module = { .base = { &mp_type_module }, diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index be8502bc0..b29e9df61 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -24,18 +24,18 @@ * THE SOFTWARE. */ -#include "shared-bindings/busio/I2C.h" -#include "shared-bindings/busio/SPI.h" -#include "shared-bindings/busio/UART.h" +// #include "shared-bindings/busio/I2C.h" +// #include "shared-bindings/busio/SPI.h" +// #include "shared-bindings/busio/UART.h" #include "shared-bindings/microcontroller/Pin.h" #include "supervisor/shared/translate.h" #include "mpconfigboard.h" #include "py/runtime.h" -#ifdef CIRCUITPY_DISPLAYIO -#include "shared-module/displayio/__init__.h" -#endif +// #ifdef CIRCUITPY_DISPLAYIO +// #include "shared-module/displayio/__init__.h" +// #endif #if BOARD_I2C mp_obj_t common_hal_board_get_i2c(void) { diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index ec778e91c..b3c16f4ae 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -40,7 +40,9 @@ extern uint16_t usb_serial_number[1 + COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2]; void load_serial_number(void) { // create serial number based on device unique id - uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH]; + +//LUCIAN: edited to fake a serial number + uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH] = {'0','1','2','3'}; //common_hal_mcu_processor_get_uid(raw_id); static const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 4ea3a8260..5490bf059 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -51,6 +51,7 @@ else SRC_SUPERVISOR += supervisor/internal_flash.c endif +USB=FALSE ifeq ($(USB),FALSE) ifeq ($(wildcard supervisor/serial.c),) SRC_SUPERVISOR += supervisor/stub/serial.c -- cgit v1.2.3 From 4a6bdb6fe471b3024b2ca1d977ef02bfd94cc12a Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 18 Jul 2019 16:47:28 -0700 Subject: Track a dirty area for in-memory bitmaps This fixes the bug that bitmap changes do not cause screen updates and optimizes the refresh when the bitmap is simply shown on the screen. If the bitmap is used in tiles, then changing it will cause all TileGrids using it to do a full refresh. Fixes #1981 --- shared-bindings/displayio/TileGrid.c | 7 ++++--- shared-bindings/displayio/TileGrid.h | 3 ++- shared-module/displayio/Bitmap.c | 38 ++++++++++++++++++++++++++++++++++++ shared-module/displayio/Bitmap.h | 5 +++++ shared-module/displayio/TileGrid.c | 32 +++++++++++++++++++++++++++--- shared-module/displayio/TileGrid.h | 3 ++- supervisor/shared/display.h | 3 +-- tools/gen_display_resources.py | 3 ++- 8 files changed, 83 insertions(+), 11 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index 6ba4914a0..53fbb51c8 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -131,7 +131,8 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t); self->base.type = &displayio_tilegrid_type; - common_hal_displayio_tilegrid_construct(self, native, bitmap_width / tile_width, + common_hal_displayio_tilegrid_construct(self, native, + bitmap_width / tile_width, bitmap_height / tile_height, pixel_shader, args[ARG_width].u_int, args[ARG_height].u_int, tile_width, tile_height, x, y, args[ARG_default_tile].u_int); return MP_OBJ_FROM_PTR(self); @@ -346,7 +347,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v } if (x >= common_hal_displayio_tilegrid_get_width(self) || y >= common_hal_displayio_tilegrid_get_height(self)) { - mp_raise_IndexError(translate("tile index out of bounds")); + mp_raise_IndexError(translate("Tile index out of bounds")); } if (value_obj == MP_OBJ_SENTINEL) { @@ -357,7 +358,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v } else { mp_int_t value = mp_obj_get_int(value_obj); if (value < 0 || value > 255) { - mp_raise_ValueError(translate("Tile indices must be 0 - 255")); + mp_raise_ValueError(translate("Tile value out of bounds")); } common_hal_displayio_tilegrid_set_tile(self, x, y, value); } diff --git a/shared-bindings/displayio/TileGrid.h b/shared-bindings/displayio/TileGrid.h index 1f9995a94..8227abfd3 100644 --- a/shared-bindings/displayio/TileGrid.h +++ b/shared-bindings/displayio/TileGrid.h @@ -32,7 +32,8 @@ extern const mp_obj_type_t displayio_tilegrid_type; void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap, - uint16_t bitmap_width_in_tiles, mp_obj_t pixel_shader, uint16_t width, uint16_t height, + uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles, + mp_obj_t pixel_shader, uint16_t width, uint16_t height, uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile); mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self); diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index f8dc24c15..59971d25c 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -63,6 +63,11 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t wi } self->x_mask = (1 << self->x_shift) - 1; // Used as a modulus on the x value self->bitmask = (1 << bits_per_value) - 1; + + self->dirty_area.x1 = 0; + self->dirty_area.x2 = width; + self->dirty_area.y1 = 0; + self->dirty_area.y2 = height; } uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self) { @@ -104,6 +109,26 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, if (self->read_only) { mp_raise_RuntimeError(translate("Read-only object")); } + // Update the dirty area. + if (self->dirty_area.x1 == self->dirty_area.x2) { + self->dirty_area.x1 = x; + self->dirty_area.x2 = x + 1; + self->dirty_area.y1 = y; + self->dirty_area.y2 = y + 1; + } else { + if (x < self->dirty_area.x1) { + self->dirty_area.x1 = x; + } else if (x >= self->dirty_area.x2) { + self->dirty_area.x2 = x + 1; + } + if (y < self->dirty_area.y1) { + self->dirty_area.y1 = y; + } else if (y >= self->dirty_area.y2) { + self->dirty_area.y2 = y + 1; + } + } + + // Update our data int32_t row_start = y * self->stride; uint32_t bytes_per_value = self->bits_per_value / 8; if (bytes_per_value < 1) { @@ -124,3 +149,16 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, } } } + +displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail) { + if (self->dirty_area.x1 == self->dirty_area.x2) { + return tail; + } + self->dirty_area.next = tail; + return &self->dirty_area; +} + +void displayio_bitmap_finish_refresh(displayio_bitmap_t *self) { + self->dirty_area.x1 = 0; + self->dirty_area.x2 = 0; +} diff --git a/shared-module/displayio/Bitmap.h b/shared-module/displayio/Bitmap.h index 48ca9e2cf..f4bd7ce4d 100644 --- a/shared-module/displayio/Bitmap.h +++ b/shared-module/displayio/Bitmap.h @@ -31,6 +31,7 @@ #include #include "py/obj.h" +#include "shared-module/displayio/area.h" typedef struct { mp_obj_base_t base; @@ -41,8 +42,12 @@ typedef struct { uint8_t bits_per_value; uint8_t x_shift; size_t x_mask; + displayio_area_t dirty_area; uint16_t bitmask; bool read_only; } displayio_bitmap_t; +void displayio_bitmap_finish_refresh(displayio_bitmap_t *self); +displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail); + #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_BITMAP_H diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index cdca45a29..31abfb712 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -26,6 +26,7 @@ #include "shared-bindings/displayio/TileGrid.h" +#include "py/runtime.h" #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/displayio/OnDiskBitmap.h" @@ -33,7 +34,7 @@ #include "shared-bindings/displayio/Shape.h" void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap, - uint16_t bitmap_width_in_tiles, + uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles, mp_obj_t pixel_shader, uint16_t width, uint16_t height, uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile) { uint32_t total_tiles = width * height; @@ -54,6 +55,7 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_ self->inline_tiles = false; } self->bitmap_width_in_tiles = bitmap_width_in_tiles; + self->tiles_in_bitmap = bitmap_width_in_tiles * bitmap_height_in_tiles; self->width_in_tiles = width; self->height_in_tiles = height; self->x = x; @@ -204,6 +206,9 @@ uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint1 } void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index) { + if (tile_index >= self->tiles_in_bitmap) { + mp_raise_ValueError(translate("Tile value out of bounds")); + } uint8_t* tiles = self->tiles; if (self->inline_tiles) { tiles = (uint8_t*) &self->tiles; @@ -442,6 +447,14 @@ void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) { } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { displayio_colorconverter_finish_refresh(self->pixel_shader); } + if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + displayio_bitmap_finish_refresh(self->bitmap); + } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { + // TODO: Support shape changes. + } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) { + // OnDiskBitmap changes will trigger a complete reload so no need to + // track changes. + } // TODO(tannewt): We could double buffer changes to position and move them over here. // That way they won't change during a refresh and tear. } @@ -458,8 +471,21 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel return &self->current_area; } - // We must recheck if our sources require a refresh because needs_refresh may or may not have - // been called. + // If we have an in-memory bitmap, then check it for modifications. + if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + displayio_area_t* refresh_area = displayio_bitmap_get_refresh_areas(self->bitmap, tail); + if (refresh_area != tail) { + // Special case a TileGrid that shows a full bitmap and use it's + // dirty area. Copy it to ours so we can transform it. + if (self->tiles_in_bitmap == 1) { + displayio_area_copy(refresh_area, &self->dirty_area); + self->partial_change = true; + } else { + self->full_change = true; + } + } + } + self->full_change = self->full_change || (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type) && displayio_palette_needs_refresh(self->pixel_shader)) || diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index 4d97eccc2..160b920dd 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -41,7 +41,8 @@ typedef struct { int16_t y; uint16_t pixel_width; uint16_t pixel_height; - uint16_t bitmap_width_in_tiles; + uint16_t bitmap_width_in_tiles;; + uint8_t tiles_in_bitmap; uint16_t width_in_tiles; uint16_t height_in_tiles; uint16_t tile_width; diff --git a/supervisor/shared/display.h b/supervisor/shared/display.h index d5faa7777..2a2ccf46d 100644 --- a/supervisor/shared/display.h +++ b/supervisor/shared/display.h @@ -35,11 +35,10 @@ // These are autogenerated resources. // This is fixed so it doesn't need to be in RAM. -extern const displayio_bitmap_t supervisor_terminal_font_bitmap; - extern const fontio_builtinfont_t supervisor_terminal_font; // These will change so they must live in RAM. +extern displayio_bitmap_t supervisor_terminal_font_bitmap; extern displayio_tilegrid_t supervisor_terminal_text_grid; extern terminalio_terminal_obj_t supervisor_terminal; diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 2c674c8eb..9707b210c 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -122,6 +122,7 @@ displayio_tilegrid_t supervisor_terminal_text_grid = {{ .pixel_width = {1}, .pixel_height = {2}, .bitmap_width_in_tiles = {0}, + .tiles_in_bitmap = {0}, .width_in_tiles = 1, .height_in_tiles = 1, .tile_width = {1}, @@ -150,7 +151,7 @@ c_file.write("""\ """) c_file.write("""\ -const displayio_bitmap_t supervisor_terminal_font_bitmap = {{ +displayio_bitmap_t supervisor_terminal_font_bitmap = {{ .base = {{.type = &displayio_bitmap_type }}, .width = {}, .height = {}, -- cgit v1.2.3 From d9089f52ce92519448c88ef50655b31e123b23bd Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 19 Jul 2019 10:42:20 -0700 Subject: Fix it's -> its --- shared-module/displayio/TileGrid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 31abfb712..ec3950492 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -475,7 +475,7 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { displayio_area_t* refresh_area = displayio_bitmap_get_refresh_areas(self->bitmap, tail); if (refresh_area != tail) { - // Special case a TileGrid that shows a full bitmap and use it's + // Special case a TileGrid that shows a full bitmap and use its // dirty area. Copy it to ours so we can transform it. if (self->tiles_in_bitmap == 1) { displayio_area_copy(refresh_area, &self->dirty_area); -- cgit v1.2.3 From 6797ec6ed396f65916fe816f8b2b49114253dd86 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 5 Jul 2019 19:01:54 -0700 Subject: Add support for grayscale displays that are < 8 bit depth. This also improves Palette so it stores the original RGB888 colors. Lastly, it adds I2CDisplay as a display bus to talk over I2C. Particularly useful for the SSD1306. Fixes #1828. Fixes #1956 --- .../atmel-samd/boards/hallowing_m0_express/board.c | 3 + ports/atmel-samd/boards/pybadge/board.c | 3 + ports/atmel-samd/boards/pybadge_airlift/board.c | 3 + ports/atmel-samd/boards/pygamer/board.c | 3 + ports/atmel-samd/boards/pygamer_advance/board.c | 3 + ports/atmel-samd/boards/pyportal/board.c | 5 +- ports/atmel-samd/boards/ugame10/board.c | 3 + ports/atmel-samd/common-hal/busio/I2C.c | 9 ++ ports/atmel-samd/common-hal/busio/SPI.h | 1 + .../atmel-samd/common-hal/displayio/ParallelBus.c | 17 +- ports/nrf/common-hal/busio/I2C.c | 17 ++ ports/nrf/common-hal/busio/SPI.c | 2 +- py/circuitpy_defns.mk | 1 + shared-bindings/_stage/__init__.c | 7 +- shared-bindings/busio/I2C.h | 3 + shared-bindings/displayio/ColorConverter.c | 6 +- shared-bindings/displayio/ColorConverter.h | 4 +- shared-bindings/displayio/Display.c | 16 +- shared-bindings/displayio/Display.h | 6 +- shared-bindings/displayio/I2CDisplay.c | 138 ++++++++++++++++ shared-bindings/displayio/I2CDisplay.h | 46 ++++++ shared-bindings/displayio/Palette.c | 27 +++- shared-bindings/displayio/Palette.h | 2 + shared-bindings/displayio/__init__.c | 3 + shared-module/displayio/ColorConverter.c | 35 ++++- shared-module/displayio/ColorConverter.h | 4 + shared-module/displayio/Display.c | 173 +++++++++++++++------ shared-module/displayio/Display.h | 4 +- shared-module/displayio/FourWire.c | 21 ++- shared-module/displayio/FourWire.h | 6 +- shared-module/displayio/Group.c | 6 +- shared-module/displayio/Group.h | 3 +- shared-module/displayio/I2CDisplay.c | 105 +++++++++++++ shared-module/displayio/I2CDisplay.h | 41 +++++ shared-module/displayio/Palette.c | 50 +++--- shared-module/displayio/Palette.h | 19 ++- shared-module/displayio/TileGrid.c | 50 ++++-- shared-module/displayio/TileGrid.h | 3 +- shared-module/displayio/__init__.c | 135 ++++++++++------ shared-module/displayio/__init__.h | 2 + shared-module/terminalio/Terminal.c | 2 + supervisor/shared/display.c | 49 ++++-- tools/gen_display_resources.py | 17 +- 43 files changed, 855 insertions(+), 198 deletions(-) create mode 100644 shared-bindings/displayio/I2CDisplay.c create mode 100644 shared-bindings/displayio/I2CDisplay.h create mode 100644 shared-module/displayio/I2CDisplay.c create mode 100644 shared-module/displayio/I2CDisplay.h (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/hallowing_m0_express/board.c b/ports/atmel-samd/boards/hallowing_m0_express/board.c index a0e160757..1bbbfbaf8 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m0_express/board.c @@ -91,6 +91,8 @@ void board_init(void) { 1, // row start 0, // rotation 16, // Color depth + false, // Grayscale + false, // Pixels in a byte share a row. Only used for depth < 8 MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command @@ -98,6 +100,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA00, + 0x100, // Brightness command. Only available when <= 0xff 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pybadge/board.c b/ports/atmel-samd/boards/pybadge/board.c index 38902315a..7e6c11dd4 100644 --- a/ports/atmel-samd/boards/pybadge/board.c +++ b/ports/atmel-samd/boards/pybadge/board.c @@ -93,6 +93,8 @@ void board_init(void) { 0, // row start 270, // rotation 16, // Color depth + false, // grayscale + false, // pixels in byte share row. only used for depth < 8 MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command @@ -100,6 +102,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA01, // backlight pin + 0x100, // no brightness command 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pybadge_airlift/board.c b/ports/atmel-samd/boards/pybadge_airlift/board.c index a1f778df1..d7f291d7d 100644 --- a/ports/atmel-samd/boards/pybadge_airlift/board.c +++ b/ports/atmel-samd/boards/pybadge_airlift/board.c @@ -71,6 +71,8 @@ void board_init(void) { 0, // row start 90, // rotation 16, // Color depth + false, // grayscale + false, // pixels in byte share row. Only used for depth < 8 MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command @@ -78,6 +80,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA01, // backlight pin + 0x100, // brightness command, only valid <= 0xff 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pygamer/board.c b/ports/atmel-samd/boards/pygamer/board.c index 7b54b6fb5..e59b7c458 100644 --- a/ports/atmel-samd/boards/pygamer/board.c +++ b/ports/atmel-samd/boards/pygamer/board.c @@ -93,6 +93,8 @@ void board_init(void) { 0, // row start 270, // rotation 16, // Color depth + false, // Grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command @@ -100,6 +102,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA01, // backlight pin + 0x100, // Brightness command. Only available when < 0xff 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pygamer_advance/board.c b/ports/atmel-samd/boards/pygamer_advance/board.c index d1c5edc99..b23353998 100644 --- a/ports/atmel-samd/boards/pygamer_advance/board.c +++ b/ports/atmel-samd/boards/pygamer_advance/board.c @@ -71,6 +71,8 @@ void board_init(void) { 0, // row start 90, // rotation 16, // Color depth + false, // Grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command @@ -78,6 +80,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA01, // backlight pin + 0x100, // Brightness command. Only available when < 0xff 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pyportal/board.c b/ports/atmel-samd/boards/pyportal/board.c index bb80c5b48..7fffb764f 100644 --- a/ports/atmel-samd/boards/pyportal/board.c +++ b/ports/atmel-samd/boards/pyportal/board.c @@ -83,13 +83,16 @@ void board_init(void) { 0, // row start 0, // rotation 16, // Color depth + false, // grayscale + false, // pixels_in_byte_share_row (unused for depths > 8) MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command 0x37, // Set vertical scroll command display_init_sequence, sizeof(display_init_sequence), - &pin_PB31, + &pin_PB31, // Backlight pin + 0x100, // Brightness command > 0xff is none s 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/ugame10/board.c b/ports/atmel-samd/boards/ugame10/board.c index 828f0c87d..27a03ad91 100644 --- a/ports/atmel-samd/boards/ugame10/board.c +++ b/ports/atmel-samd/boards/ugame10/board.c @@ -91,6 +91,8 @@ void board_init(void) { 2, // row start 0, // rotation 16, // Color depth + false, // grayscale + false, // pixels in byte share row. Only used with depth < 8 MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command @@ -98,6 +100,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), NULL, + 0x100, // brightness command. Only valid <=0xff 1.0f, // brightness false, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index a0c04d65d..cdc616bbc 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -36,6 +36,8 @@ #include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/translate.h" +#include "common-hal/busio/SPI.h" // for never_reset_sercom + // Number of times to try to send packet if failed. #define ATTEMPTS 2 @@ -225,3 +227,10 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, } return MP_EIO; } + +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + never_reset_sercom(self->i2c_desc.device.hw); + + never_reset_pin_number(self->scl_pin); + never_reset_pin_number(self->sda_pin); +} diff --git a/ports/atmel-samd/common-hal/busio/SPI.h b/ports/atmel-samd/common-hal/busio/SPI.h index 56d163a9d..a1c0e1517 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.h +++ b/ports/atmel-samd/common-hal/busio/SPI.h @@ -43,6 +43,7 @@ typedef struct { } busio_spi_obj_t; void reset_sercoms(void); +void never_reset_sercom(Sercom* sercom); #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/atmel-samd/common-hal/displayio/ParallelBus.c b/ports/atmel-samd/common-hal/displayio/ParallelBus.c index 7a5f61448..c370f7e52 100644 --- a/ports/atmel-samd/common-hal/displayio/ParallelBus.c +++ b/ports/atmel-samd/common-hal/displayio/ParallelBus.c @@ -31,6 +31,7 @@ #include "common-hal/microcontroller/Pin.h" #include "py/runtime.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/__init__.h" #include "tick.h" @@ -66,10 +67,6 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select); common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL); - self->reset.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->reset, reset); - common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); - self->write.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->write, write); common_hal_digitalio_digitalinout_switch_to_output(&self->write, true, DRIVE_MODE_PUSH_PULL); @@ -82,11 +79,21 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel self->write_group = &PORT->Group[write->number / 32]; self->write_mask = 1 << (write->number % 32); + if (reset != NULL) { + self->reset.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->reset, reset); + common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); + never_reset_pin_number(reset->number); + + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_mcu_delay_us(4); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); + } + never_reset_pin_number(command->number); never_reset_pin_number(chip_select->number); never_reset_pin_number(write->number); never_reset_pin_number(read->number); - never_reset_pin_number(reset->number); for (uint8_t i = 0; i < 8; i++) { never_reset_pin_number(data_pin + i); } diff --git a/ports/nrf/common-hal/busio/I2C.c b/ports/nrf/common-hal/busio/I2C.c index 538c87f2d..71835d16a 100644 --- a/ports/nrf/common-hal/busio/I2C.c +++ b/ports/nrf/common-hal/busio/I2C.c @@ -57,13 +57,30 @@ STATIC twim_peripheral_t twim_peripherals[] = { #endif }; +STATIC bool never_reset[MP_ARRAY_SIZE(twim_peripherals)]; + void i2c_reset(void) { for (size_t i = 0 ; i < MP_ARRAY_SIZE(twim_peripherals); i++) { + if (never_reset[i]) { + continue; + } nrf_twim_disable(twim_peripherals[i].twim.p_twim); twim_peripherals[i].in_use = false; } } +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + for (size_t i = 0 ; i < MP_ARRAY_SIZE(twim_peripherals); i++) { + if (self->twim_peripheral == &twim_peripherals[i]) { + never_reset[i] = true; + + never_reset_pin_number(self->scl_pin_number); + never_reset_pin_number(self->sda_pin_number); + break; + } + } +} + static uint8_t twi_error_to_mp(const nrfx_err_t err) { switch (err) { case NRFX_ERROR_DRV_TWI_ERR_ANACK: diff --git a/ports/nrf/common-hal/busio/SPI.c b/ports/nrf/common-hal/busio/SPI.c index 6ab6d9493..5f1aac193 100644 --- a/ports/nrf/common-hal/busio/SPI.c +++ b/ports/nrf/common-hal/busio/SPI.c @@ -61,7 +61,7 @@ STATIC spim_peripheral_t spim_peripherals[] = { #endif }; -STATIC bool never_reset[4]; +STATIC bool never_reset[MP_ARRAY_SIZE(spim_peripherals)]; void spi_reset(void) { for (size_t i = 0 ; i < MP_ARRAY_SIZE(spim_peripherals); i++) { diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 782314fc7..93ca4deb9 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -317,6 +317,7 @@ $(filter $(SRC_PATTERNS), \ displayio/Display.c \ displayio/FourWire.c \ displayio/Group.c \ + displayio/I2CDisplay.c \ displayio/OnDiskBitmap.c \ displayio/Palette.c \ displayio/Shape.c \ diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 03775b1de..9f3f89462 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -95,7 +95,12 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { MICROPY_VM_HOOK_LOOP ; #endif } - displayio_display_set_region_to_update(display, x0, y0, x1, y1); + displayio_area_t area; + area.x1 = x0; + area.y1 = y0; + area.x2 = x1; + area.y2 = y1; + displayio_display_set_region_to_update(display, &area); render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display); displayio_display_end_transaction(display); diff --git a/shared-bindings/busio/I2C.h b/shared-bindings/busio/I2C.h index 739732e97..a2d5dbf50 100644 --- a/shared-bindings/busio/I2C.h +++ b/shared-bindings/busio/I2C.h @@ -69,4 +69,7 @@ extern uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addres extern uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t * data, size_t len); +// This is used by the supervisor to claim I2C devices indefinitely. +extern void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_H diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index 561883810..e170e0340 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -69,8 +69,10 @@ STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t if (!mp_obj_get_int_maybe(color_obj, &color)) { mp_raise_ValueError(translate("color should be an int")); } - uint16_t output_color; - common_hal_displayio_colorconverter_convert(self, color, &output_color); + _displayio_colorspace_t colorspace; + colorspace.depth = 16; + uint32_t output_color; + common_hal_displayio_colorconverter_convert(self, &colorspace, color, &output_color); return MP_OBJ_NEW_SMALL_INT(output_color); } MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_convert_obj, displayio_colorconverter_obj_convert); diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index 71be7f543..8f61e6642 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -29,9 +29,11 @@ #include "shared-module/displayio/ColorConverter.h" +#include "shared-module/displayio/Palette.h" + extern const mp_obj_type_t displayio_colorconverter_type; void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self); -bool common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, uint32_t input_color, uint16_t* output_color); +bool common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 1a36872a6..2586e562f 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -51,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the initialization sequence at minimum. //| -//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) +//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) //| //| Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -88,18 +88,21 @@ //| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270) //| :param int color_depth: The number of bits of color per pixel transmitted. (Some displays //| support 18 bit but 16 is easier to transmit. The last bit is extrapolated.) +//| :param bool grayscale: True if the display only shows a single color. +//| :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column. //| :param int set_column_command: Command used to set the start and end columns to update //| :param int set_row_command: Command used so set the start and end rows to update -//| :param int write_ram_command: Command used to write pixels values into the update region +//| :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set. //| :param int set_vertical_scroll: Command used to set the first row to show //| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight +//| :param int brightness_command: Command to set display brightness. Usually available in OLED controllers. //| :param bool brightness: Initial display brightness. This value is ignored if auto_brightness is True. //| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. //| :param bool single_byte_bounds: Display column and row commands use single bytes //| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. //| STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -109,11 +112,14 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_rowstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_pixels_in_byte_share_row, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} }, { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} }, { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} }, { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x100} }, { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, @@ -157,11 +163,13 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a common_hal_displayio_display_construct( self, display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, - args[ARG_color_depth].u_int, args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int, + args[ARG_color_depth].u_int, args[ARG_grayscale].u_bool, args[ARG_pixels_in_byte_share_row].u_bool, + args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int, args[ARG_write_ram_command].u_int, args[ARG_set_vertical_scroll].u_int, bufinfo.buf, bufinfo.len, MP_OBJ_TO_PTR(backlight_pin), + args[ARG_brightness_command].u_int, brightness, args[ARG_auto_brightness].u_bool, args[ARG_single_byte_bounds].u_bool, diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 5a027561b..a60a0cf5a 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -38,9 +38,9 @@ extern const mp_obj_type_t displayio_display_type; void common_hal_displayio_display_construct(displayio_display_obj_t* self, mp_obj_t bus, uint16_t width, uint16_t height, - int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, + int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, - uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, + uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands); @@ -54,7 +54,7 @@ bool displayio_display_begin_transaction(displayio_display_obj_t* self); void displayio_display_end_transaction(displayio_display_obj_t* self); // The second point of the region is exclusive. -void displayio_display_set_region_to_update(displayio_display_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); +void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area); bool displayio_display_frame_queued(displayio_display_obj_t* self); bool displayio_display_refresh_queued(displayio_display_obj_t* self); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c new file mode 100644 index 000000000..2aac49b4d --- /dev/null +++ b/shared-bindings/displayio/I2CDisplay.c @@ -0,0 +1,138 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/displayio/I2CDisplay.h" + +#include +#include + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: displayio +//| +//| :class:`I2CDisplay` -- Manage updating a display over I2C +//| ========================================================================== +//| +//| Manage updating a display over I2C in the background while Python code runs. +//| It doesn't handle display initialization. +//| +//| .. class:: I2CDisplay(i2c_bus, *, device_address, reset=None) +//| +//| Create a I2CDisplay object associated with the given I2C bus and reset pin. +//| +//| The I2C bus and pins are then in use by the display until `displayio.release_displays()` is +//| called even after a reload. (It does this so CircuitPython can use the display after your code +//| is done.) So, the first time you initialize a display bus in code.py you should call +//| :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run. +//| +//| :param busio.I2C i2c_bus: The I2C bus that make up the clock and data lines +//| :param int device_address: The I2C address of the device +//| :param microcontroller.Pin reset: Reset pin. When None only software reset can be used +//| +STATIC mp_obj_t displayio_i2cdisplay_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_i2c_bus, ARG_device_address, ARG_reset }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_device_address, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t reset = args[ARG_reset].u_obj; + if (reset != mp_const_none) { + assert_pin_free(reset); + } else { + reset = NULL; + } + + displayio_i2cdisplay_obj_t* self = NULL; + mp_obj_t i2c = args[ARG_i2c_bus].u_obj; + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (displays[i].i2cdisplay_bus.base.type == NULL || + displays[i].i2cdisplay_bus.base.type == &mp_type_NoneType) { + self = &displays[i].i2cdisplay_bus; + self->base.type = &displayio_i2cdisplay_type; + break; + } + } + if (self == NULL) { + mp_raise_RuntimeError(translate("Too many display busses")); + } + + common_hal_displayio_i2cdisplay_construct(self, + MP_OBJ_TO_PTR(i2c), args[ARG_device_address].u_int, reset); + return self; +} + +//| .. method:: send(command, data) +//| +//| Sends the given command value followed by the full set of data. Display state, such as +//| vertical scroll, set via ``send`` may or may not be reset once the code is done. +//| +STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) { + mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj); + if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) { + mp_raise_ValueError(translate("Command must be an int between 0 and 255")); + } + uint8_t command = command_int; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); + + // Wait for display bus to be available. + while (!common_hal_displayio_i2cdisplay_begin_transaction(self)) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP ; +#endif + } + uint8_t full_command[bufinfo.len + 1]; + full_command[0] = command; + memcpy(full_command + 1, ((uint8_t*) bufinfo.buf), bufinfo.len); + common_hal_displayio_i2cdisplay_send(self, true, full_command, bufinfo.len + 1); + common_hal_displayio_i2cdisplay_end_transaction(self); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(displayio_i2cdisplay_send_obj, displayio_i2cdisplay_obj_send); + +STATIC const mp_rom_map_elem_t displayio_i2cdisplay_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_i2cdisplay_send_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(displayio_i2cdisplay_locals_dict, displayio_i2cdisplay_locals_dict_table); + +const mp_obj_type_t displayio_i2cdisplay_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CDisplay, + .make_new = displayio_i2cdisplay_make_new, + .locals_dict = (mp_obj_dict_t*)&displayio_i2cdisplay_locals_dict, +}; diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h new file mode 100644 index 000000000..cc4162800 --- /dev/null +++ b/shared-bindings/displayio/I2CDisplay.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H + +#include "shared-module/displayio/I2CDisplay.h" +#include "common-hal/microcontroller/Pin.h" + +extern const mp_obj_type_t displayio_i2cdisplay_type; + +void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, + busio_i2c_obj_t* i2c, uint16_t device_address, const mcu_pin_obj_t* reset); + +void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self); + +bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); + +void common_hal_displayio_i2cdisplay_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length); + +void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H diff --git a/shared-bindings/displayio/Palette.c b/shared-bindings/displayio/Palette.c index 11c2f677c..974cadb02 100644 --- a/shared-bindings/displayio/Palette.c +++ b/shared-bindings/displayio/Palette.c @@ -66,11 +66,26 @@ STATIC mp_obj_t displayio_palette_make_new(const mp_obj_type_t *type, size_t n_a return MP_OBJ_FROM_PTR(self); } + +//| .. method:: __len__() +//| +//| Returns the number of colors in a Palette +//| +STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + displayio_palette_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(true); + case MP_UNARY_OP_LEN: + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_len(self)); + default: return MP_OBJ_NULL; // op not supported + } +} + //| .. method:: __setitem__(index, value) //| //| Sets the pixel color at the given index. The index should be an integer in the range 0 to color_count-1. //| -//| The value argument represents a color, and can be from 0x000000 to 0xFFFFFF (to represent an RGB value). +//| The value argument represents a color, and can be from 0x000000 to 0xFFFFFF (to represent an RGB value). //| Value can be an int, bytes (3 bytes (RGB) or 4 bytes (RGB + pad byte)), or bytearray. //| //| This allows you to:: @@ -89,12 +104,12 @@ STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t val if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { return MP_OBJ_NULL; } - // index read is not supported - if (value == MP_OBJ_SENTINEL) { - return MP_OBJ_NULL; - } displayio_palette_t *self = MP_OBJ_TO_PTR(self_in); size_t index = mp_get_index(&displayio_palette_type, self->color_count, index_in, false); + // index read + if (value == MP_OBJ_SENTINEL) { + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_color(self, index)); + } uint32_t color; mp_int_t int_value; @@ -160,5 +175,7 @@ const mp_obj_type_t displayio_palette_type = { .name = MP_QSTR_Palette, .make_new = displayio_palette_make_new, .subscr = palette_subscr, + .unary_op = group_unary_op, + .getiter = mp_obj_new_generic_iterator, .locals_dict = (mp_obj_dict_t*)&displayio_palette_locals_dict, }; diff --git a/shared-bindings/displayio/Palette.h b/shared-bindings/displayio/Palette.h index 767fc7b63..8c9fe11e3 100644 --- a/shared-bindings/displayio/Palette.h +++ b/shared-bindings/displayio/Palette.h @@ -33,6 +33,8 @@ extern const mp_obj_type_t displayio_palette_type; void common_hal_displayio_palette_construct(displayio_palette_t* self, uint16_t color_count); void common_hal_displayio_palette_set_color(displayio_palette_t* self, uint32_t palette_index, uint32_t color); +uint32_t common_hal_displayio_palette_get_color(displayio_palette_t* self, uint32_t palette_index); +uint32_t common_hal_displayio_palette_get_len(displayio_palette_t* self); void common_hal_displayio_palette_make_opaque(displayio_palette_t* self, uint32_t palette_index); void common_hal_displayio_palette_make_transparent(displayio_palette_t* self, uint32_t palette_index); diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index 9dc17103b..fd3dc4233 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -35,6 +35,7 @@ #include "shared-bindings/displayio/Display.h" #include "shared-bindings/displayio/FourWire.h" #include "shared-bindings/displayio/Group.h" +#include "shared-bindings/displayio/I2CDisplay.h" #include "shared-bindings/displayio/OnDiskBitmap.h" #include "shared-bindings/displayio/Palette.h" #include "shared-bindings/displayio/ParallelBus.h" @@ -61,6 +62,7 @@ //| Display //| FourWire //| Group +//| I2CDisplay //| OnDiskBitmap //| Palette //| ParallelBus @@ -96,6 +98,7 @@ STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_TileGrid), MP_ROM_PTR(&displayio_tilegrid_type) }, { MP_ROM_QSTR(MP_QSTR_FourWire), MP_ROM_PTR(&displayio_fourwire_type) }, + { MP_ROM_QSTR(MP_QSTR_I2CDisplay), MP_ROM_PTR(&displayio_i2cdisplay_type) }, { MP_ROM_QSTR(MP_QSTR_ParallelBus), MP_ROM_PTR(&displayio_parallelbus_type) }, { MP_ROM_QSTR(MP_QSTR_release_displays), MP_ROM_PTR(&displayio_release_displays_obj) }, diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 3928e115a..563d40c51 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -29,15 +29,36 @@ void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self) { } -bool common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, uint32_t input_color, uint16_t* output_color) { - // TODO(tannewt): Validate the color input against the input format. - uint32_t r5 = (input_color >> 19); - uint32_t g6 = (input_color >> 10) & 0x3f; - uint32_t b5 = (input_color >> 3) & 0x1f; +uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) { + uint32_t r5 = (color_rgb888 >> 19); + uint32_t g6 = (color_rgb888 >> 10) & 0x3f; + uint32_t b5 = (color_rgb888 >> 3) & 0x1f; uint32_t packed = r5 << 11 | g6 << 5 | b5; // swap bytes - *output_color = __builtin_bswap16(packed); - return true; + return __builtin_bswap16(packed); +} + +uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888) { + uint32_t r8 = (color_rgb888 >> 16); + uint32_t g8 = (color_rgb888 >> 8) & 0xff; + uint32_t b8 = color_rgb888 & 0xff; + return (r8 * 19) / 255 + (g8 * 182) / 255 + (b8 + 54) / 255; +} + +bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { + if (colorspace->depth == 16) { + *output_color = displayio_colorconverter_compute_rgb565(input_color); + return true; + } else if (colorspace->grayscale && colorspace->depth <= 8) { + uint8_t luma = displayio_colorconverter_compute_luma(input_color); + *output_color = luma >> (8 - colorspace->depth); + return true; + } + return false; +} + +bool common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { + return displayio_colorconverter_convert(self, colorspace, input_color, output_color); } // Currently no refresh logic is needed for a ColorConverter. diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index 7f3c1a0a0..c48b98e6d 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -31,6 +31,7 @@ #include #include "py/obj.h" +#include "shared-module/displayio/Palette.h" typedef struct { mp_obj_base_t base; @@ -38,5 +39,8 @@ typedef struct { bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self); void displayio_colorconverter_finish_refresh(displayio_colorconverter_t *self); +bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); +uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888); +uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888); #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 0ae88300a..9aee70e32 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -28,6 +28,7 @@ #include "py/runtime.h" #include "shared-bindings/displayio/FourWire.h" +#include "shared-bindings/displayio/I2CDisplay.h" #include "shared-bindings/displayio/ParallelBus.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" @@ -35,6 +36,7 @@ #include "supervisor/shared/display.h" #include +#include #include "tick.h" @@ -42,11 +44,14 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, - uint16_t color_depth, uint8_t set_column_command, uint8_t set_row_command, + uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, + uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, - const mcu_pin_obj_t* backlight_pin, mp_float_t brightness, bool auto_brightness, + const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands) { - self->color_depth = color_depth; + self->colorspace.depth = color_depth; + self->colorspace.grayscale = grayscale; + self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row; self->set_column_command = set_column_command; self->set_row_command = set_row_command; self->write_ram_command = write_ram_command; @@ -54,6 +59,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->current_group = NULL; self->colstart = colstart; self->rowstart = rowstart; + self->brightness_command = brightness_command; self->auto_brightness = auto_brightness; self->data_as_commands = data_as_commands; self->single_byte_bounds = single_byte_bounds; @@ -66,6 +72,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; self->send = common_hal_displayio_fourwire_send; self->end_transaction = common_hal_displayio_fourwire_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { + self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; + self->send = common_hal_displayio_i2cdisplay_send; + self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; } else { mp_raise_ValueError(translate("Unsupported display bus type")); } @@ -83,13 +93,13 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool delay = (data_size & DELAY) != 0; data_size &= ~DELAY; uint8_t *data = cmd + 2; - self->send(self->bus, true, cmd, 1); if (self->data_as_commands) { - // Loop through each parameter to force a CS toggle - for (uint32_t j=0; j < data_size; j++) { - self->send(self->bus, true, data + j, 1); - } + uint8_t full_command[data_size + 1]; + full_command[0] = cmd[0]; + memcpy(full_command + 1, data, data_size); + self->send(self->bus, true, full_command, data_size + 1); } else { + self->send(self->bus, true, cmd, 1); self->send(self->bus, false, data, data_size); } uint16_t delay_length_ms = 10; @@ -141,11 +151,13 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, } else { self->backlight_pwm.base.type = &pulseio_pwmout_type; common_hal_pulseio_pwmout_never_reset(&self->backlight_pwm); - if (!self->auto_brightness) { - common_hal_displayio_display_set_brightness(self, brightness); - } } } + if (!self->auto_brightness && (self->backlight_inout.base.type != &mp_type_NoneType || brightness_command <= 0xff)) { + common_hal_displayio_display_set_brightness(self, brightness); + } else { + self->current_brightness = -1.0; + } self->area.x1 = 0; self->area.y1 = 0; @@ -234,17 +246,7 @@ void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* s } mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self) { - if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { - uint16_t duty_cycle = common_hal_pulseio_pwmout_get_duty_cycle(&self->backlight_pwm); - return duty_cycle / ((mp_float_t) 0xffff); - } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { - if (common_hal_digitalio_digitalinout_get_value(&self->backlight_inout)) { - return 1.0; - } else { - return 0.0; - } - } - return -1.0; + return self->current_brightness; } bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness) { @@ -256,8 +258,26 @@ bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); ok = true; + } else if (self->brightness_command < 0x100) { + ok = self->begin_transaction(self->bus); + if (ok) { + if (self->data_as_commands) { + uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; + self->send(self->bus, true, set_brightness, 2); + } else { + uint8_t command = self->brightness_command; + uint8_t hex_brightness = 0xff * brightness; + self->send(self->bus, true, &command, 1); + self->send(self->bus, false, &hex_brightness, 1); + } + self->end_transaction(self->bus); + } + } self->updating_backlight = false; + if (ok) { + self->current_brightness = brightness; + } return ok; } @@ -269,35 +289,67 @@ void displayio_display_end_transaction(displayio_display_obj_t* self) { self->end_transaction(self->bus); } -void displayio_display_set_region_to_update(displayio_display_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { - self->send(self->bus, true, &self->set_column_command, 1); - bool isCommand = self->data_as_commands; - if (self->single_byte_bounds) { - uint8_t data[2]; - data[0] = x0 + self->colstart; - data[1] = x1 - 1 + self->colstart; - self->send(self->bus, isCommand, (uint8_t*) data, 2); - } else { - uint16_t data[2]; - data[0] = __builtin_bswap16(x0 + self->colstart); - data[1] = __builtin_bswap16(x1 - 1 + self->colstart); - self->send(self->bus, isCommand, (uint8_t*) data, 4); +void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area) { + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + uint16_t y1 = area->y1; + uint16_t y2 = area->y2; + // Collapse down the dimension where multiple pixels are in a byte. + if (self->colorspace.depth < 8) { + uint8_t pixels_per_byte = 8 / self->colorspace.depth; + if (self->colorspace.pixels_in_byte_share_row) { + x1 /= pixels_per_byte; + x2 /= pixels_per_byte; + } else { + y1 /= pixels_per_byte; + y2 /= pixels_per_byte; + } + } + + // Set column. + uint8_t data[5]; + data[0] = self->set_column_command; + uint8_t data_length = 1; + if (!self->data_as_commands) { + self->send(self->bus, true, data, 1); + data_length = 0; } - self->send(self->bus, true, &self->set_row_command, 1); if (self->single_byte_bounds) { - uint8_t data[2]; - data[0] = y0 + self->rowstart; - data[1] = y1 - 1 + self->rowstart; - self->send(self->bus, isCommand, (uint8_t*) data, 2); + data[data_length] = x1 + self->colstart; + data[data_length + 1] = x2 - 1 + self->colstart; + data_length += 2; } else { - uint16_t data[2]; - data[0] = __builtin_bswap16(y0 + self->rowstart); - data[1] = __builtin_bswap16(y1 - 1 + self->rowstart); - self->send(self->bus, isCommand, (uint8_t*) data, 4); + x1 += self->colstart; + x2 += self->colstart - 1; + data[data_length] = x1 >> 8; + data[data_length + 1] = x1 & 0xff; + data[data_length + 2] = x2 >> 8; + data[data_length + 3] = x2 & 0xff; + data_length += 4; } + self->send(self->bus, self->data_as_commands, data, data_length); + + // Set row. + data[0] = self->set_row_command; + data_length = 1; if (!self->data_as_commands) { - self->send(self->bus, true, &self->write_ram_command, 1); + self->send(self->bus, true, data, 1); + data_length = 0; } + if (self->single_byte_bounds) { + data[data_length] = y1 + self->rowstart; + data[data_length + 1] = y2 - 1 + self->rowstart; + data_length += 2; + } else { + y1 += self->rowstart; + y2 += self->rowstart - 1; + data[data_length] = y1 >> 8; + data[data_length + 1] = y1 & 0xff; + data[data_length + 2] = y2 >> 8; + data[data_length + 3] = y2 & 0xff; + data_length += 4; + } + self->send(self->bus, self->data_as_commands, data, data_length); } void displayio_display_start_refresh(displayio_display_obj_t* self) { @@ -322,6 +374,9 @@ void displayio_display_finish_refresh(displayio_display_obj_t* self) { } void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { + if (!self->data_as_commands) { + self->send(self->bus, true, &self->write_ram_command, 1); + } self->send(self->bus, false, pixels, length); } @@ -349,9 +404,33 @@ void release_display(displayio_display_obj_t* self) { } bool displayio_display_fill_area(displayio_display_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { - return displayio_group_fill_area(self->current_group, area, mask, buffer); + return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); } bool displayio_display_clip_area(displayio_display_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped) { - return displayio_area_compute_overlap(&self->area, area, clipped); + bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); + if (!overlaps) { + return false; + } + // Expand the area if we have multiple pixels per byte and we need to byte + // align the bounds. + if (self->colorspace.depth < 8) { + uint8_t pixels_per_byte = 8 / self->colorspace.depth; + if (self->colorspace.pixels_in_byte_share_row) { + if (clipped->x1 % pixels_per_byte != 0) { + clipped->x1 -= clipped->x1 % pixels_per_byte; + } + if (clipped->x2 % pixels_per_byte != 0) { + clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; + } + } else { + if (clipped->y1 % pixels_per_byte != 0) { + clipped->y1 -= clipped->y1 % pixels_per_byte; + } + if (clipped->y2 % pixels_per_byte != 0) { + clipped->y2 += pixels_per_byte - clipped->y2 % pixels_per_byte; + } + } + } + return true; } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index fa8902ced..96d1c06d5 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -52,11 +52,13 @@ typedef struct { uint64_t last_backlight_refresh; displayio_buffer_transform_t transform; displayio_area_t area; + mp_float_t current_brightness; uint16_t width; uint16_t height; - uint16_t color_depth; + _displayio_colorspace_t colorspace; int16_t colstart; int16_t rowstart; + uint16_t brightness_command; uint8_t set_column_command; uint8_t set_row_command; uint8_t write_ram_command; diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index d38da56fc..913635db8 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -59,6 +59,11 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); + + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_mcu_delay_us(10); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); + common_hal_mcu_delay_us(10); } never_reset_pin_number(command->number); @@ -88,13 +93,19 @@ bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) { void common_hal_displayio_fourwire_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); + common_hal_digitalio_digitalinout_set_value(&self->command, !command); if (command) { - common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); - common_hal_mcu_delay_us(1); - common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + // Toggle chip select after each command byte in case the display driver + // IC latches commands based on it. + for (size_t i = 0; i < data_length; i++) { + common_hal_busio_spi_write(self->bus, &data[i], 1); + common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + common_hal_mcu_delay_us(1); + common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + } + } else { + common_hal_busio_spi_write(self->bus, data, data_length); } - common_hal_digitalio_digitalinout_set_value(&self->command, !command); - common_hal_busio_spi_write(self->bus, data, data_length); } void common_hal_displayio_fourwire_end_transaction(mp_obj_t obj) { diff --git a/shared-module/displayio/FourWire.h b/shared-module/displayio/FourWire.h index 743139e62..a4260a3ac 100644 --- a/shared-module/displayio/FourWire.h +++ b/shared-module/displayio/FourWire.h @@ -24,8 +24,8 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_DISPLAYIO_FOURWIRE_H -#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_DISPLAYIO_FOURWIRE_H +#ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_FOURWIRE_H +#define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_FOURWIRE_H #include "common-hal/busio/SPI.h" #include "common-hal/digitalio/DigitalInOut.h" @@ -43,4 +43,4 @@ typedef struct { uint8_t phase; } displayio_fourwire_obj_t; -#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_DISPLAYIO_FOURWIRE_H +#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_FOURWIRE_H diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index 15060e87b..38418a029 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -270,19 +270,19 @@ void displayio_group_construct(displayio_group_t* self, displayio_group_child_t* self->in_group = false; } -bool displayio_group_fill_area(displayio_group_t *self, const displayio_area_t* area, uint32_t* mask, uint32_t* buffer) { +bool displayio_group_fill_area(displayio_group_t *self, const _displayio_colorspace_t* colorspace, const displayio_area_t* area, uint32_t* mask, uint32_t* buffer) { // Track if any of the layers finishes filling in the given area. We can ignore any remaining // layers at that point. bool full_coverage = false; for (int32_t i = self->size - 1; i >= 0 ; i--) { mp_obj_t layer = self->children[i].native; if (MP_OBJ_IS_TYPE(layer, &displayio_tilegrid_type)) { - if (displayio_tilegrid_fill_area(layer, area, mask, buffer)) { + if (displayio_tilegrid_fill_area(layer, colorspace, area, mask, buffer)) { full_coverage = true; break; } } else if (MP_OBJ_IS_TYPE(layer, &displayio_group_type)) { - if (displayio_group_fill_area(layer, area, mask, buffer)) { + if (displayio_group_fill_area(layer, colorspace, area, mask, buffer)) { full_coverage = true; break; } diff --git a/shared-module/displayio/Group.h b/shared-module/displayio/Group.h index 7ce19a4cd..4e2308e56 100644 --- a/shared-module/displayio/Group.h +++ b/shared-module/displayio/Group.h @@ -32,6 +32,7 @@ #include "py/obj.h" #include "shared-module/displayio/area.h" +#include "shared-module/displayio/Palette.h" typedef struct { mp_obj_t native; @@ -54,7 +55,7 @@ typedef struct { void displayio_group_construct(displayio_group_t* self, displayio_group_child_t* child_array, uint32_t max_size, uint32_t scale, mp_int_t x, mp_int_t y); bool displayio_group_get_previous_area(displayio_group_t *group, displayio_area_t* area); -bool displayio_group_fill_area(displayio_group_t *group, const displayio_area_t* area, uint32_t* mask, uint32_t *buffer); +bool displayio_group_fill_area(displayio_group_t *group, const _displayio_colorspace_t* colorspace, const displayio_area_t* area, uint32_t* mask, uint32_t *buffer); void displayio_group_update_transform(displayio_group_t *group, const displayio_buffer_transform_t* parent_transform); void displayio_group_finish_refresh(displayio_group_t *self); displayio_area_t* displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t* tail); diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c new file mode 100644 index 000000000..9d8949528 --- /dev/null +++ b/shared-module/displayio/I2CDisplay.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/displayio/I2CDisplay.h" + +#include +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/time/__init__.h" + +#include "tick.h" + +void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, + busio_i2c_obj_t* i2c, uint16_t device_address, const mcu_pin_obj_t* reset) { + + // Probe the bus to see if a device acknowledges the given address. + if (!common_hal_busio_i2c_probe(i2c, device_address)) { + mp_raise_ValueError_varg(translate("Unable to find I2C Display at %x"), device_address); + } + + // Write to the device and return 0 on success or an appropriate error code from mperrno.h + self->bus = i2c; + common_hal_busio_i2c_never_reset(self->bus); + // Our object is statically allocated off the heap so make sure the bus object lives to the end + // of the heap as well. + gc_never_free(self->bus); + + self->address = device_address; + + if (reset != NULL) { + common_hal_digitalio_digitalinout_construct(&self->reset, reset); + common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); + never_reset_pin_number(reset->number); + + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_mcu_delay_us(1); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); + } +} + +void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { + if (self->bus == &self->inline_bus) { + common_hal_busio_i2c_deinit(self->bus); + } + + reset_pin_number(self->reset.pin->number); +} + +bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { + displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); + if (!common_hal_busio_i2c_try_lock(self->bus)) { + return false; + } + return true; +} + +void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { + displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); + if (command) { + uint8_t command_bytes[2 * data_length]; + for (uint32_t i = 0; i < data_length; i++) { + command_bytes[2 * i] = 0x80; + command_bytes[2 * i + 1] = data[i]; + } + common_hal_busio_i2c_write(self->bus, self->address, command_bytes, 2 * data_length, true); + } else { + uint8_t data_bytes[data_length + 1]; + data_bytes[0] = 0x40; + memcpy(data_bytes + 1, data, data_length); + common_hal_busio_i2c_write(self->bus, self->address, data_bytes, data_length + 1, true); + } +} + +void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t obj) { + displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); + common_hal_busio_i2c_unlock(self->bus); +} diff --git a/shared-module/displayio/I2CDisplay.h b/shared-module/displayio/I2CDisplay.h new file mode 100644 index 000000000..4636c3f73 --- /dev/null +++ b/shared-module/displayio/I2CDisplay.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_I2CDISPLAY_H +#define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_I2CDISPLAY_H + +#include "common-hal/busio/I2C.h" +#include "common-hal/digitalio/DigitalInOut.h" + +typedef struct { + mp_obj_base_t base; + busio_i2c_obj_t* bus; + busio_i2c_obj_t inline_bus; + digitalio_digitalinout_obj_t reset; + uint16_t address; +} displayio_i2cdisplay_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_I2CDISPLAY_H diff --git a/shared-module/displayio/Palette.c b/shared-module/displayio/Palette.c index 8dc6e766b..444151b3c 100644 --- a/shared-module/displayio/Palette.c +++ b/shared-module/displayio/Palette.c @@ -26,49 +26,49 @@ #include "shared-bindings/displayio/Palette.h" +#include "shared-module/displayio/ColorConverter.h" + void common_hal_displayio_palette_construct(displayio_palette_t* self, uint16_t color_count) { self->color_count = color_count; - self->colors = (uint32_t *) m_malloc(color_count * sizeof(uint16_t), false); - uint32_t opaque_byte_count = color_count / 8; - if (color_count % 8 > 0) { - opaque_byte_count += 1; - } - self->opaque = (uint32_t *) m_malloc(opaque_byte_count, false); + self->colors = (_displayio_color_t *) m_malloc(color_count * sizeof(_displayio_color_t), false); } void common_hal_displayio_palette_make_opaque(displayio_palette_t* self, uint32_t palette_index) { - self->opaque[palette_index / 32] &= ~(0x1 << (palette_index % 32)); + self->colors[palette_index].transparent = false; } void common_hal_displayio_palette_make_transparent(displayio_palette_t* self, uint32_t palette_index) { - self->opaque[palette_index / 32] |= (0x1 << (palette_index % 32)); + self->colors[palette_index].transparent = true; +} + +uint32_t common_hal_displayio_palette_get_len(displayio_palette_t* self) { + return self->color_count; } void common_hal_displayio_palette_set_color(displayio_palette_t* self, uint32_t palette_index, uint32_t color) { - uint32_t shift = (palette_index % 2) * 16; - uint32_t masked = self->colors[palette_index / 2] & ~(0xffff << shift); - uint32_t r5 = (color >> 19); - uint32_t g6 = (color >> 10) & 0x3f; - uint32_t b5 = (color >> 3) & 0x1f; - uint32_t packed = r5 << 11 | g6 << 5 | b5; - // swap bytes - packed = __builtin_bswap16(packed); - uint32_t final_color = masked | packed << shift; - if (self->colors[palette_index / 2] == final_color) { + if (self->colors[palette_index].rgb888 == color) { return; } - self->colors[palette_index / 2] = final_color; + self->colors[palette_index].rgb888 = color; + self->colors[palette_index].luma = displayio_colorconverter_compute_luma(color); + self->colors[palette_index].rgb565 = displayio_colorconverter_compute_rgb565(color); self->needs_refresh = true; } -bool displayio_palette_get_color(displayio_palette_t *self, uint32_t palette_index, uint16_t* color) { - if (palette_index > self->color_count) { - return false; +uint32_t common_hal_displayio_palette_get_color(displayio_palette_t* self, uint32_t palette_index) { + return self->colors[palette_index].rgb888; +} + +bool displayio_palette_get_color(displayio_palette_t *self, const _displayio_colorspace_t* colorspace, uint32_t palette_index, uint32_t* color) { + if (palette_index > self->color_count || self->colors[palette_index].transparent) { + return false; // returns opaque } - if ((self->opaque[palette_index / 32] & (0x1 << (palette_index % 32))) != 0) { - return false; + + if (colorspace->grayscale) { + *color = self->colors[palette_index].luma >> (8 - colorspace->depth); + } else { + *color = self->colors[palette_index].rgb565; } - *color = (self->colors[palette_index / 2] >> (16 * (palette_index % 2))) & 0xffff; return true; } diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index 3813e8bdd..6f5e2774c 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -32,15 +32,28 @@ #include "py/obj.h" +typedef struct { + uint8_t depth; + bool grayscale; + bool pixels_in_byte_share_row; + uint8_t hue; +} _displayio_colorspace_t; + +typedef struct { + uint32_t rgb888; + uint16_t rgb565; + uint8_t luma; + bool transparent; // This may have additional bits added later for blending. +} _displayio_color_t; + typedef struct { mp_obj_base_t base; - uint32_t* opaque; - uint32_t* colors; + _displayio_color_t* colors; uint32_t color_count; bool needs_refresh; } displayio_palette_t; -bool displayio_palette_get_color(displayio_palette_t *palette, uint32_t palette_index, uint16_t* color); +bool displayio_palette_get_color(displayio_palette_t *palette, const _displayio_colorspace_t* colorspace, uint32_t palette_index, uint32_t* color); bool displayio_palette_needs_refresh(displayio_palette_t *self); void displayio_palette_finish_refresh(displayio_palette_t *self); diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 0cd00e0ce..77e6daf6f 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -291,7 +291,7 @@ void common_hal_displayio_tilegrid_set_top_left(displayio_tilegrid_t *self, uint self->full_change = true; } -bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { +bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_colorspace_t* colorspace, const displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { // If no tiles are present we have no impact. uint8_t* tiles = self->tiles; if (self->inline_tiles) { @@ -371,12 +371,13 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const displayio_ar y_shift = temp_shift; } + uint8_t pixels_per_byte = 8 / colorspace->depth; for (int16_t y = start_y; y < end_y; y++) { - int16_t row_start = start + (y - start_y + y_shift) * y_stride; + int16_t row_start = start + (y - start_y + y_shift) * y_stride; // in pixels int16_t local_y = y / self->absolute_transform->scale; for (int16_t x = start_x; x < end_x; x++) { // Compute the destination pixel in the buffer and mask based on the transformations. - int16_t offset = row_start + (x - start_x + x_shift) * x_stride; + int16_t offset = row_start + (x - start_x + x_shift) * x_stride; // in pixels // This is super useful for debugging out range accesses. Uncomment to use. // if (offset < 0 || offset >= (int32_t) displayio_area_size(area)) { @@ -404,23 +405,38 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const displayio_ar value = common_hal_displayio_ondiskbitmap_get_pixel(self->bitmap, tile_x, tile_y); } - uint16_t* pixel = ((uint16_t*) buffer) + offset; + uint32_t pixel; + bool opaque = true; if (self->pixel_shader == mp_const_none) { - *pixel = value; - return true; + pixel = value; } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) { - if (!displayio_palette_get_color(self->pixel_shader, value, pixel)) { - // A pixel is transparent so we haven't fully covered the area ourselves. - full_coverage = false; - } else { - mask[offset / 32] |= 1 << (offset % 32); - } + opaque = displayio_palette_get_color(self->pixel_shader, colorspace, value, &pixel); } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { - if (!common_hal_displayio_colorconverter_convert(self->pixel_shader, value, pixel)) { - // A pixel is transparent so we haven't fully covered the area ourselves. - full_coverage = false; - } else { - mask[offset / 32] |= 1 << (offset % 32); + opaque = displayio_colorconverter_convert(self->pixel_shader, colorspace, value, &pixel); + } + if (!opaque) { + // A pixel is transparent so we haven't fully covered the area ourselves. + full_coverage = false; + } else { + mask[offset / 32] |= 1 << (offset % 32); + if (colorspace->depth == 16) { + *(((uint16_t*) buffer) + offset) = pixel; + } else if (colorspace->depth == 8) { + *(((uint8_t*) buffer) + offset) = pixel; + } else if (colorspace->depth < 8) { + // Reorder the offsets to pack multiple rows into a byte (meaning they share a column). + if (!colorspace->pixels_in_byte_share_row) { + uint16_t width = displayio_area_width(area); + uint16_t row = offset / width; + uint16_t col = offset % width; + // Dividing by pixels_per_byte does truncated division even if we multiply it back out. + offset = col * pixels_per_byte + (row / pixels_per_byte) * pixels_per_byte * width + row % pixels_per_byte; + // Also useful for validating that the bitpacking worked correctly. + // if (offset > displayio_area_size(area)) { + // asm("bkpt"); + // } + } + ((uint8_t*)buffer)[offset / pixels_per_byte] |= pixel << ((offset % pixels_per_byte) * colorspace->depth); } } } diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index 4d97eccc2..fb6033e9c 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -32,6 +32,7 @@ #include "py/obj.h" #include "shared-module/displayio/area.h" +#include "shared-module/displayio/Palette.h" typedef struct { mp_obj_base_t base; @@ -71,7 +72,7 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel // Area is always in absolute screen coordinates. Update transform is used to inform TileGrids how // they relate to it. -bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const displayio_area_t* area, uint32_t* mask, uint32_t *buffer); +bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_colorspace_t* colorspace, const displayio_area_t* area, uint32_t* mask, uint32_t *buffer); void displayio_tilegrid_update_transform(displayio_tilegrid_t *group, const displayio_buffer_transform_t* parent_transform); // Fills in area with the maximum bounds of all related pixels in the last rendered frame. Returns diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index b6709e0eb..97060aaeb 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -19,9 +19,10 @@ #include "supervisor/usb.h" primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; +uint32_t frame_count = 0; bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area) { - uint16_t buffer_size = 512; + uint16_t buffer_size = 128; // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. @@ -30,15 +31,36 @@ bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area } uint16_t subrectangles = 1; uint16_t rows_per_buffer = displayio_area_height(&clipped); - if (displayio_area_size(area) > buffer_size) { - rows_per_buffer = buffer_size / displayio_area_width(&clipped); + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / display->colorspace.depth; + uint16_t pixels_per_buffer = displayio_area_size(&clipped); + if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { + rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary. + if (display->colorspace.depth < 8 && !display->colorspace.pixels_in_byte_share_row) { + uint8_t pixels_per_byte = 8 / display->colorspace.depth; + if (rows_per_buffer % pixels_per_byte != 0) { + rows_per_buffer -= rows_per_buffer % pixels_per_byte; + } + } subrectangles = displayio_area_height(&clipped) / rows_per_buffer; if (displayio_area_height(&clipped) % rows_per_buffer != 0) { subrectangles++; } - buffer_size = rows_per_buffer * displayio_area_width(&clipped); + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } } - uint32_t buffer[buffer_size / 2]; + + // Allocated and shared as a uint32_t array so the compiler knows the + // alignment everywhere. + uint32_t buffer[buffer_size]; + volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask[mask_length]; uint16_t remaining_rows = displayio_area_height(&clipped); for (uint16_t j = 0; j < subrectangles; j++) { @@ -54,37 +76,30 @@ bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area remaining_rows -= rows_per_buffer; displayio_display_begin_transaction(display); - displayio_display_set_region_to_update(display, subrectangle.x1, subrectangle.y1, - subrectangle.x2, subrectangle.y2); + displayio_display_set_region_to_update(display, &subrectangle); displayio_display_end_transaction(display); - uint32_t mask[(buffer_size / 32) + 1]; - for (uint16_t k = 0; k < (buffer_size / 32) + 1; k++) { - mask[k] = 0x00000000; + uint16_t subrectangle_size_bytes; + if (display->colorspace.depth >= 8) { + subrectangle_size_bytes = displayio_area_size(&subrectangle) * (display->colorspace.depth / 8); + } else { + subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / display->colorspace.depth); } - bool full_coverage = displayio_display_fill_area(display, &subrectangle, mask, buffer); - if (!full_coverage) { - uint32_t index = 0; - uint32_t current_mask = 0; - for (int16_t y = subrectangle.y1; y < subrectangle.y2; y++) { - for (int16_t x = subrectangle.x1; x < subrectangle.x2; x++) { - if (index % 32 == 0) { - current_mask = mask[index / 32]; - } - if ((current_mask & (1 << (index % 32))) == 0) { - ((uint16_t*) buffer)[index] = 0x0000; - } - index++; - } - } + for (uint16_t k = 0; k < mask_length; k++) { + mask[k] = 0x00000000; + } + for (uint16_t k = 0; k < buffer_size; k++) { + buffer[k] = 0x00000000; } + displayio_display_fill_area(display, &subrectangle, mask, buffer); + if (!displayio_display_begin_transaction(display)) { // Can't acquire display bus; skip the rest of the data. Try next display. return false; } - displayio_display_send_pixels(display, (uint8_t*) buffer, displayio_area_size(&subrectangle) * sizeof(uint16_t)); + displayio_display_send_pixels(display, (uint8_t*) buffer, subrectangle_size_bytes); displayio_display_end_transaction(display); // TODO(tannewt): Make refresh displays faster so we don't starve other @@ -96,7 +111,6 @@ bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area // Check for recursive calls to displayio_refresh_displays. bool refresh_displays_in_progress = false; -uint32_t frame_count = 0; void displayio_refresh_displays(void) { if (mp_hal_is_interrupted()) { @@ -153,6 +167,8 @@ void common_hal_displayio_release_displays(void) { continue; } else if (bus_type == &displayio_fourwire_type) { common_hal_displayio_fourwire_deinit(&displays[i].fourwire_bus); + } else if (bus_type == &displayio_i2cdisplay_type) { + common_hal_displayio_i2cdisplay_deinit(&displays[i].i2cdisplay_bus); } else if (bus_type == &displayio_parallelbus_type) { common_hal_displayio_parallelbus_deinit(&displays[i].parallel_bus); } @@ -169,30 +185,53 @@ void common_hal_displayio_release_displays(void) { void reset_displays(void) { // The SPI buses used by FourWires may be allocated on the heap so we need to move them inline. for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].fourwire_bus.base.type != &displayio_fourwire_type) { - continue; - } - displayio_fourwire_obj_t* fourwire = &displays[i].fourwire_bus; - if (((uint32_t) fourwire->bus) < ((uint32_t) &displays) || - ((uint32_t) fourwire->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) { - busio_spi_obj_t* original_spi = fourwire->bus; - #if BOARD_SPI - // We don't need to move original_spi if it is the board.SPI object because it is - // statically allocated already. (Doing so would also make it impossible to reference in - // a subsequent VM run.) - if (original_spi == common_hal_board_get_spi()) { - continue; + if (displays[i].fourwire_bus.base.type == &displayio_fourwire_type) { + displayio_fourwire_obj_t* fourwire = &displays[i].fourwire_bus; + if (((uint32_t) fourwire->bus) < ((uint32_t) &displays) || + ((uint32_t) fourwire->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) { + busio_spi_obj_t* original_spi = fourwire->bus; + #if BOARD_SPI + // We don't need to move original_spi if it is the board.SPI object because it is + // statically allocated already. (Doing so would also make it impossible to reference in + // a subsequent VM run.) + if (original_spi == common_hal_board_get_spi()) { + continue; + } + #endif + memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t)); + fourwire->bus = &fourwire->inline_bus; + // Check for other displays that use the same spi bus and swap them too. + for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) { + if (displays[i].fourwire_bus.base.type == &displayio_fourwire_type && + displays[i].fourwire_bus.bus == original_spi) { + displays[i].fourwire_bus.bus = &fourwire->inline_bus; + } } - #endif - memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t)); - fourwire->bus = &fourwire->inline_bus; - // Check for other displays that use the same spi bus and swap them too. - for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) { - if (displays[i].fourwire_bus.bus == original_spi) { - displays[i].fourwire_bus.bus = &fourwire->inline_bus; + } + } else if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type) { + displayio_i2cdisplay_obj_t* i2c = &displays[i].i2cdisplay_bus; + if (((uint32_t) i2c->bus) < ((uint32_t) &displays) || + ((uint32_t) i2c->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) { + busio_i2c_obj_t* original_i2c = i2c->bus; + #if BOARD_I2C + // We don't need to move original_i2c if it is the board.SPI object because it is + // statically allocated already. (Doing so would also make it impossible to reference in + // a subsequent VM run.) + if (original_i2c == common_hal_board_get_i2c()) { + continue; + } + #endif + memcpy(&i2c->inline_bus, original_i2c, sizeof(busio_i2c_obj_t)); + i2c->bus = &i2c->inline_bus; + // Check for other displays that use the same i2c bus and swap them too. + for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) { + if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type && + displays[i].i2cdisplay_bus.bus == original_i2c) { + displays[i].i2cdisplay_bus.bus = &i2c->inline_bus; + } + } } } - } } for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index 18c1a4f4a..caa5ce36d 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -30,11 +30,13 @@ #include "shared-bindings/displayio/Display.h" #include "shared-bindings/displayio/FourWire.h" #include "shared-bindings/displayio/Group.h" +#include "shared-bindings/displayio/I2CDisplay.h" #include "shared-bindings/displayio/ParallelBus.h" typedef struct { union { displayio_fourwire_obj_t fourwire_bus; + displayio_i2cdisplay_obj_t i2cdisplay_bus; displayio_parallelbus_obj_t parallel_bus; }; displayio_display_obj_t display; diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 7adf9d032..86c3e903e 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -35,6 +35,8 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, d self->font = font; self->tilegrid = tilegrid; self->first_row = 0; + + common_hal_displayio_tilegrid_set_top_left(self->tilegrid, 0, 1); } size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, const byte *data, size_t len, int *errcode) { diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 414f85034..6a39cbe8e 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -82,8 +82,7 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) { grid->pixel_height = height_in_tiles * grid->tile_height; grid->tiles = tiles; - supervisor_terminal.cursor_x = 0; - supervisor_terminal.cursor_y = 0; + common_hal_terminalio_terminal_construct(&supervisor_terminal, grid, &supervisor_terminal_font); } void supervisor_stop_terminal(void) { @@ -147,17 +146,49 @@ displayio_bitmap_t blinka_bitmap = { .read_only = true }; -uint32_t blinka_transparency[1] = {0x80000000}; - -// These colors are RGB 565 with the bytes swapped. -uint32_t blinka_colors[8] = {0x78890000, 0x9F86B8FC, 0xffff0D5A, 0x0000f501, - 0x00000000, 0x00000000, 0x00000000, 0x00000000}; +_displayio_color_t blinka_colors[7] = { + { + .rgb888 = 0x000000, + .rgb565 = 0x0000, + .luma = 0x00, + .transparent = true + }, + { + .rgb888 = 0x8428bc, + .rgb565 = 0x7889, + .luma = 0xff // We cheat the luma here. It is actually 0x60 + }, + { + .rgb888 = 0xff89bc, + .rgb565 = 0xB8FC, + .luma = 0xb5 + }, + { + .rgb888 = 0x7beffe, + .rgb565 = 0x9F86, + .luma = 0xe0 + }, + { + .rgb888 = 0x51395f, + .rgb565 = 0x0D5A, + .luma = 0x47 + }, + { + .rgb888 = 0xffffff, + .rgb565 = 0xffff, + .luma = 0xff + }, + { + .rgb888 = 0x0736a0, + .rgb565 = 0xf501, + .luma = 0x44 + }, +}; displayio_palette_t blinka_palette = { .base = {.type = &displayio_palette_type }, - .opaque = blinka_transparency, .colors = blinka_colors, - .color_count = 16, + .color_count = 7, .needs_refresh = false }; diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 2c674c8eb..a731cbd9c 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -98,14 +98,21 @@ c_file.write("""\ """) c_file.write("""\ -uint32_t terminal_transparency[1] = {0x00000000}; - -// These colors are RGB 565 with the bytes swapped. -uint32_t terminal_colors[1] = {0xffff0000}; +_displayio_color_t terminal_colors[2] = { + { + .rgb888 = 0x000000, + .rgb565 = 0x0000, + .luma = 0x00 + }, + { + .rgb888 = 0xffffff, + .rgb565 = 0xffff, + .luma = 0xff + }, +}; displayio_palette_t supervisor_terminal_color = { .base = {.type = &displayio_palette_type }, - .opaque = terminal_transparency, .colors = terminal_colors, .color_count = 2, .needs_refresh = false -- cgit v1.2.3 From 1d1b8703b6c108b72a1abda9312646895f542672 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 19 Jul 2019 16:05:13 -0700 Subject: Review feedback including NO_BRIGHTNESS_COMMAND macro --- locale/ID.po | 13 +++++++-- locale/circuitpython.pot | 13 +++++++-- locale/de_DE.po | 13 +++++++-- locale/en_US.po | 13 +++++++-- locale/en_x_pirate.po | 13 +++++++-- locale/es.po | 13 +++++++-- locale/fil.po | 13 +++++++-- locale/fr.po | 13 +++++++-- locale/it_IT.po | 13 +++++++-- locale/pl.po | 13 +++++++-- locale/pt_BR.po | 13 +++++++-- locale/zh_Latn_pinyin.po | 13 +++++++-- .../atmel-samd/boards/hallowing_m0_express/board.c | 2 +- ports/atmel-samd/boards/pybadge/board.c | 2 +- ports/atmel-samd/boards/pybadge_airlift/board.c | 2 +- ports/atmel-samd/boards/pygamer/board.c | 2 +- ports/atmel-samd/boards/pygamer_advance/board.c | 2 +- ports/atmel-samd/boards/pyportal/board.c | 2 +- ports/atmel-samd/boards/ugame10/board.c | 2 +- shared-bindings/displayio/ColorConverter.c | 2 ++ shared-bindings/displayio/ColorConverter.h | 2 +- shared-bindings/displayio/Display.c | 10 +++++-- shared-bindings/displayio/Display.h | 2 ++ shared-bindings/displayio/I2CDisplay.c | 2 +- shared-bindings/displayio/Palette.c | 2 +- shared-module/displayio/ColorConverter.c | 4 +-- shared-module/displayio/Display.c | 32 ++++++++++------------ shared-module/displayio/Palette.h | 2 ++ shared-module/displayio/TileGrid.c | 2 +- 29 files changed, 161 insertions(+), 69 deletions(-) (limited to 'shared-module') diff --git a/locale/ID.po b/locale/ID.po index 5e555a025..b211d5379 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -312,6 +312,10 @@ msgstr "" msgid "Both pins must support hardware interrupts" msgstr "Kedua pin harus mendukung hardware interrut" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "" @@ -443,8 +447,11 @@ msgstr "Clock unit sedang digunakan" msgid "Column entry must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c msgid "Command must be an int between 0 and 255" msgstr "" diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 67271258a..d91e2b3ac 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -308,6 +308,10 @@ msgstr "" msgid "Both pins must support hardware interrupts" msgstr "" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "" @@ -433,8 +437,11 @@ msgstr "" msgid "Column entry must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c msgid "Command must be an int between 0 and 255" msgstr "" diff --git a/locale/de_DE.po b/locale/de_DE.po index b0ebf9bcb..748833147 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2018-07-27 11:55-0700\n" "Last-Translator: Pascal Deneaux\n" "Language-Team: Sebastian Plamauer, Pascal Deneaux\n" @@ -312,6 +312,10 @@ msgstr "Bit depth muss ein Vielfaches von 8 sein." msgid "Both pins must support hardware interrupts" msgstr "Beide pins müssen Hardware Interrupts unterstützen" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "Die Helligkeit muss zwischen 0 und 255 liegen" @@ -437,8 +441,11 @@ msgstr "Clock unit wird benutzt" msgid "Column entry must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c msgid "Command must be an int between 0 and 255" msgstr "Der Befehl muss ein int zwischen 0 und 255 sein" diff --git a/locale/en_US.po b/locale/en_US.po index 91fd15ac8..38074de98 100644 --- a/locale/en_US.po +++ b/locale/en_US.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2018-07-27 11:55-0700\n" "Last-Translator: \n" "Language-Team: \n" @@ -308,6 +308,10 @@ msgstr "" msgid "Both pins must support hardware interrupts" msgstr "" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "" @@ -433,8 +437,11 @@ msgstr "" msgid "Column entry must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c msgid "Command must be an int between 0 and 255" msgstr "" diff --git a/locale/en_x_pirate.po b/locale/en_x_pirate.po index 5f0ab319f..9bee12d2a 100644 --- a/locale/en_x_pirate.po +++ b/locale/en_x_pirate.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2018-07-27 11:55-0700\n" "Last-Translator: \n" "Language-Team: @sommersoft, @MrCertainly\n" @@ -312,6 +312,10 @@ msgstr "" msgid "Both pins must support hardware interrupts" msgstr "" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "" @@ -437,8 +441,11 @@ msgstr "" msgid "Column entry must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c msgid "Command must be an int between 0 and 255" msgstr "" diff --git a/locale/es.po b/locale/es.po index ff44238df..33cdfe348 100644 --- a/locale/es.po +++ b/locale/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2018-08-24 22:56-0500\n" "Last-Translator: \n" "Language-Team: \n" @@ -316,6 +316,10 @@ msgstr "Bits depth debe ser múltiplo de 8." msgid "Both pins must support hardware interrupts" msgstr "Ambos pines deben soportar interrupciones por hardware" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "El brillo debe estar entro 0 y 255" @@ -441,8 +445,11 @@ msgstr "Clock unit está siendo utilizado" msgid "Column entry must be digitalio.DigitalInOut" msgstr "Entrada de columna debe ser digitalio.DigitalInOut" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c msgid "Command must be an int between 0 and 255" msgstr "Command debe estar entre 0 y 255." diff --git a/locale/fil.po b/locale/fil.po index 4693cde64..4f05812f7 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2018-12-20 22:15-0800\n" "Last-Translator: Timothy \n" "Language-Team: fil\n" @@ -314,6 +314,10 @@ msgstr "Bit depth ay dapat multiple ng 8." msgid "Both pins must support hardware interrupts" msgstr "Ang parehong mga pin ay dapat na sumusuporta sa hardware interrupts" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "Ang liwanag ay dapat sa gitna ng 0 o 255" @@ -441,8 +445,11 @@ msgstr "Clock unit ginagamit" msgid "Column entry must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c #, fuzzy msgid "Command must be an int between 0 and 255" msgstr "Sa gitna ng 0 o 255 dapat ang bytes." diff --git a/locale/fr.po b/locale/fr.po index db2b659dd..a948630ee 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2019-04-14 20:05+0100\n" "Last-Translator: Pierrick Couturier \n" "Language-Team: fr\n" @@ -319,6 +319,10 @@ msgstr "La profondeur de bit doit être un multiple de 8." msgid "Both pins must support hardware interrupts" msgstr "Les deux entrées doivent supporter les interruptions matérielles" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "La luminosité doit être entre 0 et 255" @@ -447,8 +451,11 @@ msgstr "Horloge en cours d'utilisation" msgid "Column entry must be digitalio.DigitalInOut" msgstr "L'entrée 'Column' doit être un digitalio.DigitalInOut" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c #, fuzzy msgid "Command must be an int between 0 and 255" msgstr "La commande doit être un entier entre 0 et 255" diff --git a/locale/it_IT.po b/locale/it_IT.po index 0e717f15b..40a685f75 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2018-10-02 16:27+0200\n" "Last-Translator: Enrico Paganin \n" "Language-Team: \n" @@ -314,6 +314,10 @@ msgstr "La profondità di bit deve essere multipla di 8." msgid "Both pins must support hardware interrupts" msgstr "Entrambi i pin devono supportare gli interrupt hardware" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "La luminosità deve essere compreso tra 0 e 255" @@ -442,8 +446,11 @@ msgstr "Unità di clock in uso" msgid "Column entry must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c #, fuzzy msgid "Command must be an int between 0 and 255" msgstr "I byte devono essere compresi tra 0 e 255" diff --git a/locale/pl.po b/locale/pl.po index 2bc1a7557..896785126 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2019-03-19 18:37-0700\n" "Last-Translator: Radomir Dopieralski \n" "Language-Team: pl\n" @@ -311,6 +311,10 @@ msgstr "Głębia musi być wielokrotnością 8." msgid "Both pins must support hardware interrupts" msgstr "Obie nóżki muszą wspierać przerwania sprzętowe" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "Jasność musi być pomiędzy 0 a 255" @@ -436,8 +440,11 @@ msgstr "Jednostka zegara w użyciu" msgid "Column entry must be digitalio.DigitalInOut" msgstr "Kolumny muszą być typu digitalio.DigitalInOut" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c msgid "Command must be an int between 0 and 255" msgstr "Komenda musi być int pomiędzy 0 a 255" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 7af2e3d60..7e052bfb7 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2018-10-02 21:14-0000\n" "Last-Translator: \n" "Language-Team: \n" @@ -311,6 +311,10 @@ msgstr "" msgid "Both pins must support hardware interrupts" msgstr "Ambos os pinos devem suportar interrupções de hardware" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "O brilho deve estar entre 0 e 255" @@ -438,8 +442,11 @@ msgstr "Unidade de Clock em uso" msgid "Column entry must be digitalio.DigitalInOut" msgstr "" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c #, fuzzy msgid "Command must be an int between 0 and 255" msgstr "Os bytes devem estar entre 0 e 255." diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 7f6e80236..258a4d3df 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: circuitpython-cn\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-19 16:09-0700\n" +"POT-Creation-Date: 2019-07-19 16:10-0700\n" "PO-Revision-Date: 2019-04-13 10:10-0700\n" "Last-Translator: hexthat\n" "Language-Team: Chinese Hanyu Pinyin\n" @@ -312,6 +312,10 @@ msgstr "Bǐtè shēndù bìxū shì 8 bèi yǐshàng." msgid "Both pins must support hardware interrupts" msgstr "Liǎng gè yǐn jiǎo dōu bìxū zhīchí yìngjiàn zhōngduàn" +#: shared-bindings/displayio/Display.c +msgid "Brightness must be 0-1.0" +msgstr "" + #: shared-bindings/supervisor/__init__.c msgid "Brightness must be between 0 and 255" msgstr "Liàngdù bìxū jiè yú 0 dào 255 zhī jiān" @@ -437,8 +441,11 @@ msgstr "Shǐyòng shízhōng dānwèi" msgid "Column entry must be digitalio.DigitalInOut" msgstr "Liè tiáomù bìxū shì digitalio.DigitalInOut" -#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/I2CDisplay.c -#: shared-bindings/displayio/ParallelBus.c +#: shared-bindings/displayio/I2CDisplay.c +msgid "Command must be 0-255" +msgstr "" + +#: shared-bindings/displayio/FourWire.c shared-bindings/displayio/ParallelBus.c msgid "Command must be an int between 0 and 255" msgstr "Mìnglìng bìxū shì 0 dào 255 zhī jiān de int" diff --git a/ports/atmel-samd/boards/hallowing_m0_express/board.c b/ports/atmel-samd/boards/hallowing_m0_express/board.c index 1bbbfbaf8..be1741c87 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m0_express/board.c @@ -100,7 +100,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA00, - 0x100, // Brightness command. Only available when <= 0xff + NO_BRIGHTNESS_COMMAND, 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pybadge/board.c b/ports/atmel-samd/boards/pybadge/board.c index 7e6c11dd4..c9dca0329 100644 --- a/ports/atmel-samd/boards/pybadge/board.c +++ b/ports/atmel-samd/boards/pybadge/board.c @@ -102,7 +102,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA01, // backlight pin - 0x100, // no brightness command + NO_BRIGHTNESS_COMMAND, 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pybadge_airlift/board.c b/ports/atmel-samd/boards/pybadge_airlift/board.c index d7f291d7d..eeab3f2b2 100644 --- a/ports/atmel-samd/boards/pybadge_airlift/board.c +++ b/ports/atmel-samd/boards/pybadge_airlift/board.c @@ -80,7 +80,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA01, // backlight pin - 0x100, // brightness command, only valid <= 0xff + NO_BRIGHTNESS_COMMAND, 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pygamer/board.c b/ports/atmel-samd/boards/pygamer/board.c index e59b7c458..d413c8e34 100644 --- a/ports/atmel-samd/boards/pygamer/board.c +++ b/ports/atmel-samd/boards/pygamer/board.c @@ -102,7 +102,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA01, // backlight pin - 0x100, // Brightness command. Only available when < 0xff + NO_BRIGHTNESS_COMMAND, 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pygamer_advance/board.c b/ports/atmel-samd/boards/pygamer_advance/board.c index b23353998..498a29db2 100644 --- a/ports/atmel-samd/boards/pygamer_advance/board.c +++ b/ports/atmel-samd/boards/pygamer_advance/board.c @@ -80,7 +80,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PA01, // backlight pin - 0x100, // Brightness command. Only available when < 0xff + NO_BRIGHTNESS_COMMAND, 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/pyportal/board.c b/ports/atmel-samd/boards/pyportal/board.c index 7fffb764f..938072158 100644 --- a/ports/atmel-samd/boards/pyportal/board.c +++ b/ports/atmel-samd/boards/pyportal/board.c @@ -92,7 +92,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), &pin_PB31, // Backlight pin - 0x100, // Brightness command > 0xff is none s + NO_BRIGHTNESS_COMMAND, 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds diff --git a/ports/atmel-samd/boards/ugame10/board.c b/ports/atmel-samd/boards/ugame10/board.c index 27a03ad91..15e22a72c 100644 --- a/ports/atmel-samd/boards/ugame10/board.c +++ b/ports/atmel-samd/boards/ugame10/board.c @@ -100,7 +100,7 @@ void board_init(void) { display_init_sequence, sizeof(display_init_sequence), NULL, - 0x100, // brightness command. Only valid <=0xff + NO_BRIGHTNESS_COMMAND, 1.0f, // brightness false, // auto_brightness false, // single_byte_bounds diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index e170e0340..d9524870d 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -62,6 +62,8 @@ STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, siz //| .. method:: convert(color) //| +//| Converts the given RGB888 color to RGB565 +//| STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t color_obj) { displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index 8f61e6642..24895500e 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -34,6 +34,6 @@ extern const mp_obj_type_t displayio_colorconverter_type; void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self); -bool common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); +void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 2586e562f..361a37ece 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -119,7 +119,7 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} }, { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, - { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x100} }, + { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} }, { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, @@ -242,10 +242,14 @@ STATIC mp_obj_t displayio_display_obj_get_brightness(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_brightness_obj, displayio_display_obj_get_brightness); -STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness) { +STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) { displayio_display_obj_t *self = native_display(self_in); common_hal_displayio_display_set_auto_brightness(self, false); - bool ok = common_hal_displayio_display_set_brightness(self, mp_obj_get_float(brightness)); + mp_float_t brightness = mp_obj_get_float(brightness_obj); + if (brightness < 0 || brightness > 1.0) { + mp_raise_ValueError(translate("Brightness must be 0-1.0")); + } + bool ok = common_hal_displayio_display_set_brightness(self, brightness); if (!ok) { mp_raise_RuntimeError(translate("Brightness not adjustable")); } diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index a60a0cf5a..e765e6f25 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -36,6 +36,8 @@ extern const mp_obj_type_t displayio_display_type; #define DELAY 0x80 +#define NO_BRIGHTNESS_COMMAND 0x100 + void common_hal_displayio_display_construct(displayio_display_obj_t* self, mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index 2aac49b4d..1f74e8c9e 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -103,7 +103,7 @@ STATIC mp_obj_t displayio_i2cdisplay_make_new(const mp_obj_type_t *type, size_t STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) { mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj); if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) { - mp_raise_ValueError(translate("Command must be an int between 0 and 255")); + mp_raise_ValueError(translate("Command must be 0-255")); } uint8_t command = command_int; mp_buffer_info_t bufinfo; diff --git a/shared-bindings/displayio/Palette.c b/shared-bindings/displayio/Palette.c index 974cadb02..dda58e3c5 100644 --- a/shared-bindings/displayio/Palette.c +++ b/shared-bindings/displayio/Palette.c @@ -74,7 +74,7 @@ STATIC mp_obj_t displayio_palette_make_new(const mp_obj_type_t *type, size_t n_a STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) { displayio_palette_t *self = MP_OBJ_TO_PTR(self_in); switch (op) { - case MP_UNARY_OP_BOOL: return mp_obj_new_bool(true); + case MP_UNARY_OP_BOOL: return mp_const_true; case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_len(self)); default: return MP_OBJ_NULL; // op not supported diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 563d40c51..6b9bd5840 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -57,8 +57,8 @@ bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d return false; } -bool common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { - return displayio_colorconverter_convert(self, colorspace, input_color, output_color); +void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { + displayio_colorconverter_convert(self, colorspace, input_color, output_color); } // Currently no refresh logic is needed for a ColorConverter. diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 9aee70e32..a8515b9e5 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -153,7 +153,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, common_hal_pulseio_pwmout_never_reset(&self->backlight_pwm); } } - if (!self->auto_brightness && (self->backlight_inout.base.type != &mp_type_NoneType || brightness_command <= 0xff)) { + if (!self->auto_brightness && (self->backlight_inout.base.type != &mp_type_NoneType || + brightness_command != NO_BRIGHTNESS_COMMAND)) { common_hal_displayio_display_set_brightness(self, brightness); } else { self->current_brightness = -1.0; @@ -258,7 +259,7 @@ bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); ok = true; - } else if (self->brightness_command < 0x100) { + } else if (self->brightness_command != NO_BRIGHTNESS_COMMAND) { ok = self->begin_transaction(self->bus); if (ok) { if (self->data_as_commands) { @@ -315,17 +316,16 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ data_length = 0; } if (self->single_byte_bounds) { - data[data_length] = x1 + self->colstart; - data[data_length + 1] = x2 - 1 + self->colstart; + data[data_length++] = x1 + self->colstart; + data[data_length++] = x2 - 1 + self->colstart; data_length += 2; } else { x1 += self->colstart; x2 += self->colstart - 1; - data[data_length] = x1 >> 8; - data[data_length + 1] = x1 & 0xff; - data[data_length + 2] = x2 >> 8; - data[data_length + 3] = x2 & 0xff; - data_length += 4; + data[data_length++] = x1 >> 8; + data[data_length++] = x1 & 0xff; + data[data_length++] = x2 >> 8; + data[data_length++] = x2 & 0xff; } self->send(self->bus, self->data_as_commands, data, data_length); @@ -337,17 +337,15 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ data_length = 0; } if (self->single_byte_bounds) { - data[data_length] = y1 + self->rowstart; - data[data_length + 1] = y2 - 1 + self->rowstart; - data_length += 2; + data[data_length++] = y1 + self->rowstart; + data[data_length++] = y2 - 1 + self->rowstart; } else { y1 += self->rowstart; y2 += self->rowstart - 1; - data[data_length] = y1 >> 8; - data[data_length + 1] = y1 & 0xff; - data[data_length + 2] = y2 >> 8; - data[data_length + 3] = y2 & 0xff; - data_length += 4; + data[data_length++] = y1 >> 8; + data[data_length++] = y1 & 0xff; + data[data_length++] = y2 >> 8; + data[data_length++] = y2 & 0xff; } self->send(self->bus, self->data_as_commands, data, data_length); } diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index 6f5e2774c..19c05baf5 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -53,6 +53,8 @@ typedef struct { bool needs_refresh; } displayio_palette_t; +// Returns false if color fetch did not succeed (out of range or transparent). +// Returns true if color is opaque, and sets color. bool displayio_palette_get_color(displayio_palette_t *palette, const _displayio_colorspace_t* colorspace, uint32_t palette_index, uint32_t* color); bool displayio_palette_needs_refresh(displayio_palette_t *self); void displayio_palette_finish_refresh(displayio_palette_t *self); diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 77e6daf6f..88873d3a9 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -379,7 +379,7 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c // Compute the destination pixel in the buffer and mask based on the transformations. int16_t offset = row_start + (x - start_x + x_shift) * x_stride; // in pixels - // This is super useful for debugging out range accesses. Uncomment to use. + // This is super useful for debugging out of range accesses. Uncomment to use. // if (offset < 0 || offset >= (int32_t) displayio_area_size(area)) { // asm("bkpt"); // } -- cgit v1.2.3 From 58630a844ad1db7d30671a3cb18f433e015a40a3 Mon Sep 17 00:00:00 2001 From: Hierophect Date: Mon, 22 Jul 2019 12:58:28 -0400 Subject: Add feature conditionals and clean up --- main.c | 13 +- ports/nrf/common-hal/microcontroller/Pin.c | 2 +- ports/stm32f4/boards/DIS_F411RE/board.c | 38 + ports/stm32f4/boards/DIS_F411RE/mpconfigboard.h | 38 + ports/stm32f4/boards/DIS_F411RE/mpconfigboard.mk | 13 + ports/stm32f4/boards/DIS_F411RE/pins.c | 90 +++ .../stm32f4/boards/DIS_F411RE/stm32f4xx_hal_conf.h | 439 +++++++++++ .../stm32f4/boards/DIS_F411RE/stm32f4xx_hal_msp.c | 427 +++++++++++ ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.c | 217 ++++++ ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.h | 70 ++ ports/stm32f4/boards/DIS_F412ZG/board.c | 38 + ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.h | 38 + ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.mk | 18 + ports/stm32f4/boards/DIS_F412ZG/pins.c | 90 +++ .../stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_conf.h | 439 +++++++++++ .../stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_msp.c | 832 +++++++++++++++++++++ ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.c | 217 ++++++ ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.h | 70 ++ ports/stm32f4/boards/stm32f411_disco/board.c | 38 - .../stm32f4/boards/stm32f411_disco/mpconfigboard.h | 38 - .../boards/stm32f411_disco/mpconfigboard.mk | 13 - ports/stm32f4/boards/stm32f411_disco/pins.c | 90 --- .../boards/stm32f411_disco/stm32f4xx_hal_conf.h | 439 ----------- .../boards/stm32f411_disco/stm32f4xx_hal_msp.c | 427 ----------- .../stm32f4/boards/stm32f411_disco/stm32f4xx_it.c | 217 ------ .../stm32f4/boards/stm32f411_disco/stm32f4xx_it.h | 70 -- ports/stm32f4/boards/stm32f412g_disco/board.c | 38 - .../boards/stm32f412g_disco/mpconfigboard.h | 38 - .../boards/stm32f412g_disco/mpconfigboard.mk | 18 - ports/stm32f4/boards/stm32f412g_disco/pins.c | 90 --- .../boards/stm32f412g_disco/stm32f4xx_hal_conf.h | 439 ----------- .../boards/stm32f412g_disco/stm32f4xx_hal_msp.c | 832 --------------------- .../stm32f4/boards/stm32f412g_disco/stm32f4xx_it.c | 217 ------ .../stm32f4/boards/stm32f412g_disco/stm32f4xx_it.h | 70 -- ports/stm32f4/common-hal/busio/I2C.h | 2 - ports/stm32f4/common-hal/busio/SPI.h | 1 - ports/stm32f4/common-hal/busio/UART.h | 1 - ports/stm32f4/common-hal/digitalio/DigitalInOut.h | 2 +- ports/stm32f4/supervisor/internal_flash.c | 7 - shared-bindings/board/__init__.c | 104 +-- shared-module/board/__init__.c | 16 +- shared-module/usb_hid/Device.c | 1 - supervisor/shared/memory.c | 2 +- supervisor/shared/micropython.c | 6 +- supervisor/shared/safe_mode.c | 20 +- supervisor/shared/status_leds.c | 2 + supervisor/shared/usb/usb.c | 6 +- supervisor/supervisor.mk | 13 +- 48 files changed, 3169 insertions(+), 3177 deletions(-) create mode 100644 ports/stm32f4/boards/DIS_F411RE/board.c create mode 100644 ports/stm32f4/boards/DIS_F411RE/mpconfigboard.h create mode 100644 ports/stm32f4/boards/DIS_F411RE/mpconfigboard.mk create mode 100644 ports/stm32f4/boards/DIS_F411RE/pins.c create mode 100644 ports/stm32f4/boards/DIS_F411RE/stm32f4xx_hal_conf.h create mode 100644 ports/stm32f4/boards/DIS_F411RE/stm32f4xx_hal_msp.c create mode 100644 ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.c create mode 100644 ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.h create mode 100644 ports/stm32f4/boards/DIS_F412ZG/board.c create mode 100644 ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.h create mode 100644 ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.mk create mode 100644 ports/stm32f4/boards/DIS_F412ZG/pins.c create mode 100644 ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_conf.h create mode 100644 ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_msp.c create mode 100644 ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.c create mode 100644 ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.h delete mode 100644 ports/stm32f4/boards/stm32f411_disco/board.c delete mode 100644 ports/stm32f4/boards/stm32f411_disco/mpconfigboard.h delete mode 100644 ports/stm32f4/boards/stm32f411_disco/mpconfigboard.mk delete mode 100644 ports/stm32f4/boards/stm32f411_disco/pins.c delete mode 100644 ports/stm32f4/boards/stm32f411_disco/stm32f4xx_hal_conf.h delete mode 100644 ports/stm32f4/boards/stm32f411_disco/stm32f4xx_hal_msp.c delete mode 100644 ports/stm32f4/boards/stm32f411_disco/stm32f4xx_it.c delete mode 100644 ports/stm32f4/boards/stm32f411_disco/stm32f4xx_it.h delete mode 100644 ports/stm32f4/boards/stm32f412g_disco/board.c delete mode 100644 ports/stm32f4/boards/stm32f412g_disco/mpconfigboard.h delete mode 100644 ports/stm32f4/boards/stm32f412g_disco/mpconfigboard.mk delete mode 100644 ports/stm32f4/boards/stm32f412g_disco/pins.c delete mode 100644 ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_hal_conf.h delete mode 100644 ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_hal_msp.c delete mode 100644 ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_it.c delete mode 100644 ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_it.h (limited to 'shared-module') diff --git a/main.c b/main.c index 10c94ad52..1fea43ce3 100755 --- a/main.c +++ b/main.c @@ -45,7 +45,6 @@ #include "background.h" #include "mpconfigboard.h" -//#include "shared-module/displayio/__init__.h" #include "supervisor/cpu.h" #include "supervisor/memory.h" #include "supervisor/port.h" @@ -58,6 +57,10 @@ #include "supervisor/shared/stack.h" #include "supervisor/serial.h" +#if CIRCUITPY_DISPLAYIO +#include "shared-module/displayio/__init__.h" +#endif + #if CIRCUITPY_NETWORK #include "shared-module/network/__init__.h" #endif @@ -187,7 +190,7 @@ void cleanup_after_vm(supervisor_allocation* heap) { supervisor_move_memory(); reset_port(); - //reset_board_busses(); + reset_board_busses(); reset_board(); reset_status_led(); } @@ -392,8 +395,10 @@ int __attribute__((used)) main(void) { safe_mode_t safe_mode = port_init(); // Turn on LEDs - //init_status_leds(); - //rgb_led_status_init(); + #if MICROPY_HW_LED_RX && MICROPY_HW_LED_RX + init_status_leds(); + rgb_led_status_init(); + #endif // Wait briefly to give a reset window where we'll enter safe mode after the reset. if (safe_mode == NO_SAFE_MODE) { diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index 49b3c15ca..3cee784b6 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -105,7 +105,7 @@ void reset_pin_number(uint8_t pin_number) { #ifdef SPEAKER_ENABLE_PIN if (pin_number == SPEAKER_ENABLE_PIN->number) { speaker_enable_in_use = false; - common_hal_digitalio_digitalinout_switch_to_output(); + common_hal_digitalio_digitalinout_switch_to_output(SPEAKER_ENABLE_PIN, true, DRIVE_MODE_PUSH_PULL); nrf_gpio_pin_dir_set(pin_number, NRF_GPIO_PIN_DIR_OUTPUT); nrf_gpio_pin_write(pin_number, false); } diff --git a/ports/stm32f4/boards/DIS_F411RE/board.c b/ports/stm32f4/boards/DIS_F411RE/board.c new file mode 100644 index 000000000..4421970ee --- /dev/null +++ b/ports/stm32f4/boards/DIS_F411RE/board.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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 "boards/board.h" + +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/stm32f4/boards/DIS_F411RE/mpconfigboard.h b/ports/stm32f4/boards/DIS_F411RE/mpconfigboard.h new file mode 100644 index 000000000..675443282 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F411RE/mpconfigboard.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +//Micropython setup + +#define MICROPY_HW_BOARD_NAME "STM32F411E_DISCO" +#define MICROPY_HW_MCU_NAME "STM32F411xE" + +#define FLASH_SIZE (0x7D000) +#define FLASH_PAGE_SIZE (0x4000) + +#define CIRCUITPY_INTERNAL_NVM_SIZE (4096) +#define AUTORESET_DELAY_MS 500 +#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) \ No newline at end of file diff --git a/ports/stm32f4/boards/DIS_F411RE/mpconfigboard.mk b/ports/stm32f4/boards/DIS_F411RE/mpconfigboard.mk new file mode 100644 index 000000000..523628504 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F411RE/mpconfigboard.mk @@ -0,0 +1,13 @@ +USB_VID = 0x239A +USB_PID = 0x802A +USB_PRODUCT = "A glorious potato" +USB_MANUFACTURER = "Adafruit Industries LLC" + +MCU_SERIES = m4 +MCU_VARIANT = stm32f4 +MCU_SUB_VARIANT = stm32f411xe +CMSIS_MCU = STM32F411xE +LD_FILE = boards/STM32F411VETx_FLASH.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 + diff --git a/ports/stm32f4/boards/DIS_F411RE/pins.c b/ports/stm32f4/boards/DIS_F411RE/pins.c new file mode 100644 index 000000000..e3a4b5ed6 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F411RE/pins.c @@ -0,0 +1,90 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_PE02), MP_ROM_PTR(&pin_PE02) }, + { MP_ROM_QSTR(MP_QSTR_PE03), MP_ROM_PTR(&pin_PE03) }, + { MP_ROM_QSTR(MP_QSTR_PE04), MP_ROM_PTR(&pin_PE04) }, + { MP_ROM_QSTR(MP_QSTR_PE05), MP_ROM_PTR(&pin_PE05) }, + { MP_ROM_QSTR(MP_QSTR_PE06), MP_ROM_PTR(&pin_PE06) }, + { MP_ROM_QSTR(MP_QSTR_PC13), MP_ROM_PTR(&pin_PC13) }, + { MP_ROM_QSTR(MP_QSTR_PF02), MP_ROM_PTR(&pin_PF02) }, + { MP_ROM_QSTR(MP_QSTR_PF03), MP_ROM_PTR(&pin_PF03) }, + { MP_ROM_QSTR(MP_QSTR_PF10), MP_ROM_PTR(&pin_PF10) }, + { MP_ROM_QSTR(MP_QSTR_PC00), MP_ROM_PTR(&pin_PC00) }, + { MP_ROM_QSTR(MP_QSTR_PC01), MP_ROM_PTR(&pin_PC01) }, + { MP_ROM_QSTR(MP_QSTR_PC02), MP_ROM_PTR(&pin_PC02) }, + { MP_ROM_QSTR(MP_QSTR_PC03), MP_ROM_PTR(&pin_PC03) }, + { MP_ROM_QSTR(MP_QSTR_PA01), MP_ROM_PTR(&pin_PA01) }, + { MP_ROM_QSTR(MP_QSTR_PA02), MP_ROM_PTR(&pin_PA02) }, + { MP_ROM_QSTR(MP_QSTR_PA03), MP_ROM_PTR(&pin_PA03) }, + { MP_ROM_QSTR(MP_QSTR_PA04), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_PA05), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_PA06), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_PA07), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_PC04), MP_ROM_PTR(&pin_PC04) }, + { MP_ROM_QSTR(MP_QSTR_PC05), MP_ROM_PTR(&pin_PC05) }, + { MP_ROM_QSTR(MP_QSTR_PB00), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_PB01), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_PF11), MP_ROM_PTR(&pin_PF11) }, + { MP_ROM_QSTR(MP_QSTR_PF13), MP_ROM_PTR(&pin_PF13) }, + { MP_ROM_QSTR(MP_QSTR_PB10), MP_ROM_PTR(&pin_PB10) }, + { MP_ROM_QSTR(MP_QSTR_PB11), MP_ROM_PTR(&pin_PB11) }, + { MP_ROM_QSTR(MP_QSTR_PB12), MP_ROM_PTR(&pin_PB12) }, + { MP_ROM_QSTR(MP_QSTR_PB13), MP_ROM_PTR(&pin_PB13) }, + { MP_ROM_QSTR(MP_QSTR_PB14), MP_ROM_PTR(&pin_PB14) }, + { MP_ROM_QSTR(MP_QSTR_PB15), MP_ROM_PTR(&pin_PB15) }, + { MP_ROM_QSTR(MP_QSTR_PD12), MP_ROM_PTR(&pin_PD12) }, + { MP_ROM_QSTR(MP_QSTR_PD13), MP_ROM_PTR(&pin_PD13) }, + { MP_ROM_QSTR(MP_QSTR_PG02), MP_ROM_PTR(&pin_PG02) }, + { MP_ROM_QSTR(MP_QSTR_PC06), MP_ROM_PTR(&pin_PC06) }, + { MP_ROM_QSTR(MP_QSTR_PC07), MP_ROM_PTR(&pin_PC07) }, + { MP_ROM_QSTR(MP_QSTR_PC09), MP_ROM_PTR(&pin_PC09) }, + { MP_ROM_QSTR(MP_QSTR_PA08), MP_ROM_PTR(&pin_PA08) }, + { MP_ROM_QSTR(MP_QSTR_PA10), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_PA13), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_PA14), MP_ROM_PTR(&pin_PA14) }, + { MP_ROM_QSTR(MP_QSTR_PA15), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_PD06), MP_ROM_PTR(&pin_PD06) }, + { MP_ROM_QSTR(MP_QSTR_PG09), MP_ROM_PTR(&pin_PG09) }, + { MP_ROM_QSTR(MP_QSTR_PG10), MP_ROM_PTR(&pin_PG10) }, + { MP_ROM_QSTR(MP_QSTR_PG11), MP_ROM_PTR(&pin_PG11) }, + { MP_ROM_QSTR(MP_QSTR_PG12), MP_ROM_PTR(&pin_PG12) }, + { MP_ROM_QSTR(MP_QSTR_PG13), MP_ROM_PTR(&pin_PG13) }, + { MP_ROM_QSTR(MP_QSTR_PG14), MP_ROM_PTR(&pin_PG14) }, + { MP_ROM_QSTR(MP_QSTR_PB03), MP_ROM_PTR(&pin_PB03) }, + { MP_ROM_QSTR(MP_QSTR_PB04), MP_ROM_PTR(&pin_PB04) }, + { MP_ROM_QSTR(MP_QSTR_PB05), MP_ROM_PTR(&pin_PB05) }, + { MP_ROM_QSTR(MP_QSTR_PB06), MP_ROM_PTR(&pin_PB06) }, + { MP_ROM_QSTR(MP_QSTR_PB07), MP_ROM_PTR(&pin_PB07) }, + { MP_ROM_QSTR(MP_QSTR_PB08), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_PB09), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_PE00), MP_ROM_PTR(&pin_PE00) }, + { MP_ROM_QSTR(MP_QSTR_PE01), MP_ROM_PTR(&pin_PE01) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_PB10) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PG10) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PG11) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PF03) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PF10) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PG12) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PF04) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PG13) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PG14) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PG09) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA01) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PC01) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PC03) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PC04) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PC05) }, //alt PB09, see F401ZG-DISCO manual + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB00) }, //alt PB10, see F401ZG-DISCO manual + { MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_PE00) }, + { MP_ROM_QSTR(MP_QSTR_LED2), MP_ROM_PTR(&pin_PE01) }, + { MP_ROM_QSTR(MP_QSTR_LED3), MP_ROM_PTR(&pin_PE02) }, + { MP_ROM_QSTR(MP_QSTR_LED4), MP_ROM_PTR(&pin_PE03) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_hal_conf.h b/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_hal_conf.h new file mode 100644 index 000000000..4b6ba3d03 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_hal_conf.h @@ -0,0 +1,439 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf_template.h + * @author MCD Application Team + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32f4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED + + /* #define HAL_ADC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +/* #define HAL_CAN_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +/* #define HAL_DAC_MODULE_ENABLED */ +/* #define HAL_DCMI_MODULE_ENABLED */ +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +/* #define HAL_RNG_MODULE_ENABLED */ +/* #define HAL_RTC_MODULE_ENABLED */ +/* #define HAL_SAI_MODULE_ENABLED */ +/* #define HAL_SD_MODULE_ENABLED */ +/* #define HAL_MMC_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/* #define HAL_TIM_MODULE_ENABLED */ +/* #define HAL_UART_MODULE_ENABLED */ +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ +/* #define HAL_DSI_MODULE_ENABLED */ +/* #define HAL_QSPI_MODULE_ENABLED */ +/* #define HAL_QSPI_MODULE_ENABLED */ +/* #define HAL_CEC_MODULE_ENABLED */ +/* #define HAL_FMPI2C_MODULE_ENABLED */ +/* #define HAL_SPDIFRX_MODULE_ENABLED */ +/* #define HAL_DFSDM_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_EXTI_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature.*/ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768U) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000U) /*!< Value of the External audio frequency in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0U) /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U +#define INSTRUCTION_CACHE_ENABLE 1U +#define DATA_CACHE_ENABLE 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1U */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2U +#define MAC_ADDR1 0U +#define MAC_ADDR2 0U +#define MAC_ADDR3 0U +#define MAC_ADDR4 0U +#define MAC_ADDR5 0U + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4U) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4U) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848_PHY_ADDRESS Address*/ +#define DP83848_PHY_ADDRESS 0x01U +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FFU) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFU) + +#define PHY_READ_TO ((uint32_t)0x0000FFFFU) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFFU) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x0000U) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000U) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000U) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100U) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000U) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100U) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000U) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000U) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200U) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800U) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400U) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020U) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ +#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */ + +#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */ + +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver +* Activated: CRC code is present inside driver +* Deactivated: CRC code cleaned from driver +*/ + +#define USE_SPI_CRC 0U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED + #include "stm32f4xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED + #include "stm32f4xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED + #include "stm32f4xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f4xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_FMPI2C_MODULE_ENABLED + #include "stm32f4xx_hal_fmpi2c.h" +#endif /* HAL_FMPI2C_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f4xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32f4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_hal_msp.c b/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_hal_msp.c new file mode 100644 index 000000000..4989f9889 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_hal_msp.c @@ -0,0 +1,427 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : stm32f4xx_hal_msp.c + * Description : This file provides code for the MSP Initialization + * and de-Initialization codes. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +#include "stm32f4xx_hal.h" +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN Define */ +#define DATA_Ready_Pin GPIO_PIN_2 +#define DATA_Ready_GPIO_Port GPIOE +#define CS_I2C_SPI_Pin GPIO_PIN_3 +#define CS_I2C_SPI_GPIO_Port GPIOE +#define INT1_Pin GPIO_PIN_4 +#define INT1_GPIO_Port GPIOE +#define INT2_Pin GPIO_PIN_5 +#define INT2_GPIO_Port GPIOE +#define PC14_OSC32_IN_Pin GPIO_PIN_14 +#define PC14_OSC32_IN_GPIO_Port GPIOC +#define PC15_OSC32_OUT_Pin GPIO_PIN_15 +#define PC15_OSC32_OUT_GPIO_Port GPIOC +#define PH0_OSC_IN_Pin GPIO_PIN_0 +#define PH0_OSC_IN_GPIO_Port GPIOH +#define PH1_OSC_OUT_Pin GPIO_PIN_1 +#define PH1_OSC_OUT_GPIO_Port GPIOH +#define OTG_FS_PowerSwitchOn_Pin GPIO_PIN_0 +#define OTG_FS_PowerSwitchOn_GPIO_Port GPIOC +#define PDM_OUT_Pin GPIO_PIN_3 +#define PDM_OUT_GPIO_Port GPIOC +#define I2S3_WS_Pin GPIO_PIN_4 +#define I2S3_WS_GPIO_Port GPIOA +#define SPI1_SCK_Pin GPIO_PIN_5 +#define SPI1_SCK_GPIO_Port GPIOA +#define SPI1_MISO_Pin GPIO_PIN_6 +#define SPI1_MISO_GPIO_Port GPIOA +#define SPI1_MOSI_Pin GPIO_PIN_7 +#define SPI1_MOSI_GPIO_Port GPIOA +#define CLK_IN_Pin GPIO_PIN_10 +#define CLK_IN_GPIO_Port GPIOB +#define LD4_Pin GPIO_PIN_12 +#define LD4_GPIO_Port GPIOD +#define LD3_Pin GPIO_PIN_13 +#define LD3_GPIO_Port GPIOD +#define LD5_Pin GPIO_PIN_14 +#define LD5_GPIO_Port GPIOD +#define LD6_Pin GPIO_PIN_15 +#define LD6_GPIO_Port GPIOD +#define I2S3_MCK_Pin GPIO_PIN_7 +#define I2S3_MCK_GPIO_Port GPIOC +#define VBUS_FS_Pin GPIO_PIN_9 +#define VBUS_FS_GPIO_Port GPIOA +#define OTG_FS_ID_Pin GPIO_PIN_10 +#define OTG_FS_ID_GPIO_Port GPIOA +#define OTG_FS_DM_Pin GPIO_PIN_11 +#define OTG_FS_DM_GPIO_Port GPIOA +#define OTG_FS_DP_Pin GPIO_PIN_12 +#define OTG_FS_DP_GPIO_Port GPIOA +#define SWDIO_Pin GPIO_PIN_13 +#define SWDIO_GPIO_Port GPIOA +#define SWCLK_Pin GPIO_PIN_14 +#define SWCLK_GPIO_Port GPIOA +#define I2S3_SCK_Pin GPIO_PIN_10 +#define I2S3_SCK_GPIO_Port GPIOC +#define I2S3_SD_Pin GPIO_PIN_12 +#define I2S3_SD_GPIO_Port GPIOC +#define Audio_RST_Pin GPIO_PIN_4 +#define Audio_RST_GPIO_Port GPIOD +#define OTG_FS_OverCurrent_Pin GPIO_PIN_5 +#define OTG_FS_OverCurrent_GPIO_Port GPIOD +#define SWO_Pin GPIO_PIN_3 +#define SWO_GPIO_Port GPIOB +#define Audio_SCL_Pin GPIO_PIN_6 +#define Audio_SCL_GPIO_Port GPIOB +#define Audio_SDA_Pin GPIO_PIN_9 +#define Audio_SDA_GPIO_Port GPIOB +#define MEMS_INT2_Pin GPIO_PIN_1 +#define MEMS_INT2_GPIO_Port GPIOE + +/* USER CODE END Define */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN Macro */ + +/* USER CODE END Macro */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* External functions --------------------------------------------------------*/ +/* USER CODE BEGIN ExternalFunctions */ + +/* USER CODE END ExternalFunctions */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ +/** + * Initializes the Global MSP. + */ +void HAL_MspInit(void) +{ + /* USER CODE BEGIN MspInit 0 */ + + /* USER CODE END MspInit 0 */ + + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0); + + /* System interrupt init*/ + + /* USER CODE BEGIN MspInit 1 */ + + /* USER CODE END MspInit 1 */ +} + +/** +* @brief I2C MSP Initialization +* This function configures the hardware resources used in this example +* @param hi2c: I2C handle pointer +* @retval None +*/ +void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(hi2c->Instance==I2C1) + { + /* USER CODE BEGIN I2C1_MspInit 0 */ + + /* USER CODE END I2C1_MspInit 0 */ + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**I2C1 GPIO Configuration + PB6 ------> I2C1_SCL + PB9 ------> I2C1_SDA + */ + GPIO_InitStruct.Pin = Audio_SCL_Pin|Audio_SDA_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* Peripheral clock enable */ + __HAL_RCC_I2C1_CLK_ENABLE(); + /* USER CODE BEGIN I2C1_MspInit 1 */ + + /* USER CODE END I2C1_MspInit 1 */ + } + +} + +/** +* @brief I2C MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param hi2c: I2C handle pointer +* @retval None +*/ +void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c) +{ + if(hi2c->Instance==I2C1) + { + /* USER CODE BEGIN I2C1_MspDeInit 0 */ + + /* USER CODE END I2C1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_I2C1_CLK_DISABLE(); + + /**I2C1 GPIO Configuration + PB6 ------> I2C1_SCL + PB9 ------> I2C1_SDA + */ + HAL_GPIO_DeInit(GPIOB, Audio_SCL_Pin|Audio_SDA_Pin); + + /* USER CODE BEGIN I2C1_MspDeInit 1 */ + + /* USER CODE END I2C1_MspDeInit 1 */ + } + +} + +/** +* @brief I2S MSP Initialization +* This function configures the hardware resources used in this example +* @param hi2s: I2S handle pointer +* @retval None +*/ +void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(hi2s->Instance==SPI2) + { + /* USER CODE BEGIN SPI2_MspInit 0 */ + + /* USER CODE END SPI2_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_SPI2_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**I2S2 GPIO Configuration + PC2 ------> I2S2_ext_SD + PC3 ------> I2S2_SD + PB10 ------> I2S2_CK + PB12 ------> I2S2_WS + */ + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = PDM_OUT_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; + HAL_GPIO_Init(PDM_OUT_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = CLK_IN_Pin|GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* USER CODE BEGIN SPI2_MspInit 1 */ + + /* USER CODE END SPI2_MspInit 1 */ + } + else if(hi2s->Instance==SPI3) + { + /* USER CODE BEGIN SPI3_MspInit 0 */ + + /* USER CODE END SPI3_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_SPI3_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**I2S3 GPIO Configuration + PA4 ------> I2S3_WS + PC7 ------> I2S3_MCK + PC10 ------> I2S3_CK + PC12 ------> I2S3_SD + */ + GPIO_InitStruct.Pin = I2S3_WS_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; + HAL_GPIO_Init(I2S3_WS_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = I2S3_MCK_Pin|I2S3_SCK_Pin|I2S3_SD_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /* USER CODE BEGIN SPI3_MspInit 1 */ + + /* USER CODE END SPI3_MspInit 1 */ + } + +} + +/** +* @brief I2S MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param hi2s: I2S handle pointer +* @retval None +*/ +void HAL_I2S_MspDeInit(I2S_HandleTypeDef* hi2s) +{ + if(hi2s->Instance==SPI2) + { + /* USER CODE BEGIN SPI2_MspDeInit 0 */ + + /* USER CODE END SPI2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI2_CLK_DISABLE(); + + /**I2S2 GPIO Configuration + PC2 ------> I2S2_ext_SD + PC3 ------> I2S2_SD + PB10 ------> I2S2_CK + PB12 ------> I2S2_WS + */ + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2|PDM_OUT_Pin); + + HAL_GPIO_DeInit(GPIOB, CLK_IN_Pin|GPIO_PIN_12); + + /* USER CODE BEGIN SPI2_MspDeInit 1 */ + + /* USER CODE END SPI2_MspDeInit 1 */ + } + else if(hi2s->Instance==SPI3) + { + /* USER CODE BEGIN SPI3_MspDeInit 0 */ + + /* USER CODE END SPI3_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI3_CLK_DISABLE(); + + /**I2S3 GPIO Configuration + PA4 ------> I2S3_WS + PC7 ------> I2S3_MCK + PC10 ------> I2S3_CK + PC12 ------> I2S3_SD + */ + HAL_GPIO_DeInit(I2S3_WS_GPIO_Port, I2S3_WS_Pin); + + HAL_GPIO_DeInit(GPIOC, I2S3_MCK_Pin|I2S3_SCK_Pin|I2S3_SD_Pin); + + /* USER CODE BEGIN SPI3_MspDeInit 1 */ + + /* USER CODE END SPI3_MspDeInit 1 */ + } + +} + +/** +* @brief SPI MSP Initialization +* This function configures the hardware resources used in this example +* @param hspi: SPI handle pointer +* @retval None +*/ +void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(hspi->Instance==SPI1) + { + /* USER CODE BEGIN SPI1_MspInit 0 */ + + /* USER CODE END SPI1_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_SPI1_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**SPI1 GPIO Configuration + PA5 ------> SPI1_SCK + PA6 ------> SPI1_MISO + PA7 ------> SPI1_MOSI + */ + GPIO_InitStruct.Pin = SPI1_SCK_Pin|SPI1_MISO_Pin|SPI1_MOSI_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* USER CODE BEGIN SPI1_MspInit 1 */ + + /* USER CODE END SPI1_MspInit 1 */ + } + +} + +/** +* @brief SPI MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param hspi: SPI handle pointer +* @retval None +*/ +void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi) +{ + if(hspi->Instance==SPI1) + { + /* USER CODE BEGIN SPI1_MspDeInit 0 */ + + /* USER CODE END SPI1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI1_CLK_DISABLE(); + + /**SPI1 GPIO Configuration + PA5 ------> SPI1_SCK + PA6 ------> SPI1_MISO + PA7 ------> SPI1_MOSI + */ + HAL_GPIO_DeInit(GPIOA, SPI1_SCK_Pin|SPI1_MISO_Pin|SPI1_MOSI_Pin); + + /* USER CODE BEGIN SPI1_MspDeInit 1 */ + + /* USER CODE END SPI1_MspDeInit 1 */ + } + +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.c b/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.c new file mode 100644 index 000000000..cb86910e2 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.c @@ -0,0 +1,217 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32f4xx_it.c + * @brief Interrupt Service Routines. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "stm32f4xx_it.h" +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* External variables --------------------------------------------------------*/ +extern PCD_HandleTypeDef hpcd_USB_OTG_FS; +/* USER CODE BEGIN EV */ + +/* USER CODE END EV */ + +/******************************************************************************/ +/* Cortex-M4 Processor Interruption and Exception Handlers */ +/******************************************************************************/ +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ + /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ + + /* USER CODE END NonMaskableInt_IRQn 0 */ + /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ + + /* USER CODE END NonMaskableInt_IRQn 1 */ +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + /* USER CODE BEGIN HardFault_IRQn 0 */ + + /* USER CODE END HardFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_HardFault_IRQn 0 */ + /* USER CODE END W1_HardFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Memory management fault. + */ +void MemManage_Handler(void) +{ + /* USER CODE BEGIN MemoryManagement_IRQn 0 */ + + /* USER CODE END MemoryManagement_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ + /* USER CODE END W1_MemoryManagement_IRQn 0 */ + } +} + +/** + * @brief This function handles Pre-fetch fault, memory access fault. + */ +void BusFault_Handler(void) +{ + /* USER CODE BEGIN BusFault_IRQn 0 */ + + /* USER CODE END BusFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_BusFault_IRQn 0 */ + /* USER CODE END W1_BusFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Undefined instruction or illegal state. + */ +void UsageFault_Handler(void) +{ + /* USER CODE BEGIN UsageFault_IRQn 0 */ + + /* USER CODE END UsageFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ + /* USER CODE END W1_UsageFault_IRQn 0 */ + } +} + +/** + * @brief This function handles System service call via SWI instruction. + */ +void SVC_Handler(void) +{ + /* USER CODE BEGIN SVCall_IRQn 0 */ + + /* USER CODE END SVCall_IRQn 0 */ + /* USER CODE BEGIN SVCall_IRQn 1 */ + + /* USER CODE END SVCall_IRQn 1 */ +} + +/** + * @brief This function handles Debug monitor. + */ +void DebugMon_Handler(void) +{ + /* USER CODE BEGIN DebugMonitor_IRQn 0 */ + + /* USER CODE END DebugMonitor_IRQn 0 */ + /* USER CODE BEGIN DebugMonitor_IRQn 1 */ + + /* USER CODE END DebugMonitor_IRQn 1 */ +} + +/** + * @brief This function handles Pendable request for system service. + */ +void PendSV_Handler(void) +{ + /* USER CODE BEGIN PendSV_IRQn 0 */ + + /* USER CODE END PendSV_IRQn 0 */ + /* USER CODE BEGIN PendSV_IRQn 1 */ + + /* USER CODE END PendSV_IRQn 1 */ +} + +/** + * @brief This function handles System tick timer. + */ +void SysTick_Handler(void) +{ + /* USER CODE BEGIN SysTick_IRQn 0 */ + + /* USER CODE END SysTick_IRQn 0 */ + HAL_IncTick(); + /* USER CODE BEGIN SysTick_IRQn 1 */ + + /* USER CODE END SysTick_IRQn 1 */ +} + +/******************************************************************************/ +/* STM32F4xx Peripheral Interrupt Handlers */ +/* Add here the Interrupt Handlers for the used peripherals. */ +/* For the available peripheral interrupt handler names, */ +/* please refer to the startup file (startup_stm32f4xx.s). */ +/******************************************************************************/ + +/** + * @brief This function handles USB On The Go FS global interrupt. + */ +void OTG_FS_IRQHandler(void) +{ + /* USER CODE BEGIN OTG_FS_IRQn 0 */ + + /* USER CODE END OTG_FS_IRQn 0 */ + HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); + /* USER CODE BEGIN OTG_FS_IRQn 1 */ + + /* USER CODE END OTG_FS_IRQn 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.h b/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.h new file mode 100644 index 000000000..feee38a39 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F411RE/stm32f4xx_it.h @@ -0,0 +1,70 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32f4xx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_IT_H +#define __STM32F4xx_IT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); +void OTG_FS_IRQHandler(void); +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_IT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/DIS_F412ZG/board.c b/ports/stm32f4/boards/DIS_F412ZG/board.c new file mode 100644 index 000000000..4421970ee --- /dev/null +++ b/ports/stm32f4/boards/DIS_F412ZG/board.c @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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 "boards/board.h" + +void board_init(void) { +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.h b/ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.h new file mode 100644 index 000000000..416944257 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +//Micropython setup + +#define MICROPY_HW_BOARD_NAME "STM32F412G_DISCO" +#define MICROPY_HW_MCU_NAME "STM32F412xGS" + +#define FLASH_SIZE (0x100000) +#define FLASH_PAGE_SIZE (0x4000) + +#define CIRCUITPY_INTERNAL_NVM_SIZE (4096) +#define AUTORESET_DELAY_MS 500 +#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) \ No newline at end of file diff --git a/ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.mk b/ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.mk new file mode 100644 index 000000000..9e8711c36 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F412ZG/mpconfigboard.mk @@ -0,0 +1,18 @@ +USB_VID = 0x239A +USB_PID = 0x802A +USB_PRODUCT = "A glorious potato" +USB_MANUFACTURER = "Adafruit Industries LLC" + +#USB_VID = 0x483 +#USB_PID = 0x572B +#USB_PRODUCT = "STM32 Human Interface Potato" +#USB_MANUFACTURER = "STMicroelectronics" + +MCU_SERIES = m4 +MCU_VARIANT = stm32f4 +MCU_SUB_VARIANT = stm32f412zx +CMSIS_MCU = STM32F412xG +LD_FILE = boards/STM32F412ZGTx_FLASH.ld +TEXT0_ADDR = 0x08000000 +TEXT1_ADDR = 0x08020000 + diff --git a/ports/stm32f4/boards/DIS_F412ZG/pins.c b/ports/stm32f4/boards/DIS_F412ZG/pins.c new file mode 100644 index 000000000..e3a4b5ed6 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F412ZG/pins.c @@ -0,0 +1,90 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_PE02), MP_ROM_PTR(&pin_PE02) }, + { MP_ROM_QSTR(MP_QSTR_PE03), MP_ROM_PTR(&pin_PE03) }, + { MP_ROM_QSTR(MP_QSTR_PE04), MP_ROM_PTR(&pin_PE04) }, + { MP_ROM_QSTR(MP_QSTR_PE05), MP_ROM_PTR(&pin_PE05) }, + { MP_ROM_QSTR(MP_QSTR_PE06), MP_ROM_PTR(&pin_PE06) }, + { MP_ROM_QSTR(MP_QSTR_PC13), MP_ROM_PTR(&pin_PC13) }, + { MP_ROM_QSTR(MP_QSTR_PF02), MP_ROM_PTR(&pin_PF02) }, + { MP_ROM_QSTR(MP_QSTR_PF03), MP_ROM_PTR(&pin_PF03) }, + { MP_ROM_QSTR(MP_QSTR_PF10), MP_ROM_PTR(&pin_PF10) }, + { MP_ROM_QSTR(MP_QSTR_PC00), MP_ROM_PTR(&pin_PC00) }, + { MP_ROM_QSTR(MP_QSTR_PC01), MP_ROM_PTR(&pin_PC01) }, + { MP_ROM_QSTR(MP_QSTR_PC02), MP_ROM_PTR(&pin_PC02) }, + { MP_ROM_QSTR(MP_QSTR_PC03), MP_ROM_PTR(&pin_PC03) }, + { MP_ROM_QSTR(MP_QSTR_PA01), MP_ROM_PTR(&pin_PA01) }, + { MP_ROM_QSTR(MP_QSTR_PA02), MP_ROM_PTR(&pin_PA02) }, + { MP_ROM_QSTR(MP_QSTR_PA03), MP_ROM_PTR(&pin_PA03) }, + { MP_ROM_QSTR(MP_QSTR_PA04), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_PA05), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_PA06), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_PA07), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_PC04), MP_ROM_PTR(&pin_PC04) }, + { MP_ROM_QSTR(MP_QSTR_PC05), MP_ROM_PTR(&pin_PC05) }, + { MP_ROM_QSTR(MP_QSTR_PB00), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_PB01), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_PF11), MP_ROM_PTR(&pin_PF11) }, + { MP_ROM_QSTR(MP_QSTR_PF13), MP_ROM_PTR(&pin_PF13) }, + { MP_ROM_QSTR(MP_QSTR_PB10), MP_ROM_PTR(&pin_PB10) }, + { MP_ROM_QSTR(MP_QSTR_PB11), MP_ROM_PTR(&pin_PB11) }, + { MP_ROM_QSTR(MP_QSTR_PB12), MP_ROM_PTR(&pin_PB12) }, + { MP_ROM_QSTR(MP_QSTR_PB13), MP_ROM_PTR(&pin_PB13) }, + { MP_ROM_QSTR(MP_QSTR_PB14), MP_ROM_PTR(&pin_PB14) }, + { MP_ROM_QSTR(MP_QSTR_PB15), MP_ROM_PTR(&pin_PB15) }, + { MP_ROM_QSTR(MP_QSTR_PD12), MP_ROM_PTR(&pin_PD12) }, + { MP_ROM_QSTR(MP_QSTR_PD13), MP_ROM_PTR(&pin_PD13) }, + { MP_ROM_QSTR(MP_QSTR_PG02), MP_ROM_PTR(&pin_PG02) }, + { MP_ROM_QSTR(MP_QSTR_PC06), MP_ROM_PTR(&pin_PC06) }, + { MP_ROM_QSTR(MP_QSTR_PC07), MP_ROM_PTR(&pin_PC07) }, + { MP_ROM_QSTR(MP_QSTR_PC09), MP_ROM_PTR(&pin_PC09) }, + { MP_ROM_QSTR(MP_QSTR_PA08), MP_ROM_PTR(&pin_PA08) }, + { MP_ROM_QSTR(MP_QSTR_PA10), MP_ROM_PTR(&pin_PA10) }, + { MP_ROM_QSTR(MP_QSTR_PA13), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_PA14), MP_ROM_PTR(&pin_PA14) }, + { MP_ROM_QSTR(MP_QSTR_PA15), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_PD06), MP_ROM_PTR(&pin_PD06) }, + { MP_ROM_QSTR(MP_QSTR_PG09), MP_ROM_PTR(&pin_PG09) }, + { MP_ROM_QSTR(MP_QSTR_PG10), MP_ROM_PTR(&pin_PG10) }, + { MP_ROM_QSTR(MP_QSTR_PG11), MP_ROM_PTR(&pin_PG11) }, + { MP_ROM_QSTR(MP_QSTR_PG12), MP_ROM_PTR(&pin_PG12) }, + { MP_ROM_QSTR(MP_QSTR_PG13), MP_ROM_PTR(&pin_PG13) }, + { MP_ROM_QSTR(MP_QSTR_PG14), MP_ROM_PTR(&pin_PG14) }, + { MP_ROM_QSTR(MP_QSTR_PB03), MP_ROM_PTR(&pin_PB03) }, + { MP_ROM_QSTR(MP_QSTR_PB04), MP_ROM_PTR(&pin_PB04) }, + { MP_ROM_QSTR(MP_QSTR_PB05), MP_ROM_PTR(&pin_PB05) }, + { MP_ROM_QSTR(MP_QSTR_PB06), MP_ROM_PTR(&pin_PB06) }, + { MP_ROM_QSTR(MP_QSTR_PB07), MP_ROM_PTR(&pin_PB07) }, + { MP_ROM_QSTR(MP_QSTR_PB08), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_PB09), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_PE00), MP_ROM_PTR(&pin_PE00) }, + { MP_ROM_QSTR(MP_QSTR_PE01), MP_ROM_PTR(&pin_PE01) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_PB10) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PG10) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PG11) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PF03) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PF10) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PG12) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PF04) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PG13) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PG14) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PG09) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA01) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PC01) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PC03) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PC04) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PC05) }, //alt PB09, see F401ZG-DISCO manual + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB00) }, //alt PB10, see F401ZG-DISCO manual + { MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_PE00) }, + { MP_ROM_QSTR(MP_QSTR_LED2), MP_ROM_PTR(&pin_PE01) }, + { MP_ROM_QSTR(MP_QSTR_LED3), MP_ROM_PTR(&pin_PE02) }, + { MP_ROM_QSTR(MP_QSTR_LED4), MP_ROM_PTR(&pin_PE03) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_conf.h b/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_conf.h new file mode 100644 index 000000000..5d329c14f --- /dev/null +++ b/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_conf.h @@ -0,0 +1,439 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_conf_template.h + * @author MCD Application Team + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32f4xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_CONF_H +#define __STM32F4xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ +#define HAL_MODULE_ENABLED + + /* #define HAL_ADC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +/* #define HAL_CAN_MODULE_ENABLED */ +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_CRYP_MODULE_ENABLED */ +/* #define HAL_DAC_MODULE_ENABLED */ +/* #define HAL_DCMI_MODULE_ENABLED */ +/* #define HAL_DMA2D_MODULE_ENABLED */ +/* #define HAL_ETH_MODULE_ENABLED */ +/* #define HAL_NAND_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +#define HAL_SRAM_MODULE_ENABLED +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_HASH_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED +#define HAL_I2S_MODULE_ENABLED +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_LTDC_MODULE_ENABLED */ +/* #define HAL_RNG_MODULE_ENABLED */ +/* #define HAL_RTC_MODULE_ENABLED */ +/* #define HAL_SAI_MODULE_ENABLED */ +#define HAL_SD_MODULE_ENABLED +/* #define HAL_MMC_MODULE_ENABLED */ +/* #define HAL_SPI_MODULE_ENABLED */ +/* #define HAL_TIM_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_WWDG_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +/* #define HAL_HCD_MODULE_ENABLED */ +/* #define HAL_DSI_MODULE_ENABLED */ +/* #define HAL_QSPI_MODULE_ENABLED */ +#define HAL_QSPI_MODULE_ENABLED +/* #define HAL_CEC_MODULE_ENABLED */ +/* #define HAL_FMPI2C_MODULE_ENABLED */ +/* #define HAL_SPDIFRX_MODULE_ENABLED */ +/* #define HAL_DFSDM_MODULE_ENABLED */ +/* #define HAL_LPTIM_MODULE_ENABLED */ +/* #define HAL_EXTI_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## HSE/HSI Values adaptation ##################### */ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature.*/ +/** + * @brief External Low Speed oscillator (LSE) value. + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE ((uint32_t)32768U) /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for I2S peripheral + * This value is used by the I2S HAL module to compute the I2S clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000U) /*!< Value of the External audio frequency in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ +#define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY ((uint32_t)0U) /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U +#define INSTRUCTION_CACHE_ENABLE 1U +#define DATA_CACHE_ENABLE 1U + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1U */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2U +#define MAC_ADDR1 0U +#define MAC_ADDR2 0U +#define MAC_ADDR3 0U +#define MAC_ADDR4 0U +#define MAC_ADDR5 0U + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB ((uint32_t)4U) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB ((uint32_t)4U) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848_PHY_ADDRESS Address*/ +#define DP83848_PHY_ADDRESS 0x01U +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY ((uint32_t)0x000000FFU) +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFU) + +#define PHY_READ_TO ((uint32_t)0x0000FFFFU) +#define PHY_WRITE_TO ((uint32_t)0x0000FFFFU) + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x0000U) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000U) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000U) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100U) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000U) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100U) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000U) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000U) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200U) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800U) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400U) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020U) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ +#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */ + +#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */ + +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver +* Activated: CRC code is present inside driver +* Deactivated: CRC code cleaned from driver +*/ + +#define USE_SPI_CRC 0U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32f4xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED + #include "stm32f4xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32f4xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32f4xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32f4xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32f4xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED + #include "stm32f4xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32f4xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32f4xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED + #include "stm32f4xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32f4xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32f4xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32f4xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32f4xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32f4xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32f4xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED + #include "stm32f4xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32f4xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32f4xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32f4xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32f4xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32f4xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED + #include "stm32f4xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32f4xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32f4xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32f4xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32f4xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32f4xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED + #include "stm32f4xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32f4xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32f4xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32f4xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32f4xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32f4xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32f4xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32f4xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32f4xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32f4xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED + #include "stm32f4xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_QSPI_MODULE_ENABLED + #include "stm32f4xx_hal_qspi.h" +#endif /* HAL_QSPI_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32f4xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_FMPI2C_MODULE_ENABLED + #include "stm32f4xx_hal_fmpi2c.h" +#endif /* HAL_FMPI2C_MODULE_ENABLED */ + +#ifdef HAL_SPDIFRX_MODULE_ENABLED + #include "stm32f4xx_hal_spdifrx.h" +#endif /* HAL_SPDIFRX_MODULE_ENABLED */ + +#ifdef HAL_DFSDM_MODULE_ENABLED + #include "stm32f4xx_hal_dfsdm.h" +#endif /* HAL_DFSDM_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED + #include "stm32f4xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ + void assert_failed(uint8_t* file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_CONF_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_msp.c b/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_msp.c new file mode 100644 index 000000000..9d29f3607 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_hal_msp.c @@ -0,0 +1,832 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : stm32f4xx_hal_msp.c + * Description : This file provides code for the MSP Initialization + * and de-Initialization codes. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN Define */ +#define LED3_Pin GPIO_PIN_2 +#define LED3_GPIO_Port GPIOE +#define LED4_Pin GPIO_PIN_3 +#define LED4_GPIO_Port GPIOE +#define DFSDM_DATIN3_Pin GPIO_PIN_4 +#define DFSDM_DATIN3_GPIO_Port GPIOE +#define A0_Pin GPIO_PIN_0 +#define A0_GPIO_Port GPIOF +#define LCD_BLCTRL_Pin GPIO_PIN_5 +#define LCD_BLCTRL_GPIO_Port GPIOF +#define QSPI_BK1_IO3_Pin GPIO_PIN_6 +#define QSPI_BK1_IO3_GPIO_Port GPIOF +#define QSPI_BK1_IO2_Pin GPIO_PIN_7 +#define QSPI_BK1_IO2_GPIO_Port GPIOF +#define QSPI_BK1_IO0_Pin GPIO_PIN_8 +#define QSPI_BK1_IO0_GPIO_Port GPIOF +#define QSPI_BK1_IO1_Pin GPIO_PIN_9 +#define QSPI_BK1_IO1_GPIO_Port GPIOF +#define STLK_MCO_Pin GPIO_PIN_0 +#define STLK_MCO_GPIO_Port GPIOH +#define DFSDM_CKOUT_Pin GPIO_PIN_2 +#define DFSDM_CKOUT_GPIO_Port GPIOC +#define JOY_SEL_Pin GPIO_PIN_0 +#define JOY_SEL_GPIO_Port GPIOA +#define STLINK_RX_Pin GPIO_PIN_2 +#define STLINK_RX_GPIO_Port GPIOA +#define STLINK_TX_Pin GPIO_PIN_3 +#define STLINK_TX_GPIO_Port GPIOA +#define CODEC_I2S3_WS_Pin GPIO_PIN_4 +#define CODEC_I2S3_WS_GPIO_Port GPIOA +#define DFSDM_DATIN0_Pin GPIO_PIN_1 +#define DFSDM_DATIN0_GPIO_Port GPIOB +#define QSPI_CLK_Pin GPIO_PIN_2 +#define QSPI_CLK_GPIO_Port GPIOB +#define EXT_RESET_Pin GPIO_PIN_11 +#define EXT_RESET_GPIO_Port GPIOF +#define CTP_RST_Pin GPIO_PIN_12 +#define CTP_RST_GPIO_Port GPIOF +#define JOY_RIGHT_Pin GPIO_PIN_14 +#define JOY_RIGHT_GPIO_Port GPIOF +#define JOY_LEFT_Pin GPIO_PIN_15 +#define JOY_LEFT_GPIO_Port GPIOF +#define JOY_UP_Pin GPIO_PIN_0 +#define JOY_UP_GPIO_Port GPIOG +#define JOY_DOWN_Pin GPIO_PIN_1 +#define JOY_DOWN_GPIO_Port GPIOG +#define D4_Pin GPIO_PIN_7 +#define D4_GPIO_Port GPIOE +#define D5_Pin GPIO_PIN_8 +#define D5_GPIO_Port GPIOE +#define D6_Pin GPIO_PIN_9 +#define D6_GPIO_Port GPIOE +#define D7_Pin GPIO_PIN_10 +#define D7_GPIO_Port GPIOE +#define D8_Pin GPIO_PIN_11 +#define D8_GPIO_Port GPIOE +#define D9_Pin GPIO_PIN_12 +#define D9_GPIO_Port GPIOE +#define D10_Pin GPIO_PIN_13 +#define D10_GPIO_Port GPIOE +#define D11_Pin GPIO_PIN_14 +#define D11_GPIO_Port GPIOE +#define D12_Pin GPIO_PIN_15 +#define D12_GPIO_Port GPIOE +#define I2C2_SCL_Pin GPIO_PIN_10 +#define I2C2_SCL_GPIO_Port GPIOB +#define M2_CKIN_Pin GPIO_PIN_11 +#define M2_CKIN_GPIO_Port GPIOB +#define CODEC_I2S3_SCK_Pin GPIO_PIN_12 +#define CODEC_I2S3_SCK_GPIO_Port GPIOB +#define D13_Pin GPIO_PIN_8 +#define D13_GPIO_Port GPIOD +#define D14_Pin GPIO_PIN_9 +#define D14_GPIO_Port GPIOD +#define D15_Pin GPIO_PIN_10 +#define D15_GPIO_Port GPIOD +#define LCD_RESET_Pin GPIO_PIN_11 +#define LCD_RESET_GPIO_Port GPIOD +#define D0_Pin GPIO_PIN_14 +#define D0_GPIO_Port GPIOD +#define D1_Pin GPIO_PIN_15 +#define D1_GPIO_Port GPIOD +#define CODEC_INT_Pin GPIO_PIN_2 +#define CODEC_INT_GPIO_Port GPIOG +#define LCD_TE_Pin GPIO_PIN_4 +#define LCD_TE_GPIO_Port GPIOG +#define CTP_INT_Pin GPIO_PIN_5 +#define CTP_INT_GPIO_Port GPIOG +#define QSPI_BK1_NCS_Pin GPIO_PIN_6 +#define QSPI_BK1_NCS_GPIO_Port GPIOG +#define USB_OTGFS_OVRCR_Pin GPIO_PIN_7 +#define USB_OTGFS_OVRCR_GPIO_Port GPIOG +#define USB_OTGFS_PPWR_EN_Pin GPIO_PIN_8 +#define USB_OTGFS_PPWR_EN_GPIO_Port GPIOG +#define CODEC_I2S3_MCK_Pin GPIO_PIN_7 +#define CODEC_I2S3_MCK_GPIO_Port GPIOC +#define uSD_D0_Pin GPIO_PIN_8 +#define uSD_D0_GPIO_Port GPIOC +#define uSD_D1_Pin GPIO_PIN_9 +#define uSD_D1_GPIO_Port GPIOC +#define M2_CKINA8_Pin GPIO_PIN_8 +#define M2_CKINA8_GPIO_Port GPIOA +#define USB_OTGFS_VBUS_Pin GPIO_PIN_9 +#define USB_OTGFS_VBUS_GPIO_Port GPIOA +#define USB_OTGFS_ID_Pin GPIO_PIN_10 +#define USB_OTGFS_ID_GPIO_Port GPIOA +#define USB_OTGFS_DM_Pin GPIO_PIN_11 +#define USB_OTGFS_DM_GPIO_Port GPIOA +#define USB_OTGFS_DP_Pin GPIO_PIN_12 +#define USB_OTGFS_DP_GPIO_Port GPIOA +#define SWDIO_Pin GPIO_PIN_13 +#define SWDIO_GPIO_Port GPIOA +#define SWCLK_Pin GPIO_PIN_14 +#define SWCLK_GPIO_Port GPIOA +#define uSD_D2_Pin GPIO_PIN_10 +#define uSD_D2_GPIO_Port GPIOC +#define uSD_D3_Pin GPIO_PIN_11 +#define uSD_D3_GPIO_Port GPIOC +#define uSD_CLK_Pin GPIO_PIN_12 +#define uSD_CLK_GPIO_Port GPIOC +#define D2_Pin GPIO_PIN_0 +#define D2_GPIO_Port GPIOD +#define D3_Pin GPIO_PIN_1 +#define D3_GPIO_Port GPIOD +#define uSD_CMD_Pin GPIO_PIN_2 +#define uSD_CMD_GPIO_Port GPIOD +#define uSD_DETECT_Pin GPIO_PIN_3 +#define uSD_DETECT_GPIO_Port GPIOD +#define FMC_NOE_Pin GPIO_PIN_4 +#define FMC_NOE_GPIO_Port GPIOD +#define FMC_NWE_Pin GPIO_PIN_5 +#define FMC_NWE_GPIO_Port GPIOD +#define FMC_NE1_Pin GPIO_PIN_7 +#define FMC_NE1_GPIO_Port GPIOD +#define SWO_Pin GPIO_PIN_3 +#define SWO_GPIO_Port GPIOB +#define CODEC_I2S3ext_SD_Pin GPIO_PIN_4 +#define CODEC_I2S3ext_SD_GPIO_Port GPIOB +#define CODEC_I2S3_SD_Pin GPIO_PIN_5 +#define CODEC_I2S3_SD_GPIO_Port GPIOB +#define I2C1_SCL_Pin GPIO_PIN_6 +#define I2C1_SCL_GPIO_Port GPIOB +#define I2C1_SDA_Pin GPIO_PIN_7 +#define I2C1_SDA_GPIO_Port GPIOB +#define I2C2_SDA_Pin GPIO_PIN_9 +#define I2C2_SDA_GPIO_Port GPIOB +#define LED1_Pin GPIO_PIN_0 +#define LED1_GPIO_Port GPIOE +#define LED2_Pin GPIO_PIN_1 +#define LED2_GPIO_Port GPIOE + +/* USER CODE END Define */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN Macro */ + +/* USER CODE END Macro */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* External functions --------------------------------------------------------*/ +/* USER CODE BEGIN ExternalFunctions */ + +/* USER CODE END ExternalFunctions */ + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ +/** + * Initializes the Global MSP. + */ +void HAL_MspInit(void) +{ + /* USER CODE BEGIN MspInit 0 */ + + /* USER CODE END MspInit 0 */ + + __HAL_RCC_SYSCFG_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + /* System interrupt init*/ + + /* USER CODE BEGIN MspInit 1 */ + + /* USER CODE END MspInit 1 */ +} + +/** +* @brief I2C MSP Initialization +* This function configures the hardware resources used in this example +* @param hi2c: I2C handle pointer +* @retval None +*/ +void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(hi2c->Instance==I2C1) + { + /* USER CODE BEGIN I2C1_MspInit 0 */ + + /* USER CODE END I2C1_MspInit 0 */ + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**I2C1 GPIO Configuration + PB6 ------> I2C1_SCL + PB7 ------> I2C1_SDA + */ + GPIO_InitStruct.Pin = I2C1_SCL_Pin|I2C1_SDA_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /* Peripheral clock enable */ + __HAL_RCC_I2C1_CLK_ENABLE(); + /* USER CODE BEGIN I2C1_MspInit 1 */ + + /* USER CODE END I2C1_MspInit 1 */ + } + else if(hi2c->Instance==I2C2) + { + /* USER CODE BEGIN I2C2_MspInit 0 */ + + /* USER CODE END I2C2_MspInit 0 */ + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**I2C2 GPIO Configuration + PB10 ------> I2C2_SCL + PB9 ------> I2C2_SDA + */ + GPIO_InitStruct.Pin = I2C2_SCL_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C2; + HAL_GPIO_Init(I2C2_SCL_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = I2C2_SDA_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF9_I2C2; + HAL_GPIO_Init(I2C2_SDA_GPIO_Port, &GPIO_InitStruct); + + /* Peripheral clock enable */ + __HAL_RCC_I2C2_CLK_ENABLE(); + /* USER CODE BEGIN I2C2_MspInit 1 */ + + /* USER CODE END I2C2_MspInit 1 */ + } + +} + +/** +* @brief I2C MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param hi2c: I2C handle pointer +* @retval None +*/ +void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c) +{ + if(hi2c->Instance==I2C1) + { + /* USER CODE BEGIN I2C1_MspDeInit 0 */ + + /* USER CODE END I2C1_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_I2C1_CLK_DISABLE(); + + /**I2C1 GPIO Configuration + PB6 ------> I2C1_SCL + PB7 ------> I2C1_SDA + */ + HAL_GPIO_DeInit(GPIOB, I2C1_SCL_Pin|I2C1_SDA_Pin); + + /* USER CODE BEGIN I2C1_MspDeInit 1 */ + + /* USER CODE END I2C1_MspDeInit 1 */ + } + else if(hi2c->Instance==I2C2) + { + /* USER CODE BEGIN I2C2_MspDeInit 0 */ + + /* USER CODE END I2C2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_I2C2_CLK_DISABLE(); + + /**I2C2 GPIO Configuration + PB10 ------> I2C2_SCL + PB9 ------> I2C2_SDA + */ + HAL_GPIO_DeInit(GPIOB, I2C2_SCL_Pin|I2C2_SDA_Pin); + + /* USER CODE BEGIN I2C2_MspDeInit 1 */ + + /* USER CODE END I2C2_MspDeInit 1 */ + } + +} + +/** +* @brief I2S MSP Initialization +* This function configures the hardware resources used in this example +* @param hi2s: I2S handle pointer +* @retval None +*/ +void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(hi2s->Instance==SPI3) + { + /* USER CODE BEGIN SPI3_MspInit 0 */ + + /* USER CODE END SPI3_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_SPI3_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**I2S3 GPIO Configuration + PA4 ------> I2S3_WS + PB12 ------> I2S3_CK + PC7 ------> I2S3_MCK + PB4 ------> I2S3_ext_SD + PB5 ------> I2S3_SD + */ + GPIO_InitStruct.Pin = CODEC_I2S3_WS_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; + HAL_GPIO_Init(CODEC_I2S3_WS_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = CODEC_I2S3_SCK_Pin|CODEC_I2S3ext_SD_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF7_SPI3; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = CODEC_I2S3_MCK_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; + HAL_GPIO_Init(CODEC_I2S3_MCK_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = CODEC_I2S3_SD_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; + HAL_GPIO_Init(CODEC_I2S3_SD_GPIO_Port, &GPIO_InitStruct); + + /* USER CODE BEGIN SPI3_MspInit 1 */ + + /* USER CODE END SPI3_MspInit 1 */ + } + +} + +/** +* @brief I2S MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param hi2s: I2S handle pointer +* @retval None +*/ +void HAL_I2S_MspDeInit(I2S_HandleTypeDef* hi2s) +{ + if(hi2s->Instance==SPI3) + { + /* USER CODE BEGIN SPI3_MspDeInit 0 */ + + /* USER CODE END SPI3_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI3_CLK_DISABLE(); + + /**I2S3 GPIO Configuration + PA4 ------> I2S3_WS + PB12 ------> I2S3_CK + PC7 ------> I2S3_MCK + PB4 ------> I2S3_ext_SD + PB5 ------> I2S3_SD + */ + HAL_GPIO_DeInit(CODEC_I2S3_WS_GPIO_Port, CODEC_I2S3_WS_Pin); + + HAL_GPIO_DeInit(GPIOB, CODEC_I2S3_SCK_Pin|CODEC_I2S3ext_SD_Pin|CODEC_I2S3_SD_Pin); + + HAL_GPIO_DeInit(CODEC_I2S3_MCK_GPIO_Port, CODEC_I2S3_MCK_Pin); + + /* USER CODE BEGIN SPI3_MspDeInit 1 */ + + /* USER CODE END SPI3_MspDeInit 1 */ + } + +} + +/** +* @brief QSPI MSP Initialization +* This function configures the hardware resources used in this example +* @param hqspi: QSPI handle pointer +* @retval None +*/ +void HAL_QSPI_MspInit(QSPI_HandleTypeDef* hqspi) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(hqspi->Instance==QUADSPI) + { + /* USER CODE BEGIN QUADSPI_MspInit 0 */ + + /* USER CODE END QUADSPI_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_QSPI_CLK_ENABLE(); + + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + /**QUADSPI GPIO Configuration + PF6 ------> QUADSPI_BK1_IO3 + PF7 ------> QUADSPI_BK1_IO2 + PF8 ------> QUADSPI_BK1_IO0 + PF9 ------> QUADSPI_BK1_IO1 + PB2 ------> QUADSPI_CLK + PG6 ------> QUADSPI_BK1_NCS + */ + GPIO_InitStruct.Pin = QSPI_BK1_IO3_Pin|QSPI_BK1_IO2_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF9_QSPI; + HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = QSPI_BK1_IO0_Pin|QSPI_BK1_IO1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = QSPI_CLK_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF9_QSPI; + HAL_GPIO_Init(QSPI_CLK_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = QSPI_BK1_NCS_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + HAL_GPIO_Init(QSPI_BK1_NCS_GPIO_Port, &GPIO_InitStruct); + + /* USER CODE BEGIN QUADSPI_MspInit 1 */ + + /* USER CODE END QUADSPI_MspInit 1 */ + } + +} + +/** +* @brief QSPI MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param hqspi: QSPI handle pointer +* @retval None +*/ +void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef* hqspi) +{ + if(hqspi->Instance==QUADSPI) + { + /* USER CODE BEGIN QUADSPI_MspDeInit 0 */ + + /* USER CODE END QUADSPI_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_QSPI_CLK_DISABLE(); + + /**QUADSPI GPIO Configuration + PF6 ------> QUADSPI_BK1_IO3 + PF7 ------> QUADSPI_BK1_IO2 + PF8 ------> QUADSPI_BK1_IO0 + PF9 ------> QUADSPI_BK1_IO1 + PB2 ------> QUADSPI_CLK + PG6 ------> QUADSPI_BK1_NCS + */ + HAL_GPIO_DeInit(GPIOF, QSPI_BK1_IO3_Pin|QSPI_BK1_IO2_Pin|QSPI_BK1_IO0_Pin|QSPI_BK1_IO1_Pin); + + HAL_GPIO_DeInit(QSPI_CLK_GPIO_Port, QSPI_CLK_Pin); + + HAL_GPIO_DeInit(QSPI_BK1_NCS_GPIO_Port, QSPI_BK1_NCS_Pin); + + /* USER CODE BEGIN QUADSPI_MspDeInit 1 */ + + /* USER CODE END QUADSPI_MspDeInit 1 */ + } + +} + +/** +* @brief SD MSP Initialization +* This function configures the hardware resources used in this example +* @param hsd: SD handle pointer +* @retval None +*/ +void HAL_SD_MspInit(SD_HandleTypeDef* hsd) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(hsd->Instance==SDIO) + { + /* USER CODE BEGIN SDIO_MspInit 0 */ + + /* USER CODE END SDIO_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_SDIO_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + /**SDIO GPIO Configuration + PC8 ------> SDIO_D0 + PC9 ------> SDIO_D1 + PC10 ------> SDIO_D2 + PC11 ------> SDIO_D3 + PC12 ------> SDIO_CK + PD2 ------> SDIO_CMD + */ + GPIO_InitStruct.Pin = uSD_D0_Pin|uSD_D1_Pin|uSD_D2_Pin|uSD_D3_Pin + |uSD_CLK_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = uSD_CMD_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; + HAL_GPIO_Init(uSD_CMD_GPIO_Port, &GPIO_InitStruct); + + /* USER CODE BEGIN SDIO_MspInit 1 */ + + /* USER CODE END SDIO_MspInit 1 */ + } + +} + +/** +* @brief SD MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param hsd: SD handle pointer +* @retval None +*/ +void HAL_SD_MspDeInit(SD_HandleTypeDef* hsd) +{ + if(hsd->Instance==SDIO) + { + /* USER CODE BEGIN SDIO_MspDeInit 0 */ + + /* USER CODE END SDIO_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SDIO_CLK_DISABLE(); + + /**SDIO GPIO Configuration + PC8 ------> SDIO_D0 + PC9 ------> SDIO_D1 + PC10 ------> SDIO_D2 + PC11 ------> SDIO_D3 + PC12 ------> SDIO_CK + PD2 ------> SDIO_CMD + */ + HAL_GPIO_DeInit(GPIOC, uSD_D0_Pin|uSD_D1_Pin|uSD_D2_Pin|uSD_D3_Pin + |uSD_CLK_Pin); + + HAL_GPIO_DeInit(uSD_CMD_GPIO_Port, uSD_CMD_Pin); + + /* USER CODE BEGIN SDIO_MspDeInit 1 */ + + /* USER CODE END SDIO_MspDeInit 1 */ + } + +} + +/** +* @brief UART MSP Initialization +* This function configures the hardware resources used in this example +* @param huart: UART handle pointer +* @retval None +*/ +void HAL_UART_MspInit(UART_HandleTypeDef* huart) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(huart->Instance==USART2) + { + /* USER CODE BEGIN USART2_MspInit 0 */ + + /* USER CODE END USART2_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_USART2_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**USART2 GPIO Configuration + PA2 ------> USART2_TX + PA3 ------> USART2_RX + */ + GPIO_InitStruct.Pin = STLINK_RX_Pin|STLINK_TX_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF7_USART2; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /* USER CODE BEGIN USART2_MspInit 1 */ + + /* USER CODE END USART2_MspInit 1 */ + } + +} + +/** +* @brief UART MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param huart: UART handle pointer +* @retval None +*/ +void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) +{ + if(huart->Instance==USART2) + { + /* USER CODE BEGIN USART2_MspDeInit 0 */ + + /* USER CODE END USART2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_USART2_CLK_DISABLE(); + + /**USART2 GPIO Configuration + PA2 ------> USART2_TX + PA3 ------> USART2_RX + */ + HAL_GPIO_DeInit(GPIOA, STLINK_RX_Pin|STLINK_TX_Pin); + + /* USER CODE BEGIN USART2_MspDeInit 1 */ + + /* USER CODE END USART2_MspDeInit 1 */ + } + +} + +static uint32_t FSMC_Initialized = 0; + +static void HAL_FSMC_MspInit(void){ + /* USER CODE BEGIN FSMC_MspInit 0 */ + + /* USER CODE END FSMC_MspInit 0 */ + GPIO_InitTypeDef GPIO_InitStruct ={0}; + if (FSMC_Initialized) { + return; + } + FSMC_Initialized = 1; + /* Peripheral clock enable */ + __HAL_RCC_FSMC_CLK_ENABLE(); + + /** FSMC GPIO Configuration + PF0 ------> FSMC_A0 + PE7 ------> FSMC_D4 + PE8 ------> FSMC_D5 + PE9 ------> FSMC_D6 + PE10 ------> FSMC_D7 + PE11 ------> FSMC_D8 + PE12 ------> FSMC_D9 + PE13 ------> FSMC_D10 + PE14 ------> FSMC_D11 + PE15 ------> FSMC_D12 + PD8 ------> FSMC_D13 + PD9 ------> FSMC_D14 + PD10 ------> FSMC_D15 + PD14 ------> FSMC_D0 + PD15 ------> FSMC_D1 + PD0 ------> FSMC_D2 + PD1 ------> FSMC_D3 + PD4 ------> FSMC_NOE + PD5 ------> FSMC_NWE + PD7 ------> FSMC_NE1 + */ + GPIO_InitStruct.Pin = A0_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; + HAL_GPIO_Init(A0_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = D4_Pin|D5_Pin|D6_Pin|D7_Pin + |D8_Pin|D9_Pin|D10_Pin|D11_Pin + |D12_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; + HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = D13_Pin|D14_Pin|D15_Pin|D0_Pin + |D1_Pin|D2_Pin|D3_Pin|FMC_NOE_Pin + |FMC_NWE_Pin|FMC_NE1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + /* USER CODE BEGIN FSMC_MspInit 1 */ + + /* USER CODE END FSMC_MspInit 1 */ +} + +void HAL_SRAM_MspInit(SRAM_HandleTypeDef* hsram){ + /* USER CODE BEGIN SRAM_MspInit 0 */ + + /* USER CODE END SRAM_MspInit 0 */ + HAL_FSMC_MspInit(); + /* USER CODE BEGIN SRAM_MspInit 1 */ + + /* USER CODE END SRAM_MspInit 1 */ +} + +static uint32_t FSMC_DeInitialized = 0; + +static void HAL_FSMC_MspDeInit(void){ + /* USER CODE BEGIN FSMC_MspDeInit 0 */ + + /* USER CODE END FSMC_MspDeInit 0 */ + if (FSMC_DeInitialized) { + return; + } + FSMC_DeInitialized = 1; + /* Peripheral clock enable */ + __HAL_RCC_FSMC_CLK_DISABLE(); + + /** FSMC GPIO Configuration + PF0 ------> FSMC_A0 + PE7 ------> FSMC_D4 + PE8 ------> FSMC_D5 + PE9 ------> FSMC_D6 + PE10 ------> FSMC_D7 + PE11 ------> FSMC_D8 + PE12 ------> FSMC_D9 + PE13 ------> FSMC_D10 + PE14 ------> FSMC_D11 + PE15 ------> FSMC_D12 + PD8 ------> FSMC_D13 + PD9 ------> FSMC_D14 + PD10 ------> FSMC_D15 + PD14 ------> FSMC_D0 + PD15 ------> FSMC_D1 + PD0 ------> FSMC_D2 + PD1 ------> FSMC_D3 + PD4 ------> FSMC_NOE + PD5 ------> FSMC_NWE + PD7 ------> FSMC_NE1 + */ + HAL_GPIO_DeInit(A0_GPIO_Port, A0_Pin); + + HAL_GPIO_DeInit(GPIOE, D4_Pin|D5_Pin|D6_Pin|D7_Pin + |D8_Pin|D9_Pin|D10_Pin|D11_Pin + |D12_Pin); + + HAL_GPIO_DeInit(GPIOD, D13_Pin|D14_Pin|D15_Pin|D0_Pin + |D1_Pin|D2_Pin|D3_Pin|FMC_NOE_Pin + |FMC_NWE_Pin|FMC_NE1_Pin); + + /* USER CODE BEGIN FSMC_MspDeInit 1 */ + + /* USER CODE END FSMC_MspDeInit 1 */ +} + +void HAL_SRAM_MspDeInit(SRAM_HandleTypeDef* hsram){ + /* USER CODE BEGIN SRAM_MspDeInit 0 */ + + /* USER CODE END SRAM_MspDeInit 0 */ + HAL_FSMC_MspDeInit(); + /* USER CODE BEGIN SRAM_MspDeInit 1 */ + + /* USER CODE END SRAM_MspDeInit 1 */ +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.c b/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.c new file mode 100644 index 000000000..032a55472 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.c @@ -0,0 +1,217 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32f4xx_it.c + * @brief Interrupt Service Routines. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +#include "stm32f4xx_it.h" +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN TD */ + +/* USER CODE END TD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +/* USER CODE BEGIN PV */ + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +/* USER CODE BEGIN PFP */ + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/* External variables --------------------------------------------------------*/ +extern PCD_HandleTypeDef hpcd_USB_OTG_FS; +/* USER CODE BEGIN EV */ + +/* USER CODE END EV */ + +/******************************************************************************/ +/* Cortex-M4 Processor Interruption and Exception Handlers */ +/******************************************************************************/ +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ + /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ + + /* USER CODE END NonMaskableInt_IRQn 0 */ + /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ + + /* USER CODE END NonMaskableInt_IRQn 1 */ +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + /* USER CODE BEGIN HardFault_IRQn 0 */ + + /* USER CODE END HardFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_HardFault_IRQn 0 */ + /* USER CODE END W1_HardFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Memory management fault. + */ +void MemManage_Handler(void) +{ + /* USER CODE BEGIN MemoryManagement_IRQn 0 */ + + /* USER CODE END MemoryManagement_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ + /* USER CODE END W1_MemoryManagement_IRQn 0 */ + } +} + +/** + * @brief This function handles Pre-fetch fault, memory access fault. + */ +void BusFault_Handler(void) +{ + /* USER CODE BEGIN BusFault_IRQn 0 */ + + /* USER CODE END BusFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_BusFault_IRQn 0 */ + /* USER CODE END W1_BusFault_IRQn 0 */ + } +} + +/** + * @brief This function handles Undefined instruction or illegal state. + */ +void UsageFault_Handler(void) +{ + /* USER CODE BEGIN UsageFault_IRQn 0 */ + + /* USER CODE END UsageFault_IRQn 0 */ + while (1) + { + /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ + /* USER CODE END W1_UsageFault_IRQn 0 */ + } +} + +/** + * @brief This function handles System service call via SWI instruction. + */ +void SVC_Handler(void) +{ + /* USER CODE BEGIN SVCall_IRQn 0 */ + + /* USER CODE END SVCall_IRQn 0 */ + /* USER CODE BEGIN SVCall_IRQn 1 */ + + /* USER CODE END SVCall_IRQn 1 */ +} + +/** + * @brief This function handles Debug monitor. + */ +void DebugMon_Handler(void) +{ + /* USER CODE BEGIN DebugMonitor_IRQn 0 */ + + /* USER CODE END DebugMonitor_IRQn 0 */ + /* USER CODE BEGIN DebugMonitor_IRQn 1 */ + + /* USER CODE END DebugMonitor_IRQn 1 */ +} + +/** + * @brief This function handles Pendable request for system service. + */ +void PendSV_Handler(void) +{ + /* USER CODE BEGIN PendSV_IRQn 0 */ + + /* USER CODE END PendSV_IRQn 0 */ + /* USER CODE BEGIN PendSV_IRQn 1 */ + + /* USER CODE END PendSV_IRQn 1 */ +} + +// /** +// * @brief This function handles System tick timer. +// */ +// void SysTick_Handler(void) +// { +// /* USER CODE BEGIN SysTick_IRQn 0 */ + +// /* USER CODE END SysTick_IRQn 0 */ +// HAL_IncTick(); +// /* USER CODE BEGIN SysTick_IRQn 1 */ + +// /* USER CODE END SysTick_IRQn 1 */ +// } + +/******************************************************************************/ +/* STM32F4xx Peripheral Interrupt Handlers */ +/* Add here the Interrupt Handlers for the used peripherals. */ +/* For the available peripheral interrupt handler names, */ +/* please refer to the startup file (startup_stm32f4xx.s). */ +/******************************************************************************/ + +/** + * @brief This function handles USB On The Go FS global interrupt. + */ +// void OTG_FS_IRQHandler(void) +// { +// /* USER CODE BEGIN OTG_FS_IRQn 0 */ + +// /* USER CODE END OTG_FS_IRQn 0 */ +// // HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); +// /* USER CODE BEGIN OTG_FS_IRQn 1 */ + +// /* USER CODE END OTG_FS_IRQn 1 */ +// } + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.h b/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.h new file mode 100644 index 000000000..4571df2e3 --- /dev/null +++ b/ports/stm32f4/boards/DIS_F412ZG/stm32f4xx_it.h @@ -0,0 +1,70 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32f4xx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_IT_H +#define __STM32F4xx_IT_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +//void SysTick_Handler(void); +//void OTG_FS_IRQHandler(void); +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_IT_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/stm32f411_disco/board.c b/ports/stm32f4/boards/stm32f411_disco/board.c deleted file mode 100644 index 4421970ee..000000000 --- a/ports/stm32f4/boards/stm32f411_disco/board.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * - * 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 "boards/board.h" - -void board_init(void) { -} - -bool board_requests_safe_mode(void) { - return false; -} - -void reset_board(void) { - -} diff --git a/ports/stm32f4/boards/stm32f411_disco/mpconfigboard.h b/ports/stm32f4/boards/stm32f411_disco/mpconfigboard.h deleted file mode 100644 index 675443282..000000000 --- a/ports/stm32f4/boards/stm32f411_disco/mpconfigboard.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Glenn Ruben Bakke - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * - * 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. - */ - -//Micropython setup - -#define MICROPY_HW_BOARD_NAME "STM32F411E_DISCO" -#define MICROPY_HW_MCU_NAME "STM32F411xE" - -#define FLASH_SIZE (0x7D000) -#define FLASH_PAGE_SIZE (0x4000) - -#define CIRCUITPY_INTERNAL_NVM_SIZE (4096) -#define AUTORESET_DELAY_MS 500 -#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) \ No newline at end of file diff --git a/ports/stm32f4/boards/stm32f411_disco/mpconfigboard.mk b/ports/stm32f4/boards/stm32f411_disco/mpconfigboard.mk deleted file mode 100644 index 523628504..000000000 --- a/ports/stm32f4/boards/stm32f411_disco/mpconfigboard.mk +++ /dev/null @@ -1,13 +0,0 @@ -USB_VID = 0x239A -USB_PID = 0x802A -USB_PRODUCT = "A glorious potato" -USB_MANUFACTURER = "Adafruit Industries LLC" - -MCU_SERIES = m4 -MCU_VARIANT = stm32f4 -MCU_SUB_VARIANT = stm32f411xe -CMSIS_MCU = STM32F411xE -LD_FILE = boards/STM32F411VETx_FLASH.ld -TEXT0_ADDR = 0x08000000 -TEXT1_ADDR = 0x08020000 - diff --git a/ports/stm32f4/boards/stm32f411_disco/pins.c b/ports/stm32f4/boards/stm32f411_disco/pins.c deleted file mode 100644 index e3a4b5ed6..000000000 --- a/ports/stm32f4/boards/stm32f411_disco/pins.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "shared-bindings/board/__init__.h" - -STATIC const mp_rom_map_elem_t board_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR_PE02), MP_ROM_PTR(&pin_PE02) }, - { MP_ROM_QSTR(MP_QSTR_PE03), MP_ROM_PTR(&pin_PE03) }, - { MP_ROM_QSTR(MP_QSTR_PE04), MP_ROM_PTR(&pin_PE04) }, - { MP_ROM_QSTR(MP_QSTR_PE05), MP_ROM_PTR(&pin_PE05) }, - { MP_ROM_QSTR(MP_QSTR_PE06), MP_ROM_PTR(&pin_PE06) }, - { MP_ROM_QSTR(MP_QSTR_PC13), MP_ROM_PTR(&pin_PC13) }, - { MP_ROM_QSTR(MP_QSTR_PF02), MP_ROM_PTR(&pin_PF02) }, - { MP_ROM_QSTR(MP_QSTR_PF03), MP_ROM_PTR(&pin_PF03) }, - { MP_ROM_QSTR(MP_QSTR_PF10), MP_ROM_PTR(&pin_PF10) }, - { MP_ROM_QSTR(MP_QSTR_PC00), MP_ROM_PTR(&pin_PC00) }, - { MP_ROM_QSTR(MP_QSTR_PC01), MP_ROM_PTR(&pin_PC01) }, - { MP_ROM_QSTR(MP_QSTR_PC02), MP_ROM_PTR(&pin_PC02) }, - { MP_ROM_QSTR(MP_QSTR_PC03), MP_ROM_PTR(&pin_PC03) }, - { MP_ROM_QSTR(MP_QSTR_PA01), MP_ROM_PTR(&pin_PA01) }, - { MP_ROM_QSTR(MP_QSTR_PA02), MP_ROM_PTR(&pin_PA02) }, - { MP_ROM_QSTR(MP_QSTR_PA03), MP_ROM_PTR(&pin_PA03) }, - { MP_ROM_QSTR(MP_QSTR_PA04), MP_ROM_PTR(&pin_PA04) }, - { MP_ROM_QSTR(MP_QSTR_PA05), MP_ROM_PTR(&pin_PA05) }, - { MP_ROM_QSTR(MP_QSTR_PA06), MP_ROM_PTR(&pin_PA06) }, - { MP_ROM_QSTR(MP_QSTR_PA07), MP_ROM_PTR(&pin_PA07) }, - { MP_ROM_QSTR(MP_QSTR_PC04), MP_ROM_PTR(&pin_PC04) }, - { MP_ROM_QSTR(MP_QSTR_PC05), MP_ROM_PTR(&pin_PC05) }, - { MP_ROM_QSTR(MP_QSTR_PB00), MP_ROM_PTR(&pin_PB00) }, - { MP_ROM_QSTR(MP_QSTR_PB01), MP_ROM_PTR(&pin_PB01) }, - { MP_ROM_QSTR(MP_QSTR_PF11), MP_ROM_PTR(&pin_PF11) }, - { MP_ROM_QSTR(MP_QSTR_PF13), MP_ROM_PTR(&pin_PF13) }, - { MP_ROM_QSTR(MP_QSTR_PB10), MP_ROM_PTR(&pin_PB10) }, - { MP_ROM_QSTR(MP_QSTR_PB11), MP_ROM_PTR(&pin_PB11) }, - { MP_ROM_QSTR(MP_QSTR_PB12), MP_ROM_PTR(&pin_PB12) }, - { MP_ROM_QSTR(MP_QSTR_PB13), MP_ROM_PTR(&pin_PB13) }, - { MP_ROM_QSTR(MP_QSTR_PB14), MP_ROM_PTR(&pin_PB14) }, - { MP_ROM_QSTR(MP_QSTR_PB15), MP_ROM_PTR(&pin_PB15) }, - { MP_ROM_QSTR(MP_QSTR_PD12), MP_ROM_PTR(&pin_PD12) }, - { MP_ROM_QSTR(MP_QSTR_PD13), MP_ROM_PTR(&pin_PD13) }, - { MP_ROM_QSTR(MP_QSTR_PG02), MP_ROM_PTR(&pin_PG02) }, - { MP_ROM_QSTR(MP_QSTR_PC06), MP_ROM_PTR(&pin_PC06) }, - { MP_ROM_QSTR(MP_QSTR_PC07), MP_ROM_PTR(&pin_PC07) }, - { MP_ROM_QSTR(MP_QSTR_PC09), MP_ROM_PTR(&pin_PC09) }, - { MP_ROM_QSTR(MP_QSTR_PA08), MP_ROM_PTR(&pin_PA08) }, - { MP_ROM_QSTR(MP_QSTR_PA10), MP_ROM_PTR(&pin_PA10) }, - { MP_ROM_QSTR(MP_QSTR_PA13), MP_ROM_PTR(&pin_PA13) }, - { MP_ROM_QSTR(MP_QSTR_PA14), MP_ROM_PTR(&pin_PA14) }, - { MP_ROM_QSTR(MP_QSTR_PA15), MP_ROM_PTR(&pin_PA15) }, - { MP_ROM_QSTR(MP_QSTR_PD06), MP_ROM_PTR(&pin_PD06) }, - { MP_ROM_QSTR(MP_QSTR_PG09), MP_ROM_PTR(&pin_PG09) }, - { MP_ROM_QSTR(MP_QSTR_PG10), MP_ROM_PTR(&pin_PG10) }, - { MP_ROM_QSTR(MP_QSTR_PG11), MP_ROM_PTR(&pin_PG11) }, - { MP_ROM_QSTR(MP_QSTR_PG12), MP_ROM_PTR(&pin_PG12) }, - { MP_ROM_QSTR(MP_QSTR_PG13), MP_ROM_PTR(&pin_PG13) }, - { MP_ROM_QSTR(MP_QSTR_PG14), MP_ROM_PTR(&pin_PG14) }, - { MP_ROM_QSTR(MP_QSTR_PB03), MP_ROM_PTR(&pin_PB03) }, - { MP_ROM_QSTR(MP_QSTR_PB04), MP_ROM_PTR(&pin_PB04) }, - { MP_ROM_QSTR(MP_QSTR_PB05), MP_ROM_PTR(&pin_PB05) }, - { MP_ROM_QSTR(MP_QSTR_PB06), MP_ROM_PTR(&pin_PB06) }, - { MP_ROM_QSTR(MP_QSTR_PB07), MP_ROM_PTR(&pin_PB07) }, - { MP_ROM_QSTR(MP_QSTR_PB08), MP_ROM_PTR(&pin_PB08) }, - { MP_ROM_QSTR(MP_QSTR_PB09), MP_ROM_PTR(&pin_PB09) }, - { MP_ROM_QSTR(MP_QSTR_PE00), MP_ROM_PTR(&pin_PE00) }, - { MP_ROM_QSTR(MP_QSTR_PE01), MP_ROM_PTR(&pin_PE01) }, - { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_PB10) }, - { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_PB09) }, - { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA05) }, - { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA06) }, - { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA07) }, - { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA15) }, - { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PB08) }, - { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PG10) }, - { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PG11) }, - { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PF03) }, - { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PF10) }, - { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PG12) }, - { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PF04) }, - { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PG13) }, - { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PG14) }, - { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PG09) }, - { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA01) }, - { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PC01) }, - { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PC03) }, - { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PC04) }, - { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PC05) }, //alt PB09, see F401ZG-DISCO manual - { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB00) }, //alt PB10, see F401ZG-DISCO manual - { MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_PE00) }, - { MP_ROM_QSTR(MP_QSTR_LED2), MP_ROM_PTR(&pin_PE01) }, - { MP_ROM_QSTR(MP_QSTR_LED3), MP_ROM_PTR(&pin_PE02) }, - { MP_ROM_QSTR(MP_QSTR_LED4), MP_ROM_PTR(&pin_PE03) }, -}; -MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_hal_conf.h b/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_hal_conf.h deleted file mode 100644 index 4b6ba3d03..000000000 --- a/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_hal_conf.h +++ /dev/null @@ -1,439 +0,0 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf_template.h - * @author MCD Application Team - * @brief HAL configuration template file. - * This file should be copied to the application folder and renamed - * to stm32f4xx_hal_conf.h. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under BSD 3-Clause license, - * the "License"; You may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * opensource.org/licenses/BSD-3-Clause - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ - -/* ########################## Module Selection ############################## */ -/** - * @brief This is the list of modules to be used in the HAL driver - */ -#define HAL_MODULE_ENABLED - - /* #define HAL_ADC_MODULE_ENABLED */ -/* #define HAL_CRYP_MODULE_ENABLED */ -/* #define HAL_CAN_MODULE_ENABLED */ -/* #define HAL_CRC_MODULE_ENABLED */ -/* #define HAL_CRYP_MODULE_ENABLED */ -/* #define HAL_DAC_MODULE_ENABLED */ -/* #define HAL_DCMI_MODULE_ENABLED */ -/* #define HAL_DMA2D_MODULE_ENABLED */ -/* #define HAL_ETH_MODULE_ENABLED */ -/* #define HAL_NAND_MODULE_ENABLED */ -/* #define HAL_NOR_MODULE_ENABLED */ -/* #define HAL_PCCARD_MODULE_ENABLED */ -/* #define HAL_SRAM_MODULE_ENABLED */ -/* #define HAL_SDRAM_MODULE_ENABLED */ -/* #define HAL_HASH_MODULE_ENABLED */ -#define HAL_I2C_MODULE_ENABLED -#define HAL_I2S_MODULE_ENABLED -/* #define HAL_IWDG_MODULE_ENABLED */ -/* #define HAL_LTDC_MODULE_ENABLED */ -/* #define HAL_RNG_MODULE_ENABLED */ -/* #define HAL_RTC_MODULE_ENABLED */ -/* #define HAL_SAI_MODULE_ENABLED */ -/* #define HAL_SD_MODULE_ENABLED */ -/* #define HAL_MMC_MODULE_ENABLED */ -#define HAL_SPI_MODULE_ENABLED -/* #define HAL_TIM_MODULE_ENABLED */ -/* #define HAL_UART_MODULE_ENABLED */ -/* #define HAL_USART_MODULE_ENABLED */ -/* #define HAL_IRDA_MODULE_ENABLED */ -/* #define HAL_SMARTCARD_MODULE_ENABLED */ -/* #define HAL_WWDG_MODULE_ENABLED */ -#define HAL_PCD_MODULE_ENABLED -/* #define HAL_HCD_MODULE_ENABLED */ -/* #define HAL_DSI_MODULE_ENABLED */ -/* #define HAL_QSPI_MODULE_ENABLED */ -/* #define HAL_QSPI_MODULE_ENABLED */ -/* #define HAL_CEC_MODULE_ENABLED */ -/* #define HAL_FMPI2C_MODULE_ENABLED */ -/* #define HAL_SPDIFRX_MODULE_ENABLED */ -/* #define HAL_DFSDM_MODULE_ENABLED */ -/* #define HAL_LPTIM_MODULE_ENABLED */ -/* #define HAL_EXTI_MODULE_ENABLED */ -#define HAL_GPIO_MODULE_ENABLED -#define HAL_EXTI_MODULE_ENABLED -#define HAL_DMA_MODULE_ENABLED -#define HAL_RCC_MODULE_ENABLED -#define HAL_FLASH_MODULE_ENABLED -#define HAL_PWR_MODULE_ENABLED -#define HAL_CORTEX_MODULE_ENABLED - -/* ########################## HSE/HSI Values adaptation ##################### */ -/** - * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. - * This value is used by the RCC HAL module to compute the system frequency - * (when HSE is used as system clock source, directly or through the PLL). - */ -#if !defined (HSE_VALUE) - #define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSE_STARTUP_TIMEOUT) - #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ -#endif /* HSE_STARTUP_TIMEOUT */ - -/** - * @brief Internal High Speed oscillator (HSI) value. - * This value is used by the RCC HAL module to compute the system frequency - * (when HSI is used as system clock source, directly or through the PLL). - */ -#if !defined (HSI_VALUE) - #define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/ -#endif /* HSI_VALUE */ - -/** - * @brief Internal Low Speed oscillator (LSI) value. - */ -#if !defined (LSI_VALUE) - #define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/ -#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz - The real value may vary depending on the variations - in voltage and temperature.*/ -/** - * @brief External Low Speed oscillator (LSE) value. - */ -#if !defined (LSE_VALUE) - #define LSE_VALUE ((uint32_t)32768U) /*!< Value of the External Low Speed oscillator in Hz */ -#endif /* LSE_VALUE */ - -#if !defined (LSE_STARTUP_TIMEOUT) - #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ -#endif /* LSE_STARTUP_TIMEOUT */ - -/** - * @brief External clock source for I2S peripheral - * This value is used by the I2S HAL module to compute the I2S clock source - * frequency, this source is inserted directly through I2S_CKIN pad. - */ -#if !defined (EXTERNAL_CLOCK_VALUE) - #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000U) /*!< Value of the External audio frequency in Hz*/ -#endif /* EXTERNAL_CLOCK_VALUE */ - -/* Tip: To avoid modifying this file each time you need to use different HSE, - === you can define the HSE value in your toolchain compiler preprocessor. */ - -/* ########################### System Configuration ######################### */ -/** - * @brief This is the HAL system configuration section - */ -#define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */ -#define TICK_INT_PRIORITY ((uint32_t)0U) /*!< tick interrupt priority */ -#define USE_RTOS 0U -#define PREFETCH_ENABLE 1U -#define INSTRUCTION_CACHE_ENABLE 1U -#define DATA_CACHE_ENABLE 1U - -/* ########################## Assert Selection ############################## */ -/** - * @brief Uncomment the line below to expanse the "assert_param" macro in the - * HAL drivers code - */ -/* #define USE_FULL_ASSERT 1U */ - -/* ################## Ethernet peripheral configuration ##################### */ - -/* Section 1 : Ethernet peripheral configuration */ - -/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ -#define MAC_ADDR0 2U -#define MAC_ADDR1 0U -#define MAC_ADDR2 0U -#define MAC_ADDR3 0U -#define MAC_ADDR4 0U -#define MAC_ADDR5 0U - -/* Definition of the Ethernet driver buffers size and count */ -#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ -#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ -#define ETH_RXBUFNB ((uint32_t)4U) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4U) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848_PHY_ADDRESS Address*/ -#define DP83848_PHY_ADDRESS 0x01U -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FFU) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFU) - -#define PHY_READ_TO ((uint32_t)0x0000FFFFU) -#define PHY_WRITE_TO ((uint32_t)0x0000FFFFU) - -/* Section 3: Common PHY Registers */ - -#define PHY_BCR ((uint16_t)0x0000U) /*!< Transceiver Basic Control Register */ -#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */ - -#define PHY_RESET ((uint16_t)0x8000U) /*!< PHY Reset */ -#define PHY_LOOPBACK ((uint16_t)0x4000U) /*!< Select loop-back mode */ -#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100U) /*!< Set the full-duplex mode at 100 Mb/s */ -#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000U) /*!< Set the half-duplex mode at 100 Mb/s */ -#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100U) /*!< Set the full-duplex mode at 10 Mb/s */ -#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000U) /*!< Set the half-duplex mode at 10 Mb/s */ -#define PHY_AUTONEGOTIATION ((uint16_t)0x1000U) /*!< Enable auto-negotiation function */ -#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200U) /*!< Restart auto-negotiation function */ -#define PHY_POWERDOWN ((uint16_t)0x0800U) /*!< Select the power down mode */ -#define PHY_ISOLATE ((uint16_t)0x0400U) /*!< Isolate PHY from MII */ - -#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020U) /*!< Auto-Negotiation process completed */ -#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */ -#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */ - -/* Section 4: Extended PHY Registers */ -#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */ - -#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */ -#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */ - -/* ################## SPI peripheral configuration ########################## */ - -/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver -* Activated: CRC code is present inside driver -* Deactivated: CRC code cleaned from driver -*/ - -#define USE_SPI_CRC 0U - -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ - -#ifdef HAL_RCC_MODULE_ENABLED - #include "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_EXTI_MODULE_ENABLED - #include "stm32f4xx_hal_exti.h" -#endif /* HAL_EXTI_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_MMC_MODULE_ENABLED - #include "stm32f4xx_hal_mmc.h" -#endif /* HAL_MMC_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_hal_hcd.h" -#endif /* HAL_HCD_MODULE_ENABLED */ - -#ifdef HAL_DSI_MODULE_ENABLED - #include "stm32f4xx_hal_dsi.h" -#endif /* HAL_DSI_MODULE_ENABLED */ - -#ifdef HAL_QSPI_MODULE_ENABLED - #include "stm32f4xx_hal_qspi.h" -#endif /* HAL_QSPI_MODULE_ENABLED */ - -#ifdef HAL_CEC_MODULE_ENABLED - #include "stm32f4xx_hal_cec.h" -#endif /* HAL_CEC_MODULE_ENABLED */ - -#ifdef HAL_FMPI2C_MODULE_ENABLED - #include "stm32f4xx_hal_fmpi2c.h" -#endif /* HAL_FMPI2C_MODULE_ENABLED */ - -#ifdef HAL_SPDIFRX_MODULE_ENABLED - #include "stm32f4xx_hal_spdifrx.h" -#endif /* HAL_SPDIFRX_MODULE_ENABLED */ - -#ifdef HAL_DFSDM_MODULE_ENABLED - #include "stm32f4xx_hal_dfsdm.h" -#endif /* HAL_DFSDM_MODULE_ENABLED */ - -#ifdef HAL_LPTIM_MODULE_ENABLED - #include "stm32f4xx_hal_lptim.h" -#endif /* HAL_LPTIM_MODULE_ENABLED */ - -/* Exported macro ------------------------------------------------------------*/ -#ifdef USE_FULL_ASSERT -/** - * @brief The assert_param macro is used for function's parameters check. - * @param expr: If expr is false, it calls assert_failed function - * which reports the name of the source file and the source - * line number of the call that failed. - * If expr is true, it returns no value. - * @retval None - */ - #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) -/* Exported functions ------------------------------------------------------- */ - void assert_failed(uint8_t* file, uint32_t line); -#else - #define assert_param(expr) ((void)0U) -#endif /* USE_FULL_ASSERT */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_hal_msp.c b/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_hal_msp.c deleted file mode 100644 index 4989f9889..000000000 --- a/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_hal_msp.c +++ /dev/null @@ -1,427 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * File Name : stm32f4xx_hal_msp.c - * Description : This file provides code for the MSP Initialization - * and de-Initialization codes. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Includes ------------------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -#include "stm32f4xx_hal.h" -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN TD */ - -/* USER CODE END TD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN Define */ -#define DATA_Ready_Pin GPIO_PIN_2 -#define DATA_Ready_GPIO_Port GPIOE -#define CS_I2C_SPI_Pin GPIO_PIN_3 -#define CS_I2C_SPI_GPIO_Port GPIOE -#define INT1_Pin GPIO_PIN_4 -#define INT1_GPIO_Port GPIOE -#define INT2_Pin GPIO_PIN_5 -#define INT2_GPIO_Port GPIOE -#define PC14_OSC32_IN_Pin GPIO_PIN_14 -#define PC14_OSC32_IN_GPIO_Port GPIOC -#define PC15_OSC32_OUT_Pin GPIO_PIN_15 -#define PC15_OSC32_OUT_GPIO_Port GPIOC -#define PH0_OSC_IN_Pin GPIO_PIN_0 -#define PH0_OSC_IN_GPIO_Port GPIOH -#define PH1_OSC_OUT_Pin GPIO_PIN_1 -#define PH1_OSC_OUT_GPIO_Port GPIOH -#define OTG_FS_PowerSwitchOn_Pin GPIO_PIN_0 -#define OTG_FS_PowerSwitchOn_GPIO_Port GPIOC -#define PDM_OUT_Pin GPIO_PIN_3 -#define PDM_OUT_GPIO_Port GPIOC -#define I2S3_WS_Pin GPIO_PIN_4 -#define I2S3_WS_GPIO_Port GPIOA -#define SPI1_SCK_Pin GPIO_PIN_5 -#define SPI1_SCK_GPIO_Port GPIOA -#define SPI1_MISO_Pin GPIO_PIN_6 -#define SPI1_MISO_GPIO_Port GPIOA -#define SPI1_MOSI_Pin GPIO_PIN_7 -#define SPI1_MOSI_GPIO_Port GPIOA -#define CLK_IN_Pin GPIO_PIN_10 -#define CLK_IN_GPIO_Port GPIOB -#define LD4_Pin GPIO_PIN_12 -#define LD4_GPIO_Port GPIOD -#define LD3_Pin GPIO_PIN_13 -#define LD3_GPIO_Port GPIOD -#define LD5_Pin GPIO_PIN_14 -#define LD5_GPIO_Port GPIOD -#define LD6_Pin GPIO_PIN_15 -#define LD6_GPIO_Port GPIOD -#define I2S3_MCK_Pin GPIO_PIN_7 -#define I2S3_MCK_GPIO_Port GPIOC -#define VBUS_FS_Pin GPIO_PIN_9 -#define VBUS_FS_GPIO_Port GPIOA -#define OTG_FS_ID_Pin GPIO_PIN_10 -#define OTG_FS_ID_GPIO_Port GPIOA -#define OTG_FS_DM_Pin GPIO_PIN_11 -#define OTG_FS_DM_GPIO_Port GPIOA -#define OTG_FS_DP_Pin GPIO_PIN_12 -#define OTG_FS_DP_GPIO_Port GPIOA -#define SWDIO_Pin GPIO_PIN_13 -#define SWDIO_GPIO_Port GPIOA -#define SWCLK_Pin GPIO_PIN_14 -#define SWCLK_GPIO_Port GPIOA -#define I2S3_SCK_Pin GPIO_PIN_10 -#define I2S3_SCK_GPIO_Port GPIOC -#define I2S3_SD_Pin GPIO_PIN_12 -#define I2S3_SD_GPIO_Port GPIOC -#define Audio_RST_Pin GPIO_PIN_4 -#define Audio_RST_GPIO_Port GPIOD -#define OTG_FS_OverCurrent_Pin GPIO_PIN_5 -#define OTG_FS_OverCurrent_GPIO_Port GPIOD -#define SWO_Pin GPIO_PIN_3 -#define SWO_GPIO_Port GPIOB -#define Audio_SCL_Pin GPIO_PIN_6 -#define Audio_SCL_GPIO_Port GPIOB -#define Audio_SDA_Pin GPIO_PIN_9 -#define Audio_SDA_GPIO_Port GPIOB -#define MEMS_INT2_Pin GPIO_PIN_1 -#define MEMS_INT2_GPIO_Port GPIOE - -/* USER CODE END Define */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN Macro */ - -/* USER CODE END Macro */ - -/* Private variables ---------------------------------------------------------*/ -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* External functions --------------------------------------------------------*/ -/* USER CODE BEGIN ExternalFunctions */ - -/* USER CODE END ExternalFunctions */ - -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ -/** - * Initializes the Global MSP. - */ -void HAL_MspInit(void) -{ - /* USER CODE BEGIN MspInit 0 */ - - /* USER CODE END MspInit 0 */ - - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0); - - /* System interrupt init*/ - - /* USER CODE BEGIN MspInit 1 */ - - /* USER CODE END MspInit 1 */ -} - -/** -* @brief I2C MSP Initialization -* This function configures the hardware resources used in this example -* @param hi2c: I2C handle pointer -* @retval None -*/ -void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(hi2c->Instance==I2C1) - { - /* USER CODE BEGIN I2C1_MspInit 0 */ - - /* USER CODE END I2C1_MspInit 0 */ - - __HAL_RCC_GPIOB_CLK_ENABLE(); - /**I2C1 GPIO Configuration - PB6 ------> I2C1_SCL - PB9 ------> I2C1_SDA - */ - GPIO_InitStruct.Pin = Audio_SCL_Pin|Audio_SDA_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - /* Peripheral clock enable */ - __HAL_RCC_I2C1_CLK_ENABLE(); - /* USER CODE BEGIN I2C1_MspInit 1 */ - - /* USER CODE END I2C1_MspInit 1 */ - } - -} - -/** -* @brief I2C MSP De-Initialization -* This function freeze the hardware resources used in this example -* @param hi2c: I2C handle pointer -* @retval None -*/ -void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c) -{ - if(hi2c->Instance==I2C1) - { - /* USER CODE BEGIN I2C1_MspDeInit 0 */ - - /* USER CODE END I2C1_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_I2C1_CLK_DISABLE(); - - /**I2C1 GPIO Configuration - PB6 ------> I2C1_SCL - PB9 ------> I2C1_SDA - */ - HAL_GPIO_DeInit(GPIOB, Audio_SCL_Pin|Audio_SDA_Pin); - - /* USER CODE BEGIN I2C1_MspDeInit 1 */ - - /* USER CODE END I2C1_MspDeInit 1 */ - } - -} - -/** -* @brief I2S MSP Initialization -* This function configures the hardware resources used in this example -* @param hi2s: I2S handle pointer -* @retval None -*/ -void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(hi2s->Instance==SPI2) - { - /* USER CODE BEGIN SPI2_MspInit 0 */ - - /* USER CODE END SPI2_MspInit 0 */ - /* Peripheral clock enable */ - __HAL_RCC_SPI2_CLK_ENABLE(); - - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - /**I2S2 GPIO Configuration - PC2 ------> I2S2_ext_SD - PC3 ------> I2S2_SD - PB10 ------> I2S2_CK - PB12 ------> I2S2_WS - */ - GPIO_InitStruct.Pin = GPIO_PIN_2; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = PDM_OUT_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; - HAL_GPIO_Init(PDM_OUT_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = CLK_IN_Pin|GPIO_PIN_12; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - /* USER CODE BEGIN SPI2_MspInit 1 */ - - /* USER CODE END SPI2_MspInit 1 */ - } - else if(hi2s->Instance==SPI3) - { - /* USER CODE BEGIN SPI3_MspInit 0 */ - - /* USER CODE END SPI3_MspInit 0 */ - /* Peripheral clock enable */ - __HAL_RCC_SPI3_CLK_ENABLE(); - - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - /**I2S3 GPIO Configuration - PA4 ------> I2S3_WS - PC7 ------> I2S3_MCK - PC10 ------> I2S3_CK - PC12 ------> I2S3_SD - */ - GPIO_InitStruct.Pin = I2S3_WS_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; - HAL_GPIO_Init(I2S3_WS_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = I2S3_MCK_Pin|I2S3_SCK_Pin|I2S3_SD_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - /* USER CODE BEGIN SPI3_MspInit 1 */ - - /* USER CODE END SPI3_MspInit 1 */ - } - -} - -/** -* @brief I2S MSP De-Initialization -* This function freeze the hardware resources used in this example -* @param hi2s: I2S handle pointer -* @retval None -*/ -void HAL_I2S_MspDeInit(I2S_HandleTypeDef* hi2s) -{ - if(hi2s->Instance==SPI2) - { - /* USER CODE BEGIN SPI2_MspDeInit 0 */ - - /* USER CODE END SPI2_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_SPI2_CLK_DISABLE(); - - /**I2S2 GPIO Configuration - PC2 ------> I2S2_ext_SD - PC3 ------> I2S2_SD - PB10 ------> I2S2_CK - PB12 ------> I2S2_WS - */ - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2|PDM_OUT_Pin); - - HAL_GPIO_DeInit(GPIOB, CLK_IN_Pin|GPIO_PIN_12); - - /* USER CODE BEGIN SPI2_MspDeInit 1 */ - - /* USER CODE END SPI2_MspDeInit 1 */ - } - else if(hi2s->Instance==SPI3) - { - /* USER CODE BEGIN SPI3_MspDeInit 0 */ - - /* USER CODE END SPI3_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_SPI3_CLK_DISABLE(); - - /**I2S3 GPIO Configuration - PA4 ------> I2S3_WS - PC7 ------> I2S3_MCK - PC10 ------> I2S3_CK - PC12 ------> I2S3_SD - */ - HAL_GPIO_DeInit(I2S3_WS_GPIO_Port, I2S3_WS_Pin); - - HAL_GPIO_DeInit(GPIOC, I2S3_MCK_Pin|I2S3_SCK_Pin|I2S3_SD_Pin); - - /* USER CODE BEGIN SPI3_MspDeInit 1 */ - - /* USER CODE END SPI3_MspDeInit 1 */ - } - -} - -/** -* @brief SPI MSP Initialization -* This function configures the hardware resources used in this example -* @param hspi: SPI handle pointer -* @retval None -*/ -void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(hspi->Instance==SPI1) - { - /* USER CODE BEGIN SPI1_MspInit 0 */ - - /* USER CODE END SPI1_MspInit 0 */ - /* Peripheral clock enable */ - __HAL_RCC_SPI1_CLK_ENABLE(); - - __HAL_RCC_GPIOA_CLK_ENABLE(); - /**SPI1 GPIO Configuration - PA5 ------> SPI1_SCK - PA6 ------> SPI1_MISO - PA7 ------> SPI1_MOSI - */ - GPIO_InitStruct.Pin = SPI1_SCK_Pin|SPI1_MISO_Pin|SPI1_MOSI_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - /* USER CODE BEGIN SPI1_MspInit 1 */ - - /* USER CODE END SPI1_MspInit 1 */ - } - -} - -/** -* @brief SPI MSP De-Initialization -* This function freeze the hardware resources used in this example -* @param hspi: SPI handle pointer -* @retval None -*/ -void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi) -{ - if(hspi->Instance==SPI1) - { - /* USER CODE BEGIN SPI1_MspDeInit 0 */ - - /* USER CODE END SPI1_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_SPI1_CLK_DISABLE(); - - /**SPI1 GPIO Configuration - PA5 ------> SPI1_SCK - PA6 ------> SPI1_MISO - PA7 ------> SPI1_MOSI - */ - HAL_GPIO_DeInit(GPIOA, SPI1_SCK_Pin|SPI1_MISO_Pin|SPI1_MOSI_Pin); - - /* USER CODE BEGIN SPI1_MspDeInit 1 */ - - /* USER CODE END SPI1_MspDeInit 1 */ - } - -} - -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_it.c b/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_it.c deleted file mode 100644 index cb86910e2..000000000 --- a/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_it.c +++ /dev/null @@ -1,217 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32f4xx_it.c - * @brief Interrupt Service Routines. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Includes ------------------------------------------------------------------*/ -#include "main.h" -#include "stm32f4xx_it.h" -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN TD */ - -/* USER CODE END TD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN PD */ - -/* USER CODE END PD */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN PM */ - -/* USER CODE END PM */ - -/* Private variables ---------------------------------------------------------*/ -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* Private user code ---------------------------------------------------------*/ -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -/* External variables --------------------------------------------------------*/ -extern PCD_HandleTypeDef hpcd_USB_OTG_FS; -/* USER CODE BEGIN EV */ - -/* USER CODE END EV */ - -/******************************************************************************/ -/* Cortex-M4 Processor Interruption and Exception Handlers */ -/******************************************************************************/ -/** - * @brief This function handles Non maskable interrupt. - */ -void NMI_Handler(void) -{ - /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ - - /* USER CODE END NonMaskableInt_IRQn 0 */ - /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ - - /* USER CODE END NonMaskableInt_IRQn 1 */ -} - -/** - * @brief This function handles Hard fault interrupt. - */ -void HardFault_Handler(void) -{ - /* USER CODE BEGIN HardFault_IRQn 0 */ - - /* USER CODE END HardFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_HardFault_IRQn 0 */ - /* USER CODE END W1_HardFault_IRQn 0 */ - } -} - -/** - * @brief This function handles Memory management fault. - */ -void MemManage_Handler(void) -{ - /* USER CODE BEGIN MemoryManagement_IRQn 0 */ - - /* USER CODE END MemoryManagement_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ - /* USER CODE END W1_MemoryManagement_IRQn 0 */ - } -} - -/** - * @brief This function handles Pre-fetch fault, memory access fault. - */ -void BusFault_Handler(void) -{ - /* USER CODE BEGIN BusFault_IRQn 0 */ - - /* USER CODE END BusFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_BusFault_IRQn 0 */ - /* USER CODE END W1_BusFault_IRQn 0 */ - } -} - -/** - * @brief This function handles Undefined instruction or illegal state. - */ -void UsageFault_Handler(void) -{ - /* USER CODE BEGIN UsageFault_IRQn 0 */ - - /* USER CODE END UsageFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ - /* USER CODE END W1_UsageFault_IRQn 0 */ - } -} - -/** - * @brief This function handles System service call via SWI instruction. - */ -void SVC_Handler(void) -{ - /* USER CODE BEGIN SVCall_IRQn 0 */ - - /* USER CODE END SVCall_IRQn 0 */ - /* USER CODE BEGIN SVCall_IRQn 1 */ - - /* USER CODE END SVCall_IRQn 1 */ -} - -/** - * @brief This function handles Debug monitor. - */ -void DebugMon_Handler(void) -{ - /* USER CODE BEGIN DebugMonitor_IRQn 0 */ - - /* USER CODE END DebugMonitor_IRQn 0 */ - /* USER CODE BEGIN DebugMonitor_IRQn 1 */ - - /* USER CODE END DebugMonitor_IRQn 1 */ -} - -/** - * @brief This function handles Pendable request for system service. - */ -void PendSV_Handler(void) -{ - /* USER CODE BEGIN PendSV_IRQn 0 */ - - /* USER CODE END PendSV_IRQn 0 */ - /* USER CODE BEGIN PendSV_IRQn 1 */ - - /* USER CODE END PendSV_IRQn 1 */ -} - -/** - * @brief This function handles System tick timer. - */ -void SysTick_Handler(void) -{ - /* USER CODE BEGIN SysTick_IRQn 0 */ - - /* USER CODE END SysTick_IRQn 0 */ - HAL_IncTick(); - /* USER CODE BEGIN SysTick_IRQn 1 */ - - /* USER CODE END SysTick_IRQn 1 */ -} - -/******************************************************************************/ -/* STM32F4xx Peripheral Interrupt Handlers */ -/* Add here the Interrupt Handlers for the used peripherals. */ -/* For the available peripheral interrupt handler names, */ -/* please refer to the startup file (startup_stm32f4xx.s). */ -/******************************************************************************/ - -/** - * @brief This function handles USB On The Go FS global interrupt. - */ -void OTG_FS_IRQHandler(void) -{ - /* USER CODE BEGIN OTG_FS_IRQn 0 */ - - /* USER CODE END OTG_FS_IRQn 0 */ - HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); - /* USER CODE BEGIN OTG_FS_IRQn 1 */ - - /* USER CODE END OTG_FS_IRQn 1 */ -} - -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_it.h b/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_it.h deleted file mode 100644 index feee38a39..000000000 --- a/ports/stm32f4/boards/stm32f411_disco/stm32f4xx_it.h +++ /dev/null @@ -1,70 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32f4xx_it.h - * @brief This file contains the headers of the interrupt handlers. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_IT_H -#define __STM32F4xx_IT_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - -/* USER CODE END EM */ - -/* Exported functions prototypes ---------------------------------------------*/ -void NMI_Handler(void); -void HardFault_Handler(void); -void MemManage_Handler(void); -void BusFault_Handler(void); -void UsageFault_Handler(void); -void SVC_Handler(void); -void DebugMon_Handler(void); -void PendSV_Handler(void); -void SysTick_Handler(void); -void OTG_FS_IRQHandler(void); -/* USER CODE BEGIN EFP */ - -/* USER CODE END EFP */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32F4xx_IT_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/stm32f412g_disco/board.c b/ports/stm32f4/boards/stm32f412g_disco/board.c deleted file mode 100644 index 4421970ee..000000000 --- a/ports/stm32f4/boards/stm32f412g_disco/board.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * - * 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 "boards/board.h" - -void board_init(void) { -} - -bool board_requests_safe_mode(void) { - return false; -} - -void reset_board(void) { - -} diff --git a/ports/stm32f4/boards/stm32f412g_disco/mpconfigboard.h b/ports/stm32f4/boards/stm32f412g_disco/mpconfigboard.h deleted file mode 100644 index 416944257..000000000 --- a/ports/stm32f4/boards/stm32f412g_disco/mpconfigboard.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Glenn Ruben Bakke - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * - * 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. - */ - -//Micropython setup - -#define MICROPY_HW_BOARD_NAME "STM32F412G_DISCO" -#define MICROPY_HW_MCU_NAME "STM32F412xGS" - -#define FLASH_SIZE (0x100000) -#define FLASH_PAGE_SIZE (0x4000) - -#define CIRCUITPY_INTERNAL_NVM_SIZE (4096) -#define AUTORESET_DELAY_MS 500 -#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE) \ No newline at end of file diff --git a/ports/stm32f4/boards/stm32f412g_disco/mpconfigboard.mk b/ports/stm32f4/boards/stm32f412g_disco/mpconfigboard.mk deleted file mode 100644 index 9e8711c36..000000000 --- a/ports/stm32f4/boards/stm32f412g_disco/mpconfigboard.mk +++ /dev/null @@ -1,18 +0,0 @@ -USB_VID = 0x239A -USB_PID = 0x802A -USB_PRODUCT = "A glorious potato" -USB_MANUFACTURER = "Adafruit Industries LLC" - -#USB_VID = 0x483 -#USB_PID = 0x572B -#USB_PRODUCT = "STM32 Human Interface Potato" -#USB_MANUFACTURER = "STMicroelectronics" - -MCU_SERIES = m4 -MCU_VARIANT = stm32f4 -MCU_SUB_VARIANT = stm32f412zx -CMSIS_MCU = STM32F412xG -LD_FILE = boards/STM32F412ZGTx_FLASH.ld -TEXT0_ADDR = 0x08000000 -TEXT1_ADDR = 0x08020000 - diff --git a/ports/stm32f4/boards/stm32f412g_disco/pins.c b/ports/stm32f4/boards/stm32f412g_disco/pins.c deleted file mode 100644 index e3a4b5ed6..000000000 --- a/ports/stm32f4/boards/stm32f412g_disco/pins.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "shared-bindings/board/__init__.h" - -STATIC const mp_rom_map_elem_t board_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR_PE02), MP_ROM_PTR(&pin_PE02) }, - { MP_ROM_QSTR(MP_QSTR_PE03), MP_ROM_PTR(&pin_PE03) }, - { MP_ROM_QSTR(MP_QSTR_PE04), MP_ROM_PTR(&pin_PE04) }, - { MP_ROM_QSTR(MP_QSTR_PE05), MP_ROM_PTR(&pin_PE05) }, - { MP_ROM_QSTR(MP_QSTR_PE06), MP_ROM_PTR(&pin_PE06) }, - { MP_ROM_QSTR(MP_QSTR_PC13), MP_ROM_PTR(&pin_PC13) }, - { MP_ROM_QSTR(MP_QSTR_PF02), MP_ROM_PTR(&pin_PF02) }, - { MP_ROM_QSTR(MP_QSTR_PF03), MP_ROM_PTR(&pin_PF03) }, - { MP_ROM_QSTR(MP_QSTR_PF10), MP_ROM_PTR(&pin_PF10) }, - { MP_ROM_QSTR(MP_QSTR_PC00), MP_ROM_PTR(&pin_PC00) }, - { MP_ROM_QSTR(MP_QSTR_PC01), MP_ROM_PTR(&pin_PC01) }, - { MP_ROM_QSTR(MP_QSTR_PC02), MP_ROM_PTR(&pin_PC02) }, - { MP_ROM_QSTR(MP_QSTR_PC03), MP_ROM_PTR(&pin_PC03) }, - { MP_ROM_QSTR(MP_QSTR_PA01), MP_ROM_PTR(&pin_PA01) }, - { MP_ROM_QSTR(MP_QSTR_PA02), MP_ROM_PTR(&pin_PA02) }, - { MP_ROM_QSTR(MP_QSTR_PA03), MP_ROM_PTR(&pin_PA03) }, - { MP_ROM_QSTR(MP_QSTR_PA04), MP_ROM_PTR(&pin_PA04) }, - { MP_ROM_QSTR(MP_QSTR_PA05), MP_ROM_PTR(&pin_PA05) }, - { MP_ROM_QSTR(MP_QSTR_PA06), MP_ROM_PTR(&pin_PA06) }, - { MP_ROM_QSTR(MP_QSTR_PA07), MP_ROM_PTR(&pin_PA07) }, - { MP_ROM_QSTR(MP_QSTR_PC04), MP_ROM_PTR(&pin_PC04) }, - { MP_ROM_QSTR(MP_QSTR_PC05), MP_ROM_PTR(&pin_PC05) }, - { MP_ROM_QSTR(MP_QSTR_PB00), MP_ROM_PTR(&pin_PB00) }, - { MP_ROM_QSTR(MP_QSTR_PB01), MP_ROM_PTR(&pin_PB01) }, - { MP_ROM_QSTR(MP_QSTR_PF11), MP_ROM_PTR(&pin_PF11) }, - { MP_ROM_QSTR(MP_QSTR_PF13), MP_ROM_PTR(&pin_PF13) }, - { MP_ROM_QSTR(MP_QSTR_PB10), MP_ROM_PTR(&pin_PB10) }, - { MP_ROM_QSTR(MP_QSTR_PB11), MP_ROM_PTR(&pin_PB11) }, - { MP_ROM_QSTR(MP_QSTR_PB12), MP_ROM_PTR(&pin_PB12) }, - { MP_ROM_QSTR(MP_QSTR_PB13), MP_ROM_PTR(&pin_PB13) }, - { MP_ROM_QSTR(MP_QSTR_PB14), MP_ROM_PTR(&pin_PB14) }, - { MP_ROM_QSTR(MP_QSTR_PB15), MP_ROM_PTR(&pin_PB15) }, - { MP_ROM_QSTR(MP_QSTR_PD12), MP_ROM_PTR(&pin_PD12) }, - { MP_ROM_QSTR(MP_QSTR_PD13), MP_ROM_PTR(&pin_PD13) }, - { MP_ROM_QSTR(MP_QSTR_PG02), MP_ROM_PTR(&pin_PG02) }, - { MP_ROM_QSTR(MP_QSTR_PC06), MP_ROM_PTR(&pin_PC06) }, - { MP_ROM_QSTR(MP_QSTR_PC07), MP_ROM_PTR(&pin_PC07) }, - { MP_ROM_QSTR(MP_QSTR_PC09), MP_ROM_PTR(&pin_PC09) }, - { MP_ROM_QSTR(MP_QSTR_PA08), MP_ROM_PTR(&pin_PA08) }, - { MP_ROM_QSTR(MP_QSTR_PA10), MP_ROM_PTR(&pin_PA10) }, - { MP_ROM_QSTR(MP_QSTR_PA13), MP_ROM_PTR(&pin_PA13) }, - { MP_ROM_QSTR(MP_QSTR_PA14), MP_ROM_PTR(&pin_PA14) }, - { MP_ROM_QSTR(MP_QSTR_PA15), MP_ROM_PTR(&pin_PA15) }, - { MP_ROM_QSTR(MP_QSTR_PD06), MP_ROM_PTR(&pin_PD06) }, - { MP_ROM_QSTR(MP_QSTR_PG09), MP_ROM_PTR(&pin_PG09) }, - { MP_ROM_QSTR(MP_QSTR_PG10), MP_ROM_PTR(&pin_PG10) }, - { MP_ROM_QSTR(MP_QSTR_PG11), MP_ROM_PTR(&pin_PG11) }, - { MP_ROM_QSTR(MP_QSTR_PG12), MP_ROM_PTR(&pin_PG12) }, - { MP_ROM_QSTR(MP_QSTR_PG13), MP_ROM_PTR(&pin_PG13) }, - { MP_ROM_QSTR(MP_QSTR_PG14), MP_ROM_PTR(&pin_PG14) }, - { MP_ROM_QSTR(MP_QSTR_PB03), MP_ROM_PTR(&pin_PB03) }, - { MP_ROM_QSTR(MP_QSTR_PB04), MP_ROM_PTR(&pin_PB04) }, - { MP_ROM_QSTR(MP_QSTR_PB05), MP_ROM_PTR(&pin_PB05) }, - { MP_ROM_QSTR(MP_QSTR_PB06), MP_ROM_PTR(&pin_PB06) }, - { MP_ROM_QSTR(MP_QSTR_PB07), MP_ROM_PTR(&pin_PB07) }, - { MP_ROM_QSTR(MP_QSTR_PB08), MP_ROM_PTR(&pin_PB08) }, - { MP_ROM_QSTR(MP_QSTR_PB09), MP_ROM_PTR(&pin_PB09) }, - { MP_ROM_QSTR(MP_QSTR_PE00), MP_ROM_PTR(&pin_PE00) }, - { MP_ROM_QSTR(MP_QSTR_PE01), MP_ROM_PTR(&pin_PE01) }, - { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_PB10) }, - { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_PB09) }, - { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PA05) }, - { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PA06) }, - { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PA07) }, - { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PA15) }, - { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PB08) }, - { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PG10) }, - { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PG11) }, - { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PF03) }, - { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PF10) }, - { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PG12) }, - { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PF04) }, - { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PG13) }, - { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PG14) }, - { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PG09) }, - { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA01) }, - { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PC01) }, - { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PC03) }, - { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PC04) }, - { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PC05) }, //alt PB09, see F401ZG-DISCO manual - { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB00) }, //alt PB10, see F401ZG-DISCO manual - { MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_PE00) }, - { MP_ROM_QSTR(MP_QSTR_LED2), MP_ROM_PTR(&pin_PE01) }, - { MP_ROM_QSTR(MP_QSTR_LED3), MP_ROM_PTR(&pin_PE02) }, - { MP_ROM_QSTR(MP_QSTR_LED4), MP_ROM_PTR(&pin_PE03) }, -}; -MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_hal_conf.h b/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_hal_conf.h deleted file mode 100644 index 5d329c14f..000000000 --- a/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_hal_conf.h +++ /dev/null @@ -1,439 +0,0 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_conf_template.h - * @author MCD Application Team - * @brief HAL configuration template file. - * This file should be copied to the application folder and renamed - * to stm32f4xx_hal_conf.h. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2017 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under BSD 3-Clause license, - * the "License"; You may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * opensource.org/licenses/BSD-3-Clause - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_CONF_H -#define __STM32F4xx_HAL_CONF_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ - -/* ########################## Module Selection ############################## */ -/** - * @brief This is the list of modules to be used in the HAL driver - */ -#define HAL_MODULE_ENABLED - - /* #define HAL_ADC_MODULE_ENABLED */ -/* #define HAL_CRYP_MODULE_ENABLED */ -/* #define HAL_CAN_MODULE_ENABLED */ -/* #define HAL_CRC_MODULE_ENABLED */ -/* #define HAL_CRYP_MODULE_ENABLED */ -/* #define HAL_DAC_MODULE_ENABLED */ -/* #define HAL_DCMI_MODULE_ENABLED */ -/* #define HAL_DMA2D_MODULE_ENABLED */ -/* #define HAL_ETH_MODULE_ENABLED */ -/* #define HAL_NAND_MODULE_ENABLED */ -/* #define HAL_NOR_MODULE_ENABLED */ -/* #define HAL_PCCARD_MODULE_ENABLED */ -#define HAL_SRAM_MODULE_ENABLED -/* #define HAL_SDRAM_MODULE_ENABLED */ -/* #define HAL_HASH_MODULE_ENABLED */ -#define HAL_I2C_MODULE_ENABLED -#define HAL_I2S_MODULE_ENABLED -/* #define HAL_IWDG_MODULE_ENABLED */ -/* #define HAL_LTDC_MODULE_ENABLED */ -/* #define HAL_RNG_MODULE_ENABLED */ -/* #define HAL_RTC_MODULE_ENABLED */ -/* #define HAL_SAI_MODULE_ENABLED */ -#define HAL_SD_MODULE_ENABLED -/* #define HAL_MMC_MODULE_ENABLED */ -/* #define HAL_SPI_MODULE_ENABLED */ -/* #define HAL_TIM_MODULE_ENABLED */ -#define HAL_UART_MODULE_ENABLED -/* #define HAL_USART_MODULE_ENABLED */ -/* #define HAL_IRDA_MODULE_ENABLED */ -/* #define HAL_SMARTCARD_MODULE_ENABLED */ -/* #define HAL_WWDG_MODULE_ENABLED */ -#define HAL_PCD_MODULE_ENABLED -/* #define HAL_HCD_MODULE_ENABLED */ -/* #define HAL_DSI_MODULE_ENABLED */ -/* #define HAL_QSPI_MODULE_ENABLED */ -#define HAL_QSPI_MODULE_ENABLED -/* #define HAL_CEC_MODULE_ENABLED */ -/* #define HAL_FMPI2C_MODULE_ENABLED */ -/* #define HAL_SPDIFRX_MODULE_ENABLED */ -/* #define HAL_DFSDM_MODULE_ENABLED */ -/* #define HAL_LPTIM_MODULE_ENABLED */ -/* #define HAL_EXTI_MODULE_ENABLED */ -#define HAL_GPIO_MODULE_ENABLED -#define HAL_EXTI_MODULE_ENABLED -#define HAL_DMA_MODULE_ENABLED -#define HAL_RCC_MODULE_ENABLED -#define HAL_FLASH_MODULE_ENABLED -#define HAL_PWR_MODULE_ENABLED -#define HAL_CORTEX_MODULE_ENABLED - -/* ########################## HSE/HSI Values adaptation ##################### */ -/** - * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. - * This value is used by the RCC HAL module to compute the system frequency - * (when HSE is used as system clock source, directly or through the PLL). - */ -#if !defined (HSE_VALUE) - #define HSE_VALUE ((uint32_t)8000000U) /*!< Value of the External oscillator in Hz */ -#endif /* HSE_VALUE */ - -#if !defined (HSE_STARTUP_TIMEOUT) - #define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */ -#endif /* HSE_STARTUP_TIMEOUT */ - -/** - * @brief Internal High Speed oscillator (HSI) value. - * This value is used by the RCC HAL module to compute the system frequency - * (when HSI is used as system clock source, directly or through the PLL). - */ -#if !defined (HSI_VALUE) - #define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/ -#endif /* HSI_VALUE */ - -/** - * @brief Internal Low Speed oscillator (LSI) value. - */ -#if !defined (LSI_VALUE) - #define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/ -#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz - The real value may vary depending on the variations - in voltage and temperature.*/ -/** - * @brief External Low Speed oscillator (LSE) value. - */ -#if !defined (LSE_VALUE) - #define LSE_VALUE ((uint32_t)32768U) /*!< Value of the External Low Speed oscillator in Hz */ -#endif /* LSE_VALUE */ - -#if !defined (LSE_STARTUP_TIMEOUT) - #define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */ -#endif /* LSE_STARTUP_TIMEOUT */ - -/** - * @brief External clock source for I2S peripheral - * This value is used by the I2S HAL module to compute the I2S clock source - * frequency, this source is inserted directly through I2S_CKIN pad. - */ -#if !defined (EXTERNAL_CLOCK_VALUE) - #define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000U) /*!< Value of the External audio frequency in Hz*/ -#endif /* EXTERNAL_CLOCK_VALUE */ - -/* Tip: To avoid modifying this file each time you need to use different HSE, - === you can define the HSE value in your toolchain compiler preprocessor. */ - -/* ########################### System Configuration ######################### */ -/** - * @brief This is the HAL system configuration section - */ -#define VDD_VALUE ((uint32_t)3300U) /*!< Value of VDD in mv */ -#define TICK_INT_PRIORITY ((uint32_t)0U) /*!< tick interrupt priority */ -#define USE_RTOS 0U -#define PREFETCH_ENABLE 1U -#define INSTRUCTION_CACHE_ENABLE 1U -#define DATA_CACHE_ENABLE 1U - -/* ########################## Assert Selection ############################## */ -/** - * @brief Uncomment the line below to expanse the "assert_param" macro in the - * HAL drivers code - */ -/* #define USE_FULL_ASSERT 1U */ - -/* ################## Ethernet peripheral configuration ##################### */ - -/* Section 1 : Ethernet peripheral configuration */ - -/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ -#define MAC_ADDR0 2U -#define MAC_ADDR1 0U -#define MAC_ADDR2 0U -#define MAC_ADDR3 0U -#define MAC_ADDR4 0U -#define MAC_ADDR5 0U - -/* Definition of the Ethernet driver buffers size and count */ -#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ -#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ -#define ETH_RXBUFNB ((uint32_t)4U) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ -#define ETH_TXBUFNB ((uint32_t)4U) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ - -/* Section 2: PHY configuration section */ - -/* DP83848_PHY_ADDRESS Address*/ -#define DP83848_PHY_ADDRESS 0x01U -/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ -#define PHY_RESET_DELAY ((uint32_t)0x000000FFU) -/* PHY Configuration delay */ -#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFU) - -#define PHY_READ_TO ((uint32_t)0x0000FFFFU) -#define PHY_WRITE_TO ((uint32_t)0x0000FFFFU) - -/* Section 3: Common PHY Registers */ - -#define PHY_BCR ((uint16_t)0x0000U) /*!< Transceiver Basic Control Register */ -#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */ - -#define PHY_RESET ((uint16_t)0x8000U) /*!< PHY Reset */ -#define PHY_LOOPBACK ((uint16_t)0x4000U) /*!< Select loop-back mode */ -#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100U) /*!< Set the full-duplex mode at 100 Mb/s */ -#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000U) /*!< Set the half-duplex mode at 100 Mb/s */ -#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100U) /*!< Set the full-duplex mode at 10 Mb/s */ -#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000U) /*!< Set the half-duplex mode at 10 Mb/s */ -#define PHY_AUTONEGOTIATION ((uint16_t)0x1000U) /*!< Enable auto-negotiation function */ -#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200U) /*!< Restart auto-negotiation function */ -#define PHY_POWERDOWN ((uint16_t)0x0800U) /*!< Select the power down mode */ -#define PHY_ISOLATE ((uint16_t)0x0400U) /*!< Isolate PHY from MII */ - -#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020U) /*!< Auto-Negotiation process completed */ -#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */ -#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */ - -/* Section 4: Extended PHY Registers */ -#define PHY_SR ((uint16_t)0x10U) /*!< PHY status register Offset */ - -#define PHY_SPEED_STATUS ((uint16_t)0x0002U) /*!< PHY Speed mask */ -#define PHY_DUPLEX_STATUS ((uint16_t)0x0004U) /*!< PHY Duplex mask */ - -/* ################## SPI peripheral configuration ########################## */ - -/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver -* Activated: CRC code is present inside driver -* Deactivated: CRC code cleaned from driver -*/ - -#define USE_SPI_CRC 0U - -/* Includes ------------------------------------------------------------------*/ -/** - * @brief Include module's header file - */ - -#ifdef HAL_RCC_MODULE_ENABLED - #include "stm32f4xx_hal_rcc.h" -#endif /* HAL_RCC_MODULE_ENABLED */ - -#ifdef HAL_EXTI_MODULE_ENABLED - #include "stm32f4xx_hal_exti.h" -#endif /* HAL_EXTI_MODULE_ENABLED */ - -#ifdef HAL_GPIO_MODULE_ENABLED - #include "stm32f4xx_hal_gpio.h" -#endif /* HAL_GPIO_MODULE_ENABLED */ - -#ifdef HAL_DMA_MODULE_ENABLED - #include "stm32f4xx_hal_dma.h" -#endif /* HAL_DMA_MODULE_ENABLED */ - -#ifdef HAL_CORTEX_MODULE_ENABLED - #include "stm32f4xx_hal_cortex.h" -#endif /* HAL_CORTEX_MODULE_ENABLED */ - -#ifdef HAL_ADC_MODULE_ENABLED - #include "stm32f4xx_hal_adc.h" -#endif /* HAL_ADC_MODULE_ENABLED */ - -#ifdef HAL_CAN_MODULE_ENABLED - #include "stm32f4xx_hal_can.h" -#endif /* HAL_CAN_MODULE_ENABLED */ - -#ifdef HAL_CRC_MODULE_ENABLED - #include "stm32f4xx_hal_crc.h" -#endif /* HAL_CRC_MODULE_ENABLED */ - -#ifdef HAL_CRYP_MODULE_ENABLED - #include "stm32f4xx_hal_cryp.h" -#endif /* HAL_CRYP_MODULE_ENABLED */ - -#ifdef HAL_DMA2D_MODULE_ENABLED - #include "stm32f4xx_hal_dma2d.h" -#endif /* HAL_DMA2D_MODULE_ENABLED */ - -#ifdef HAL_DAC_MODULE_ENABLED - #include "stm32f4xx_hal_dac.h" -#endif /* HAL_DAC_MODULE_ENABLED */ - -#ifdef HAL_DCMI_MODULE_ENABLED - #include "stm32f4xx_hal_dcmi.h" -#endif /* HAL_DCMI_MODULE_ENABLED */ - -#ifdef HAL_ETH_MODULE_ENABLED - #include "stm32f4xx_hal_eth.h" -#endif /* HAL_ETH_MODULE_ENABLED */ - -#ifdef HAL_FLASH_MODULE_ENABLED - #include "stm32f4xx_hal_flash.h" -#endif /* HAL_FLASH_MODULE_ENABLED */ - -#ifdef HAL_SRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sram.h" -#endif /* HAL_SRAM_MODULE_ENABLED */ - -#ifdef HAL_NOR_MODULE_ENABLED - #include "stm32f4xx_hal_nor.h" -#endif /* HAL_NOR_MODULE_ENABLED */ - -#ifdef HAL_NAND_MODULE_ENABLED - #include "stm32f4xx_hal_nand.h" -#endif /* HAL_NAND_MODULE_ENABLED */ - -#ifdef HAL_PCCARD_MODULE_ENABLED - #include "stm32f4xx_hal_pccard.h" -#endif /* HAL_PCCARD_MODULE_ENABLED */ - -#ifdef HAL_SDRAM_MODULE_ENABLED - #include "stm32f4xx_hal_sdram.h" -#endif /* HAL_SDRAM_MODULE_ENABLED */ - -#ifdef HAL_HASH_MODULE_ENABLED - #include "stm32f4xx_hal_hash.h" -#endif /* HAL_HASH_MODULE_ENABLED */ - -#ifdef HAL_I2C_MODULE_ENABLED - #include "stm32f4xx_hal_i2c.h" -#endif /* HAL_I2C_MODULE_ENABLED */ - -#ifdef HAL_I2S_MODULE_ENABLED - #include "stm32f4xx_hal_i2s.h" -#endif /* HAL_I2S_MODULE_ENABLED */ - -#ifdef HAL_IWDG_MODULE_ENABLED - #include "stm32f4xx_hal_iwdg.h" -#endif /* HAL_IWDG_MODULE_ENABLED */ - -#ifdef HAL_LTDC_MODULE_ENABLED - #include "stm32f4xx_hal_ltdc.h" -#endif /* HAL_LTDC_MODULE_ENABLED */ - -#ifdef HAL_PWR_MODULE_ENABLED - #include "stm32f4xx_hal_pwr.h" -#endif /* HAL_PWR_MODULE_ENABLED */ - -#ifdef HAL_RNG_MODULE_ENABLED - #include "stm32f4xx_hal_rng.h" -#endif /* HAL_RNG_MODULE_ENABLED */ - -#ifdef HAL_RTC_MODULE_ENABLED - #include "stm32f4xx_hal_rtc.h" -#endif /* HAL_RTC_MODULE_ENABLED */ - -#ifdef HAL_SAI_MODULE_ENABLED - #include "stm32f4xx_hal_sai.h" -#endif /* HAL_SAI_MODULE_ENABLED */ - -#ifdef HAL_SD_MODULE_ENABLED - #include "stm32f4xx_hal_sd.h" -#endif /* HAL_SD_MODULE_ENABLED */ - -#ifdef HAL_MMC_MODULE_ENABLED - #include "stm32f4xx_hal_mmc.h" -#endif /* HAL_MMC_MODULE_ENABLED */ - -#ifdef HAL_SPI_MODULE_ENABLED - #include "stm32f4xx_hal_spi.h" -#endif /* HAL_SPI_MODULE_ENABLED */ - -#ifdef HAL_TIM_MODULE_ENABLED - #include "stm32f4xx_hal_tim.h" -#endif /* HAL_TIM_MODULE_ENABLED */ - -#ifdef HAL_UART_MODULE_ENABLED - #include "stm32f4xx_hal_uart.h" -#endif /* HAL_UART_MODULE_ENABLED */ - -#ifdef HAL_USART_MODULE_ENABLED - #include "stm32f4xx_hal_usart.h" -#endif /* HAL_USART_MODULE_ENABLED */ - -#ifdef HAL_IRDA_MODULE_ENABLED - #include "stm32f4xx_hal_irda.h" -#endif /* HAL_IRDA_MODULE_ENABLED */ - -#ifdef HAL_SMARTCARD_MODULE_ENABLED - #include "stm32f4xx_hal_smartcard.h" -#endif /* HAL_SMARTCARD_MODULE_ENABLED */ - -#ifdef HAL_WWDG_MODULE_ENABLED - #include "stm32f4xx_hal_wwdg.h" -#endif /* HAL_WWDG_MODULE_ENABLED */ - -#ifdef HAL_PCD_MODULE_ENABLED - #include "stm32f4xx_hal_pcd.h" -#endif /* HAL_PCD_MODULE_ENABLED */ - -#ifdef HAL_HCD_MODULE_ENABLED - #include "stm32f4xx_hal_hcd.h" -#endif /* HAL_HCD_MODULE_ENABLED */ - -#ifdef HAL_DSI_MODULE_ENABLED - #include "stm32f4xx_hal_dsi.h" -#endif /* HAL_DSI_MODULE_ENABLED */ - -#ifdef HAL_QSPI_MODULE_ENABLED - #include "stm32f4xx_hal_qspi.h" -#endif /* HAL_QSPI_MODULE_ENABLED */ - -#ifdef HAL_CEC_MODULE_ENABLED - #include "stm32f4xx_hal_cec.h" -#endif /* HAL_CEC_MODULE_ENABLED */ - -#ifdef HAL_FMPI2C_MODULE_ENABLED - #include "stm32f4xx_hal_fmpi2c.h" -#endif /* HAL_FMPI2C_MODULE_ENABLED */ - -#ifdef HAL_SPDIFRX_MODULE_ENABLED - #include "stm32f4xx_hal_spdifrx.h" -#endif /* HAL_SPDIFRX_MODULE_ENABLED */ - -#ifdef HAL_DFSDM_MODULE_ENABLED - #include "stm32f4xx_hal_dfsdm.h" -#endif /* HAL_DFSDM_MODULE_ENABLED */ - -#ifdef HAL_LPTIM_MODULE_ENABLED - #include "stm32f4xx_hal_lptim.h" -#endif /* HAL_LPTIM_MODULE_ENABLED */ - -/* Exported macro ------------------------------------------------------------*/ -#ifdef USE_FULL_ASSERT -/** - * @brief The assert_param macro is used for function's parameters check. - * @param expr: If expr is false, it calls assert_failed function - * which reports the name of the source file and the source - * line number of the call that failed. - * If expr is true, it returns no value. - * @retval None - */ - #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) -/* Exported functions ------------------------------------------------------- */ - void assert_failed(uint8_t* file, uint32_t line); -#else - #define assert_param(expr) ((void)0U) -#endif /* USE_FULL_ASSERT */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32F4xx_HAL_CONF_H */ - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_hal_msp.c b/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_hal_msp.c deleted file mode 100644 index 9d29f3607..000000000 --- a/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_hal_msp.c +++ /dev/null @@ -1,832 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * File Name : stm32f4xx_hal_msp.c - * Description : This file provides code for the MSP Initialization - * and de-Initialization codes. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f4xx_hal.h" -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN TD */ - -/* USER CODE END TD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN Define */ -#define LED3_Pin GPIO_PIN_2 -#define LED3_GPIO_Port GPIOE -#define LED4_Pin GPIO_PIN_3 -#define LED4_GPIO_Port GPIOE -#define DFSDM_DATIN3_Pin GPIO_PIN_4 -#define DFSDM_DATIN3_GPIO_Port GPIOE -#define A0_Pin GPIO_PIN_0 -#define A0_GPIO_Port GPIOF -#define LCD_BLCTRL_Pin GPIO_PIN_5 -#define LCD_BLCTRL_GPIO_Port GPIOF -#define QSPI_BK1_IO3_Pin GPIO_PIN_6 -#define QSPI_BK1_IO3_GPIO_Port GPIOF -#define QSPI_BK1_IO2_Pin GPIO_PIN_7 -#define QSPI_BK1_IO2_GPIO_Port GPIOF -#define QSPI_BK1_IO0_Pin GPIO_PIN_8 -#define QSPI_BK1_IO0_GPIO_Port GPIOF -#define QSPI_BK1_IO1_Pin GPIO_PIN_9 -#define QSPI_BK1_IO1_GPIO_Port GPIOF -#define STLK_MCO_Pin GPIO_PIN_0 -#define STLK_MCO_GPIO_Port GPIOH -#define DFSDM_CKOUT_Pin GPIO_PIN_2 -#define DFSDM_CKOUT_GPIO_Port GPIOC -#define JOY_SEL_Pin GPIO_PIN_0 -#define JOY_SEL_GPIO_Port GPIOA -#define STLINK_RX_Pin GPIO_PIN_2 -#define STLINK_RX_GPIO_Port GPIOA -#define STLINK_TX_Pin GPIO_PIN_3 -#define STLINK_TX_GPIO_Port GPIOA -#define CODEC_I2S3_WS_Pin GPIO_PIN_4 -#define CODEC_I2S3_WS_GPIO_Port GPIOA -#define DFSDM_DATIN0_Pin GPIO_PIN_1 -#define DFSDM_DATIN0_GPIO_Port GPIOB -#define QSPI_CLK_Pin GPIO_PIN_2 -#define QSPI_CLK_GPIO_Port GPIOB -#define EXT_RESET_Pin GPIO_PIN_11 -#define EXT_RESET_GPIO_Port GPIOF -#define CTP_RST_Pin GPIO_PIN_12 -#define CTP_RST_GPIO_Port GPIOF -#define JOY_RIGHT_Pin GPIO_PIN_14 -#define JOY_RIGHT_GPIO_Port GPIOF -#define JOY_LEFT_Pin GPIO_PIN_15 -#define JOY_LEFT_GPIO_Port GPIOF -#define JOY_UP_Pin GPIO_PIN_0 -#define JOY_UP_GPIO_Port GPIOG -#define JOY_DOWN_Pin GPIO_PIN_1 -#define JOY_DOWN_GPIO_Port GPIOG -#define D4_Pin GPIO_PIN_7 -#define D4_GPIO_Port GPIOE -#define D5_Pin GPIO_PIN_8 -#define D5_GPIO_Port GPIOE -#define D6_Pin GPIO_PIN_9 -#define D6_GPIO_Port GPIOE -#define D7_Pin GPIO_PIN_10 -#define D7_GPIO_Port GPIOE -#define D8_Pin GPIO_PIN_11 -#define D8_GPIO_Port GPIOE -#define D9_Pin GPIO_PIN_12 -#define D9_GPIO_Port GPIOE -#define D10_Pin GPIO_PIN_13 -#define D10_GPIO_Port GPIOE -#define D11_Pin GPIO_PIN_14 -#define D11_GPIO_Port GPIOE -#define D12_Pin GPIO_PIN_15 -#define D12_GPIO_Port GPIOE -#define I2C2_SCL_Pin GPIO_PIN_10 -#define I2C2_SCL_GPIO_Port GPIOB -#define M2_CKIN_Pin GPIO_PIN_11 -#define M2_CKIN_GPIO_Port GPIOB -#define CODEC_I2S3_SCK_Pin GPIO_PIN_12 -#define CODEC_I2S3_SCK_GPIO_Port GPIOB -#define D13_Pin GPIO_PIN_8 -#define D13_GPIO_Port GPIOD -#define D14_Pin GPIO_PIN_9 -#define D14_GPIO_Port GPIOD -#define D15_Pin GPIO_PIN_10 -#define D15_GPIO_Port GPIOD -#define LCD_RESET_Pin GPIO_PIN_11 -#define LCD_RESET_GPIO_Port GPIOD -#define D0_Pin GPIO_PIN_14 -#define D0_GPIO_Port GPIOD -#define D1_Pin GPIO_PIN_15 -#define D1_GPIO_Port GPIOD -#define CODEC_INT_Pin GPIO_PIN_2 -#define CODEC_INT_GPIO_Port GPIOG -#define LCD_TE_Pin GPIO_PIN_4 -#define LCD_TE_GPIO_Port GPIOG -#define CTP_INT_Pin GPIO_PIN_5 -#define CTP_INT_GPIO_Port GPIOG -#define QSPI_BK1_NCS_Pin GPIO_PIN_6 -#define QSPI_BK1_NCS_GPIO_Port GPIOG -#define USB_OTGFS_OVRCR_Pin GPIO_PIN_7 -#define USB_OTGFS_OVRCR_GPIO_Port GPIOG -#define USB_OTGFS_PPWR_EN_Pin GPIO_PIN_8 -#define USB_OTGFS_PPWR_EN_GPIO_Port GPIOG -#define CODEC_I2S3_MCK_Pin GPIO_PIN_7 -#define CODEC_I2S3_MCK_GPIO_Port GPIOC -#define uSD_D0_Pin GPIO_PIN_8 -#define uSD_D0_GPIO_Port GPIOC -#define uSD_D1_Pin GPIO_PIN_9 -#define uSD_D1_GPIO_Port GPIOC -#define M2_CKINA8_Pin GPIO_PIN_8 -#define M2_CKINA8_GPIO_Port GPIOA -#define USB_OTGFS_VBUS_Pin GPIO_PIN_9 -#define USB_OTGFS_VBUS_GPIO_Port GPIOA -#define USB_OTGFS_ID_Pin GPIO_PIN_10 -#define USB_OTGFS_ID_GPIO_Port GPIOA -#define USB_OTGFS_DM_Pin GPIO_PIN_11 -#define USB_OTGFS_DM_GPIO_Port GPIOA -#define USB_OTGFS_DP_Pin GPIO_PIN_12 -#define USB_OTGFS_DP_GPIO_Port GPIOA -#define SWDIO_Pin GPIO_PIN_13 -#define SWDIO_GPIO_Port GPIOA -#define SWCLK_Pin GPIO_PIN_14 -#define SWCLK_GPIO_Port GPIOA -#define uSD_D2_Pin GPIO_PIN_10 -#define uSD_D2_GPIO_Port GPIOC -#define uSD_D3_Pin GPIO_PIN_11 -#define uSD_D3_GPIO_Port GPIOC -#define uSD_CLK_Pin GPIO_PIN_12 -#define uSD_CLK_GPIO_Port GPIOC -#define D2_Pin GPIO_PIN_0 -#define D2_GPIO_Port GPIOD -#define D3_Pin GPIO_PIN_1 -#define D3_GPIO_Port GPIOD -#define uSD_CMD_Pin GPIO_PIN_2 -#define uSD_CMD_GPIO_Port GPIOD -#define uSD_DETECT_Pin GPIO_PIN_3 -#define uSD_DETECT_GPIO_Port GPIOD -#define FMC_NOE_Pin GPIO_PIN_4 -#define FMC_NOE_GPIO_Port GPIOD -#define FMC_NWE_Pin GPIO_PIN_5 -#define FMC_NWE_GPIO_Port GPIOD -#define FMC_NE1_Pin GPIO_PIN_7 -#define FMC_NE1_GPIO_Port GPIOD -#define SWO_Pin GPIO_PIN_3 -#define SWO_GPIO_Port GPIOB -#define CODEC_I2S3ext_SD_Pin GPIO_PIN_4 -#define CODEC_I2S3ext_SD_GPIO_Port GPIOB -#define CODEC_I2S3_SD_Pin GPIO_PIN_5 -#define CODEC_I2S3_SD_GPIO_Port GPIOB -#define I2C1_SCL_Pin GPIO_PIN_6 -#define I2C1_SCL_GPIO_Port GPIOB -#define I2C1_SDA_Pin GPIO_PIN_7 -#define I2C1_SDA_GPIO_Port GPIOB -#define I2C2_SDA_Pin GPIO_PIN_9 -#define I2C2_SDA_GPIO_Port GPIOB -#define LED1_Pin GPIO_PIN_0 -#define LED1_GPIO_Port GPIOE -#define LED2_Pin GPIO_PIN_1 -#define LED2_GPIO_Port GPIOE - -/* USER CODE END Define */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN Macro */ - -/* USER CODE END Macro */ - -/* Private variables ---------------------------------------------------------*/ -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* External functions --------------------------------------------------------*/ -/* USER CODE BEGIN ExternalFunctions */ - -/* USER CODE END ExternalFunctions */ - -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ -/** - * Initializes the Global MSP. - */ -void HAL_MspInit(void) -{ - /* USER CODE BEGIN MspInit 0 */ - - /* USER CODE END MspInit 0 */ - - __HAL_RCC_SYSCFG_CLK_ENABLE(); - __HAL_RCC_PWR_CLK_ENABLE(); - - /* System interrupt init*/ - - /* USER CODE BEGIN MspInit 1 */ - - /* USER CODE END MspInit 1 */ -} - -/** -* @brief I2C MSP Initialization -* This function configures the hardware resources used in this example -* @param hi2c: I2C handle pointer -* @retval None -*/ -void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(hi2c->Instance==I2C1) - { - /* USER CODE BEGIN I2C1_MspInit 0 */ - - /* USER CODE END I2C1_MspInit 0 */ - - __HAL_RCC_GPIOB_CLK_ENABLE(); - /**I2C1 GPIO Configuration - PB6 ------> I2C1_SCL - PB7 ------> I2C1_SDA - */ - GPIO_InitStruct.Pin = I2C1_SCL_Pin|I2C1_SDA_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - /* Peripheral clock enable */ - __HAL_RCC_I2C1_CLK_ENABLE(); - /* USER CODE BEGIN I2C1_MspInit 1 */ - - /* USER CODE END I2C1_MspInit 1 */ - } - else if(hi2c->Instance==I2C2) - { - /* USER CODE BEGIN I2C2_MspInit 0 */ - - /* USER CODE END I2C2_MspInit 0 */ - - __HAL_RCC_GPIOB_CLK_ENABLE(); - /**I2C2 GPIO Configuration - PB10 ------> I2C2_SCL - PB9 ------> I2C2_SDA - */ - GPIO_InitStruct.Pin = I2C2_SCL_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF4_I2C2; - HAL_GPIO_Init(I2C2_SCL_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = I2C2_SDA_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF9_I2C2; - HAL_GPIO_Init(I2C2_SDA_GPIO_Port, &GPIO_InitStruct); - - /* Peripheral clock enable */ - __HAL_RCC_I2C2_CLK_ENABLE(); - /* USER CODE BEGIN I2C2_MspInit 1 */ - - /* USER CODE END I2C2_MspInit 1 */ - } - -} - -/** -* @brief I2C MSP De-Initialization -* This function freeze the hardware resources used in this example -* @param hi2c: I2C handle pointer -* @retval None -*/ -void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c) -{ - if(hi2c->Instance==I2C1) - { - /* USER CODE BEGIN I2C1_MspDeInit 0 */ - - /* USER CODE END I2C1_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_I2C1_CLK_DISABLE(); - - /**I2C1 GPIO Configuration - PB6 ------> I2C1_SCL - PB7 ------> I2C1_SDA - */ - HAL_GPIO_DeInit(GPIOB, I2C1_SCL_Pin|I2C1_SDA_Pin); - - /* USER CODE BEGIN I2C1_MspDeInit 1 */ - - /* USER CODE END I2C1_MspDeInit 1 */ - } - else if(hi2c->Instance==I2C2) - { - /* USER CODE BEGIN I2C2_MspDeInit 0 */ - - /* USER CODE END I2C2_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_I2C2_CLK_DISABLE(); - - /**I2C2 GPIO Configuration - PB10 ------> I2C2_SCL - PB9 ------> I2C2_SDA - */ - HAL_GPIO_DeInit(GPIOB, I2C2_SCL_Pin|I2C2_SDA_Pin); - - /* USER CODE BEGIN I2C2_MspDeInit 1 */ - - /* USER CODE END I2C2_MspDeInit 1 */ - } - -} - -/** -* @brief I2S MSP Initialization -* This function configures the hardware resources used in this example -* @param hi2s: I2S handle pointer -* @retval None -*/ -void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(hi2s->Instance==SPI3) - { - /* USER CODE BEGIN SPI3_MspInit 0 */ - - /* USER CODE END SPI3_MspInit 0 */ - /* Peripheral clock enable */ - __HAL_RCC_SPI3_CLK_ENABLE(); - - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - /**I2S3 GPIO Configuration - PA4 ------> I2S3_WS - PB12 ------> I2S3_CK - PC7 ------> I2S3_MCK - PB4 ------> I2S3_ext_SD - PB5 ------> I2S3_SD - */ - GPIO_InitStruct.Pin = CODEC_I2S3_WS_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; - HAL_GPIO_Init(CODEC_I2S3_WS_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = CODEC_I2S3_SCK_Pin|CODEC_I2S3ext_SD_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF7_SPI3; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = CODEC_I2S3_MCK_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; - HAL_GPIO_Init(CODEC_I2S3_MCK_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = CODEC_I2S3_SD_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF6_SPI3; - HAL_GPIO_Init(CODEC_I2S3_SD_GPIO_Port, &GPIO_InitStruct); - - /* USER CODE BEGIN SPI3_MspInit 1 */ - - /* USER CODE END SPI3_MspInit 1 */ - } - -} - -/** -* @brief I2S MSP De-Initialization -* This function freeze the hardware resources used in this example -* @param hi2s: I2S handle pointer -* @retval None -*/ -void HAL_I2S_MspDeInit(I2S_HandleTypeDef* hi2s) -{ - if(hi2s->Instance==SPI3) - { - /* USER CODE BEGIN SPI3_MspDeInit 0 */ - - /* USER CODE END SPI3_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_SPI3_CLK_DISABLE(); - - /**I2S3 GPIO Configuration - PA4 ------> I2S3_WS - PB12 ------> I2S3_CK - PC7 ------> I2S3_MCK - PB4 ------> I2S3_ext_SD - PB5 ------> I2S3_SD - */ - HAL_GPIO_DeInit(CODEC_I2S3_WS_GPIO_Port, CODEC_I2S3_WS_Pin); - - HAL_GPIO_DeInit(GPIOB, CODEC_I2S3_SCK_Pin|CODEC_I2S3ext_SD_Pin|CODEC_I2S3_SD_Pin); - - HAL_GPIO_DeInit(CODEC_I2S3_MCK_GPIO_Port, CODEC_I2S3_MCK_Pin); - - /* USER CODE BEGIN SPI3_MspDeInit 1 */ - - /* USER CODE END SPI3_MspDeInit 1 */ - } - -} - -/** -* @brief QSPI MSP Initialization -* This function configures the hardware resources used in this example -* @param hqspi: QSPI handle pointer -* @retval None -*/ -void HAL_QSPI_MspInit(QSPI_HandleTypeDef* hqspi) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(hqspi->Instance==QUADSPI) - { - /* USER CODE BEGIN QUADSPI_MspInit 0 */ - - /* USER CODE END QUADSPI_MspInit 0 */ - /* Peripheral clock enable */ - __HAL_RCC_QSPI_CLK_ENABLE(); - - __HAL_RCC_GPIOF_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); - /**QUADSPI GPIO Configuration - PF6 ------> QUADSPI_BK1_IO3 - PF7 ------> QUADSPI_BK1_IO2 - PF8 ------> QUADSPI_BK1_IO0 - PF9 ------> QUADSPI_BK1_IO1 - PB2 ------> QUADSPI_CLK - PG6 ------> QUADSPI_BK1_NCS - */ - GPIO_InitStruct.Pin = QSPI_BK1_IO3_Pin|QSPI_BK1_IO2_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF9_QSPI; - HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = QSPI_BK1_IO0_Pin|QSPI_BK1_IO1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; - HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = QSPI_CLK_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF9_QSPI; - HAL_GPIO_Init(QSPI_CLK_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = QSPI_BK1_NCS_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; - HAL_GPIO_Init(QSPI_BK1_NCS_GPIO_Port, &GPIO_InitStruct); - - /* USER CODE BEGIN QUADSPI_MspInit 1 */ - - /* USER CODE END QUADSPI_MspInit 1 */ - } - -} - -/** -* @brief QSPI MSP De-Initialization -* This function freeze the hardware resources used in this example -* @param hqspi: QSPI handle pointer -* @retval None -*/ -void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef* hqspi) -{ - if(hqspi->Instance==QUADSPI) - { - /* USER CODE BEGIN QUADSPI_MspDeInit 0 */ - - /* USER CODE END QUADSPI_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_QSPI_CLK_DISABLE(); - - /**QUADSPI GPIO Configuration - PF6 ------> QUADSPI_BK1_IO3 - PF7 ------> QUADSPI_BK1_IO2 - PF8 ------> QUADSPI_BK1_IO0 - PF9 ------> QUADSPI_BK1_IO1 - PB2 ------> QUADSPI_CLK - PG6 ------> QUADSPI_BK1_NCS - */ - HAL_GPIO_DeInit(GPIOF, QSPI_BK1_IO3_Pin|QSPI_BK1_IO2_Pin|QSPI_BK1_IO0_Pin|QSPI_BK1_IO1_Pin); - - HAL_GPIO_DeInit(QSPI_CLK_GPIO_Port, QSPI_CLK_Pin); - - HAL_GPIO_DeInit(QSPI_BK1_NCS_GPIO_Port, QSPI_BK1_NCS_Pin); - - /* USER CODE BEGIN QUADSPI_MspDeInit 1 */ - - /* USER CODE END QUADSPI_MspDeInit 1 */ - } - -} - -/** -* @brief SD MSP Initialization -* This function configures the hardware resources used in this example -* @param hsd: SD handle pointer -* @retval None -*/ -void HAL_SD_MspInit(SD_HandleTypeDef* hsd) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(hsd->Instance==SDIO) - { - /* USER CODE BEGIN SDIO_MspInit 0 */ - - /* USER CODE END SDIO_MspInit 0 */ - /* Peripheral clock enable */ - __HAL_RCC_SDIO_CLK_ENABLE(); - - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOD_CLK_ENABLE(); - /**SDIO GPIO Configuration - PC8 ------> SDIO_D0 - PC9 ------> SDIO_D1 - PC10 ------> SDIO_D2 - PC11 ------> SDIO_D3 - PC12 ------> SDIO_CK - PD2 ------> SDIO_CMD - */ - GPIO_InitStruct.Pin = uSD_D0_Pin|uSD_D1_Pin|uSD_D2_Pin|uSD_D3_Pin - |uSD_CLK_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = uSD_CMD_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; - HAL_GPIO_Init(uSD_CMD_GPIO_Port, &GPIO_InitStruct); - - /* USER CODE BEGIN SDIO_MspInit 1 */ - - /* USER CODE END SDIO_MspInit 1 */ - } - -} - -/** -* @brief SD MSP De-Initialization -* This function freeze the hardware resources used in this example -* @param hsd: SD handle pointer -* @retval None -*/ -void HAL_SD_MspDeInit(SD_HandleTypeDef* hsd) -{ - if(hsd->Instance==SDIO) - { - /* USER CODE BEGIN SDIO_MspDeInit 0 */ - - /* USER CODE END SDIO_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_SDIO_CLK_DISABLE(); - - /**SDIO GPIO Configuration - PC8 ------> SDIO_D0 - PC9 ------> SDIO_D1 - PC10 ------> SDIO_D2 - PC11 ------> SDIO_D3 - PC12 ------> SDIO_CK - PD2 ------> SDIO_CMD - */ - HAL_GPIO_DeInit(GPIOC, uSD_D0_Pin|uSD_D1_Pin|uSD_D2_Pin|uSD_D3_Pin - |uSD_CLK_Pin); - - HAL_GPIO_DeInit(uSD_CMD_GPIO_Port, uSD_CMD_Pin); - - /* USER CODE BEGIN SDIO_MspDeInit 1 */ - - /* USER CODE END SDIO_MspDeInit 1 */ - } - -} - -/** -* @brief UART MSP Initialization -* This function configures the hardware resources used in this example -* @param huart: UART handle pointer -* @retval None -*/ -void HAL_UART_MspInit(UART_HandleTypeDef* huart) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(huart->Instance==USART2) - { - /* USER CODE BEGIN USART2_MspInit 0 */ - - /* USER CODE END USART2_MspInit 0 */ - /* Peripheral clock enable */ - __HAL_RCC_USART2_CLK_ENABLE(); - - __HAL_RCC_GPIOA_CLK_ENABLE(); - /**USART2 GPIO Configuration - PA2 ------> USART2_TX - PA3 ------> USART2_RX - */ - GPIO_InitStruct.Pin = STLINK_RX_Pin|STLINK_TX_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF7_USART2; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - /* USER CODE BEGIN USART2_MspInit 1 */ - - /* USER CODE END USART2_MspInit 1 */ - } - -} - -/** -* @brief UART MSP De-Initialization -* This function freeze the hardware resources used in this example -* @param huart: UART handle pointer -* @retval None -*/ -void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) -{ - if(huart->Instance==USART2) - { - /* USER CODE BEGIN USART2_MspDeInit 0 */ - - /* USER CODE END USART2_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_USART2_CLK_DISABLE(); - - /**USART2 GPIO Configuration - PA2 ------> USART2_TX - PA3 ------> USART2_RX - */ - HAL_GPIO_DeInit(GPIOA, STLINK_RX_Pin|STLINK_TX_Pin); - - /* USER CODE BEGIN USART2_MspDeInit 1 */ - - /* USER CODE END USART2_MspDeInit 1 */ - } - -} - -static uint32_t FSMC_Initialized = 0; - -static void HAL_FSMC_MspInit(void){ - /* USER CODE BEGIN FSMC_MspInit 0 */ - - /* USER CODE END FSMC_MspInit 0 */ - GPIO_InitTypeDef GPIO_InitStruct ={0}; - if (FSMC_Initialized) { - return; - } - FSMC_Initialized = 1; - /* Peripheral clock enable */ - __HAL_RCC_FSMC_CLK_ENABLE(); - - /** FSMC GPIO Configuration - PF0 ------> FSMC_A0 - PE7 ------> FSMC_D4 - PE8 ------> FSMC_D5 - PE9 ------> FSMC_D6 - PE10 ------> FSMC_D7 - PE11 ------> FSMC_D8 - PE12 ------> FSMC_D9 - PE13 ------> FSMC_D10 - PE14 ------> FSMC_D11 - PE15 ------> FSMC_D12 - PD8 ------> FSMC_D13 - PD9 ------> FSMC_D14 - PD10 ------> FSMC_D15 - PD14 ------> FSMC_D0 - PD15 ------> FSMC_D1 - PD0 ------> FSMC_D2 - PD1 ------> FSMC_D3 - PD4 ------> FSMC_NOE - PD5 ------> FSMC_NWE - PD7 ------> FSMC_NE1 - */ - GPIO_InitStruct.Pin = A0_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; - HAL_GPIO_Init(A0_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = D4_Pin|D5_Pin|D6_Pin|D7_Pin - |D8_Pin|D9_Pin|D10_Pin|D11_Pin - |D12_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; - HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = D13_Pin|D14_Pin|D15_Pin|D0_Pin - |D1_Pin|D2_Pin|D3_Pin|FMC_NOE_Pin - |FMC_NWE_Pin|FMC_NE1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; - HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); - - /* USER CODE BEGIN FSMC_MspInit 1 */ - - /* USER CODE END FSMC_MspInit 1 */ -} - -void HAL_SRAM_MspInit(SRAM_HandleTypeDef* hsram){ - /* USER CODE BEGIN SRAM_MspInit 0 */ - - /* USER CODE END SRAM_MspInit 0 */ - HAL_FSMC_MspInit(); - /* USER CODE BEGIN SRAM_MspInit 1 */ - - /* USER CODE END SRAM_MspInit 1 */ -} - -static uint32_t FSMC_DeInitialized = 0; - -static void HAL_FSMC_MspDeInit(void){ - /* USER CODE BEGIN FSMC_MspDeInit 0 */ - - /* USER CODE END FSMC_MspDeInit 0 */ - if (FSMC_DeInitialized) { - return; - } - FSMC_DeInitialized = 1; - /* Peripheral clock enable */ - __HAL_RCC_FSMC_CLK_DISABLE(); - - /** FSMC GPIO Configuration - PF0 ------> FSMC_A0 - PE7 ------> FSMC_D4 - PE8 ------> FSMC_D5 - PE9 ------> FSMC_D6 - PE10 ------> FSMC_D7 - PE11 ------> FSMC_D8 - PE12 ------> FSMC_D9 - PE13 ------> FSMC_D10 - PE14 ------> FSMC_D11 - PE15 ------> FSMC_D12 - PD8 ------> FSMC_D13 - PD9 ------> FSMC_D14 - PD10 ------> FSMC_D15 - PD14 ------> FSMC_D0 - PD15 ------> FSMC_D1 - PD0 ------> FSMC_D2 - PD1 ------> FSMC_D3 - PD4 ------> FSMC_NOE - PD5 ------> FSMC_NWE - PD7 ------> FSMC_NE1 - */ - HAL_GPIO_DeInit(A0_GPIO_Port, A0_Pin); - - HAL_GPIO_DeInit(GPIOE, D4_Pin|D5_Pin|D6_Pin|D7_Pin - |D8_Pin|D9_Pin|D10_Pin|D11_Pin - |D12_Pin); - - HAL_GPIO_DeInit(GPIOD, D13_Pin|D14_Pin|D15_Pin|D0_Pin - |D1_Pin|D2_Pin|D3_Pin|FMC_NOE_Pin - |FMC_NWE_Pin|FMC_NE1_Pin); - - /* USER CODE BEGIN FSMC_MspDeInit 1 */ - - /* USER CODE END FSMC_MspDeInit 1 */ -} - -void HAL_SRAM_MspDeInit(SRAM_HandleTypeDef* hsram){ - /* USER CODE BEGIN SRAM_MspDeInit 0 */ - - /* USER CODE END SRAM_MspDeInit 0 */ - HAL_FSMC_MspDeInit(); - /* USER CODE BEGIN SRAM_MspDeInit 1 */ - - /* USER CODE END SRAM_MspDeInit 1 */ -} - -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_it.c b/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_it.c deleted file mode 100644 index 032a55472..000000000 --- a/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_it.c +++ /dev/null @@ -1,217 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32f4xx_it.c - * @brief Interrupt Service Routines. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f4xx_hal.h" -#include "stm32f4xx_it.h" -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN TD */ - -/* USER CODE END TD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN PD */ - -/* USER CODE END PD */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN PM */ - -/* USER CODE END PM */ - -/* Private variables ---------------------------------------------------------*/ -/* USER CODE BEGIN PV */ - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -/* USER CODE BEGIN PFP */ - -/* USER CODE END PFP */ - -/* Private user code ---------------------------------------------------------*/ -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -/* External variables --------------------------------------------------------*/ -extern PCD_HandleTypeDef hpcd_USB_OTG_FS; -/* USER CODE BEGIN EV */ - -/* USER CODE END EV */ - -/******************************************************************************/ -/* Cortex-M4 Processor Interruption and Exception Handlers */ -/******************************************************************************/ -/** - * @brief This function handles Non maskable interrupt. - */ -void NMI_Handler(void) -{ - /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ - - /* USER CODE END NonMaskableInt_IRQn 0 */ - /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ - - /* USER CODE END NonMaskableInt_IRQn 1 */ -} - -/** - * @brief This function handles Hard fault interrupt. - */ -void HardFault_Handler(void) -{ - /* USER CODE BEGIN HardFault_IRQn 0 */ - - /* USER CODE END HardFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_HardFault_IRQn 0 */ - /* USER CODE END W1_HardFault_IRQn 0 */ - } -} - -/** - * @brief This function handles Memory management fault. - */ -void MemManage_Handler(void) -{ - /* USER CODE BEGIN MemoryManagement_IRQn 0 */ - - /* USER CODE END MemoryManagement_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ - /* USER CODE END W1_MemoryManagement_IRQn 0 */ - } -} - -/** - * @brief This function handles Pre-fetch fault, memory access fault. - */ -void BusFault_Handler(void) -{ - /* USER CODE BEGIN BusFault_IRQn 0 */ - - /* USER CODE END BusFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_BusFault_IRQn 0 */ - /* USER CODE END W1_BusFault_IRQn 0 */ - } -} - -/** - * @brief This function handles Undefined instruction or illegal state. - */ -void UsageFault_Handler(void) -{ - /* USER CODE BEGIN UsageFault_IRQn 0 */ - - /* USER CODE END UsageFault_IRQn 0 */ - while (1) - { - /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ - /* USER CODE END W1_UsageFault_IRQn 0 */ - } -} - -/** - * @brief This function handles System service call via SWI instruction. - */ -void SVC_Handler(void) -{ - /* USER CODE BEGIN SVCall_IRQn 0 */ - - /* USER CODE END SVCall_IRQn 0 */ - /* USER CODE BEGIN SVCall_IRQn 1 */ - - /* USER CODE END SVCall_IRQn 1 */ -} - -/** - * @brief This function handles Debug monitor. - */ -void DebugMon_Handler(void) -{ - /* USER CODE BEGIN DebugMonitor_IRQn 0 */ - - /* USER CODE END DebugMonitor_IRQn 0 */ - /* USER CODE BEGIN DebugMonitor_IRQn 1 */ - - /* USER CODE END DebugMonitor_IRQn 1 */ -} - -/** - * @brief This function handles Pendable request for system service. - */ -void PendSV_Handler(void) -{ - /* USER CODE BEGIN PendSV_IRQn 0 */ - - /* USER CODE END PendSV_IRQn 0 */ - /* USER CODE BEGIN PendSV_IRQn 1 */ - - /* USER CODE END PendSV_IRQn 1 */ -} - -// /** -// * @brief This function handles System tick timer. -// */ -// void SysTick_Handler(void) -// { -// /* USER CODE BEGIN SysTick_IRQn 0 */ - -// /* USER CODE END SysTick_IRQn 0 */ -// HAL_IncTick(); -// /* USER CODE BEGIN SysTick_IRQn 1 */ - -// /* USER CODE END SysTick_IRQn 1 */ -// } - -/******************************************************************************/ -/* STM32F4xx Peripheral Interrupt Handlers */ -/* Add here the Interrupt Handlers for the used peripherals. */ -/* For the available peripheral interrupt handler names, */ -/* please refer to the startup file (startup_stm32f4xx.s). */ -/******************************************************************************/ - -/** - * @brief This function handles USB On The Go FS global interrupt. - */ -// void OTG_FS_IRQHandler(void) -// { -// /* USER CODE BEGIN OTG_FS_IRQn 0 */ - -// /* USER CODE END OTG_FS_IRQn 0 */ -// // HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS); -// /* USER CODE BEGIN OTG_FS_IRQn 1 */ - -// /* USER CODE END OTG_FS_IRQn 1 */ -// } - -/* USER CODE BEGIN 1 */ - -/* USER CODE END 1 */ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_it.h b/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_it.h deleted file mode 100644 index 4571df2e3..000000000 --- a/ports/stm32f4/boards/stm32f412g_disco/stm32f4xx_it.h +++ /dev/null @@ -1,70 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file stm32f4xx_it.h - * @brief This file contains the headers of the interrupt handlers. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_IT_H -#define __STM32F4xx_IT_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - -/* USER CODE END EM */ - -/* Exported functions prototypes ---------------------------------------------*/ -void NMI_Handler(void); -void HardFault_Handler(void); -void MemManage_Handler(void); -void BusFault_Handler(void); -void UsageFault_Handler(void); -void SVC_Handler(void); -void DebugMon_Handler(void); -void PendSV_Handler(void); -//void SysTick_Handler(void); -//void OTG_FS_IRQHandler(void); -/* USER CODE BEGIN EFP */ - -/* USER CODE END EFP */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32F4xx_IT_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/ports/stm32f4/common-hal/busio/I2C.h b/ports/stm32f4/common-hal/busio/I2C.h index b75d15f00..6f6711167 100644 --- a/ports/stm32f4/common-hal/busio/I2C.h +++ b/ports/stm32f4/common-hal/busio/I2C.h @@ -27,8 +27,6 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_I2C_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_I2C_H -#include "nrfx_twim.h" - #include "py/obj.h" typedef struct { diff --git a/ports/stm32f4/common-hal/busio/SPI.h b/ports/stm32f4/common-hal/busio/SPI.h index 1b0de8acf..36fc0350c 100644 --- a/ports/stm32f4/common-hal/busio/SPI.h +++ b/ports/stm32f4/common-hal/busio/SPI.h @@ -27,7 +27,6 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_SPI_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_SPI_H -#include "nrfx_spim.h" #include "py/obj.h" typedef struct { diff --git a/ports/stm32f4/common-hal/busio/UART.h b/ports/stm32f4/common-hal/busio/UART.h index 58432001c..80a707f71 100644 --- a/ports/stm32f4/common-hal/busio/UART.h +++ b/ports/stm32f4/common-hal/busio/UART.h @@ -28,7 +28,6 @@ #define MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_UART_H #include "common-hal/microcontroller/Pin.h" -#include "nrfx_uarte.h" #include "py/obj.h" #include "py/ringbuf.h" diff --git a/ports/stm32f4/common-hal/digitalio/DigitalInOut.h b/ports/stm32f4/common-hal/digitalio/DigitalInOut.h index c6b3d21d2..9122ba4a1 100644 --- a/ports/stm32f4/common-hal/digitalio/DigitalInOut.h +++ b/ports/stm32f4/common-hal/digitalio/DigitalInOut.h @@ -27,7 +27,7 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_DIGITALIO_DIGITALINOUT_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_DIGITALIO_DIGITALINOUT_H -//#include "common-hal/microcontroller/Pin.h" +#include "common-hal/microcontroller/Pin.h" typedef struct { mp_obj_base_t base; diff --git a/ports/stm32f4/supervisor/internal_flash.c b/ports/stm32f4/supervisor/internal_flash.c index da9825bec..fa776ae1d 100644 --- a/ports/stm32f4/supervisor/internal_flash.c +++ b/ports/stm32f4/supervisor/internal_flash.c @@ -35,13 +35,6 @@ #include "py/runtime.h" #include "lib/oofatfs/ff.h" -// #include "peripherals/nrf/nvm.h" - -// #ifdef BLUETOOTH_SD -// #include "ble_drv.h" -// #include "nrf_sdm.h" -// #endif - /*------------------------------------------------------------------*/ /* Internal Flash API diff --git a/shared-bindings/board/__init__.c b/shared-bindings/board/__init__.c index ccf9ec5ab..9107fc57f 100644 --- a/shared-bindings/board/__init__.c +++ b/shared-bindings/board/__init__.c @@ -46,23 +46,23 @@ //| Returns the `busio.I2C` object for the board designated SDA and SCL pins. It is a singleton. //| -// #if BOARD_I2C -// mp_obj_t board_i2c(void) { -// mp_obj_t singleton = common_hal_board_get_i2c(); -// if (singleton != NULL) { -// return singleton; -// } -// assert_pin_free(DEFAULT_I2C_BUS_SDA); -// assert_pin_free(DEFAULT_I2C_BUS_SCL); -// return common_hal_board_create_i2c(); -// } -// #else -// mp_obj_t board_i2c(void) { -// mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_I2C); -// return NULL; -// } -// #endif -// MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); +#if BOARD_I2C +mp_obj_t board_i2c(void) { + mp_obj_t singleton = common_hal_board_get_i2c(); + if (singleton != NULL) { + return singleton; + } + assert_pin_free(DEFAULT_I2C_BUS_SDA); + assert_pin_free(DEFAULT_I2C_BUS_SCL); + return common_hal_board_create_i2c(); +} +#else +mp_obj_t board_i2c(void) { + mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_I2C); + return NULL; +} +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); // //| .. function:: SPI() @@ -70,48 +70,48 @@ // //| Returns the `busio.SPI` object for the board designated SCK, MOSI and MISO pins. It is a // //| singleton. // //| -// #if BOARD_SPI -// mp_obj_t board_spi(void) { -// mp_obj_t singleton = common_hal_board_get_spi(); -// if (singleton != NULL) { -// return singleton; -// } -// assert_pin_free(DEFAULT_SPI_BUS_SCK); -// assert_pin_free(DEFAULT_SPI_BUS_MOSI); -// assert_pin_free(DEFAULT_SPI_BUS_MISO); -// return common_hal_board_create_spi(); -// } -// #else -// mp_obj_t board_spi(void) { -// mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); -// return NULL; -// } -// #endif -// MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi); +#if BOARD_SPI +mp_obj_t board_spi(void) { + mp_obj_t singleton = common_hal_board_get_spi(); + if (singleton != NULL) { + return singleton; + } + assert_pin_free(DEFAULT_SPI_BUS_SCK); + assert_pin_free(DEFAULT_SPI_BUS_MOSI); + assert_pin_free(DEFAULT_SPI_BUS_MISO); + return common_hal_board_create_spi(); +} +#else +mp_obj_t board_spi(void) { + mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); + return NULL; +} +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi); // //| .. function:: UART() // //| // //| Returns the `busio.UART` object for the board designated TX and RX pins. It is a singleton. // //| -// #if BOARD_UART -// mp_obj_t board_uart(void) { -// mp_obj_t singleton = common_hal_board_get_uart(); -// if (singleton != NULL) { -// return singleton; -// } +#if BOARD_UART +mp_obj_t board_uart(void) { + mp_obj_t singleton = common_hal_board_get_uart(); + if (singleton != NULL) { + return singleton; + } -// assert_pin_free(DEFAULT_UART_BUS_RX); -// assert_pin_free(DEFAULT_UART_BUS_TX); + assert_pin_free(DEFAULT_UART_BUS_RX); + assert_pin_free(DEFAULT_UART_BUS_TX); -// return common_hal_board_create_uart(); -// } -// #else -// mp_obj_t board_uart(void) { -// mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); -// return NULL; -// } -// #endif -// MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); + return common_hal_board_create_uart(); +} +#else +mp_obj_t board_uart(void) { + mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); + return NULL; +} +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); const mp_obj_module_t board_module = { .base = { &mp_type_module }, diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index b29e9df61..5a1dead78 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -24,18 +24,20 @@ * THE SOFTWARE. */ -// #include "shared-bindings/busio/I2C.h" -// #include "shared-bindings/busio/SPI.h" -// #include "shared-bindings/busio/UART.h" - #include "shared-bindings/microcontroller/Pin.h" #include "supervisor/shared/translate.h" #include "mpconfigboard.h" #include "py/runtime.h" -// #ifdef CIRCUITPY_DISPLAYIO -// #include "shared-module/displayio/__init__.h" -// #endif +#if CIRCUITPY_BUSIO +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/busio/UART.h" +#endif + +#if CIRCUITPY_DISPLAYIO +#include "shared-module/displayio/__init__.h" +#endif #if BOARD_I2C mp_obj_t common_hal_board_get_i2c(void) { diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index a2a4c30ac..0e256cb5e 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -47,7 +47,6 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t* // Wait until interface is ready, timeout = 2 seconds uint64_t end_ticks = ticks_ms + 2000; - while ( (ticks_ms < end_ticks) && !tud_hid_generic_ready() ) { } if ( !tud_hid_generic_ready() ) { diff --git a/supervisor/shared/memory.c b/supervisor/shared/memory.c index c9c4bc2d5..11133415d 100755 --- a/supervisor/shared/memory.c +++ b/supervisor/shared/memory.c @@ -118,5 +118,5 @@ supervisor_allocation* allocate_memory(uint32_t length, bool high) { } void supervisor_move_memory(void) { - //supervisor_display_move_memory(); + supervisor_display_move_memory(); } diff --git a/supervisor/shared/micropython.c b/supervisor/shared/micropython.c index db9864793..245db11d4 100644 --- a/supervisor/shared/micropython.c +++ b/supervisor/shared/micropython.c @@ -30,7 +30,7 @@ #include "lib/oofatfs/ff.h" #include "py/mpconfig.h" -//#include "supervisor/shared/status_leds.h" +#include "supervisor/shared/status_leds.h" int mp_hal_stdin_rx_chr(void) { for (;;) { @@ -38,14 +38,14 @@ int mp_hal_stdin_rx_chr(void) { MICROPY_VM_HOOK_LOOP #endif if (serial_bytes_available()) { - //toggle_rx_led(); + toggle_rx_led(); return serial_read(); } } } void mp_hal_stdout_tx_strn(const char *str, size_t len) { - //toggle_tx_led(); + toggle_tx_led(); #ifdef CIRCUITPY_BOOT_OUTPUT_FILE if (boot_output_file != NULL) { diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 33a9e660e..97b2d8d42 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -59,16 +59,16 @@ safe_mode_t wait_for_safe_mode_reset(void) { common_hal_digitalio_digitalinout_construct(&status_led, MICROPY_HW_LED_STATUS); common_hal_digitalio_digitalinout_switch_to_output(&status_led, true, DRIVE_MODE_PUSH_PULL); #endif - // uint64_t start_ticks = 0;//ticks_ms; - // uint64_t diff = 0; - // while (diff < 700) { - // #ifdef MICROPY_HW_LED_STATUS - // // Blink on for 100, off for 100, on for 100, off for 100 and on for 200 - // common_hal_digitalio_digitalinout_set_value(&status_led, diff > 100 && diff / 100 != 2 && diff / 100 != 4); - // #endif - // diff = 0 - start_ticks; - // //diff = ticks_ms - start_ticks; - // } + uint64_t start_ticks = ticks_ms; + uint64_t diff = 0; + while (diff < 700) { + #ifdef MICROPY_HW_LED_STATUS + // Blink on for 100, off for 100, on for 100, off for 100 and on for 200 + common_hal_digitalio_digitalinout_set_value(&status_led, diff > 100 && diff / 100 != 2 && diff / 100 != 4); + #endif + diff = 0 - start_ticks; + //diff = ticks_ms - start_ticks; + } #ifdef MICROPY_HW_LED_STATUS common_hal_digitalio_digitalinout_deinit(&status_led); #endif diff --git a/supervisor/shared/status_leds.c b/supervisor/shared/status_leds.c index d99853ceb..672242a96 100644 --- a/supervisor/shared/status_leds.c +++ b/supervisor/shared/status_leds.c @@ -26,8 +26,10 @@ #include "supervisor/shared/status_leds.h" +#if CIRCUITPY_DIGITALIO #include "common-hal/digitalio/DigitalInOut.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#endif #ifdef MICROPY_HW_LED_RX digitalio_digitalinout_obj_t rx_led; diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index b3c16f4ae..0678a3a3f 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -40,10 +40,8 @@ extern uint16_t usb_serial_number[1 + COMMON_HAL_MCU_PROCESSOR_UID_LENGTH * 2]; void load_serial_number(void) { // create serial number based on device unique id - -//LUCIAN: edited to fake a serial number - uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH] = {'0','1','2','3'}; - //common_hal_mcu_processor_get_uid(raw_id); + uint8_t raw_id[COMMON_HAL_MCU_PROCESSOR_UID_LENGTH]; + common_hal_mcu_processor_get_uid(raw_id); static const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 4ea3a8260..b4d7e9d50 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -2,20 +2,17 @@ SRC_SUPERVISOR = \ main.c \ supervisor/port.c \ supervisor/shared/autoreload.c \ + supervisor/shared/display.c \ supervisor/shared/filesystem.c \ supervisor/shared/flash.c \ supervisor/shared/micropython.c \ supervisor/shared/rgb_led_status.c \ + supervisor/shared/safe_mode.c \ supervisor/shared/stack.c \ + supervisor/shared/status_leds.c \ supervisor/shared/safe_mode.c \ - supervisor/shared/translate.c - -#bug, not conditional -# supervisor/shared/display.c \ -# supervisor/shared/status_leds.c \ -# supervisor/shared/safe_mode.c \ - - + supervisor/shared/translate.c \ + ifndef $(NO_USB) NO_USB = $(wildcard supervisor/usb.c) endif -- cgit v1.2.3 From c921f6637f55936726a880f225812302a3fdf0d1 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 24 Jul 2019 16:46:31 +0700 Subject: update tinyusb lib to 0.5.x --- lib/tinyusb | 2 +- ports/nrf/Makefile | 1 + shared-module/usb_hid/Device.c | 10 ++-- shared-module/usb_midi/PortOut.c | 2 +- supervisor/shared/usb/tusb_config.h | 2 +- supervisor/shared/usb/usb_desc.c | 43 ++++++++++------ supervisor/shared/usb/usb_desc.h | 43 ---------------- supervisor/shared/usb/usb_msc_flash.c | 96 +++++++++++++++++++---------------- 8 files changed, 90 insertions(+), 109 deletions(-) delete mode 100644 supervisor/shared/usb/usb_desc.h (limited to 'shared-module') diff --git a/lib/tinyusb b/lib/tinyusb index 0848c462b..1ee9ef4f2 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 0848c462b3e431a9da42e96537d2b597a4579636 +Subproject commit 1ee9ef4f2b7c6acfab6c398a4f57ca22036958f7 diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 83f87536b..9da2c498d 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -81,6 +81,7 @@ INC += -I./nrfx INC += -I./nrfx/hal INC += -I./nrfx/mdk INC += -I./nrfx/drivers/include +INC += -I./nrfx/drivers/src INC += -I./bluetooth INC += -I./peripherals INC += -I../../lib/mp-readline diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index 0e256cb5e..a5a57419c 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -47,15 +47,15 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t* // Wait until interface is ready, timeout = 2 seconds uint64_t end_ticks = ticks_ms + 2000; - while ( (ticks_ms < end_ticks) && !tud_hid_generic_ready() ) { } + while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) { } - if ( !tud_hid_generic_ready() ) { + if ( !tud_hid_ready() ) { mp_raise_msg(&mp_type_OSError, translate("USB Busy")); } memcpy(self->report_buffer, report, len); - if ( !tud_hid_generic_report(self->report_id, self->report_buffer, len) ) { + if ( !tud_hid_report(self->report_id, self->report_buffer, len) ) { mp_raise_msg(&mp_type_OSError, translate("USB Error")); } } @@ -70,7 +70,7 @@ static usb_hid_device_obj_t* get_hid_device(uint8_t report_id) { } // Callbacks invoked when receive Get_Report request through control endpoint -uint16_t tud_hid_generic_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) { +uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) { // only support Input Report if ( report_type != HID_REPORT_TYPE_INPUT ) return 0; @@ -80,7 +80,7 @@ uint16_t tud_hid_generic_get_report_cb(uint8_t report_id, hid_report_type_t repo } // Callbacks invoked when receive Set_Report request through control endpoint -void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { +void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { usb_hid_device_obj_t* hid_device = get_hid_device(report_id); if ( report_type == HID_REPORT_TYPE_OUTPUT ) { diff --git a/shared-module/usb_midi/PortOut.c b/shared-module/usb_midi/PortOut.c index 99a4fad43..0b37dcfd4 100644 --- a/shared-module/usb_midi/PortOut.c +++ b/shared-module/usb_midi/PortOut.c @@ -33,5 +33,5 @@ size_t common_hal_usb_midi_portout_write(usb_midi_portout_obj_t *self, const uin } bool common_hal_usb_midi_portout_ready_to_tx(usb_midi_portout_obj_t *self) { - return tud_midi_connected(); + return tud_midi_mounted(); } diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index 301805275..ad5825b6c 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -107,7 +107,7 @@ // USB RAM PLACEMENT //--------------------------------------------------------------------+ #define CFG_TUSB_ATTR_USBRAM -#define CFG_TUSB_MEM_ALIGN ATTR_ALIGNED(4) +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) #ifdef __cplusplus diff --git a/supervisor/shared/usb/usb_desc.c b/supervisor/shared/usb/usb_desc.c index 5a0de1ffc..48f2da3d3 100644 --- a/supervisor/shared/usb/usb_desc.c +++ b/supervisor/shared/usb/usb_desc.c @@ -24,23 +24,36 @@ * THE SOFTWARE. */ -#include "supervisor/shared/usb/usb_desc.h" +#include "lib/tinyusb/src/tusb.h" #include "shared-module/usb_hid/Device.h" #include "genhdr/autogen_usb_descriptor.h" -// tud_desc_set is required by tinyusb stack -tud_desc_set_t tud_desc_set = -{ - .device = &usb_desc_dev, - .config = &usb_desc_cfg, - .string_arr = (uint8_t const **) string_desc_arr, - .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]), +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void) { + return usb_desc_dev; +} - .hid_report = - { - .generic = hid_report_descriptor, - .boot_keyboard = NULL, - .boot_mouse = NULL - } -}; +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { + (void) index; // for multiple configurations + return usb_desc_cfg; +} + + +// Invoked when received GET HID REPORT DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_hid_descriptor_report_cb(void) { + return hid_report_descriptor; +} + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index) { + uint8_t const max_index = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]); + return (index < max_index) ? string_desc_arr[index] : NULL; +} diff --git a/supervisor/shared/usb/usb_desc.h b/supervisor/shared/usb/usb_desc.h deleted file mode 100644 index 250147aa6..000000000 --- a/supervisor/shared/usb/usb_desc.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 hathach for Adafruit Industries - * - * 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. - */ - -#ifndef USB_DESC_H_ -#define USB_DESC_H_ - -#include "lib/tinyusb/src/tusb.h" - -#ifdef __cplusplus - extern "C" { -#endif - -// Descriptors set used by tinyusb stack -extern tud_desc_set_t tud_desc_set; - -#ifdef __cplusplus - } -#endif - -#endif /* USB_DESC_H_ */ diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index f6f0fa9c3..205cb7b50 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -59,59 +59,18 @@ static fs_user_mount_t* get_vfs(int lun) { } // Callback invoked when received an SCSI command not in built-in list below -// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE +// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE // - READ10 and WRITE10 have their own callbacks int32_t tud_msc_scsi_cb (uint8_t lun, const uint8_t scsi_cmd[16], void* buffer, uint16_t bufsize) { const void* response = NULL; int32_t resplen = 0; switch ( scsi_cmd[0] ) { - case SCSI_CMD_TEST_UNIT_READY: - // Command that host uses to check our readiness before sending other commands - resplen = 0; - if (lun > 1) { - resplen = -1; - } else { - fs_user_mount_t* current_mount = get_vfs(lun); - if (current_mount == NULL) { - resplen = -1; - } - if (ejected[lun]) { - resplen = -1; - } - } - break; - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: // Host is about to read/write etc ... better not to disconnect disk resplen = 0; break; - case SCSI_CMD_START_STOP_UNIT: - { - // Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power - const scsi_start_stop_unit_t* start_stop = (const scsi_start_stop_unit_t*) scsi_cmd; - // Start bit = 0 : low power mode, if load_eject = 1 : unmount disk storage as well - // Start bit = 1 : Ready mode, if load_eject = 1 : mount disk storage - resplen = 0; - if (start_stop->load_eject == 1) { - if (lun > 1) { - resplen = -1; - } else { - fs_user_mount_t* current_mount = get_vfs(lun); - if (current_mount == NULL) { - resplen = -1; - } - if (disk_ioctl(current_mount, CTRL_SYNC, NULL) != RES_OK) { - resplen = -1; - } else { - ejected[lun] = true; - } - } - } - } - break; - default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); @@ -127,7 +86,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, const uint8_t scsi_cmd[16], void* buffer, } // copy response to stack's buffer if any - if ( response && resplen ) { + if ( response && (resplen > 0) ) { memcpy(buffer, response, resplen); } @@ -206,3 +165,54 @@ void tud_msc_write10_complete_cb (uint8_t lun) { // This write is complete, start the autoreload clock. autoreload_start(); } + +// Invoked when received SCSI_CMD_INQUIRY +// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { + (void) lun; + + memcpy(vendor_id , CFG_TUD_MSC_VENDOR , strlen(CFG_TUD_MSC_VENDOR)); + memcpy(product_id , CFG_TUD_MSC_PRODUCT , strlen(CFG_TUD_MSC_PRODUCT)); + memcpy(product_rev, CFG_TUD_MSC_PRODUCT_REV, strlen(CFG_TUD_MSC_PRODUCT_REV)); +} + +// Invoked when received Test Unit Ready command. +// return true allowing host to read/write this LUN e.g SD card inserted +bool tud_msc_test_unit_ready_cb(uint8_t lun) { + if (lun > 1) { + return false; + } + + fs_user_mount_t* current_mount = get_vfs(lun); + if (current_mount == NULL) { + return false; + } + if (ejected[lun]) { + return false; + } + + return true; +} + +// Invoked when received Start Stop Unit command +// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage +// - Start = 1 : active mode, if load_eject = 1 : load disk storage +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { + if (load_eject) { + if (lun > 1) { + return false; + } else { + fs_user_mount_t* current_mount = get_vfs(lun); + if (current_mount == NULL) { + return false; + } + if (disk_ioctl(current_mount, CTRL_SYNC, NULL) != RES_OK) { + return false; + } else { + ejected[lun] = true; + } + } + } + + return true; +} -- cgit v1.2.3 From 6b44e40ee8dba415213468afe14f7202b42ec429 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 24 Jul 2019 20:57:32 -0500 Subject: audiocore: Factor from audioio When nrf pwm audio is introduced, it will be called `audiopwmio`. To enable code sharing with the existing (dac-based) `audioio`, factor the sample and mixer types to `audiocore`. INCOMPATIBLE CHANGE: Now, `Mixer`, `RawSample` and `WaveFile` must be imported from `audiocore`, not `audioio`. --- ports/atmel-samd/audio_dma.c | 4 +- ports/atmel-samd/audio_dma.h | 4 +- ports/atmel-samd/common-hal/audiobusio/I2SOut.c | 2 +- py/circuitpy_defns.mk | 10 +- py/circuitpy_mpconfig.h | 8 + py/circuitpy_mpconfig.mk | 5 + shared-bindings/audiocore/Mixer.c | 252 +++++++++++++++++ shared-bindings/audiocore/Mixer.h | 52 ++++ shared-bindings/audiocore/RawSample.c | 187 +++++++++++++ shared-bindings/audiocore/RawSample.h | 44 +++ shared-bindings/audiocore/WaveFile.c | 202 ++++++++++++++ shared-bindings/audiocore/WaveFile.h | 47 ++++ shared-bindings/audiocore/__init__.c | 69 +++++ shared-bindings/audiocore/__init__.h | 34 +++ shared-bindings/audioio/AudioOut.c | 2 +- shared-bindings/audioio/AudioOut.h | 2 +- shared-bindings/audioio/Mixer.c | 252 ----------------- shared-bindings/audioio/Mixer.h | 52 ---- shared-bindings/audioio/RawSample.c | 187 ------------- shared-bindings/audioio/RawSample.h | 45 ---- shared-bindings/audioio/WaveFile.c | 202 -------------- shared-bindings/audioio/WaveFile.h | 46 ---- shared-bindings/audioio/__init__.c | 17 +- shared-bindings/index.rst | 1 + shared-module/audiocore/Mixer.c | 341 ++++++++++++++++++++++++ shared-module/audiocore/Mixer.h | 75 ++++++ shared-module/audiocore/RawSample.c | 94 +++++++ shared-module/audiocore/RawSample.h | 59 ++++ shared-module/audiocore/WaveFile.c | 268 +++++++++++++++++++ shared-module/audiocore/WaveFile.h | 70 +++++ shared-module/audiocore/__init__.c | 125 +++++++++ shared-module/audiocore/__init__.h | 53 ++++ shared-module/audioio/Mixer.c | 341 ------------------------ shared-module/audioio/Mixer.h | 75 ------ shared-module/audioio/RawSample.c | 94 ------- shared-module/audioio/RawSample.h | 59 ---- shared-module/audioio/WaveFile.c | 268 ------------------- shared-module/audioio/WaveFile.h | 70 ----- shared-module/audioio/__init__.c | 125 --------- shared-module/audioio/__init__.h | 23 +- 40 files changed, 2009 insertions(+), 1857 deletions(-) create mode 100644 shared-bindings/audiocore/Mixer.c create mode 100644 shared-bindings/audiocore/Mixer.h create mode 100644 shared-bindings/audiocore/RawSample.c create mode 100644 shared-bindings/audiocore/RawSample.h create mode 100644 shared-bindings/audiocore/WaveFile.c create mode 100644 shared-bindings/audiocore/WaveFile.h create mode 100644 shared-bindings/audiocore/__init__.c create mode 100644 shared-bindings/audiocore/__init__.h delete mode 100644 shared-bindings/audioio/Mixer.c delete mode 100644 shared-bindings/audioio/Mixer.h delete mode 100644 shared-bindings/audioio/RawSample.c delete mode 100644 shared-bindings/audioio/RawSample.h delete mode 100644 shared-bindings/audioio/WaveFile.c delete mode 100644 shared-bindings/audioio/WaveFile.h create mode 100644 shared-module/audiocore/Mixer.c create mode 100644 shared-module/audiocore/Mixer.h create mode 100644 shared-module/audiocore/RawSample.c create mode 100644 shared-module/audiocore/RawSample.h create mode 100644 shared-module/audiocore/WaveFile.c create mode 100644 shared-module/audiocore/WaveFile.h create mode 100644 shared-module/audiocore/__init__.c create mode 100644 shared-module/audiocore/__init__.h delete mode 100644 shared-module/audioio/Mixer.c delete mode 100644 shared-module/audioio/Mixer.h delete mode 100644 shared-module/audioio/RawSample.c delete mode 100644 shared-module/audioio/RawSample.h delete mode 100644 shared-module/audioio/WaveFile.c delete mode 100644 shared-module/audioio/WaveFile.h (limited to 'shared-module') diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index 68d6f182d..6b5eeddcc 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -29,8 +29,8 @@ #include "samd/events.h" #include "samd/dma.h" -#include "shared-bindings/audioio/RawSample.h" -#include "shared-bindings/audioio/WaveFile.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/audiocore/WaveFile.h" #include "py/mpstate.h" #include "py/runtime.h" diff --git a/ports/atmel-samd/audio_dma.h b/ports/atmel-samd/audio_dma.h index 041d675a2..53173c277 100644 --- a/ports/atmel-samd/audio_dma.h +++ b/ports/atmel-samd/audio_dma.h @@ -29,8 +29,8 @@ #include "extmod/vfs_fat.h" #include "py/obj.h" -#include "shared-module/audioio/RawSample.h" -#include "shared-module/audioio/WaveFile.h" +#include "shared-module/audiocore/RawSample.h" +#include "shared-module/audiocore/WaveFile.h" typedef struct { mp_obj_t sample; diff --git a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c index 20934bed4..05a6aaf7b 100644 --- a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c +++ b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c @@ -33,7 +33,7 @@ #include "py/runtime.h" #include "common-hal/audiobusio/I2SOut.h" #include "shared-bindings/audiobusio/I2SOut.h" -#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/microcontroller/Pin.h" #include "supervisor/shared/translate.h" diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 93ca4deb9..bdefc18cc 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -108,6 +108,9 @@ endif ifeq ($(CIRCUITPY_AUDIOIO),1) SRC_PATTERNS += audioio/% endif +ifeq ($(CIRCUITPY_AUDIOCORE),1) +SRC_PATTERNS += audiocore/% +endif ifeq ($(CIRCUITPY_BITBANGIO),1) SRC_PATTERNS += bitbangio/% endif @@ -301,9 +304,10 @@ $(filter $(SRC_PATTERNS), \ _stage/Text.c \ _stage/__init__.c \ audioio/__init__.c \ - audioio/Mixer.c \ - audioio/RawSample.c \ - audioio/WaveFile.c \ + audiocore/__init__.c \ + audiocore/Mixer.c \ + audiocore/RawSample.c \ + audiocore/WaveFile.c \ bitbangio/I2C.c \ bitbangio/OneWire.c \ bitbangio/SPI.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 2026185ef..3440eb052 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -230,6 +230,13 @@ extern const struct _mp_obj_module_t audiobusio_module; #define AUDIOBUSIO_MODULE #endif +#if CIRCUITPY_AUDIOCORE +#define AUDIOCORE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiocore), (mp_obj_t)&audiocore_module }, +extern const struct _mp_obj_module_t audiocore_module; +#else +#define AUDIOCORE_MODULE +#endif + #if CIRCUITPY_AUDIOIO #define AUDIOIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module }, extern const struct _mp_obj_module_t audioio_module; @@ -564,6 +571,7 @@ extern const struct _mp_obj_module_t ustack_module; #define MICROPY_PORT_BUILTIN_MODULES_STRONG_LINKS \ ANALOGIO_MODULE \ AUDIOBUSIO_MODULE \ + AUDIOCORE_MODULE \ AUDIOIO_MODULE \ BITBANGIO_MODULE \ BLEIO_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 47303a73a..1c1a4c8ea 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -61,6 +61,11 @@ CIRCUITPY_AUDIOIO = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) +ifndef CIRCUITPY_AUDIOCORE +CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOIO) +endif +CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE) + ifndef CIRCUITPY_BITBANGIO CIRCUITPY_BITBANGIO = $(CIRCUITPY_FULL_BUILD) endif diff --git a/shared-bindings/audiocore/Mixer.c b/shared-bindings/audiocore/Mixer.c new file mode 100644 index 000000000..b2f0a3fda --- /dev/null +++ b/shared-bindings/audiocore/Mixer.c @@ -0,0 +1,252 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/audiocore/Mixer.h" + +#include + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audioio +//| +//| :class:`Mixer` -- Mixes one or more audio samples together +//| =========================================================== +//| +//| Mixer mixes multiple samples into one sample. +//| +//| .. class:: Mixer(channel_count=2, buffer_size=1024) +//| +//| Create a Mixer object that can mix multiple channels with the same sample rate. +//| +//| :param int channel_count: The maximum number of samples to mix at once +//| :param int buffer_size: The total size in bytes of the buffers to mix into +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audioio +//| import digitalio +//| +//| # Required for CircuitPlayground Express +//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) +//| speaker_enable.switch_to_output(value=True) +//| +//| music = audioio.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) +//| drum = audioio.WaveFile(open("drum.wav", "rb")) +//| mixer = audioio.Mixer(voice_count=2, sample_rate=16000, channel_count=1, bits_per_sample=16, samples_signed=True) +//| a = audioio.AudioOut(board.A0) +//| +//| print("playing") +//| a.play(mixer) +//| mixer.play(music, voice=0) +//| while mixer.playing: +//| mixer.play(drum, voice=1) +//| time.sleep(1) +//| print("stopped") +//| +STATIC mp_obj_t audioio_mixer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_voice_count, ARG_buffer_size, ARG_channel_count, ARG_bits_per_sample, ARG_samples_signed, ARG_sample_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t voice_count = args[ARG_voice_count].u_int; + if (voice_count < 1 || voice_count > 255) { + mp_raise_ValueError(translate("Invalid voice count")); + } + + mp_int_t channel_count = args[ARG_channel_count].u_int; + if (channel_count < 1 || channel_count > 2) { + mp_raise_ValueError(translate("Invalid channel count")); + } + mp_int_t sample_rate = args[ARG_sample_rate].u_int; + if (sample_rate < 1) { + mp_raise_ValueError(translate("Sample rate must be positive")); + } + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); + } + audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, audioio_mixer_voice_t, voice_count); + self->base.type = &audioio_mixer_type; + common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the Mixer and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audioio_mixer_deinit(mp_obj_t self_in) { + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audioio_mixer_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_deinit_obj, audioio_mixer_deinit); + +STATIC void check_for_deinit(audioio_mixer_obj_t *self) { + if (common_hal_audioio_mixer_deinited(self)) { + raise_deinited_error(); + } +} + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audioio_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audioio_mixer_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer___exit___obj, 4, 4, audioio_mixer_obj___exit__); + + +//| .. method:: play(sample, *, voice=0, loop=False) +//| +//| Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. +//| +//| The sample must match the Mixer's encoding settings given in the constructor. +//| +STATIC mp_obj_t audioio_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_voice, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_voice, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audioio_mixer_play(self, sample, args[ARG_voice].u_int, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_play_obj, 1, audioio_mixer_obj_play); + +//| .. method:: stop_voice(voice=0) +//| +//| Stops playback of the sample on the given voice. +//| +STATIC mp_obj_t audioio_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_voice }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, + }; + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_stop_voice_obj, 1, audioio_mixer_obj_stop_voice); + +//| .. attribute:: playing +//| +//| True when any voice is being output. (read-only) +//| +STATIC mp_obj_t audioio_mixer_obj_get_playing(mp_obj_t self_in) { + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_playing_obj, audioio_mixer_obj_get_playing); + +const mp_obj_property_t audioio_mixer_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixer_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: sample_rate +//| +//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). +//| +STATIC mp_obj_t audioio_mixer_obj_get_sample_rate(mp_obj_t self_in) { + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_mixer_get_sample_rate(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_sample_rate_obj, audioio_mixer_obj_get_sample_rate); + + +const mp_obj_property_t audioio_mixer_sample_rate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixer_get_sample_rate_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t audioio_mixer_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixer___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixer_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop_voice), MP_ROM_PTR(&audioio_mixer_stop_voice_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_mixer_sample_rate_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audioio_mixer_locals_dict, audioio_mixer_locals_dict_table); + +const mp_obj_type_t audioio_mixer_type = { + { &mp_type_type }, + .name = MP_QSTR_Mixer, + .make_new = audioio_mixer_make_new, + .locals_dict = (mp_obj_dict_t*)&audioio_mixer_locals_dict, +}; diff --git a/shared-bindings/audiocore/Mixer.h b/shared-bindings/audiocore/Mixer.h new file mode 100644 index 000000000..ef12f9a70 --- /dev/null +++ b/shared-bindings/audiocore/Mixer.h @@ -0,0 +1,52 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H + +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/audiocore/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" + +extern const mp_obj_type_t audioio_mixer_type; + +void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, + uint8_t voice_count, + uint32_t buffer_size, + uint8_t bits_per_sample, + bool samples_signed, + uint8_t channel_count, + uint32_t sample_rate); + +void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self); +bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self); +void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, uint8_t voice, bool loop); +void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice); + +bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); +uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H diff --git a/shared-bindings/audiocore/RawSample.c b/shared-bindings/audiocore/RawSample.c new file mode 100644 index 000000000..912b48bfb --- /dev/null +++ b/shared-bindings/audiocore/RawSample.c @@ -0,0 +1,187 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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 + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audioio +//| +//| :class:`RawSample` -- A raw audio sample buffer +//| ======================================================== +//| +//| An in-memory sound sample +//| +//| .. class:: RawSample(buffer, *, channel_count=1, sample_rate=8000) +//| +//| Create a RawSample based on the given buffer of signed values. If channel_count is more than +//| 1 then each channel's samples should alternate. In other words, for a two channel buffer, the +//| first sample will be for channel 1, the second sample will be for channel two, the third for +//| channel 1 and so on. +//| +//| :param array buffer: An `array.array` with samples +//| :param int channel_count: The number of channels in the buffer +//| :param int sample_rate: The desired playback sample rate +//| +//| Simple 8ksps 440 Hz sin wave:: +//| +//| import audioio +//| import board +//| import array +//| import time +//| import math +//| +//| # Generate one period of sine wav. +//| length = 8000 // 440 +//| sine_wave = array.array("h", [0] * length) +//| for i in range(length): +//| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15)) +//| +//| dac = audioio.AudioOut(board.SPEAKER) +//| sine_wave = audioio.RawSample(sine_wave) +//| dac.play(sine_wave, loop=True) +//| time.sleep(1) +//| dac.stop() +//| +STATIC mp_obj_t audioio_rawsample_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_channel_count, ARG_sample_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1 } }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + audioio_rawsample_obj_t *self = m_new_obj(audioio_rawsample_obj_t); + self->base.type = &audioio_rawsample_type; + mp_buffer_info_t bufinfo; + if (mp_get_buffer(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ)) { + uint8_t bytes_per_sample = 1; + bool signed_samples = bufinfo.typecode == 'b' || bufinfo.typecode == 'h'; + if (bufinfo.typecode == 'h' || bufinfo.typecode == 'H') { + bytes_per_sample = 2; + } else if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + mp_raise_ValueError(translate("sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or 'B'")); + } + common_hal_audioio_rawsample_construct(self, ((uint8_t*)bufinfo.buf), bufinfo.len, + bytes_per_sample, signed_samples, args[ARG_channel_count].u_int, + args[ARG_sample_rate].u_int); + } else { + mp_raise_TypeError(translate("buffer must be a bytes-like object")); + } + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the AudioOut and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audioio_rawsample_deinit(mp_obj_t self_in) { + audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audioio_rawsample_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_deinit_obj, audioio_rawsample_deinit); + +STATIC void check_for_deinit(audioio_rawsample_obj_t *self) { + if (common_hal_audioio_rawsample_deinited(self)) { + raise_deinited_error(); + } +} + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audioio_rawsample_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audioio_rawsample_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_rawsample___exit___obj, 4, 4, audioio_rawsample_obj___exit__); + +//| .. attribute:: sample_rate +//| +//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). +//| When the sample is looped, this can change the pitch output without changing the underlying +//| sample. This will not change the sample rate of any active playback. Call ``play`` again to +//| change it. +//| +STATIC mp_obj_t audioio_rawsample_obj_get_sample_rate(mp_obj_t self_in) { + audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_rawsample_get_sample_rate(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_get_sample_rate_obj, audioio_rawsample_obj_get_sample_rate); + +STATIC mp_obj_t audioio_rawsample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { + audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_audioio_rawsample_set_sample_rate(self, mp_obj_get_int(sample_rate)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audioio_rawsample_set_sample_rate_obj, audioio_rawsample_obj_set_sample_rate); + +const mp_obj_property_t audioio_rawsample_sample_rate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_rawsample_get_sample_rate_obj, + (mp_obj_t)&audioio_rawsample_set_sample_rate_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_rawsample_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_rawsample___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_rawsample_sample_rate_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audioio_rawsample_locals_dict, audioio_rawsample_locals_dict_table); + +const mp_obj_type_t audioio_rawsample_type = { + { &mp_type_type }, + .name = MP_QSTR_RawSample, + .make_new = audioio_rawsample_make_new, + .locals_dict = (mp_obj_dict_t*)&audioio_rawsample_locals_dict, +}; diff --git a/shared-bindings/audiocore/RawSample.h b/shared-bindings/audiocore/RawSample.h new file mode 100644 index 000000000..b02778cad --- /dev/null +++ b/shared-bindings/audiocore/RawSample.h @@ -0,0 +1,44 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H + +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/audiocore/RawSample.h" + +extern const mp_obj_type_t audioio_rawsample_type; + +void common_hal_audioio_rawsample_construct(audioio_rawsample_obj_t* self, + uint8_t* buffer, uint32_t len, uint8_t bytes_per_sample, bool samples_signed, + uint8_t channel_count, uint32_t sample_rate); + +void common_hal_audioio_rawsample_deinit(audioio_rawsample_obj_t* self); +bool common_hal_audioio_rawsample_deinited(audioio_rawsample_obj_t* self); +uint32_t common_hal_audioio_rawsample_get_sample_rate(audioio_rawsample_obj_t* self); +void common_hal_audioio_rawsample_set_sample_rate(audioio_rawsample_obj_t* self, uint32_t sample_rate); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c new file mode 100644 index 000000000..4c1993b7c --- /dev/null +++ b/shared-bindings/audiocore/WaveFile.c @@ -0,0 +1,202 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 + +#include "lib/utils/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/audiocore/WaveFile.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audioio +//| +//| :class:`WaveFile` -- Load a wave file for audio playback +//| ======================================================== +//| +//| A .wav file prepped for audio playback. Only mono and stereo files are supported. Samples must +//| be 8 bit unsigned or 16 bit signed. +//| +//| .. class:: WaveFile(file) +//| +//| Load a .wav file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`. +//| +//| :param typing.BinaryIO file: Already opened wave file +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audioio +//| import digitalio +//| +//| # Required for CircuitPlayground Express +//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) +//| speaker_enable.switch_to_output(value=True) +//| +//| data = open("cplay-5.1-16bit-16khz.wav", "rb") +//| wav = audioio.WaveFile(data) +//| a = audioio.AudioOut(board.A0) +//| +//| print("playing") +//| a.play(wav) +//| while a.playing: +//| pass +//| print("stopped") +//| +STATIC mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 1, 1, false); + + audioio_wavefile_obj_t *self = m_new_obj(audioio_wavefile_obj_t); + self->base.type = &audioio_wavefile_type; + if (MP_OBJ_IS_TYPE(args[0], &mp_type_fileio)) { + common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0])); + } else { + mp_raise_TypeError(translate("file must be a file opened in byte mode")); + } + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the WaveFile and releases all memory resources for reuse. +//| +STATIC mp_obj_t audioio_wavefile_deinit(mp_obj_t self_in) { + audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audioio_wavefile_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_deinit_obj, audioio_wavefile_deinit); + +STATIC void check_for_deinit(audioio_wavefile_obj_t *self) { + if (common_hal_audioio_wavefile_deinited(self)) { + raise_deinited_error(); + } +} + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audioio_wavefile_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audioio_wavefile_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_wavefile___exit___obj, 4, 4, audioio_wavefile_obj___exit__); + +//| .. attribute:: sample_rate +//| +//| 32 bit value that dictates how quickly samples are loaded into the DAC +//| in Hertz (cycles per second). When the sample is looped, this can change +//| the pitch output without changing the underlying sample. +//| +STATIC mp_obj_t audioio_wavefile_obj_get_sample_rate(mp_obj_t self_in) { + audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_sample_rate(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_sample_rate_obj, audioio_wavefile_obj_get_sample_rate); + +STATIC mp_obj_t audioio_wavefile_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { + audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_audioio_wavefile_set_sample_rate(self, mp_obj_get_int(sample_rate)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audioio_wavefile_set_sample_rate_obj, audioio_wavefile_obj_set_sample_rate); + +const mp_obj_property_t audioio_wavefile_sample_rate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_wavefile_get_sample_rate_obj, + (mp_obj_t)&audioio_wavefile_set_sample_rate_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: bits_per_sample +//| +//| Bits per sample. (read only) +//| +STATIC mp_obj_t audioio_wavefile_obj_get_bits_per_sample(mp_obj_t self_in) { + audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_bits_per_sample(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_bits_per_sample_obj, audioio_wavefile_obj_get_bits_per_sample); + +const mp_obj_property_t audioio_wavefile_bits_per_sample_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_wavefile_get_bits_per_sample_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: channel_count +//| +//| Number of audio channels. (read only) +//| +STATIC mp_obj_t audioio_wavefile_obj_get_channel_count(mp_obj_t self_in) { + audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_channel_count(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_channel_count_obj, audioio_wavefile_obj_get_channel_count); + +const mp_obj_property_t audioio_wavefile_channel_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_wavefile_get_channel_count_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +STATIC const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_wavefile_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_wavefile___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_wavefile_sample_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audioio_wavefile_bits_per_sample_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audioio_wavefile_channel_count_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audioio_wavefile_locals_dict, audioio_wavefile_locals_dict_table); + +const mp_obj_type_t audioio_wavefile_type = { + { &mp_type_type }, + .name = MP_QSTR_WaveFile, + .make_new = audioio_wavefile_make_new, + .locals_dict = (mp_obj_dict_t*)&audioio_wavefile_locals_dict, +}; diff --git a/shared-bindings/audiocore/WaveFile.h b/shared-bindings/audiocore/WaveFile.h new file mode 100644 index 000000000..d2572318b --- /dev/null +++ b/shared-bindings/audiocore/WaveFile.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H + +#include "py/obj.h" +#include "extmod/vfs_fat.h" + +#include "shared-module/audiocore/WaveFile.h" + +extern const mp_obj_type_t audioio_wavefile_type; + +void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, + pyb_file_obj_t* file); + +void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self); +bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self); +uint32_t common_hal_audioio_wavefile_get_sample_rate(audioio_wavefile_obj_t* self); +void common_hal_audioio_wavefile_set_sample_rate(audioio_wavefile_obj_t* self, uint32_t sample_rate); +uint8_t common_hal_audioio_wavefile_get_bits_per_sample(audioio_wavefile_obj_t* self); +uint8_t common_hal_audioio_wavefile_get_channel_count(audioio_wavefile_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H diff --git a/shared-bindings/audiocore/__init__.c b/shared-bindings/audiocore/__init__.c new file mode 100644 index 000000000..c64759d4f --- /dev/null +++ b/shared-bindings/audiocore/__init__.c @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/audiocore/WaveFile.h" + +//| :mod:`audiocore` --- Support for audio samples and mixer +//| ======================================================== +//| +//| .. module:: audiocore +//| :synopsis: Support for audio samples and mixer +//| :platform: SAMD21 +//| +//| The `audiocore` module contains core classes for audio IO +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| Mixer +//| RawSample +//| WaveFile +//| + +STATIC const mp_rom_map_elem_t audiocore_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiocore) }, + { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, + { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) }, + { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(audiocore_module_globals, audiocore_module_globals_table); + +const mp_obj_module_t audiocore_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&audiocore_module_globals, +}; diff --git a/shared-bindings/audiocore/__init__.h b/shared-bindings/audiocore/__init__.h new file mode 100644 index 000000000..02437cd13 --- /dev/null +++ b/shared-bindings/audiocore/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H + +#include "py/obj.h" + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H diff --git a/shared-bindings/audioio/AudioOut.c b/shared-bindings/audioio/AudioOut.c index 571dcdaca..79df66f7d 100644 --- a/shared-bindings/audioio/AudioOut.c +++ b/shared-bindings/audioio/AudioOut.c @@ -32,7 +32,7 @@ #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/audioio/AudioOut.h" -#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" diff --git a/shared-bindings/audioio/AudioOut.h b/shared-bindings/audioio/AudioOut.h index d09a5c9ca..1076ac5cc 100644 --- a/shared-bindings/audioio/AudioOut.h +++ b/shared-bindings/audioio/AudioOut.h @@ -29,7 +29,7 @@ #include "common-hal/audioio/AudioOut.h" #include "common-hal/microcontroller/Pin.h" -#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/audiocore/RawSample.h" extern const mp_obj_type_t audioio_audioout_type; diff --git a/shared-bindings/audioio/Mixer.c b/shared-bindings/audioio/Mixer.c deleted file mode 100644 index dce4b3955..000000000 --- a/shared-bindings/audioio/Mixer.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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 "shared-bindings/audioio/Mixer.h" - -#include - -#include "lib/utils/context_manager_helpers.h" -#include "py/binary.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audioio/RawSample.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| .. currentmodule:: audioio -//| -//| :class:`Mixer` -- Mixes one or more audio samples together -//| =========================================================== -//| -//| Mixer mixes multiple samples into one sample. -//| -//| .. class:: Mixer(channel_count=2, buffer_size=1024) -//| -//| Create a Mixer object that can mix multiple channels with the same sample rate. -//| -//| :param int channel_count: The maximum number of samples to mix at once -//| :param int buffer_size: The total size in bytes of the buffers to mix into -//| -//| Playing a wave file from flash:: -//| -//| import board -//| import audioio -//| import digitalio -//| -//| # Required for CircuitPlayground Express -//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) -//| speaker_enable.switch_to_output(value=True) -//| -//| music = audioio.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) -//| drum = audioio.WaveFile(open("drum.wav", "rb")) -//| mixer = audioio.Mixer(voice_count=2, sample_rate=16000, channel_count=1, bits_per_sample=16, samples_signed=True) -//| a = audioio.AudioOut(board.A0) -//| -//| print("playing") -//| a.play(mixer) -//| mixer.play(music, voice=0) -//| while mixer.playing: -//| mixer.play(drum, voice=1) -//| time.sleep(1) -//| print("stopped") -//| -STATIC mp_obj_t audioio_mixer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_voice_count, ARG_buffer_size, ARG_channel_count, ARG_bits_per_sample, ARG_samples_signed, ARG_sample_rate }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, - { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, - { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, - { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, - { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, - { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_int_t voice_count = args[ARG_voice_count].u_int; - if (voice_count < 1 || voice_count > 255) { - mp_raise_ValueError(translate("Invalid voice count")); - } - - mp_int_t channel_count = args[ARG_channel_count].u_int; - if (channel_count < 1 || channel_count > 2) { - mp_raise_ValueError(translate("Invalid channel count")); - } - mp_int_t sample_rate = args[ARG_sample_rate].u_int; - if (sample_rate < 1) { - mp_raise_ValueError(translate("Sample rate must be positive")); - } - mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; - if (bits_per_sample != 8 && bits_per_sample != 16) { - mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); - } - audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, audioio_mixer_voice_t, voice_count); - self->base.type = &audioio_mixer_type; - common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: deinit() -//| -//| Deinitialises the Mixer and releases any hardware resources for reuse. -//| -STATIC mp_obj_t audioio_mixer_deinit(mp_obj_t self_in) { - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audioio_mixer_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_deinit_obj, audioio_mixer_deinit); - -STATIC void check_for_deinit(audioio_mixer_obj_t *self) { - if (common_hal_audioio_mixer_deinited(self)) { - raise_deinited_error(); - } -} - -//| .. method:: __enter__() -//| -//| No-op used by Context Managers. -//| -// Provided by context manager helper. - -//| .. method:: __exit__() -//| -//| Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info. -//| -STATIC mp_obj_t audioio_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_audioio_mixer_deinit(args[0]); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer___exit___obj, 4, 4, audioio_mixer_obj___exit__); - - -//| .. method:: play(sample, *, voice=0, loop=False) -//| -//| Plays the sample once when loop=False and continuously when loop=True. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. -//| -//| The sample must match the Mixer's encoding settings given in the constructor. -//| -STATIC mp_obj_t audioio_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_voice, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_voice, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_audioio_mixer_play(self, sample, args[ARG_voice].u_int, args[ARG_loop].u_bool); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_play_obj, 1, audioio_mixer_obj_play); - -//| .. method:: stop_voice(voice=0) -//| -//| Stops playback of the sample on the given voice. -//| -STATIC mp_obj_t audioio_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_voice }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, - }; - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_stop_voice_obj, 1, audioio_mixer_obj_stop_voice); - -//| .. attribute:: playing -//| -//| True when any voice is being output. (read-only) -//| -STATIC mp_obj_t audioio_mixer_obj_get_playing(mp_obj_t self_in) { - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_playing_obj, audioio_mixer_obj_get_playing); - -const mp_obj_property_t audioio_mixer_playing_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_get_playing_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: sample_rate -//| -//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). -//| -STATIC mp_obj_t audioio_mixer_obj_get_sample_rate(mp_obj_t self_in) { - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_mixer_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_sample_rate_obj, audioio_mixer_obj_get_sample_rate); - - -const mp_obj_property_t audioio_mixer_sample_rate_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_get_sample_rate_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t audioio_mixer_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixer_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixer___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixer_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop_voice), MP_ROM_PTR(&audioio_mixer_stop_voice_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_mixer_sample_rate_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(audioio_mixer_locals_dict, audioio_mixer_locals_dict_table); - -const mp_obj_type_t audioio_mixer_type = { - { &mp_type_type }, - .name = MP_QSTR_Mixer, - .make_new = audioio_mixer_make_new, - .locals_dict = (mp_obj_dict_t*)&audioio_mixer_locals_dict, -}; diff --git a/shared-bindings/audioio/Mixer.h b/shared-bindings/audioio/Mixer.h deleted file mode 100644 index 832072b8f..000000000 --- a/shared-bindings/audioio/Mixer.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H - -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/audioio/Mixer.h" -#include "shared-bindings/audioio/RawSample.h" - -extern const mp_obj_type_t audioio_mixer_type; - -void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, - uint8_t voice_count, - uint32_t buffer_size, - uint8_t bits_per_sample, - bool samples_signed, - uint8_t channel_count, - uint32_t sample_rate); - -void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self); -bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self); -void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, uint8_t voice, bool loop); -void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice); - -bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); -uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H diff --git a/shared-bindings/audioio/RawSample.c b/shared-bindings/audioio/RawSample.c deleted file mode 100644 index 62998f580..000000000 --- a/shared-bindings/audioio/RawSample.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * - * 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 - -#include "lib/utils/context_manager_helpers.h" -#include "py/binary.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audioio/AudioOut.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| .. currentmodule:: audioio -//| -//| :class:`RawSample` -- A raw audio sample buffer -//| ======================================================== -//| -//| An in-memory sound sample -//| -//| .. class:: RawSample(buffer, *, channel_count=1, sample_rate=8000) -//| -//| Create a RawSample based on the given buffer of signed values. If channel_count is more than -//| 1 then each channel's samples should alternate. In other words, for a two channel buffer, the -//| first sample will be for channel 1, the second sample will be for channel two, the third for -//| channel 1 and so on. -//| -//| :param array buffer: An `array.array` with samples -//| :param int channel_count: The number of channels in the buffer -//| :param int sample_rate: The desired playback sample rate -//| -//| Simple 8ksps 440 Hz sin wave:: -//| -//| import audioio -//| import board -//| import array -//| import time -//| import math -//| -//| # Generate one period of sine wav. -//| length = 8000 // 440 -//| sine_wave = array.array("h", [0] * length) -//| for i in range(length): -//| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15)) -//| -//| dac = audioio.AudioOut(board.SPEAKER) -//| sine_wave = audioio.RawSample(sine_wave) -//| dac.play(sine_wave, loop=True) -//| time.sleep(1) -//| dac.stop() -//| -STATIC mp_obj_t audioio_rawsample_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_buffer, ARG_channel_count, ARG_sample_rate }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1 } }, - { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - audioio_rawsample_obj_t *self = m_new_obj(audioio_rawsample_obj_t); - self->base.type = &audioio_rawsample_type; - mp_buffer_info_t bufinfo; - if (mp_get_buffer(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ)) { - uint8_t bytes_per_sample = 1; - bool signed_samples = bufinfo.typecode == 'b' || bufinfo.typecode == 'h'; - if (bufinfo.typecode == 'h' || bufinfo.typecode == 'H') { - bytes_per_sample = 2; - } else if (bufinfo.typecode != 'b' && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { - mp_raise_ValueError(translate("sample_source buffer must be a bytearray or array of type 'h', 'H', 'b' or 'B'")); - } - common_hal_audioio_rawsample_construct(self, ((uint8_t*)bufinfo.buf), bufinfo.len, - bytes_per_sample, signed_samples, args[ARG_channel_count].u_int, - args[ARG_sample_rate].u_int); - } else { - mp_raise_TypeError(translate("buffer must be a bytes-like object")); - } - - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: deinit() -//| -//| Deinitialises the AudioOut and releases any hardware resources for reuse. -//| -STATIC mp_obj_t audioio_rawsample_deinit(mp_obj_t self_in) { - audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audioio_rawsample_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_deinit_obj, audioio_rawsample_deinit); - -STATIC void check_for_deinit(audioio_rawsample_obj_t *self) { - if (common_hal_audioio_rawsample_deinited(self)) { - raise_deinited_error(); - } -} - -//| .. method:: __enter__() -//| -//| No-op used by Context Managers. -//| -// Provided by context manager helper. - -//| .. method:: __exit__() -//| -//| Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info. -//| -STATIC mp_obj_t audioio_rawsample_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_audioio_rawsample_deinit(args[0]); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_rawsample___exit___obj, 4, 4, audioio_rawsample_obj___exit__); - -//| .. attribute:: sample_rate -//| -//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). -//| When the sample is looped, this can change the pitch output without changing the underlying -//| sample. This will not change the sample rate of any active playback. Call ``play`` again to -//| change it. -//| -STATIC mp_obj_t audioio_rawsample_obj_get_sample_rate(mp_obj_t self_in) { - audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_rawsample_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_get_sample_rate_obj, audioio_rawsample_obj_get_sample_rate); - -STATIC mp_obj_t audioio_rawsample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { - audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_audioio_rawsample_set_sample_rate(self, mp_obj_get_int(sample_rate)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(audioio_rawsample_set_sample_rate_obj, audioio_rawsample_obj_set_sample_rate); - -const mp_obj_property_t audioio_rawsample_sample_rate_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_rawsample_get_sample_rate_obj, - (mp_obj_t)&audioio_rawsample_set_sample_rate_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t audioio_rawsample_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_rawsample_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_rawsample___exit___obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_rawsample_sample_rate_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(audioio_rawsample_locals_dict, audioio_rawsample_locals_dict_table); - -const mp_obj_type_t audioio_rawsample_type = { - { &mp_type_type }, - .name = MP_QSTR_RawSample, - .make_new = audioio_rawsample_make_new, - .locals_dict = (mp_obj_dict_t*)&audioio_rawsample_locals_dict, -}; diff --git a/shared-bindings/audioio/RawSample.h b/shared-bindings/audioio/RawSample.h deleted file mode 100644 index 0d764b77c..000000000 --- a/shared-bindings/audioio/RawSample.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H - -#include "common-hal/audioio/AudioOut.h" -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/audioio/RawSample.h" - -extern const mp_obj_type_t audioio_rawsample_type; - -void common_hal_audioio_rawsample_construct(audioio_rawsample_obj_t* self, - uint8_t* buffer, uint32_t len, uint8_t bytes_per_sample, bool samples_signed, - uint8_t channel_count, uint32_t sample_rate); - -void common_hal_audioio_rawsample_deinit(audioio_rawsample_obj_t* self); -bool common_hal_audioio_rawsample_deinited(audioio_rawsample_obj_t* self); -uint32_t common_hal_audioio_rawsample_get_sample_rate(audioio_rawsample_obj_t* self); -void common_hal_audioio_rawsample_set_sample_rate(audioio_rawsample_obj_t* self, uint32_t sample_rate); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H diff --git a/shared-bindings/audioio/WaveFile.c b/shared-bindings/audioio/WaveFile.c deleted file mode 100644 index 242c915d3..000000000 --- a/shared-bindings/audioio/WaveFile.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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 - -#include "lib/utils/context_manager_helpers.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/audioio/WaveFile.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| .. currentmodule:: audioio -//| -//| :class:`WaveFile` -- Load a wave file for audio playback -//| ======================================================== -//| -//| A .wav file prepped for audio playback. Only mono and stereo files are supported. Samples must -//| be 8 bit unsigned or 16 bit signed. -//| -//| .. class:: WaveFile(file) -//| -//| Load a .wav file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`. -//| -//| :param typing.BinaryIO file: Already opened wave file -//| -//| Playing a wave file from flash:: -//| -//| import board -//| import audioio -//| import digitalio -//| -//| # Required for CircuitPlayground Express -//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) -//| speaker_enable.switch_to_output(value=True) -//| -//| data = open("cplay-5.1-16bit-16khz.wav", "rb") -//| wav = audioio.WaveFile(data) -//| a = audioio.AudioOut(board.A0) -//| -//| print("playing") -//| a.play(wav) -//| while a.playing: -//| pass -//| print("stopped") -//| -STATIC mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 1, 1, false); - - audioio_wavefile_obj_t *self = m_new_obj(audioio_wavefile_obj_t); - self->base.type = &audioio_wavefile_type; - if (MP_OBJ_IS_TYPE(args[0], &mp_type_fileio)) { - common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0])); - } else { - mp_raise_TypeError(translate("file must be a file opened in byte mode")); - } - - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: deinit() -//| -//| Deinitialises the WaveFile and releases all memory resources for reuse. -//| -STATIC mp_obj_t audioio_wavefile_deinit(mp_obj_t self_in) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audioio_wavefile_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_deinit_obj, audioio_wavefile_deinit); - -STATIC void check_for_deinit(audioio_wavefile_obj_t *self) { - if (common_hal_audioio_wavefile_deinited(self)) { - raise_deinited_error(); - } -} - -//| .. method:: __enter__() -//| -//| No-op used by Context Managers. -//| -// Provided by context manager helper. - -//| .. method:: __exit__() -//| -//| Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info. -//| -STATIC mp_obj_t audioio_wavefile_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_audioio_wavefile_deinit(args[0]); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_wavefile___exit___obj, 4, 4, audioio_wavefile_obj___exit__); - -//| .. attribute:: sample_rate -//| -//| 32 bit value that dictates how quickly samples are loaded into the DAC -//| in Hertz (cycles per second). When the sample is looped, this can change -//| the pitch output without changing the underlying sample. -//| -STATIC mp_obj_t audioio_wavefile_obj_get_sample_rate(mp_obj_t self_in) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_sample_rate_obj, audioio_wavefile_obj_get_sample_rate); - -STATIC mp_obj_t audioio_wavefile_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_audioio_wavefile_set_sample_rate(self, mp_obj_get_int(sample_rate)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(audioio_wavefile_set_sample_rate_obj, audioio_wavefile_obj_set_sample_rate); - -const mp_obj_property_t audioio_wavefile_sample_rate_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_wavefile_get_sample_rate_obj, - (mp_obj_t)&audioio_wavefile_set_sample_rate_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: bits_per_sample -//| -//| Bits per sample. (read only) -//| -STATIC mp_obj_t audioio_wavefile_obj_get_bits_per_sample(mp_obj_t self_in) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_bits_per_sample(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_bits_per_sample_obj, audioio_wavefile_obj_get_bits_per_sample); - -const mp_obj_property_t audioio_wavefile_bits_per_sample_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_wavefile_get_bits_per_sample_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: channel_count -//| -//| Number of audio channels. (read only) -//| -STATIC mp_obj_t audioio_wavefile_obj_get_channel_count(mp_obj_t self_in) { - audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_channel_count(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_channel_count_obj, audioio_wavefile_obj_get_channel_count); - -const mp_obj_property_t audioio_wavefile_channel_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_wavefile_get_channel_count_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - - -STATIC const mp_rom_map_elem_t audioio_wavefile_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_wavefile_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_wavefile___exit___obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_wavefile_sample_rate_obj) }, - { MP_ROM_QSTR(MP_QSTR_bits_per_sample), MP_ROM_PTR(&audioio_wavefile_bits_per_sample_obj) }, - { MP_ROM_QSTR(MP_QSTR_channel_count), MP_ROM_PTR(&audioio_wavefile_channel_count_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(audioio_wavefile_locals_dict, audioio_wavefile_locals_dict_table); - -const mp_obj_type_t audioio_wavefile_type = { - { &mp_type_type }, - .name = MP_QSTR_WaveFile, - .make_new = audioio_wavefile_make_new, - .locals_dict = (mp_obj_dict_t*)&audioio_wavefile_locals_dict, -}; diff --git a/shared-bindings/audioio/WaveFile.h b/shared-bindings/audioio/WaveFile.h deleted file mode 100644 index 62a4200dc..000000000 --- a/shared-bindings/audioio/WaveFile.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H - -#include "common-hal/audioio/AudioOut.h" -#include "common-hal/microcontroller/Pin.h" -#include "extmod/vfs_fat.h" - -extern const mp_obj_type_t audioio_wavefile_type; - -void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, - pyb_file_obj_t* file); - -void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self); -bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self); -uint32_t common_hal_audioio_wavefile_get_sample_rate(audioio_wavefile_obj_t* self); -void common_hal_audioio_wavefile_set_sample_rate(audioio_wavefile_obj_t* self, uint32_t sample_rate); -uint8_t common_hal_audioio_wavefile_get_bits_per_sample(audioio_wavefile_obj_t* self); -uint8_t common_hal_audioio_wavefile_get_channel_count(audioio_wavefile_obj_t* self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H diff --git a/shared-bindings/audioio/__init__.c b/shared-bindings/audioio/__init__.c index 4786b6425..837b66255 100644 --- a/shared-bindings/audioio/__init__.c +++ b/shared-bindings/audioio/__init__.c @@ -32,9 +32,11 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/audioio/__init__.h" #include "shared-bindings/audioio/AudioOut.h" -#include "shared-bindings/audioio/Mixer.h" -#include "shared-bindings/audioio/RawSample.h" -#include "shared-bindings/audioio/WaveFile.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/audioio/AudioOut.h" +#include "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/audiocore/WaveFile.h" //| :mod:`audioio` --- Support for audio input and output //| ====================================================== @@ -51,22 +53,19 @@ //| :maxdepth: 3 //| //| AudioOut -//| Mixer -//| RawSample -//| WaveFile //| //| All classes change hardware state and should be deinitialized when they //| are no longer needed if the program continues after use. To do so, either //| call :py:meth:`!deinit` or use a context manager. See //| :ref:`lifetime-and-contextmanagers` for more info. //| +//| Since CircuitPython 5, `Mixer`, `RawSample` and `WaveFile` are moved +//| to :mod:`audiocore`. +//| STATIC const mp_rom_map_elem_t audioio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audioio) }, { MP_ROM_QSTR(MP_QSTR_AudioOut), MP_ROM_PTR(&audioio_audioout_type) }, - { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, - { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) }, - { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) }, }; STATIC MP_DEFINE_CONST_DICT(audioio_module_globals, audioio_module_globals_table); diff --git a/shared-bindings/index.rst b/shared-bindings/index.rst index 8f9bbbb31..b7690d292 100644 --- a/shared-bindings/index.rst +++ b/shared-bindings/index.rst @@ -36,6 +36,7 @@ Module Supported Ports `analogio` **All Supported** `audiobusio` **SAMD/SAMD Express** `audioio` **SAMD Express** +`audiocore` **All with audioio** `binascii` **ESP8266** `bitbangio` **SAMD Express, ESP8266** `board` **All Supported** diff --git a/shared-module/audiocore/Mixer.c b/shared-module/audiocore/Mixer.c new file mode 100644 index 000000000..da66bb36e --- /dev/null +++ b/shared-module/audiocore/Mixer.c @@ -0,0 +1,341 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/audiocore/Mixer.h" + +#include + +#include "py/runtime.h" +#include "shared-module/audiocore/__init__.h" +#include "shared-module/audiocore/RawSample.h" + +void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, + uint8_t voice_count, + uint32_t buffer_size, + uint8_t bits_per_sample, + bool samples_signed, + uint8_t channel_count, + uint32_t sample_rate) { + self->len = buffer_size / 2 / sizeof(uint32_t) * sizeof(uint32_t); + + self->first_buffer = m_malloc(self->len, false); + if (self->first_buffer == NULL) { + common_hal_audioio_mixer_deinit(self); + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); + } + + self->second_buffer = m_malloc(self->len, false); + if (self->second_buffer == NULL) { + common_hal_audioio_mixer_deinit(self); + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); + } + + self->bits_per_sample = bits_per_sample; + self->samples_signed = samples_signed; + self->channel_count = channel_count; + self->sample_rate = sample_rate; + self->voice_count = voice_count; + + for (uint8_t i = 0; i < self->voice_count; i++) { + self->voice[i].sample = NULL; + } +} + +void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self) { + self->first_buffer = NULL; + self->second_buffer = NULL; +} + +bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self) { + return self->first_buffer == NULL; +} + +uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self) { + return self->sample_rate; +} + +void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, uint8_t v, bool loop) { + if (v >= self->voice_count) { + mp_raise_ValueError(translate("Voice index too high")); + } + if (audiosample_sample_rate(sample) != self->sample_rate) { + mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); + } + if (audiosample_channel_count(sample) != self->channel_count) { + mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); + } + if (audiosample_bits_per_sample(sample) != self->bits_per_sample) { + mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); + } + bool single_buffer; + bool samples_signed; + uint32_t max_buffer_length; + uint8_t spacing; + audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, + &max_buffer_length, &spacing); + if (samples_signed != self->samples_signed) { + mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); + } + audioio_mixer_voice_t* voice = &self->voice[v]; + voice->sample = sample; + voice->loop = loop; + + audiosample_reset_buffer(sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); + // Track length in terms of words. + voice->buffer_length /= sizeof(uint32_t); + voice->more_data = result == GET_BUFFER_MORE_DATA; +} + +void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice) { + self->voice[voice].sample = NULL; +} + +bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self) { + for (int32_t v = 0; v < self->voice_count; v++) { + if (self->voice[v].sample != NULL) { + return true; + } + } + return false; +} + +void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, + bool single_channel, + uint8_t channel) { + for (int32_t i = 0; i < self->voice_count; i++) { + self->voice[i].sample = NULL; + } +} + +uint32_t add8signed(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return __QADD8(a, b); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 4; i++) { + int8_t ai = a >> (sizeof(int8_t) * 8 * i); + int8_t bi = b >> (sizeof(int8_t) * 8 * i); + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > CHAR_MAX) { + intermediate = CHAR_MAX; + } else if (intermediate < CHAR_MIN) { + //intermediate = CHAR_MIN; + } + result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int8_t) * 8 * i); + } + return result; + #endif +} + +uint32_t add8unsigned(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + // Subtract out the DC offset, add and then shift back. + a = __USUB8(a, 0x80808080); + b = __USUB8(b, 0x80808080); + uint32_t sum = __QADD8(a, b); + return __UADD8(sum, 0x80808080); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 4; i++) { + int8_t ai = (a >> (sizeof(uint8_t) * 8 * i)) - 128; + int8_t bi = (b >> (sizeof(uint8_t) * 8 * i)) - 128; + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > UCHAR_MAX) { + intermediate = UCHAR_MAX; + } + result |= ((uint8_t) intermediate + 128) << (sizeof(uint8_t) * 8 * i); + } + return result; + #endif +} + +uint32_t add16signed(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return __QADD16(a, b); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 2; i++) { + int16_t ai = a >> (sizeof(int16_t) * 8 * i); + int16_t bi = b >> (sizeof(int16_t) * 8 * i); + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } else if (intermediate < SHRT_MIN) { + intermediate = SHRT_MIN; + } + result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); + } + return result; + #endif +} + +uint32_t add16unsigned(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + // Subtract out the DC offset, add and then shift back. + a = __USUB16(a, 0x80008000); + b = __USUB16(b, 0x80008000); + uint32_t sum = __QADD16(a, b); + return __UADD16(sum, 0x80008000); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 2; i++) { + int16_t ai = (a >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + int16_t bi = (b >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > USHRT_MAX) { + intermediate = USHRT_MAX; + } + result |= ((uint16_t) intermediate + 0x8000) << (sizeof(int16_t) * 8 * i); + } + return result; + #endif +} + +audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length) { + if (!single_channel) { + channel = 0; + } + + uint32_t channel_read_count = self->left_read_count; + if (channel == 1) { + channel_read_count = self->right_read_count; + } + *buffer_length = self->len; + + bool need_more_data = self->read_count == channel_read_count; + if (need_more_data) { + uint32_t* word_buffer; + if (self->use_first_buffer) { + *buffer = (uint8_t*) self->first_buffer; + word_buffer = self->first_buffer; + } else { + *buffer = (uint8_t*) self->second_buffer; + word_buffer = self->second_buffer; + } + self->use_first_buffer = !self->use_first_buffer; + bool voices_active = false; + for (int32_t v = 0; v < self->voice_count; v++) { + audioio_mixer_voice_t* voice = &self->voice[v]; + + uint32_t j = 0; + bool voice_done = voice->sample == NULL; + for (uint32_t i = 0; i < self->len / sizeof(uint32_t); i++) { + if (!voice_done && j >= voice->buffer_length) { + if (!voice->more_data) { + if (voice->loop) { + audiosample_reset_buffer(voice->sample, false, 0); + } else { + voice->sample = NULL; + voice_done = true; + } + } + if (!voice_done) { + // Load another buffer + audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); + // Track length in terms of words. + voice->buffer_length /= sizeof(uint32_t); + voice->more_data = result == GET_BUFFER_MORE_DATA; + j = 0; + } + } + // First active voice gets copied over verbatim. + uint32_t sample_value; + if (voice_done) { + // Exit early if another voice already set all samples once. + if (voices_active) { + continue; + } + sample_value = 0; + if (!self->samples_signed) { + if (self->bits_per_sample == 8) { + sample_value = 0x7f7f7f7f; + } else { + sample_value = 0x7fff7fff; + } + } + } else { + sample_value = voice->remaining_buffer[j]; + } + + if (!voices_active) { + word_buffer[i] = sample_value; + } else { + if (self->bits_per_sample == 8) { + if (self->samples_signed) { + word_buffer[i] = add8signed(word_buffer[i], sample_value); + } else { + word_buffer[i] = add8unsigned(word_buffer[i], sample_value); + } + } else { + if (self->samples_signed) { + word_buffer[i] = add16signed(word_buffer[i], sample_value); + } else { + word_buffer[i] = add16unsigned(word_buffer[i], sample_value); + } + } + } + j++; + } + voice->buffer_length -= j; + voice->remaining_buffer += j; + + voices_active = true; + } + + self->read_count += 1; + } else if (!self->use_first_buffer) { + *buffer = (uint8_t*) self->first_buffer; + } else { + *buffer = (uint8_t*) self->second_buffer; + } + + + if (channel == 0) { + self->left_read_count += 1; + } else if (channel == 1) { + self->right_read_count += 1; + *buffer = *buffer + self->bits_per_sample / 8; + } + return GET_BUFFER_MORE_DATA; +} + +void audioio_mixer_get_buffer_structure(audioio_mixer_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing) { + *single_buffer = false; + *samples_signed = self->samples_signed; + *max_buffer_length = self->len; + if (single_channel) { + *spacing = self->channel_count; + } else { + *spacing = 1; + } +} diff --git a/shared-module/audiocore/Mixer.h b/shared-module/audiocore/Mixer.h new file mode 100644 index 000000000..22eb6a37f --- /dev/null +++ b/shared-module/audiocore/Mixer.h @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" + +typedef struct { + mp_obj_t sample; + bool loop; + bool more_data; + uint32_t* remaining_buffer; + uint32_t buffer_length; +} audioio_mixer_voice_t; + +typedef struct { + mp_obj_base_t base; + uint32_t* first_buffer; + uint32_t* second_buffer; + uint32_t len; // in words + uint8_t bits_per_sample; + bool use_first_buffer; + bool samples_signed; + uint8_t channel_count; + uint32_t sample_rate; + + uint32_t read_count; + uint32_t left_read_count; + uint32_t right_read_count; + + uint8_t voice_count; + audioio_mixer_voice_t voice[]; +} audioio_mixer_obj_t; + + +// These are not available from Python because it may be called in an interrupt. +void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, + bool single_channel, + uint8_t channel); +audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length); // length in bytes +void audioio_mixer_get_buffer_structure(audioio_mixer_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H diff --git a/shared-module/audiocore/RawSample.c b/shared-module/audiocore/RawSample.c new file mode 100644 index 000000000..d6bf3a567 --- /dev/null +++ b/shared-module/audiocore/RawSample.c @@ -0,0 +1,94 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/audiocore/RawSample.h" + +#include + +#include "shared-module/audiocore/RawSample.h" + +void common_hal_audioio_rawsample_construct(audioio_rawsample_obj_t* self, + uint8_t* buffer, + uint32_t len, + uint8_t bytes_per_sample, + bool samples_signed, + uint8_t channel_count, + uint32_t sample_rate) { + self->buffer = buffer; + self->bits_per_sample = bytes_per_sample * 8; + self->samples_signed = samples_signed; + self->len = len; + self->channel_count = channel_count; + self->sample_rate = sample_rate; + self->buffer_read = false; +} + +void common_hal_audioio_rawsample_deinit(audioio_rawsample_obj_t* self) { + self->buffer = NULL; +} +bool common_hal_audioio_rawsample_deinited(audioio_rawsample_obj_t* self) { + return self->buffer == NULL; +} + +uint32_t common_hal_audioio_rawsample_get_sample_rate(audioio_rawsample_obj_t* self) { + return self->sample_rate; +} +void common_hal_audioio_rawsample_set_sample_rate(audioio_rawsample_obj_t* self, + uint32_t sample_rate) { + self->sample_rate = sample_rate; +} + +void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t* self, + bool single_channel, + uint8_t channel) { +} + +audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length) { + *buffer_length = self->len; + if (single_channel) { + *buffer = self->buffer + (channel % self->channel_count) * (self->bits_per_sample / 8); + } else { + *buffer = self->buffer; + } + return GET_BUFFER_DONE; +} + +void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing) { + *single_buffer = true; + *samples_signed = self->samples_signed; + *max_buffer_length = self->len; + if (single_channel) { + *spacing = self->channel_count; + } else { + *spacing = 1; + } +} diff --git a/shared-module/audiocore/RawSample.h b/shared-module/audiocore/RawSample.h new file mode 100644 index 000000000..6c2c19c9b --- /dev/null +++ b/shared-module/audiocore/RawSample.h @@ -0,0 +1,59 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_RAWSAMPLE_H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_RAWSAMPLE_H + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" + +typedef struct { + mp_obj_base_t base; + uint8_t* buffer; + uint32_t len; + uint8_t bits_per_sample; + bool samples_signed; + uint8_t channel_count; + uint32_t sample_rate; + bool buffer_read; +} audioio_rawsample_obj_t; + + +// These are not available from Python because it may be called in an interrupt. +void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t* self, + bool single_channel, + uint8_t channel); +audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length); // length in bytes +void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_RAWSAMPLE_H diff --git a/shared-module/audiocore/WaveFile.c b/shared-module/audiocore/WaveFile.c new file mode 100644 index 000000000..810d9c33b --- /dev/null +++ b/shared-module/audiocore/WaveFile.c @@ -0,0 +1,268 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/audiocore/WaveFile.h" + +#include +#include + +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "shared-module/audiocore/WaveFile.h" +#include "supervisor/shared/translate.h" + +struct wave_format_chunk { + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; + uint16_t block_align; + uint16_t bits_per_sample; + uint16_t extra_params; // Assumed to be zero below. +}; + +void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, + pyb_file_obj_t* file) { + // Load the wave + self->file = file; + uint8_t chunk_header[16]; + f_rewind(&self->file->fp); + UINT bytes_read; + if (f_read(&self->file->fp, chunk_header, 16, &bytes_read) != FR_OK) { + mp_raise_OSError(MP_EIO); + } + if (bytes_read != 16 || + memcmp(chunk_header, "RIFF", 4) != 0 || + memcmp(chunk_header + 8, "WAVEfmt ", 8) != 0) { + mp_raise_ValueError(translate("Invalid wave file")); + } + uint32_t format_size; + if (f_read(&self->file->fp, &format_size, 4, &bytes_read) != FR_OK) { + mp_raise_OSError(MP_EIO); + } + if (bytes_read != 4 || + format_size > sizeof(struct wave_format_chunk)) { + mp_raise_ValueError(translate("Invalid format chunk size")); + } + struct wave_format_chunk format; + if (f_read(&self->file->fp, &format, format_size, &bytes_read) != FR_OK) { + mp_raise_OSError(MP_EIO); + } + if (bytes_read != format_size) { + } + + if (format.audio_format != 1 || + format.num_channels > 2 || + format.bits_per_sample > 16 || + (format_size == 18 && + format.extra_params != 0)) { + mp_raise_ValueError(translate("Unsupported format")); + } + // Get the sample_rate + self->sample_rate = format.sample_rate; + self->len = 256; + self->channel_count = format.num_channels; + self->bits_per_sample = format.bits_per_sample; + + // TODO(tannewt): Skip any extra chunks that occur before the data section. + + uint8_t data_tag[4]; + if (f_read(&self->file->fp, &data_tag, 4, &bytes_read) != FR_OK) { + mp_raise_OSError(MP_EIO); + } + if (bytes_read != 4 || + memcmp((uint8_t *) data_tag, "data", 4) != 0) { + mp_raise_ValueError(translate("Data chunk must follow fmt chunk")); + } + + uint32_t data_length; + if (f_read(&self->file->fp, &data_length, 4, &bytes_read) != FR_OK) { + mp_raise_OSError(MP_EIO); + } + if (bytes_read != 4) { + mp_raise_ValueError(translate("Invalid file")); + } + self->file_length = data_length; + self->data_start = self->file->fp.fptr; + + // Try to allocate two buffers, one will be loaded from file and the other + // DMAed to DAC. + self->buffer = m_malloc(self->len, false); + if (self->buffer == NULL) { + common_hal_audioio_wavefile_deinit(self); + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); + } + + self->second_buffer = m_malloc(self->len, false); + if (self->second_buffer == NULL) { + common_hal_audioio_wavefile_deinit(self); + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); + } +} + +void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self) { + self->buffer = NULL; +} + +bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self) { + return self->buffer == NULL; +} + +uint32_t common_hal_audioio_wavefile_get_sample_rate(audioio_wavefile_obj_t* self) { + return self->sample_rate; +} + +void common_hal_audioio_wavefile_set_sample_rate(audioio_wavefile_obj_t* self, + uint32_t sample_rate) { + self->sample_rate = sample_rate; +} + +uint8_t common_hal_audioio_wavefile_get_bits_per_sample(audioio_wavefile_obj_t* self) { + return self->bits_per_sample; +} + +uint8_t common_hal_audioio_wavefile_get_channel_count(audioio_wavefile_obj_t* self) { + return self->channel_count; +} + +bool audioio_wavefile_samples_signed(audioio_wavefile_obj_t* self) { + return self->bits_per_sample > 8; +} + +uint32_t audioio_wavefile_max_buffer_length(audioio_wavefile_obj_t* self) { + return 512; +} + +void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t* self, + bool single_channel, + uint8_t channel) { + if (single_channel && channel == 1) { + return; + } + // We don't reset the buffer index in case we're looping and we have an odd number of buffer + // loads + self->bytes_remaining = self->file_length; + f_lseek(&self->file->fp, self->data_start); + self->read_count = 0; + self->left_read_count = 0; + self->right_read_count = 0; +} + +audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length) { + if (!single_channel) { + channel = 0; + } + + uint32_t channel_read_count = self->left_read_count; + if (channel == 1) { + channel_read_count = self->right_read_count; + } + + bool need_more_data = self->read_count == channel_read_count; + + if (self->bytes_remaining == 0 && need_more_data) { + *buffer = NULL; + *buffer_length = 0; + return GET_BUFFER_DONE; + } + + if (need_more_data) { + uint16_t num_bytes_to_load = self->len; + if (num_bytes_to_load > self->bytes_remaining) { + num_bytes_to_load = self->bytes_remaining; + } + UINT length_read; + if (self->buffer_index % 2 == 1) { + *buffer = self->second_buffer; + } else { + *buffer = self->buffer; + } + if (f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read) != FR_OK) { + return GET_BUFFER_ERROR; + } + self->bytes_remaining -= length_read; + // Pad the last buffer to word align it. + if (self->bytes_remaining == 0 && length_read % sizeof(uint32_t) != 0) { + uint32_t pad = length_read % sizeof(uint32_t); + length_read += pad; + if (self->bits_per_sample == 8) { + for (uint32_t i = 0; i < pad; i++) { + ((uint8_t*) (*buffer))[length_read / sizeof(uint8_t) - i - 1] = 0x80; + } + } else if (self->bits_per_sample == 16) { + // We know the buffer is aligned because we allocated it onto the heap ourselves. + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + ((int16_t*) (*buffer))[length_read / sizeof(int16_t) - 1] = 0; + #pragma GCC diagnostic pop + } + } + *buffer_length = length_read; + if (self->buffer_index % 2 == 1) { + self->second_buffer_length = length_read; + } else { + self->buffer_length = length_read; + } + self->buffer_index += 1; + self->read_count += 1; + } + + uint32_t buffers_back = self->read_count - 1 - channel_read_count; + if ((self->buffer_index - buffers_back) % 2 == 0) { + *buffer = self->second_buffer; + *buffer_length = self->second_buffer_length; + } else { + *buffer = self->buffer; + *buffer_length = self->buffer_length; + } + + if (channel == 0) { + self->left_read_count += 1; + } else if (channel == 1) { + self->right_read_count += 1; + *buffer = *buffer + self->bits_per_sample / 8; + } + + return self->bytes_remaining == 0 ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA; +} + +void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing) { + *single_buffer = false; + *samples_signed = self->bits_per_sample > 8; + *max_buffer_length = 512; + if (single_channel) { + *spacing = self->channel_count; + } else { + *spacing = 1; + } +} diff --git a/shared-module/audiocore/WaveFile.h b/shared-module/audiocore/WaveFile.h new file mode 100644 index 000000000..97dd6a46f --- /dev/null +++ b/shared-module/audiocore/WaveFile.h @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" + +typedef struct { + mp_obj_base_t base; + uint8_t* buffer; + uint32_t buffer_length; + uint8_t* second_buffer; + uint32_t second_buffer_length; + uint32_t file_length; // In bytes + uint16_t data_start; // Where the data values start + uint8_t bits_per_sample; + uint16_t buffer_index; + uint32_t bytes_remaining; + + uint8_t channel_count; + uint32_t sample_rate; + + uint32_t len; + pyb_file_obj_t* file; + + uint32_t read_count; + uint32_t left_read_count; + uint32_t right_read_count; +} audioio_wavefile_obj_t; + +// These are not available from Python because it may be called in an interrupt. +void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t* self, + bool single_channel, + uint8_t channel); +audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length); // length in bytes +void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c new file mode 100644 index 000000000..067cae5dd --- /dev/null +++ b/shared-module/audiocore/__init__.c @@ -0,0 +1,125 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-module/audioio/__init__.h" + +#include "py/obj.h" +#include "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/audiocore/WaveFile.h" +#include "shared-module/audiocore/Mixer.h" +#include "shared-module/audiocore/RawSample.h" +#include "shared-module/audiocore/WaveFile.h" + +uint32_t audiosample_sample_rate(mp_obj_t sample_obj) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + return sample->sample_rate; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return file->sample_rate; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + return mixer->sample_rate; + } + return 16000; +} + +uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + return sample->bits_per_sample; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return file->bits_per_sample; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + return mixer->bits_per_sample; + } + return 8; +} + +uint8_t audiosample_channel_count(mp_obj_t sample_obj) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + return sample->channel_count; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return file->channel_count; + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + return mixer->channel_count; + } + return 1; +} + +void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + audioio_rawsample_reset_buffer(sample, single_channel, audio_channel); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audioio_wavefile_reset_buffer(file, single_channel, audio_channel); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audioio_mixer_reset_buffer(file, single_channel, audio_channel); + } +} + +audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, + bool single_channel, + uint8_t channel, + uint8_t** buffer, uint32_t* buffer_length) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + return audioio_rawsample_get_buffer(sample, single_channel, channel, buffer, buffer_length); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return audioio_wavefile_get_buffer(file, single_channel, channel, buffer, buffer_length); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return audioio_mixer_get_buffer(file, single_channel, channel, buffer, buffer_length); + } + return GET_BUFFER_DONE; +} + +void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing) { + if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { + audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); + audioio_rawsample_get_buffer_structure(sample, single_channel, single_buffer, + samples_signed, max_buffer_length, spacing); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { + audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audioio_wavefile_get_buffer_structure(file, single_channel, single_buffer, samples_signed, + max_buffer_length, spacing); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { + audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audioio_mixer_get_buffer_structure(file, single_channel, single_buffer, samples_signed, + max_buffer_length, spacing); + } +} diff --git a/shared-module/audiocore/__init__.h b/shared-module/audiocore/__init__.h new file mode 100644 index 000000000..7aa0c1824 --- /dev/null +++ b/shared-module/audiocore/__init__.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOCORE__INIT__H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOCORE__INIT__H + +#include +#include + +#include "py/obj.h" + +typedef enum { + GET_BUFFER_DONE, // No more data to read + GET_BUFFER_MORE_DATA, // More data to read. + GET_BUFFER_ERROR, // Error while reading data. +} audioio_get_buffer_result_t; + +uint32_t audiosample_sample_rate(mp_obj_t sample_obj); +uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj); +uint8_t audiosample_channel_count(mp_obj_t sample_obj); +void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel); +audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, + bool single_channel, + uint8_t channel, + uint8_t** buffer, uint32_t* buffer_length); +void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOCORE__INIT__H diff --git a/shared-module/audioio/Mixer.c b/shared-module/audioio/Mixer.c deleted file mode 100644 index 8020a621e..000000000 --- a/shared-module/audioio/Mixer.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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 "shared-bindings/audioio/Mixer.h" - -#include - -#include "py/runtime.h" -#include "shared-module/audioio/__init__.h" -#include "shared-module/audioio/RawSample.h" - -void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, - uint8_t voice_count, - uint32_t buffer_size, - uint8_t bits_per_sample, - bool samples_signed, - uint8_t channel_count, - uint32_t sample_rate) { - self->len = buffer_size / 2 / sizeof(uint32_t) * sizeof(uint32_t); - - self->first_buffer = m_malloc(self->len, false); - if (self->first_buffer == NULL) { - common_hal_audioio_mixer_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); - } - - self->second_buffer = m_malloc(self->len, false); - if (self->second_buffer == NULL) { - common_hal_audioio_mixer_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); - } - - self->bits_per_sample = bits_per_sample; - self->samples_signed = samples_signed; - self->channel_count = channel_count; - self->sample_rate = sample_rate; - self->voice_count = voice_count; - - for (uint8_t i = 0; i < self->voice_count; i++) { - self->voice[i].sample = NULL; - } -} - -void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self) { - self->first_buffer = NULL; - self->second_buffer = NULL; -} - -bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self) { - return self->first_buffer == NULL; -} - -uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self) { - return self->sample_rate; -} - -void common_hal_audioio_mixer_play(audioio_mixer_obj_t* self, mp_obj_t sample, uint8_t v, bool loop) { - if (v >= self->voice_count) { - mp_raise_ValueError(translate("Voice index too high")); - } - if (audiosample_sample_rate(sample) != self->sample_rate) { - mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); - } - if (audiosample_channel_count(sample) != self->channel_count) { - mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); - } - if (audiosample_bits_per_sample(sample) != self->bits_per_sample) { - mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); - } - bool single_buffer; - bool samples_signed; - uint32_t max_buffer_length; - uint8_t spacing; - audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, - &max_buffer_length, &spacing); - if (samples_signed != self->samples_signed) { - mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); - } - audioio_mixer_voice_t* voice = &self->voice[v]; - voice->sample = sample; - voice->loop = loop; - - audiosample_reset_buffer(sample, false, 0); - audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); - // Track length in terms of words. - voice->buffer_length /= sizeof(uint32_t); - voice->more_data = result == GET_BUFFER_MORE_DATA; -} - -void common_hal_audioio_mixer_stop_voice(audioio_mixer_obj_t* self, uint8_t voice) { - self->voice[voice].sample = NULL; -} - -bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self) { - for (int32_t v = 0; v < self->voice_count; v++) { - if (self->voice[v].sample != NULL) { - return true; - } - } - return false; -} - -void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, - bool single_channel, - uint8_t channel) { - for (int32_t i = 0; i < self->voice_count; i++) { - self->voice[i].sample = NULL; - } -} - -uint32_t add8signed(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return __QADD8(a, b); - #else - uint32_t result = 0; - for (int8_t i = 0; i < 4; i++) { - int8_t ai = a >> (sizeof(int8_t) * 8 * i); - int8_t bi = b >> (sizeof(int8_t) * 8 * i); - int32_t intermediate = (int32_t) ai + bi; - if (intermediate > CHAR_MAX) { - intermediate = CHAR_MAX; - } else if (intermediate < CHAR_MIN) { - //intermediate = CHAR_MIN; - } - result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int8_t) * 8 * i); - } - return result; - #endif -} - -uint32_t add8unsigned(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - // Subtract out the DC offset, add and then shift back. - a = __USUB8(a, 0x80808080); - b = __USUB8(b, 0x80808080); - uint32_t sum = __QADD8(a, b); - return __UADD8(sum, 0x80808080); - #else - uint32_t result = 0; - for (int8_t i = 0; i < 4; i++) { - int8_t ai = (a >> (sizeof(uint8_t) * 8 * i)) - 128; - int8_t bi = (b >> (sizeof(uint8_t) * 8 * i)) - 128; - int32_t intermediate = (int32_t) ai + bi; - if (intermediate > UCHAR_MAX) { - intermediate = UCHAR_MAX; - } - result |= ((uint8_t) intermediate + 128) << (sizeof(uint8_t) * 8 * i); - } - return result; - #endif -} - -uint32_t add16signed(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return __QADD16(a, b); - #else - uint32_t result = 0; - for (int8_t i = 0; i < 2; i++) { - int16_t ai = a >> (sizeof(int16_t) * 8 * i); - int16_t bi = b >> (sizeof(int16_t) * 8 * i); - int32_t intermediate = (int32_t) ai + bi; - if (intermediate > SHRT_MAX) { - intermediate = SHRT_MAX; - } else if (intermediate < SHRT_MIN) { - intermediate = SHRT_MIN; - } - result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); - } - return result; - #endif -} - -uint32_t add16unsigned(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - // Subtract out the DC offset, add and then shift back. - a = __USUB16(a, 0x80008000); - b = __USUB16(b, 0x80008000); - uint32_t sum = __QADD16(a, b); - return __UADD16(sum, 0x80008000); - #else - uint32_t result = 0; - for (int8_t i = 0; i < 2; i++) { - int16_t ai = (a >> (sizeof(uint16_t) * 8 * i)) - 0x8000; - int16_t bi = (b >> (sizeof(uint16_t) * 8 * i)) - 0x8000; - int32_t intermediate = (int32_t) ai + bi; - if (intermediate > USHRT_MAX) { - intermediate = USHRT_MAX; - } - result |= ((uint16_t) intermediate + 0x8000) << (sizeof(int16_t) * 8 * i); - } - return result; - #endif -} - -audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, - bool single_channel, - uint8_t channel, - uint8_t** buffer, - uint32_t* buffer_length) { - if (!single_channel) { - channel = 0; - } - - uint32_t channel_read_count = self->left_read_count; - if (channel == 1) { - channel_read_count = self->right_read_count; - } - *buffer_length = self->len; - - bool need_more_data = self->read_count == channel_read_count; - if (need_more_data) { - uint32_t* word_buffer; - if (self->use_first_buffer) { - *buffer = (uint8_t*) self->first_buffer; - word_buffer = self->first_buffer; - } else { - *buffer = (uint8_t*) self->second_buffer; - word_buffer = self->second_buffer; - } - self->use_first_buffer = !self->use_first_buffer; - bool voices_active = false; - for (int32_t v = 0; v < self->voice_count; v++) { - audioio_mixer_voice_t* voice = &self->voice[v]; - - uint32_t j = 0; - bool voice_done = voice->sample == NULL; - for (uint32_t i = 0; i < self->len / sizeof(uint32_t); i++) { - if (!voice_done && j >= voice->buffer_length) { - if (!voice->more_data) { - if (voice->loop) { - audiosample_reset_buffer(voice->sample, false, 0); - } else { - voice->sample = NULL; - voice_done = true; - } - } - if (!voice_done) { - // Load another buffer - audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); - // Track length in terms of words. - voice->buffer_length /= sizeof(uint32_t); - voice->more_data = result == GET_BUFFER_MORE_DATA; - j = 0; - } - } - // First active voice gets copied over verbatim. - uint32_t sample_value; - if (voice_done) { - // Exit early if another voice already set all samples once. - if (voices_active) { - continue; - } - sample_value = 0; - if (!self->samples_signed) { - if (self->bits_per_sample == 8) { - sample_value = 0x7f7f7f7f; - } else { - sample_value = 0x7fff7fff; - } - } - } else { - sample_value = voice->remaining_buffer[j]; - } - - if (!voices_active) { - word_buffer[i] = sample_value; - } else { - if (self->bits_per_sample == 8) { - if (self->samples_signed) { - word_buffer[i] = add8signed(word_buffer[i], sample_value); - } else { - word_buffer[i] = add8unsigned(word_buffer[i], sample_value); - } - } else { - if (self->samples_signed) { - word_buffer[i] = add16signed(word_buffer[i], sample_value); - } else { - word_buffer[i] = add16unsigned(word_buffer[i], sample_value); - } - } - } - j++; - } - voice->buffer_length -= j; - voice->remaining_buffer += j; - - voices_active = true; - } - - self->read_count += 1; - } else if (!self->use_first_buffer) { - *buffer = (uint8_t*) self->first_buffer; - } else { - *buffer = (uint8_t*) self->second_buffer; - } - - - if (channel == 0) { - self->left_read_count += 1; - } else if (channel == 1) { - self->right_read_count += 1; - *buffer = *buffer + self->bits_per_sample / 8; - } - return GET_BUFFER_MORE_DATA; -} - -void audioio_mixer_get_buffer_structure(audioio_mixer_obj_t* self, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing) { - *single_buffer = false; - *samples_signed = self->samples_signed; - *max_buffer_length = self->len; - if (single_channel) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audioio/Mixer.h b/shared-module/audioio/Mixer.h deleted file mode 100644 index 6a88fe0bd..000000000 --- a/shared-module/audioio/Mixer.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H -#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H - -#include "py/obj.h" - -#include "shared-module/audioio/__init__.h" - -typedef struct { - mp_obj_t sample; - bool loop; - bool more_data; - uint32_t* remaining_buffer; - uint32_t buffer_length; -} audioio_mixer_voice_t; - -typedef struct { - mp_obj_base_t base; - uint32_t* first_buffer; - uint32_t* second_buffer; - uint32_t len; // in words - uint8_t bits_per_sample; - bool use_first_buffer; - bool samples_signed; - uint8_t channel_count; - uint32_t sample_rate; - - uint32_t read_count; - uint32_t left_read_count; - uint32_t right_read_count; - - uint8_t voice_count; - audioio_mixer_voice_t voice[]; -} audioio_mixer_obj_t; - - -// These are not available from Python because it may be called in an interrupt. -void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, - bool single_channel, - uint8_t channel); -audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, - bool single_channel, - uint8_t channel, - uint8_t** buffer, - uint32_t* buffer_length); // length in bytes -void audioio_mixer_get_buffer_structure(audioio_mixer_obj_t* self, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H diff --git a/shared-module/audioio/RawSample.c b/shared-module/audioio/RawSample.c deleted file mode 100644 index 6422e346b..000000000 --- a/shared-module/audioio/RawSample.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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 "shared-bindings/audioio/RawSample.h" - -#include - -#include "shared-module/audioio/RawSample.h" - -void common_hal_audioio_rawsample_construct(audioio_rawsample_obj_t* self, - uint8_t* buffer, - uint32_t len, - uint8_t bytes_per_sample, - bool samples_signed, - uint8_t channel_count, - uint32_t sample_rate) { - self->buffer = buffer; - self->bits_per_sample = bytes_per_sample * 8; - self->samples_signed = samples_signed; - self->len = len; - self->channel_count = channel_count; - self->sample_rate = sample_rate; - self->buffer_read = false; -} - -void common_hal_audioio_rawsample_deinit(audioio_rawsample_obj_t* self) { - self->buffer = NULL; -} -bool common_hal_audioio_rawsample_deinited(audioio_rawsample_obj_t* self) { - return self->buffer == NULL; -} - -uint32_t common_hal_audioio_rawsample_get_sample_rate(audioio_rawsample_obj_t* self) { - return self->sample_rate; -} -void common_hal_audioio_rawsample_set_sample_rate(audioio_rawsample_obj_t* self, - uint32_t sample_rate) { - self->sample_rate = sample_rate; -} - -void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t* self, - bool single_channel, - uint8_t channel) { -} - -audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t* self, - bool single_channel, - uint8_t channel, - uint8_t** buffer, - uint32_t* buffer_length) { - *buffer_length = self->len; - if (single_channel) { - *buffer = self->buffer + (channel % self->channel_count) * (self->bits_per_sample / 8); - } else { - *buffer = self->buffer; - } - return GET_BUFFER_DONE; -} - -void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t* self, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing) { - *single_buffer = true; - *samples_signed = self->samples_signed; - *max_buffer_length = self->len; - if (single_channel) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audioio/RawSample.h b/shared-module/audioio/RawSample.h deleted file mode 100644 index fe5283db4..000000000 --- a/shared-module/audioio/RawSample.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_RAWSAMPLE_H -#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_RAWSAMPLE_H - -#include "py/obj.h" - -#include "shared-module/audioio/__init__.h" - -typedef struct { - mp_obj_base_t base; - uint8_t* buffer; - uint32_t len; - uint8_t bits_per_sample; - bool samples_signed; - uint8_t channel_count; - uint32_t sample_rate; - bool buffer_read; -} audioio_rawsample_obj_t; - - -// These are not available from Python because it may be called in an interrupt. -void audioio_rawsample_reset_buffer(audioio_rawsample_obj_t* self, - bool single_channel, - uint8_t channel); -audioio_get_buffer_result_t audioio_rawsample_get_buffer(audioio_rawsample_obj_t* self, - bool single_channel, - uint8_t channel, - uint8_t** buffer, - uint32_t* buffer_length); // length in bytes -void audioio_rawsample_get_buffer_structure(audioio_rawsample_obj_t* self, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_RAWSAMPLE_H diff --git a/shared-module/audioio/WaveFile.c b/shared-module/audioio/WaveFile.c deleted file mode 100644 index d5dd9419c..000000000 --- a/shared-module/audioio/WaveFile.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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 "shared-bindings/audioio/WaveFile.h" - -#include -#include - -#include "py/mperrno.h" -#include "py/runtime.h" - -#include "shared-module/audioio/WaveFile.h" -#include "supervisor/shared/translate.h" - -struct wave_format_chunk { - uint16_t audio_format; - uint16_t num_channels; - uint32_t sample_rate; - uint32_t byte_rate; - uint16_t block_align; - uint16_t bits_per_sample; - uint16_t extra_params; // Assumed to be zero below. -}; - -void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, - pyb_file_obj_t* file) { - // Load the wave - self->file = file; - uint8_t chunk_header[16]; - f_rewind(&self->file->fp); - UINT bytes_read; - if (f_read(&self->file->fp, chunk_header, 16, &bytes_read) != FR_OK) { - mp_raise_OSError(MP_EIO); - } - if (bytes_read != 16 || - memcmp(chunk_header, "RIFF", 4) != 0 || - memcmp(chunk_header + 8, "WAVEfmt ", 8) != 0) { - mp_raise_ValueError(translate("Invalid wave file")); - } - uint32_t format_size; - if (f_read(&self->file->fp, &format_size, 4, &bytes_read) != FR_OK) { - mp_raise_OSError(MP_EIO); - } - if (bytes_read != 4 || - format_size > sizeof(struct wave_format_chunk)) { - mp_raise_ValueError(translate("Invalid format chunk size")); - } - struct wave_format_chunk format; - if (f_read(&self->file->fp, &format, format_size, &bytes_read) != FR_OK) { - mp_raise_OSError(MP_EIO); - } - if (bytes_read != format_size) { - } - - if (format.audio_format != 1 || - format.num_channels > 2 || - format.bits_per_sample > 16 || - (format_size == 18 && - format.extra_params != 0)) { - mp_raise_ValueError(translate("Unsupported format")); - } - // Get the sample_rate - self->sample_rate = format.sample_rate; - self->len = 256; - self->channel_count = format.num_channels; - self->bits_per_sample = format.bits_per_sample; - - // TODO(tannewt): Skip any extra chunks that occur before the data section. - - uint8_t data_tag[4]; - if (f_read(&self->file->fp, &data_tag, 4, &bytes_read) != FR_OK) { - mp_raise_OSError(MP_EIO); - } - if (bytes_read != 4 || - memcmp((uint8_t *) data_tag, "data", 4) != 0) { - mp_raise_ValueError(translate("Data chunk must follow fmt chunk")); - } - - uint32_t data_length; - if (f_read(&self->file->fp, &data_length, 4, &bytes_read) != FR_OK) { - mp_raise_OSError(MP_EIO); - } - if (bytes_read != 4) { - mp_raise_ValueError(translate("Invalid file")); - } - self->file_length = data_length; - self->data_start = self->file->fp.fptr; - - // Try to allocate two buffers, one will be loaded from file and the other - // DMAed to DAC. - self->buffer = m_malloc(self->len, false); - if (self->buffer == NULL) { - common_hal_audioio_wavefile_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); - } - - self->second_buffer = m_malloc(self->len, false); - if (self->second_buffer == NULL) { - common_hal_audioio_wavefile_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); - } -} - -void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self) { - self->buffer = NULL; -} - -bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self) { - return self->buffer == NULL; -} - -uint32_t common_hal_audioio_wavefile_get_sample_rate(audioio_wavefile_obj_t* self) { - return self->sample_rate; -} - -void common_hal_audioio_wavefile_set_sample_rate(audioio_wavefile_obj_t* self, - uint32_t sample_rate) { - self->sample_rate = sample_rate; -} - -uint8_t common_hal_audioio_wavefile_get_bits_per_sample(audioio_wavefile_obj_t* self) { - return self->bits_per_sample; -} - -uint8_t common_hal_audioio_wavefile_get_channel_count(audioio_wavefile_obj_t* self) { - return self->channel_count; -} - -bool audioio_wavefile_samples_signed(audioio_wavefile_obj_t* self) { - return self->bits_per_sample > 8; -} - -uint32_t audioio_wavefile_max_buffer_length(audioio_wavefile_obj_t* self) { - return 512; -} - -void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t* self, - bool single_channel, - uint8_t channel) { - if (single_channel && channel == 1) { - return; - } - // We don't reset the buffer index in case we're looping and we have an odd number of buffer - // loads - self->bytes_remaining = self->file_length; - f_lseek(&self->file->fp, self->data_start); - self->read_count = 0; - self->left_read_count = 0; - self->right_read_count = 0; -} - -audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self, - bool single_channel, - uint8_t channel, - uint8_t** buffer, - uint32_t* buffer_length) { - if (!single_channel) { - channel = 0; - } - - uint32_t channel_read_count = self->left_read_count; - if (channel == 1) { - channel_read_count = self->right_read_count; - } - - bool need_more_data = self->read_count == channel_read_count; - - if (self->bytes_remaining == 0 && need_more_data) { - *buffer = NULL; - *buffer_length = 0; - return GET_BUFFER_DONE; - } - - if (need_more_data) { - uint16_t num_bytes_to_load = self->len; - if (num_bytes_to_load > self->bytes_remaining) { - num_bytes_to_load = self->bytes_remaining; - } - UINT length_read; - if (self->buffer_index % 2 == 1) { - *buffer = self->second_buffer; - } else { - *buffer = self->buffer; - } - if (f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read) != FR_OK) { - return GET_BUFFER_ERROR; - } - self->bytes_remaining -= length_read; - // Pad the last buffer to word align it. - if (self->bytes_remaining == 0 && length_read % sizeof(uint32_t) != 0) { - uint32_t pad = length_read % sizeof(uint32_t); - length_read += pad; - if (self->bits_per_sample == 8) { - for (uint32_t i = 0; i < pad; i++) { - ((uint8_t*) (*buffer))[length_read / sizeof(uint8_t) - i - 1] = 0x80; - } - } else if (self->bits_per_sample == 16) { - // We know the buffer is aligned because we allocated it onto the heap ourselves. - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - ((int16_t*) (*buffer))[length_read / sizeof(int16_t) - 1] = 0; - #pragma GCC diagnostic pop - } - } - *buffer_length = length_read; - if (self->buffer_index % 2 == 1) { - self->second_buffer_length = length_read; - } else { - self->buffer_length = length_read; - } - self->buffer_index += 1; - self->read_count += 1; - } - - uint32_t buffers_back = self->read_count - 1 - channel_read_count; - if ((self->buffer_index - buffers_back) % 2 == 0) { - *buffer = self->second_buffer; - *buffer_length = self->second_buffer_length; - } else { - *buffer = self->buffer; - *buffer_length = self->buffer_length; - } - - if (channel == 0) { - self->left_read_count += 1; - } else if (channel == 1) { - self->right_read_count += 1; - *buffer = *buffer + self->bits_per_sample / 8; - } - - return self->bytes_remaining == 0 ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA; -} - -void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t* self, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing) { - *single_buffer = false; - *samples_signed = self->bits_per_sample > 8; - *max_buffer_length = 512; - if (single_channel) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audioio/WaveFile.h b/shared-module/audioio/WaveFile.h deleted file mode 100644 index 2cee2b1d2..000000000 --- a/shared-module/audioio/WaveFile.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H -#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H - -#include "py/obj.h" - -#include "shared-module/audioio/__init__.h" - -typedef struct { - mp_obj_base_t base; - uint8_t* buffer; - uint32_t buffer_length; - uint8_t* second_buffer; - uint32_t second_buffer_length; - uint32_t file_length; // In bytes - uint16_t data_start; // Where the data values start - uint8_t bits_per_sample; - uint16_t buffer_index; - uint32_t bytes_remaining; - - uint8_t channel_count; - uint32_t sample_rate; - - uint32_t len; - pyb_file_obj_t* file; - - uint32_t read_count; - uint32_t left_read_count; - uint32_t right_read_count; -} audioio_wavefile_obj_t; - -// These are not available from Python because it may be called in an interrupt. -void audioio_wavefile_reset_buffer(audioio_wavefile_obj_t* self, - bool single_channel, - uint8_t channel); -audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t* self, - bool single_channel, - uint8_t channel, - uint8_t** buffer, - uint32_t* buffer_length); // length in bytes -void audioio_wavefile_get_buffer_structure(audioio_wavefile_obj_t* self, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H diff --git a/shared-module/audioio/__init__.c b/shared-module/audioio/__init__.c index b87b06a83..e69de29bb 100644 --- a/shared-module/audioio/__init__.c +++ b/shared-module/audioio/__init__.c @@ -1,125 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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 "shared-module/audioio/__init__.h" - -#include "py/obj.h" -#include "shared-bindings/audioio/Mixer.h" -#include "shared-bindings/audioio/RawSample.h" -#include "shared-bindings/audioio/WaveFile.h" -#include "shared-module/audioio/Mixer.h" -#include "shared-module/audioio/RawSample.h" -#include "shared-module/audioio/WaveFile.h" - -uint32_t audiosample_sample_rate(mp_obj_t sample_obj) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - return sample->sample_rate; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return file->sample_rate; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); - return mixer->sample_rate; - } - return 16000; -} - -uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - return sample->bits_per_sample; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return file->bits_per_sample; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); - return mixer->bits_per_sample; - } - return 8; -} - -uint8_t audiosample_channel_count(mp_obj_t sample_obj) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - return sample->channel_count; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return file->channel_count; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); - return mixer->channel_count; - } - return 1; -} - -void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - audioio_rawsample_reset_buffer(sample, single_channel, audio_channel); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - audioio_wavefile_reset_buffer(file, single_channel, audio_channel); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - audioio_mixer_reset_buffer(file, single_channel, audio_channel); - } -} - -audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, - bool single_channel, - uint8_t channel, - uint8_t** buffer, uint32_t* buffer_length) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - return audioio_rawsample_get_buffer(sample, single_channel, channel, buffer, buffer_length); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return audioio_wavefile_get_buffer(file, single_channel, channel, buffer, buffer_length); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return audioio_mixer_get_buffer(file, single_channel, channel, buffer, buffer_length); - } - return GET_BUFFER_DONE; -} - -void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing) { - if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { - audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); - audioio_rawsample_get_buffer_structure(sample, single_channel, single_buffer, - samples_signed, max_buffer_length, spacing); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { - audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - audioio_wavefile_get_buffer_structure(file, single_channel, single_buffer, samples_signed, - max_buffer_length, spacing); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - audioio_mixer_get_buffer_structure(file, single_channel, single_buffer, samples_signed, - max_buffer_length, spacing); - } -} diff --git a/shared-module/audioio/__init__.h b/shared-module/audioio/__init__.h index c805f3116..53b2d4a16 100644 --- a/shared-module/audioio/__init__.h +++ b/shared-module/audioio/__init__.h @@ -27,27 +27,6 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO__INIT__H #define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO__INIT__H -#include -#include - -#include "py/obj.h" - -typedef enum { - GET_BUFFER_DONE, // No more data to read - GET_BUFFER_MORE_DATA, // More data to read. - GET_BUFFER_ERROR, // Error while reading data. -} audioio_get_buffer_result_t; - -uint32_t audiosample_sample_rate(mp_obj_t sample_obj); -uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj); -uint8_t audiosample_channel_count(mp_obj_t sample_obj); -void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t audio_channel); -audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, - bool single_channel, - uint8_t channel, - uint8_t** buffer, uint32_t* buffer_length); -void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing); +#include "shared-module/audiocore/__init__.h" #endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO__INIT__H -- cgit v1.2.3 From af8cfbedfb921bfead84a4fab08f5bf9f86274e5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 24 Jul 2019 13:25:34 -0700 Subject: Add knobs for SSD1322 and two fixes. * Fix terminal clear after first successful code.py run. * Fix transmitting too many bytes for column constraint with single byte bounds. --- shared-bindings/displayio/Display.c | 16 +++++++++---- shared-bindings/displayio/Display.h | 5 ++-- shared-module/displayio/Display.c | 27 ++++++++++++++------- shared-module/displayio/Palette.h | 2 ++ shared-module/displayio/TileGrid.c | 6 ++++- shared-module/displayio/__init__.c | 48 ++++++++++++++++++------------------- supervisor/shared/display.c | 3 ++- 7 files changed, 66 insertions(+), 41 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 361a37ece..9cb4d6e74 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -51,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the initialization sequence at minimum. //| -//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) +//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, bytes_per_cell=1, reverse_pixels_in_byte=False, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) //| //| Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -90,6 +90,8 @@ //| support 18 bit but 16 is easier to transmit. The last bit is extrapolated.) //| :param bool grayscale: True if the display only shows a single color. //| :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column. +//| :param int bytes_per_cell: Number of bytes per addressable memory location when color_depth < 8. When greater than one, bytes share a row or column according to pixels_in_byte_share_row. +//| :param bool reverse_pixels_in_byte: Reverses the pixel order within each byte when color_depth < 8. Does not apply across multiple bytes even if there is more than one byte per cell (bytes_per_cell.) //| :param int set_column_command: Command used to set the start and end columns to update //| :param int set_row_command: Command used so set the start and end rows to update //| :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set. @@ -102,7 +104,7 @@ //| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. //| STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -114,6 +116,8 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_pixels_in_byte_share_row, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_bytes_per_cell, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, + { MP_QSTR_reverse_pixels_in_byte, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} }, { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} }, { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, @@ -163,7 +167,8 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a common_hal_displayio_display_construct( self, display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, - args[ARG_color_depth].u_int, args[ARG_grayscale].u_bool, args[ARG_pixels_in_byte_share_row].u_bool, + args[ARG_color_depth].u_int, args[ARG_grayscale].u_bool, + args[ARG_pixels_in_byte_share_row].u_bool, args[ARG_bytes_per_cell].u_bool, args[ARG_reverse_pixels_in_byte].u_bool, args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int, args[ARG_write_ram_command].u_int, args[ARG_set_vertical_scroll].u_int, @@ -199,7 +204,10 @@ STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) group = MP_OBJ_TO_PTR(native_group(group_in)); } - common_hal_displayio_display_show(self, group); + bool ok = common_hal_displayio_display_show(self, group); + if (!ok) { + mp_raise_ValueError(translate("Group already used")); + } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index e765e6f25..a8938bbcd 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -40,7 +40,8 @@ extern const mp_obj_type_t displayio_display_type; void common_hal_displayio_display_construct(displayio_display_obj_t* self, mp_obj_t bus, uint16_t width, uint16_t height, - int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, + int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, + bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, @@ -48,7 +49,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self); -void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); +bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index a8515b9e5..51c6f292a 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -44,7 +44,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, - uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, + uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, @@ -52,6 +52,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->colorspace.depth = color_depth; self->colorspace.grayscale = grayscale; self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row; + self->colorspace.bytes_per_cell = bytes_per_cell; + self->colorspace.reverse_pixels_in_byte = reverse_pixels_in_byte; self->set_column_command = set_column_command; self->set_row_command = set_row_command; self->write_ram_command = write_ram_command; @@ -195,17 +197,25 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, common_hal_displayio_display_show(self, &circuitpython_splash); } -void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { +bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { if (root_group == NULL) { root_group = &circuitpython_splash; } if (root_group == self->current_group) { - return; + return true; + } + if (root_group->in_group) { + return false; + } + if (self->current_group != NULL) { + self->current_group->in_group = false; } displayio_group_update_transform(root_group, &self->transform); + root_group->in_group = true; self->current_group = root_group; self->full_refresh = true; common_hal_displayio_display_refresh_soon(self); + return true; } void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self) { @@ -299,11 +309,11 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ if (self->colorspace.depth < 8) { uint8_t pixels_per_byte = 8 / self->colorspace.depth; if (self->colorspace.pixels_in_byte_share_row) { - x1 /= pixels_per_byte; - x2 /= pixels_per_byte; + x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; + x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; } else { - y1 /= pixels_per_byte; - y2 /= pixels_per_byte; + y1 /= pixels_per_byte * self->colorspace.bytes_per_cell; + y2 /= pixels_per_byte * self->colorspace.bytes_per_cell; } } @@ -318,7 +328,6 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ if (self->single_byte_bounds) { data[data_length++] = x1 + self->colstart; data[data_length++] = x2 - 1 + self->colstart; - data_length += 2; } else { x1 += self->colstart; x2 += self->colstart - 1; @@ -413,7 +422,7 @@ bool displayio_display_clip_area(displayio_display_obj_t *self, const displayio_ // Expand the area if we have multiple pixels per byte and we need to byte // align the bounds. if (self->colorspace.depth < 8) { - uint8_t pixels_per_byte = 8 / self->colorspace.depth; + uint8_t pixels_per_byte = 8 / self->colorspace.depth * self->colorspace.bytes_per_cell; if (self->colorspace.pixels_in_byte_share_row) { if (clipped->x1 % pixels_per_byte != 0) { clipped->x1 -= clipped->x1 % pixels_per_byte; diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index 19c05baf5..a917e2432 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -36,6 +36,8 @@ typedef struct { uint8_t depth; bool grayscale; bool pixels_in_byte_share_row; + uint8_t bytes_per_cell; + bool reverse_pixels_in_byte; uint8_t hue; } _displayio_colorspace_t; diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 88873d3a9..fee2ae978 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -436,7 +436,11 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c // asm("bkpt"); // } } - ((uint8_t*)buffer)[offset / pixels_per_byte] |= pixel << ((offset % pixels_per_byte) * colorspace->depth); + uint8_t shift = (offset % pixels_per_byte) * colorspace->depth; + if (colorspace->reverse_pixels_in_byte) { + shift = (pixels_per_byte - 1) * colorspace->depth - shift; + } + ((uint8_t*)buffer)[offset / pixels_per_byte] |= pixel << shift; } } } diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 97060aaeb..8f6e650a1 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -209,35 +209,35 @@ void reset_displays(void) { } } } else if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type) { - displayio_i2cdisplay_obj_t* i2c = &displays[i].i2cdisplay_bus; - if (((uint32_t) i2c->bus) < ((uint32_t) &displays) || - ((uint32_t) i2c->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) { - busio_i2c_obj_t* original_i2c = i2c->bus; - #if BOARD_I2C - // We don't need to move original_i2c if it is the board.SPI object because it is - // statically allocated already. (Doing so would also make it impossible to reference in - // a subsequent VM run.) - if (original_i2c == common_hal_board_get_i2c()) { - continue; - } - #endif - memcpy(&i2c->inline_bus, original_i2c, sizeof(busio_i2c_obj_t)); - i2c->bus = &i2c->inline_bus; - // Check for other displays that use the same i2c bus and swap them too. - for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) { - if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type && - displays[i].i2cdisplay_bus.bus == original_i2c) { - displays[i].i2cdisplay_bus.bus = &i2c->inline_bus; - } + displayio_i2cdisplay_obj_t* i2c = &displays[i].i2cdisplay_bus; + if (((uint32_t) i2c->bus) < ((uint32_t) &displays) || + ((uint32_t) i2c->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) { + busio_i2c_obj_t* original_i2c = i2c->bus; + #if BOARD_I2C + // We don't need to move original_i2c if it is the board.SPI object because it is + // statically allocated already. (Doing so would also make it impossible to reference in + // a subsequent VM run.) + if (original_i2c == common_hal_board_get_i2c()) { + continue; + } + #endif + memcpy(&i2c->inline_bus, original_i2c, sizeof(busio_i2c_obj_t)); + i2c->bus = &i2c->inline_bus; + // Check for other displays that use the same i2c bus and swap them too. + for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) { + if (displays[i].i2cdisplay_bus.base.type == &displayio_i2cdisplay_type && + displays[i].i2cdisplay_bus.bus == original_i2c) { + displays[i].i2cdisplay_bus.bus = &i2c->inline_bus; } } } - } - - for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].display.base.type == NULL) { + } else { + // Not an active display. continue; } + + // Reset the displayed group. Only the first will get the terminal but + // that's ok. displayio_display_obj_t* display = &displays[i].display; display->auto_brightness = true; common_hal_displayio_display_show(display, &circuitpython_splash); diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 6a39cbe8e..fd51e2c07 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -229,5 +229,6 @@ displayio_group_t circuitpython_splash = { .size = 2, .max_size = 2, .children = splash_children, - .item_removed = false + .item_removed = false, + .in_group = false }; -- cgit v1.2.3 From 54cde56ec5374f9b6c1aa9eb9dd6139b80df254a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 25 Jul 2019 17:55:57 -0500 Subject: audiopwmio: Add the shared files for this new module --- py/circuitpy_defns.mk | 6 + py/circuitpy_mpconfig.h | 8 + py/circuitpy_mpconfig.mk | 9 ++ shared-bindings/audiopwmio/AudioOut.c | 294 ++++++++++++++++++++++++++++++++++ shared-bindings/audiopwmio/AudioOut.h | 49 ++++++ shared-bindings/audiopwmio/__init__.c | 71 ++++++++ shared-bindings/audiopwmio/__init__.h | 34 ++++ shared-module/audiopwmio/__init__.c | 0 shared-module/audiopwmio/__init__.h | 32 ++++ 9 files changed, 503 insertions(+) create mode 100644 shared-bindings/audiopwmio/AudioOut.c create mode 100644 shared-bindings/audiopwmio/AudioOut.h create mode 100644 shared-bindings/audiopwmio/__init__.c create mode 100644 shared-bindings/audiopwmio/__init__.h create mode 100644 shared-module/audiopwmio/__init__.c create mode 100644 shared-module/audiopwmio/__init__.h (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index bdefc18cc..28d560a73 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -108,6 +108,9 @@ endif ifeq ($(CIRCUITPY_AUDIOIO),1) SRC_PATTERNS += audioio/% endif +ifeq ($(CIRCUITPY_AUDIOPWMIO),1) +SRC_PATTERNS += audiopwmio/% +endif ifeq ($(CIRCUITPY_AUDIOCORE),1) SRC_PATTERNS += audiocore/% endif @@ -223,6 +226,8 @@ $(filter $(SRC_PATTERNS), \ audiobusio/__init__.c \ audiobusio/I2SOut.c \ audiobusio/PDMIn.c \ + audiopwmio/__init__.c \ + audiopwmio/AudioOut.c \ audioio/__init__.c \ audioio/AudioOut.c \ bleio/__init__.c \ @@ -303,6 +308,7 @@ $(filter $(SRC_PATTERNS), \ _stage/Layer.c \ _stage/Text.c \ _stage/__init__.c \ + audiopwmio/__init__.c \ audioio/__init__.c \ audiocore/__init__.c \ audiocore/Mixer.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 3440eb052..d88d6538e 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -244,6 +244,13 @@ extern const struct _mp_obj_module_t audioio_module; #define AUDIOIO_MODULE #endif +#if CIRCUITPY_AUDIOPWMIO +#define AUDIOPWMIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiopwmio), (mp_obj_t)&audiopwmio_module }, +extern const struct _mp_obj_module_t audiopwmio_module; +#else +#define AUDIOPWMIO_MODULE +#endif + #if CIRCUITPY_BITBANGIO #define BITBANGIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }, extern const struct _mp_obj_module_t bitbangio_module; @@ -573,6 +580,7 @@ extern const struct _mp_obj_module_t ustack_module; AUDIOBUSIO_MODULE \ AUDIOCORE_MODULE \ AUDIOIO_MODULE \ + AUDIOPWMIO_MODULE \ BITBANGIO_MODULE \ BLEIO_MODULE \ BOARD_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 772a1c3e1..a408cd7ac 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -74,9 +74,18 @@ CIRCUITPY_AUDIOIO = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) +ifndef CIRCUITPY_AUDIOPWMIO +CIRCUITPY_AUDIOPWMIO = 0 +endif +CFLAGS += -DCIRCUITPY_AUDIOPWMIO=$(CIRCUITPY_AUDIOPWMIO) + ifndef CIRCUITPY_AUDIOCORE +ifeq ($(CIRCUITPY_AUDIOPWMIO),1) +CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOPWMIO) +else CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOIO) endif +endif CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE) ifndef CIRCUITPY_BITBANGIO diff --git a/shared-bindings/audiopwmio/AudioOut.c b/shared-bindings/audiopwmio/AudioOut.c new file mode 100644 index 000000000..37c845165 --- /dev/null +++ b/shared-bindings/audiopwmio/AudioOut.c @@ -0,0 +1,294 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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 + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiopwmio/AudioOut.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audiopwmio +//| +//| :class:`AudioOut` -- Output an analog audio signal +//| ======================================================== +//| +//| AudioOut can be used to output an analog audio signal on a given pin. +//| +//| .. class:: AudioOut(left_channel, *, right_channel=None, quiescent_value=0x8000) +//| +//| Create a AudioOut object associated with the given pin(s). This allows you to +//| play audio signals out on the given pin(s). In contrast to mod:`audioio`, +//| the pin(s) specified are digital pins, and are driven with a device-dependent PWM +//| signal. +//| +//| :param ~microcontroller.Pin left_channel: The pin to output the left channel to +//| :param ~microcontroller.Pin right_channel: The pin to output the right channel to +//| :param int quiescent_value: The output value when no signal is present. Samples should start +//| and end with this value to prevent audible popping. +//| +//| Simple 8ksps 440 Hz sin wave:: +//| +//| import audiocore +//| import audiopwmio +//| import board +//| import array +//| import time +//| import math +//| +//| # Generate one period of sine wav. +//| length = 8000 // 440 +//| sine_wave = array.array("H", [0] * length) +//| for i in range(length): +//| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15) + 2 ** 15) +//| +//| dac = audiopwmio.AudioOut(board.SPEAKER) +//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) +//| dac.play(sine_wave, loop=True) +//| time.sleep(1) +//| dac.stop() +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audiocore +//| import audiopwmio +//| import digitalio +//| +//| # Required for CircuitPlayground Express +//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) +//| speaker_enable.switch_to_output(value=True) +//| +//| data = open("cplay-5.1-16bit-16khz.wav", "rb") +//| wav = audiocore.WaveFile(data) +//| a = audiopwmio.AudioOut(board.SPEAKER) +//| +//| print("playing") +//| a.play(wav) +//| while a.playing: +//| pass +//| print("stopped") +//| +STATIC mp_obj_t audiopwmio_audioout_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_left_channel, ARG_right_channel, ARG_quiescent_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_left_channel, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_right_channel, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = mp_const_none} }, + { MP_QSTR_quiescent_value, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x8000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t left_channel_obj = args[ARG_left_channel].u_obj; + assert_pin(left_channel_obj, false); + const mcu_pin_obj_t *left_channel_pin = MP_OBJ_TO_PTR(left_channel_obj); + + mp_obj_t right_channel_obj = args[ARG_right_channel].u_obj; + const mcu_pin_obj_t *right_channel_pin = NULL; + if (right_channel_obj != mp_const_none) { + assert_pin(right_channel_obj, false); + right_channel_pin = MP_OBJ_TO_PTR(right_channel_obj); + } + + // create AudioOut object from the given pin + audiopwmio_audioout_obj_t *self = m_new_obj(audiopwmio_audioout_obj_t); + self->base.type = &audiopwmio_audioout_type; + common_hal_audiopwmio_audioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the AudioOut and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audiopwmio_audioout_deinit(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiopwmio_audioout_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_deinit_obj, audiopwmio_audioout_deinit); + +STATIC void check_for_deinit(audiopwmio_audioout_obj_t *self) { + if (common_hal_audiopwmio_audioout_deinited(self)) { + raise_deinited_error(); + } +} +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audiopwmio_audioout_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audiopwmio_audioout_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiopwmio_audioout___exit___obj, 4, 4, audiopwmio_audioout_obj___exit__); + + +//| .. method:: play(sample, *, loop=False) +//| +//| Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audiopwmio.WaveFile` or `audiopwmio.RawSample`. +//| +//| The sample itself should consist of 16 bit samples. Microcontrollers with a lower output +//| resolution will use the highest order bits to output. For example, the SAMD21 has a 10 bit +//| DAC that ignores the lowest 6 bits when playing 16 bit samples. +//| +STATIC mp_obj_t audiopwmio_audioout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audiopwmio_audioout_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiopwmio_audioout_play_obj, 1, audiopwmio_audioout_obj_play); + +//| .. method:: stop() +//| +//| Stops playback and resets to the start of the sample. +//| +STATIC mp_obj_t audiopwmio_audioout_obj_stop(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_audiopwmio_audioout_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_stop_obj, audiopwmio_audioout_obj_stop); + +//| .. attribute:: playing +//| +//| True when an audio sample is being output even if `paused`. (read-only) +//| +STATIC mp_obj_t audiopwmio_audioout_obj_get_playing(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiopwmio_audioout_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_get_playing_obj, audiopwmio_audioout_obj_get_playing); + +const mp_obj_property_t audiopwmio_audioout_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiopwmio_audioout_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. method:: pause() +//| +//| Stops playback temporarily while remembering the position. Use `resume` to resume playback. +//| +STATIC mp_obj_t audiopwmio_audioout_obj_pause(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (!common_hal_audiopwmio_audioout_get_playing(self)) { + mp_raise_RuntimeError(translate("Not playing")); + } + common_hal_audiopwmio_audioout_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_pause_obj, audiopwmio_audioout_obj_pause); + +//| .. method:: resume() +//| +//| Resumes sample playback after :py:func:`pause`. +//| +STATIC mp_obj_t audiopwmio_audioout_obj_resume(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (common_hal_audiopwmio_audioout_get_paused(self)) { + common_hal_audiopwmio_audioout_resume(self); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_resume_obj, audiopwmio_audioout_obj_resume); + +//| .. attribute:: paused +//| +//| True when playback is paused. (read-only) +//| +STATIC mp_obj_t audiopwmio_audioout_obj_get_paused(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiopwmio_audioout_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_get_paused_obj, audiopwmio_audioout_obj_get_paused); + +const mp_obj_property_t audiopwmio_audioout_paused_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiopwmio_audioout_get_paused_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t audiopwmio_audioout_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiopwmio_audioout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiopwmio_audioout___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiopwmio_audioout_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiopwmio_audioout_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&audiopwmio_audioout_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&audiopwmio_audioout_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiopwmio_audioout_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&audiopwmio_audioout_paused_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audiopwmio_audioout_locals_dict, audiopwmio_audioout_locals_dict_table); + +const mp_obj_type_t audiopwmio_audioout_type = { + { &mp_type_type }, + .name = MP_QSTR_PWMAudioOut, + .make_new = audiopwmio_audioout_make_new, + .locals_dict = (mp_obj_dict_t*)&audiopwmio_audioout_locals_dict, +}; diff --git a/shared-bindings/audiopwmio/AudioOut.h b/shared-bindings/audiopwmio/AudioOut.h new file mode 100644 index 000000000..7fb0e0f33 --- /dev/null +++ b/shared-bindings/audiopwmio/AudioOut.h @@ -0,0 +1,49 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO_AUDIOOUT_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO_AUDIOOUT_H + +#include "common-hal/audiopwmio/AudioOut.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/audiocore/RawSample.h" + +extern const mp_obj_type_t audiopwmio_audioout_type; + +// left_channel will always be non-NULL but right_channel may be for mono output. +void common_hal_audiopwmio_audioout_construct(audiopwmio_audioout_obj_t* self, + const mcu_pin_obj_t* left_channel, const mcu_pin_obj_t* right_channel, uint16_t default_value); + +void common_hal_audiopwmio_audioout_deinit(audiopwmio_audioout_obj_t* self); +bool common_hal_audiopwmio_audioout_deinited(audiopwmio_audioout_obj_t* self); +void common_hal_audiopwmio_audioout_play(audiopwmio_audioout_obj_t* self, mp_obj_t sample, bool loop); +void common_hal_audiopwmio_audioout_stop(audiopwmio_audioout_obj_t* self); +bool common_hal_audiopwmio_audioout_get_playing(audiopwmio_audioout_obj_t* self); +void common_hal_audiopwmio_audioout_pause(audiopwmio_audioout_obj_t* self); +void common_hal_audiopwmio_audioout_resume(audiopwmio_audioout_obj_t* self); +bool common_hal_audiopwmio_audioout_get_paused(audiopwmio_audioout_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO_AUDIOOUT_H diff --git a/shared-bindings/audiopwmio/__init__.c b/shared-bindings/audiopwmio/__init__.c new file mode 100644 index 000000000..6253d1e8e --- /dev/null +++ b/shared-bindings/audiopwmio/__init__.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiopwmio/__init__.h" +#include "shared-bindings/audiopwmio/AudioOut.h" + +//| :mod:`audiopwmio` --- Support for audio input and output +//| ======================================================== +//| +//| .. module:: audiopwmio +//| :synopsis: Support for audio output via digital PWM +//| :platform: NRF52 +//| +//| The `audiopwmio` module contains classes to provide access to audio IO. +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| AudioOut +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +//| Since CircuitPython 5, `Mixer`, `RawSample` and `WaveFile` are moved +//| to :mod:`audiocore`. +//| + +STATIC const mp_rom_map_elem_t audiopwmio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiopwmio) }, + { MP_ROM_QSTR(MP_QSTR_AudioOut), MP_ROM_PTR(&audiopwmio_audioout_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(audiopwmio_module_globals, audiopwmio_module_globals_table); + +const mp_obj_module_t audiopwmio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&audiopwmio_module_globals, +}; diff --git a/shared-bindings/audiopwmio/__init__.h b/shared-bindings/audiopwmio/__init__.h new file mode 100644 index 000000000..e4b7067d1 --- /dev/null +++ b/shared-bindings/audiopwmio/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H + +#include "py/obj.h" + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H diff --git a/shared-module/audiopwmio/__init__.c b/shared-module/audiopwmio/__init__.c new file mode 100644 index 000000000..e69de29bb diff --git a/shared-module/audiopwmio/__init__.h b/shared-module/audiopwmio/__init__.h new file mode 100644 index 000000000..964e4aafe --- /dev/null +++ b/shared-module/audiopwmio/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOPWMIO__INIT__H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOPWMIO__INIT__H + +#include "shared-module/audiocore/__init__.h" + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOPWMIO__INIT__H -- cgit v1.2.3 From 7b9d26cefe02d1a357b2594339db474b7c5cd88e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 15 Jul 2019 19:56:21 -0500 Subject: WavFile.h: include vfs_fat.h for pyb_file_obj_t definition Without such a definition, this header is not self-contained, but requires whoever included it to also include vfs_fat.h --- shared-module/audiocore/WaveFile.h | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-module') diff --git a/shared-module/audiocore/WaveFile.h b/shared-module/audiocore/WaveFile.h index 97dd6a46f..3eecbf15c 100644 --- a/shared-module/audiocore/WaveFile.h +++ b/shared-module/audiocore/WaveFile.h @@ -27,6 +27,7 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H #define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H +#include "extmod/vfs_fat.h" #include "py/obj.h" #include "shared-module/audiocore/__init__.h" -- cgit v1.2.3 From 28ca05ccdcf674ad128f357ac8f54a1931560331 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 27 Jul 2019 13:20:59 -0400 Subject: allow discovery from central or peripheral --- ports/nrf/boards/make-pins.py | 208 ------------ ports/nrf/common-hal/bleio/Central.c | 335 +------------------- ports/nrf/common-hal/bleio/Central.h | 4 +- ports/nrf/common-hal/bleio/Characteristic.c | 66 ++-- ports/nrf/common-hal/bleio/CharacteristicBuffer.c | 2 +- ports/nrf/common-hal/bleio/Peripheral.c | 15 +- ports/nrf/common-hal/bleio/Peripheral.h | 6 +- ports/nrf/common-hal/bleio/Service.c | 5 + ports/nrf/common-hal/bleio/Service.h | 2 + ports/nrf/common-hal/bleio/__init__.c | 365 +++++++++++++++++++++- ports/nrf/common-hal/bleio/__init__.h | 8 +- ports/nrf/nrfx_config.h | 1 + ports/nrf/peripherals/nrf/timers.c | 2 +- shared-bindings/bleio/Central.c | 77 +++-- shared-bindings/bleio/Central.h | 2 +- shared-bindings/bleio/Peripheral.c | 72 ++++- shared-bindings/bleio/Peripheral.h | 2 +- shared-bindings/bleio/Service.c | 22 ++ shared-bindings/bleio/Service.h | 1 + shared-bindings/bleio/__init__.h | 11 + shared-module/bleio/__init__.h | 6 - 21 files changed, 564 insertions(+), 648 deletions(-) delete mode 100644 ports/nrf/boards/make-pins.py (limited to 'shared-module') diff --git a/ports/nrf/boards/make-pins.py b/ports/nrf/boards/make-pins.py deleted file mode 100644 index d1cfd5b70..000000000 --- a/ports/nrf/boards/make-pins.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python -"""Creates the pin file for the nRF5.""" - -from __future__ import print_function - -import argparse -import sys -import csv - - -def parse_port_pin(name_str): - """Parses a string and returns a (port-num, pin-num) tuple.""" - if len(name_str) < 4: - raise ValueError("Expecting pin name to be at least 5 charcters.") - if name_str[0] != 'P': - raise ValueError("Expecting pin name to start with P") - if name_str[1] not in ('0', '1'): - raise ValueError("Expecting pin port to be in 0 or 1") - port = ord(name_str[1]) - ord('0') - pin_str = name_str[3:] - if not pin_str.isdigit(): - raise ValueError("Expecting numeric pin number.") - return (port, int(pin_str)) - - -class Pin(object): - """Holds the information associated with a pin.""" - - def __init__(self, port, pin): - self.port = port - self.pin = pin - self.adc_channel = '0' - self.board_pin = False - - def cpu_pin_name(self): - return 'P{:d}_{:02d}'.format(self.port, self.pin) - - def is_board_pin(self): - return self.board_pin - - def set_is_board_pin(self): - self.board_pin = True - - def parse_adc(self, adc_str): - if (adc_str[:3] != 'AIN'): - return - self.adc_channel = 'SAADC_CH_PSELP_PSELP_AnalogInput%d' % int(adc_str[3]) - - def print(self): - print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s});'.format( - self.cpu_pin_name(), self.cpu_pin_name(), - self.port, self.pin, self.adc_channel)) - - def print_header(self, hdr_file): - hdr_file.write('extern const pin_obj_t pin_{:s};\n'. - format(self.cpu_pin_name())) - - -class NamedPin(object): - - def __init__(self, name, pin): - self._name = name - self._pin = pin - - def pin(self): - return self._pin - - def name(self): - return self._name - - -class Pins(object): - - def __init__(self): - self.cpu_pins = [] # list of NamedPin objects - self.board_pins = [] # list of NamedPin objects - - def find_pin(self, port_num, pin_num): - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.port == port_num and pin.pin == pin_num: - return pin - - def parse_af_file(self, filename): - with open(filename, 'r') as csvfile: - rows = csv.reader(csvfile) - for row in rows: - try: - (port_num, pin_num) = parse_port_pin(row[0]) - except: - continue - pin = Pin(port_num, pin_num) - if len(row) > 1: - pin.parse_adc(row[1]) - self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) - - def parse_board_file(self, filename): - with open(filename, 'r') as csvfile: - rows = csv.reader(csvfile) - for row in rows: - try: - (port_num, pin_num) = parse_port_pin(row[1]) - except: - continue - pin = self.find_pin(port_num, pin_num) - if pin: - pin.set_is_board_pin() - self.board_pins.append(NamedPin(row[0], pin)) - - def print_named(self, label, named_pins): - print('') - print('STATIC const mp_rom_map_elem_t {:s}_table[] = {{'.format(label)) - for named_pin in named_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name())) - print('};') - print('MP_DEFINE_CONST_DICT({:s}, {:s}_table);'.format(label, label)) - - def print(self): - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - pin.print() - self.print_named('mcu_pin_globals', self.cpu_pins) - self.print_named('board_module_globals', self.board_pins) - - def print_header(self, hdr_filename): - with open(hdr_filename, 'wt') as hdr_file: - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - pin.print_header(hdr_file) - - def print_qstr(self, qstr_filename): - with open(qstr_filename, 'wt') as qstr_file: - qstr_set = set([]) - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - qstr_set |= set([named_pin.name()]) - for named_pin in self.board_pins: - qstr_set |= set([named_pin.name()]) - for qstr in sorted(qstr_set): - print('Q({})'.format(qstr), file=qstr_file) - - -def main(): - parser = argparse.ArgumentParser( - prog="make-pins.py", - usage="%(prog)s [options] [command]", - description="Generate board specific pin file" - ) - parser.add_argument( - "-a", "--af", - dest="af_filename", - help="Specifies the alternate function file for the chip", - default="nrf_af.csv" - ) - parser.add_argument( - "-b", "--board", - dest="board_filename", - help="Specifies the board file", - ) - parser.add_argument( - "-p", "--prefix", - dest="prefix_filename", - help="Specifies beginning portion of generated pins file", - default="nrf52_prefix.c" - ) - parser.add_argument( - "-q", "--qstr", - dest="qstr_filename", - help="Specifies name of generated qstr header file", - default="build/pins_qstr.h" - ) - parser.add_argument( - "-r", "--hdr", - dest="hdr_filename", - help="Specifies name of generated pin header file", - default="build/pins.h" - ) - args = parser.parse_args(sys.argv[1:]) - - pins = Pins() - - print('// This file was automatically generated by make-pins.py') - print('//') - if args.af_filename: - print('// --af {:s}'.format(args.af_filename)) - pins.parse_af_file(args.af_filename) - - if args.board_filename: - print('// --board {:s}'.format(args.board_filename)) - pins.parse_board_file(args.board_filename) - - if args.prefix_filename: - print('// --prefix {:s}'.format(args.prefix_filename)) - print('') - with open(args.prefix_filename, 'r') as prefix_file: - print(prefix_file.read()) - pins.print() - pins.print_header(args.hdr_filename) - pins.print_qstr(args.qstr_filename) - - -if __name__ == "__main__": - main() diff --git a/ports/nrf/common-hal/bleio/Central.c b/ports/nrf/common-hal/bleio/Central.c index d90737411..c42a2084a 100644 --- a/ports/nrf/common-hal/bleio/Central.c +++ b/ports/nrf/common-hal/bleio/Central.c @@ -35,216 +35,8 @@ #include "py/objstr.h" #include "py/runtime.h" #include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Central.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -static bleio_service_obj_t *m_char_discovery_service; -static bleio_characteristic_obj_t *m_desc_discovery_characteristic; - -static volatile bool m_discovery_in_process; -static volatile bool m_discovery_successful; - -// service_uuid may be NULL, to discover all services. -STATIC bool discover_next_services(bleio_central_obj_t *self, uint16_t start_handle, ble_uuid_t *service_uuid) { - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_primary_services_discover(self->conn_handle, start_handle, service_uuid); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg(translate("Failed to discover services")); - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_characteristics(bleio_central_obj_t *self, bleio_service_obj_t *service, uint16_t start_handle) { - m_char_discovery_service = service; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = service->end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_characteristics_discover(self->conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_descriptors(bleio_central_obj_t *self, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { - m_desc_discovery_characteristic = characteristic; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_descriptors_discover(self->conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_service_t *gattc_service = &response->services[i]; - - bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); - service->base.type = &bleio_service_type; - - // Initialize several fields at once. - common_hal_bleio_service_construct(service, NULL, mp_obj_new_list(0, NULL), false); - - service->device = MP_OBJ_FROM_PTR(central); - service->start_handle = gattc_service->handle_range.start_handle; - service->end_handle = gattc_service->handle_range.end_handle; - service->handle = gattc_service->handle_range.start_handle; - - if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known service UUID. - bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); - service->uuid = uuid; - service->device = MP_OBJ_FROM_PTR(central); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just set the UUID to NULL. - service->uuid = NULL; - } - - mp_obj_list_append(central->service_list, service); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_char_t *gattc_char = &response->chars[i]; - - bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); - characteristic->base.type = &bleio_characteristic_type; - - characteristic->descriptor_list = mp_obj_new_list(0, NULL); - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known characteristic UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - bleio_characteristic_properties_t props; - - props.broadcast = gattc_char->char_props.broadcast; - props.indicate = gattc_char->char_props.indicate; - props.notify = gattc_char->char_props.notify; - props.read = gattc_char->char_props.read; - props.write = gattc_char->char_props.write; - props.write_no_response = gattc_char->char_props.write_wo_resp; - - // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. - common_hal_bleio_characteristic_construct(characteristic, uuid, props, mp_obj_new_list(0, NULL)); - characteristic->handle = gattc_char->handle_value; - characteristic->service = m_char_discovery_service; - - mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_desc_t *gattc_desc = &response->descs[i]; - - // Remember handles for certain well-known descriptors. - switch (gattc_desc->uuid.uuid) { - case DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION: - m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; - break; - - case DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION: - m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; - break; - - case DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION: - m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; - break; - - default: - // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, - // so ignore those. - // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors - break; - } - - bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); - descriptor->base.type = &bleio_descriptor_type; - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known descriptor UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - common_hal_bleio_descriptor_construct(descriptor, uuid); - descriptor->handle = gattc_desc->handle; - descriptor->characteristic = m_desc_discovery_characteristic; - - mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} +#include "common-hal/bleio/__init__.h" STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { bleio_central_obj_t *central = (bleio_central_obj_t*)central_in; @@ -262,20 +54,6 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { case BLE_GAP_EVT_DISCONNECTED: central->conn_handle = BLE_CONN_HANDLE_INVALID; - m_discovery_successful = false; - m_discovery_in_process = false; - break; - - case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: - on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, central); - break; - - case BLE_GATTC_EVT_CHAR_DISC_RSP: - on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, central); - break; - - case BLE_GATTC_EVT_DESC_DISC_RSP: - on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, central); break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: @@ -288,7 +66,6 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { sd_ble_gap_conn_param_update(central->conn_handle, &request->conn_params); break; } - default: // For debugging. // mp_printf(&mp_plat_print, "Unhandled central event: 0x%04x\n", ble_evt->header.evt_id); @@ -299,12 +76,11 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { void common_hal_bleio_central_construct(bleio_central_obj_t *self) { common_hal_bleio_adapter_set_enabled(true); - self->service_list = mp_obj_new_list(0, NULL); - self->gatt_role = GATT_ROLE_CLIENT; + self->remote_services_list = mp_obj_new_list(0, NULL); self->conn_handle = BLE_CONN_HANDLE_INVALID; } -void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout, mp_obj_t service_uuids) { +void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { common_hal_bleio_adapter_set_enabled(true); ble_drv_add_event_handler(central_on_ble_evt, self); @@ -345,109 +121,6 @@ void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_o if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { mp_raise_OSError_msg(translate("Failed to connect: timeout")); } - - // Connection successful. - // Now discover services on the remote peripheral. - - if (service_uuids == mp_const_none) { - - // List of service UUID's not given, so discover all available services. - - uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; - - while (discover_next_services(self, next_service_start_handle, MP_OBJ_NULL)) { - // discover_next_services() appends to service_list. - - // Get the most recently discovered service, and then ask for services - // whose handles start after the last attribute handle inside that service. - const bleio_service_obj_t *service = - MP_OBJ_TO_PTR(self->service_list->items[self->service_list->len - 1]); - next_service_start_handle = service->end_handle + 1; - } - } else { - mp_obj_iter_buf_t iter_buf; - mp_obj_t iterable = mp_getiter(service_uuids, &iter_buf); - mp_obj_t uuid_obj; - while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - mp_raise_ValueError(translate("non-UUID found in service_uuids")); - } - bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - - ble_uuid_t nrf_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); - - // Service might or might not be discovered; that's ok. Caller has to check - // Central.remote_services to find out. - // We only need to call this once for each service to discover. - discover_next_services(self, BLE_GATT_HANDLE_START, &nrf_uuid); - } - } - - - for (size_t service_idx = 0; service_idx < self->service_list->len; ++service_idx) { - bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->service_list->items[service_idx]); - - // Skip the service if it had an unknown (unregistered) UUID. - if (service->uuid == NULL) { - continue; - } - - uint16_t next_char_start_handle = service->start_handle; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_characteristics() appends to the characteristic_list. - while (next_char_start_handle <= service->end_handle && - discover_next_characteristics(self, service, next_char_start_handle)) { - - - // Get the most recently discovered characteristic, and then ask for characteristics - // whose handles start after the last attribute handle inside that characteristic. - const bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); - next_char_start_handle = characteristic->handle + 1; - } - - // Got characteristics for this service. Now discover descriptors for each characteristic. - size_t char_list_len = service->characteristic_list->len; - for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { - bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); - const bool last_characteristic = char_idx == char_list_len - 1; - bleio_characteristic_obj_t *next_characteristic = last_characteristic - ? NULL - : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); - - // Skip the characteristic if it had an unknown (unregistered) UUID. - if (characteristic->uuid == NULL) { - continue; - } - - uint16_t next_desc_start_handle = characteristic->handle + 1; - - // Don't run past the end of this service or the beginning of the next characteristic. - uint16_t next_desc_end_handle = next_characteristic == NULL - ? service->end_handle - : next_characteristic->handle - 1; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_descriptors() appends to the descriptor_list. - while (next_desc_start_handle <= service->end_handle && - next_desc_start_handle < next_desc_end_handle && - discover_next_descriptors(self, characteristic, - next_desc_start_handle, next_desc_end_handle)) { - - // Get the most recently discovered descriptor, and then ask for descriptors - // whose handles start after that descriptor's handle. - const bleio_descriptor_obj_t *descriptor = - MP_OBJ_TO_PTR(characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]); - next_desc_start_handle = descriptor->handle + 1; - } - } - - } } void common_hal_bleio_central_disconnect(bleio_central_obj_t *self) { @@ -459,5 +132,5 @@ bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self) { } mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self) { - return self->service_list; + return self->remote_services_list; } diff --git a/ports/nrf/common-hal/bleio/Central.h b/ports/nrf/common-hal/bleio/Central.h index ac1670088..8b0d811bd 100644 --- a/ports/nrf/common-hal/bleio/Central.h +++ b/ports/nrf/common-hal/bleio/Central.h @@ -36,10 +36,10 @@ typedef struct { mp_obj_base_t base; - gatt_role_t gatt_role; volatile bool waiting_to_connect; volatile uint16_t conn_handle; - mp_obj_list_t *service_list; + // Services discovered after connecting to a remote peripheral. + mp_obj_list_t *remote_services_list; } bleio_central_obj_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c index 17417a5e6..e9f0225cf 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -33,8 +33,10 @@ #include "nrf_soc.h" #include "py/runtime.h" -#include "common-hal/bleio/__init__.h" -#include "common-hal/bleio/Characteristic.h" + +#include "shared-bindings/bleio/__init__.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Service.h" STATIC volatile bleio_characteristic_obj_t *m_read_characteristic; @@ -225,53 +227,39 @@ mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_charact } mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self) { - switch (common_hal_bleio_device_get_gatt_role(self->service->device)) { - case GATT_ROLE_CLIENT: + if (common_hal_bleio_service_get_is_remote(self->service)) { gattc_read(self); - break; - - case GATT_ROLE_SERVER: + } else { gatts_read(self); - break; - - default: - mp_raise_RuntimeError(translate("bad GATT role")); - break; } return self->value_data; } void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { - bool sent = false; - uint16_t cccd = 0; + if (common_hal_bleio_service_get_is_remote(self->service)) { + gattc_write(self, bufinfo); + } else { + bool sent = false; + uint16_t cccd = 0; - switch (common_hal_bleio_device_get_gatt_role(self->service->device)) { - case GATT_ROLE_SERVER: - if (self->props.notify || self->props.indicate) { + if (self->props.notify || self->props.indicate) { cccd = get_cccd(self); - } - // It's possible that both notify and indicate are set. - if (self->props.notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { - gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_NOTIFICATION); - sent = true; - } - if (self->props.indicate && (cccd & BLE_GATT_HVX_INDICATION)) { - gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_INDICATION); - sent = true; - } - if (!sent) { - gatts_write(self, bufinfo); - } - break; + } - case GATT_ROLE_CLIENT: - gattc_write(self, bufinfo); - break; + // It's possible that both notify and indicate are set. + if (self->props.notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { + gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_NOTIFICATION); + sent = true; + } + if (self->props.indicate && (cccd & BLE_GATT_HVX_INDICATION)) { + gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_INDICATION); + sent = true; + } - default: - mp_raise_RuntimeError(translate("bad GATT role")); - break; + if (!sent) { + gatts_write(self, bufinfo); + } } } @@ -289,8 +277,8 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, mp_raise_ValueError(translate("No CCCD for this Characteristic")); } - if (common_hal_bleio_device_get_gatt_role(self->service->device) != GATT_ROLE_CLIENT) { - mp_raise_ValueError(translate("Can't set CCCD for local Characteristic")); + if (!common_hal_bleio_service_get_is_remote(self->service)) { + mp_raise_ValueError(translate("Can't set CCCD on local Characteristic")); } uint16_t cccd_value = diff --git a/ports/nrf/common-hal/bleio/CharacteristicBuffer.c b/ports/nrf/common-hal/bleio/CharacteristicBuffer.c index 59eaaf02b..a6d834d7d 100644 --- a/ports/nrf/common-hal/bleio/CharacteristicBuffer.c +++ b/ports/nrf/common-hal/bleio/CharacteristicBuffer.c @@ -37,7 +37,7 @@ #include "tick.h" -#include "common-hal/bleio/__init__.h" +#include "shared-bindings/bleio/__init__.h" #include "common-hal/bleio/CharacteristicBuffer.h" STATIC void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) { diff --git a/ports/nrf/common-hal/bleio/Peripheral.c b/ports/nrf/common-hal/bleio/Peripheral.c index 608bd1342..930000534 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.c +++ b/ports/nrf/common-hal/bleio/Peripheral.c @@ -120,20 +120,21 @@ STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { } } -void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *service_list, mp_obj_t name) { +void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *services_list, mp_obj_t name) { common_hal_bleio_adapter_set_enabled(true); - self->service_list = service_list; + self->services_list = services_list; + // Used only for discovery when acting as a client. + self->remote_services_list = mp_obj_new_list(0, NULL); self->name = name; - self->gatt_role = GATT_ROLE_SERVER; self->conn_handle = BLE_CONN_HANDLE_INVALID; self->adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; // Add all the services. - for (size_t service_idx = 0; service_idx < service_list->len; ++service_idx) { - bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[service_idx]); + for (size_t service_idx = 0; service_idx < services_list->len; ++service_idx) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(services_list->items[service_idx]); service->device = MP_OBJ_FROM_PTR(self); @@ -156,8 +157,8 @@ void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_ } -mp_obj_list_t *common_hal_bleio_peripheral_get_service_list(bleio_peripheral_obj_t *self) { - return self->service_list; +mp_obj_list_t *common_hal_bleio_peripheral_get_services_list(bleio_peripheral_obj_t *self) { + return self->services_list; } bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self) { diff --git a/ports/nrf/common-hal/bleio/Peripheral.h b/ports/nrf/common-hal/bleio/Peripheral.h index 2a1251715..3127a527f 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.h +++ b/ports/nrf/common-hal/bleio/Peripheral.h @@ -41,9 +41,11 @@ typedef struct { mp_obj_base_t base; mp_obj_t name; - gatt_role_t gatt_role; volatile uint16_t conn_handle; - mp_obj_list_t *service_list; + // Services provided by this peripheral. + mp_obj_list_t *services_list; + // Remote services discovered when this peripheral is acting as a client. + mp_obj_list_t *remote_services_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must // maintain them and not change it. If we need to change the contents during advertising, // there are tricks to get the SD to notice (see DevZone - TBS). diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c index b6fcde827..02c2ac1f9 100644 --- a/ports/nrf/common-hal/bleio/Service.c +++ b/ports/nrf/common-hal/bleio/Service.c @@ -39,6 +39,7 @@ void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_ob self->handle = 0xFFFF; self->uuid = uuid; self->characteristic_list = characteristic_list; + self->is_remote = false; self->is_secondary = is_secondary; for (size_t characteristic_idx = 0; characteristic_idx < characteristic_list->len; ++characteristic_idx) { @@ -57,6 +58,10 @@ mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_ob return self->characteristic_list; } +bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { + return self->is_remote; +} + bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { return self->is_secondary; } diff --git a/ports/nrf/common-hal/bleio/Service.h b/ports/nrf/common-hal/bleio/Service.h index 583593fb8..03ac2bca8 100644 --- a/ports/nrf/common-hal/bleio/Service.h +++ b/ports/nrf/common-hal/bleio/Service.h @@ -35,6 +35,8 @@ typedef struct { mp_obj_base_t base; // Handle for this service. uint16_t handle; + // True if created during discovery. + bool is_remote; bool is_secondary; bleio_uuid_obj_t *uuid; // May be a Peripheral, Central, etc. diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c index 2dba5780c..a24898b0a 100644 --- a/ports/nrf/common-hal/bleio/__init__.c +++ b/ports/nrf/common-hal/bleio/__init__.c @@ -26,12 +26,24 @@ * THE SOFTWARE. */ +#include "py/runtime.h" #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Central.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Peripheral.h" +#include "shared-bindings/bleio/Service.h" +#include "shared-bindings/bleio/UUID.h" + #include "common-hal/bleio/__init__.h" +static volatile bool m_discovery_in_process; +static volatile bool m_discovery_successful; + +static bleio_service_obj_t *m_char_discovery_service; +static bleio_characteristic_obj_t *m_desc_discovery_characteristic; + // Turn off BLE on a reset or reload. void bleio_reset() { if (common_hal_bleio_adapter_get_enabled()) { @@ -47,22 +59,359 @@ const super_adapter_obj_t common_hal_bleio_adapter_obj = { }, }; -gatt_role_t common_hal_bleio_device_get_gatt_role(mp_obj_t device) { +uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { - return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->gatt_role; + return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { - return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->gatt_role; + return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; } else { - return GATT_ROLE_NONE; + return 0; } } -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { +mp_obj_list_t *common_hal_bleio_device_get_remote_services_list(mp_obj_t device) { if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { - return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; + return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->remote_services_list; } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { - return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; + return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->remote_services_list; } else { - return 0; + return NULL; + } +} + +// service_uuid may be NULL, to discover all services. +STATIC bool discover_next_services(mp_obj_t device, uint16_t start_handle, ble_uuid_t *service_uuid) { + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_primary_services_discover(conn_handle, start_handle, service_uuid); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg(translate("Failed to discover services")); + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC bool discover_next_characteristics(mp_obj_t device, bleio_service_obj_t *service, uint16_t start_handle) { + m_char_discovery_service = service; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = service->end_handle; + + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); + if (err_code != NRF_SUCCESS) { + return false; + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC bool discover_next_descriptors(mp_obj_t device, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { + m_desc_discovery_characteristic = characteristic; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = end_handle; + + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_descriptors_discover(conn_handle, &handle_range); + if (err_code != NRF_SUCCESS) { + return false; + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_service_t *gattc_service = &response->services[i]; + + bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); + service->base.type = &bleio_service_type; + + // Initialize several fields at once. + common_hal_bleio_service_construct(service, NULL, mp_obj_new_list(0, NULL), false); + + service->device = device; + service->is_remote = true; + service->start_handle = gattc_service->handle_range.start_handle; + service->end_handle = gattc_service->handle_range.end_handle; + service->handle = gattc_service->handle_range.start_handle; + + if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known service UUID. + bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); + service->uuid = uuid; + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just set the UUID to NULL. + service->uuid = NULL; + } + + mp_obj_list_append(common_hal_bleio_device_get_remote_services_list(device), service); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_char_t *gattc_char = &response->chars[i]; + + bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); + characteristic->base.type = &bleio_characteristic_type; + + characteristic->descriptor_list = mp_obj_new_list(0, NULL); + + bleio_uuid_obj_t *uuid = NULL; + + if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known characteristic UUID. + uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just leave the UUID as NULL. + } + + bleio_characteristic_properties_t props; + + props.broadcast = gattc_char->char_props.broadcast; + props.indicate = gattc_char->char_props.indicate; + props.notify = gattc_char->char_props.notify; + props.read = gattc_char->char_props.read; + props.write = gattc_char->char_props.write; + props.write_no_response = gattc_char->char_props.write_wo_resp; + + // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. + common_hal_bleio_characteristic_construct(characteristic, uuid, props, mp_obj_new_list(0, NULL)); + characteristic->handle = gattc_char->handle_value; + characteristic->service = m_char_discovery_service; + + mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); + } + + if (response->count > 0) { + m_discovery_successful = true; } + m_discovery_in_process = false; +} + +STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_desc_t *gattc_desc = &response->descs[i]; + + // Remember handles for certain well-known descriptors. + switch (gattc_desc->uuid.uuid) { + case DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION: + m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; + break; + + case DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION: + m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; + break; + + case DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION: + m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; + break; + + default: + // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, + // so ignore those. + // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors + break; + } + + bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); + descriptor->base.type = &bleio_descriptor_type; + + bleio_uuid_obj_t *uuid = NULL; + + if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known descriptor UUID. + uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just leave the UUID as NULL. + } + + common_hal_bleio_descriptor_construct(descriptor, uuid); + descriptor->handle = gattc_desc->handle; + descriptor->characteristic = m_desc_discovery_characteristic; + + mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t device) { + switch (ble_evt->header.evt_id) { + case BLE_GAP_EVT_DISCONNECTED: + m_discovery_successful = false; + m_discovery_in_process = false; + break; + + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, device); + break; + + case BLE_GATTC_EVT_CHAR_DISC_RSP: + on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, device); + break; + + case BLE_GATTC_EVT_DESC_DISC_RSP: + on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, device); + break; + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + + +void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { + mp_obj_list_t *remote_services_list = common_hal_bleio_device_get_remote_services_list(device); + + ble_drv_add_event_handler(discovery_on_ble_evt, device); + + if (service_uuids_whitelist == mp_const_none) { + // List of service UUID's not given, so discover all available services. + + uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; + + while (discover_next_services(device, next_service_start_handle, MP_OBJ_NULL)) { + // discover_next_services() appends to remote_services_list. + + // Get the most recently discovered service, and then ask for services + // whose handles start after the last attribute handle inside that service. + const bleio_service_obj_t *service = + MP_OBJ_TO_PTR(remote_services_list->items[remote_services_list->len - 1]); + next_service_start_handle = service->end_handle + 1; + } + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); + mp_obj_t uuid_obj; + while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + mp_raise_ValueError(translate("non-UUID found in service_uuids_whitelist")); + } + bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); + + ble_uuid_t nrf_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); + + // Service might or might not be discovered; that's ok. Caller has to check + // Central.remote_services to find out. + // We only need to call this once for each service to discover. + discover_next_services(device, BLE_GATT_HANDLE_START, &nrf_uuid); + } + } + + + for (size_t service_idx = 0; service_idx < remote_services_list->len; ++service_idx) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(remote_services_list->items[service_idx]); + + // Skip the service if it had an unknown (unregistered) UUID. + if (service->uuid == NULL) { + continue; + } + + uint16_t next_char_start_handle = service->start_handle; + + // Stop when we go past the end of the range of handles for this service or + // discovery call returns nothing. + // discover_next_characteristics() appends to the characteristic_list. + while (next_char_start_handle <= service->end_handle && + discover_next_characteristics(device, service, next_char_start_handle)) { + + + // Get the most recently discovered characteristic, and then ask for characteristics + // whose handles start after the last attribute handle inside that characteristic. + const bleio_characteristic_obj_t *characteristic = + MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); + next_char_start_handle = characteristic->handle + 1; + } + + // Got characteristics for this service. Now discover descriptors for each characteristic. + size_t char_list_len = service->characteristic_list->len; + for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { + bleio_characteristic_obj_t *characteristic = + MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); + const bool last_characteristic = char_idx == char_list_len - 1; + bleio_characteristic_obj_t *next_characteristic = last_characteristic + ? NULL + : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); + + // Skip the characteristic if it had an unknown (unregistered) UUID. + if (characteristic->uuid == NULL) { + continue; + } + + uint16_t next_desc_start_handle = characteristic->handle + 1; + + // Don't run past the end of this service or the beginning of the next characteristic. + uint16_t next_desc_end_handle = next_characteristic == NULL + ? service->end_handle + : next_characteristic->handle - 1; + + // Stop when we go past the end of the range of handles for this service or + // discovery call returns nothing. + // discover_next_descriptors() appends to the descriptor_list. + while (next_desc_start_handle <= service->end_handle && + next_desc_start_handle < next_desc_end_handle && + discover_next_descriptors(device, characteristic, + next_desc_start_handle, next_desc_end_handle)) { + + // Get the most recently discovered descriptor, and then ask for descriptors + // whose handles start after that descriptor's handle. + const bleio_descriptor_obj_t *descriptor = + MP_OBJ_TO_PTR(characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]); + next_desc_start_handle = descriptor->handle + 1; + } + } + } + + // This event handler is no longer needed. + ble_drv_remove_event_handler(discovery_on_ble_evt, device); + } diff --git a/ports/nrf/common-hal/bleio/__init__.h b/ports/nrf/common-hal/bleio/__init__.h index 0c46b631f..c0bba3799 100644 --- a/ports/nrf/common-hal/bleio/__init__.h +++ b/ports/nrf/common-hal/bleio/__init__.h @@ -27,16 +27,10 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H -#include "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Adapter.h" - -#include "shared-module/bleio/__init__.h" +void bleio_reset(void); // We assume variable length data. // 20 bytes max (23 - 3). #define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) -gatt_role_t common_hal_bleio_device_get_gatt_role(mp_obj_t device); -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); - #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index a2b48065d..8fa6721e2 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -78,6 +78,7 @@ // TIMERS #define NRFX_TIMER_ENABLED 1 // Don't enable TIMER0: it's used by the SoftDevice. +#define NRFX_TIMER0_ENABLED 0 #define NRFX_TIMER1_ENABLED 1 #define NRFX_TIMER2_ENABLED 1 diff --git a/ports/nrf/peripherals/nrf/timers.c b/ports/nrf/peripherals/nrf/timers.c index 7f7a003d3..88f3dd468 100644 --- a/ports/nrf/peripherals/nrf/timers.c +++ b/ports/nrf/peripherals/nrf/timers.c @@ -36,7 +36,7 @@ STATIC nrfx_timer_t nrfx_timers[] = { #if NRFX_CHECK(NRFX_TIMER0_ENABLED) - // Note that TIMER0 is reserved for use by the SoftDevice, so it should not usually be enabled. + #error NRFX_TIMER0_ENABLED should not be on: TIMER0 is used by the SoftDevice NRFX_TIMER_INSTANCE(0), #endif #if NRFX_CHECK(NRFX_TIMER1_ENABLED) diff --git a/shared-bindings/bleio/Central.c b/shared-bindings/bleio/Central.c index fc00bce5c..70b270c65 100644 --- a/shared-bindings/bleio/Central.c +++ b/shared-bindings/bleio/Central.c @@ -34,6 +34,7 @@ #include "py/objproperty.h" #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Address.h" #include "shared-bindings/bleio/Characteristic.h" @@ -56,12 +57,16 @@ //| //| my_entry = None //| for entry in entries: -//| if entry.name is not None and entry.name == 'MyPeripheral': +//| if entry.name is not None and entry.name == 'InterestingPeripheral': //| my_entry = entry //| break //| -//| central = bleio.Central(my_entry.address) -//| central.connect(10.0) # timeout after 10 seconds +//| if not my_entry: +//| raise Exception("'InterestingPeripheral' not found") +//| +//| central = bleio.Central() +//| central.connect(my_entry.address, 10) # timeout after 10 seconds +//| central.discover_remote_services() //| //| .. class:: Central() @@ -79,24 +84,11 @@ STATIC mp_obj_t bleio_central_make_new(const mp_obj_type_t *type, size_t n_args, return MP_OBJ_FROM_PTR(self); } -//| .. method:: connect(address, timeout, *, service_uuids=None) -//| Attempts a connection to the remote peripheral. If the connection is successful, -//| Do BLE discovery for the listed services, to find their handles and characteristics. -//| The attribute `remote_services` will contain a list of all discovered services. +//| .. method:: connect(address, timeout, *, service_uuids_whitelist=None) +//| Attempts a connection to the remote peripheral. //| //| :param bleio.Address address: The address of the peripheral to connect to //| :param float/int timeout: Try to connect for timeout seconds. -//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services -//| provided by the peripheral that you want to use. -//| The peripheral may provide more services, but services not listed are ignored. -//| If a service in service_uuids is not found during discovery, it will not -//| appear in `remote_services`. -//| -//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. -//| -//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you -//| you must have already created a :py:class:~`UUID` object for that UUID in order for the -//| service or characteristic to be discovered. (This restriction may be lifted in the future.) //| STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -105,7 +97,6 @@ STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args static const mp_arg_t allowed_args[] = { { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_service_uuids_whitelist, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -119,7 +110,7 @@ STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); // common_hal_bleio_central_connect() will validate that services is an iterable or None. - common_hal_bleio_central_connect(self, address, timeout, args[ARG_service_uuids_whitelist].u_obj); + common_hal_bleio_central_connect(self, address, timeout); return mp_const_none; } @@ -139,6 +130,47 @@ STATIC mp_obj_t bleio_central_disconnect(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_disconnect); +//| .. method:: discover_remote_services(service_uuids_whitelist=None) +//| Do BLE discovery for all services or for the given service UUIDS, +//| to find their handles and characteristics. +//| The attribute `remote_services` will contain a list of all discovered services. +//| `Central.connected` must be True. +//| +//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services +//| provided by the peripheral that you want to use. +//| The peripheral may provide more services, but services not listed are ignored. +//| If a service in service_uuids_whitelist is not found during discovery, it will not +//| appear in `remote_services`. +//| +//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. +//| +//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you +//| you must have already created a :py:class:~`UUID` object for that UUID in order for the +//| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered +//| for use. (This restriction may be lifted in the future.) +//| +STATIC mp_obj_t bleio_central_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_service_uuids_whitelist }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (!common_hal_bleio_central_get_connected(self)) { + mp_raise_ValueError(translate("Not connected")); + } + + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_discover_remote_services_obj, 1, bleio_central_discover_remote_services); + //| .. attribute:: connected //| //| True if connected to a remove peripheral. @@ -181,8 +213,9 @@ const mp_obj_property_t bleio_central_remote_services_obj = { STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = { // Methods - { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_central_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_central_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_central_discover_remote_services_obj) }, // Properties { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_central_connected_obj) }, diff --git a/shared-bindings/bleio/Central.h b/shared-bindings/bleio/Central.h index 0e84037f9..1d7fb6248 100644 --- a/shared-bindings/bleio/Central.h +++ b/shared-bindings/bleio/Central.h @@ -34,7 +34,7 @@ extern const mp_obj_type_t bleio_central_type; extern void common_hal_bleio_central_construct(bleio_central_obj_t *self); -extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout, mp_obj_t service_uuids); +extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout); extern void common_hal_bleio_central_disconnect(bleio_central_obj_t *self); extern bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self); extern mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self); diff --git a/shared-bindings/bleio/Peripheral.c b/shared-bindings/bleio/Peripheral.c index 1302c9652..69bc72d92 100644 --- a/shared-bindings/bleio/Peripheral.c +++ b/shared-bindings/bleio/Peripheral.c @@ -35,6 +35,7 @@ #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Peripheral.h" @@ -107,15 +108,15 @@ STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_ar self->base.type = &bleio_peripheral_type; // Copy the services list and validate its items. - mp_obj_t service_list_obj = mp_obj_new_list(0, NULL); - mp_obj_list_t *service_list = MP_OBJ_FROM_PTR(service_list_obj); + mp_obj_t services_list_obj = mp_obj_new_list(0, NULL); + mp_obj_list_t *services_list = MP_OBJ_FROM_PTR(services_list_obj); mp_obj_t service; while ((service = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (!MP_OBJ_IS_TYPE(service, &bleio_service_type)) { mp_raise_ValueError(translate("non-Service found in services")); } - mp_obj_list_append(service_list, service); + mp_obj_list_append(services_list, service); } const mp_obj_t name = args[ARG_name].u_obj; @@ -128,7 +129,7 @@ STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_ar mp_raise_ValueError(translate("name must be a string")); } - common_hal_bleio_peripheral_construct(self, service_list, name_str); + common_hal_bleio_peripheral_construct(self, services_list, name_str); return MP_OBJ_FROM_PTR(self); } @@ -158,8 +159,8 @@ const mp_obj_property_t bleio_peripheral_connected_obj = { STATIC mp_obj_t bleio_peripheral_get_services(mp_obj_t self_in) { bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *service_list = common_hal_bleio_peripheral_get_service_list(self); - return mp_obj_new_tuple(service_list->len, service_list->items); + mp_obj_list_t *services_list = common_hal_bleio_peripheral_get_services_list(self); + return mp_obj_new_tuple(services_list->len, services_list->items); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_services_obj, bleio_peripheral_get_services); @@ -265,16 +266,63 @@ STATIC mp_obj_t bleio_peripheral_disconnect(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripheral_disconnect); +//| .. method:: discover_remote_services(service_uuids_whitelist=None) +//| Do BLE discovery for all services or for the given service UUIDS, +//| to find their handles and characteristics. +//| The attribute `remote_services` will contain a list of all discovered services. +//| `Peripheral.connected` must be True. +//| +//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services +//| provided by the peripheral that you want to use. +//| The peripheral may provide more services, but services not listed are ignored. +//| If a service in service_uuids_whitelist is not found during discovery, it will not +//| appear in `remote_services`. +//| +//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. +//| +//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you +//| you must have already created a :py:class:~`UUID` object for that UUID in order for the +//| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered +//| for use. (This restriction may be lifted in the future.) +//| +//| Thought it is unusual for a peripheral to act as a BLE client, it can do so, and +//| needs to be able to do discovery on its peer (a central). +//| Examples include a peripheral accessing a central that provides Current Time Service, +//| Apple Notification Center Service, or Battery Service. +//| +STATIC mp_obj_t bleio_peripheral_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_service_uuids_whitelist }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (!common_hal_bleio_peripheral_get_connected(self)) { + mp_raise_ValueError(translate("Not connected")); + } + + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_discover_remote_services_obj, 1, bleio_peripheral_discover_remote_services); + STATIC const mp_rom_map_elem_t bleio_peripheral_locals_dict_table[] = { // Methods - { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_peripheral_stop_advertising_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_peripheral_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_peripheral_stop_advertising_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_peripheral_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_peripheral_discover_remote_services_obj) }, // Properties - { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) }, - { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_peripheral_name_obj) }, - { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) }, + { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_peripheral_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_peripheral_locals_dict, bleio_peripheral_locals_dict_table); diff --git a/shared-bindings/bleio/Peripheral.h b/shared-bindings/bleio/Peripheral.h index 846250a5f..7dad0bccd 100644 --- a/shared-bindings/bleio/Peripheral.h +++ b/shared-bindings/bleio/Peripheral.h @@ -33,7 +33,7 @@ extern const mp_obj_type_t bleio_peripheral_type; extern void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *service_list, mp_obj_t name); -extern mp_obj_list_t *common_hal_bleio_peripheral_get_service_list(bleio_peripheral_obj_t *self); +extern mp_obj_list_t *common_hal_bleio_peripheral_get_services_list(bleio_peripheral_obj_t *self); extern bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self); extern mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *self); extern void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *device, bool connectable, float interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo); diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c index db0606991..b4aeab2bd 100644 --- a/shared-bindings/bleio/Service.c +++ b/shared-bindings/bleio/Service.c @@ -43,12 +43,16 @@ //| .. class:: Service(uuid, characteristics, *, secondary=False) //| //| Create a new Service object identified by the specified UUID. +//| //| To mark the service as secondary, pass `True` as :py:data:`secondary`. //| //| :param bleio.UUID uuid: The uuid of the service //| :param iterable characteristics: the Characteristic objects for this service //| :param bool secondary: If the service is a secondary one //| +//| A Service may be remote (:py:data:`remote` is ``True``), but a remote Service +//| cannot be constructed directly. It is created by `Central.discover_remote_services()` +//| or `Peripheral.discover_remote_services()`. STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_uuid, ARG_characteristics, ARG_secondary }; @@ -119,6 +123,24 @@ const mp_obj_property_t bleio_service_characteristics_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: remote +//| +//| True if this is a service provided by a remote device. (read-only) +//| +STATIC mp_obj_t bleio_service_get_remote(mp_obj_t self_in) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_bleio_service_get_is_remote(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_remote_obj, bleio_service_get_remote); + +const mp_obj_property_t bleio_service_remote_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_remote_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + //| .. attribute:: secondary //| //| True if this is a secondary service. (read-only) diff --git a/shared-bindings/bleio/Service.h b/shared-bindings/bleio/Service.h index f646c81a9..716c2e8a9 100644 --- a/shared-bindings/bleio/Service.h +++ b/shared-bindings/bleio/Service.h @@ -35,6 +35,7 @@ const mp_obj_type_t bleio_service_type; extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, mp_obj_list_t *characteristic_list, bool is_secondary); extern bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self); extern mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self); +extern bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self); extern bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self); extern void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self); diff --git a/shared-bindings/bleio/__init__.h b/shared-bindings/bleio/__init__.h index 4aa6dd45b..dd6e55204 100644 --- a/shared-bindings/bleio/__init__.h +++ b/shared-bindings/bleio/__init__.h @@ -29,8 +29,19 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H +#include "py/objlist.h" + +#include "shared-bindings/bleio/__init__.h" +#include "shared-bindings/bleio/Adapter.h" + +#include "shared-module/bleio/__init__.h" #include "common-hal/bleio/Adapter.h" extern const super_adapter_obj_t common_hal_bleio_adapter_obj; +extern uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); +extern mp_obj_list_t *common_hal_bleio_device_get_remote_services_list(mp_obj_t device); +extern void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); + + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H diff --git a/shared-module/bleio/__init__.h b/shared-module/bleio/__init__.h index 07d148594..f8f0e0660 100644 --- a/shared-module/bleio/__init__.h +++ b/shared-module/bleio/__init__.h @@ -27,12 +27,6 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H -typedef enum { - GATT_ROLE_NONE, - GATT_ROLE_SERVER, - GATT_ROLE_CLIENT, -} gatt_role_t; - extern void bleio_reset(void); #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H -- cgit v1.2.3 From 1f9cb44fa3a09996d042b7b9e01864bf2feac363 Mon Sep 17 00:00:00 2001 From: Dave Astels Date: Wed, 31 Jul 2019 15:00:21 -0400 Subject: Expose rotation with a property --- shared-bindings/displayio/Display.c | 18 ++++++++++++++++++ shared-bindings/displayio/Display.h | 1 + shared-module/displayio/Display.c | 6 +++++- shared-module/displayio/Display.h | 1 + 4 files changed, 25 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 6338fe459..ab9bad19c 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -329,6 +329,23 @@ const mp_obj_property_t displayio_display_height_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| .. attribute:: rotation +//| +//| The rotation of the display as an int in degrees. +//| +STATIC mp_obj_t displayio_display_obj_get_rotation(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_rotation(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_rotation_obj, displayio_display_obj_get_rotation); + +const mp_obj_property_t displayio_display_rotation_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_rotation_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + //| .. attribute:: bus //| //| The bus being used by the display @@ -479,6 +496,7 @@ STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&displayio_display_rotation_obj) }, { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_display_bus_obj) }, // { MP_ROM_QSTR(MP_QSTR_screenshot), MP_ROM_PTR(&displayio_display_screenshot_obj) }, }; diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index e765e6f25..40793be14 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -68,6 +68,7 @@ void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* s uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self); uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self); +uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self); mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self); bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index a8515b9e5..74a96fac2 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -119,7 +119,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->width = width; self->height = height; - rotation = rotation % 360; + self->rotation = rotation % 360; self->transform.x = 0; self->transform.y = 0; self->transform.scale = 1; @@ -242,6 +242,10 @@ uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self){ return self->height; } +uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self){ + return self->rotation; +} + void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness) { self->auto_brightness = auto_brightness; } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index 96d1c06d5..74ae175b1 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -55,6 +55,7 @@ typedef struct { mp_float_t current_brightness; uint16_t width; uint16_t height; + uint16_t rotation; _displayio_colorspace_t colorspace; int16_t colstart; int16_t rowstart; -- cgit v1.2.3 From c1e5247d51ffb34bdfdb1f5039ba9118fab25f26 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Fri, 2 Aug 2019 12:36:34 +0200 Subject: Add support for scaling to _stage On high-resolution displays we can use 2x2 or even 3x3 pixels. --- shared-bindings/_stage/__init__.c | 12 +++++++++--- shared-module/_stage/__init__.c | 37 +++++++++++++++++++++---------------- shared-module/_stage/__init__.h | 2 +- 3 files changed, 31 insertions(+), 20 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 1ca206339..485fa80c5 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -50,7 +50,7 @@ //| Layer //| Text //| -//| .. function:: render(x0, y0, x1, y1, layers, buffer, display) +//| .. function:: render(x0, y0, x1, y1, layers, buffer, display[, scale]) //| //| Render and send to the display a fragment of the screen. //| @@ -61,6 +61,7 @@ //| :param list layers: A list of the :py:class:`~_stage.Layer` objects. //| :param bytearray buffer: A buffer to use for rendering. //| :param ~displayio.Display display: The display to use. +//| :param int scale: How many times should the image be scaled up. //| //| There are also no sanity checks, outside of the basic overflow //| checking. The caller is responsible for making the passed parameters @@ -89,6 +90,10 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { mp_raise_TypeError(translate("argument num/types mismatch")); } displayio_display_obj_t *display = MP_OBJ_TO_PTR(native_display); + uint8_t scale = 1; + if (n_args >= 8) { + scale = mp_obj_get_int(args[7]); + } while (!displayio_display_begin_transaction(display)) { #ifdef MICROPY_VM_HOOK_LOOP @@ -103,12 +108,13 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { displayio_display_set_region_to_update(display, &area); display->send(display->bus, true, &display->write_ram_command, 1); - render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display); + render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, + display, scale); displayio_display_end_transaction(display); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 7, stage_render); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 8, stage_render); STATIC const mp_rom_map_elem_t stage_module_globals_table[] = { diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index 1af279e92..ca71b758e 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -34,30 +34,35 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, mp_obj_t *layers, size_t layers_size, uint16_t *buffer, size_t buffer_size, - displayio_display_obj_t *display) { + displayio_display_obj_t *display, uint8_t scale) { size_t index = 0; for (uint16_t y = y0; y < y1; ++y) { - for (uint16_t x = x0; x < x1; ++x) { - for (size_t layer = 0; layer < layers_size; ++layer) { + for (uint8_t yscale = 0; yscale < scale; ++yscale) { + for (uint16_t x = x0; x < x1; ++x) { uint16_t c = TRANSPARENT; - layer_obj_t *obj = MP_OBJ_TO_PTR(layers[layer]); - if (obj->base.type == &mp_type_layer) { - c = get_layer_pixel(obj, x, y); - } else if (obj->base.type == &mp_type_text) { - c = get_text_pixel((text_obj_t *)obj, x, y); + for (size_t layer = 0; layer < layers_size; ++layer) { + layer_obj_t *obj = MP_OBJ_TO_PTR(layers[layer]); + if (obj->base.type == &mp_type_layer) { + c = get_layer_pixel(obj, x, y); + } else if (obj->base.type == &mp_type_text) { + c = get_text_pixel((text_obj_t *)obj, x, y); + } + if (c != TRANSPARENT) { + break; + } } - if (c != TRANSPARENT) { + for (uint8_t xscale = 0; xscale < scale; ++xscale) { buffer[index] = c; - break; + index += 1; + // The buffer is full, send it. + if (index >= buffer_size) { + display->send(display->bus, false, ((uint8_t*)buffer), + buffer_size * 2); + index = 0; + } } } - index += 1; - // The buffer is full, send it. - if (index >= buffer_size) { - display->send(display->bus, false, ((uint8_t*)buffer), buffer_size * 2); - index = 0; - } } } // Send the remaining data. diff --git a/shared-module/_stage/__init__.h b/shared-module/_stage/__init__.h index d263302b4..5af2124ae 100644 --- a/shared-module/_stage/__init__.h +++ b/shared-module/_stage/__init__.h @@ -37,6 +37,6 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, mp_obj_t *layers, size_t layers_size, uint16_t *buffer, size_t buffer_size, - displayio_display_obj_t *display); + displayio_display_obj_t *display, uint8_t scale); #endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE -- cgit v1.2.3 From 7ce3776b8086abbe0d01056651904a59bf4f8bec Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 2 Aug 2019 17:56:44 -0400 Subject: WIP: rework of Characteristic properties; enhance Descriptor; not tested --- ports/nrf/common-hal/bleio/Attribute.c | 60 ++++++++ ports/nrf/common-hal/bleio/Attribute.h | 32 +++++ ports/nrf/common-hal/bleio/Central.h | 1 - ports/nrf/common-hal/bleio/Characteristic.c | 21 +-- ports/nrf/common-hal/bleio/Characteristic.h | 6 +- ports/nrf/common-hal/bleio/Descriptor.c | 6 +- ports/nrf/common-hal/bleio/Descriptor.h | 7 +- ports/nrf/common-hal/bleio/Peripheral.c | 4 +- ports/nrf/common-hal/bleio/Peripheral.h | 1 - ports/nrf/common-hal/bleio/Service.c | 74 +++++++--- ports/nrf/common-hal/bleio/__init__.c | 29 ++-- py/circuitpy_defns.mk | 11 +- py/obj.h | 1 + py/objlist.c | 5 + shared-bindings/bleio/Address.c | 12 +- shared-bindings/bleio/Attribute.c | 93 +++++++++++++ shared-bindings/bleio/Attribute.h | 38 +++++ shared-bindings/bleio/Characteristic.c | 207 ++++++++++------------------ shared-bindings/bleio/Characteristic.h | 3 +- shared-bindings/bleio/Descriptor.c | 90 ++---------- shared-bindings/bleio/Descriptor.h | 21 +-- shared-bindings/bleio/__init__.c | 38 +++-- shared-bindings/bleio/__init__.h | 1 - shared-module/bleio/Attribute.c | 46 +++++++ shared-module/bleio/Attribute.h | 41 ++++++ shared-module/bleio/Characteristic.h | 21 +-- shared-module/bleio/__init__.h | 32 ----- 27 files changed, 546 insertions(+), 355 deletions(-) create mode 100644 ports/nrf/common-hal/bleio/Attribute.c create mode 100644 ports/nrf/common-hal/bleio/Attribute.h create mode 100644 shared-bindings/bleio/Attribute.c create mode 100644 shared-bindings/bleio/Attribute.h create mode 100644 shared-module/bleio/Attribute.c create mode 100644 shared-module/bleio/Attribute.h delete mode 100644 shared-module/bleio/__init__.h (limited to 'shared-module') diff --git a/ports/nrf/common-hal/bleio/Attribute.c b/ports/nrf/common-hal/bleio/Attribute.c new file mode 100644 index 000000000..bffe68254 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Attribute.c @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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 "shared-bindings/bleio/Attribute.h" + +// Convert a bleio security mode to a ble_gap_conn_sec_mode_t setting. +void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SEC_MODE_NO_ACCESS: + BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); + break; + + case SEC_MODE_OPEN: + BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); + break; + + case SEC_MODE_ENC_NO_MITM: + BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); + break; + + case SEC_MODE_ENC_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); + break; + + case SEC_MODE_LESC_ENC_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); + break; + + case SEC_MODE_SIGNED_NO_MITM: + BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); + break; + + case SEC_MODE_SIGNED_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); + break; + } +} diff --git a/ports/nrf/common-hal/bleio/Attribute.h b/ports/nrf/common-hal/bleio/Attribute.h new file mode 100644 index 000000000..44c2fdfa1 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Attribute.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H + +// Nothing yet. + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H diff --git a/ports/nrf/common-hal/bleio/Central.h b/ports/nrf/common-hal/bleio/Central.h index 8b0d811bd..b7a9050b8 100644 --- a/ports/nrf/common-hal/bleio/Central.h +++ b/ports/nrf/common-hal/bleio/Central.h @@ -31,7 +31,6 @@ #include #include "py/objlist.h" -#include "shared-module/bleio/__init__.h" #include "shared-module/bleio/Address.h" typedef struct { diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c index b318ae81c..41fcdd1f1 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -164,7 +164,8 @@ STATIC void gattc_write(bleio_characteristic_obj_t *characteristic, mp_buffer_in check_connected(conn_handle); ble_gattc_write_params_t write_params = { - .write_op = characteristic->props.write_no_response ? BLE_GATT_OP_WRITE_CMD : BLE_GATT_OP_WRITE_REQ, + .write_op = (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) + ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, .handle = characteristic->handle, .p_value = bufinfo->buf, .len = bufinfo->len, @@ -211,12 +212,14 @@ STATIC void characteristic_on_ble_evt(ble_evt_t *ble_evt, void *param) { } -void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, mp_obj_list_t *descriptor_list) { +void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t security_mode, mp_obj_t descriptors) { self->service = mp_const_none; self->uuid = uuid; self->value_data = mp_const_none; self->props = props; - self->descriptor_list = descriptor_list; + self->security_mode = security_mode; + self->descriptor_list = mp_obj_new_list_from_iter(descriptors); + self->handle = BLE_GATT_HANDLE_INVALID; ble_drv_add_event_handler(characteristic_on_ble_evt, self); @@ -238,21 +241,23 @@ mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *s void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { if (common_hal_bleio_service_get_is_remote(self->service)) { - gattc_write(self, bufinfo); + gattc_write(self, bufinfo); } else { bool sent = false; uint16_t cccd = 0; - if (self->props.notify || self->props.indicate) { - cccd = get_cccd(self); + const bool notify = self->props & CHAR_PROP_NOTIFY; + const bool indicate = self->props & CHAR_PROP_INDICATE; + if (notify | indicate) { + cccd = get_cccd(self); } // It's possible that both notify and indicate are set. - if (self->props.notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { + if (notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_NOTIFICATION); sent = true; } - if (self->props.indicate && (cccd & BLE_GATT_HVX_INDICATION)) { + if (indicate && (cccd & BLE_GATT_HVX_INDICATION)) { gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_INDICATION); sent = true; } diff --git a/ports/nrf/common-hal/bleio/Characteristic.h b/ports/nrf/common-hal/bleio/Characteristic.h index 7cb227596..8c8309f09 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.h +++ b/ports/nrf/common-hal/bleio/Characteristic.h @@ -28,17 +28,19 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H +#include "shared-bindings/bleio/Attribute.h" +#include "shared-module/bleio/Characteristic.h" #include "common-hal/bleio/Service.h" #include "common-hal/bleio/UUID.h" -#include "shared-module/bleio/Characteristic.h" typedef struct { mp_obj_base_t base; bleio_service_obj_t *service; bleio_uuid_obj_t *uuid; - volatile mp_obj_t value_data; + mp_obj_t value_data; uint16_t handle; bleio_characteristic_properties_t props; + bleio_attribute_security_mode_t security_mode; mp_obj_list_t *descriptor_list; uint16_t user_desc_handle; uint16_t cccd_handle; diff --git a/ports/nrf/common-hal/bleio/Descriptor.c b/ports/nrf/common-hal/bleio/Descriptor.c index 005af6eaa..ad62b2535 100644 --- a/ports/nrf/common-hal/bleio/Descriptor.c +++ b/ports/nrf/common-hal/bleio/Descriptor.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * Copyright (c) 2016 Glenn Ruben Bakke * @@ -33,10 +33,6 @@ void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_u self->uuid = uuid; } -mp_int_t common_hal_bleio_descriptor_get_handle(bleio_descriptor_obj_t *self) { - return self->handle; -} - bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { return self->uuid; } diff --git a/ports/nrf/common-hal/bleio/Descriptor.h b/ports/nrf/common-hal/bleio/Descriptor.h index b7af6a42f..ad94a0bb9 100644 --- a/ports/nrf/common-hal/bleio/Descriptor.h +++ b/ports/nrf/common-hal/bleio/Descriptor.h @@ -30,14 +30,17 @@ #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H #include "py/obj.h" -#include "common-hal/bleio/Characteristic.h" + +#include "shared-bindings/bleio/Characteristic.h" #include "common-hal/bleio/UUID.h" typedef struct { mp_obj_base_t base; - uint16_t handle; bleio_characteristic_obj_t *characteristic; bleio_uuid_obj_t *uuid; + mp_obj_t value_data; + uint16_t handle; + bleio_attribute_security_mode_t security_mode; } bleio_descriptor_obj_t; #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H diff --git a/ports/nrf/common-hal/bleio/Peripheral.c b/ports/nrf/common-hal/bleio/Peripheral.c index c45041ad0..905b26835 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.c +++ b/ports/nrf/common-hal/bleio/Peripheral.c @@ -138,10 +138,10 @@ STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { // Pairing process completed ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status; if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { - mp_printf(&mp_plat_print, "Pairing succeeded, status: 0x%04x\n", status->auth_status); + // mp_printf(&mp_plat_print, "Pairing succeeded, status: 0x%04x\n", status->auth_status); self->pair_status = PAIR_PAIRED; } else { - mp_printf(&mp_plat_print, "Pairing failed, status: 0x%04x\n", status->auth_status); + // mp_printf(&mp_plat_print, "Pairing failed, status: 0x%04x\n", status->auth_status); self->pair_status = PAIR_NOT_PAIRED; } break; diff --git a/ports/nrf/common-hal/bleio/Peripheral.h b/ports/nrf/common-hal/bleio/Peripheral.h index e4a664b01..e75a1641a 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.h +++ b/ports/nrf/common-hal/bleio/Peripheral.h @@ -35,7 +35,6 @@ #include "py/obj.h" #include "py/objlist.h" -#include "shared-module/bleio/__init__.h" #include "shared-module/bleio/Address.h" typedef enum { diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c index 02c2ac1f9..cdcbad7c4 100644 --- a/ports/nrf/common-hal/bleio/Service.c +++ b/ports/nrf/common-hal/bleio/Service.c @@ -29,8 +29,8 @@ #include "ble.h" #include "py/runtime.h" #include "common-hal/bleio/__init__.h" -#include "common-hal/bleio/Characteristic.h" #include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/Adapter.h" @@ -74,12 +74,12 @@ void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self) MP_OBJ_TO_PTR(self->characteristic_list->items[characteristic_idx]); ble_gatts_char_md_t char_md = { - .char_props.broadcast = characteristic->props.broadcast, - .char_props.read = characteristic->props.read, - .char_props.write_wo_resp = characteristic->props.write_no_response, - .char_props.write = characteristic->props.write, - .char_props.notify = characteristic->props.notify, - .char_props.indicate = characteristic->props.indicate, + .char_props.broadcast = (bool) characteristic->props & CHAR_PROP_BROADCAST, + .char_props.read = (bool) characteristic->props & CHAR_PROP_READ, + .char_props.write_wo_resp = (bool) characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE, + .char_props.write = (bool) characteristic->props & CHAR_PROP_WRITE, + .char_props.notify = (bool) characteristic->props & CHAR_PROP_NOTIFY, + .char_props.indicate = (bool) characteristic->props & CHAR_PROP_INDICATE, }; ble_gatts_attr_md_t cccd_md = { @@ -93,28 +93,28 @@ void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self) char_md.p_cccd_md = &cccd_md; } - ble_uuid_t uuid; - bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &uuid); + ble_uuid_t char_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &char_uuid); - ble_gatts_attr_md_t attr_md = { + ble_gatts_attr_md_t char_attr_md = { .vloc = BLE_GATTS_VLOC_STACK, .vlen = 1, }; - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_attr_md.write_perm); - ble_gatts_attr_t attr_char_value = { - .p_uuid = &uuid, - .p_attr_md = &attr_md, + ble_gatts_attr_t char_attr = { + .p_uuid = &char_uuid, + .p_attr_md = &char_attr_md, .init_len = sizeof(uint8_t), .max_len = GATT_MAX_DATA_LENGTH, }; - ble_gatts_char_handles_t handles; + ble_gatts_char_handles_t char_handles; uint32_t err_code; - err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &attr_char_value, &handles); + err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &char_attr, &char_handles); if (err_code != NRF_SUCCESS) { mp_raise_OSError_msg_varg(translate("Failed to add characteristic, err 0x%04x"), err_code); } @@ -123,9 +123,41 @@ void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self) mp_raise_ValueError(translate("Characteristic already in use by another Service.")); } - characteristic->user_desc_handle = handles.user_desc_handle; - characteristic->cccd_handle = handles.cccd_handle; - characteristic->sccd_handle = handles.sccd_handle; - characteristic->handle = handles.value_handle; + characteristic->user_desc_handle = char_handles.user_desc_handle; + characteristic->cccd_handle = char_handles.cccd_handle; + characteristic->sccd_handle = char_handles.sccd_handle; + characteristic->handle = char_handles.value_handle; + + // Add the descriptors for this characteristic. + for (size_t descriptor_idx = 0; descriptor_idx < characteristic->descriptor_list->len; ++descriptor_idx) { + bleio_descriptor_obj_t *descriptor = + MP_OBJ_TO_PTR(characteristic->descriptor_list->items[descriptor_idx]); + + ble_uuid_t desc_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(descriptor->uuid, &desc_uuid); + + ble_gatts_attr_md_t desc_attr_md = { + // Data passed is not in a permanent location and should be copied. + .vloc = BLE_GATTS_VLOC_STACK, + .vlen = 1, + }; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_attr_md.write_perm); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(descriptor->value_data, &bufinfo, MP_BUFFER_READ); + + ble_gatts_attr_t desc_attr = { + .p_uuid = &desc_uuid, + .p_attr_md = &desc_attr_md, + .init_len = bufinfo.len, + .p_value = bufinfo.buf, + .init_offs = 0, + .max_len = GATT_MAX_DATA_LENGTH, + }; + + err_code = sd_ble_gatts_descriptor_add(characteristic->handle, &desc_attr, &descriptor->handle); + } } } diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c index a24898b0a..303e70797 100644 --- a/ports/nrf/common-hal/bleio/__init__.c +++ b/ports/nrf/common-hal/bleio/__init__.c @@ -204,17 +204,16 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_ob // For now, just leave the UUID as NULL. } - bleio_characteristic_properties_t props; - - props.broadcast = gattc_char->char_props.broadcast; - props.indicate = gattc_char->char_props.indicate; - props.notify = gattc_char->char_props.notify; - props.read = gattc_char->char_props.read; - props.write = gattc_char->char_props.write; - props.write_no_response = gattc_char->char_props.write_wo_resp; + bleio_characteristic_properties_t props = + (gattc_char->char_props.broadcast ? CHAR_PROP_BROADCAST : 0) | + (gattc_char->char_props.indicate ? CHAR_PROP_INDICATE : 0) | + (gattc_char->char_props.notify ? CHAR_PROP_NOTIFY : 0) | + (gattc_char->char_props.read ? CHAR_PROP_READ : 0) | + (gattc_char->char_props.write ? CHAR_PROP_WRITE : 0) | + (gattc_char->char_props.write_wo_resp ? CHAR_PROP_WRITE_NO_RESPONSE : 0); // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. - common_hal_bleio_characteristic_construct(characteristic, uuid, props, mp_obj_new_list(0, NULL)); + common_hal_bleio_characteristic_construct(characteristic, uuid, props, SEC_MODE_OPEN, mp_const_empty_tuple); characteristic->handle = gattc_char->handle_value; characteristic->service = m_char_discovery_service; @@ -233,15 +232,15 @@ STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_ob // Remember handles for certain well-known descriptors. switch (gattc_desc->uuid.uuid) { - case DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION: + case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; break; - case DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION: + case BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG: m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; break; - case DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION: + case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; break; @@ -268,7 +267,8 @@ STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_ob // For now, just leave the UUID as NULL. } - common_hal_bleio_descriptor_construct(descriptor, uuid); + // TODO: can we find out security mode? + common_hal_bleio_descriptor_construct(descriptor, uuid, SEC_MODE_OPEN); descriptor->handle = gattc_desc->handle; descriptor->characteristic = m_desc_discovery_characteristic; @@ -313,6 +313,9 @@ void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t ble_drv_add_event_handler(discovery_on_ble_evt, device); + // Start over with an empty list. + mp_obj_list_clear(MP_OBJ_FROM_PTR(common_hal_bleio_device_get_remote_services_list(device))); + if (service_uuids_whitelist == mp_const_none) { // List of service UUID's not given, so discover all available services. diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index bdefc18cc..5e5ebeaa8 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -227,6 +227,7 @@ $(filter $(SRC_PATTERNS), \ audioio/AudioOut.c \ bleio/__init__.c \ bleio/Adapter.c \ + bleio/Attribute.c \ bleio/Central.c \ bleio/Characteristic.c \ bleio/CharacteristicBuffer.c \ @@ -276,6 +277,9 @@ $(filter $(SRC_PATTERNS), \ # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_BINDINGS_ENUMS = \ $(filter $(SRC_PATTERNS), \ + bleio/Address.c \ + bleio/Attribute.c \ + bleio/ScanEntry.c \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ @@ -289,12 +293,6 @@ SRC_BINDINGS_ENUMS += \ help.c \ util.c -SRC_BINDINGS_ENUMS += \ -$(filter $(SRC_PATTERNS), \ - bleio/Address.c \ - bleio/ScanEntry.c \ -) - # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_SHARED_MODULE = \ $(filter $(SRC_PATTERNS), \ @@ -314,6 +312,7 @@ $(filter $(SRC_PATTERNS), \ bitbangio/__init__.c \ board/__init__.c \ bleio/Address.c \ + bleio/Attribute.c \ bleio/ScanEntry.c \ busio/OneWire.c \ displayio/Bitmap.c \ diff --git a/py/obj.h b/py/obj.h index 6eead377d..c719c2945 100644 --- a/py/obj.h +++ b/py/obj.h @@ -668,6 +668,7 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items); +mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable); mp_obj_t mp_obj_new_dict(size_t n_args); mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items); mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step); diff --git a/py/objlist.c b/py/objlist.c index 558c4c611..ea38e64e5 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -68,6 +68,11 @@ STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) { return list; } +mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable) { + mp_obj_t list = mp_obj_new_list(0, NULL); + return list_extend_from_iter(list, iterable); +} + STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { (void)type_in; mp_arg_check_num(n_args, kw_args, 0, 1, false); diff --git a/shared-bindings/bleio/Address.c b/shared-bindings/bleio/Address.c index 475fc9427..d77cfa404 100644 --- a/shared-bindings/bleio/Address.c +++ b/shared-bindings/bleio/Address.c @@ -174,13 +174,13 @@ STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_pr //| A randomly generated address that changes on every connection. //| STATIC const mp_rom_map_elem_t bleio_address_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_address_bytes), MP_ROM_PTR(&bleio_address_address_bytes_obj) }, - { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&bleio_address_type_obj) }, + { MP_ROM_QSTR(MP_QSTR_address_bytes), MP_ROM_PTR(&bleio_address_address_bytes_obj) }, + { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&bleio_address_type_obj) }, // These match the BLE_GAP_ADDR_TYPES values used by the nRF library. - { MP_ROM_QSTR(MP_QSTR_PUBLIC), MP_OBJ_NEW_SMALL_INT(0) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_OBJ_NEW_SMALL_INT(1) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_OBJ_NEW_SMALL_INT(2) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_OBJ_NEW_SMALL_INT(3) }, + { MP_ROM_QSTR(MP_QSTR_PUBLIC), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_ROM_INT(3) }, }; diff --git a/shared-bindings/bleio/Attribute.c b/shared-bindings/bleio/Attribute.c new file mode 100644 index 000000000..f640cc05c --- /dev/null +++ b/shared-bindings/bleio/Attribute.c @@ -0,0 +1,93 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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 "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/UUID.h" + +// + +//| .. currentmodule:: bleio +//| +//| :class:`Attribute` -- BLE Attribute +//| ========================================================= +//| +//| Definitions associated with all BLE attributes: characteristics, descriptors, etc. +//| `Attribute` is, notionally, a superclass of `Characteristic` and `Descriptor`, +//| but is not defined as a Python superclass of those classes. +//| +//| .. class:: Attribute() +//| +//| You cannot create an instance of `Attribute`. +//| + +STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = { + +//| .. data:: NO_ACCESS +//| +//| security mode: access not allowed +//| +//| .. data:: OPEN +//| +//| security_mode: no security (link is not encrypted) +//| +//| .. data:: ENCRYPT_NO_MITM +//| +//| security_mode: unauthenticated encryption, without man-in-the-middle protection +//| +//| .. data:: ENCRYPT_WITH_MITM +//| +//| security_mode: authenticated encryption, with man-in-the-middle protection +//| +//| .. data:: LESC_ENCRYPT_WITH_MITM +//| +//| security_mode: LESC encryption, with man-in-the-middle protection +//| +//| .. data:: SIGNED_NO_MITM +//| +//| security_mode: unauthenticated data signing, without man-in-the-middle protection +//| +//| .. data:: SIGNED_WITH_MITM +//| +//| security_mode: authenticated data signing, without man-in-the-middle protection +//| + { MP_ROM_QSTR(MP_QSTR_NO_ACCESS), MP_ROM_INT(SEC_MODE_NO_ACCESS) }, + { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SEC_MODE_OPEN) }, + { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SEC_MODE_ENC_NO_MITM) }, + { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SEC_MODE_ENC_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SEC_MODE_LESC_ENC_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SEC_MODE_SIGNED_NO_MITM) }, + { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SEC_MODE_SIGNED_WITH_MITM) }, + +}; +STATIC MP_DEFINE_CONST_DICT(bleio_attribute_locals_dict, bleio_attribute_locals_dict_table); + +const mp_obj_type_t bleio_attribute_type = { + { &mp_type_type }, + .name = MP_QSTR_Attribute, + .locals_dict = (mp_obj_dict_t*)&bleio_attribute_locals_dict, +}; diff --git a/shared-bindings/bleio/Attribute.h b/shared-bindings/bleio/Attribute.h new file mode 100644 index 000000000..06a6eb5a9 --- /dev/null +++ b/shared-bindings/bleio/Attribute.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H + +#include "py/obj.h" + +#include "shared-module/bleio/Attribute.h" + +extern const mp_obj_type_t bleio_attribute_type; + +extern void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c index 3bf0476ab..09ed48ef9 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -28,6 +28,7 @@ #include "py/objproperty.h" #include "py/runtime.h" +#include "shared-bindings/bleio/Attribute.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/UUID.h" @@ -40,30 +41,25 @@ //| and writing of the characteristic's value. //| //| -//| .. class:: Characteristic(uuid, *, broadcast=False, indicate=False, notify=False, read=False, write=False, write_no_response=False) +//| .. class:: Characteristic(uuid, *, properties=0, security_mode=`Attribute.OPEN`, descriptors=None) //| //| Create a new Characteristic object identified by the specified UUID. //| //| :param bleio.UUID uuid: The uuid of the characteristic -//| :param bool broadcast: Allowed in advertising packets -//| :param bool indicate: Server will indicate to the client when the value is set and wait for a response -//| :param bool notify: Server will notify the client when the value is set -//| :param bool read: Clients may read this characteristic -//| :param bool write: Clients may write this characteristic; a response will be sent back -//| :param bool write_no_response: Clients may write this characteristic; no response will be sent back +//| :param int properties: bitmask of these values bitwise-or'd together: `BROADCAST`, `INDICATE`, +//| `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE` +//| :param int security_mode: one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, +//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, +//| `Attribute.SIGNED_NO_MITM`, `Attribute.SIGNED_WITH_MITM`. +//| :param iterable descriptors: BLE descriptors for this characteristic. //| STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { - ARG_uuid, ARG_broadcast, ARG_indicate, ARG_notify, ARG_read, ARG_write, ARG_write_no_response, - }; + enum { ARG_uuid, ARG_properties, ARG_security_mode, ARG_descriptors }; static const mp_arg_t allowed_args[] = { { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_broadcast, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_indicate, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_notify, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_read, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_write, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_write_no_response, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_properties, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 0 } }, + { MP_QSTR_security_mode, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, + { MP_QSTR_descriptors, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -76,129 +72,41 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t } bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t); - self->base.type = &bleio_characteristic_type; - - bleio_characteristic_properties_t properties; - - properties.broadcast = args[ARG_broadcast].u_bool; - properties.indicate = args[ARG_indicate].u_bool; - properties.notify = args[ARG_notify].u_bool; - properties.read = args[ARG_read].u_bool; - properties.write = args[ARG_write].u_bool; - properties.write_no_response = args[ARG_write_no_response].u_bool; - - // Initialize, with an empty descriptor list. - common_hal_bleio_characteristic_construct(self, uuid, properties, mp_obj_new_list(0, NULL)); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. attribute:: broadcast -//| -//| A `bool` specifying if the characteristic allows broadcasting its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_broadcast(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).broadcast); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_broadcast_obj, bleio_characteristic_get_broadcast); - -const mp_obj_property_t bleio_characteristic_broadcast_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_broadcast_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: indicate -//| -//| A `bool` specifying if the characteristic allows indicating its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_indicate(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).indicate); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_indicate_obj, bleio_characteristic_get_indicate); - - -const mp_obj_property_t bleio_characteristic_indicate_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_indicate_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: notify -//| -//| A `bool` specifying if the characteristic allows notifying its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_notify(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).notify); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_notify_obj, bleio_characteristic_get_notify); - -const mp_obj_property_t bleio_characteristic_notify_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_notify_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; + const bleio_characteristic_properties_t properties = args[ARG_properties].u_int; + if (properties & ~CHAR_PROP_ALL) { + mp_raise_ValueError(translate("Invalid properties")); + } -//| .. attribute:: read -//| -//| A `bool` specifying if the characteristic allows reading its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_read(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + const bleio_attribute_security_mode_t security_mode = args[ARG_security_mode].u_int; + common_hal_bleio_attribute_security_mode_check_valid(security_mode); - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).read); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_read_obj, bleio_characteristic_get_read); + mp_obj_t descriptors = args[ARG_descriptors].u_obj; + if (descriptors == mp_const_none) { + descriptors = mp_const_empty_tuple; + } -const mp_obj_property_t bleio_characteristic_read_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_read_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; + bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t); + self->base.type = &bleio_characteristic_type; -//| .. attribute:: write -//| -//| A `bool` specifying if the characteristic allows writing to its value. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_write(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_bleio_characteristic_construct(self, uuid, properties, security_mode, descriptors); - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).write); + return MP_OBJ_FROM_PTR(self); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_obj, bleio_characteristic_get_write); -const mp_obj_property_t bleio_characteristic_write_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_write_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: write_no_response +//| .. attribute:: properties //| -//| A `bool` specifying if the characteristic allows writing to its value without response. (read-only) +//| An int bitmask representing which properties are set. //| -STATIC mp_obj_t bleio_characteristic_get_write_no_response(mp_obj_t self_in) { +STATIC mp_obj_t bleio_characteristic_get_properties(mp_obj_t self_in) { bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).write_no_response); + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_properties(self)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_no_response_obj, bleio_characteristic_get_write_no_response); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_properties_obj, bleio_characteristic_get_properties); -const mp_obj_property_t bleio_characteristic_write_no_response_obj = { +const mp_obj_property_t bleio_characteristic_properties_obj = { .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_write_no_response_obj, + .proxy = { (mp_obj_t)&bleio_characteristic_get_properties_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj }, }; @@ -301,16 +209,43 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_ch STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_broadcast), MP_ROM_PTR(&bleio_characteristic_broadcast_obj) }, - { MP_ROM_QSTR(MP_QSTR_descriptors), MP_ROM_PTR(&bleio_characteristic_descriptors_obj) }, - { MP_ROM_QSTR(MP_QSTR_indicate), MP_ROM_PTR(&bleio_characteristic_indicate_obj) }, - { MP_ROM_QSTR(MP_QSTR_notify), MP_ROM_PTR(&bleio_characteristic_notify_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&bleio_characteristic_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_obj) }, - { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) }, - { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_characteristic_value_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&bleio_characteristic_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_write_no_response), MP_ROM_PTR(&bleio_characteristic_write_no_response_obj) }, + { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_get_properties) }, + { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_obj) }, + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_characteristic_value_obj) }, + + // Bitmask constants to represent properties +//| .. data:: BROADCAST +//| +//| property: allowed in advertising packets +//| +//| .. data:: INDICATE +//| +//| property: server will indicate to the client when the value is set and wait for a response +//| +//| .. data:: NOTIFY +//| +//| property: server will notify the client when the value is set +//| +//| .. data:: READ +//| +//| property: clients may read this characteristic +//| +//| .. data:: WRITE +//| +//| property: clients may write this characteristic; a response will be sent back +//| +//| .. data:: WRITE_NO_RESPONSE +//| +//| property: clients may write this characteristic; no response will be sent back +//| + { MP_ROM_QSTR(MP_QSTR_BROADCAST), MP_ROM_INT(CHAR_PROP_BROADCAST) }, + { MP_ROM_QSTR(MP_QSTR_INDICATE), MP_ROM_INT(CHAR_PROP_INDICATE) }, + { MP_ROM_QSTR(MP_QSTR_NOTIFY), MP_ROM_INT(CHAR_PROP_NOTIFY) }, + { MP_ROM_QSTR(MP_QSTR_READ), MP_ROM_INT(CHAR_PROP_READ) }, + { MP_ROM_QSTR(MP_QSTR_WRITE), MP_ROM_INT(CHAR_PROP_WRITE) }, + { MP_ROM_QSTR(MP_QSTR_WRITE_NO_RESPONSE), MP_ROM_INT(CHAR_PROP_WRITE_NO_RESPONSE) }, + }; STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_locals_dict, bleio_characteristic_locals_dict_table); @@ -330,5 +265,5 @@ const mp_obj_type_t bleio_characteristic_type = { .name = MP_QSTR_Characteristic, .make_new = bleio_characteristic_make_new, .print = bleio_characteristic_print, - .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict + .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict, }; diff --git a/shared-bindings/bleio/Characteristic.h b/shared-bindings/bleio/Characteristic.h index d450c42b4..379f9b4bf 100644 --- a/shared-bindings/bleio/Characteristic.h +++ b/shared-bindings/bleio/Characteristic.h @@ -28,12 +28,13 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H +#include "shared-bindings/bleio/Attribute.h" #include "shared-module/bleio/Characteristic.h" #include "common-hal/bleio/Characteristic.h" extern const mp_obj_type_t bleio_characteristic_type; -extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, mp_obj_list_t *descriptor_list); +extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t security_mode, mp_obj_t descriptors); extern mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self); extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self); diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c index f2e5aa01d..b709f3aa7 100644 --- a/shared-bindings/bleio/Descriptor.c +++ b/shared-bindings/bleio/Descriptor.c @@ -28,6 +28,7 @@ #include "py/objproperty.h" #include "py/runtime.h" +#include "shared-bindings/bleio/Attribute.h" #include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/UUID.h" @@ -41,23 +42,15 @@ //| information about the characteristic. //| -//| .. class:: Descriptor(uuid) +//| .. class:: Descriptor(uuid, security_mode=`Attribute.OPEN`) //| -//| Create a new descriptor object with the UUID uuid. +//| Create a new descriptor object with the UUID uuid and the given value, if any. -//| .. attribute:: handle -//| -//| The descriptor handle. (read-only) -//| - -//| .. attribute:: uuid -//| -//| The descriptor uuid. (read-only) -//| STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_uuid }; + enum { ARG_uuid, ARG_security_mode }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_security_mode, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -69,28 +62,22 @@ STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_ar mp_raise_ValueError(translate("Expected a UUID")); } + const bleio_attribute_security_mode_t security_mode = args[ARG_security_mode].u_int; + common_hal_bleio_attribute_security_mode_check_valid(security_mode); + bleio_descriptor_obj_t *self = m_new_obj(bleio_descriptor_obj_t); self->base.type = type; bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_arg); - common_hal_bleio_descriptor_construct(self, uuid); - return MP_OBJ_FROM_PTR(self); -} + common_hal_bleio_descriptor_construct(self, uuid, security_mode); -STATIC mp_obj_t bleio_descriptor_get_handle(mp_obj_t self_in) { - bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_int(common_hal_bleio_descriptor_get_handle(self)); + return MP_OBJ_FROM_PTR(self); } -MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_handle_obj, bleio_descriptor_get_handle); - -const mp_obj_property_t bleio_descriptor_handle_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_descriptor_get_handle_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; +//| .. attribute:: uuid +//| +//| The descriptor uuid. (read-only) +//| STATIC mp_obj_t bleio_descriptor_get_uuid(mp_obj_t self_in) { bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -108,54 +95,7 @@ const mp_obj_property_t bleio_descriptor_uuid_obj = { STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = { // Properties - { MP_ROM_QSTR(MP_QSTR_handle), MP_ROM_PTR(&bleio_descriptor_handle_obj) }, { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_descriptor_uuid_obj) }, - - // Static variables - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_EXTENDED_PROPERTIES), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_EXTENDED_PROPERTIES) }, - - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_USER_DESCRIPTION), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION) }, - - { MP_ROM_QSTR(MP_QSTR_CLIENT_CHARACTERISTIC_CONFIGURATION), - MP_ROM_INT(DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION) }, - - { MP_ROM_QSTR(MP_QSTR_SERVER_CHARACTERISTIC_CONFIGURATION), - MP_ROM_INT(DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION) }, - - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_PRESENTATION_FORMAT), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_PRESENTATION_FORMAT) }, - - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_AGGREGATE_FORMAT), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_AGGREGATE_FORMAT) }, - - { MP_ROM_QSTR(MP_QSTR_VALID_RANGE), - MP_ROM_INT(DESCRIPTOR_UUID_VALID_RANGE) }, - - { MP_ROM_QSTR(MP_QSTR_EXTERNAL_REPORT_REFERENCE), - MP_ROM_INT(DESCRIPTOR_UUID_EXTERNAL_REPORT_REFERENCE) }, - - { MP_ROM_QSTR(MP_QSTR_REPORT_REFERENCE), - MP_ROM_INT(DESCRIPTOR_UUID_REPORT_REFERENCE) }, - - { MP_ROM_QSTR(MP_QSTR_NUMBER_OF_DIGITALS), - MP_ROM_INT(DESCRIPTOR_UUID_NUMBER_OF_DIGITALS) }, - - { MP_ROM_QSTR(MP_QSTR_VALUE_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_VALUE_TRIGGER_SETTING) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_CONFIGURATION), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_CONFIGURATION) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_MEASUREMENT ), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_MEASUREMENT) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_TRIGGER_SETTING) }, - - { MP_ROM_QSTR(MP_QSTR_TIME_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_TIME_TRIGGER_SETTING) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_descriptor_locals_dict, bleio_descriptor_locals_dict_table); diff --git a/shared-bindings/bleio/Descriptor.h b/shared-bindings/bleio/Descriptor.h index fd11ea08c..a7daee574 100644 --- a/shared-bindings/bleio/Descriptor.h +++ b/shared-bindings/bleio/Descriptor.h @@ -28,31 +28,14 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H +#include "shared-module/bleio/Attribute.h" #include "common-hal/bleio/Descriptor.h" #include "common-hal/bleio/UUID.h" -enum { - DESCRIPTOR_UUID_CHARACTERISTIC_EXTENDED_PROPERTIES = 0x2900, - DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION = 0x2901, - DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION = 0x2902, - DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION = 0x2903, - DESCRIPTOR_UUID_CHARACTERISTIC_PRESENTATION_FORMAT = 0x2904, - DESCRIPTOR_UUID_CHARACTERISTIC_AGGREGATE_FORMAT = 0x2905, - DESCRIPTOR_UUID_VALID_RANGE = 0x2906, - DESCRIPTOR_UUID_EXTERNAL_REPORT_REFERENCE = 0x2907, - DESCRIPTOR_UUID_REPORT_REFERENCE = 0x2908, - DESCRIPTOR_UUID_NUMBER_OF_DIGITALS = 0x2909, - DESCRIPTOR_UUID_VALUE_TRIGGER_SETTING = 0x290A, - DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_CONFIGURATION = 0x290B, - DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_MEASUREMENT = 0x290C, - DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_TRIGGER_SETTING = 0x290D, - DESCRIPTOR_UUID_TIME_TRIGGER_SETTING = 0x290E, -}; - extern const mp_obj_type_t bleio_descriptor_type; -extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid); extern mp_int_t common_hal_bleio_descriptor_get_handle(bleio_descriptor_obj_t *self); extern mp_obj_t common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self); +extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t security_mode); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index ba3bae6c7..7a6f96436 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -31,21 +31,26 @@ #include "shared-bindings/bleio/Central.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/CharacteristicBuffer.h" -// #include "shared-bindings/bleio/Descriptor.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Peripheral.h" #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/Scanner.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" -//| :mod:`bleio` --- Bluetooth Low Energy functionality +//| :mod:`bleio` --- Bluetooth Low Energy (BLE) communication //| ================================================================ //| //| .. module:: bleio //| :synopsis: Bluetooth Low Energy functionality //| :platform: nRF //| -//| The `bleio` module contains methods for managing the BLE adapter. +//| The `bleio` module provides necessary low-level functionality for communicating +//| using Bluetooth Low Energy (BLE). We recommend you use `bleio` in conjunction +//| with the `adafruit_ble `_ +//| CircuitPython library, which builds on `bleio`, and +//| provides higher-level convenience functionality, including predefined beacons, clients, +//| servers. //| //| Libraries //| @@ -72,20 +77,23 @@ //| STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) }, - { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, - { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&bleio_central_type) }, - { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, - { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_ROM_PTR(&bleio_characteristic_buffer_type) }, -// { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, - { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&bleio_peripheral_type) }, - { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, - { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, - { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, - { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) }, + { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, + { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&bleio_central_type) }, + { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, + { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_ROM_PTR(&bleio_characteristic_buffer_type) }, + { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, + { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&bleio_peripheral_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, + { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, + { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, + { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, // Properties - { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, + { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, + + // constants + { MP_ROM_QSTR(MP_QSTR_SEC), MP_ROM_PTR(&bleio_uuid_type) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); diff --git a/shared-bindings/bleio/__init__.h b/shared-bindings/bleio/__init__.h index dd6e55204..626b188a9 100644 --- a/shared-bindings/bleio/__init__.h +++ b/shared-bindings/bleio/__init__.h @@ -34,7 +34,6 @@ #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" -#include "shared-module/bleio/__init__.h" #include "common-hal/bleio/Adapter.h" extern const super_adapter_obj_t common_hal_bleio_adapter_obj; diff --git a/shared-module/bleio/Attribute.c b/shared-module/bleio/Attribute.c new file mode 100644 index 000000000..ac854ec6b --- /dev/null +++ b/shared-module/bleio/Attribute.c @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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 + +#include "py/runtime.h" +#include "shared-bindings/bleio/Attribute.h" + +void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SEC_MODE_NO_ACCESS: + case SEC_MODE_OPEN: + case SEC_MODE_ENC_NO_MITM: + case SEC_MODE_ENC_WITH_MITM: + case SEC_MODE_LESC_ENC_WITH_MITM: + case SEC_MODE_SIGNED_NO_MITM: + case SEC_MODE_SIGNED_WITH_MITM: + break; + default: + mp_raise_ValueError(translate("Invalid security_mode")); + break; + } +} diff --git a/shared-module/bleio/Attribute.h b/shared-module/bleio/Attribute.h new file mode 100644 index 000000000..62615f1b5 --- /dev/null +++ b/shared-module/bleio/Attribute.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H + +// BLE security modes: 0x +typedef enum { + SEC_MODE_NO_ACCESS = 0x00, + SEC_MODE_OPEN = 0x11, + SEC_MODE_ENC_NO_MITM = 0x21, + SEC_MODE_ENC_WITH_MITM = 0x31, + SEC_MODE_LESC_ENC_WITH_MITM = 0x41, + SEC_MODE_SIGNED_NO_MITM = 0x12, + SEC_MODE_SIGNED_WITH_MITM = 0x22, +} bleio_attribute_security_mode_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H diff --git a/shared-module/bleio/Characteristic.h b/shared-module/bleio/Characteristic.h index 27b43588f..409a57c76 100644 --- a/shared-module/bleio/Characteristic.h +++ b/shared-module/bleio/Characteristic.h @@ -27,14 +27,17 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H -// Flags for each characteristic property. Common across ports. -typedef struct { - bool broadcast : 1; - bool read : 1; - bool write_no_response : 1; - bool write : 1; - bool notify : 1; - bool indicate : 1; -} bleio_characteristic_properties_t; +typedef enum { + CHAR_PROP_NONE = 0, + CHAR_PROP_BROADCAST = 1u << 0, + CHAR_PROP_INDICATE = 1u << 1, + CHAR_PROP_NOTIFY = 1u << 2, + CHAR_PROP_READ = 1u << 3, + CHAR_PROP_WRITE = 1u << 4, + CHAR_PROP_WRITE_NO_RESPONSE = 1u << 5, + CHAR_PROP_ALL = (CHAR_PROP_BROADCAST | CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY | + CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE) +} bleio_characteristic_properties_enum_t; +typedef uint8_t bleio_characteristic_properties_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H diff --git a/shared-module/bleio/__init__.h b/shared-module/bleio/__init__.h deleted file mode 100644 index f8f0e0660..000000000 --- a/shared-module/bleio/__init__.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H -#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H - -extern void bleio_reset(void); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H -- cgit v1.2.3 From 9907e3fa288eb9c31d0152e56c4d9ba998cf8122 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Sat, 3 Aug 2019 13:48:55 +0200 Subject: Allow to specify pre-allocated buffer in audicore.WaveFile It lets us re-use the same buffer for playing multiple files. This also allows us to control the size of the buffer. Half of the buffer will be used for the fist, and half for the second internal buffer. --- shared-bindings/audiocore/WaveFile.c | 22 ++++++++++++++++------ shared-bindings/audiocore/WaveFile.h | 2 +- shared-module/audiocore/WaveFile.c | 33 ++++++++++++++++++++++----------- 3 files changed, 39 insertions(+), 18 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c index 4c1993b7c..7398353b0 100644 --- a/shared-bindings/audiocore/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -39,13 +39,15 @@ //| ======================================================== //| //| A .wav file prepped for audio playback. Only mono and stereo files are supported. Samples must -//| be 8 bit unsigned or 16 bit signed. +//| be 8 bit unsigned or 16 bit signed. If a buffer is provided, it will be used instead of allocating +//| an internal buffer. //| -//| .. class:: WaveFile(file) +//| .. class:: WaveFile(file[, buffer]) //| //| Load a .wav file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`. //| //| :param typing.BinaryIO file: Already opened wave file +//| :param bytearray buffer: Optional pre-allocated buffer //| //| Playing a wave file from flash:: //| @@ -68,15 +70,23 @@ //| print("stopped") //| STATIC mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 1, 1, false); + mp_arg_check_num(n_args, kw_args, 1, 2, false); audioio_wavefile_obj_t *self = m_new_obj(audioio_wavefile_obj_t); self->base.type = &audioio_wavefile_type; - if (MP_OBJ_IS_TYPE(args[0], &mp_type_fileio)) { - common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0])); - } else { + if (!MP_OBJ_IS_TYPE(args[0], &mp_type_fileio)) { mp_raise_TypeError(translate("file must be a file opened in byte mode")); } + uint8_t *buffer = NULL; + size_t buffer_size = 0; + if (n_args >= 2) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + buffer = bufinfo.buf; + buffer_size = bufinfo.len; + } + common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0]), + buffer, buffer_size); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiocore/WaveFile.h b/shared-bindings/audiocore/WaveFile.h index d2572318b..f4a172319 100644 --- a/shared-bindings/audiocore/WaveFile.h +++ b/shared-bindings/audiocore/WaveFile.h @@ -35,7 +35,7 @@ extern const mp_obj_type_t audioio_wavefile_type; void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, - pyb_file_obj_t* file); + pyb_file_obj_t* file, uint8_t *buffer, size_t buffer_size); void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self); bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self); diff --git a/shared-module/audiocore/WaveFile.c b/shared-module/audiocore/WaveFile.c index 810d9c33b..df5d4b61d 100644 --- a/shared-module/audiocore/WaveFile.c +++ b/shared-module/audiocore/WaveFile.c @@ -46,7 +46,9 @@ struct wave_format_chunk { }; void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, - pyb_file_obj_t* file) { + pyb_file_obj_t* file, + uint8_t *buffer, + size_t buffer_size) { // Load the wave self->file = file; uint8_t chunk_header[16]; @@ -84,7 +86,6 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, } // Get the sample_rate self->sample_rate = format.sample_rate; - self->len = 256; self->channel_count = format.num_channels; self->bits_per_sample = format.bits_per_sample; @@ -111,21 +112,31 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, // Try to allocate two buffers, one will be loaded from file and the other // DMAed to DAC. - self->buffer = m_malloc(self->len, false); - if (self->buffer == NULL) { - common_hal_audioio_wavefile_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); - } + if (buffer_size) { + self->len = buffer_size / 2; + self->buffer = buffer; + self->second_buffer = buffer + self->len; + } else { + self->len = 256; + self->buffer = m_malloc(self->len, false); + if (self->buffer == NULL) { + common_hal_audioio_wavefile_deinit(self); + mp_raise_msg(&mp_type_MemoryError, + translate("Couldn't allocate first buffer")); + } - self->second_buffer = m_malloc(self->len, false); - if (self->second_buffer == NULL) { - common_hal_audioio_wavefile_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); + self->second_buffer = m_malloc(self->len, false); + if (self->second_buffer == NULL) { + common_hal_audioio_wavefile_deinit(self); + mp_raise_msg(&mp_type_MemoryError, + translate("Couldn't allocate second buffer")); + } } } void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self) { self->buffer = NULL; + self->second_buffer = NULL; } bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self) { -- cgit v1.2.3 From 065efb05b75e35f7e161b6828742b01d26ce5379 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 3 Aug 2019 11:20:06 -0500 Subject: bring MixerVoice back to building state; update documentation --- py/circuitpy_defns.mk | 1 + shared-bindings/audiocore/Mixer.c | 82 ++++-------- shared-bindings/audiocore/MixerVoice.c | 221 +++++++++++++++++++++++++++++++++ shared-bindings/audiocore/MixerVoice.h | 47 +++++++ shared-bindings/audiocore/__init__.c | 1 + shared-bindings/audioio/MixerVoice.c | 210 ------------------------------- shared-bindings/audioio/MixerVoice.h | 29 ----- shared-module/audiocore/Mixer.c | 1 + shared-module/audiocore/MixerVoice.c | 82 ++++++++++++ shared-module/audiocore/MixerVoice.h | 46 +++++++ shared-module/audioio/MixerVoice.c | 64 ---------- shared-module/audioio/MixerVoice.h | 28 ----- 12 files changed, 424 insertions(+), 388 deletions(-) create mode 100644 shared-bindings/audiocore/MixerVoice.c create mode 100644 shared-bindings/audiocore/MixerVoice.h delete mode 100644 shared-bindings/audioio/MixerVoice.c delete mode 100644 shared-bindings/audioio/MixerVoice.h create mode 100644 shared-module/audiocore/MixerVoice.c create mode 100644 shared-module/audiocore/MixerVoice.h delete mode 100644 shared-module/audioio/MixerVoice.c delete mode 100644 shared-module/audioio/MixerVoice.h (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index bdefc18cc..16a2474f3 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -306,6 +306,7 @@ $(filter $(SRC_PATTERNS), \ audioio/__init__.c \ audiocore/__init__.c \ audiocore/Mixer.c \ + audiocore/MixerVoice.c \ audiocore/RawSample.c \ audiocore/WaveFile.c \ bitbangio/I2C.c \ diff --git a/shared-bindings/audiocore/Mixer.c b/shared-bindings/audiocore/Mixer.c index ee4d8548c..66babdd08 100644 --- a/shared-bindings/audiocore/Mixer.c +++ b/shared-bindings/audiocore/Mixer.c @@ -24,6 +24,8 @@ * THE SOFTWARE. */ #include "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiocore/MixerVoice.h" +#include "shared-module/audiocore/MixerVoice.h" #include @@ -43,33 +45,43 @@ //| //| Mixer mixes multiple samples into one sample. //| -//| .. class:: Mixer(channel_count=2, buffer_size=1024) +//| .. class:: Mixer(voice_count=2, buffer_size=1024, channel_count=2, bits_per_sample=16, samples_signed=True, sample_rate=8000) //| //| Create a Mixer object that can mix multiple channels with the same sample rate. +//| Samples are accessed and controlled with the mixer's `audioio.MixerVoice` objects. //| -//| :param int channel_count: The maximum number of samples to mix at once +//| :param int voice_count: The maximum number of voices to mix //| :param int buffer_size: The total size in bytes of the buffers to mix into +//| :param int channel_count: The maximum number of samples to mix at once +//| :param int bits_per_sample: The bits per sample of the samples being played +//| :param bool samples_signed: Samples are signed (True) or unsigned (False) +//| :param int sample_rate: The sample rate to be used for all samples //| //| Playing a wave file from flash:: //| //| import board //| import audioio +//| import audiocore //| import digitalio //| //| # Required for CircuitPlayground Express //| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) //| speaker_enable.switch_to_output(value=True) //| -//| music = audioio.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) -//| drum = audioio.WaveFile(open("drum.wav", "rb")) -//| mixer = audioio.Mixer(voice_count=2, sample_rate=16000, channel_count=1, bits_per_sample=16, samples_signed=True) +//| music = audiocore.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) +//| drum = audiocore.WaveFile(open("drum.wav", "rb")) +//| mixer = audiocore.Mixer(voice_count=2, sample_rate=16000, channel_count=1, +//| bits_per_sample=16, samples_signed=True) //| a = audioio.AudioOut(board.A0) //| //| print("playing") +//| # Have AudioOut play our Mixer source //| a.play(mixer) -//| mixer.play(music, voice=0) +//| # Play the first sample voice +//| mixer.voice[0].play(music) //| while mixer.playing: -//| mixer.play(drum, voice=1) +//| # Play the second sample voice +//| mixer.voice[1].play(drum) //| time.sleep(1) //| print("stopped") //| @@ -151,54 +163,6 @@ STATIC mp_obj_t audioio_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer___exit___obj, 4, 4, audioio_mixer_obj___exit__); - -//| .. method:: play(sample, *, voice=0, loop=False) -//| -//| Plays the sample once when loop=False and continuously when loop=True. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. -//| -//| The sample must match the Mixer's encoding settings given in the constructor. -//| -STATIC mp_obj_t audioio_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_voice, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_voice, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_audioio_mixer_play(self, sample, args[ARG_voice].u_int, args[ARG_loop].u_bool); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_play_obj, 1, audioio_mixer_obj_play); - -//| .. method:: stop_voice(voice=0) -//| -//| Stops playback of the sample on the given voice. -//| -STATIC mp_obj_t audioio_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_voice }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, - }; - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_stop_voice_obj, 1, audioio_mixer_obj_stop_voice); - //| .. attribute:: playing //| //| True when any voice is being output. (read-only) @@ -237,11 +201,15 @@ const mp_obj_property_t audioio_mixer_sample_rate_obj = { //| .. attribute:: voice //| -//| tuple of voice objects +//| A tuple of the mixer's `audioio.MixerVoice` object(s). +//| +//| .. code-block:: python //| +//| >>> mixer.voice +//| (,) STATIC mp_obj_t audioio_mixer_obj_get_voice(mp_obj_t self_in) { audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + check_for_deinit(self); return self->voice_tuple; } MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_voice_obj, audioio_mixer_obj_get_voice); diff --git a/shared-bindings/audiocore/MixerVoice.c b/shared-bindings/audiocore/MixerVoice.c new file mode 100644 index 000000000..50f14c758 --- /dev/null +++ b/shared-bindings/audiocore/MixerVoice.c @@ -0,0 +1,221 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 DeanM for Adafruit Industries + * + * 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 "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiocore/MixerVoice.h" + +#include + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audioio +//| +//| :class:`MixerVoice` -- Voice objects used with Mixer +//| ===================================================== +//| +//| Used to access and control samples with `audioio.Mixer`. +//| +//| .. class:: MixerVoice() +//| +//| MixerVoice instance object(s) created by `audioio.Mixer`. +//| +// TODO: support mono or stereo voices +STATIC mp_obj_t audioio_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + audioio_mixervoice_obj_t *self = m_new_obj(audioio_mixervoice_obj_t); + self->base.type = &audioio_mixervoice_type; + self->sample = NULL; + self->level = ((1 << 15)-1); + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the Voice and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audioio_mixervoice_deinit(mp_obj_t self_in) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_deinit_obj, audioio_mixervoice_deinit); + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audioio_mixervoice_obj___exit__(size_t n_args, const mp_obj_t *args) { + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixervoice___exit___obj, 4, 4, audioio_mixervoice_obj___exit__); + + +//| .. method:: play(sample, *, loop=False) +//| +//| Plays the sample once when ``loop=False``, and continuously when ``loop=True``. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. +//| +//| The sample must match the `audioio.Mixer`'s encoding settings given in the constructor. +//| +STATIC mp_obj_t audioio_mixervoice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + //raise_error_if_deinited(common_hal_audioio_mixervoice_deinited(self)); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audioio_mixervoice_play(self, sample, args[ARG_loop].u_bool); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_play_obj, 1, audioio_mixervoice_obj_play); + +//| .. method:: stop() +//| +//| Stops playback of the sample on this voice. +//| +STATIC mp_obj_t audioio_mixervoice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_voice }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, + }; + audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + //raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_audioio_mixervoice_stop(self); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_stop_obj, 1, audioio_mixervoice_obj_stop); + +//| .. method:: level() +//| +//| The volume level of a voice, as a floating point number between 0 and 1. +//| +STATIC mp_obj_t audioio_mixervoice_obj_get_level(mp_obj_t self_in) { + + #if !MICROPY_PY_BUILTINS_FLOAT + #error "floating point not supported" + #endif + + return mp_obj_new_float(common_hal_audioio_mixervoice_get_level(self_in)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_get_level_obj, audioio_mixervoice_obj_get_level); + +STATIC mp_obj_t audioio_mixervoice_obj_set_level(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_level }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_level, MP_ARG_OBJ | MP_ARG_REQUIRED }, + }; + audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + #if MICROPY_PY_BUILTINS_FLOAT + float level = mp_obj_get_float(args[ARG_level].u_obj); + #else + #error "floating point not supported" + #endif + + if (level > 1 || level < 0) { + mp_raise_ValueError(translate("level must be between 0 and 1")); + } + + common_hal_audioio_mixervoice_set_level(self, level); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_set_level_obj, 1, audioio_mixervoice_obj_set_level); + +const mp_obj_property_t audioio_mixervoice_level_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixervoice_get_level_obj, + (mp_obj_t)&audioio_mixervoice_set_level_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//TODO: @sommersoft - enable voice.playing tracking? will need an additional field +// in the struct, with supporting logic. disabled documentation for now. + +// .. attribute:: playing +// +// True when any voice is being output. (read-only) +// +STATIC mp_obj_t audioio_mixervoice_obj_get_playing(mp_obj_t self_in) { +#if 0 + audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); +#endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_get_playing_obj, audioio_mixervoice_obj_get_playing); + +const mp_obj_property_t audioio_mixervoice_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audioio_mixervoice_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t audioio_mixervoice_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixervoice_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixervoice___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixervoice_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_mixervoice_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixervoice_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_level), MP_ROM_PTR(&audioio_mixervoice_level_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audioio_mixervoice_locals_dict, audioio_mixervoice_locals_dict_table); + +const mp_obj_type_t audioio_mixervoice_type = { + { &mp_type_type }, + .name = MP_QSTR_MixerVoice, + .make_new = audioio_mixervoice_make_new, + .locals_dict = (mp_obj_dict_t*)&audioio_mixervoice_locals_dict, +}; diff --git a/shared-bindings/audiocore/MixerVoice.h b/shared-bindings/audiocore/MixerVoice.h new file mode 100644 index 000000000..4e7ea47e7 --- /dev/null +++ b/shared-bindings/audiocore/MixerVoice.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 DeanM for Adafruit Industries + * + * 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. + */ +#ifndef SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ +#define SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ + +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/audiocore/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-module/audiocore/MixerVoice.h" +#include "shared-module/audiocore/Mixer.h" + +extern const mp_obj_type_t audioio_mixer_type; +extern const mp_obj_type_t audioio_mixervoice_type; + +void common_hal_audioio_mixervoice_deinit(audioio_mixervoice_obj_t* self); +void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent); +void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop); +void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self); +float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self); +void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float gain); + +bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self); + +#endif /* SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ */ diff --git a/shared-bindings/audiocore/__init__.c b/shared-bindings/audiocore/__init__.c index c64759d4f..9d82b1f99 100644 --- a/shared-bindings/audiocore/__init__.c +++ b/shared-bindings/audiocore/__init__.c @@ -50,6 +50,7 @@ //| :maxdepth: 3 //| //| Mixer +//| MixerVoice //| RawSample //| WaveFile //| diff --git a/shared-bindings/audioio/MixerVoice.c b/shared-bindings/audioio/MixerVoice.c deleted file mode 100644 index cba82feb2..000000000 --- a/shared-bindings/audioio/MixerVoice.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * MixerVoice.c - * - * Created on: Nov 15, 2018 - * Author: dean - */ -#include "shared-bindings/audioio/Mixer.h" -#include "shared-bindings/audioio/MixerVoice.h" - -#include - -#include "lib/utils/context_manager_helpers.h" -#include "py/binary.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audioio/RawSample.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| .. currentmodule:: audioio -//| -//| :class:`Mixer` -- Mixes one or more audio samples together -//| =========================================================== -//| -//| Mixer mixes multiple samples into one sample. -//| -//| .. class:: Mixer(channel_count=2, buffer_size=1024) -//| -//| Create a Mixer object that can mix multiple channels with the same sample rate. -//| -//| :param int channel_count: The maximum number of samples to mix at once -//| :param int buffer_size: The total size in bytes of the buffers to mix into -//| -// TODO: support mono or stereo voices -STATIC mp_obj_t audioio_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - audioio_mixervoice_obj_t *self = m_new_obj(audioio_mixervoice_obj_t); - self->base.type = &audioio_mixervoice_type; - self->sample = NULL; - self->level = ((1 << 15)-1); - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: deinit() -//| -//| Deinitialises the Voice and releases any hardware resources for reuse. -//| -STATIC mp_obj_t audioio_mixervoice_deinit(mp_obj_t self_in) { - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_deinit_obj, audioio_mixervoice_deinit); - -//| .. method:: __enter__() -//| -//| No-op used by Context Managers. -//| -// Provided by context manager helper. - -//| .. method:: __exit__() -//| -//| Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info. -//| -STATIC mp_obj_t audioio_mixervoice_obj___exit__(size_t n_args, const mp_obj_t *args) { - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixervoice___exit___obj, 4, 4, audioio_mixervoice_obj___exit__); - - -//| .. method:: play(sample, *, loop=False) -//| -//| Plays the sample once when loop=False and continuously when loop=True. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. -//| -//| The sample must match the Mixer's encoding settings given in the constructor. -//| -STATIC mp_obj_t audioio_mixervoice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - //raise_error_if_deinited(common_hal_audioio_mixervoice_deinited(self)); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_audioio_mixervoice_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_play_obj, 1, audioio_mixervoice_obj_play); - -//| .. method:: stop() -//| -//| Stops playback of the sample on this voice. -//| -STATIC mp_obj_t audioio_mixervoice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_voice }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, - }; - audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - //raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - common_hal_audioio_mixervoice_stop(self); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_stop_obj, 1, audioio_mixervoice_obj_stop); - -//| .. method:: get_gain(voice, gain) -//| -//| Get the gain of a voice. -//| -//| Returns as a floating point number between 0 and 1 -//| -STATIC mp_obj_t audioio_mixervoice_obj_get_level(mp_obj_t self_in) { - - #if !MICROPY_PY_BUILTINS_FLOAT - #error "floating point not supported" - #endif - - return mp_obj_new_float(common_hal_audioio_mixervoice_get_level(self_in)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_get_level_obj, audioio_mixervoice_obj_get_level); - -//| .. method:: set_gain(voice, gain) -//| -//| Set the gain of a voice. -//| -//| gain must be a floating point number between 0 and 1 -//| -STATIC mp_obj_t audioio_mixervoice_obj_set_level(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_level }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_level, MP_ARG_OBJ | MP_ARG_REQUIRED }, - }; - audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - #if MICROPY_PY_BUILTINS_FLOAT - float level = mp_obj_get_float(args[ARG_level].u_obj); - #else - #error "floating point not supported" - #endif - - if (level > 1 || level < 0) { - mp_raise_ValueError(translate("level must be between 0 and 1")); - } - - common_hal_audioio_mixervoice_set_level(self, level); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_set_level_obj, 1, audioio_mixervoice_obj_set_level); - -const mp_obj_property_t audioio_mixervoice_level_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixervoice_get_level_obj, - (mp_obj_t)&audioio_mixervoice_set_level_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: playing -//| -//| True when any voice is being output. (read-only) -//| -STATIC mp_obj_t audioio_mixervoice_obj_get_playing(mp_obj_t self_in) { -#if 0 - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); - return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); -#endif - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_get_playing_obj, audioio_mixervoice_obj_get_playing); - -const mp_obj_property_t audioio_mixervoice_playing_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixervoice_get_playing_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t audioio_mixervoice_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixervoice_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixervoice___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixervoice_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_mixervoice_stop_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixervoice_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_level), MP_ROM_PTR(&audioio_mixervoice_level_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(audioio_mixervoice_locals_dict, audioio_mixervoice_locals_dict_table); - -const mp_obj_type_t audioio_mixervoice_type = { - { &mp_type_type }, - .name = MP_QSTR_MixerVoice, - .make_new = audioio_mixervoice_make_new, - .locals_dict = (mp_obj_dict_t*)&audioio_mixervoice_locals_dict, -}; diff --git a/shared-bindings/audioio/MixerVoice.h b/shared-bindings/audioio/MixerVoice.h deleted file mode 100644 index 641a0faf2..000000000 --- a/shared-bindings/audioio/MixerVoice.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * MixerVoice.h - * - * Created on: Nov 15, 2018 - * Author: dean - */ - -#ifndef SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ -#define SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ - -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/audioio/Mixer.h" -#include "shared-bindings/audioio/RawSample.h" -#include "shared-module/audioio/MixerVoice.h" -#include "shared-module/audioio/Mixer.h" - -extern const mp_obj_type_t audioio_mixer_type; -extern const mp_obj_type_t audioio_mixervoice_type; - -void common_hal_audioio_mixervoice_deinit(audioio_mixervoice_obj_t* self); -void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent); -void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop); -void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self); -float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self); -void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float gain); - -bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self); - -#endif /* SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ */ diff --git a/shared-module/audiocore/Mixer.c b/shared-module/audiocore/Mixer.c index 8c083f419..40ed63dc4 100644 --- a/shared-module/audiocore/Mixer.c +++ b/shared-module/audiocore/Mixer.c @@ -25,6 +25,7 @@ */ #include "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiocore/MixerVoice.h" #include diff --git a/shared-module/audiocore/MixerVoice.c b/shared-module/audiocore/MixerVoice.c new file mode 100644 index 000000000..c16dfccb0 --- /dev/null +++ b/shared-module/audiocore/MixerVoice.c @@ -0,0 +1,82 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 DeanM for Adafruit Industries + * + * 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 "shared-bindings/audiocore/Mixer.h" + +#include + +#include "py/runtime.h" +#include "shared-module/audioio/__init__.h" +#include "shared-module/audiocore/RawSample.h" +#include "shared-module/audiocore/MixerVoice.h" + +void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent) { + self->parent = parent; +} + +float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self) { + return self->level; +} + +void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float level) { + self->level = level * ((1 << 15)-1); +} + +void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop) { + if (audiosample_sample_rate(sample) != self->parent->sample_rate) { + mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); + } + if (audiosample_channel_count(sample) != self->parent->channel_count) { + mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); + } + if (audiosample_bits_per_sample(sample) != self->parent->bits_per_sample) { + mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); + } + bool single_buffer; + bool samples_signed; + uint32_t max_buffer_length; + uint8_t spacing; + audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, + &max_buffer_length, &spacing); + if (samples_signed != self->parent->samples_signed) { + mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); + } + self->sample = sample; + self->loop = loop; + + audiosample_reset_buffer(sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &self->remaining_buffer, &self->buffer_length); + // Track length in terms of words. + self->buffer_length /= sizeof(uint32_t); + self->more_data = result == GET_BUFFER_MORE_DATA; +} + +bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self) { + return self->sample != NULL; +} + +void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self) { + self->sample = NULL; +} diff --git a/shared-module/audiocore/MixerVoice.h b/shared-module/audiocore/MixerVoice.h new file mode 100644 index 000000000..6010313bf --- /dev/null +++ b/shared-module/audiocore/MixerVoice.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 DeanM for Adafruit Industries + * + * 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. + */ +#ifndef SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ +#define SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/audiocore/Mixer.h" + +typedef struct { + mp_obj_base_t base; + audioio_mixer_obj_t *parent; + mp_obj_t sample; + bool loop; + bool more_data; + uint32_t* remaining_buffer; + uint32_t buffer_length; + int16_t level; +} audioio_mixervoice_obj_t; + + +#endif /* SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ */ diff --git a/shared-module/audioio/MixerVoice.c b/shared-module/audioio/MixerVoice.c deleted file mode 100644 index 3e8aaff89..000000000 --- a/shared-module/audioio/MixerVoice.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * MixerVoice.c - * - * Created on: Nov 15, 2018 - * Author: dean - */ - -#include "shared-bindings/audioio/Mixer.h" - -#include - -#include "py/runtime.h" -#include "shared-module/audioio/__init__.h" -#include "shared-module/audioio/RawSample.h" -#include "shared-module/audioio/MixerVoice.h" - -void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent) { - self->parent = parent; -} - -float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self) { - return self->level; -} - -void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float level) { - self->level = level * ((1 << 15)-1); -} - -void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop) { - if (audiosample_sample_rate(sample) != self->parent->sample_rate) { - mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); - } - if (audiosample_channel_count(sample) != self->parent->channel_count) { - mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); - } - if (audiosample_bits_per_sample(sample) != self->parent->bits_per_sample) { - mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); - } - bool single_buffer; - bool samples_signed; - uint32_t max_buffer_length; - uint8_t spacing; - audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, - &max_buffer_length, &spacing); - if (samples_signed != self->parent->samples_signed) { - mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); - } - self->sample = sample; - self->loop = loop; - - audiosample_reset_buffer(sample, false, 0); - audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &self->remaining_buffer, &self->buffer_length); - // Track length in terms of words. - self->buffer_length /= sizeof(uint32_t); - self->more_data = result == GET_BUFFER_MORE_DATA; -} - -bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self) { - return self->sample != NULL; -} - -void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self) { - self->sample = NULL; -} diff --git a/shared-module/audioio/MixerVoice.h b/shared-module/audioio/MixerVoice.h deleted file mode 100644 index 2811a741a..000000000 --- a/shared-module/audioio/MixerVoice.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * MixerVoice.h - * - * Created on: Nov 15, 2018 - * Author: dean - */ - -#ifndef SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ -#define SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ - -#include "py/obj.h" - -#include "shared-module/audioio/__init__.h" -#include "shared-module/audioio/Mixer.h" - -typedef struct { - mp_obj_base_t base; - audioio_mixer_obj_t *parent; - mp_obj_t sample; - bool loop; - bool more_data; - uint32_t* remaining_buffer; - uint32_t buffer_length; - int16_t level; -} audioio_mixervoice_obj_t; - - -#endif /* SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ */ -- cgit v1.2.3 From 1b7e213be4dc6cacd2b648e16470756473106c4a Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 8 Aug 2019 14:58:51 -0400 Subject: fix terminalio not clearing on construct --- shared-module/terminalio/Terminal.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'shared-module') diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 86c3e903e..df92a5dc4 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -36,6 +36,12 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, d self->tilegrid = tilegrid; self->first_row = 0; + for (uint16_t x = 0; x < self->tilegrid->width_in_tiles; x++) { + for (uint16_t y = 0; y < self->tilegrid->height_in_tiles; y++) { + common_hal_displayio_tilegrid_set_tile(self->tilegrid, x, y, 0); + } + } + common_hal_displayio_tilegrid_set_top_left(self->tilegrid, 0, 1); } -- cgit v1.2.3 From be5205d02081771e7aea51285f94fee83ef4fb77 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 10 Aug 2019 09:33:45 -0500 Subject: usb_hid: Allow USB work to progress while waiting for tud_hid_ready Otherwise, examples like the one attached to the related issue fail because tud_hid_ready never returns true. Testing performed: Adapted the example to nrf particle xenon (it was handy), removed dependency on IR, verified that the problem occurred before this change, and that it was fixed after this change. Closes: #2048 --- shared-module/usb_hid/Device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index a5a57419c..26d70cb82 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -47,7 +47,11 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t* // Wait until interface is ready, timeout = 2 seconds uint64_t end_ticks = ticks_ms + 2000; - while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) { } + while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP; +#endif + } if ( !tud_hid_ready() ) { mp_raise_msg(&mp_type_OSError, translate("USB Busy")); -- cgit v1.2.3 From e3c0428838efa2800dfa319089b869048dad851a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 11 Aug 2019 08:40:19 -0500 Subject: shared-module: Use RUN_BACKGROUND_TASKS --- shared-module/displayio/Display.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 51c6f292a..d1b4be20f 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -85,9 +85,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint32_t i = 0; while (!self->begin_transaction(self->bus)) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; -#endif + RUN_BACKGROUND_TASKS; } while (i < init_sequence_len) { uint8_t *cmd = init_sequence + i; @@ -235,7 +233,7 @@ int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* sel uint64_t last_refresh = self->last_refresh; // Don't try to refresh if we got an exception. while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { - MICROPY_VM_HOOK_LOOP + RUN_BACKGROUND_TASKS; } return 0; } -- cgit v1.2.3 From 614962ad6f38285c44598d414a9f5919e0dd40e3 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Tue, 13 Aug 2019 19:30:42 -0500 Subject: non-DSP 8bit & 16bit functions working. --- shared-module/audiocore/Mixer.c | 186 +++++++++++++++++++++++++++------------- 1 file changed, 125 insertions(+), 61 deletions(-) (limited to 'shared-module') diff --git a/shared-module/audiocore/Mixer.c b/shared-module/audiocore/Mixer.c index 40ed63dc4..8dd9c6522 100644 --- a/shared-module/audiocore/Mixer.c +++ b/shared-module/audiocore/Mixer.c @@ -123,13 +123,13 @@ uint32_t add8unsigned(uint32_t a, uint32_t b) { #else uint32_t result = 0; for (int8_t i = 0; i < 4; i++) { - int8_t ai = (a >> (sizeof(uint8_t) * 8 * i)) - 128; - int8_t bi = (b >> (sizeof(uint8_t) * 8 * i)) - 128; - int32_t intermediate = (int32_t) ai + bi; + uint8_t ai = (a >> (sizeof(uint8_t) * 8 * i)); + uint8_t bi = (b >> (sizeof(uint8_t) * 8 * i)); + int32_t intermediate = (int32_t) (ai + bi) / 2; if (intermediate > UCHAR_MAX) { intermediate = UCHAR_MAX; } - result |= ((uint8_t) intermediate + 128) << (sizeof(uint8_t) * 8 * i); + result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i); } return result; #endif @@ -179,64 +179,129 @@ uint32_t add16unsigned(uint32_t a, uint32_t b) { //TODO: static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + // if mul == 0, no need in wasting cycles + if (mul == 0) { + return 0; + } + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + int32_t hi, lo; + int32_t bits = 16; // saturate to 16 bits + int32_t shift = 0; // shift is done automatically + asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); + asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); + asm volatile("pkhbt %0, %1, %2, lsl #8" : "=r" (val) : "r" (lo), "r" (hi)); // pack return val; - val = __USUB8(val, 0x80808080); - #else - uint32_t result = 0; - for (int8_t i = 0; i < 4; i++) { - int8_t ai = (val >> (sizeof(uint8_t) * 8 * i)) - 128; - } - return result; - #endif + #else + uint32_t result = 0; + float mod_mul = (float) mul / (float) ((1<<15)-1); + for (int8_t i = 0; i < 4; i++) { + uint8_t ai = val >> (sizeof(uint8_t) * 8 * i); + int32_t intermediate = ai * mod_mul; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } + result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i); + } + + return result; + #endif } //TODO: static inline uint32_t mult8signed(uint32_t val, int32_t mul) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return val; - #else - uint32_t result = 0; - for (int8_t i = 0; i < 4; i++) { - int8_t ai = val >> (sizeof(int8_t) * 8 * i); - } - return result; - #endif + // if mul == 0, no need in wasting cycles + if (mul == 0) { + return 0; + } + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + int32_t hi, lo; + int32_t bits = 16; // saturate to 16 bits + int32_t shift = 0; // shift is done automatically + asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); + asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); + asm volatile("pkhbt %0, %1, %2, lsl #8" : "=r" (val) : "r" (lo), "r" (hi)); // pack + return val; + #else + uint32_t result = 0; + float mod_mul = (float)mul / (float)((1<<15)-1); + for (int8_t i = 0; i < 4; i++) { + int16_t ai = val >> (sizeof(int8_t) * 8 * i); + int32_t intermediate = ai * mod_mul; + if (intermediate > CHAR_MAX) { + intermediate = CHAR_MAX; + } else if (intermediate < CHAR_MIN) { + intermediate = CHAR_MIN; + } + result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int16_t) * 8 * i); + } + return result; + #endif } //TODO: static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + // if mul == 0, no need in wasting cycles + if (mul == 0) { + return 0; + } + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + int32_t hi, lo; + asm volatile("umaal %0, %1, %2, %3" : "=r" (lo), "=r" (hi) : "r" (val), "r" (mul)); // unsigned accumulation mult (res=64bit) + asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack return val; - val = __USUB16(val, 0x80008000); - #else - uint32_t result = 0; - for (int8_t i = 0; i < 2; i++) { - int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)) - 0x8000; - } - return result; - #endif + #else + //mp_printf(&mp_plat_print, "mult16signed called:\n\tval: %u\t mul: %u\n", val, mul); + uint32_t result = 0; + float mod_mul = (float)mul / (float)((1<<15)-1); + for (int8_t i = 0; i < 2; i++) { + int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + int32_t intermediate = ai * mod_mul; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } else if (intermediate < SHRT_MIN) { + intermediate = SHRT_MIN; + } + result |= (((uint32_t) intermediate) + 0x8000) << (sizeof(int16_t) * 8 * i); + } + //mp_printf(&mp_plat_print, "\t mod_mul: %f\t result: %u\n", (double)mod_mul, result); + return val; + #endif } static inline uint32_t mult16signed(uint32_t val, int32_t mul) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - int32_t hi, lo; - int32_t bits = 16; // saturate to 16 bits - int32_t shift = 0; // shift is done automatically - asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); - asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); - asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); - asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); - asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack + // if mul == 0, no need in wasting cycles + if (mul == 0) { + return 0; + } + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + int32_t hi, lo; + int32_t bits = 16; // saturate to 16 bits + int32_t shift = 0; // shift is done automatically + asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); + asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); + asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack return val; - #else - uint32_t result = 0; - //TODO: - for (int8_t i = 0; i < 2; i++) { - int16_t ai = val >> (sizeof(int16_t) * 8 * i); - } - return result; - #endif + #else + uint32_t result = 0; + float mod_mul = (float)mul / (float)((1<<15)-1); + for (int8_t i = 0; i < 2; i++) { + int16_t ai = val >> (sizeof(int16_t) * 8 * i); + int32_t intermediate = ai * mod_mul; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } else if (intermediate < SHRT_MIN) { + intermediate = SHRT_MIN; + } + result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); + } + return result; + #endif } audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, @@ -311,19 +376,18 @@ audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, // apply the mixer level if (!self->samples_signed) { - if (self->bits_per_sample == 8) { - sample_value = mult8unsigned(sample_value, voice->level); - } else { - sample_value = mult16unsigned(sample_value, voice->level); - } - } - else{ - if (self->bits_per_sample == 8) { - sample_value = mult8signed(sample_value, voice->level); - } else { - sample_value = mult16signed(sample_value, voice->level); - } - } + if (self->bits_per_sample == 8) { + sample_value = mult8unsigned(sample_value, voice->level); + } else { + sample_value = mult16unsigned(sample_value, voice->level); + } + } else { + if (self->bits_per_sample == 8) { + sample_value = mult8signed(sample_value, voice->level); + } else { + sample_value = mult16signed(sample_value, voice->level); + } + } if (!voices_active) { word_buffer[i] = sample_value; -- cgit v1.2.3 From b3de7efc07365bd4cb3a8c89196dfbc29bcc9c04 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 14 Aug 2019 15:53:58 -0700 Subject: Fix I2CDisplay lifecycle and splash lifecycle. Fixes https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_SSD1306/issues/2 --- py/circuitpy_mpconfig.h | 10 +--------- shared-module/board/__init__.c | 29 ++++++++++++++++++++++++----- shared-module/displayio/Display.c | 19 +++++++++++++++---- shared-module/displayio/__init__.c | 6 ++++-- 4 files changed, 44 insertions(+), 20 deletions(-) (limited to 'shared-module') diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index d88d6538e..1dbca8c61 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -273,13 +273,7 @@ extern const struct _mp_obj_module_t board_module; #define BOARD_SPI (defined(DEFAULT_SPI_BUS_SCK) && defined(DEFAULT_SPI_BUS_MISO) && defined(DEFAULT_SPI_BUS_MOSI)) #define BOARD_UART (defined(DEFAULT_UART_BUS_RX) && defined(DEFAULT_UART_BUS_TX)) -#if BOARD_I2C -#define BOARD_I2C_ROOT_POINTER mp_obj_t shared_i2c_bus; -#else -#define BOARD_I2C_ROOT_POINTER -#endif - -// SPI is always allocated off the heap. +// I2C and SPI are always allocated off the heap. #if BOARD_UART #define BOARD_UART_ROOT_POINTER mp_obj_t shared_uart_bus; @@ -289,7 +283,6 @@ extern const struct _mp_obj_module_t board_module; #else #define BOARD_MODULE -#define BOARD_I2C_ROOT_POINTER #define BOARD_UART_ROOT_POINTER #endif @@ -647,7 +640,6 @@ extern const struct _mp_obj_module_t ustack_module; GAMEPAD_ROOT_POINTERS \ mp_obj_t pew_singleton; \ mp_obj_t terminal_tilegrid_tiles; \ - BOARD_I2C_ROOT_POINTER \ BOARD_UART_ROOT_POINTER \ FLASH_ROOT_POINTERS \ NETWORK_ROOT_POINTERS \ diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 5a1dead78..dd07d7190 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -40,17 +40,25 @@ #endif #if BOARD_I2C +// Statically allocate the I2C object so it can live past the end of the heap and into the next VM. +// That way it can be used by built-in I2CDisplay displays and be accessible through board.I2C(). +STATIC busio_i2c_obj_t i2c_obj; +STATIC mp_obj_t i2c_singleton = NULL; + mp_obj_t common_hal_board_get_i2c(void) { - return MP_STATE_VM(shared_i2c_bus); + return i2c_singleton; } mp_obj_t common_hal_board_create_i2c(void) { - busio_i2c_obj_t *self = m_new_ll_obj(busio_i2c_obj_t); + if (i2c_singleton != NULL) { + return i2c_singleton; + } + busio_i2c_obj_t *self = &i2c_obj; self->base.type = &busio_i2c_type; common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 400000, 0); - MP_STATE_VM(shared_i2c_bus) = MP_OBJ_FROM_PTR(self); - return MP_STATE_VM(shared_i2c_bus); + i2c_singleton = (mp_obj_t)self; + return i2c_singleton; } #endif @@ -101,7 +109,18 @@ mp_obj_t common_hal_board_create_uart(void) { void reset_board_busses(void) { #if BOARD_I2C - MP_STATE_VM(shared_i2c_bus) = NULL; + bool display_using_i2c = false; + #if CIRCUITPY_DISPLAYIO + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (displays[i].i2cdisplay_bus.bus == i2c_singleton) { + display_using_i2c = true; + break; + } + } + #endif + if (!display_using_i2c) { + i2c_singleton = NULL; + } #endif #if BOARD_SPI bool display_using_spi = false; diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 51c6f292a..aa36ee982 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -199,19 +199,26 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { if (root_group == NULL) { - root_group = &circuitpython_splash; + if (!circuitpython_splash.in_group) { + root_group = &circuitpython_splash; + } else if (self->current_group == &circuitpython_splash) { + return false; + } } if (root_group == self->current_group) { return true; } - if (root_group->in_group) { + if (root_group != NULL && root_group->in_group) { return false; } if (self->current_group != NULL) { self->current_group->in_group = false; } - displayio_group_update_transform(root_group, &self->transform); - root_group->in_group = true; + + if (root_group != NULL) { + displayio_group_update_transform(root_group, &self->transform); + root_group->in_group = true; + } self->current_group = root_group; self->full_refresh = true; common_hal_displayio_display_refresh_soon(self); @@ -402,6 +409,10 @@ void displayio_display_update_backlight(displayio_display_obj_t* self) { } void release_display(displayio_display_obj_t* self) { + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 8f6e650a1..3e9c4aa2a 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -163,7 +163,7 @@ void displayio_refresh_displays(void) { void common_hal_displayio_release_displays(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { mp_const_obj_t bus_type = displays[i].fourwire_bus.base.type; - if (bus_type == NULL) { + if (bus_type == NULL || bus_type == &mp_type_NoneType) { continue; } else if (bus_type == &displayio_fourwire_type) { common_hal_displayio_fourwire_deinit(&displays[i].fourwire_bus); @@ -235,12 +235,14 @@ void reset_displays(void) { // Not an active display. continue; } + } + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { // Reset the displayed group. Only the first will get the terminal but // that's ok. displayio_display_obj_t* display = &displays[i].display; display->auto_brightness = true; - common_hal_displayio_display_show(display, &circuitpython_splash); + common_hal_displayio_display_show(display, NULL); } } -- cgit v1.2.3 From 630c92392abef67b0e6f81c98316dea93d3b2376 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 16 Aug 2019 15:18:53 -0400 Subject: address review comments; avoid calling common_hal_bleio_device... routines from shared-bindings --- ports/nrf/common-hal/bleio/Attribute.c | 14 +++++----- ports/nrf/common-hal/bleio/Central.c | 11 +++++++- ports/nrf/common-hal/bleio/Peripheral.c | 11 +++++--- ports/nrf/common-hal/bleio/__init__.c | 4 +-- shared-bindings/bleio/Attribute.c | 14 +++++----- shared-bindings/bleio/Central.c | 45 ++++++++------------------------- shared-bindings/bleio/Central.h | 3 ++- shared-bindings/bleio/Characteristic.c | 4 +-- shared-bindings/bleio/Descriptor.c | 4 +-- shared-bindings/bleio/Peripheral.c | 41 ++++++------------------------ shared-bindings/bleio/Peripheral.h | 3 ++- shared-bindings/bleio/__init__.c | 3 --- shared-module/bleio/Attribute.c | 14 +++++----- shared-module/bleio/Attribute.h | 14 +++++----- 14 files changed, 74 insertions(+), 111 deletions(-) (limited to 'shared-module') diff --git a/ports/nrf/common-hal/bleio/Attribute.c b/ports/nrf/common-hal/bleio/Attribute.c index bffe68254..fd1e7538d 100644 --- a/ports/nrf/common-hal/bleio/Attribute.c +++ b/ports/nrf/common-hal/bleio/Attribute.c @@ -29,31 +29,31 @@ // Convert a bleio security mode to a ble_gap_conn_sec_mode_t setting. void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { switch (security_mode) { - case SEC_MODE_NO_ACCESS: + case SECURITY_MODE_NO_ACCESS: BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); break; - case SEC_MODE_OPEN: + case SECURITY_MODE_OPEN: BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); break; - case SEC_MODE_ENC_NO_MITM: + case SECURITY_MODE_ENC_NO_MITM: BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); break; - case SEC_MODE_ENC_WITH_MITM: + case SECURITY_MODE_ENC_WITH_MITM: BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); break; - case SEC_MODE_LESC_ENC_WITH_MITM: + case SECURITY_MODE_LESC_ENC_WITH_MITM: BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); break; - case SEC_MODE_SIGNED_NO_MITM: + case SECURITY_MODE_SIGNED_NO_MITM: BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); break; - case SEC_MODE_SIGNED_WITH_MITM: + case SECURITY_MODE_SIGNED_WITH_MITM: BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); break; } diff --git a/ports/nrf/common-hal/bleio/Central.c b/ports/nrf/common-hal/bleio/Central.c index c42a2084a..d771437d6 100644 --- a/ports/nrf/common-hal/bleio/Central.c +++ b/ports/nrf/common-hal/bleio/Central.c @@ -34,9 +34,9 @@ #include "nrf_soc.h" #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Central.h" -#include "common-hal/bleio/__init__.h" STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { bleio_central_obj_t *central = (bleio_central_obj_t*)central_in; @@ -131,6 +131,15 @@ bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self) { return self->conn_handle != BLE_CONN_HANDLE_INVALID; } +mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist) { + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); + // Convert to a tuple and then clear the list so the callee will take ownership. + mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_services_list->len, + self->remote_services_list->items); + mp_obj_list_clear(self->remote_services_list); + return services_tuple; +} + mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self) { return self->remote_services_list; } diff --git a/ports/nrf/common-hal/bleio/Peripheral.c b/ports/nrf/common-hal/bleio/Peripheral.c index 640b93180..ed35516fc 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.c +++ b/ports/nrf/common-hal/bleio/Peripheral.c @@ -36,12 +36,12 @@ #include "py/objlist.h" #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Peripheral.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" -#include "common-hal/bleio/Service.h" #define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(300, UNIT_0_625_MS) @@ -303,8 +303,13 @@ void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *self) { sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); } -mp_obj_list_t *common_hal_bleio_peripheral_get_remote_services(bleio_peripheral_obj_t *self) { - return self->remote_services_list; +mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist) { + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); + // Convert to a tuple and then clear the list so the callee will take ownership. + mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_services_list->len, + self->remote_services_list->items); + mp_obj_list_clear(self->remote_services_list); + return services_tuple; } void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *self) { diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c index 2d144f8b5..2e26ac07d 100644 --- a/ports/nrf/common-hal/bleio/__init__.c +++ b/ports/nrf/common-hal/bleio/__init__.c @@ -218,7 +218,7 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_ob // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. common_hal_bleio_characteristic_construct( - characteristic, uuid, props, SEC_MODE_OPEN, SEC_MODE_OPEN, + characteristic, uuid, props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, GATT_MAX_DATA_LENGTH, false, // max_length, fixed_length: values may not matter for gattc mp_obj_new_list(0, NULL)); characteristic->handle = gattc_char->handle_value; @@ -274,7 +274,7 @@ STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_ob // For now, just leave the UUID as NULL. } - common_hal_bleio_descriptor_construct(descriptor, uuid, SEC_MODE_OPEN, SEC_MODE_OPEN, + common_hal_bleio_descriptor_construct(descriptor, uuid, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, GATT_MAX_DATA_LENGTH, false); descriptor->handle = gattc_desc->handle; descriptor->characteristic = m_desc_discovery_characteristic; diff --git a/shared-bindings/bleio/Attribute.c b/shared-bindings/bleio/Attribute.c index cbbc07b9e..2cc9ef6d0 100644 --- a/shared-bindings/bleio/Attribute.c +++ b/shared-bindings/bleio/Attribute.c @@ -76,13 +76,13 @@ STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = { //| //| security_mode: authenticated data signing, without man-in-the-middle protection //| - { MP_ROM_QSTR(MP_QSTR_NO_ACCESS), MP_ROM_INT(SEC_MODE_NO_ACCESS) }, - { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SEC_MODE_OPEN) }, - { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SEC_MODE_ENC_NO_MITM) }, - { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SEC_MODE_ENC_WITH_MITM) }, - { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SEC_MODE_LESC_ENC_WITH_MITM) }, - { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SEC_MODE_SIGNED_NO_MITM) }, - { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SEC_MODE_SIGNED_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_NO_ACCESS), MP_ROM_INT(SECURITY_MODE_NO_ACCESS) }, + { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SECURITY_MODE_OPEN) }, + { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SECURITY_MODE_ENC_NO_MITM) }, + { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_ENC_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_LESC_ENC_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_NO_MITM) }, + { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_WITH_MITM) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_attribute_locals_dict, bleio_attribute_locals_dict_table); diff --git a/shared-bindings/bleio/Central.c b/shared-bindings/bleio/Central.c index 70b270c65..1fc455d8d 100644 --- a/shared-bindings/bleio/Central.c +++ b/shared-bindings/bleio/Central.c @@ -34,7 +34,6 @@ #include "py/objproperty.h" #include "py/objstr.h" #include "py/runtime.h" -#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Address.h" #include "shared-bindings/bleio/Characteristic.h" @@ -66,7 +65,7 @@ //| //| central = bleio.Central() //| central.connect(my_entry.address, 10) # timeout after 10 seconds -//| central.discover_remote_services() +//| remote_services = central.discover_remote_services() //| //| .. class:: Central() @@ -132,15 +131,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_dis //| .. method:: discover_remote_services(service_uuids_whitelist=None) //| Do BLE discovery for all services or for the given service UUIDS, -//| to find their handles and characteristics. -//| The attribute `remote_services` will contain a list of all discovered services. -//| `Central.connected` must be True. +//| to find their handles and characteristics, and return the discovered services. +//| `Peripheral.connected` must be True. //| //| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services //| provided by the peripheral that you want to use. -//| The peripheral may provide more services, but services not listed are ignored. -//| If a service in service_uuids_whitelist is not found during discovery, it will not -//| appear in `remote_services`. +//| The peripheral may provide more services, but services not listed are ignored +//| and will not be returned. //| //| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. //| @@ -149,6 +146,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_dis //| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered //| for use. (This restriction may be lifted in the future.) //| +//| :return: A tuple of services provided by the remote peripheral. +//| STATIC mp_obj_t bleio_central_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -164,10 +163,9 @@ STATIC mp_obj_t bleio_central_discover_remote_services(mp_uint_t n_args, const m mp_raise_ValueError(translate("Not connected")); } - common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), - args[ARG_service_uuids_whitelist].u_obj); - - return mp_const_none; + return MP_OBJ_FROM_PTR(common_hal_bleio_central_discover_remote_services( + MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj)); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_discover_remote_services_obj, 1, bleio_central_discover_remote_services); @@ -189,28 +187,6 @@ const mp_obj_property_t bleio_central_connected_obj = { (mp_obj_t)&mp_const_none_obj }, }; - -//| .. attribute:: remote_services (read-only) -//| -//| A tuple of services provided by the remote peripheral. -//| If the Central is not connected, an empty tuple will be returned. -//| -STATIC mp_obj_t bleio_central_get_remote_services(mp_obj_t self_in) { - bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); - - // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *service_list = common_hal_bleio_central_get_remote_services(self); - return mp_obj_new_tuple(service_list->len, service_list->items); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_get_remote_services_obj, bleio_central_get_remote_services); - -const mp_obj_property_t bleio_central_remote_services_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_central_get_remote_services_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = { // Methods { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) }, @@ -219,7 +195,6 @@ STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_central_connected_obj) }, - { MP_ROM_QSTR(MP_QSTR_remote_services), MP_ROM_PTR(&bleio_central_remote_services_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_central_locals_dict, bleio_central_locals_dict_table); diff --git a/shared-bindings/bleio/Central.h b/shared-bindings/bleio/Central.h index 1d7fb6248..cbc437087 100644 --- a/shared-bindings/bleio/Central.h +++ b/shared-bindings/bleio/Central.h @@ -28,6 +28,7 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H +#include "py/objtuple.h" #include "common-hal/bleio/Central.h" #include "common-hal/bleio/Service.h" @@ -37,6 +38,6 @@ extern void common_hal_bleio_central_construct(bleio_central_obj_t *self); extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout); extern void common_hal_bleio_central_disconnect(bleio_central_obj_t *self); extern bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self); -extern mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self); +extern mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c index c9e0f3757..4894ad114 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -67,8 +67,8 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t static const mp_arg_t allowed_args[] = { { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_properties, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN} }, - { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN} }, + { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, + { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} }, { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_descriptors, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} }, diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c index 95477336e..d7c2a85c7 100644 --- a/shared-bindings/bleio/Descriptor.c +++ b/shared-bindings/bleio/Descriptor.c @@ -62,8 +62,8 @@ STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_ar enum { ARG_uuid, ARG_read_perm, ARG_write_perm, ARG_max_length, ARG_fixed_length }; static const mp_arg_t allowed_args[] = { { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, - { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, + { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN } }, + { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN } }, { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} }, { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, }; diff --git a/shared-bindings/bleio/Peripheral.c b/shared-bindings/bleio/Peripheral.c index b42ca3784..630e6ed36 100644 --- a/shared-bindings/bleio/Peripheral.c +++ b/shared-bindings/bleio/Peripheral.c @@ -35,7 +35,6 @@ #include "py/objstr.h" #include "py/runtime.h" -#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Peripheral.h" @@ -263,15 +262,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripher //| .. method:: discover_remote_services(service_uuids_whitelist=None) //| Do BLE discovery for all services or for the given service UUIDS, -//| to find their handles and characteristics. -//| The attribute `remote_services` will contain a list of all discovered services. +//| to find their handles and characteristics, and return the discovered services. //| `Peripheral.connected` must be True. //| //| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services //| provided by the peripheral that you want to use. -//| The peripheral may provide more services, but services not listed are ignored. -//| If a service in service_uuids_whitelist is not found during discovery, it will not -//| appear in `remote_services`. +//| The peripheral may provide more services, but services not listed are ignored +//| and will not be returned. //| //| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. //| @@ -285,6 +282,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripher //| Examples include a peripheral accessing a central that provides Current Time Service, //| Apple Notification Center Service, or Battery Service. //| +//| :return: A tuple of services provided by the remote central. +//| STATIC mp_obj_t bleio_peripheral_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -300,27 +299,12 @@ STATIC mp_obj_t bleio_peripheral_discover_remote_services(mp_uint_t n_args, cons mp_raise_ValueError(translate("Not connected")); } - common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), - args[ARG_service_uuids_whitelist].u_obj); - - return mp_const_none; + return MP_OBJ_FROM_PTR(common_hal_bleio_peripheral_discover_remote_services( + MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj)); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_discover_remote_services_obj, 1, bleio_peripheral_discover_remote_services); -//| .. attribute:: remote_services (read-only) -//| -//| A tuple of services provided by the remote central. -//| If discovery did not occur, an empty tuple will be returned. -//| -STATIC mp_obj_t bleio_peripheral_get_remote_services(mp_obj_t self_in) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *service_list = common_hal_bleio_peripheral_get_remote_services(self); - return mp_obj_new_tuple(service_list->len, service_list->items); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_remote_services_obj, bleio_peripheral_get_remote_services); - //| .. method:: pair() //| //| Request pairing with connected central. @@ -333,14 +317,6 @@ STATIC mp_obj_t bleio_peripheral_pair(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_pair_obj, bleio_peripheral_pair); -const mp_obj_property_t bleio_peripheral_remote_services_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_peripheral_get_remote_services_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - - STATIC const mp_rom_map_elem_t bleio_peripheral_locals_dict_table[] = { // Methods { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) }, @@ -352,7 +328,6 @@ STATIC const mp_rom_map_elem_t bleio_peripheral_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) }, { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_peripheral_name_obj) }, - { MP_ROM_QSTR(MP_QSTR_remote_services), MP_ROM_PTR(&bleio_peripheral_remote_services_obj) }, { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) }, }; diff --git a/shared-bindings/bleio/Peripheral.h b/shared-bindings/bleio/Peripheral.h index d9b72b2c3..597b65ce2 100644 --- a/shared-bindings/bleio/Peripheral.h +++ b/shared-bindings/bleio/Peripheral.h @@ -28,6 +28,7 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H +#include "py/objtuple.h" #include "common-hal/bleio/Peripheral.h" extern const mp_obj_type_t bleio_peripheral_type; @@ -39,7 +40,7 @@ extern mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *sel extern void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *device, bool connectable, float interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo); extern void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *device); extern void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *device); -extern mp_obj_list_t *common_hal_bleio_peripheral_get_remote_services(bleio_peripheral_obj_t *self); +extern mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist); extern void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *device); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index 05be48ddc..739f461a5 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -94,9 +94,6 @@ STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, - - // constants - { MP_ROM_QSTR(MP_QSTR_SEC), MP_ROM_PTR(&bleio_uuid_type) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); diff --git a/shared-module/bleio/Attribute.c b/shared-module/bleio/Attribute.c index ac854ec6b..2275003c9 100644 --- a/shared-module/bleio/Attribute.c +++ b/shared-module/bleio/Attribute.c @@ -31,13 +31,13 @@ void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode) { switch (security_mode) { - case SEC_MODE_NO_ACCESS: - case SEC_MODE_OPEN: - case SEC_MODE_ENC_NO_MITM: - case SEC_MODE_ENC_WITH_MITM: - case SEC_MODE_LESC_ENC_WITH_MITM: - case SEC_MODE_SIGNED_NO_MITM: - case SEC_MODE_SIGNED_WITH_MITM: + case SECURITY_MODE_NO_ACCESS: + case SECURITY_MODE_OPEN: + case SECURITY_MODE_ENC_NO_MITM: + case SECURITY_MODE_ENC_WITH_MITM: + case SECURITY_MODE_LESC_ENC_WITH_MITM: + case SECURITY_MODE_SIGNED_NO_MITM: + case SECURITY_MODE_SIGNED_WITH_MITM: break; default: mp_raise_ValueError(translate("Invalid security_mode")); diff --git a/shared-module/bleio/Attribute.h b/shared-module/bleio/Attribute.h index 62615f1b5..a498a14a5 100644 --- a/shared-module/bleio/Attribute.h +++ b/shared-module/bleio/Attribute.h @@ -29,13 +29,13 @@ // BLE security modes: 0x typedef enum { - SEC_MODE_NO_ACCESS = 0x00, - SEC_MODE_OPEN = 0x11, - SEC_MODE_ENC_NO_MITM = 0x21, - SEC_MODE_ENC_WITH_MITM = 0x31, - SEC_MODE_LESC_ENC_WITH_MITM = 0x41, - SEC_MODE_SIGNED_NO_MITM = 0x12, - SEC_MODE_SIGNED_WITH_MITM = 0x22, + SECURITY_MODE_NO_ACCESS = 0x00, + SECURITY_MODE_OPEN = 0x11, + SECURITY_MODE_ENC_NO_MITM = 0x21, + SECURITY_MODE_ENC_WITH_MITM = 0x31, + SECURITY_MODE_LESC_ENC_WITH_MITM = 0x41, + SECURITY_MODE_SIGNED_NO_MITM = 0x12, + SECURITY_MODE_SIGNED_WITH_MITM = 0x22, } bleio_attribute_security_mode_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H -- cgit v1.2.3 From e2a4c76a3745c512eb85ca5555ec35e5f7d52769 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 18 Aug 2019 08:44:10 -0400 Subject: make nrf touchio be generic: now available for SAMD51 too --- .../boards/capablerobot_usbhub/mpconfigboard.mk | 2 - ports/atmel-samd/boards/cp32-m4/mpconfigboard.mk | 2 - .../boards/datalore_ip_m4/mpconfigboard.mk | 2 - .../boards/feather_m4_express/mpconfigboard.mk | 2 - .../grandcentral_m4_express/mpconfigboard.mk | 2 - .../boards/itsybitsy_m4_express/mpconfigboard.mk | 2 - .../boards/kicksat-sprite/mpconfigboard.mk | 2 - .../boards/metro_m4_airlift_lite/mpconfigboard.mk | 2 - .../boards/metro_m4_express/mpconfigboard.mk | 2 - .../atmel-samd/boards/mini_sam_m4/mpconfigboard.mk | 2 - ports/atmel-samd/boards/pybadge/mpconfigboard.mk | 2 - .../boards/pybadge_airlift/mpconfigboard.mk | 2 - ports/atmel-samd/boards/pygamer/mpconfigboard.mk | 2 - .../boards/pygamer_advance/mpconfigboard.mk | 2 - ports/atmel-samd/boards/pyportal/mpconfigboard.mk | 3 - .../boards/pyportal_titano/mpconfigboard.mk | 3 - .../boards/robohatmm1_m4/mpconfigboard.mk | 3 - ports/atmel-samd/boards/sam32/mpconfigboard.mk | 3 - .../boards/trellis_m4_express/mpconfigboard.mk | 2 - ports/atmel-samd/common-hal/touchio/TouchIn.c | 7 +- ports/atmel-samd/common-hal/touchio/TouchIn.h | 5 + ports/atmel-samd/mpconfigport.mk | 2 + ports/atmel-samd/supervisor/port.c | 6 +- ports/nrf/common-hal/touchio/TouchIn.c | 116 --------------------- ports/nrf/common-hal/touchio/TouchIn.h | 43 -------- ports/nrf/common-hal/touchio/__init__.c | 1 - py/circuitpy_defns.mk | 35 ++++--- py/circuitpy_mpconfig.mk | 12 ++- shared-bindings/touchio/TouchIn.h | 5 + shared-module/touchio/TouchIn.c | 110 +++++++++++++++++++ shared-module/touchio/TouchIn.h | 44 ++++++++ shared-module/touchio/__init__.c | 1 + 32 files changed, 208 insertions(+), 221 deletions(-) delete mode 100644 ports/nrf/common-hal/touchio/TouchIn.c delete mode 100644 ports/nrf/common-hal/touchio/TouchIn.h delete mode 100644 ports/nrf/common-hal/touchio/__init__.c create mode 100644 shared-module/touchio/TouchIn.c create mode 100644 shared-module/touchio/TouchIn.h create mode 100644 shared-module/touchio/__init__.c (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/capablerobot_usbhub/mpconfigboard.mk b/ports/atmel-samd/boards/capablerobot_usbhub/mpconfigboard.mk index 97c8eb863..f390a8681 100644 --- a/ports/atmel-samd/boards/capablerobot_usbhub/mpconfigboard.mk +++ b/ports/atmel-samd/boards/capablerobot_usbhub/mpconfigboard.mk @@ -14,5 +14,3 @@ LONGINT_IMPL = MPZ # No I2S on SAMD51G CIRCUITPY_AUDIOBUSIO = 0 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/cp32-m4/mpconfigboard.mk b/ports/atmel-samd/boards/cp32-m4/mpconfigboard.mk index 72a191044..86a7719b8 100644 --- a/ports/atmel-samd/boards/cp32-m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/cp32-m4/mpconfigboard.mk @@ -14,5 +14,3 @@ EXTERNAL_FLASH_DEVICES = "W25Q128JV_PM" CIRCUITPY_PS2IO = 1 # No I2S on SAMD51G. CIRCUITPY_AUDIOBUSIO = 0 -# No touch on SAMD51 yet. -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk b/ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk index 794920fe3..aa5f47d40 100644 --- a/ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk @@ -15,5 +15,3 @@ LONGINT_IMPL = MPZ CIRCUITPY_NETWORK = 1 MICROPY_PY_WIZNET5K = 5500 CIRCUITPY_PS2IO = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.mk index 8169345f5..176ebac82 100644 --- a/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m4_express/mpconfigboard.mk @@ -15,5 +15,3 @@ LONGINT_IMPL = MPZ CIRCUITPY_NETWORK = 1 MICROPY_PY_WIZNET5K = 5500 CIRCUITPY_PS2IO = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/grandcentral_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/grandcentral_m4_express/mpconfigboard.mk index 13631a736..423761c3f 100644 --- a/ports/atmel-samd/boards/grandcentral_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/grandcentral_m4_express/mpconfigboard.mk @@ -13,5 +13,3 @@ EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ, GD25Q64C" LONGINT_IMPL = MPZ CIRCUITPY_PS2IO = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.mk index 31bb38e20..f53983ef7 100644 --- a/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/itsybitsy_m4_express/mpconfigboard.mk @@ -15,5 +15,3 @@ LONGINT_IMPL = MPZ CIRCUITPY_PS2IO = 1 # No I2S on SAMD51G CIRCUITPY_AUDIOBUSIO = 0 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk b/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk index 5871cca2a..706e551c5 100644 --- a/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk +++ b/ports/atmel-samd/boards/kicksat-sprite/mpconfigboard.mk @@ -11,8 +11,6 @@ QSPI_FLASH_FILESYSTEM = 0 INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = MPZ -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 # Not needed. CIRCUITPY_AUDIOBUSIO = 0 CIRCUITPY_DISPLAYIO = 0 diff --git a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk index d7d0c1d6e..98d85ba82 100644 --- a/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m4_airlift_lite/mpconfigboard.mk @@ -15,5 +15,3 @@ LONGINT_IMPL = MPZ CIRCUITPY_NETWORK = 1 MICROPY_PY_WIZNET5K = 5500 CIRCUITPY_PS2IO = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.mk index 829bf749f..68b6f6406 100644 --- a/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m4_express/mpconfigboard.mk @@ -15,5 +15,3 @@ LONGINT_IMPL = MPZ CIRCUITPY_NETWORK = 1 MICROPY_PY_WIZNET5K = 5500 CIRCUITPY_PS2IO = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/mini_sam_m4/mpconfigboard.mk b/ports/atmel-samd/boards/mini_sam_m4/mpconfigboard.mk index a8f47dced..b70b9bbb0 100644 --- a/ports/atmel-samd/boards/mini_sam_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/mini_sam_m4/mpconfigboard.mk @@ -15,5 +15,3 @@ LONGINT_IMPL = MPZ CIRCUITPY_PS2IO = 1 # No I2S on SAMD51G CIRCUITPY_AUDIOBUSIO = 0 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/pybadge/mpconfigboard.mk b/ports/atmel-samd/boards/pybadge/mpconfigboard.mk index b8d10387b..7e2cb6439 100644 --- a/ports/atmel-samd/boards/pybadge/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pybadge/mpconfigboard.mk @@ -17,7 +17,5 @@ CIRCUITPY_DISPLAYIO = 1 CIRCUITPY_GAMEPAD = 1 CIRCUITPY_GAMEPADSHIFT = 1 CIRCUITPY_STAGE = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pybadge diff --git a/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.mk b/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.mk index 12683e995..7e77b0fea 100644 --- a/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pybadge_airlift/mpconfigboard.mk @@ -17,7 +17,5 @@ CIRCUITPY_DISPLAYIO = 1 CIRCUITPY_GAMEPAD = 1 CIRCUITPY_GAMEPADSHIFT = 1 CIRCUITPY_STAGE = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pybadge diff --git a/ports/atmel-samd/boards/pygamer/mpconfigboard.mk b/ports/atmel-samd/boards/pygamer/mpconfigboard.mk index 69fb14358..0fce468d9 100644 --- a/ports/atmel-samd/boards/pygamer/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pygamer/mpconfigboard.mk @@ -17,7 +17,5 @@ CIRCUITPY_DISPLAYIO = 1 CIRCUITPY_GAMEPAD = 1 CIRCUITPY_GAMEPADSHIFT = 1 CIRCUITPY_STAGE = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pygamer diff --git a/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.mk b/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.mk index 1bb2c553d..8711738d4 100644 --- a/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pygamer_advance/mpconfigboard.mk @@ -17,7 +17,5 @@ CIRCUITPY_DISPLAYIO = 1 CIRCUITPY_GAMEPAD = 1 CIRCUITPY_GAMEPADSHIFT = 1 CIRCUITPY_STAGE = 1 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pybadge diff --git a/ports/atmel-samd/boards/pyportal/mpconfigboard.mk b/ports/atmel-samd/boards/pyportal/mpconfigboard.mk index 996b17b3b..f763c74fa 100644 --- a/ports/atmel-samd/boards/pyportal/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pyportal/mpconfigboard.mk @@ -11,6 +11,3 @@ QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICE_COUNT = 2 EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ, GD25Q64C" LONGINT_IMPL = MPZ - -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.mk b/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.mk index 0ca438311..58b363779 100644 --- a/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pyportal_titano/mpconfigboard.mk @@ -11,6 +11,3 @@ QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICE_COUNT = 2 EXTERNAL_FLASH_DEVICES = "W25Q64JV_IQ, GD25Q64C" LONGINT_IMPL = MPZ - -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/robohatmm1_m4/mpconfigboard.mk b/ports/atmel-samd/boards/robohatmm1_m4/mpconfigboard.mk index afd15ad0a..f391bf625 100644 --- a/ports/atmel-samd/boards/robohatmm1_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/robohatmm1_m4/mpconfigboard.mk @@ -17,8 +17,6 @@ LONGINT_IMPL = MPZ CIRCUITPY_PS2IO = 1 # No I2S on SAMD51G CIRCUITPY_AUDIOBUSIO = 0 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 # Make room for more stuff CIRCUITPY_DISPLAYIO = 0 CIRCUITPY_FREQUENCYIO = 0 @@ -28,4 +26,3 @@ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel #FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_INA219 #FROZEN_MPY_DIRS += $(TOP)/frozen/RoboticsMasters_CircuitPython_MPU9250 - diff --git a/ports/atmel-samd/boards/sam32/mpconfigboard.mk b/ports/atmel-samd/boards/sam32/mpconfigboard.mk index ca1e11f01..12884a9cc 100644 --- a/ports/atmel-samd/boards/sam32/mpconfigboard.mk +++ b/ports/atmel-samd/boards/sam32/mpconfigboard.mk @@ -9,6 +9,3 @@ CHIP_FAMILY = samd51 INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = MPZ - -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/boards/trellis_m4_express/mpconfigboard.mk b/ports/atmel-samd/boards/trellis_m4_express/mpconfigboard.mk index 6d108e649..f1fb49901 100644 --- a/ports/atmel-samd/boards/trellis_m4_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/trellis_m4_express/mpconfigboard.mk @@ -15,5 +15,3 @@ LONGINT_IMPL = MPZ CIRCUITPY_PS2IO = 1 # No I2S on SAMD51G CIRCUITPY_AUDIOBUSIO = 0 -# No touch on SAMD51 yet -CIRCUITPY_TOUCHIO = 0 diff --git a/ports/atmel-samd/common-hal/touchio/TouchIn.c b/ports/atmel-samd/common-hal/touchio/TouchIn.c index 9fb3a2ea1..0658c1d05 100644 --- a/ports/atmel-samd/common-hal/touchio/TouchIn.c +++ b/ports/atmel-samd/common-hal/touchio/TouchIn.c @@ -34,9 +34,10 @@ #include "shared-bindings/touchio/TouchIn.h" #include "supervisor/shared/translate.h" +// Native touchio only exists for SAMD21 #ifdef SAMD21 + #include "hpl/pm/hpl_pm_base.h" -#endif #include "samd/clocks.h" #include "samd/pins.h" @@ -67,7 +68,6 @@ void common_hal_touchio_touchin_construct(touchio_touchin_obj_t* self, claim_pin(pin); // Turn on the PTC if its not in use. We won't turn it off until reset. - #ifdef SAMD21 if ((( Ptc *) PTC)->CTRLA.bit.ENABLE == 0) { // We run the PTC at 8mhz so divide the 48mhz clock by 6. uint8_t gclk = find_free_gclk(6); @@ -96,7 +96,6 @@ void common_hal_touchio_touchin_construct(touchio_touchin_obj_t* self, // but for touches using fruit or other objects, the difference is much less. self->threshold = get_raw_reading(self) + 100; - #endif } bool common_hal_touchio_touchin_deinited(touchio_touchin_obj_t* self) { @@ -141,3 +140,5 @@ uint16_t common_hal_touchio_touchin_get_threshold(touchio_touchin_obj_t *self) { void common_hal_touchio_touchin_set_threshold(touchio_touchin_obj_t *self, uint16_t new_threshold) { self->threshold = new_threshold; } + +#endif // SAMD21 diff --git a/ports/atmel-samd/common-hal/touchio/TouchIn.h b/ports/atmel-samd/common-hal/touchio/TouchIn.h index ffe8a6c01..85550b8a3 100644 --- a/ports/atmel-samd/common-hal/touchio/TouchIn.h +++ b/ports/atmel-samd/common-hal/touchio/TouchIn.h @@ -27,6 +27,9 @@ #ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_TOUCHIO_TOUCHIN_H #define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_TOUCHIO_TOUCHIN_H +// Native touchio only exists for SAMD21 +#ifdef SAMD21 + #include "common-hal/microcontroller/Pin.h" #include "samd21_ptc_component.h" @@ -42,4 +45,6 @@ typedef struct { void touchin_reset(void); +#endif // SAMD21 + #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_TOUCHIO_TOUCHIN_H diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index 4ddd097f0..af33edb0e 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -18,11 +18,13 @@ endif ifeq ($(CHIP_FAMILY),samd21) # frequencyio not yet verified as working on SAMD21. CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 1 endif # Put samd51-only choices here. ifeq ($(CHIP_FAMILY),samd51) CIRCUITPY_SAMD = 1 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 endif INTERNAL_LIBM = 1 diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 37360deb0..512fd8eb8 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -54,7 +54,11 @@ #include "common-hal/pulseio/PWMOut.h" #include "common-hal/ps2io/Ps2.h" #include "common-hal/rtc/RTC.h" + +#if CIRCUITPY_TOUCHIO_USE_NATIVE #include "common-hal/touchio/TouchIn.h" +#endif + #include "samd/cache.h" #include "samd/clocks.h" #include "samd/events.h" @@ -211,7 +215,7 @@ void reset_port(void) { //pdmin_reset(); #endif -#if CIRCUITPY_TOUCHIO +#if CIRCUITPY_TOUCHIO && CIRCUITPY_TOUCHIO_USE_NATIVE touchin_reset(); #endif eic_reset(); diff --git a/ports/nrf/common-hal/touchio/TouchIn.c b/ports/nrf/common-hal/touchio/TouchIn.c deleted file mode 100644 index ba50b17b0..000000000 --- a/ports/nrf/common-hal/touchio/TouchIn.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries - * Copyright (c) 2018 Nick Moore for Adafruit Industries - * - * 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 -#include - -#include "py/nlr.h" -#include "py/mperrno.h" -#include "py/runtime.h" -#include "py/binary.h" -#include "py/mphal.h" -#include "shared-bindings/touchio/TouchIn.h" -#include "supervisor/shared/translate.h" - -#include "nrf.h" - -// This is a capacitive touch sensing routine using a single digital -// pin. The pin should be connected to the sensing pad, and to ground -// via a 1Mohm or thereabout drain resistor. When a reading is taken, -// the pin's capacitance is charged by setting it to a digital output -// 'high' for a few microseconds, and then it is changed to a high -// impedance input. We measure how long it takes to discharge through -// the resistor (around 50us), using a busy-waiting loop, and average -// over N_SAMPLES cycles to reduce the effects of noise. - -#define N_SAMPLES 10 -#define TIMEOUT_TICKS 10000 - -static uint16_t get_raw_reading(touchio_touchin_obj_t *self) { - - uint16_t ticks = 0; - - for (uint16_t i = 0; i < N_SAMPLES; i++) { - // set pad to digital output high for 10us to charge it - - nrf_gpio_cfg_output(self->pin->number); - nrf_gpio_pin_set(self->pin->number); - mp_hal_delay_us(10); - - // set pad back to an input and take some samples - - nrf_gpio_cfg_input(self->pin->number, NRF_GPIO_PIN_NOPULL); - - while(nrf_gpio_pin_read(self->pin->number)) { - if (ticks >= TIMEOUT_TICKS) return TIMEOUT_TICKS; - ticks++; - } - } - return ticks; -} - -void common_hal_touchio_touchin_construct(touchio_touchin_obj_t* self, - const mcu_pin_obj_t *pin) { - self->pin = pin; - claim_pin(pin); - - self->threshold = get_raw_reading(self) * 1.05 + 100; -} - -bool common_hal_touchio_touchin_deinited(touchio_touchin_obj_t* self) { - return self->pin == NULL; -} - -void common_hal_touchio_touchin_deinit(touchio_touchin_obj_t* self) { - if (common_hal_touchio_touchin_deinited(self)) { - return; - } - - reset_pin_number(self->pin->number); - self->pin = NULL; -} - -void touchin_reset() { -} - -bool common_hal_touchio_touchin_get_value(touchio_touchin_obj_t *self) { - uint16_t reading = get_raw_reading(self); - return reading > self->threshold; -} - -uint16_t common_hal_touchio_touchin_get_raw_value(touchio_touchin_obj_t *self) { - return get_raw_reading(self); -} - -uint16_t common_hal_touchio_touchin_get_threshold(touchio_touchin_obj_t *self) { - return self->threshold; -} - -void common_hal_touchio_touchin_set_threshold(touchio_touchin_obj_t *self, - uint16_t new_threshold) { - self->threshold = new_threshold; -} diff --git a/ports/nrf/common-hal/touchio/TouchIn.h b/ports/nrf/common-hal/touchio/TouchIn.h deleted file mode 100644 index 121580eac..000000000 --- a/ports/nrf/common-hal/touchio/TouchIn.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Scott Shawcroft - * Copyright (c) 2018 Nick Moore for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_TOUCHIO_TOUCHIN_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_TOUCHIO_TOUCHIN_H - -#include "common-hal/microcontroller/Pin.h" - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - const mcu_pin_obj_t *pin; - uint16_t threshold; -} touchio_touchin_obj_t; - -void touchin_reset(void); - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_TOUCHIO_TOUCHIN_H diff --git a/ports/nrf/common-hal/touchio/__init__.c b/ports/nrf/common-hal/touchio/__init__.c deleted file mode 100644 index d2290447c..000000000 --- a/ports/nrf/common-hal/touchio/__init__.c +++ /dev/null @@ -1 +0,0 @@ -// No touchio module functions. diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index d4733e338..95939de2b 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -217,9 +217,8 @@ ifeq ($(CIRCUITPY_PEW),1) SRC_PATTERNS += _pew/% endif -# All possible sources are listed here, and are filtered by SRC_PATTERNS. -SRC_COMMON_HAL = \ -$(filter $(SRC_PATTERNS), \ +# All possible sources are listed here, and are filtered by SRC_PATTERNS in SRC_COMMON_HAL +SRC_COMMON_HAL_ALL = \ analogio/AnalogIn.c \ analogio/AnalogOut.c \ analogio/__init__.c \ @@ -272,10 +271,9 @@ $(filter $(SRC_PATTERNS), \ rtc/__init__.c \ supervisor/Runtime.c \ supervisor/__init__.c \ - time/__init__.c \ - touchio/TouchIn.c \ - touchio/__init__.c \ -) + time/__init__.c + +SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL)) # These don't have corresponding files in each port but are still located in # shared-bindings to make it clear what the contents of the modules are. @@ -298,9 +296,7 @@ SRC_BINDINGS_ENUMS += \ help.c \ util.c -# All possible sources are listed here, and are filtered by SRC_PATTERNS. -SRC_SHARED_MODULE = \ -$(filter $(SRC_PATTERNS), \ +SRC_SHARED_MODULE_ALL = \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ _stage/Layer.c \ @@ -349,8 +345,23 @@ $(filter $(SRC_PATTERNS), \ uheap/__init__.c \ ustack/__init__.c \ _pew/__init__.c \ - _pew/PewPew.c \ -) + _pew/PewPew.c + +# All possible sources are listed here, and are filtered by SRC_PATTERNS. +SRC_SHARED_MODULE = $(filter $(SRC_PATTERNS), $(SRC_SHARED_MODULE_ALL)) + +# Use the native touchio if requested. This flag is set conditionally in, say, mpconfigport.h. +# The presence of common-hal/touchio/* # does not imply it's available for all chips in a port, +# so there is an explicit flag. For example, SAMD21 touchio is native, but SAMD51 is not. +ifeq ($(CIRCUITPY_TOUCHIO_USE_NATIVE),1) +SRC_COMMON_HAL_ALL += \ + touchio/TouchIn.c \ + touchio/__init__.c +else +SRC_SHARED_MODULE_ALL += \ + touchio/TouchIn.c \ + touchio/__init__.c +endif ifeq ($(INTERNAL_LIBM),1) SRC_LIBM = \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index a408cd7ac..7469fbf3f 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -45,10 +45,10 @@ endif # Use for for early stage or highly restricted ports ifndef CIRCUITPY_DEFAULT_BUILD ifeq ($(CIRCUITPY_MINIMAL_BUILD),1) - CIRCUITPY_FULL_BUILD = 0 - CIRCUITPY_DEFAULT_BUILD = 0 + CIRCUITPY_FULL_BUILD = 0 + CIRCUITPY_DEFAULT_BUILD = 0 else - CIRCUITPY_DEFAULT_BUILD = 1 + CIRCUITPY_DEFAULT_BUILD = 1 endif endif @@ -235,6 +235,12 @@ CIRCUITPY_TIME = $(CIRCUITPY_DEFAULT_BUILD) endif CFLAGS += -DCIRCUITPY_TIME=$(CIRCUITPY_TIME) +# touchio might be native or generic. See circuitpy_defns.mk. +ifndef CIRCUITPY_TOUCHIO_USE_NATIVE +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 +endif +CFLAGS += -DCIRCUITPY_TOUCHIO_USE_NATIVE=$(CIRCUITPY_TOUCHIO_USE_NATIVE) + ifndef CIRCUITPY_TOUCHIO CIRCUITPY_TOUCHIO = $(CIRCUITPY_DEFAULT_BUILD) endif diff --git a/shared-bindings/touchio/TouchIn.h b/shared-bindings/touchio/TouchIn.h index 2e5c51607..e04e79c0b 100644 --- a/shared-bindings/touchio/TouchIn.h +++ b/shared-bindings/touchio/TouchIn.h @@ -28,7 +28,12 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_TOUCHIO_TOUCHIN_H #include "common-hal/microcontroller/Pin.h" + +#if CIRCUITPY_TOUCHIO_USE_NATIVE #include "common-hal/touchio/TouchIn.h" +#else +#include "shared-module/touchio/TouchIn.h" +#endif extern const mp_obj_type_t touchio_touchin_type; diff --git a/shared-module/touchio/TouchIn.c b/shared-module/touchio/TouchIn.c new file mode 100644 index 000000000..056556c90 --- /dev/null +++ b/shared-module/touchio/TouchIn.c @@ -0,0 +1,110 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2018 Nick Moore for Adafruit Industries + * + * 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 +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "shared-bindings/touchio/TouchIn.h" + +// This is a capacitive touch sensing routine using a single digital +// pin. The pin should be connected to the sensing pad, and to ground +// via a 1Mohm or thereabout drain resistor. When a reading is taken, +// the pin's capacitance is charged by setting it to a digital output +// 'high' for a few microseconds, and then it is changed to a high +// impedance input. We measure how long it takes to discharge through +// the resistor (around 50us), using a busy-waiting loop, and average +// over N_SAMPLES cycles to reduce the effects of noise. + +#define N_SAMPLES 10 +#define TIMEOUT_TICKS 10000 + +static uint16_t get_raw_reading(touchio_touchin_obj_t *self) { + + uint16_t ticks = 0; + + for (uint16_t i = 0; i < N_SAMPLES; i++) { + // set pad to digital output high for 10us to charge it + + common_hal_digitalio_digitalinout_switch_to_output(self->digitalinout, true, DRIVE_MODE_PUSH_PULL); + mp_hal_delay_us(10); + + // set pad back to an input and take some samples + + common_hal_digitalio_digitalinout_switch_to_input(self->digitalinout, PULL_NONE); + + while(common_hal_digitalio_digitalinout_get_value(self->digitalinout)) { + if (ticks >= TIMEOUT_TICKS) return TIMEOUT_TICKS; + ticks++; + } + } + return ticks; +} + +void common_hal_touchio_touchin_construct(touchio_touchin_obj_t* self, const mcu_pin_obj_t *pin) { + self->digitalinout = m_new_obj(digitalio_digitalinout_obj_t); + self->digitalinout->base.type = &digitalio_digitalinout_type; + + common_hal_digitalio_digitalinout_construct(self->digitalinout, pin); + + self->threshold = get_raw_reading(self) * 1.05 + 100; +} + +bool common_hal_touchio_touchin_deinited(touchio_touchin_obj_t* self) { + return self->digitalinout == MP_OBJ_NULL; +} + +void common_hal_touchio_touchin_deinit(touchio_touchin_obj_t* self) { + if (common_hal_touchio_touchin_deinited(self)) { + return; + } + + common_hal_digitalio_digitalinout_deinit(self->digitalinout); + self->digitalinout = MP_OBJ_NULL; +} + +void touchin_reset() { +} + +bool common_hal_touchio_touchin_get_value(touchio_touchin_obj_t *self) { + uint16_t reading = get_raw_reading(self); + return reading > self->threshold; +} + +uint16_t common_hal_touchio_touchin_get_raw_value(touchio_touchin_obj_t *self) { + return get_raw_reading(self); +} + +uint16_t common_hal_touchio_touchin_get_threshold(touchio_touchin_obj_t *self) { + return self->threshold; +} + +void common_hal_touchio_touchin_set_threshold(touchio_touchin_obj_t *self, + uint16_t new_threshold) { + self->threshold = new_threshold; +} diff --git a/shared-module/touchio/TouchIn.h b/shared-module/touchio/TouchIn.h new file mode 100644 index 000000000..8ff6fda8f --- /dev/null +++ b/shared-module/touchio/TouchIn.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * Copyright (c) 2018 Nick Moore for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_TOUCHIO_TOUCHIN_H +#define MICROPY_INCLUDED_SHARED_MODULE_TOUCHIO_TOUCHIN_H + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + digitalio_digitalinout_obj_t *digitalinout; + uint16_t threshold; +} touchio_touchin_obj_t; + +void touchin_reset(void); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_TOUCHIO_TOUCHIN_H diff --git a/shared-module/touchio/__init__.c b/shared-module/touchio/__init__.c new file mode 100644 index 000000000..d2290447c --- /dev/null +++ b/shared-module/touchio/__init__.c @@ -0,0 +1 @@ +// No touchio module functions. -- cgit v1.2.3 From 17190ae63e8a5fb43c99ca7f1f91bf684bdbc16e Mon Sep 17 00:00:00 2001 From: sommersoft Date: Mon, 19 Aug 2019 21:20:52 -0500 Subject: abandon incomplete mixer asm math functions --- shared-module/audiocore/Mixer.c | 51 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) (limited to 'shared-module') diff --git a/shared-module/audiocore/Mixer.c b/shared-module/audiocore/Mixer.c index 8dd9c6522..c372d68d0 100644 --- a/shared-module/audiocore/Mixer.c +++ b/shared-module/audiocore/Mixer.c @@ -4,6 +4,8 @@ * The MIT License (MIT) * * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * 2018 DeanM for Adafruit Industries + * 2019 Michael Schroeder * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -105,7 +107,7 @@ uint32_t add8signed(uint32_t a, uint32_t b) { if (intermediate > CHAR_MAX) { intermediate = CHAR_MAX; } else if (intermediate < CHAR_MIN) { - //intermediate = CHAR_MIN; + intermediate = CHAR_MIN; } result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int8_t) * 8 * i); } @@ -114,13 +116,13 @@ uint32_t add8signed(uint32_t a, uint32_t b) { } uint32_t add8unsigned(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) // Subtract out the DC offset, add and then shift back. a = __USUB8(a, 0x80808080); b = __USUB8(b, 0x80808080); uint32_t sum = __QADD8(a, b); return __UADD8(sum, 0x80808080); - #else + #else*/ uint32_t result = 0; for (int8_t i = 0; i < 4; i++) { uint8_t ai = (a >> (sizeof(uint8_t) * 8 * i)); @@ -132,13 +134,13 @@ uint32_t add8unsigned(uint32_t a, uint32_t b) { result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i); } return result; - #endif + //#endif } uint32_t add16signed(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) return __QADD16(a, b); - #else + #else*/ uint32_t result = 0; for (int8_t i = 0; i < 2; i++) { int16_t ai = a >> (sizeof(int16_t) * 8 * i); @@ -152,7 +154,7 @@ uint32_t add16signed(uint32_t a, uint32_t b) { result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); } return result; - #endif + //#endif } uint32_t add16unsigned(uint32_t a, uint32_t b) { @@ -183,17 +185,9 @@ static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { if (mul == 0) { return 0; } - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - int32_t hi, lo; - int32_t bits = 16; // saturate to 16 bits - int32_t shift = 0; // shift is done automatically - asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); - asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); - asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); - asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); - asm volatile("pkhbt %0, %1, %2, lsl #8" : "=r" (val) : "r" (lo), "r" (hi)); // pack + /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) return val; - #else + #else*/ uint32_t result = 0; float mod_mul = (float) mul / (float) ((1<<15)-1); for (int8_t i = 0; i < 4; i++) { @@ -206,7 +200,7 @@ static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { } return result; - #endif + //#endif } //TODO: @@ -215,17 +209,11 @@ static inline uint32_t mult8signed(uint32_t val, int32_t mul) { if (mul == 0) { return 0; } + /* #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - int32_t hi, lo; - int32_t bits = 16; // saturate to 16 bits - int32_t shift = 0; // shift is done automatically - asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); - asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); - asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); - asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); - asm volatile("pkhbt %0, %1, %2, lsl #8" : "=r" (val) : "r" (lo), "r" (hi)); // pack return val; #else + */ uint32_t result = 0; float mod_mul = (float)mul / (float)((1<<15)-1); for (int8_t i = 0; i < 4; i++) { @@ -239,7 +227,7 @@ static inline uint32_t mult8signed(uint32_t val, int32_t mul) { result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int16_t) * 8 * i); } return result; - #endif + //#endif } //TODO: @@ -248,13 +236,11 @@ static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) { if (mul == 0) { return 0; } + /* #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - int32_t hi, lo; - asm volatile("umaal %0, %1, %2, %3" : "=r" (lo), "=r" (hi) : "r" (val), "r" (mul)); // unsigned accumulation mult (res=64bit) - asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack return val; #else - //mp_printf(&mp_plat_print, "mult16signed called:\n\tval: %u\t mul: %u\n", val, mul); + */ uint32_t result = 0; float mod_mul = (float)mul / (float)((1<<15)-1); for (int8_t i = 0; i < 2; i++) { @@ -267,9 +253,8 @@ static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) { } result |= (((uint32_t) intermediate) + 0x8000) << (sizeof(int16_t) * 8 * i); } - //mp_printf(&mp_plat_print, "\t mod_mul: %f\t result: %u\n", (double)mod_mul, result); return val; - #endif + //#endif } static inline uint32_t mult16signed(uint32_t val, int32_t mul) { -- cgit v1.2.3 From cccbbd956dbc976a4c059f11dfa1410341a51dc1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 19 Aug 2019 23:40:34 -0400 Subject: Detect lack of pulldown; check for pin in use --- shared-bindings/touchio/TouchIn.c | 3 ++- shared-module/touchio/TouchIn.c | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/touchio/TouchIn.c b/shared-bindings/touchio/TouchIn.c index 78fceef41..33d369c74 100644 --- a/shared-bindings/touchio/TouchIn.c +++ b/shared-bindings/touchio/TouchIn.c @@ -68,10 +68,11 @@ STATIC mp_obj_t touchio_touchin_make_new(const mp_obj_type_t *type, // 1st argument is the pin mp_obj_t pin_obj = args[0]; assert_pin(pin_obj, false); + const mcu_pin_obj_t *pin = MP_OBJ_TO_PTR(pin_obj); + assert_pin_free(pin); touchio_touchin_obj_t *self = m_new_obj(touchio_touchin_obj_t); self->base.type = &touchio_touchin_type; - const mcu_pin_obj_t *pin = MP_OBJ_TO_PTR(pin_obj); common_hal_touchio_touchin_construct(self, pin); return (mp_obj_t) self; diff --git a/shared-module/touchio/TouchIn.c b/shared-module/touchio/TouchIn.c index 056556c90..88d12b8b8 100644 --- a/shared-module/touchio/TouchIn.c +++ b/shared-module/touchio/TouchIn.c @@ -67,12 +67,17 @@ static uint16_t get_raw_reading(touchio_touchin_obj_t *self) { } void common_hal_touchio_touchin_construct(touchio_touchin_obj_t* self, const mcu_pin_obj_t *pin) { + claim_pin(pin); self->digitalinout = m_new_obj(digitalio_digitalinout_obj_t); self->digitalinout->base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(self->digitalinout, pin); - self->threshold = get_raw_reading(self) * 1.05 + 100; + uint16_t raw_reading = get_raw_reading(self); + if (raw_reading == TIMEOUT_TICKS) { + mp_raise_ValueError(translate("No pulldown on pin; 1Mohm recommended")); + } + self->threshold = raw_reading * 1.05 + 100; } bool common_hal_touchio_touchin_deinited(touchio_touchin_obj_t* self) { -- cgit v1.2.3 From 70680d5b22aa6cb797ccf26645d553a4c72b5100 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 2 Aug 2019 16:17:38 -0700 Subject: EPaper displays work mostly. --- .../atmel-samd/common-hal/displayio/ParallelBus.c | 19 +- py/circuitpy_defns.mk | 1 + shared-bindings/displayio/EPaperDisplay.c | 331 +++++-------- shared-bindings/displayio/EPaperDisplay.h | 53 +- shared-bindings/displayio/FourWire.c | 26 +- shared-bindings/displayio/FourWire.h | 5 +- shared-bindings/displayio/I2CDisplay.c | 2 +- shared-bindings/displayio/I2CDisplay.h | 5 +- shared-bindings/displayio/ParallelBus.c | 4 +- shared-bindings/displayio/ParallelBus.h | 5 +- shared-bindings/displayio/__init__.c | 3 + shared-module/displayio/ColorConverter.c | 90 ++++ shared-module/displayio/ColorConverter.h | 3 + shared-module/displayio/Display.c | 30 +- shared-module/displayio/Display.h | 2 +- shared-module/displayio/EPaperDisplay.c | 531 +++++++++++++++++++++ shared-module/displayio/EPaperDisplay.h | 92 ++++ shared-module/displayio/FourWire.c | 27 +- shared-module/displayio/Group.c | 3 + shared-module/displayio/I2CDisplay.c | 23 +- shared-module/displayio/OnDiskBitmap.c | 49 +- shared-module/displayio/Palette.c | 18 +- shared-module/displayio/Palette.h | 8 +- shared-module/displayio/TileGrid.c | 1 + shared-module/displayio/__init__.c | 91 +++- shared-module/displayio/__init__.h | 6 +- supervisor/shared/display.c | 24 +- tools/gen_display_resources.py | 6 +- 28 files changed, 1123 insertions(+), 335 deletions(-) create mode 100644 shared-module/displayio/EPaperDisplay.c create mode 100644 shared-module/displayio/EPaperDisplay.h (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/displayio/ParallelBus.c b/ports/atmel-samd/common-hal/displayio/ParallelBus.c index c370f7e52..a43d20511 100644 --- a/ports/atmel-samd/common-hal/displayio/ParallelBus.c +++ b/ports/atmel-samd/common-hal/displayio/ParallelBus.c @@ -84,10 +84,7 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); - - common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_mcu_delay_us(4); - common_hal_digitalio_digitalinout_set_value(&self->reset, true); + common_hal_displayio_parallelbus_reset(self); } never_reset_pin_number(command->number); @@ -111,13 +108,25 @@ void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self) reset_pin_number(self->reset.pin->number); } +void common_hal_displayio_parallelbus_reset(mp_obj_t obj) { + displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); + + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_mcu_delay_us(4); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); +} + +bool common_hal_displayio_parallelbus_bus_free(mp_obj_t obj) { + return true; +} + bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); return true; } -void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->command, !command); uint32_t* clear_write = (uint32_t*) &self->write_group->OUTCLR.reg; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 95939de2b..d0f0cf7dc 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -320,6 +320,7 @@ SRC_SHARED_MODULE_ALL = \ displayio/Bitmap.c \ displayio/ColorConverter.c \ displayio/Display.c \ + displayio/EPaperDisplay.c \ displayio/FourWire.c \ displayio/Group.c \ displayio/I2CDisplay.c \ diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index d88b4c818..d13d07e4a 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "shared-bindings/displayio/Display.h" +#include "shared-bindings/displayio/EPaperDisplay.h" #include @@ -41,147 +41,143 @@ //| .. currentmodule:: displayio //| -//| :class:`Display` -- Manage updating a display over a display bus +//| :class:`EPaperDisplay` -- Manage updating an epaper display over a display bus //| ========================================================================== //| -//| This initializes a display and connects it into CircuitPython. Unlike other -//| objects in CircuitPython, Display objects live until `displayio.release_displays()` +//| This initializes an epaper display and connects it into CircuitPython. Unlike other +//| objects in CircuitPython, EPaperDisplay objects live until `displayio.release_displays()` //| is called. This is done so that CircuitPython can use the display itself. //| //| Most people should not use this class directly. Use a specific display driver instead that will -//| contain the initialization sequence at minimum. +//| contain the startup and shutdown sequences at minimum. //| -//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) +//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, refresh_display_command, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) //| -//| Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). +//| Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| -//| The ``init_sequence`` is bitpacked to minimize the ram impact. Every command begins with a -//| command byte followed by a byte to determine the parameter count and if a delay is need after. -//| When the top bit of the second byte is 1, the next byte will be the delay time in milliseconds. -//| The remaining 7 bits are the parameter count excluding any delay byte. The third through final -//| bytes are the remaining command parameters. The next byte will begin a new command definition. -//| Here is a portion of ILI9341 init code: -//| -//| .. code-block:: python -//| -//| init_sequence = (b"\xe1\x0f\x00\x0E\x14\x03\x11\x07\x31\xC1\x48\x08\x0F\x0C\x31\x36\x0F" # Set Gamma -//| b"\x11\x80\x78"# Exit Sleep then delay 0x78 (120ms) -//| b"\x29\x80\x78"# Display on then delay 0x78 (120ms) -//| ) -//| display = displayio.Display(display_bus, init_sequence, width=320, height=240) -//| -//| The first command is 0xe1 with 15 (0xf) parameters following. The second and third are 0x11 and -//| 0x29 respectively with delays (0x80) of 120ms (0x78) and no parameters. Multiple byte literals -//| (b"") are merged together on load. The parens are needed to allow byte literals on subsequent -//| lines. -//| -//| The initialization sequence should always leave the display memory access inline with the scan -//| of the display to minimize tearing artifacts. +//| The ``start_sequence`` and ``stop_sequence`` bitpacked to minimize the ram impact. Every +//| command begins with a command byte followed by a byte to determine the parameter count and if +//| a delay is need after. When the top bit of the second byte is 1, the next byte will be the +//| delay time in milliseconds. The remaining 7 bits are the parameter count excluding any delay +//| byte. The third through final bytes are the remaining command parameters. The next byte will +//| begin a new command definition. //| //| :param display_bus: The bus that the display is connected to //| :type display_bus: displayio.FourWire or displayio.ParallelBus -//| :param buffer init_sequence: Byte-packed initialization sequence. +//| :param buffer start_sequence: Byte-packed initialization sequence. +//| :param buffer stop_sequence: Byte-packed initialization sequence. //| :param int width: Width in pixels //| :param int height: Height in pixels +//| :param int ram_width: RAM width in pixels +//| :param int ram_height: RAM height in pixels //| :param int colstart: The index if the first visible column //| :param int rowstart: The index if the first visible row //| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270) -//| :param int color_depth: The number of bits of color per pixel transmitted. (Some displays -//| support 18 bit but 16 is easier to transmit. The last bit is extrapolated.) -//| :param bool grayscale: True if the display only shows a single color. -//| :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column. -//| :param int set_column_command: Command used to set the start and end columns to update -//| :param int set_row_command: Command used so set the start and end rows to update -//| :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set. -//| :param int set_vertical_scroll: Command used to set the first row to show -//| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight -//| :param int brightness_command: Command to set display brightness. Usually available in OLED controllers. -//| :param bool brightness: Initial display brightness. This value is ignored if auto_brightness is True. -//| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. -//| :param bool single_byte_bounds: Display column and row commands use single bytes -//| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. +//| :param int set_column_window_command: Command used to set the start and end columns to update +//| :param int set_row_window_command: Command used so set the start and end rows to update +//| :param int set_current_column_command: Command used to set the current column location +//| :param int set_current_row_command: Command used to set the current row location +//| :param int write_black_ram_command: Command used to write pixels values into the update region +//| :param bool black_bits_inverted: True if 0 bits are used to show black pixels. Otherwise, 1 means to show black. +//| :param int write_color_ram_command: Command used to write pixels values into the update region +//| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color. +//| :param int third_color: Color of third ePaper color in RGB888. +//| :param int refresh_display_command: Command used to start a display refresh +//| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy +//| :param bool busy_state: State of the busy pin when the display is busy +//| :param int seconds_per_frame: Minimum number of seconds between screen refreshes +//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte //| -STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; +STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_third_color, ARG_refresh_display_command, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_stop_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, + { MP_QSTR_ram_width, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, + { MP_QSTR_ram_height, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED, }, { MP_QSTR_colstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_rowstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, - { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, - { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_pixels_in_byte_share_row, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, - { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} }, - { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} }, - { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, - { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} }, - { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, - { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} }, - { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, - { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_data_as_commands, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_set_column_window_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} }, + { MP_QSTR_set_row_window_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} }, + { MP_QSTR_set_current_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} }, + { MP_QSTR_set_current_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_COMMAND} }, + { MP_QSTR_write_black_ram_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_black_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_write_color_ram_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_third_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, + { MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_seconds_per_frame, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} }, + { MP_QSTR_always_toggle_chip_select, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t display_bus = args[ARG_display_bus].u_obj; - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_init_sequence].u_obj, &bufinfo, MP_BUFFER_READ); + mp_buffer_info_t start_bufinfo; + mp_get_buffer_raise(args[ARG_start_sequence].u_obj, &start_bufinfo, MP_BUFFER_READ); + mp_buffer_info_t stop_bufinfo; + mp_get_buffer_raise(args[ARG_stop_sequence].u_obj, &stop_bufinfo, MP_BUFFER_READ); - mp_obj_t backlight_pin_obj = args[ARG_backlight_pin].u_obj; - assert_pin(backlight_pin_obj, true); - const mcu_pin_obj_t* backlight_pin = NULL; - if (backlight_pin_obj != NULL && backlight_pin_obj != mp_const_none) { - backlight_pin = MP_OBJ_TO_PTR(backlight_pin_obj); - assert_pin_free(backlight_pin); - } - mp_float_t brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + mp_obj_t busy_pin_obj = args[ARG_busy_pin].u_obj; + assert_pin(busy_pin_obj, true); + const mcu_pin_obj_t* busy_pin = NULL; + if (busy_pin_obj != NULL && busy_pin_obj != mp_const_none) { + busy_pin = MP_OBJ_TO_PTR(busy_pin_obj); + assert_pin_free(busy_pin); + } mp_int_t rotation = args[ARG_rotation].u_int; if (rotation % 90 != 0) { mp_raise_ValueError(translate("Display rotation must be in 90 degree increments")); } - displayio_display_obj_t *self = NULL; + displayio_epaperdisplay_obj_t *self = NULL; for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display.base.type == NULL || displays[i].display.base.type == &mp_type_NoneType) { - self = &displays[i].display; + self = &displays[i].epaper_display; break; } } if (self == NULL) { mp_raise_RuntimeError(translate("Too many displays")); } - self->base.type = &displayio_display_type; - common_hal_displayio_display_construct( + + mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj); + + mp_int_t write_color_ram_command = NO_COMMAND; + mp_int_t third_color = args[ARG_third_color].u_int; + if (args[ARG_write_color_ram_command].u_obj != mp_const_none) { + write_color_ram_command = mp_obj_get_int(args[ARG_write_color_ram_command].u_obj); + } + + self->base.type = &displayio_epaperdisplay_type; + common_hal_displayio_epaperdisplay_construct( self, - display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, - args[ARG_color_depth].u_int, args[ARG_grayscale].u_bool, args[ARG_pixels_in_byte_share_row].u_bool, - args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int, - args[ARG_write_ram_command].u_int, - args[ARG_set_vertical_scroll].u_int, - bufinfo.buf, bufinfo.len, - MP_OBJ_TO_PTR(backlight_pin), - args[ARG_brightness_command].u_int, - brightness, - args[ARG_auto_brightness].u_bool, - args[ARG_single_byte_bounds].u_bool, - args[ARG_data_as_commands].u_bool + display_bus, + start_bufinfo.buf, start_bufinfo.len, stop_bufinfo.buf, stop_bufinfo.len, + args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, + args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int, + args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int, + args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, third_color, args[ARG_refresh_display_command].u_int, + busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool ); return self; } // Helper to ensure we have the native super class instead of a subclass. -static displayio_display_obj_t* native_display(mp_obj_t display_obj) { - mp_obj_t native_display = mp_instance_cast_to_native_base(display_obj, &displayio_display_type); +static displayio_epaperdisplay_obj_t* native_display(mp_obj_t display_obj) { + mp_obj_t native_display = mp_instance_cast_to_native_base(display_obj, &displayio_epaperdisplay_type); mp_obj_assert_native_inited(native_display); return MP_OBJ_TO_PTR(native_display); } @@ -192,139 +188,75 @@ static displayio_display_obj_t* native_display(mp_obj_t display_obj) { //| CircuitPython terminal will be shown. //| //| :param Group group: The group to show. -STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) { - displayio_display_obj_t *self = native_display(self_in); +STATIC mp_obj_t displayio_epaperdisplay_obj_show(mp_obj_t self_in, mp_obj_t group_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); displayio_group_t* group = NULL; if (group_in != mp_const_none) { group = MP_OBJ_TO_PTR(native_group(group_in)); } - common_hal_displayio_display_show(self, group); + bool ok = common_hal_displayio_epaperdisplay_show(self, group); + if (!ok) { + mp_raise_ValueError(translate("Group already used")); + } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); +MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_show_obj, displayio_epaperdisplay_obj_show); //| .. method:: refresh_soon() //| //| Queues up a display refresh that happens in the background. //| -STATIC mp_obj_t displayio_display_obj_refresh_soon(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - common_hal_displayio_display_refresh_soon(self); +STATIC mp_obj_t displayio_epaperdisplay_obj_refresh_soon(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + common_hal_displayio_epaperdisplay_refresh_soon(self); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_refresh_soon_obj, displayio_display_obj_refresh_soon); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_soon_obj, displayio_epaperdisplay_obj_refresh_soon); //| .. method:: wait_for_frame() //| //| Waits until the next frame has been transmitted to the display unless the wait count is //| behind the rendered frames. In that case, this will return immediately with the wait count. //| -STATIC mp_obj_t displayio_display_obj_wait_for_frame(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_wait_for_frame(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_wait_for_frame_obj, displayio_display_obj_wait_for_frame); - -//| .. attribute:: brightness -//| -//| The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When -//| `auto_brightness` is True, the value of `brightness` will change automatically. -//| If `brightness` is set, `auto_brightness` will be disabled and will be set to False. -//| -STATIC mp_obj_t displayio_display_obj_get_brightness(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - mp_float_t brightness = common_hal_displayio_display_get_brightness(self); - if (brightness < 0) { - mp_raise_RuntimeError(translate("Brightness not adjustable")); - } - return mp_obj_new_float(brightness); +STATIC mp_obj_t displayio_epaperdisplay_obj_wait_for_frame(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_wait_for_frame(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_brightness_obj, displayio_display_obj_get_brightness); - -STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) { - displayio_display_obj_t *self = native_display(self_in); - common_hal_displayio_display_set_auto_brightness(self, false); - mp_float_t brightness = mp_obj_get_float(brightness_obj); - if (brightness < 0 || brightness > 1.0) { - mp_raise_ValueError(translate("Brightness must be 0-1.0")); - } - bool ok = common_hal_displayio_display_set_brightness(self, brightness); - if (!ok) { - mp_raise_RuntimeError(translate("Brightness not adjustable")); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_brightness_obj, displayio_display_obj_set_brightness); - -const mp_obj_property_t displayio_display_brightness_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_brightness_obj, - (mp_obj_t)&displayio_display_set_brightness_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: auto_brightness -//| -//| True when the display brightness is adjusted automatically, based on an ambient -//| light sensor or other method. Note that some displays may have this set to True by default, -//| but not actually implement automatic brightness adjustment. `auto_brightness` is set to False -//| if `brightness` is set manually. -//| -STATIC mp_obj_t displayio_display_obj_get_auto_brightness(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return mp_obj_new_bool(common_hal_displayio_display_get_auto_brightness(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_brightness_obj, displayio_display_obj_get_auto_brightness); - -STATIC mp_obj_t displayio_display_obj_set_auto_brightness(mp_obj_t self_in, mp_obj_t auto_brightness) { - displayio_display_obj_t *self = native_display(self_in); - - common_hal_displayio_display_set_auto_brightness(self, mp_obj_is_true(auto_brightness)); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_brightness_obj, displayio_display_obj_set_auto_brightness); - -const mp_obj_property_t displayio_display_auto_brightness_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_auto_brightness_obj, - (mp_obj_t)&displayio_display_set_auto_brightness_obj, - (mp_obj_t)&mp_const_none_obj}, -}; +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_wait_for_frame_obj, displayio_epaperdisplay_obj_wait_for_frame); //| .. attribute:: width //| -//| Gets the width of the board +//| Gets the width of the display in pixels //| //| -STATIC mp_obj_t displayio_display_obj_get_width(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_width(self)); +STATIC mp_obj_t displayio_epaperdisplay_obj_get_width(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_width(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_width_obj, displayio_display_obj_get_width); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_width_obj, displayio_epaperdisplay_obj_get_width); -const mp_obj_property_t displayio_display_width_obj = { +const mp_obj_property_t displayio_epaperdisplay_width_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_width_obj, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_width_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; //| .. attribute:: height //| -//| Gets the height of the board +//| Gets the height of the display in pixels //| //| -STATIC mp_obj_t displayio_display_obj_get_height(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_height(self)); +STATIC mp_obj_t displayio_epaperdisplay_obj_get_height(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_height(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_height_obj, displayio_display_obj_get_height); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_height_obj, displayio_epaperdisplay_obj_get_height); -const mp_obj_property_t displayio_display_height_obj = { +const mp_obj_property_t displayio_epaperdisplay_height_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_height_obj, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_height_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; @@ -334,37 +266,34 @@ const mp_obj_property_t displayio_display_height_obj = { //| The bus being used by the display //| //| -STATIC mp_obj_t displayio_display_obj_get_bus(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); +STATIC mp_obj_t displayio_epaperdisplay_obj_get_bus(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); return self->bus; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_bus_obj, displayio_display_obj_get_bus); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_bus_obj, displayio_epaperdisplay_obj_get_bus); -const mp_obj_property_t displayio_display_bus_obj = { +const mp_obj_property_t displayio_epaperdisplay_bus_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_bus_obj, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_bus_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; -STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_display_show_obj) }, - { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_display_refresh_soon_obj) }, - { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_display_wait_for_frame_obj) }, - - { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) }, - { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) }, +STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_epaperdisplay_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_epaperdisplay_refresh_soon_obj) }, + { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_epaperdisplay_wait_for_frame_obj) }, - { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) }, - { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_display_bus_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(displayio_display_locals_dict, displayio_display_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(displayio_epaperdisplay_locals_dict, displayio_epaperdisplay_locals_dict_table); -const mp_obj_type_t displayio_display_type = { +const mp_obj_type_t displayio_epaperdisplay_type = { { &mp_type_type }, - .name = MP_QSTR_Display, - .make_new = displayio_display_make_new, - .locals_dict = (mp_obj_dict_t*)&displayio_display_locals_dict, + .name = MP_QSTR_EPaperDisplay, + .make_new = displayio_epaperdisplay_make_new, + .locals_dict = (mp_obj_dict_t*)&displayio_epaperdisplay_locals_dict, }; diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 6ffabedee..3deeef959 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -24,47 +24,52 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H #include "common-hal/microcontroller/Pin.h" -#include "shared-module/displayio/Display.h" +#include "shared-module/displayio/EPaperDisplay.h" #include "shared-module/displayio/Group.h" extern const mp_obj_type_t displayio_epaperdisplay_type; #define DELAY 0x80 -void common_hal_displayio_display_construct(displayio_display_obj_t* self, - mp_obj_t bus, uint16_t width, uint16_t height, uint16_t seconds_per_frame, - uint16_t rotation, uint16_t color_depth, bool grayscale, - uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* busy_pin, uint16_t partial_command); +#define NO_COMMAND 0x100 -int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self); +void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self, + mp_obj_t bus, uint8_t* start_sequence, uint16_t start_sequence_len, uint8_t* stop_sequence, uint16_t stop_sequence_len, + uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, + uint16_t set_column_window_command, uint16_t set_row_window_command, + uint16_t set_current_column_command, uint16_t set_current_row_command, + uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t third_color, uint16_t refresh_display_command, + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); -void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); +int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self); -void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self); +bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group); -bool displayio_display_begin_transaction(displayio_display_obj_t* self); -void displayio_display_end_transaction(displayio_display_obj_t* self); +void common_hal_displayio_epaperdisplay_refresh_soon(displayio_epaperdisplay_obj_t* self); + +bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self); +void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self); // The second point of the region is exclusive. -void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area); -bool displayio_display_frame_queued(displayio_display_obj_t* self); +void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area); +bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self); -bool displayio_display_refresh_queued(displayio_display_obj_t* self); -void displayio_display_finish_refresh(displayio_display_obj_t* self); -void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length); +bool displayio_epaperdisplay_refresh_queued(displayio_epaperdisplay_obj_t* self); +void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self); +void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length); -bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); -void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); +bool common_hal_displayio_epaperdisplay_get_auto_brightness(displayio_epaperdisplay_obj_t* self); +void common_hal_displayio_epaperdisplay_set_auto_brightness(displayio_epaperdisplay_obj_t* self, bool auto_brightness); -uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self); -uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self); +uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self); +uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self); -mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self); -bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness); +mp_float_t common_hal_displayio_epaperdisplay_get_brightness(displayio_epaperdisplay_obj_t* self); +bool common_hal_displayio_epaperdisplay_set_brightness(displayio_epaperdisplay_obj_t* self, mp_float_t brightness); -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_EPAPERDISPLAY_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index 0d41359ee..efd553e2e 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -103,31 +103,41 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_ return self; } -//| .. method:: send(command, data) +//| .. method:: send(command, data, *, toggle_every_byte=False) //| //| Sends the given command value followed by the full set of data. Display state, such as //| vertical scroll, set via ``send`` may or may not be reset once the code is done. //| -STATIC mp_obj_t displayio_fourwire_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) { - mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj); - if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) { +STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_command, ARG_data, ARG_toggle_every_byte }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_toggle_every_byte, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t command_int = args[ARG_command].u_int; + if (command_int > 255 || command_int < 0) { mp_raise_ValueError(translate("Command must be an int between 0 and 255")); } + displayio_fourwire_obj_t *self = pos_args[0]; uint8_t command = command_int; mp_buffer_info_t bufinfo; - mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); // Wait for display bus to be available. while (!common_hal_displayio_fourwire_begin_transaction(self)) { RUN_BACKGROUND_TASKS; } - common_hal_displayio_fourwire_send(self, true, &command, 1); - common_hal_displayio_fourwire_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len); + common_hal_displayio_fourwire_send(self, true, args[ARG_toggle_every_byte].u_bool, &command, 1); + common_hal_displayio_fourwire_send(self, false, args[ARG_toggle_every_byte].u_bool, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_fourwire_end_transaction(self); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_3(displayio_fourwire_send_obj, displayio_fourwire_obj_send); +MP_DEFINE_CONST_FUN_OBJ_KW(displayio_fourwire_send_obj, 3, displayio_fourwire_obj_send); STATIC const mp_rom_map_elem_t displayio_fourwire_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_fourwire_send_obj) }, diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h index 5dbd60764..ee69a63ac 100644 --- a/shared-bindings/displayio/FourWire.h +++ b/shared-bindings/displayio/FourWire.h @@ -40,9 +40,12 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self); +void common_hal_displayio_fourwire_reset(mp_obj_t self); +bool common_hal_displayio_fourwire_bus_free(mp_obj_t self); + bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self); -void common_hal_displayio_fourwire_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length); +void common_hal_displayio_fourwire_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); void common_hal_displayio_fourwire_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index 9ef989d71..4428e8dbb 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -116,7 +116,7 @@ STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_ob uint8_t full_command[bufinfo.len + 1]; full_command[0] = command; memcpy(full_command + 1, ((uint8_t*) bufinfo.buf), bufinfo.len); - common_hal_displayio_i2cdisplay_send(self, true, full_command, bufinfo.len + 1); + common_hal_displayio_i2cdisplay_send(self, true, false, full_command, bufinfo.len + 1); common_hal_displayio_i2cdisplay_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h index cc4162800..6a75fc488 100644 --- a/shared-bindings/displayio/I2CDisplay.h +++ b/shared-bindings/displayio/I2CDisplay.h @@ -37,9 +37,12 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self); +void common_hal_displayio_i2cdisplay_reset(mp_obj_t self); +bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self); + bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); -void common_hal_displayio_i2cdisplay_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length); +void common_hal_displayio_i2cdisplay_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index c29c79fff..e260f9b7e 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -124,8 +124,8 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o while (!common_hal_displayio_parallelbus_begin_transaction(self)) { RUN_BACKGROUND_TASKS; } - common_hal_displayio_parallelbus_send(self, true, &command, 1); - common_hal_displayio_parallelbus_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len); + common_hal_displayio_parallelbus_send(self, true, false, &command, 1); + common_hal_displayio_parallelbus_send(self, false, false, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_parallelbus_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/ParallelBus.h b/shared-bindings/displayio/ParallelBus.h index c4cde5ff5..b8da91041 100644 --- a/shared-bindings/displayio/ParallelBus.h +++ b/shared-bindings/displayio/ParallelBus.h @@ -40,9 +40,12 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self); +void common_hal_displayio_parallelbus_reset(mp_obj_t self); +bool common_hal_displayio_parallelbus_bus_free(mp_obj_t self); + bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self); -void common_hal_displayio_parallelbus_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length); +void common_hal_displayio_parallelbus_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); void common_hal_displayio_parallelbus_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index fd3dc4233..8c5d1f228 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -33,6 +33,7 @@ #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/displayio/Display.h" +#include "shared-bindings/displayio/EPaperDisplay.h" #include "shared-bindings/displayio/FourWire.h" #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/I2CDisplay.h" @@ -60,6 +61,7 @@ //| Bitmap //| ColorConverter //| Display +//| EPaperDisplay //| FourWire //| Group //| I2CDisplay @@ -91,6 +93,7 @@ STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&displayio_bitmap_type) }, { MP_ROM_QSTR(MP_QSTR_ColorConverter), MP_ROM_PTR(&displayio_colorconverter_type) }, { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&displayio_display_type) }, + { MP_ROM_QSTR(MP_QSTR_EPaperDisplay), MP_ROM_PTR(&displayio_epaperdisplay_type) }, { MP_ROM_QSTR(MP_QSTR_Group), MP_ROM_PTR(&displayio_group_type) }, { MP_ROM_QSTR(MP_QSTR_OnDiskBitmap), MP_ROM_PTR(&displayio_ondiskbitmap_type) }, { MP_ROM_QSTR(MP_QSTR_Palette), MP_ROM_PTR(&displayio_palette_type) }, diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 6b9bd5840..0277c79f0 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -45,14 +45,104 @@ uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888) { return (r8 * 19) / 255 + (g8 * 182) / 255 + (b8 + 54) / 255; } +void compute_bounds(uint8_t r8, uint8_t g8, uint8_t b8, uint8_t* min, uint8_t* max) { + if (r8 > g8) { + if (b8 > r8) { + *max = b8; + } else { + *max = r8; + } + if (b8 < g8) { + *min = b8; + } else { + *min = g8; + } + } else { + if (b8 > g8) { + *max = b8; + } else { + *max = g8; + } + if (b8 < r8) { + *min = b8; + } else { + *min = r8; + } + } +} + +uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888) { + uint32_t r8 = (color_rgb888 >> 16); + uint32_t g8 = (color_rgb888 >> 8) & 0xff; + uint32_t b8 = color_rgb888 & 0xff; + uint8_t max; + uint8_t min; + compute_bounds(r8, g8, b8, &min, &max); + return max - min; +} + +uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888) { + uint32_t r8 = (color_rgb888 >> 16); + uint32_t g8 = (color_rgb888 >> 8) & 0xff; + uint32_t b8 = color_rgb888 & 0xff; + uint8_t max; + uint8_t min; + compute_bounds(r8, g8, b8, &min, &max); + uint8_t c = max - min; + if (c == 0) { + return 0; + } + + int32_t hue = 0; + if (max == r8) { + hue = (((int32_t) (g8 - b8) * 40) / c) % 240; + } else if (max == g8) { + hue = (((int32_t) (b8 - r8) + (2 * c)) * 40) / c; + } else if (max == b8) { + hue = (((int32_t) (r8 - g8) + (4 * c)) * 40) / c; + } + if (hue < 0) { + hue += 240; + } + + return hue; +} + +void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t* colorspace, uint8_t pixel_hue, uint8_t pixel_luma, uint32_t* color) { + + int16_t hue_diff = colorspace->tricolor_hue - pixel_hue; + if ((-10 <= hue_diff && hue_diff <= 10) || hue_diff <= -220 || hue_diff >= 220) { + if (colorspace->grayscale) { + *color = 0; + } else { + *color = 1; + } + } else if (!colorspace->grayscale) { + *color = 0; + } +} + bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { if (colorspace->depth == 16) { *output_color = displayio_colorconverter_compute_rgb565(input_color); return true; + } else if (colorspace->tricolor) { + uint8_t luma = displayio_colorconverter_compute_luma(input_color); + *output_color = luma >> (8 - colorspace->depth); + if (displayio_colorconverter_compute_chroma(input_color) <= 16) { + if (!colorspace->grayscale) { + *output_color = 0; + } + return true; + } + uint8_t pixel_hue = displayio_colorconverter_compute_hue(input_color); + displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, output_color); + return true; } else if (colorspace->grayscale && colorspace->depth <= 8) { uint8_t luma = displayio_colorconverter_compute_luma(input_color); *output_color = luma >> (8 - colorspace->depth); return true; + } else if (!colorspace->grayscale && colorspace->depth == 1) { } return false; } diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index c48b98e6d..c79e6a2f7 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -42,5 +42,8 @@ void displayio_colorconverter_finish_refresh(displayio_colorconverter_t *self); bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888); +uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888); +uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888); +void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t* colorspace, uint8_t pixel_hue, uint8_t pixel_luma, uint32_t* color); #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index d11813b8c..97a18740a 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -40,8 +40,6 @@ #include "tick.h" -#define DELAY 0x80 - void common_hal_displayio_display_construct(displayio_display_obj_t* self, mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, @@ -97,10 +95,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t full_command[data_size + 1]; full_command[0] = cmd[0]; memcpy(full_command + 1, data, data_size); - self->send(self->bus, true, full_command, data_size + 1); + self->send(self->bus, true, true, full_command, data_size + 1); } else { - self->send(self->bus, true, cmd, 1); - self->send(self->bus, false, data, data_size); + self->send(self->bus, true, true, cmd, 1); + self->send(self->bus, false, false, data, data_size); } uint16_t delay_length_ms = 10; if (delay) { @@ -232,6 +230,9 @@ const displayio_area_t* displayio_display_get_refresh_areas(displayio_display_ob self->area.next = NULL; return &self->area; } else { + if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { + asm("bkpt"); + } return displayio_group_get_refresh_areas(self->current_group, NULL); } } @@ -283,12 +284,12 @@ bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, if (ok) { if (self->data_as_commands) { uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; - self->send(self->bus, true, set_brightness, 2); + self->send(self->bus, true, true, set_brightness, 2); } else { uint8_t command = self->brightness_command; uint8_t hex_brightness = 0xff * brightness; - self->send(self->bus, true, &command, 1); - self->send(self->bus, false, &hex_brightness, 1); + self->send(self->bus, true, true, &command, 1); + self->send(self->bus, false, false, &hex_brightness, 1); } self->end_transaction(self->bus); } @@ -331,7 +332,7 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ data[0] = self->set_column_command; uint8_t data_length = 1; if (!self->data_as_commands) { - self->send(self->bus, true, data, 1); + self->send(self->bus, true, true, data, 1); data_length = 0; } if (self->single_byte_bounds) { @@ -345,13 +346,13 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ data[data_length++] = x2 >> 8; data[data_length++] = x2 & 0xff; } - self->send(self->bus, self->data_as_commands, data, data_length); + self->send(self->bus, self->data_as_commands, self->data_as_commands, data, data_length); // Set row. data[0] = self->set_row_command; data_length = 1; if (!self->data_as_commands) { - self->send(self->bus, true, data, 1); + self->send(self->bus, true, true, data, 1); data_length = 0; } if (self->single_byte_bounds) { @@ -365,7 +366,7 @@ void displayio_display_set_region_to_update(displayio_display_obj_t* self, displ data[data_length++] = y2 >> 8; data[data_length++] = y2 & 0xff; } - self->send(self->bus, self->data_as_commands, data, data_length); + self->send(self->bus, self->data_as_commands, self->data_as_commands, data, data_length); } void displayio_display_start_refresh(displayio_display_obj_t* self) { @@ -391,9 +392,9 @@ void displayio_display_finish_refresh(displayio_display_obj_t* self) { void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { if (!self->data_as_commands) { - self->send(self->bus, true, &self->write_ram_command, 1); + self->send(self->bus, true, true, &self->write_ram_command, 1); } - self->send(self->bus, false, pixels, length); + self->send(self->bus, false, false, pixels, length); } void displayio_display_update_backlight(displayio_display_obj_t* self) { @@ -414,7 +415,6 @@ void release_display(displayio_display_obj_t* self) { if (self->current_group != NULL) { self->current_group->in_group = false; } - if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index 74ae175b1..c85d69b0e 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -34,7 +34,7 @@ #include "shared-module/displayio/area.h" typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, bool command, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); typedef void (*display_bus_end_transaction)(mp_obj_t bus); typedef struct { diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c new file mode 100644 index 000000000..5e4bdc340 --- /dev/null +++ b/shared-module/displayio/EPaperDisplay.c @@ -0,0 +1,531 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/displayio/EPaperDisplay.h" + +#include "py/runtime.h" +#include "shared-bindings/displayio/ColorConverter.h" +#include "shared-bindings/displayio/FourWire.h" +#include "shared-bindings/displayio/I2CDisplay.h" +#include "shared-bindings/displayio/ParallelBus.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/display.h" +#include "supervisor/usb.h" + +#include +#include + +#include "tick.h" + +void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self, + mp_obj_t bus, uint8_t* start_sequence, uint16_t start_sequence_len, uint8_t* stop_sequence, uint16_t stop_sequence_len, + uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, + int16_t colstart, int16_t rowstart, uint16_t rotation, + uint16_t set_column_window_command, uint16_t set_row_window_command, + uint16_t set_current_column_command, uint16_t set_current_row_command, + uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t third_color, uint16_t refresh_display_command, + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select) { + self->colorspace.depth = 1; + self->colorspace.grayscale = true; + self->colorspace.pixels_in_byte_share_row = true; + self->colorspace.bytes_per_cell = 1; + self->colorspace.reverse_pixels_in_byte = true; + + if (third_color != 0x000000) { + self->colorspace.tricolor = true; + self->colorspace.tricolor_hue = displayio_colorconverter_compute_hue(third_color); + self->colorspace.tricolor_luma = displayio_colorconverter_compute_luma(third_color); + } + + self->set_column_window_command = set_column_window_command; + self->set_row_window_command = set_row_window_command; + self->set_current_column_command = set_current_column_command; + self->set_current_row_command = set_current_row_command; + self->write_black_ram_command = write_black_ram_command; + self->black_bits_inverted = black_bits_inverted; + self->write_color_ram_command = write_color_ram_command; + self->color_bits_inverted = color_bits_inverted; + self->refresh_display_command = refresh_display_command; + self->busy_state = busy_state; + self->refresh = true; + self->current_group = NULL; + self->colstart = colstart; + self->rowstart = rowstart; + self->refreshing = false; + self->milliseconds_per_frame = seconds_per_frame * 1000; + self->always_toggle_chip_select = always_toggle_chip_select; + + self->start_sequence = start_sequence; + self->start_sequence_len = start_sequence_len; + self->stop_sequence = stop_sequence; + self->stop_sequence_len = stop_sequence_len; + + + if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { + self->bus_reset = common_hal_displayio_parallelbus_reset; + self->bus_free = common_hal_displayio_parallelbus_bus_free; + self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; + self->send = common_hal_displayio_parallelbus_send; + self->end_transaction = common_hal_displayio_parallelbus_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { + self->bus_reset = common_hal_displayio_fourwire_reset; + self->bus_free = common_hal_displayio_fourwire_bus_free; + self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; + self->send = common_hal_displayio_fourwire_send; + self->end_transaction = common_hal_displayio_fourwire_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { + self->bus_reset = common_hal_displayio_i2cdisplay_reset; + self->bus_free = common_hal_displayio_i2cdisplay_bus_free; + self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; + self->send = common_hal_displayio_i2cdisplay_send; + self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; + } else { + mp_raise_ValueError(translate("Unsupported display bus type")); + } + self->bus = bus; + + supervisor_start_terminal(width, height); + + self->width = width; + self->height = height; + rotation = rotation % 360; + self->transform.x = 0; + self->transform.y = 0; + self->transform.scale = 1; + self->transform.mirror_x = false; + self->transform.mirror_y = false; + self->transform.transpose_xy = false; + if (rotation == 0 || rotation == 180) { + if (rotation == 180) { + self->transform.mirror_x = true; + self->transform.mirror_y = true; + } + } else { + self->transform.transpose_xy = true; + if (rotation == 270) { + self->transform.mirror_y = true; + } else { + self->transform.mirror_x = true; + } + } + + self->ram_width = ram_width; + self->ram_height = ram_height; + + self->area.x1 = 0; + self->area.y1 = 0; + self->area.next = NULL; + + self->transform.dx = 1; + self->transform.dy = 1; + if (self->transform.transpose_xy) { + self->area.x2 = height; + self->area.y2 = width; + if (self->transform.mirror_x) { + self->transform.x = height; + self->transform.dx = -1; + } + if (self->transform.mirror_y) { + self->transform.y = width; + self->transform.dy = -1; + } + } else { + self->area.x2 = width; + self->area.y2 = height; + if (self->transform.mirror_x) { + self->transform.x = width; + self->transform.dx = -1; + } + if (self->transform.mirror_y) { + self->transform.y = height; + self->transform.dy = -1; + } + } + + self->busy.base.type = &mp_type_NoneType; + if (busy_pin != NULL) { + self->busy.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->busy, busy_pin); + never_reset_pin_number(busy_pin->number); + } + + // Set the group after initialization otherwise we may send pixels while we delay in + // initialization. + common_hal_displayio_epaperdisplay_show(self, &circuitpython_splash); +} + +bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group) { + if (root_group == NULL && !circuitpython_splash.in_group) { + root_group = &circuitpython_splash; + } + if (root_group == self->current_group) { + return true; + } + if (root_group != NULL && root_group->in_group) { + return false; + } + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + if (root_group != NULL) { + displayio_group_update_transform(root_group, &self->transform); + root_group->in_group = true; + self->current_group = root_group; + } + self->full_refresh = true; + common_hal_displayio_epaperdisplay_refresh_soon(self); + return true; +} + +void common_hal_displayio_epaperdisplay_refresh_soon(displayio_epaperdisplay_obj_t* self) { + self->refresh = true; +} + +const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self) { + const displayio_area_t* first_area; + if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { + asm("bkpt"); + } + if (self->full_refresh) { + first_area = &self->area; + } else { + first_area = displayio_group_get_refresh_areas(self->current_group, NULL); + } + if (first_area != NULL && self->set_row_window_command == NO_COMMAND) { + self->area.next = NULL; + return &self->area; + } + return first_area; +} + +int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self) { + uint64_t last_refresh = self->last_refresh; + // Don't try to refresh if we got an exception. + while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { + MICROPY_VM_HOOK_LOOP + } + return 0; +} + +uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self){ + return self->width; +} + +uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self){ + return self->height; +} + +bool displayio_epaperdisplay_bus_free(displayio_epaperdisplay_obj_t *self) { + return self->bus_free(self->bus); +} + +bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self) { + return self->begin_transaction(self->bus); +} + +void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self) { + self->end_transaction(self->bus); +} + +STATIC void wait_for_busy(displayio_epaperdisplay_obj_t* self) { + if (self->busy.base.type == &mp_type_NoneType) { + return; + } + while (common_hal_digitalio_digitalinout_get_value(&self->busy) == self->busy_state) { + #ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP + #endif + } +} + +STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool should_wait_for_busy, uint8_t* sequence, uint32_t sequence_len) { + uint32_t i = 0; + while (i < sequence_len) { + uint8_t *cmd = sequence + i; + uint8_t data_size = *(cmd + 1); + bool delay = (data_size & DELAY) != 0; + data_size &= ~DELAY; + uint8_t *data = cmd + 2; + self->begin_transaction(self->bus); + self->send(self->bus, true, self->always_toggle_chip_select, cmd, 1); + self->send(self->bus, false, self->always_toggle_chip_select, data, data_size); + self->end_transaction(self->bus); + uint16_t delay_length_ms = 0; + if (delay) { + data_size++; + delay_length_ms = *(cmd + 1 + data_size); + if (delay_length_ms == 255) { + delay_length_ms = 500; + } + } + common_hal_time_delay_ms(delay_length_ms); + if (should_wait_for_busy) { + wait_for_busy(self); + } + i += 2 + data_size; + } +} + +void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area) { + if (self->set_row_window_command == NO_COMMAND) { + return; + } + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + uint16_t y1 = area->y1; + uint16_t y2 = area->y2; + // Collapse down the dimension where multiple pixels are in a byte. + uint8_t pixels_per_byte = 8 / self->colorspace.depth; + x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; + x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; + + + // Set column. + uint8_t data[5]; + data[0] = self->set_column_window_command; + self->send(self->bus, true, self->always_toggle_chip_select, data, 1); + uint8_t data_length = 0; + if (self->ram_width / pixels_per_byte < 0x100) { + data[data_length++] = x1 + self->colstart; + data[data_length++] = x2 - 1 + self->colstart; + } else { + x1 += self->colstart; + x2 += self->colstart - 1; + data[data_length++] = x1 >> 8; + data[data_length++] = x1 & 0xff; + data[data_length++] = x2 >> 8; + data[data_length++] = x2 & 0xff; + } + self->send(self->bus, false, self->always_toggle_chip_select, data, data_length); + if (self->set_current_column_command != NO_COMMAND) { + uint8_t command = self->set_current_column_command; + self->send(self->bus, true, self->always_toggle_chip_select, &command, 1); + self->send(self->bus, false, self->always_toggle_chip_select, data, data_length / 2); + } + + // Set row. + data[0] = self->set_row_window_command; + self->send(self->bus, true, self->always_toggle_chip_select, data, 1); + data_length = 0; + if (self->ram_height < 0x100) { + data[data_length++] = y1 + self->rowstart; + data[data_length++] = y2 - 1 + self->rowstart; + } else { + y1 += self->rowstart; + y2 += self->rowstart - 1; + data[data_length++] = y1 & 0xff; + data[data_length++] = y1 >> 8; + data[data_length++] = y2 & 0xff; + data[data_length++] = y2 >> 8; + } + self->send(self->bus, false, self->always_toggle_chip_select, data, data_length); + if (self->set_current_row_command != NO_COMMAND) { + uint8_t command = self->set_current_row_command; + self->send(self->bus, true, self->always_toggle_chip_select, &command, 1); + self->send(self->bus, false, self->always_toggle_chip_select, data, data_length / 2); + } +} + +void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self) { + // run start sequence + self->bus_reset(self->bus); + + send_command_sequence(self, true, self->start_sequence, self->start_sequence_len); + self->last_refresh = ticks_ms; +} + +bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self) { + if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { + if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { + self->refreshing = false; + // Run stop sequence but don't wait for busy because busy is set when sleeping. + send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); + } else { + return false; + } + } + if (self->current_group == NULL) { + return false; + } + // Refresh at seconds per frame rate. + return (ticks_ms - self->last_refresh) > self->milliseconds_per_frame; +} + +void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { + // Actually refresh the display now that all pixel RAM has been updated. + displayio_epaperdisplay_begin_transaction(self); + self->send(self->bus, true, self->always_toggle_chip_select, &self->refresh_display_command, 1); + displayio_epaperdisplay_end_transaction(self); + self->refreshing = true; + + if (self->current_group != NULL) { + displayio_group_finish_refresh(self->current_group); + } + self->refresh = false; + self->full_refresh = false; + self->last_refresh = ticks_ms; +} + +void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length) { +} + + +bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, const displayio_area_t* area) { + uint16_t buffer_size = 128; // In uint32_ts + + displayio_area_t clipped; + // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. + if (!displayio_epaperdisplay_clip_area(self, area, &clipped)) { + return true; + } + uint16_t subrectangles = 1; + uint16_t rows_per_buffer = displayio_area_height(&clipped); + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->colorspace.depth; + uint16_t pixels_per_buffer = displayio_area_size(&clipped); + if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { + rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + } + + // Allocated and shared as a uint32_t array so the compiler knows the + // alignment everywhere. + uint32_t buffer[buffer_size]; + volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask[mask_length]; + + uint8_t passes = 1; + if (self->colorspace.tricolor) { + passes = 2; + } + for (uint8_t pass = 0; pass < passes; pass++) { + uint16_t remaining_rows = displayio_area_height(&clipped); + + displayio_epaperdisplay_begin_transaction(self); + displayio_epaperdisplay_set_region_to_update(self, &clipped); + displayio_epaperdisplay_end_transaction(self); + + uint8_t write_command = self->write_black_ram_command; + if (pass == 1) { + write_command = self->write_color_ram_command; + } + displayio_epaperdisplay_begin_transaction(self); + self->send(self->bus, true, self->always_toggle_chip_select, &write_command, 1); + displayio_epaperdisplay_end_transaction(self); + + for (uint16_t j = 0; j < subrectangles; j++) { + displayio_area_t subrectangle = { + .x1 = clipped.x1, + .y1 = clipped.y1 + rows_per_buffer * j, + .x2 = clipped.x2, + .y2 = clipped.y1 + rows_per_buffer * (j + 1) + }; + if (remaining_rows < rows_per_buffer) { + subrectangle.y2 = subrectangle.y1 + remaining_rows; + } + remaining_rows -= rows_per_buffer; + + + uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->colorspace.depth); + + for (uint16_t k = 0; k < mask_length; k++) { + mask[k] = 0x00000000; + } + for (uint16_t k = 0; k < buffer_size; k++) { + buffer[k] = 0x00000000; + } + + self->colorspace.grayscale = true; + if (pass == 1) { + self->colorspace.grayscale = false; + } + displayio_group_fill_area(self->current_group, &self->colorspace, &subrectangle, mask, buffer); + + // Invert it all. + if ((pass == 1 && self->color_bits_inverted) || + (pass == 0 && self->black_bits_inverted)) { + for (uint16_t k = 0; k < buffer_size; k++) { + buffer[k] = ~buffer[k]; + } + } + + if (!displayio_epaperdisplay_begin_transaction(self)) { + // Can't acquire display bus; skip the rest of the data. Try next display. + return false; + } + self->send(self->bus, false, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); + displayio_epaperdisplay_end_transaction(self); + + // TODO(tannewt): Make refresh displays faster so we don't starve other + // background tasks. + usb_background(); + } + } + + return true; +} + +void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + if (self->busy.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_deinit(&self->busy); + } +} + +bool displayio_epaperdisplay_fill_area(displayio_epaperdisplay_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { + return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); +} + +bool displayio_epaperdisplay_clip_area(displayio_epaperdisplay_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped) { + bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); + if (!overlaps) { + return false; + } + // Expand the area if we have multiple pixels per byte and we need to byte + // align the bounds. + uint8_t pixels_per_byte = 8; + if (clipped->x1 % pixels_per_byte != 0) { + clipped->x1 -= clipped->x1 % pixels_per_byte; + } + if (clipped->x2 % pixels_per_byte != 0) { + clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; + } + return true; +} diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h new file mode 100644 index 000000000..737b5987a --- /dev/null +++ b/shared-module/displayio/EPaperDisplay.h @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H +#define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H + +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/displayio/Group.h" +#include "shared-bindings/pulseio/PWMOut.h" + +#include "shared-module/displayio/area.h" + +typedef void (*display_bus_bus_reset)(mp_obj_t bus); +typedef bool (*display_bus_bus_free)(mp_obj_t bus); +typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); +typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_end_transaction)(mp_obj_t bus); + +typedef struct { + mp_obj_base_t base; + mp_obj_t bus; + displayio_group_t *current_group; + uint64_t last_refresh; + display_bus_bus_reset bus_reset; + display_bus_bus_free bus_free; + display_bus_begin_transaction begin_transaction; + display_bus_send send; + display_bus_end_transaction end_transaction; + digitalio_digitalinout_obj_t busy; + uint32_t milliseconds_per_frame; + uint8_t* start_sequence; + uint32_t start_sequence_len; + uint8_t* stop_sequence; + uint32_t stop_sequence_len; + displayio_buffer_transform_t transform; + displayio_area_t area; + uint16_t width; + uint16_t height; + uint16_t ram_width; + uint16_t ram_height; + _displayio_colorspace_t colorspace; + int16_t colstart; + int16_t rowstart; + uint16_t set_column_window_command; + uint16_t set_row_window_command; + uint16_t set_current_column_command; + uint16_t set_current_row_command; + uint16_t write_black_ram_command; + uint16_t write_color_ram_command; + uint8_t refresh_display_command; + uint8_t hue; + bool busy_state; + bool black_bits_inverted; + bool color_bits_inverted; + bool refresh; + bool refreshing; + bool full_refresh; // New group means we need to refresh the whole display. + bool always_toggle_chip_select; +} displayio_epaperdisplay_obj_t; + +bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* display, const displayio_area_t* area); +void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self); +const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self); +bool displayio_epaperdisplay_fill_area(displayio_epaperdisplay_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer); +bool displayio_epaperdisplay_clip_area(displayio_epaperdisplay_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped); +bool displayio_epaperdisplay_bus_free(displayio_epaperdisplay_obj_t *self); +void release_epaperdisplay(displayio_epaperdisplay_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 913635db8..64ad80665 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -59,11 +59,7 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); - - common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_mcu_delay_us(10); - common_hal_digitalio_digitalinout_set_value(&self->reset, true); - common_hal_mcu_delay_us(10); + common_hal_displayio_fourwire_reset(self); } never_reset_pin_number(command->number); @@ -80,6 +76,23 @@ void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self) { reset_pin_number(self->reset.pin->number); } +void common_hal_displayio_fourwire_reset(mp_obj_t obj) { + displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_time_delay_ms(1); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); + common_hal_time_delay_ms(1); +} + +bool common_hal_displayio_fourwire_bus_free(mp_obj_t obj) { + displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); + if (!common_hal_busio_spi_try_lock(self->bus)) { + return false; + } + common_hal_busio_spi_unlock(self->bus); + return true; +} + bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); if (!common_hal_busio_spi_try_lock(self->bus)) { @@ -91,10 +104,10 @@ bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_fourwire_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_fourwire_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->command, !command); - if (command) { + if (toggle_every_byte) { // Toggle chip select after each command byte in case the display driver // IC latches commands based on it. for (size_t i = 0; i < data_length; i++) { diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index 38418a029..eb6e9a453 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -304,6 +304,9 @@ void displayio_group_finish_refresh(displayio_group_t *self) { } displayio_area_t* displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t* tail) { + if (self->base.type != &displayio_group_type) { + asm("bkpt"); + } if (self->item_removed) { self->dirty_area.next = tail; tail = &self->dirty_area; diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 9d8949528..23ebc0889 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -59,10 +59,7 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); - - common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_mcu_delay_us(1); - common_hal_digitalio_digitalinout_set_value(&self->reset, true); + common_hal_displayio_i2cdisplay_reset(self); } } @@ -74,7 +71,17 @@ void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { reset_pin_number(self->reset.pin->number); } -bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { + +void common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { + displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); + + common_hal_digitalio_digitalinout_set_value(&self->reset, false); + common_hal_mcu_delay_us(1); + common_hal_digitalio_digitalinout_set_value(&self->reset, true); +} + + +bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t obj) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); if (!common_hal_busio_i2c_try_lock(self->bus)) { return false; @@ -82,7 +89,11 @@ bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, bool command, uint8_t *data, uint32_t data_length) { +bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { + return common_hal_displayio_i2cdisplay_bus_free(obj); +} + +void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); if (command) { uint8_t command_bytes[2 * data_length]; diff --git a/shared-module/displayio/OnDiskBitmap.c b/shared-module/displayio/OnDiskBitmap.c index 2b5642437..10fc0c4a2 100644 --- a/shared-module/displayio/OnDiskBitmap.c +++ b/shared-module/displayio/OnDiskBitmap.c @@ -74,7 +74,7 @@ void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, self->g_bitmask = 0x3e0; self->b_bitmask = 0x1f; } - } else if ((indexed) && (self->bits_per_pixel != 1)) { + } else if (indexed && self->bits_per_pixel != 1) { uint16_t palette_size = number_of_colors * sizeof(uint32_t); uint16_t palette_offset = 0xe + header_size; @@ -90,25 +90,24 @@ void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, if (palette_bytes_read != palette_size) { mp_raise_ValueError(translate("Unable to read color palette data")); } - - } else if (!(header_size == 12 || header_size == 40 || header_size == 108 || header_size == 124)) { mp_raise_ValueError_varg(translate("Only Windows format, uncompressed BMP supported: given header size is %d"), header_size); } - if ((bits_per_pixel == 4 ) || (( bits_per_pixel == 8) && (number_of_colors == 0))) { - mp_raise_ValueError_varg(translate("Only monochrome, indexed 8bpp, and 16bpp or greater BMPs supported: %d bpp given"), bits_per_pixel); + if (bits_per_pixel == 8 && number_of_colors == 0) { + mp_raise_ValueError_varg(translate("Only monochrome, indexed 4bpp or 8bpp, and 16bpp or greater BMPs supported: %d bpp given"), bits_per_pixel); } - if (self->bits_per_pixel >=8){ - self->stride = (self->width * (bits_per_pixel / 8)); + uint8_t bytes_per_pixel = (self->bits_per_pixel / 8) ? (self->bits_per_pixel /8) : 1; + uint8_t pixels_per_byte = 8 / self->bits_per_pixel; + if (pixels_per_byte == 0){ + self->stride = (self->width * bytes_per_pixel); // Rows are word aligned. if (self->stride % 4 != 0) { self->stride += 4 - self->stride % 4; } - } else { - uint32_t bit_stride = self->width; + uint32_t bit_stride = self->width * self->bits_per_pixel; if (bit_stride % 32 != 0) { bit_stride += 32 - bit_stride % 32; } @@ -126,10 +125,11 @@ uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *s uint32_t location; uint8_t bytes_per_pixel = (self->bits_per_pixel / 8) ? (self->bits_per_pixel /8) : 1; - if (self->bits_per_pixel >= 8){ + uint8_t pixels_per_byte = 8 / self->bits_per_pixel; + if (pixels_per_byte == 0){ location = self->data_offset + (self->height - y - 1) * self->stride + x * bytes_per_pixel; } else { - location = self->data_offset + (self->height - y - 1) * self->stride + x / 8; + location = self->data_offset + (self->height - y - 1) * self->stride + x / pixels_per_byte; } // We don't cache here because the underlying FS caches sectors. f_lseek(&self->file->fp, location); @@ -141,20 +141,21 @@ uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *s uint8_t red; uint8_t green; uint8_t blue; - if (self->bits_per_pixel == 1) { - uint8_t bit_offset = x%8; - tmp = ( pixel_data & (0x80 >> (bit_offset))) >> (7 - bit_offset); - if (tmp == 1) { - return 0x00FFFFFF; - } else { - return 0x00000000; + if (bytes_per_pixel == 1) { + uint8_t offset = (x % pixels_per_byte) * self->bits_per_pixel; + uint8_t mask = (1 << self->bits_per_pixel) - 1; + + uint8_t index = (pixel_data >> ((8 - self->bits_per_pixel) - offset)) & mask; + if (self->bits_per_pixel == 1) { + if (index == 1) { + return 0xFFFFFF; + } else if (index == 0) { + return 0x000000; + } else { + asm("bkpt"); + } } - } else if (bytes_per_pixel == 1) { - blue = ((self->palette_data[pixel_data] & 0xFF) >> 0); - red = ((self->palette_data[pixel_data] & 0xFF0000) >> 16); - green = ((self->palette_data[pixel_data] & 0xFF00) >> 8); - tmp = (red << 16 | green << 8 | blue ); - return tmp; + return self->palette_data[index]; } else if (bytes_per_pixel == 2) { if (self->g_bitmask == 0x07e0) { // 565 red =((pixel_data & self->r_bitmask) >>11); diff --git a/shared-module/displayio/Palette.c b/shared-module/displayio/Palette.c index 444151b3c..3bce86f48 100644 --- a/shared-module/displayio/Palette.c +++ b/shared-module/displayio/Palette.c @@ -52,6 +52,10 @@ void common_hal_displayio_palette_set_color(displayio_palette_t* self, uint32_t self->colors[palette_index].rgb888 = color; self->colors[palette_index].luma = displayio_colorconverter_compute_luma(color); self->colors[palette_index].rgb565 = displayio_colorconverter_compute_rgb565(color); + + uint8_t chroma = displayio_colorconverter_compute_chroma(color); + self->colors[palette_index].chroma = chroma; + self->colors[palette_index].hue = displayio_colorconverter_compute_hue(color); self->needs_refresh = true; } @@ -64,7 +68,19 @@ bool displayio_palette_get_color(displayio_palette_t *self, const _displayio_col return false; // returns opaque } - if (colorspace->grayscale) { + if (colorspace->tricolor) { + uint8_t luma = self->colors[palette_index].luma; + *color = luma >> (8 - colorspace->depth); + // Chroma 0 means the color is a gray and has no hue so never color based on it. + if (self->colors[palette_index].chroma <= 16) { + if (!colorspace->grayscale) { + *color = 0; + } + return true; + } + uint8_t pixel_hue = self->colors[palette_index].hue; + displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, color); + } else if (colorspace->grayscale) { *color = self->colors[palette_index].luma >> (8 - colorspace->depth); } else { *color = self->colors[palette_index].rgb565; diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index a917e2432..1cfdd199a 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -34,17 +34,21 @@ typedef struct { uint8_t depth; + uint8_t bytes_per_cell; + uint8_t tricolor_hue; + uint8_t tricolor_luma; bool grayscale; + bool tricolor; bool pixels_in_byte_share_row; - uint8_t bytes_per_cell; bool reverse_pixels_in_byte; - uint8_t hue; } _displayio_colorspace_t; typedef struct { uint32_t rgb888; uint16_t rgb565; uint8_t luma; + uint8_t hue; + uint8_t chroma; bool transparent; // This may have additional bits added later for blending. } _displayio_color_t; diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 6144f8f99..6553cf901 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -443,6 +443,7 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c } uint8_t shift = (offset % pixels_per_byte) * colorspace->depth; if (colorspace->reverse_pixels_in_byte) { + // Reverse the shift by subtracting it from the leftmost shift. shift = (pixels_per_byte - 1) * colorspace->depth - shift; } ((uint8_t*)buffer)[offset / pixels_per_byte] |= pixel << shift; diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 3e9c4aa2a..a8f888654 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -133,26 +133,50 @@ void displayio_refresh_displays(void) { // Skip null display. continue; } - displayio_display_obj_t* display = &displays[i].display; - displayio_display_update_backlight(display); - - // Time to refresh at specified frame rate? - if (!displayio_display_frame_queued(display)) { - // Too soon. Try next display. - continue; - } - if (!displayio_display_begin_transaction(display)) { - // Can't acquire display bus; skip updating this display. Try next display. - continue; - } - displayio_display_end_transaction(display); - displayio_display_start_refresh(display); - const displayio_area_t* current_area = displayio_display_get_refresh_areas(display); - while (current_area != NULL) { - refresh_area(display, current_area); - current_area = current_area->next; + if (displays[i].display.base.type == &displayio_display_type) { + displayio_display_obj_t* display = &displays[i].display; + displayio_display_update_backlight(display); + + // Time to refresh at specified frame rate? + if (!displayio_display_frame_queued(display)) { + // Too soon. Try next display. + continue; + } + if (!displayio_display_begin_transaction(display)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + displayio_display_end_transaction(display); + displayio_display_start_refresh(display); + const displayio_area_t* current_area = displayio_display_get_refresh_areas(display); + while (current_area != NULL) { + refresh_area(display, current_area); + current_area = current_area->next; + } + displayio_display_finish_refresh(display); + } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { + displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; + // Time to refresh at specified frame rate? + if (!displayio_epaperdisplay_frame_queued(display)) { + // Too soon. Try next display. + continue; + } + if (!displayio_epaperdisplay_bus_free(display)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(display); + if (current_area == NULL) { + continue; + } + displayio_epaperdisplay_start_refresh(display); + while (current_area != NULL) { + displayio_epaperdisplay_refresh_area(display, current_area); + current_area = current_area->next; + } + displayio_epaperdisplay_finish_refresh(display); } - displayio_display_finish_refresh(display); + frame_count++; } @@ -175,7 +199,14 @@ void common_hal_displayio_release_displays(void) { displays[i].fourwire_bus.base.type = &mp_type_NoneType; } for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - release_display(&displays[i].display); + mp_const_obj_t display_type = displays[i].display.base.type; + if (display_type == NULL || display_type == &mp_type_NoneType) { + continue; + } else if (display_type == &displayio_display_type) { + release_display(&displays[i].display); + } else if (display_type == &displayio_epaperdisplay_type) { + release_epaperdisplay(&displays[i].epaper_display); + } displays[i].display.base.type = &mp_type_NoneType; } @@ -232,7 +263,7 @@ void reset_displays(void) { } } } else { - // Not an active display. + // Not an active display bus. continue; } } @@ -240,9 +271,14 @@ void reset_displays(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { // Reset the displayed group. Only the first will get the terminal but // that's ok. - displayio_display_obj_t* display = &displays[i].display; - display->auto_brightness = true; - common_hal_displayio_display_show(display, NULL); + if (displays[i].display.base.type == &displayio_display_type) { + displayio_display_obj_t* display = &displays[i].display; + display->auto_brightness = true; + common_hal_displayio_display_show(display, NULL); + } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { + displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; + common_hal_displayio_epaperdisplay_show(display, NULL); + } } } @@ -254,8 +290,11 @@ void displayio_gc_collect(void) { // Alternatively, we could use gc_collect_root over the whole object, // but this is more precise, and is the only field that needs marking. - gc_collect_ptr(displays[i].display.current_group); - + if (displays[i].display.base.type == &displayio_display_type) { + gc_collect_ptr(displays[i].display.current_group); + } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { + gc_collect_ptr(displays[i].epaper_display.current_group); + } } } diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index caa5ce36d..95eefbdd9 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -28,6 +28,7 @@ #define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO___INIT___H #include "shared-bindings/displayio/Display.h" +#include "shared-bindings/displayio/EPaperDisplay.h" #include "shared-bindings/displayio/FourWire.h" #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/I2CDisplay.h" @@ -39,7 +40,10 @@ typedef struct { displayio_i2cdisplay_obj_t i2cdisplay_bus; displayio_parallelbus_obj_t parallel_bus; }; - displayio_display_obj_t display; + union { + displayio_display_obj_t display; + displayio_epaperdisplay_obj_t epaper_display; + }; } primary_display_t; extern primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index fd51e2c07..586b6f8be 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -151,37 +151,49 @@ _displayio_color_t blinka_colors[7] = { .rgb888 = 0x000000, .rgb565 = 0x0000, .luma = 0x00, + .chroma = 0, .transparent = true }, { .rgb888 = 0x8428bc, .rgb565 = 0x7889, - .luma = 0xff // We cheat the luma here. It is actually 0x60 + .luma = 0xff, // We cheat the luma here. It is actually 0x60 + .hue = 184, + .chroma = 148 }, { .rgb888 = 0xff89bc, .rgb565 = 0xB8FC, - .luma = 0xb5 + .luma = 0xb5, + .hue = 222, + .chroma = 118 }, { .rgb888 = 0x7beffe, .rgb565 = 0x9F86, - .luma = 0xe0 + .luma = 0xe0, + .hue = 124, + .chroma = 131 }, { .rgb888 = 0x51395f, .rgb565 = 0x0D5A, - .luma = 0x47 + .luma = 0x47, + .hue = 185, + .chroma = 38 }, { .rgb888 = 0xffffff, .rgb565 = 0xffff, - .luma = 0xff + .luma = 0xff, + .chroma = 0 }, { .rgb888 = 0x0736a0, .rgb565 = 0xf501, - .luma = 0x44 + .luma = 0x44, + .hue = 147, + .chroma = 153 }, }; diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 0f6b9014b..65600a195 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -102,12 +102,14 @@ _displayio_color_t terminal_colors[2] = { { .rgb888 = 0x000000, .rgb565 = 0x0000, - .luma = 0x00 + .luma = 0x00, + .chroma = 0 }, { .rgb888 = 0xffffff, .rgb565 = 0xffff, - .luma = 0xff + .luma = 0xff, + .chroma = 0 }, }; -- cgit v1.2.3 From c247e7df9c043dc6a452a6cabc7bf232c0e9e085 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 14 Aug 2019 14:17:35 -0700 Subject: Begin refresh rework. --- ports/atmel-samd/background.c | 2 +- ports/nrf/background.c | 2 +- ports/stm32f4/background.c | 2 +- py/circuitpy_mpconfig.h | 2 +- shared-bindings/displayio/Display.c | 37 ++++++-- shared-bindings/displayio/Display.h | 14 +-- shared-bindings/displayio/EPaperDisplay.c | 45 +++++---- shared-bindings/displayio/EPaperDisplay.h | 9 +- shared-module/displayio/Display.c | 124 ++++++++++++++++++++++++- shared-module/displayio/Display.h | 8 +- shared-module/displayio/EPaperDisplay.c | 71 ++++++++++---- shared-module/displayio/EPaperDisplay.h | 8 +- shared-module/displayio/__init__.c | 149 ++---------------------------- shared-module/displayio/__init__.h | 2 +- 14 files changed, 254 insertions(+), 221 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c index 694238070..386ba0715 100644 --- a/ports/atmel-samd/background.c +++ b/ports/atmel-samd/background.c @@ -60,7 +60,7 @@ void run_background_tasks(void) { audio_dma_background(); #endif #if CIRCUITPY_DISPLAYIO - displayio_refresh_displays(); + displayio_background(); #endif #if CIRCUITPY_NETWORK diff --git a/ports/nrf/background.c b/ports/nrf/background.c index 453bc96df..94411cbce 100644 --- a/ports/nrf/background.c +++ b/ports/nrf/background.c @@ -56,7 +56,7 @@ void run_background_tasks(void) { #endif #if CIRCUITPY_DISPLAYIO - displayio_refresh_displays(); + displayio_background(); #endif running_background_tasks = false; diff --git a/ports/stm32f4/background.c b/ports/stm32f4/background.c index e9872b045..b91c3793e 100644 --- a/ports/stm32f4/background.c +++ b/ports/stm32f4/background.c @@ -49,7 +49,7 @@ void run_background_tasks(void) { //usb_background(); #if CIRCUITPY_DISPLAYIO - displayio_refresh_displays(); + displayio_background(); #endif running_background_tasks = false; diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 393b7600c..c2e2e2d02 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -307,7 +307,7 @@ extern const struct _mp_obj_module_t terminalio_module; #define DISPLAYIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_displayio), (mp_obj_t)&displayio_module }, #define FONTIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_fontio), (mp_obj_t)&fontio_module }, #define TERMINALIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_terminalio), (mp_obj_t)&terminalio_module }, -#define CIRCUITPY_DISPLAY_LIMIT (3) +#define CIRCUITPY_DISPLAY_LIMIT (1) #else #define DISPLAYIO_MODULE #define FONTIO_MODULE diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 0c48b0cc5..fb9bfff85 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -212,27 +212,42 @@ STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) } MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); -//| .. method:: refresh_soon() +//| .. method:: refresh(*, target_frames_per_second=None, minimum_frames_per_second=1) //| -//| Queues up a display refresh that happens in the background. +//| Waits for the target frame rate and then refreshes the display. If the call is too late for the given target frame rate, then the refresh returns immediately without updating the screen to hopefully help getting caught up. If the current frame rate is below the minimum frame rate, then an exception will be raised. //| -STATIC mp_obj_t displayio_display_obj_refresh_soon(mp_obj_t self_in) { +STATIC mp_obj_t displayio_display_obj_refresh(mp_obj_t self_in) { displayio_display_obj_t *self = native_display(self_in); - common_hal_displayio_display_refresh_soon(self); + common_hal_displayio_display_refresh(self); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_refresh_soon_obj, displayio_display_obj_refresh_soon); -//| .. method:: wait_for_frame() +//| .. attribute:: auto_refresh //| -//| Waits until the next frame has been transmitted to the display unless the wait count is -//| behind the rendered frames. In that case, this will return immediately with the wait count. +//| True when the display is refreshed automatically. //| -STATIC mp_obj_t displayio_display_obj_wait_for_frame(mp_obj_t self_in) { +STATIC mp_obj_t displayio_display_obj_get_auto_refresh(mp_obj_t self_in) { displayio_display_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_wait_for_frame(self)); + return mp_obj_new_bool(common_hal_displayio_display_get_auto_refresh(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_wait_for_frame_obj, displayio_display_obj_wait_for_frame); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_refresh_obj, displayio_display_obj_get_auto_refresh); + +STATIC mp_obj_t displayio_display_obj_set_auto_refresh(mp_obj_t self_in, mp_obj_t auto_refresh) { + displayio_display_obj_t *self = native_display(self_in); + + common_hal_displayio_display_set_auto_refresh(self, mp_obj_is_true(auto_refresh)); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_auto_refresh_obj, displayio_display_obj_set_auto_refresh); + +const mp_obj_property_t displayio_display_auto_refresh_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_auto_refresh_obj, + (mp_obj_t)&displayio_display_set_auto_refresh_obj, + (mp_obj_t)&mp_const_none_obj}, +}; //| .. attribute:: brightness //| @@ -442,6 +457,8 @@ STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_display_wait_for_frame_obj) }, { MP_ROM_QSTR(MP_QSTR_fill_row), MP_ROM_PTR(&displayio_display_fill_row_obj) }, + { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&displayio_display_auto_refresh_obj) }, + { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) }, { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) }, diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 8df1adc08..0d416b868 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -44,26 +44,16 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, - mp_float_t brightness, bool auto_brightness, + mp_float_t brightness, bool auto_brightness, bool auto_refresh, uint8_t frames_per_second, bool single_byte_bounds, bool data_as_commands); -int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self); - bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); -void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self); +void common_hal_displayio_display_refresh(displayio_display_obj_t* self); bool displayio_display_begin_transaction(displayio_display_obj_t* self); void displayio_display_end_transaction(displayio_display_obj_t* self); -// The second point of the region is exclusive. -void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area); -bool displayio_display_frame_queued(displayio_display_obj_t* self); - -bool displayio_display_refresh_queued(displayio_display_obj_t* self); -void displayio_display_finish_refresh(displayio_display_obj_t* self); -void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length); - bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index d13d07e4a..4b00240d1 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -51,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the startup and shutdown sequences at minimum. //| -//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, refresh_display_command, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) +//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, highlight_color=0x000000, refresh_display_command, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) //| //| Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -81,7 +81,7 @@ //| :param bool black_bits_inverted: True if 0 bits are used to show black pixels. Otherwise, 1 means to show black. //| :param int write_color_ram_command: Command used to write pixels values into the update region //| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color. -//| :param int third_color: Color of third ePaper color in RGB888. +//| :param int highlight_color: RGB888 of source color to highlight with third ePaper color. //| :param int refresh_display_command: Command used to start a display refresh //| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy //| :param bool busy_state: State of the busy pin when the display is busy @@ -89,7 +89,7 @@ //| :param bool always_toggle_chip_select: When True, chip select is toggled every byte //| STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_third_color, ARG_refresh_display_command, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; + enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_refresh_display_command, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -109,7 +109,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size { MP_QSTR_black_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_write_color_ram_command, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_third_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, + { MP_QSTR_highlight_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, { MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED }, { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, @@ -155,7 +155,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj); mp_int_t write_color_ram_command = NO_COMMAND; - mp_int_t third_color = args[ARG_third_color].u_int; + mp_int_t highlight_color = args[ARG_highlight_color].u_int; if (args[ARG_write_color_ram_command].u_obj != mp_const_none) { write_color_ram_command = mp_obj_get_int(args[ARG_write_color_ram_command].u_obj); } @@ -168,7 +168,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int, args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int, - args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, third_color, args[ARG_refresh_display_command].u_int, + args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool ); @@ -203,27 +203,38 @@ STATIC mp_obj_t displayio_epaperdisplay_obj_show(mp_obj_t self_in, mp_obj_t grou } MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_show_obj, displayio_epaperdisplay_obj_show); -//| .. method:: refresh_soon() +//| .. method:: refresh() //| -//| Queues up a display refresh that happens in the background. +//| Refreshes the display immediately or raises an exception if too soon. Use +//| ``time.sleep(display.time_to_refresh)`` to sleep until a refresh can occur. //| STATIC mp_obj_t displayio_epaperdisplay_obj_refresh_soon(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); - common_hal_displayio_epaperdisplay_refresh_soon(self); + bool ok = common_hal_displayio_epaperdisplay_refresh(self); + if (!ok) { + mp_raise_RuntimeError(translate("Refresh too soon")); + } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_soon_obj, displayio_epaperdisplay_obj_refresh_soon); -//| .. method:: wait_for_frame() +//| .. attribute:: time_to_refresh //| -//| Waits until the next frame has been transmitted to the display unless the wait count is -//| behind the rendered frames. In that case, this will return immediately with the wait count. +//| Time, in fractional seconds, until the ePaper display can be refreshed. //| -STATIC mp_obj_t displayio_epaperdisplay_obj_wait_for_frame(mp_obj_t self_in) { +//| +STATIC mp_obj_t displayio_epaperdisplay_obj_get_time_to_refresh(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_wait_for_frame(self)); + return mp_obj_new_float(common_hal_displayio_epaperdisplay_get_time_to_refresh(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_wait_for_frame_obj, displayio_epaperdisplay_obj_wait_for_frame); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_time_to_refresh_obj, displayio_epaperdisplay_obj_get_time_to_refresh); + +const mp_obj_property_t displayio_epaperdisplay_time_to_refresh_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_time_to_refresh_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; //| .. attribute:: width //| @@ -282,12 +293,12 @@ const mp_obj_property_t displayio_epaperdisplay_bus_obj = { STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_epaperdisplay_show_obj) }, - { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_epaperdisplay_refresh_soon_obj) }, - { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_epaperdisplay_wait_for_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_epaperdisplay_refresh_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) }, + { MP_ROM_QSTR(MP_QSTR_time_to_refresh), MP_ROM_PTR(&displayio_epaperdisplay_time_to_refresh_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_epaperdisplay_locals_dict, displayio_epaperdisplay_locals_dict_table); diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 3deeef959..87feb4da0 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -43,23 +43,24 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, - uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t third_color, uint16_t refresh_display_command, + uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self); bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group); -void common_hal_displayio_epaperdisplay_refresh_soon(displayio_epaperdisplay_obj_t* self); - bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self); void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self); +bool displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); + +mp_float_t displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); + // The second point of the region is exclusive. void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area); bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self); -bool displayio_epaperdisplay_refresh_queued(displayio_epaperdisplay_obj_t* self); void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self); void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 97a18740a..fafb35f43 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -221,10 +221,6 @@ bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_ return true; } -void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self) { - self->refresh = true; -} - const displayio_area_t* displayio_display_get_refresh_areas(displayio_display_obj_t *self) { if (self->full_refresh) { self->area.next = NULL; @@ -246,6 +242,118 @@ int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* sel return 0; } +STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area) { + uint16_t buffer_size = 128; // In uint32_ts + + displayio_area_t clipped; + // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. + if (!displayio_display_clip_area(display, area, &clipped)) { + return true; + } + uint16_t subrectangles = 1; + uint16_t rows_per_buffer = displayio_area_height(&clipped); + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / display->colorspace.depth; + uint16_t pixels_per_buffer = displayio_area_size(&clipped); + if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { + rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary. + if (display->colorspace.depth < 8 && !display->colorspace.pixels_in_byte_share_row) { + uint8_t pixels_per_byte = 8 / display->colorspace.depth; + if (rows_per_buffer % pixels_per_byte != 0) { + rows_per_buffer -= rows_per_buffer % pixels_per_byte; + } + } + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + } + + // Allocated and shared as a uint32_t array so the compiler knows the + // alignment everywhere. + uint32_t buffer[buffer_size]; + volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask[mask_length]; + uint16_t remaining_rows = displayio_area_height(&clipped); + + for (uint16_t j = 0; j < subrectangles; j++) { + displayio_area_t subrectangle = { + .x1 = clipped.x1, + .y1 = clipped.y1 + rows_per_buffer * j, + .x2 = clipped.x2, + .y2 = clipped.y1 + rows_per_buffer * (j + 1) + }; + if (remaining_rows < rows_per_buffer) { + subrectangle.y2 = subrectangle.y1 + remaining_rows; + } + remaining_rows -= rows_per_buffer; + + displayio_display_begin_transaction(display); + displayio_display_set_region_to_update(display, &subrectangle); + displayio_display_end_transaction(display); + + uint16_t subrectangle_size_bytes; + if (display->colorspace.depth >= 8) { + subrectangle_size_bytes = displayio_area_size(&subrectangle) * (display->colorspace.depth / 8); + } else { + subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / display->colorspace.depth); + } + + for (uint16_t k = 0; k < mask_length; k++) { + mask[k] = 0x00000000; + } + for (uint16_t k = 0; k < buffer_size; k++) { + buffer[k] = 0x00000000; + } + + displayio_display_fill_area(display, &subrectangle, mask, buffer); + + if (!displayio_display_begin_transaction(display)) { + // Can't acquire display bus; skip the rest of the data. Try next display. + return false; + } + displayio_display_send_pixels(display, (uint8_t*) buffer, subrectangle_size_bytes); + displayio_display_end_transaction(display); + + // TODO(tannewt): Make refresh displays faster so we don't starve other + // background tasks. + usb_background(); + } + return true; +} + +STATIC void refresh_display(displayio_display_obj_t* self) { + if (!displayio_display_begin_transaction(self)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + displayio_display_end_transaction(self); + displayio_display_start_refresh(self); + const displayio_area_t* current_area = displayio_display_get_refresh_areas(self); + while (current_area != NULL) { + refresh_area(self, current_area); + current_area = current_area->next; + } + displayio_display_finish_refresh(self); +} + +void common_hal_displayio_display_refresh(displayio_display_obj_t* self) { + // Time to refresh at specified frame rate? + while (!displayio_display_frame_queued(self)) { + // Too soon. Try next display. + continue; + } + refresh_display(self); +} + bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self) { return self->auto_brightness; } @@ -411,6 +519,14 @@ void displayio_display_update_backlight(displayio_display_obj_t* self) { self->last_backlight_refresh = ticks_ms; } +void displayio_display_background(displayio_display_obj_t* self) { + displayio_display_update_backlight(self); + + if (self->auto_refresh && (ticks_ms - self->last_refresh) > 16) { + display_refresh(self); + } +} + void release_display(displayio_display_obj_t* self) { if (self->current_group != NULL) { self->current_group->in_group = false; diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index c85d69b0e..db0a23012 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -63,7 +63,7 @@ typedef struct { uint8_t set_column_command; uint8_t set_row_command; uint8_t write_ram_command; - bool refresh; + bool auto_refresh; bool single_byte_bounds; bool data_as_commands; bool auto_brightness; @@ -71,11 +71,7 @@ typedef struct { bool full_refresh; // New group means we need to refresh the whole display. } displayio_display_obj_t; -void displayio_display_start_refresh(displayio_display_obj_t* self); -const displayio_area_t* displayio_display_get_refresh_areas(displayio_display_obj_t *self); -bool displayio_display_fill_area(displayio_display_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer); -void displayio_display_update_backlight(displayio_display_obj_t* self); -bool displayio_display_clip_area(displayio_display_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped); +void displayio_display_background(displayio_display_obj_t* self); void release_display(displayio_display_obj_t* self); #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_H diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 5e4bdc340..434adbdf4 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -48,7 +48,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, - uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t third_color, uint16_t refresh_display_command, + uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select) { self->colorspace.depth = 1; self->colorspace.grayscale = true; @@ -56,10 +56,10 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->colorspace.bytes_per_cell = 1; self->colorspace.reverse_pixels_in_byte = true; - if (third_color != 0x000000) { + if (highlight_color != 0x000000) { self->colorspace.tricolor = true; - self->colorspace.tricolor_hue = displayio_colorconverter_compute_hue(third_color); - self->colorspace.tricolor_luma = displayio_colorconverter_compute_luma(third_color); + self->colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); + self->colorspace.tricolor_luma = displayio_colorconverter_compute_luma(highlight_color); } self->set_column_window_command = set_column_window_command; @@ -174,6 +174,11 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* never_reset_pin_number(busy_pin->number); } + // Clear the color memory if it isn't in use. + if (highlight_color == 0x00 && write_color_ram_command != NO_COMMAND) { + // TODO: Clear + } + // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_epaperdisplay_show(self, &circuitpython_splash); @@ -198,14 +203,9 @@ bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self self->current_group = root_group; } self->full_refresh = true; - common_hal_displayio_epaperdisplay_refresh_soon(self); return true; } -void common_hal_displayio_epaperdisplay_refresh_soon(displayio_epaperdisplay_obj_t* self) { - self->refresh = true; -} - const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self) { const displayio_area_t* first_area; if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { @@ -359,21 +359,23 @@ void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self) self->last_refresh = ticks_ms; } -bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self) { +void displayio_epaperdisplay_background_task(displayio_epaperdisplay_obj_t* self) { if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { self->refreshing = false; // Run stop sequence but don't wait for busy because busy is set when sleeping. send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); - } else { - return false; } } - if (self->current_group == NULL) { - return false; - } +} + +uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self) { // Refresh at seconds per frame rate. - return (ticks_ms - self->last_refresh) > self->milliseconds_per_frame; + uint32_t elapsed_time = ticks_ms - self->last_refresh; + if (elapsed_time > self->milliseconds_per_frame) { + return 0; + } + return self->milliseconds_per_frame - elapsed_time; } void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { @@ -394,7 +396,6 @@ void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length) { } - bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, const displayio_area_t* area) { uint16_t buffer_size = 128; // In uint32_ts @@ -500,6 +501,42 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c return true; } +bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self) { + + if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { + if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { + self->refreshing = false; + // Run stop sequence but don't wait for busy because busy is set when sleeping. + send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); + } else { + return false; + } + } + if (self->current_group == NULL) { + return false; + } + // Refresh at seconds per frame rate. + if (ticks_ms - self->last_refresh) > self->milliseconds_per_frame; + + if (displayio_epaperdisplay_get_time_to_refresh(display) > 0) { + return false; + } + if (!displayio_epaperdisplay_bus_free(display)) { + // Can't acquire display bus; skip updating this display. Try next display. + continue; + } + const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(display); + if (current_area == NULL) { + continue; + } + displayio_epaperdisplay_start_refresh(display); + while (current_area != NULL) { + displayio_epaperdisplay_refresh_area(display, current_area); + current_area = current_area->next; + } + displayio_epaperdisplay_finish_refresh(display); +} + void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { if (self->current_group != NULL) { self->current_group->in_group = false; diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 737b5987a..cc7db6f6d 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -75,18 +75,12 @@ typedef struct { bool busy_state; bool black_bits_inverted; bool color_bits_inverted; - bool refresh; bool refreshing; bool full_refresh; // New group means we need to refresh the whole display. bool always_toggle_chip_select; } displayio_epaperdisplay_obj_t; -bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* display, const displayio_area_t* area); -void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self); -const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self); -bool displayio_epaperdisplay_fill_area(displayio_epaperdisplay_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer); -bool displayio_epaperdisplay_clip_area(displayio_epaperdisplay_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped); -bool displayio_epaperdisplay_bus_free(displayio_epaperdisplay_obj_t *self); +void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); void release_epaperdisplay(displayio_epaperdisplay_obj_t* self); #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index a8f888654..0ebed58c2 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -19,100 +19,11 @@ #include "supervisor/usb.h" primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; -uint32_t frame_count = 0; -bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area) { - uint16_t buffer_size = 128; // In uint32_ts +// Check for recursive calls to displayio_background. +bool displayio_background_in_progress = false; - displayio_area_t clipped; - // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. - if (!displayio_display_clip_area(display, area, &clipped)) { - return true; - } - uint16_t subrectangles = 1; - uint16_t rows_per_buffer = displayio_area_height(&clipped); - uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / display->colorspace.depth; - uint16_t pixels_per_buffer = displayio_area_size(&clipped); - if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { - rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); - if (rows_per_buffer == 0) { - rows_per_buffer = 1; - } - // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary. - if (display->colorspace.depth < 8 && !display->colorspace.pixels_in_byte_share_row) { - uint8_t pixels_per_byte = 8 / display->colorspace.depth; - if (rows_per_buffer % pixels_per_byte != 0) { - rows_per_buffer -= rows_per_buffer % pixels_per_byte; - } - } - subrectangles = displayio_area_height(&clipped) / rows_per_buffer; - if (displayio_area_height(&clipped) % rows_per_buffer != 0) { - subrectangles++; - } - pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); - buffer_size = pixels_per_buffer / pixels_per_word; - if (pixels_per_buffer % pixels_per_word) { - buffer_size += 1; - } - } - - // Allocated and shared as a uint32_t array so the compiler knows the - // alignment everywhere. - uint32_t buffer[buffer_size]; - volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; - uint32_t mask[mask_length]; - uint16_t remaining_rows = displayio_area_height(&clipped); - - for (uint16_t j = 0; j < subrectangles; j++) { - displayio_area_t subrectangle = { - .x1 = clipped.x1, - .y1 = clipped.y1 + rows_per_buffer * j, - .x2 = clipped.x2, - .y2 = clipped.y1 + rows_per_buffer * (j + 1) - }; - if (remaining_rows < rows_per_buffer) { - subrectangle.y2 = subrectangle.y1 + remaining_rows; - } - remaining_rows -= rows_per_buffer; - - displayio_display_begin_transaction(display); - displayio_display_set_region_to_update(display, &subrectangle); - displayio_display_end_transaction(display); - - uint16_t subrectangle_size_bytes; - if (display->colorspace.depth >= 8) { - subrectangle_size_bytes = displayio_area_size(&subrectangle) * (display->colorspace.depth / 8); - } else { - subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / display->colorspace.depth); - } - - for (uint16_t k = 0; k < mask_length; k++) { - mask[k] = 0x00000000; - } - for (uint16_t k = 0; k < buffer_size; k++) { - buffer[k] = 0x00000000; - } - - displayio_display_fill_area(display, &subrectangle, mask, buffer); - - if (!displayio_display_begin_transaction(display)) { - // Can't acquire display bus; skip the rest of the data. Try next display. - return false; - } - displayio_display_send_pixels(display, (uint8_t*) buffer, subrectangle_size_bytes); - displayio_display_end_transaction(display); - - // TODO(tannewt): Make refresh displays faster so we don't starve other - // background tasks. - usb_background(); - } - return true; -} - -// Check for recursive calls to displayio_refresh_displays. -bool refresh_displays_in_progress = false; - -void displayio_refresh_displays(void) { +void displayio_background(void) { if (mp_hal_is_interrupted()) { return; } @@ -121,12 +32,12 @@ void displayio_refresh_displays(void) { return; } - if (refresh_displays_in_progress) { + if (displayio_background_in_progress) { // Don't allow recursive calls to this routine. return; } - refresh_displays_in_progress = true; + displayio_background_in_progress = true; for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display.base.type == NULL || displays[i].display.base.type == &mp_type_NoneType) { @@ -134,54 +45,14 @@ void displayio_refresh_displays(void) { continue; } if (displays[i].display.base.type == &displayio_display_type) { - displayio_display_obj_t* display = &displays[i].display; - displayio_display_update_backlight(display); - - // Time to refresh at specified frame rate? - if (!displayio_display_frame_queued(display)) { - // Too soon. Try next display. - continue; - } - if (!displayio_display_begin_transaction(display)) { - // Can't acquire display bus; skip updating this display. Try next display. - continue; - } - displayio_display_end_transaction(display); - displayio_display_start_refresh(display); - const displayio_area_t* current_area = displayio_display_get_refresh_areas(display); - while (current_area != NULL) { - refresh_area(display, current_area); - current_area = current_area->next; - } - displayio_display_finish_refresh(display); - } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { - displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; - // Time to refresh at specified frame rate? - if (!displayio_epaperdisplay_frame_queued(display)) { - // Too soon. Try next display. - continue; - } - if (!displayio_epaperdisplay_bus_free(display)) { - // Can't acquire display bus; skip updating this display. Try next display. - continue; - } - const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(display); - if (current_area == NULL) { - continue; - } - displayio_epaperdisplay_start_refresh(display); - while (current_area != NULL) { - displayio_epaperdisplay_refresh_area(display, current_area); - current_area = current_area->next; - } - displayio_epaperdisplay_finish_refresh(display); + displayio_display_background(&displays[i].display); + } else if (displays[i].epaperdisplay.base.type == &displayio_epaperdisplay_type) { + displayio_epaperdisplay_background(&displays[i].epaperdisplay); } - - frame_count++; } // All done. - refresh_displays_in_progress = false; + displayio_background_in_progress = false; } void common_hal_displayio_release_displays(void) { @@ -245,7 +116,7 @@ void reset_displays(void) { ((uint32_t) i2c->bus) > ((uint32_t) &displays + CIRCUITPY_DISPLAY_LIMIT)) { busio_i2c_obj_t* original_i2c = i2c->bus; #if BOARD_I2C - // We don't need to move original_i2c if it is the board.SPI object because it is + // We don't need to move original_i2c if it is the board.I2C object because it is // statically allocated already. (Doing so would also make it impossible to reference in // a subsequent VM run.) if (original_i2c == common_hal_board_get_i2c()) { diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index 95eefbdd9..e78bc61ce 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -50,7 +50,7 @@ extern primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; extern displayio_group_t circuitpython_splash; -void displayio_refresh_displays(void); +void displayio_background(void); void reset_displays(void); void displayio_gc_collect(void); -- cgit v1.2.3 From 36a23e0fe3914b43645e51bf23a4d8bfec2db2c9 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 16 Aug 2019 18:34:00 -0700 Subject: Rework refresh API and factor common display stuff out NOT TESTED! Just compiles Fixes #1691 --- ports/atmel-samd/Makefile | 3 +- .../atmel-samd/boards/hallowing_m0_express/board.c | 4 +- ports/atmel-samd/boards/pybadge/board.c | 4 +- ports/atmel-samd/boards/pybadge_airlift/board.c | 4 +- ports/atmel-samd/boards/pygamer/board.c | 4 +- ports/atmel-samd/boards/pygamer_advance/board.c | 4 +- ports/atmel-samd/boards/pyportal/board.c | 4 +- ports/atmel-samd/boards/pyportal_titano/board.c | 4 +- ports/nrf/Makefile | 3 +- ports/stm32f4/Makefile | 3 +- py/circuitpy_defns.mk | 6 + shared-bindings/_stage/__init__.c | 10 +- shared-bindings/displayio/Display.c | 54 ++- shared-bindings/displayio/Display.h | 23 +- shared-bindings/displayio/EPaperDisplay.c | 10 +- shared-bindings/displayio/EPaperDisplay.h | 19 +- shared-module/_stage/__init__.c | 4 +- shared-module/displayio/Display.c | 479 +++++++-------------- shared-module/displayio/Display.h | 27 +- shared-module/displayio/EPaperDisplay.c | 350 +++------------ shared-module/displayio/EPaperDisplay.h | 28 +- shared-module/displayio/__init__.c | 10 +- shared-module/displayio/display_core.c | 309 +++++++++++++ shared-module/displayio/display_core.h | 90 ++++ 24 files changed, 726 insertions(+), 730 deletions(-) create mode 100644 shared-module/displayio/display_core.c create mode 100644 shared-module/displayio/display_core.h (limited to 'shared-module') diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 8e3fe9460..11e6874ed 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -289,7 +289,8 @@ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix common-hal/, $(SRC_COMMON_HAL)) SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ - $(addprefix shared-module/, $(SRC_SHARED_MODULE)) + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL)) SRC_S = supervisor/$(CHIP_FAMILY)_cpu.s diff --git a/ports/atmel-samd/boards/hallowing_m0_express/board.c b/ports/atmel-samd/boards/hallowing_m0_express/board.c index c12431f8b..b4c54062f 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m0_express/board.c @@ -106,7 +106,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pybadge/board.c b/ports/atmel-samd/boards/pybadge/board.c index e30b901b0..37f7991d1 100644 --- a/ports/atmel-samd/boards/pybadge/board.c +++ b/ports/atmel-samd/boards/pybadge/board.c @@ -108,7 +108,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pybadge_airlift/board.c b/ports/atmel-samd/boards/pybadge_airlift/board.c index 38fb33886..7622de6f0 100644 --- a/ports/atmel-samd/boards/pybadge_airlift/board.c +++ b/ports/atmel-samd/boards/pybadge_airlift/board.c @@ -86,7 +86,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pygamer/board.c b/ports/atmel-samd/boards/pygamer/board.c index 5ccf3fc50..b33ae4fb0 100644 --- a/ports/atmel-samd/boards/pygamer/board.c +++ b/ports/atmel-samd/boards/pygamer/board.c @@ -108,7 +108,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pygamer_advance/board.c b/ports/atmel-samd/boards/pygamer_advance/board.c index 72d4dda8d..8eb501243 100644 --- a/ports/atmel-samd/boards/pygamer_advance/board.c +++ b/ports/atmel-samd/boards/pygamer_advance/board.c @@ -86,7 +86,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pyportal/board.c b/ports/atmel-samd/boards/pyportal/board.c index a5de1d145..2a7289778 100644 --- a/ports/atmel-samd/boards/pyportal/board.c +++ b/ports/atmel-samd/boards/pyportal/board.c @@ -98,7 +98,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pyportal_titano/board.c b/ports/atmel-samd/boards/pyportal_titano/board.c index 0ed1010a1..a18bb380b 100644 --- a/ports/atmel-samd/boards/pyportal_titano/board.c +++ b/ports/atmel-samd/boards/pyportal_titano/board.c @@ -118,7 +118,9 @@ void board_init(void) { 1.0f, // brightness (ignored) true, // auto_brightness false, // single_byte_bounds - false); // data_as_commands + false, // data_as_commands + true, // auto_refresh + 60); // native_frames_per_second } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile index 9a461f9d8..6ec160088 100755 --- a/ports/nrf/Makefile +++ b/ports/nrf/Makefile @@ -192,7 +192,8 @@ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix common-hal/, $(SRC_COMMON_HAL)) SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ - $(addprefix shared-module/, $(SRC_SHARED_MODULE)) + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL)) SRC_S = supervisor/cpu.s diff --git a/ports/stm32f4/Makefile b/ports/stm32f4/Makefile index 7f0744443..c75a6c7ee 100755 --- a/ports/stm32f4/Makefile +++ b/ports/stm32f4/Makefile @@ -216,7 +216,8 @@ SRC_COMMON_HAL_EXPANDED = $(addprefix shared-bindings/, $(SRC_COMMON_HAL)) \ $(addprefix common-hal/, $(SRC_COMMON_HAL)) SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \ - $(addprefix shared-module/, $(SRC_SHARED_MODULE)) + $(addprefix shared-module/, $(SRC_SHARED_MODULE)) \ + $(addprefix shared-module/, $(SRC_SHARED_MODULE_INTERNAL)) diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index d0f0cf7dc..e7b917512 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -364,6 +364,12 @@ SRC_SHARED_MODULE_ALL += \ touchio/__init__.c endif +# All possible sources are listed here, and are filtered by SRC_PATTERNS. +SRC_SHARED_MODULE_INTERNAL = \ +$(filter $(SRC_PATTERNS), \ + displayio/display_core.c \ +) + ifeq ($(INTERNAL_LIBM),1) SRC_LIBM = \ $(addprefix lib/,\ diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 6096f6b6d..1d970cce4 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -30,6 +30,7 @@ #include "shared-bindings/busio/SPI.h" #include "shared-bindings/displayio/Display.h" #include "shared-module/_stage/__init__.h" +#include "shared-module/displayio/display_core.h" #include "Layer.h" #include "Text.h" @@ -95,7 +96,8 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { scale = mp_obj_get_int(args[7]); } - while (!displayio_display_begin_transaction(display)) { + // TODO: Everything below should be in shared-module because it's not argument parsing. + while (!displayio_display_core_begin_transaction(&display->core)) { RUN_BACKGROUND_TASKS; } displayio_area_t area; @@ -103,12 +105,12 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { area.y1 = y0; area.x2 = x1; area.y2 = y1; - displayio_display_set_region_to_update(display, &area); + displayio_display_core_set_region_to_update(&display->core, display->set_column_command, display->set_row_command, NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area); - display->send(display->bus, true, &display->write_ram_command, 1); + display->core.send(display->core.bus, true, true, &display->write_ram_command, 1); render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display, scale); - displayio_display_end_transaction(display); + displayio_display_core_end_transaction(&display->core); return mp_const_none; } diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index fb9bfff85..ded4119ca 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -51,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the initialization sequence at minimum. //| -//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, bytes_per_cell=1, reverse_pixels_in_byte=False, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) +//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, bytes_per_cell=1, reverse_pixels_in_byte=False, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False, auto_refresh=True, native_frames_per_second=60) //| //| Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -102,9 +102,11 @@ //| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. //| :param bool single_byte_bounds: Display column and row commands use single bytes //| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. +//| :param bool auto_refresh: Automatically refresh the screen +//| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence. //| STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -128,6 +130,8 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_data_as_commands, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -178,7 +182,9 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a brightness, args[ARG_auto_brightness].u_bool, args[ARG_single_byte_bounds].u_bool, - args[ARG_data_as_commands].u_bool + args[ARG_data_as_commands].u_bool, + args[ARG_auto_refresh].u_bool, + args[ARG_native_frames_per_second].u_int ); return self; @@ -214,14 +220,28 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| .. method:: refresh(*, target_frames_per_second=None, minimum_frames_per_second=1) //| -//| Waits for the target frame rate and then refreshes the display. If the call is too late for the given target frame rate, then the refresh returns immediately without updating the screen to hopefully help getting caught up. If the current frame rate is below the minimum frame rate, then an exception will be raised. +//| When auto refresh is off, waits for the target frame rate and then refreshes the display. If +//| the call is too late for the given target frame rate, then the refresh returns immediately +//| without updating the screen to hopefully help getting caught up. If the current frame rate +//| is below the minimum frame rate, then an exception will be raised. //| -STATIC mp_obj_t displayio_display_obj_refresh(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - common_hal_displayio_display_refresh(self); +//| When auto refresh is on, updates the display immediately. (The display will also update +//| without calls to this.) +//| +STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} }, + { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + displayio_display_obj_t *self = native_display(pos_args[0]); + common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, 1000 / args[ARG_minimum_frames_per_second].u_int); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_refresh_soon_obj, displayio_display_obj_refresh_soon); +MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh); //| .. attribute:: auto_refresh //| @@ -376,7 +396,7 @@ const mp_obj_property_t displayio_display_rotation_obj = { //| STATIC mp_obj_t displayio_display_obj_get_bus(mp_obj_t self_in) { displayio_display_obj_t *self = native_display(self_in); - return self->bus; + return common_hal_displayio_display_get_bus(self); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_bus_obj, displayio_display_obj_get_bus); @@ -412,18 +432,18 @@ STATIC mp_obj_t displayio_display_obj_fill_row(size_t n_args, const mp_obj_t *po if (bufinfo.typecode != BYTEARRAY_TYPECODE) { mp_raise_ValueError(translate("Buffer is not a bytearray.")); } - if (self->colorspace.depth != 16) { + if (self->core.colorspace.depth != 16) { mp_raise_ValueError(translate("Display must have a 16 bit colorspace.")); } displayio_area_t area = { .x1 = 0, .y1 = y, - .x2 = self->width, + .x2 = self->core.width, .y2 = y + 1 }; - uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->colorspace.depth; - uint16_t buffer_size = self->width / pixels_per_word; + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; + uint16_t buffer_size = self->core.width / pixels_per_word; uint16_t pixels_per_buffer = displayio_area_size(&area); if (pixels_per_buffer % pixels_per_word) { buffer_size += 1; @@ -440,7 +460,7 @@ STATIC mp_obj_t displayio_display_obj_fill_row(size_t n_args, const mp_obj_t *po mask[k] = 0x00000000; } - displayio_display_fill_area(self, &area, mask, result_buffer); + displayio_display_core_fill_area(&self->core, &area, mask, result_buffer); return result; } else { mp_raise_ValueError(translate("Buffer is too small")); @@ -448,13 +468,9 @@ STATIC mp_obj_t displayio_display_obj_fill_row(size_t n_args, const mp_obj_t *po } MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_fill_row_obj, 1, displayio_display_obj_fill_row); - - - STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_display_show_obj) }, - { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_display_refresh_soon_obj) }, - { MP_ROM_QSTR(MP_QSTR_wait_for_frame), MP_ROM_PTR(&displayio_display_wait_for_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&displayio_display_refresh_obj) }, { MP_ROM_QSTR(MP_QSTR_fill_row), MP_ROM_PTR(&displayio_display_fill_row_obj) }, { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&displayio_display_auto_refresh_obj) }, diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 0d416b868..06c848d0d 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -44,24 +44,29 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, - mp_float_t brightness, bool auto_brightness, bool auto_refresh, uint8_t frames_per_second, - bool single_byte_bounds, bool data_as_commands); + mp_float_t brightness, bool auto_brightness, + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second); -bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); +bool common_hal_displayio_display_show(displayio_display_obj_t* self, + displayio_group_t* root_group); -void common_hal_displayio_display_refresh(displayio_display_obj_t* self); +// Times in ms. +void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time); -bool displayio_display_begin_transaction(displayio_display_obj_t* self); -void displayio_display_end_transaction(displayio_display_obj_t* self); - -bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); -void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); +bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self); +void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, bool auto_refresh); uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self); uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self); uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self); +bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); +void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); + mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self); bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness); +mp_obj_t common_hal_displayio_display_get_bus(displayio_display_obj_t* self); + + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_DISPLAY_H diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 4b00240d1..8f3c16efd 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -208,7 +208,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_show_obj, displayio_epaperdisp //| Refreshes the display immediately or raises an exception if too soon. Use //| ``time.sleep(display.time_to_refresh)`` to sleep until a refresh can occur. //| -STATIC mp_obj_t displayio_epaperdisplay_obj_refresh_soon(mp_obj_t self_in) { +STATIC mp_obj_t displayio_epaperdisplay_obj_refresh(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); bool ok = common_hal_displayio_epaperdisplay_refresh(self); if (!ok) { @@ -216,7 +216,7 @@ STATIC mp_obj_t displayio_epaperdisplay_obj_refresh_soon(mp_obj_t self_in) { } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_soon_obj, displayio_epaperdisplay_obj_refresh_soon); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_obj, displayio_epaperdisplay_obj_refresh); //| .. attribute:: time_to_refresh //| @@ -225,7 +225,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_refresh_soon_obj, displayio_ep //| STATIC mp_obj_t displayio_epaperdisplay_obj_get_time_to_refresh(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); - return mp_obj_new_float(common_hal_displayio_epaperdisplay_get_time_to_refresh(self)); + return mp_obj_new_float(common_hal_displayio_epaperdisplay_get_time_to_refresh(self) / 1000.0); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_time_to_refresh_obj, displayio_epaperdisplay_obj_get_time_to_refresh); @@ -279,7 +279,7 @@ const mp_obj_property_t displayio_epaperdisplay_height_obj = { //| STATIC mp_obj_t displayio_epaperdisplay_obj_get_bus(mp_obj_t self_in) { displayio_epaperdisplay_obj_t *self = native_display(self_in); - return self->bus; + return common_hal_displayio_epaperdisplay_get_bus(self); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_bus_obj, displayio_epaperdisplay_obj_get_bus); @@ -293,7 +293,7 @@ const mp_obj_property_t displayio_epaperdisplay_bus_obj = { STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_epaperdisplay_show_obj) }, - { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_epaperdisplay_refresh_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&displayio_epaperdisplay_refresh_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 87feb4da0..2a3cb921f 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -46,23 +46,12 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); -int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self); +bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group); -bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self); -void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self); - -bool displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); - -mp_float_t displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); - -// The second point of the region is exclusive. -void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area); -bool displayio_epaperdisplay_frame_queued(displayio_epaperdisplay_obj_t* self); - -void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self); -void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length); +// Returns time in milliseconds. +uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); bool common_hal_displayio_epaperdisplay_get_auto_brightness(displayio_epaperdisplay_obj_t* self); void common_hal_displayio_epaperdisplay_set_auto_brightness(displayio_epaperdisplay_obj_t* self, bool auto_brightness); @@ -73,4 +62,6 @@ uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_o mp_float_t common_hal_displayio_epaperdisplay_get_brightness(displayio_epaperdisplay_obj_t* self); bool common_hal_displayio_epaperdisplay_set_brightness(displayio_epaperdisplay_obj_t* self, mp_float_t brightness); +mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index ca71b758e..bfef165e7 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -57,7 +57,7 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, index += 1; // The buffer is full, send it. if (index >= buffer_size) { - display->send(display->bus, false, ((uint8_t*)buffer), + display->core.send(display->core.bus, false, false, ((uint8_t*)buffer), buffer_size * 2); index = 0; } @@ -67,6 +67,6 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, } // Send the remaining data. if (index) { - display->send(display->bus, false, ((uint8_t*)buffer), index * 2); + display->core.send(display->core.bus, false, false, ((uint8_t*)buffer), index * 2); } } diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index fafb35f43..86800328f 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -33,7 +33,9 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" #include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/display_core.h" #include "supervisor/shared/display.h" +#include "supervisor/usb.h" #include #include @@ -41,48 +43,34 @@ #include "tick.h" void common_hal_displayio_display_construct(displayio_display_obj_t* self, - mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, - uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, - uint8_t set_column_command, uint8_t set_row_command, - uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, - const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands) { - self->colorspace.depth = color_depth; - self->colorspace.grayscale = grayscale; - self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row; - self->colorspace.bytes_per_cell = bytes_per_cell; - self->colorspace.reverse_pixels_in_byte = reverse_pixels_in_byte; + mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, + uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, + uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, + uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, + uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, + uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second) { + uint16_t ram_width = 0x100; + uint16_t ram_height = 0x100; + if (single_byte_bounds) { + ram_width = 0xff; + ram_height = 0xff; + } + displayio_display_core_construct(&self->core, bus, width, height, ram_width, ram_height, colstart, rowstart, rotation, + color_depth, grayscale, pixels_in_byte_share_row, bytes_per_cell, reverse_pixels_in_byte); + self->set_column_command = set_column_command; self->set_row_command = set_row_command; self->write_ram_command = write_ram_command; - self->refresh = false; - self->current_group = NULL; - self->colstart = colstart; - self->rowstart = rowstart; self->brightness_command = brightness_command; self->auto_brightness = auto_brightness; self->data_as_commands = data_as_commands; - self->single_byte_bounds = single_byte_bounds; - - if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { - self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; - self->send = common_hal_displayio_parallelbus_send; - self->end_transaction = common_hal_displayio_parallelbus_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { - self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; - self->send = common_hal_displayio_fourwire_send; - self->end_transaction = common_hal_displayio_fourwire_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { - self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; - self->send = common_hal_displayio_i2cdisplay_send; - self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; - } else { - mp_raise_ValueError(translate("Unsupported display bus type")); - } - self->bus = bus; + + self->native_frames_per_second = native_frames_per_second; + self->native_frame_time = 1000 / native_frames_per_second; uint32_t i = 0; - while (!self->begin_transaction(self->bus)) { + while (!displayio_display_core_begin_transaction(&self->core)) { RUN_BACKGROUND_TASKS; } while (i < init_sequence_len) { @@ -95,10 +83,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t full_command[data_size + 1]; full_command[0] = cmd[0]; memcpy(full_command + 1, data, data_size); - self->send(self->bus, true, true, full_command, data_size + 1); + self->core.send(self->core.bus, true, true, full_command, data_size + 1); } else { - self->send(self->bus, true, true, cmd, 1); - self->send(self->bus, false, false, data, data_size); + self->core.send(self->core.bus, true, true, cmd, 1); + self->core.send(self->core.bus, false, false, data, data_size); } uint16_t delay_length_ms = 10; if (delay) { @@ -111,33 +99,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, common_hal_time_delay_ms(delay_length_ms); i += 2 + data_size; } - self->end_transaction(self->bus); + self->core.end_transaction(self->core.bus); supervisor_start_terminal(width, height); - self->width = width; - self->height = height; - self->rotation = rotation % 360; - self->transform.x = 0; - self->transform.y = 0; - self->transform.scale = 1; - self->transform.mirror_x = false; - self->transform.mirror_y = false; - self->transform.transpose_xy = false; - if (rotation == 0 || rotation == 180) { - if (rotation == 180) { - self->transform.mirror_x = true; - self->transform.mirror_y = true; - } - } else { - self->transform.transpose_xy = true; - if (rotation == 270) { - self->transform.mirror_y = true; - } else { - self->transform.mirror_x = true; - } - } - // Always set the backlight type in case we're reusing memory. self->backlight_inout.base.type = &mp_type_NoneType; if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { @@ -158,101 +123,98 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->current_brightness = -1.0; } - self->area.x1 = 0; - self->area.y1 = 0; - self->area.next = NULL; - - self->transform.dx = 1; - self->transform.dy = 1; - if (self->transform.transpose_xy) { - self->area.x2 = height; - self->area.y2 = width; - if (self->transform.mirror_x) { - self->transform.x = height; - self->transform.dx = -1; - } - if (self->transform.mirror_y) { - self->transform.y = width; - self->transform.dy = -1; - } - } else { - self->area.x2 = width; - self->area.y2 = height; - if (self->transform.mirror_x) { - self->transform.x = width; - self->transform.dx = -1; - } - if (self->transform.mirror_y) { - self->transform.y = height; - self->transform.dy = -1; - } - } - // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_display_show(self, &circuitpython_splash); } bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { - if (root_group == NULL) { - if (!circuitpython_splash.in_group) { - root_group = &circuitpython_splash; - } else if (self->current_group == &circuitpython_splash) { - return false; + return displayio_display_core_show(&self->core, root_group); +} + +uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self){ + return displayio_display_core_get_width(&self->core); +} + +uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self){ + return displayio_display_core_get_height(&self->core); +} + +bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self) { + return self->auto_brightness; +} + +void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness) { + self->auto_brightness = auto_brightness; +} + +mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self) { + return self->current_brightness; +} + +bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness) { + self->updating_backlight = true; + bool ok = false; + if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { + common_hal_pulseio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t) (0xffff * brightness)); + ok = true; + } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); + ok = true; + } else if (self->brightness_command != NO_BRIGHTNESS_COMMAND) { + ok = displayio_display_core_begin_transaction(&self->core); + if (ok) { + if (self->data_as_commands) { + uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; + self->core.send(self->core.bus, true, true, set_brightness, 2); + } else { + uint8_t command = self->brightness_command; + uint8_t hex_brightness = 0xff * brightness; + self->core.send(self->core.bus, true, true, &command, 1); + self->core.send(self->core.bus, false, false, &hex_brightness, 1); + } + displayio_display_core_end_transaction(&self->core); } + } - if (root_group == self->current_group) { - return true; - } - if (root_group != NULL && root_group->in_group) { - return false; - } - if (self->current_group != NULL) { - self->current_group->in_group = false; + self->updating_backlight = false; + if (ok) { + self->current_brightness = brightness; } + return ok; +} - if (root_group != NULL) { - displayio_group_update_transform(root_group, &self->transform); - root_group->in_group = true; - } - self->current_group = root_group; - self->full_refresh = true; - common_hal_displayio_display_refresh_soon(self); - return true; +mp_obj_t common_hal_displayio_display_get_bus(displayio_display_obj_t* self) { + return self->core.bus; } -const displayio_area_t* displayio_display_get_refresh_areas(displayio_display_obj_t *self) { - if (self->full_refresh) { - self->area.next = NULL; - return &self->area; +STATIC const displayio_area_t* _get_refresh_areas(displayio_display_obj_t *self) { + if (self->core.full_refresh) { + self->core.area.next = NULL; + return &self->core.area; } else { - if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { - asm("bkpt"); - } - return displayio_group_get_refresh_areas(self->current_group, NULL); + return displayio_group_get_refresh_areas(self->core.current_group, NULL); } } -int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self) { - uint64_t last_refresh = self->last_refresh; - // Don't try to refresh if we got an exception. - while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { - RUN_BACKGROUND_TASKS; +STATIC void _send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { + if (!self->data_as_commands) { + self->core.send(self->core.bus, true, true, &self->write_ram_command, 1); } - return 0; + self->core.send(self->core.bus, false, false, pixels, length); } -STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_t* area) { +STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* area) { uint16_t buffer_size = 128; // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. - if (!displayio_display_clip_area(display, area, &clipped)) { + if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { return true; } uint16_t subrectangles = 1; uint16_t rows_per_buffer = displayio_area_height(&clipped); - uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / display->colorspace.depth; + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; uint16_t pixels_per_buffer = displayio_area_size(&clipped); if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); @@ -260,8 +222,8 @@ STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_ rows_per_buffer = 1; } // If pixels are packed by column then ensure rows_per_buffer is on a byte boundary. - if (display->colorspace.depth < 8 && !display->colorspace.pixels_in_byte_share_row) { - uint8_t pixels_per_byte = 8 / display->colorspace.depth; + if (self->core.colorspace.depth < 8 && !self->core.colorspace.pixels_in_byte_share_row) { + uint8_t pixels_per_byte = 8 / self->core.colorspace.depth; if (rows_per_buffer % pixels_per_byte != 0) { rows_per_buffer -= rows_per_buffer % pixels_per_byte; } @@ -296,15 +258,13 @@ STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_ } remaining_rows -= rows_per_buffer; - displayio_display_begin_transaction(display); - displayio_display_set_region_to_update(display, &subrectangle); - displayio_display_end_transaction(display); + displayio_display_core_set_region_to_update(&self->core, self->set_column_command, self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, &subrectangle); uint16_t subrectangle_size_bytes; - if (display->colorspace.depth >= 8) { - subrectangle_size_bytes = displayio_area_size(&subrectangle) * (display->colorspace.depth / 8); + if (self->core.colorspace.depth >= 8) { + subrectangle_size_bytes = displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); } else { - subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / display->colorspace.depth); + subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); } for (uint16_t k = 0; k < mask_length; k++) { @@ -314,14 +274,16 @@ STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_ buffer[k] = 0x00000000; } - displayio_display_fill_area(display, &subrectangle, mask, buffer); + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - if (!displayio_display_begin_transaction(display)) { - // Can't acquire display bus; skip the rest of the data. Try next display. + // Can't acquire display bus; skip the rest of the data. + if (!displayio_display_core_bus_free(&self->core)) { return false; } - displayio_display_send_pixels(display, (uint8_t*) buffer, subrectangle_size_bytes); - displayio_display_end_transaction(display); + + displayio_display_core_begin_transaction(&self->core); + _send_pixels(self, (uint8_t*) buffer, subrectangle_size_bytes); + displayio_display_core_end_transaction(&self->core); // TODO(tannewt): Make refresh displays faster so we don't starve other // background tasks. @@ -330,182 +292,59 @@ STATIC bool refresh_area(displayio_display_obj_t* display, const displayio_area_ return true; } -STATIC void refresh_display(displayio_display_obj_t* self) { - if (!displayio_display_begin_transaction(self)) { +STATIC void _refresh_display(displayio_display_obj_t* self) { + if (!displayio_display_core_bus_free(&self->core)) { // Can't acquire display bus; skip updating this display. Try next display. - continue; + return; } - displayio_display_end_transaction(self); - displayio_display_start_refresh(self); - const displayio_area_t* current_area = displayio_display_get_refresh_areas(self); + displayio_display_core_start_refresh(&self->core); + const displayio_area_t* current_area = _get_refresh_areas(self); while (current_area != NULL) { - refresh_area(self, current_area); + _refresh_area(self, current_area); current_area = current_area->next; } - displayio_display_finish_refresh(self); -} - -void common_hal_displayio_display_refresh(displayio_display_obj_t* self) { - // Time to refresh at specified frame rate? - while (!displayio_display_frame_queued(self)) { - // Too soon. Try next display. - continue; - } - refresh_display(self); -} - -bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self) { - return self->auto_brightness; -} - -uint16_t common_hal_displayio_display_get_width(displayio_display_obj_t* self){ - return self->width; -} - -uint16_t common_hal_displayio_display_get_height(displayio_display_obj_t* self){ - return self->height; + displayio_display_core_finish_refresh(&self->core); } uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self){ - return self->rotation; -} - -void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness) { - self->auto_brightness = auto_brightness; -} - -mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self) { - return self->current_brightness; + return self->core.rotation; } -bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness) { - self->updating_backlight = true; - bool ok = false; - if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { - common_hal_pulseio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t) (0xffff * brightness)); - ok = true; - } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { - common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); - ok = true; - } else if (self->brightness_command != NO_BRIGHTNESS_COMMAND) { - ok = self->begin_transaction(self->bus); - if (ok) { - if (self->data_as_commands) { - uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; - self->send(self->bus, true, true, set_brightness, 2); - } else { - uint8_t command = self->brightness_command; - uint8_t hex_brightness = 0xff * brightness; - self->send(self->bus, true, true, &command, 1); - self->send(self->bus, false, false, &hex_brightness, 1); - } - self->end_transaction(self->bus); +void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time) { + if (!self->auto_refresh) { + uint64_t current_time = ticks_ms; + uint32_t current_frame_time = current_time - self->core.last_refresh; + // Test to see if the real frame time is below our minimum. + if (current_frame_time > maximum_frame_time) { + mp_raise_RuntimeError(translate("Below minimum frame rate")); } - - } - self->updating_backlight = false; - if (ok) { - self->current_brightness = brightness; - } - return ok; -} - -bool displayio_display_begin_transaction(displayio_display_obj_t* self) { - return self->begin_transaction(self->bus); -} - -void displayio_display_end_transaction(displayio_display_obj_t* self) { - self->end_transaction(self->bus); -} - -void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area) { - uint16_t x1 = area->x1; - uint16_t x2 = area->x2; - uint16_t y1 = area->y1; - uint16_t y2 = area->y2; - // Collapse down the dimension where multiple pixels are in a byte. - if (self->colorspace.depth < 8) { - uint8_t pixels_per_byte = 8 / self->colorspace.depth; - if (self->colorspace.pixels_in_byte_share_row) { - x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; - x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; - } else { - y1 /= pixels_per_byte * self->colorspace.bytes_per_cell; - y2 /= pixels_per_byte * self->colorspace.bytes_per_cell; + uint32_t current_call_time = current_time - self->last_refresh_call; + self->last_refresh_call = current_time; + // Skip the actual refresh to help catch up. + if (current_call_time > target_frame_time) { + return; + } + uint32_t remaining_time = target_frame_time - (current_frame_time % target_frame_time); + // We're ahead of the game so wait until we align with the frame rate. + while (ticks_ms - self->last_refresh_call < remaining_time) { + #ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP ; + #endif } } - - // Set column. - uint8_t data[5]; - data[0] = self->set_column_command; - uint8_t data_length = 1; - if (!self->data_as_commands) { - self->send(self->bus, true, true, data, 1); - data_length = 0; - } - if (self->single_byte_bounds) { - data[data_length++] = x1 + self->colstart; - data[data_length++] = x2 - 1 + self->colstart; - } else { - x1 += self->colstart; - x2 += self->colstart - 1; - data[data_length++] = x1 >> 8; - data[data_length++] = x1 & 0xff; - data[data_length++] = x2 >> 8; - data[data_length++] = x2 & 0xff; - } - self->send(self->bus, self->data_as_commands, self->data_as_commands, data, data_length); - - // Set row. - data[0] = self->set_row_command; - data_length = 1; - if (!self->data_as_commands) { - self->send(self->bus, true, true, data, 1); - data_length = 0; - } - if (self->single_byte_bounds) { - data[data_length++] = y1 + self->rowstart; - data[data_length++] = y2 - 1 + self->rowstart; - } else { - y1 += self->rowstart; - y2 += self->rowstart - 1; - data[data_length++] = y1 >> 8; - data[data_length++] = y1 & 0xff; - data[data_length++] = y2 >> 8; - data[data_length++] = y2 & 0xff; - } - self->send(self->bus, self->data_as_commands, self->data_as_commands, data, data_length); -} - -void displayio_display_start_refresh(displayio_display_obj_t* self) { - self->last_refresh = ticks_ms; -} - -bool displayio_display_frame_queued(displayio_display_obj_t* self) { - if (self->current_group == NULL) { - return false; - } - // Refresh at ~60 fps. - return (ticks_ms - self->last_refresh) > 16; + _refresh_display(self); } -void displayio_display_finish_refresh(displayio_display_obj_t* self) { - if (self->current_group != NULL) { - displayio_group_finish_refresh(self->current_group); - } - self->refresh = false; - self->full_refresh = false; - self->last_refresh = ticks_ms; +bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self) { + return self->auto_refresh; } -void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { - if (!self->data_as_commands) { - self->send(self->bus, true, true, &self->write_ram_command, 1); - } - self->send(self->bus, false, false, pixels, length); +void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, + bool auto_refresh) { + self->auto_refresh = auto_refresh; } -void displayio_display_update_backlight(displayio_display_obj_t* self) { +STATIC void _update_backlight(displayio_display_obj_t* self) { if (!self->auto_brightness || self->updating_backlight) { return; } @@ -520,17 +359,15 @@ void displayio_display_update_backlight(displayio_display_obj_t* self) { } void displayio_display_background(displayio_display_obj_t* self) { - displayio_display_update_backlight(self); + _update_backlight(self); - if (self->auto_refresh && (ticks_ms - self->last_refresh) > 16) { - display_refresh(self); + if (self->auto_refresh && (ticks_ms - self->core.last_refresh) > self->native_frame_time) { + _refresh_display(self); } } void release_display(displayio_display_obj_t* self) { - if (self->current_group != NULL) { - self->current_group->in_group = false; - } + release_display_core(&self->core); if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); @@ -539,34 +376,6 @@ void release_display(displayio_display_obj_t* self) { } } -bool displayio_display_fill_area(displayio_display_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { - return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); -} - -bool displayio_display_clip_area(displayio_display_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped) { - bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); - if (!overlaps) { - return false; - } - // Expand the area if we have multiple pixels per byte and we need to byte - // align the bounds. - if (self->colorspace.depth < 8) { - uint8_t pixels_per_byte = 8 / self->colorspace.depth * self->colorspace.bytes_per_cell; - if (self->colorspace.pixels_in_byte_share_row) { - if (clipped->x1 % pixels_per_byte != 0) { - clipped->x1 -= clipped->x1 % pixels_per_byte; - } - if (clipped->x2 % pixels_per_byte != 0) { - clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; - } - } else { - if (clipped->y1 % pixels_per_byte != 0) { - clipped->y1 -= clipped->y1 % pixels_per_byte; - } - if (clipped->y2 % pixels_per_byte != 0) { - clipped->y2 += pixels_per_byte - clipped->y2 % pixels_per_byte; - } - } - } - return true; +void displayio_display_collect_ptrs(displayio_display_obj_t* self) { + displayio_display_core_collect_ptrs(&self->core); } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index db0a23012..cff566a61 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -32,46 +32,33 @@ #include "shared-bindings/pulseio/PWMOut.h" #include "shared-module/displayio/area.h" - -typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); -typedef void (*display_bus_end_transaction)(mp_obj_t bus); +#include "shared-module/displayio/display_core.h" typedef struct { mp_obj_base_t base; - mp_obj_t bus; - displayio_group_t *current_group; - uint64_t last_refresh; - display_bus_begin_transaction begin_transaction; - display_bus_send send; - display_bus_end_transaction end_transaction; + displayio_display_core_t core; union { digitalio_digitalinout_obj_t backlight_inout; pulseio_pwmout_obj_t backlight_pwm; }; uint64_t last_backlight_refresh; - displayio_buffer_transform_t transform; - displayio_area_t area; + uint64_t last_refresh_call; mp_float_t current_brightness; - uint16_t width; - uint16_t height; - uint16_t rotation; - _displayio_colorspace_t colorspace; - int16_t colstart; - int16_t rowstart; uint16_t brightness_command; + uint16_t native_frames_per_second; + uint16_t native_frame_time; uint8_t set_column_command; uint8_t set_row_command; uint8_t write_ram_command; bool auto_refresh; - bool single_byte_bounds; bool data_as_commands; bool auto_brightness; bool updating_backlight; - bool full_refresh; // New group means we need to refresh the whole display. } displayio_display_obj_t; void displayio_display_background(displayio_display_obj_t* self); void release_display(displayio_display_obj_t* self); +void displayio_display_collect_ptrs(displayio_display_obj_t* self); + #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_H diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 434adbdf4..6ff060a6a 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -50,18 +50,14 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t set_current_column_command, uint16_t set_current_row_command, uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select) { - self->colorspace.depth = 1; - self->colorspace.grayscale = true; - self->colorspace.pixels_in_byte_share_row = true; - self->colorspace.bytes_per_cell = 1; - self->colorspace.reverse_pixels_in_byte = true; - if (highlight_color != 0x000000) { - self->colorspace.tricolor = true; - self->colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); - self->colorspace.tricolor_luma = displayio_colorconverter_compute_luma(highlight_color); + self->core.colorspace.tricolor = true; + self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); + self->core.colorspace.tricolor_luma = displayio_colorconverter_compute_luma(highlight_color); } + displayio_display_core_construct(&self->core, bus, width, height, ram_width, ram_height, colstart, rowstart, rotation, 1, true, true, 1, true); + self->set_column_window_command = set_column_window_command; self->set_row_window_command = set_row_window_command; self->set_current_column_command = set_current_column_command; @@ -72,10 +68,6 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->color_bits_inverted = color_bits_inverted; self->refresh_display_command = refresh_display_command; self->busy_state = busy_state; - self->refresh = true; - self->current_group = NULL; - self->colstart = colstart; - self->rowstart = rowstart; self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; self->always_toggle_chip_select = always_toggle_chip_select; @@ -85,88 +77,6 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->stop_sequence = stop_sequence; self->stop_sequence_len = stop_sequence_len; - - if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { - self->bus_reset = common_hal_displayio_parallelbus_reset; - self->bus_free = common_hal_displayio_parallelbus_bus_free; - self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; - self->send = common_hal_displayio_parallelbus_send; - self->end_transaction = common_hal_displayio_parallelbus_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { - self->bus_reset = common_hal_displayio_fourwire_reset; - self->bus_free = common_hal_displayio_fourwire_bus_free; - self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; - self->send = common_hal_displayio_fourwire_send; - self->end_transaction = common_hal_displayio_fourwire_end_transaction; - } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { - self->bus_reset = common_hal_displayio_i2cdisplay_reset; - self->bus_free = common_hal_displayio_i2cdisplay_bus_free; - self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; - self->send = common_hal_displayio_i2cdisplay_send; - self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; - } else { - mp_raise_ValueError(translate("Unsupported display bus type")); - } - self->bus = bus; - - supervisor_start_terminal(width, height); - - self->width = width; - self->height = height; - rotation = rotation % 360; - self->transform.x = 0; - self->transform.y = 0; - self->transform.scale = 1; - self->transform.mirror_x = false; - self->transform.mirror_y = false; - self->transform.transpose_xy = false; - if (rotation == 0 || rotation == 180) { - if (rotation == 180) { - self->transform.mirror_x = true; - self->transform.mirror_y = true; - } - } else { - self->transform.transpose_xy = true; - if (rotation == 270) { - self->transform.mirror_y = true; - } else { - self->transform.mirror_x = true; - } - } - - self->ram_width = ram_width; - self->ram_height = ram_height; - - self->area.x1 = 0; - self->area.y1 = 0; - self->area.next = NULL; - - self->transform.dx = 1; - self->transform.dy = 1; - if (self->transform.transpose_xy) { - self->area.x2 = height; - self->area.y2 = width; - if (self->transform.mirror_x) { - self->transform.x = height; - self->transform.dx = -1; - } - if (self->transform.mirror_y) { - self->transform.y = width; - self->transform.dy = -1; - } - } else { - self->area.x2 = width; - self->area.y2 = height; - if (self->transform.mirror_x) { - self->transform.x = width; - self->transform.dx = -1; - } - if (self->transform.mirror_y) { - self->transform.y = height; - self->transform.dy = -1; - } - } - self->busy.base.type = &mp_type_NoneType; if (busy_pin != NULL) { self->busy.base.type = &digitalio_digitalinout_type; @@ -179,77 +89,37 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* // TODO: Clear } + supervisor_start_terminal(width, height); + // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_epaperdisplay_show(self, &circuitpython_splash); } bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self, displayio_group_t* root_group) { - if (root_group == NULL && !circuitpython_splash.in_group) { - root_group = &circuitpython_splash; - } - if (root_group == self->current_group) { - return true; - } - if (root_group != NULL && root_group->in_group) { - return false; - } - if (self->current_group != NULL) { - self->current_group->in_group = false; - } - if (root_group != NULL) { - displayio_group_update_transform(root_group, &self->transform); - root_group->in_group = true; - self->current_group = root_group; - } - self->full_refresh = true; - return true; + return displayio_display_core_show(&self->core, root_group); } const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self) { const displayio_area_t* first_area; - if (self->current_group == NULL || self->current_group->base.type != &displayio_group_type) { - asm("bkpt"); - } - if (self->full_refresh) { - first_area = &self->area; + if (self->core.full_refresh) { + first_area = &self->core.area; } else { - first_area = displayio_group_get_refresh_areas(self->current_group, NULL); + first_area = displayio_group_get_refresh_areas(self->core.current_group, NULL); } if (first_area != NULL && self->set_row_window_command == NO_COMMAND) { - self->area.next = NULL; - return &self->area; + self->core.area.next = NULL; + return &self->core.area; } return first_area; } -int32_t common_hal_displayio_epaperdisplay_wait_for_frame(displayio_epaperdisplay_obj_t* self) { - uint64_t last_refresh = self->last_refresh; - // Don't try to refresh if we got an exception. - while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { - MICROPY_VM_HOOK_LOOP - } - return 0; -} - uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self){ - return self->width; + return displayio_display_core_get_width(&self->core); } uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self){ - return self->height; -} - -bool displayio_epaperdisplay_bus_free(displayio_epaperdisplay_obj_t *self) { - return self->bus_free(self->bus); -} - -bool displayio_epaperdisplay_begin_transaction(displayio_epaperdisplay_obj_t* self) { - return self->begin_transaction(self->bus); -} - -void displayio_epaperdisplay_end_transaction(displayio_epaperdisplay_obj_t* self) { - self->end_transaction(self->bus); + return displayio_display_core_get_height(&self->core); } STATIC void wait_for_busy(displayio_epaperdisplay_obj_t* self) { @@ -271,10 +141,10 @@ STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool shou bool delay = (data_size & DELAY) != 0; data_size &= ~DELAY; uint8_t *data = cmd + 2; - self->begin_transaction(self->bus); - self->send(self->bus, true, self->always_toggle_chip_select, cmd, 1); - self->send(self->bus, false, self->always_toggle_chip_select, data, data_size); - self->end_transaction(self->bus); + displayio_display_core_begin_transaction(&self->core); + self->core.send(self->core.bus, true, self->always_toggle_chip_select, cmd, 1); + self->core.send(self->core.bus, false, self->always_toggle_chip_select, data, data_size); + displayio_display_core_end_transaction(&self->core); uint16_t delay_length_ms = 0; if (delay) { data_size++; @@ -291,87 +161,17 @@ STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool shou } } -void displayio_epaperdisplay_set_region_to_update(displayio_epaperdisplay_obj_t* self, displayio_area_t* area) { - if (self->set_row_window_command == NO_COMMAND) { - return; - } - uint16_t x1 = area->x1; - uint16_t x2 = area->x2; - uint16_t y1 = area->y1; - uint16_t y2 = area->y2; - // Collapse down the dimension where multiple pixels are in a byte. - uint8_t pixels_per_byte = 8 / self->colorspace.depth; - x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; - x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; - - - // Set column. - uint8_t data[5]; - data[0] = self->set_column_window_command; - self->send(self->bus, true, self->always_toggle_chip_select, data, 1); - uint8_t data_length = 0; - if (self->ram_width / pixels_per_byte < 0x100) { - data[data_length++] = x1 + self->colstart; - data[data_length++] = x2 - 1 + self->colstart; - } else { - x1 += self->colstart; - x2 += self->colstart - 1; - data[data_length++] = x1 >> 8; - data[data_length++] = x1 & 0xff; - data[data_length++] = x2 >> 8; - data[data_length++] = x2 & 0xff; - } - self->send(self->bus, false, self->always_toggle_chip_select, data, data_length); - if (self->set_current_column_command != NO_COMMAND) { - uint8_t command = self->set_current_column_command; - self->send(self->bus, true, self->always_toggle_chip_select, &command, 1); - self->send(self->bus, false, self->always_toggle_chip_select, data, data_length / 2); - } - - // Set row. - data[0] = self->set_row_window_command; - self->send(self->bus, true, self->always_toggle_chip_select, data, 1); - data_length = 0; - if (self->ram_height < 0x100) { - data[data_length++] = y1 + self->rowstart; - data[data_length++] = y2 - 1 + self->rowstart; - } else { - y1 += self->rowstart; - y2 += self->rowstart - 1; - data[data_length++] = y1 & 0xff; - data[data_length++] = y1 >> 8; - data[data_length++] = y2 & 0xff; - data[data_length++] = y2 >> 8; - } - self->send(self->bus, false, self->always_toggle_chip_select, data, data_length); - if (self->set_current_row_command != NO_COMMAND) { - uint8_t command = self->set_current_row_command; - self->send(self->bus, true, self->always_toggle_chip_select, &command, 1); - self->send(self->bus, false, self->always_toggle_chip_select, data, data_length / 2); - } -} - void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self) { // run start sequence - self->bus_reset(self->bus); + self->core.bus_reset(self->core.bus); send_command_sequence(self, true, self->start_sequence, self->start_sequence_len); - self->last_refresh = ticks_ms; -} - -void displayio_epaperdisplay_background_task(displayio_epaperdisplay_obj_t* self) { - if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { - if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { - self->refreshing = false; - // Run stop sequence but don't wait for busy because busy is set when sleeping. - send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); - } - } + displayio_display_core_start_refresh(&self->core); } uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self) { // Refresh at seconds per frame rate. - uint32_t elapsed_time = ticks_ms - self->last_refresh; + uint32_t elapsed_time = ticks_ms - self->core.last_refresh; if (elapsed_time > self->milliseconds_per_frame) { return 0; } @@ -380,20 +180,16 @@ uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaper void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { // Actually refresh the display now that all pixel RAM has been updated. - displayio_epaperdisplay_begin_transaction(self); - self->send(self->bus, true, self->always_toggle_chip_select, &self->refresh_display_command, 1); - displayio_epaperdisplay_end_transaction(self); + displayio_display_core_begin_transaction(&self->core); + self->core.send(self->core.bus, true, self->always_toggle_chip_select, &self->refresh_display_command, 1); + displayio_display_core_end_transaction(&self->core); self->refreshing = true; - if (self->current_group != NULL) { - displayio_group_finish_refresh(self->current_group); - } - self->refresh = false; - self->full_refresh = false; - self->last_refresh = ticks_ms; + displayio_display_core_finish_refresh(&self->core); } -void displayio_epaperdisplay_send_pixels(displayio_epaperdisplay_obj_t* self, uint8_t* pixels, uint32_t length) { +mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self) { + return self->core.bus; } bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, const displayio_area_t* area) { @@ -401,12 +197,12 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. - if (!displayio_epaperdisplay_clip_area(self, area, &clipped)) { + if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { return true; } uint16_t subrectangles = 1; uint16_t rows_per_buffer = displayio_area_height(&clipped); - uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->colorspace.depth; + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; uint16_t pixels_per_buffer = displayio_area_size(&clipped); if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); @@ -431,23 +227,23 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint32_t mask[mask_length]; uint8_t passes = 1; - if (self->colorspace.tricolor) { + if (self->core.colorspace.tricolor) { passes = 2; } for (uint8_t pass = 0; pass < passes; pass++) { uint16_t remaining_rows = displayio_area_height(&clipped); - displayio_epaperdisplay_begin_transaction(self); - displayio_epaperdisplay_set_region_to_update(self, &clipped); - displayio_epaperdisplay_end_transaction(self); + if (self->set_row_window_command != NO_COMMAND) { + displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, false, self->always_toggle_chip_select, &clipped); + } uint8_t write_command = self->write_black_ram_command; if (pass == 1) { write_command = self->write_color_ram_command; } - displayio_epaperdisplay_begin_transaction(self); - self->send(self->bus, true, self->always_toggle_chip_select, &write_command, 1); - displayio_epaperdisplay_end_transaction(self); + displayio_display_core_begin_transaction(&self->core); + self->core.send(self->core.bus, true, self->always_toggle_chip_select, &write_command, 1); + displayio_display_core_end_transaction(&self->core); for (uint16_t j = 0; j < subrectangles; j++) { displayio_area_t subrectangle = { @@ -462,7 +258,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c remaining_rows -= rows_per_buffer; - uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->colorspace.depth); + uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); for (uint16_t k = 0; k < mask_length; k++) { mask[k] = 0x00000000; @@ -471,11 +267,11 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c buffer[k] = 0x00000000; } - self->colorspace.grayscale = true; + self->core.colorspace.grayscale = true; if (pass == 1) { - self->colorspace.grayscale = false; + self->core.colorspace.grayscale = false; } - displayio_group_fill_area(self->current_group, &self->colorspace, &subrectangle, mask, buffer); + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); // Invert it all. if ((pass == 1 && self->color_bits_inverted) || @@ -485,12 +281,12 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c } } - if (!displayio_epaperdisplay_begin_transaction(self)) { + if (!displayio_display_core_begin_transaction(&self->core)) { // Can't acquire display bus; skip the rest of the data. Try next display. return false; } - self->send(self->bus, false, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); - displayio_epaperdisplay_end_transaction(self); + self->core.send(self->core.bus, false, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); + displayio_display_core_end_transaction(&self->core); // TODO(tannewt): Make refresh displays faster so we don't starve other // background tasks. @@ -512,57 +308,47 @@ bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* s return false; } } - if (self->current_group == NULL) { - return false; + if (self->core.current_group == NULL) { + return true; } // Refresh at seconds per frame rate. - if (ticks_ms - self->last_refresh) > self->milliseconds_per_frame; - - if (displayio_epaperdisplay_get_time_to_refresh(display) > 0) { + if (common_hal_displayio_epaperdisplay_get_time_to_refresh(self) > 0) { return false; } - if (!displayio_epaperdisplay_bus_free(display)) { + if (!displayio_display_core_bus_free(&self->core)) { // Can't acquire display bus; skip updating this display. Try next display. - continue; + return false; } - const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(display); + const displayio_area_t* current_area = displayio_epaperdisplay_get_refresh_areas(self); if (current_area == NULL) { - continue; + return true; } - displayio_epaperdisplay_start_refresh(display); + displayio_epaperdisplay_start_refresh(self); while (current_area != NULL) { - displayio_epaperdisplay_refresh_area(display, current_area); + displayio_epaperdisplay_refresh_area(self, current_area); current_area = current_area->next; } - displayio_epaperdisplay_finish_refresh(display); + displayio_epaperdisplay_finish_refresh(self); + return true; } -void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { - if (self->current_group != NULL) { - self->current_group->in_group = false; +void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) { + if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { + if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { + self->refreshing = false; + // Run stop sequence but don't wait for busy because busy is set when sleeping. + send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); + } } +} + +void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { + release_display_core(&self->core); if (self->busy.base.type == &digitalio_digitalinout_type) { common_hal_digitalio_digitalinout_deinit(&self->busy); } } -bool displayio_epaperdisplay_fill_area(displayio_epaperdisplay_obj_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { - return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); -} - -bool displayio_epaperdisplay_clip_area(displayio_epaperdisplay_obj_t *self, const displayio_area_t* area, displayio_area_t* clipped) { - bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); - if (!overlaps) { - return false; - } - // Expand the area if we have multiple pixels per byte and we need to byte - // align the bounds. - uint8_t pixels_per_byte = 8; - if (clipped->x1 % pixels_per_byte != 0) { - clipped->x1 -= clipped->x1 % pixels_per_byte; - } - if (clipped->x2 % pixels_per_byte != 0) { - clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; - } - return true; +void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self) { + displayio_display_core_collect_ptrs(&self->core); } diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index cc7db6f6d..88b5ebfaf 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -32,38 +32,17 @@ #include "shared-bindings/pulseio/PWMOut.h" #include "shared-module/displayio/area.h" - -typedef void (*display_bus_bus_reset)(mp_obj_t bus); -typedef bool (*display_bus_bus_free)(mp_obj_t bus); -typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); -typedef void (*display_bus_end_transaction)(mp_obj_t bus); +#include "shared-module/displayio/display_core.h" typedef struct { mp_obj_base_t base; - mp_obj_t bus; - displayio_group_t *current_group; - uint64_t last_refresh; - display_bus_bus_reset bus_reset; - display_bus_bus_free bus_free; - display_bus_begin_transaction begin_transaction; - display_bus_send send; - display_bus_end_transaction end_transaction; + displayio_display_core_t core; digitalio_digitalinout_obj_t busy; uint32_t milliseconds_per_frame; uint8_t* start_sequence; uint32_t start_sequence_len; uint8_t* stop_sequence; uint32_t stop_sequence_len; - displayio_buffer_transform_t transform; - displayio_area_t area; - uint16_t width; - uint16_t height; - uint16_t ram_width; - uint16_t ram_height; - _displayio_colorspace_t colorspace; - int16_t colstart; - int16_t rowstart; uint16_t set_column_window_command; uint16_t set_row_window_command; uint16_t set_current_column_command; @@ -76,11 +55,12 @@ typedef struct { bool black_bits_inverted; bool color_bits_inverted; bool refreshing; - bool full_refresh; // New group means we need to refresh the whole display. bool always_toggle_chip_select; } displayio_epaperdisplay_obj_t; void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); void release_epaperdisplay(displayio_epaperdisplay_obj_t* self); +void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self); + #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 0ebed58c2..0a3b1fd10 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -4,7 +4,6 @@ #include "shared-module/displayio/__init__.h" #include "lib/utils/interrupt_char.h" -#include "py/gc.h" #include "py/reload.h" #include "py/runtime.h" #include "shared-bindings/board/__init__.h" @@ -16,7 +15,6 @@ #include "supervisor/shared/autoreload.h" #include "supervisor/shared/display.h" #include "supervisor/memory.h" -#include "supervisor/usb.h" primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; @@ -46,8 +44,8 @@ void displayio_background(void) { } if (displays[i].display.base.type == &displayio_display_type) { displayio_display_background(&displays[i].display); - } else if (displays[i].epaperdisplay.base.type == &displayio_epaperdisplay_type) { - displayio_epaperdisplay_background(&displays[i].epaperdisplay); + } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { + displayio_epaperdisplay_background(&displays[i].epaper_display); } } @@ -162,9 +160,9 @@ void displayio_gc_collect(void) { // Alternatively, we could use gc_collect_root over the whole object, // but this is more precise, and is the only field that needs marking. if (displays[i].display.base.type == &displayio_display_type) { - gc_collect_ptr(displays[i].display.current_group); + displayio_display_collect_ptrs(&displays[i].display); } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { - gc_collect_ptr(displays[i].epaper_display.current_group); + displayio_epaperdisplay_collect_ptrs(&displays[i].epaper_display); } } } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c new file mode 100644 index 000000000..f8a8d8fea --- /dev/null +++ b/shared-module/displayio/display_core.c @@ -0,0 +1,309 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/displayio/Display.h" + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/displayio/FourWire.h" +#include "shared-bindings/displayio/I2CDisplay.h" +#include "shared-bindings/displayio/ParallelBus.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/display.h" + +#include +#include + +#include "tick.h" + +void displayio_display_core_construct(displayio_display_core_t* self, + mp_obj_t bus, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, + uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte) { + self->colorspace.depth = color_depth; + self->colorspace.grayscale = grayscale; + self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row; + self->colorspace.bytes_per_cell = bytes_per_cell; + self->colorspace.reverse_pixels_in_byte = reverse_pixels_in_byte; + self->current_group = NULL; + self->colstart = colstart; + self->rowstart = rowstart; + + if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { + self->bus_reset = common_hal_displayio_parallelbus_reset; + self->bus_free = common_hal_displayio_parallelbus_bus_free; + self->begin_transaction = common_hal_displayio_parallelbus_begin_transaction; + self->send = common_hal_displayio_parallelbus_send; + self->end_transaction = common_hal_displayio_parallelbus_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_fourwire_type)) { + self->bus_reset = common_hal_displayio_fourwire_reset; + self->bus_free = common_hal_displayio_fourwire_bus_free; + self->begin_transaction = common_hal_displayio_fourwire_begin_transaction; + self->send = common_hal_displayio_fourwire_send; + self->end_transaction = common_hal_displayio_fourwire_end_transaction; + } else if (MP_OBJ_IS_TYPE(bus, &displayio_i2cdisplay_type)) { + self->bus_reset = common_hal_displayio_i2cdisplay_reset; + self->bus_free = common_hal_displayio_i2cdisplay_bus_free; + self->begin_transaction = common_hal_displayio_i2cdisplay_begin_transaction; + self->send = common_hal_displayio_i2cdisplay_send; + self->end_transaction = common_hal_displayio_i2cdisplay_end_transaction; + } else { + mp_raise_ValueError(translate("Unsupported display bus type")); + } + self->bus = bus; + + + supervisor_start_terminal(width, height); + + self->width = width; + self->height = height; + self->ram_width = width; + self->ram_height = height; + rotation = rotation % 360; + self->transform.x = 0; + self->transform.y = 0; + self->transform.scale = 1; + self->transform.mirror_x = false; + self->transform.mirror_y = false; + self->transform.transpose_xy = false; + if (rotation == 0 || rotation == 180) { + if (rotation == 180) { + self->transform.mirror_x = true; + self->transform.mirror_y = true; + } + } else { + self->transform.transpose_xy = true; + if (rotation == 270) { + self->transform.mirror_y = true; + } else { + self->transform.mirror_x = true; + } + } + + self->area.x1 = 0; + self->area.y1 = 0; + self->area.next = NULL; + + self->transform.dx = 1; + self->transform.dy = 1; + if (self->transform.transpose_xy) { + self->area.x2 = height; + self->area.y2 = width; + if (self->transform.mirror_x) { + self->transform.x = height; + self->transform.dx = -1; + } + if (self->transform.mirror_y) { + self->transform.y = width; + self->transform.dy = -1; + } + } else { + self->area.x2 = width; + self->area.y2 = height; + if (self->transform.mirror_x) { + self->transform.x = width; + self->transform.dx = -1; + } + if (self->transform.mirror_y) { + self->transform.y = height; + self->transform.dy = -1; + } + } +} + +bool displayio_display_core_show(displayio_display_core_t* self, displayio_group_t* root_group) { + if (root_group == NULL) { + if (!circuitpython_splash.in_group) { + root_group = &circuitpython_splash; + } else if (self->current_group == &circuitpython_splash) { + return false; + } + } + if (root_group == self->current_group) { + return true; + } + if (root_group != NULL && root_group->in_group) { + return false; + } + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + + if (root_group != NULL) { + displayio_group_update_transform(root_group, &self->transform); + root_group->in_group = true; + } + self->current_group = root_group; + self->full_refresh = true; + return true; +} + +uint16_t displayio_display_core_get_width(displayio_display_core_t* self){ + return self->width; +} + +uint16_t displayio_display_core_get_height(displayio_display_core_t* self){ + return self->height; +} + +bool displayio_display_core_bus_free(displayio_display_core_t *self) { + return self->bus_free(self->bus); +} + +bool displayio_display_core_begin_transaction(displayio_display_core_t* self) { + return self->begin_transaction(self->bus); +} + +void displayio_display_core_end_transaction(displayio_display_core_t* self) { + self->end_transaction(self->bus); +} + +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area) { + displayio_display_core_begin_transaction(self); + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + uint16_t y1 = area->y1; + uint16_t y2 = area->y2; + // Collapse down the dimension where multiple pixels are in a byte. + if (self->colorspace.depth < 8) { + uint8_t pixels_per_byte = 8 / self->colorspace.depth; + if (self->colorspace.pixels_in_byte_share_row) { + x1 /= pixels_per_byte * self->colorspace.bytes_per_cell; + x2 /= pixels_per_byte * self->colorspace.bytes_per_cell; + } else { + y1 /= pixels_per_byte * self->colorspace.bytes_per_cell; + y2 /= pixels_per_byte * self->colorspace.bytes_per_cell; + } + } + + // Set column. + uint8_t data[5]; + data[0] = column_command; + uint8_t data_length = 1; + if (!data_as_commands) { + self->send(self->bus, true, true, data, 1); + data_length = 0; + } + if (self->ram_width < 0x100) { + data[data_length++] = x1 + self->colstart; + data[data_length++] = x2 - 1 + self->colstart; + } else { + x1 += self->colstart; + x2 += self->colstart - 1; + data[data_length++] = x1 >> 8; + data[data_length++] = x1 & 0xff; + data[data_length++] = x2 >> 8; + data[data_length++] = x2 & 0xff; + } + self->send(self->bus, data_as_commands, data_as_commands, data, data_length); + if (set_current_column_command != NO_COMMAND) { + uint8_t command = set_current_column_command; + self->send(self->bus, true, always_toggle_chip_select, &command, 1); + self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); + } + + // Set row. + data[0] = row_command; + data_length = 1; + if (!data_as_commands) { + self->send(self->bus, true, true, data, 1); + data_length = 0; + } + if (self->ram_height < 0x100) { + data[data_length++] = y1 + self->rowstart; + data[data_length++] = y2 - 1 + self->rowstart; + } else { + y1 += self->rowstart; + y2 += self->rowstart - 1; + data[data_length++] = y1 >> 8; + data[data_length++] = y1 & 0xff; + data[data_length++] = y2 >> 8; + data[data_length++] = y2 & 0xff; + } + self->send(self->bus, data_as_commands, data_as_commands, data, data_length); + if (set_current_row_command != NO_COMMAND) { + uint8_t command = set_current_row_command; + self->send(self->bus, true, always_toggle_chip_select, &command, 1); + self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); + } + + displayio_display_core_end_transaction(self); +} + +void displayio_display_core_start_refresh(displayio_display_core_t* self) { + self->last_refresh = ticks_ms; +} + +void displayio_display_core_finish_refresh(displayio_display_core_t* self) { + if (self->current_group != NULL) { + displayio_group_finish_refresh(self->current_group); + } + self->full_refresh = false; + self->last_refresh = ticks_ms; +} + +void release_display_core(displayio_display_core_t* self) { + if (self->current_group != NULL) { + self->current_group->in_group = false; + } +} + +void displayio_display_core_collect_ptrs(displayio_display_core_t* self) { + gc_collect_ptr(self->current_group); +} + +bool displayio_display_core_fill_area(displayio_display_core_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) { + return displayio_group_fill_area(self->current_group, &self->colorspace, area, mask, buffer); +} + +bool displayio_display_core_clip_area(displayio_display_core_t *self, const displayio_area_t* area, displayio_area_t* clipped) { + bool overlaps = displayio_area_compute_overlap(&self->area, area, clipped); + if (!overlaps) { + return false; + } + // Expand the area if we have multiple pixels per byte and we need to byte + // align the bounds. + if (self->colorspace.depth < 8) { + uint8_t pixels_per_byte = 8 / self->colorspace.depth * self->colorspace.bytes_per_cell; + if (self->colorspace.pixels_in_byte_share_row) { + if (clipped->x1 % pixels_per_byte != 0) { + clipped->x1 -= clipped->x1 % pixels_per_byte; + } + if (clipped->x2 % pixels_per_byte != 0) { + clipped->x2 += pixels_per_byte - clipped->x2 % pixels_per_byte; + } + } else { + if (clipped->y1 % pixels_per_byte != 0) { + clipped->y1 -= clipped->y1 % pixels_per_byte; + } + if (clipped->y2 % pixels_per_byte != 0) { + clipped->y2 += pixels_per_byte - clipped->y2 % pixels_per_byte; + } + } + } + return true; +} diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h new file mode 100644 index 000000000..c837ce913 --- /dev/null +++ b/shared-module/displayio/display_core.h @@ -0,0 +1,90 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H +#define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H + +#include "shared-bindings/displayio/Group.h" + +#include "shared-module/displayio/area.h" + +#define NO_COMMAND 0x100 + +typedef void (*display_bus_bus_reset)(mp_obj_t bus); +typedef bool (*display_bus_bus_free)(mp_obj_t bus); +typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); +typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_end_transaction)(mp_obj_t bus); + +typedef struct { + mp_obj_t bus; + displayio_group_t *current_group; + uint64_t last_refresh; + display_bus_bus_reset bus_reset; + display_bus_bus_free bus_free; + display_bus_begin_transaction begin_transaction; + display_bus_send send; + display_bus_end_transaction end_transaction; + displayio_buffer_transform_t transform; + displayio_area_t area; + uint16_t width; + uint16_t height; + uint16_t rotation; + uint16_t ram_width; + uint16_t ram_height; + _displayio_colorspace_t colorspace; + int16_t colstart; + int16_t rowstart; + bool full_refresh; // New group means we need to refresh the whole display. +} displayio_display_core_t; + +void displayio_display_core_construct(displayio_display_core_t* self, + mp_obj_t bus, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, + uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte); + +bool displayio_display_core_show(displayio_display_core_t* self, displayio_group_t* root_group); + +uint16_t displayio_display_core_get_width(displayio_display_core_t* self); +uint16_t displayio_display_core_get_height(displayio_display_core_t* self); + +bool displayio_display_core_bus_free(displayio_display_core_t *self); +bool displayio_display_core_begin_transaction(displayio_display_core_t* self); +void displayio_display_core_end_transaction(displayio_display_core_t* self); + +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area); + +void release_display_core(displayio_display_core_t* self); + +void displayio_display_core_start_refresh(displayio_display_core_t* self); +void displayio_display_core_finish_refresh(displayio_display_core_t* self); + +void displayio_display_core_collect_ptrs(displayio_display_core_t* self); + +bool displayio_display_core_fill_area(displayio_display_core_t *self, displayio_area_t* area, uint32_t* mask, uint32_t *buffer); + +bool displayio_display_core_clip_area(displayio_display_core_t *self, const displayio_area_t* area, displayio_area_t* clipped); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H -- cgit v1.2.3 From 24b30965c41ae32b82c56b166f3287cf2c14f419 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 20 Aug 2019 21:35:42 -0700 Subject: Refresh ePaper displays once code.py is done running --- main.c | 8 ++++++++ shared-bindings/displayio/__init__.c | 2 +- shared-module/displayio/EPaperDisplay.c | 27 +++++++++++++++++++++++++++ shared-module/displayio/EPaperDisplay.h | 1 + shared-module/displayio/__init__.c | 24 +++++++++++++----------- shared-module/displayio/display_core.c | 3 ++- 6 files changed, 52 insertions(+), 13 deletions(-) (limited to 'shared-module') diff --git a/main.c b/main.c index 6ab50fc3c..076674c44 100755 --- a/main.c +++ b/main.c @@ -253,6 +253,7 @@ bool run_code_py(safe_mode_t safe_mode) { } bool serial_connected_before_animation = false; + bool refreshed_epaper_display = false; rgb_status_animation_t animation; prep_rgb_status_animation(&result, found_main, safe_mode, &animation); while (true) { @@ -290,6 +291,13 @@ bool run_code_py(safe_mode_t safe_mode) { } serial_connected_before_animation = serial_connected(); + // Refresh the ePaper display if we have one. That way it'll show an error message. + #if CIRCUITPY_DISPLAYIO + if (!refreshed_epaper_display) { + refreshed_epaper_display = maybe_refresh_epaperdisplay(); + } + #endif + tick_rgb_status_animation(&animation); } } diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index 8c5d1f228..f78325593 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -77,7 +77,7 @@ //| //| Releases any actively used displays so their busses and pins can be used again. This will also //| release the builtin display on boards that have one. You will need to reinitialize it yourself -//| afterwards. +//| afterwards. This may take seconds to complete if an active EPaperDisplay is refreshing. //| //| Use this once in your code.py if you initialize a display. Place it right before the //| initialization so the display is active as long as possible. diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 6ff060a6a..7e65502d4 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -170,6 +170,9 @@ void displayio_epaperdisplay_start_refresh(displayio_epaperdisplay_obj_t* self) } uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self) { + if (self->core.last_refresh == 0) { + return 0; + } // Refresh at seconds per frame rate. uint32_t elapsed_time = ticks_ms - self->core.last_refresh; if (elapsed_time > self->milliseconds_per_frame) { @@ -343,6 +346,13 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) { } void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { + if (self->refreshing) { + wait_for_busy(self); + self->refreshing = false; + // Run stop sequence but don't wait for busy because busy is set when sleeping. + send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); + } + release_display_core(&self->core); if (self->busy.base.type == &digitalio_digitalinout_type) { common_hal_digitalio_digitalinout_deinit(&self->busy); @@ -352,3 +362,20 @@ void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self) { displayio_display_core_collect_ptrs(&self->core); } + +bool maybe_refresh_epaperdisplay(void) { + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (displays[i].epaper_display.base.type != &displayio_epaperdisplay_type || + displays[i].epaper_display.core.current_group != &circuitpython_splash) { + // Skip regular displays and those not showing the splash. + continue; + } + displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; + if (common_hal_displayio_epaperdisplay_get_time_to_refresh(display) != 0) { + return false; + } + return common_hal_displayio_epaperdisplay_refresh(display); + } + // Return true if no ePaper displays are available to pretend it was updated. + return true; +} diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 88b5ebfaf..2be2add4b 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -60,6 +60,7 @@ typedef struct { void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); void release_epaperdisplay(displayio_epaperdisplay_obj_t* self); +bool maybe_refresh_epaperdisplay(void); void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 0a3b1fd10..a41884c78 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -54,6 +54,19 @@ void displayio_background(void) { } void common_hal_displayio_release_displays(void) { + // Release displays before busses so that they can send any final commands to turn the display + // off properly. + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + mp_const_obj_t display_type = displays[i].display.base.type; + if (display_type == NULL || display_type == &mp_type_NoneType) { + continue; + } else if (display_type == &displayio_display_type) { + release_display(&displays[i].display); + } else if (display_type == &displayio_epaperdisplay_type) { + release_epaperdisplay(&displays[i].epaper_display); + } + displays[i].display.base.type = &mp_type_NoneType; + } for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { mp_const_obj_t bus_type = displays[i].fourwire_bus.base.type; if (bus_type == NULL || bus_type == &mp_type_NoneType) { @@ -67,17 +80,6 @@ void common_hal_displayio_release_displays(void) { } displays[i].fourwire_bus.base.type = &mp_type_NoneType; } - for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - mp_const_obj_t display_type = displays[i].display.base.type; - if (display_type == NULL || display_type == &mp_type_NoneType) { - continue; - } else if (display_type == &displayio_display_type) { - release_display(&displays[i].display); - } else if (display_type == &displayio_epaperdisplay_type) { - release_epaperdisplay(&displays[i].epaper_display); - } - displays[i].display.base.type = &mp_type_NoneType; - } supervisor_stop_terminal(); } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index f8a8d8fea..24d8ab51f 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -52,6 +52,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->current_group = NULL; self->colstart = colstart; self->rowstart = rowstart; + self->last_refresh = 0; if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { self->bus_reset = common_hal_displayio_parallelbus_reset; @@ -140,7 +141,7 @@ bool displayio_display_core_show(displayio_display_core_t* self, displayio_group if (!circuitpython_splash.in_group) { root_group = &circuitpython_splash; } else if (self->current_group == &circuitpython_splash) { - return false; + return true; } } if (root_group == self->current_group) { -- cgit v1.2.3 From 3a98de12368a63de1538f61da7690e9fa230b540 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 21 Aug 2019 11:49:49 -0700 Subject: Add reset() to display busses to detect whether it works --- .../boards/itsybitsy_m0_express/mpconfigboard.mk | 3 +++ ports/atmel-samd/common-hal/displayio/ParallelBus.c | 7 ++++++- shared-bindings/displayio/FourWire.c | 16 ++++++++++++++++ shared-bindings/displayio/FourWire.h | 2 +- shared-bindings/displayio/I2CDisplay.c | 16 ++++++++++++++++ shared-bindings/displayio/I2CDisplay.h | 2 +- shared-bindings/displayio/ParallelBus.c | 16 ++++++++++++++++ shared-bindings/displayio/ParallelBus.h | 2 +- shared-module/displayio/FourWire.c | 8 +++++++- shared-module/displayio/I2CDisplay.c | 10 +++++++--- shared-module/displayio/display_core.h | 2 +- 11 files changed, 75 insertions(+), 9 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk index fd66f425d..410a0e087 100644 --- a/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/itsybitsy_m0_express/mpconfigboard.mk @@ -12,6 +12,9 @@ EXTERNAL_FLASH_DEVICE_COUNT = 2 EXTERNAL_FLASH_DEVICES = "W25Q16FW, GD25Q16C" LONGINT_IMPL = MPZ +CIRCUITPY_I2CSLAVE = 0 +CIRCUITPY_RTC = 0 + CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 diff --git a/ports/atmel-samd/common-hal/displayio/ParallelBus.c b/ports/atmel-samd/common-hal/displayio/ParallelBus.c index a43d20511..e2ce9952b 100644 --- a/ports/atmel-samd/common-hal/displayio/ParallelBus.c +++ b/ports/atmel-samd/common-hal/displayio/ParallelBus.c @@ -79,6 +79,7 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel self->write_group = &PORT->Group[write->number / 32]; self->write_mask = 1 << (write->number % 32); + self->reset.base.type = &mp_type_NoneType; if (reset != NULL) { self->reset.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->reset, reset); @@ -108,12 +109,16 @@ void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self) reset_pin_number(self->reset.pin->number); } -void common_hal_displayio_parallelbus_reset(mp_obj_t obj) { +bool common_hal_displayio_parallelbus_reset(mp_obj_t obj) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); + if (self->reset.base.type == &mp_type_NoneType) { + return false; + } common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_mcu_delay_us(4); common_hal_digitalio_digitalinout_set_value(&self->reset, true); + return true; } bool common_hal_displayio_parallelbus_bus_free(mp_obj_t obj) { diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index efd553e2e..c69623344 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -103,6 +103,21 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_ return self; } +//| .. method:: reset() +//| +//| Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin +//| is available. +//| +STATIC mp_obj_t displayio_fourwire_obj_reset(mp_obj_t self_in) { + displayio_fourwire_obj_t *self = self_in; + + if (!common_hal_displayio_fourwire_reset(self)) { + mp_raise_RuntimeError(translate("no reset pin available")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_fourwire_reset_obj, displayio_fourwire_obj_reset); + //| .. method:: send(command, data, *, toggle_every_byte=False) //| //| Sends the given command value followed by the full set of data. Display state, such as @@ -140,6 +155,7 @@ STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_a MP_DEFINE_CONST_FUN_OBJ_KW(displayio_fourwire_send_obj, 3, displayio_fourwire_obj_send); STATIC const mp_rom_map_elem_t displayio_fourwire_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_fourwire_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_fourwire_send_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_fourwire_locals_dict, displayio_fourwire_locals_dict_table); diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h index ee69a63ac..9c71d63cc 100644 --- a/shared-bindings/displayio/FourWire.h +++ b/shared-bindings/displayio/FourWire.h @@ -40,7 +40,7 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self); -void common_hal_displayio_fourwire_reset(mp_obj_t self); +bool common_hal_displayio_fourwire_reset(mp_obj_t self); bool common_hal_displayio_fourwire_bus_free(mp_obj_t self); bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index 4428e8dbb..4de5e83ef 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -95,6 +95,21 @@ STATIC mp_obj_t displayio_i2cdisplay_make_new(const mp_obj_type_t *type, size_t return self; } +//| .. method:: reset() +//| +//| Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin +//| is available. +//| +STATIC mp_obj_t displayio_i2cdisplay_obj_reset(mp_obj_t self_in) { + displayio_i2cdisplay_obj_t *self = self_in; + + if (!common_hal_displayio_i2cdisplay_reset(self)) { + mp_raise_RuntimeError(translate("no reset pin available")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_i2cdisplay_reset_obj, displayio_i2cdisplay_obj_reset); + //| .. method:: send(command, data) //| //| Sends the given command value followed by the full set of data. Display state, such as @@ -124,6 +139,7 @@ STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_ob MP_DEFINE_CONST_FUN_OBJ_3(displayio_i2cdisplay_send_obj, displayio_i2cdisplay_obj_send); STATIC const mp_rom_map_elem_t displayio_i2cdisplay_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_i2cdisplay_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_i2cdisplay_send_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_i2cdisplay_locals_dict, displayio_i2cdisplay_locals_dict_table); diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h index 6a75fc488..683cff383 100644 --- a/shared-bindings/displayio/I2CDisplay.h +++ b/shared-bindings/displayio/I2CDisplay.h @@ -37,7 +37,7 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self); -void common_hal_displayio_i2cdisplay_reset(mp_obj_t self); +bool common_hal_displayio_i2cdisplay_reset(mp_obj_t self); bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self); bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index e260f9b7e..a08c37679 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -106,6 +106,21 @@ STATIC mp_obj_t displayio_parallelbus_make_new(const mp_obj_type_t *type, size_t return self; } +//| .. method:: reset() +//| +//| Performs a hardware reset via the reset pin. Raises an exception if called when no reset pin +//| is available. +//| +STATIC mp_obj_t displayio_parallelbus_obj_reset(mp_obj_t self_in) { + displayio_parallelbus_obj_t *self = self_in; + + if (!common_hal_displayio_parallelbus_reset(self)) { + mp_raise_RuntimeError(translate("no reset pin available")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_parallelbus_reset_obj, displayio_parallelbus_obj_reset); + //| .. method:: send(command, data) //| //| Sends the given command value followed by the full set of data. Display state, such as @@ -133,6 +148,7 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o MP_DEFINE_CONST_FUN_OBJ_3(displayio_parallelbus_send_obj, displayio_parallelbus_obj_send); STATIC const mp_rom_map_elem_t displayio_parallelbus_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&displayio_parallelbus_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_parallelbus_send_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_parallelbus_locals_dict, displayio_parallelbus_locals_dict_table); diff --git a/shared-bindings/displayio/ParallelBus.h b/shared-bindings/displayio/ParallelBus.h index b8da91041..a0f967332 100644 --- a/shared-bindings/displayio/ParallelBus.h +++ b/shared-bindings/displayio/ParallelBus.h @@ -40,7 +40,7 @@ void common_hal_displayio_parallelbus_construct(displayio_parallelbus_obj_t* sel void common_hal_displayio_parallelbus_deinit(displayio_parallelbus_obj_t* self); -void common_hal_displayio_parallelbus_reset(mp_obj_t self); +bool common_hal_displayio_parallelbus_reset(mp_obj_t self); bool common_hal_displayio_parallelbus_bus_free(mp_obj_t self); bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self); diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 64ad80665..7294e9772 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -55,7 +55,9 @@ void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select); common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL); + self->reset.base.type = &mp_type_NoneType; if (reset != NULL) { + self->reset.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); @@ -76,12 +78,16 @@ void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self) { reset_pin_number(self->reset.pin->number); } -void common_hal_displayio_fourwire_reset(mp_obj_t obj) { +bool common_hal_displayio_fourwire_reset(mp_obj_t obj) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); + if (self->reset.base.type == &mp_type_NoneType) { + return false; + } common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_time_delay_ms(1); common_hal_digitalio_digitalinout_set_value(&self->reset, true); common_hal_time_delay_ms(1); + return true; } bool common_hal_displayio_fourwire_bus_free(mp_obj_t obj) { diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 23ebc0889..95830ba0e 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -55,7 +55,9 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, self->address = device_address; + self->reset.base.type = &mp_type_NoneType; if (reset != NULL) { + self->reset.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->reset, reset); common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); never_reset_pin_number(reset->number); @@ -71,16 +73,18 @@ void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { reset_pin_number(self->reset.pin->number); } - -void common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { +bool common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); + if (self->reset.base.type == &mp_type_NoneType) { + return false; + } common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_mcu_delay_us(1); common_hal_digitalio_digitalinout_set_value(&self->reset, true); + return true; } - bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t obj) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); if (!common_hal_busio_i2c_try_lock(self->bus)) { diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index c837ce913..b1a412883 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -33,7 +33,7 @@ #define NO_COMMAND 0x100 -typedef void (*display_bus_bus_reset)(mp_obj_t bus); +typedef bool (*display_bus_bus_reset)(mp_obj_t bus); typedef bool (*display_bus_bus_free)(mp_obj_t bus); typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); -- cgit v1.2.3 From f2a1972ba8a3eeeed33f9ac693ef4176c883aec4 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 21 Aug 2019 13:15:35 -0700 Subject: Add refresh_time to use if busy_pin is not given --- shared-bindings/displayio/EPaperDisplay.c | 11 +++++++---- shared-bindings/displayio/EPaperDisplay.h | 2 +- shared-module/displayio/EPaperDisplay.c | 14 +++++++++++--- shared-module/displayio/EPaperDisplay.h | 1 + 4 files changed, 20 insertions(+), 8 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 8f3c16efd..dd773e410 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -51,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the startup and shutdown sequences at minimum. //| -//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, highlight_color=0x000000, refresh_display_command, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) +//| .. class:: EPaperDisplay(display_bus, start_sequence, stop_sequence, *, width, height, ram_width, ram_height, colstart=0, rowstart=0, rotation=0, set_column_window_command=None, set_row_window_command=None, single_byte_bounds=False, write_black_ram_command, black_bits_inverted=False, write_color_ram_command=None, color_bits_inverted=False, highlight_color=0x000000, refresh_display_command, refresh_time=40, busy_pin=None, busy_state=True, seconds_per_frame=180, always_toggle_chip_select=False) //| //| Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -83,13 +83,14 @@ //| :param bool color_bits_inverted: True if 0 bits are used to show the color. Otherwise, 1 means to show color. //| :param int highlight_color: RGB888 of source color to highlight with third ePaper color. //| :param int refresh_display_command: Command used to start a display refresh +//| :param float refresh_time: Time it takes to refresh the display before the stop_sequence should be sent. Ignored when busy_pin is provided. //| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy //| :param bool busy_state: State of the busy pin when the display is busy -//| :param int seconds_per_frame: Minimum number of seconds between screen refreshes +//| :param float seconds_per_frame: Minimum number of seconds between screen refreshes //| :param bool always_toggle_chip_select: When True, chip select is toggled every byte //| STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_refresh_display_command, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; + enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -111,6 +112,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size { MP_QSTR_color_bits_inverted, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_highlight_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x000000} }, { MP_QSTR_refresh_display_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_refresh_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(40)} }, { MP_QSTR_busy_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_seconds_per_frame, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} }, @@ -152,6 +154,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size mp_raise_RuntimeError(translate("Too many displays")); } + mp_float_t refresh_time = mp_obj_get_float(args[ARG_refresh_time].u_obj); mp_float_t seconds_per_frame = mp_obj_get_float(args[ARG_seconds_per_frame].u_obj); mp_int_t write_color_ram_command = NO_COMMAND; @@ -168,7 +171,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int, args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int, - args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, + args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time, busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool ); diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 2a3cb921f..786fc3628 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -43,7 +43,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, - uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, + uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 7e65502d4..bf0e6676f 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -48,7 +48,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, - uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, + uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time, const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select) { if (highlight_color != 0x000000) { self->core.colorspace.tricolor = true; @@ -67,6 +67,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->write_color_ram_command = write_color_ram_command; self->color_bits_inverted = color_bits_inverted; self->refresh_display_command = refresh_display_command; + self->refresh_time = refresh_time * 1000; self->busy_state = busy_state; self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; @@ -336,8 +337,15 @@ bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* s } void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) { - if (self->refreshing && self->busy.base.type == &digitalio_digitalinout_type) { - if (common_hal_digitalio_digitalinout_get_value(&self->busy) != self->busy_state) { + if (self->refreshing) { + bool refresh_done = false; + if (self->busy.base.type == &digitalio_digitalinout_type) { + bool busy = common_hal_digitalio_digitalinout_get_value(&self->busy); + refresh_done = busy != self->busy_state; + } else { + refresh_done = ticks_ms - self->core.last_refresh > self->refresh_time; + } + if (refresh_done) { self->refreshing = false; // Run stop sequence but don't wait for busy because busy is set when sleeping. send_command_sequence(self, false, self->stop_sequence, self->stop_sequence_len); diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 2be2add4b..a5d4ec93f 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -43,6 +43,7 @@ typedef struct { uint32_t start_sequence_len; uint8_t* stop_sequence; uint32_t stop_sequence_len; + uint16_t refresh_time; uint16_t set_column_window_command; uint16_t set_row_window_command; uint16_t set_current_column_command; -- cgit v1.2.3 From 8d836fa248d10b8943945423a069a3fba387f8a2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 22 Aug 2019 00:33:27 -0700 Subject: Regular display fixes including refresh tweaks --- shared-module/displayio/Display.c | 25 ++++++++++++++++++------- shared-module/displayio/Display.h | 2 ++ shared-module/displayio/EPaperDisplay.c | 8 +++++--- shared-module/displayio/TileGrid.c | 2 +- shared-module/displayio/TileGrid.h | 2 +- shared-module/displayio/__init__.c | 4 +--- shared-module/displayio/display_core.c | 11 +++++++---- 7 files changed, 35 insertions(+), 19 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 86800328f..109b91507 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -64,21 +64,23 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->write_ram_command = write_ram_command; self->brightness_command = brightness_command; self->auto_brightness = auto_brightness; + self->auto_refresh = auto_refresh; + self->first_manual_refresh = !auto_refresh; self->data_as_commands = data_as_commands; self->native_frames_per_second = native_frames_per_second; self->native_frame_time = 1000 / native_frames_per_second; uint32_t i = 0; - while (!displayio_display_core_begin_transaction(&self->core)) { - RUN_BACKGROUND_TASKS; - } while (i < init_sequence_len) { uint8_t *cmd = init_sequence + i; uint8_t data_size = *(cmd + 1); bool delay = (data_size & DELAY) != 0; data_size &= ~DELAY; uint8_t *data = cmd + 2; + while (!displayio_display_core_begin_transaction(&self->core)) { + RUN_BACKGROUND_TASKS; + } if (self->data_as_commands) { uint8_t full_command[data_size + 1]; full_command[0] = cmd[0]; @@ -88,6 +90,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->core.send(self->core.bus, true, true, cmd, 1); self->core.send(self->core.bus, false, false, data, data_size); } + self->core.end_transaction(self->core.bus); uint16_t delay_length_ms = 10; if (delay) { data_size++; @@ -99,7 +102,6 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, common_hal_time_delay_ms(delay_length_ms); i += 2 + data_size; } - self->core.end_transaction(self->core.bus); supervisor_start_terminal(width, height); @@ -192,9 +194,10 @@ STATIC const displayio_area_t* _get_refresh_areas(displayio_display_obj_t *self) if (self->core.full_refresh) { self->core.area.next = NULL; return &self->core.area; - } else { + } else if (self->core.current_group != NULL) { return displayio_group_get_refresh_areas(self->core.current_group, NULL); } + return NULL; } STATIC void _send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { @@ -242,7 +245,7 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* // Allocated and shared as a uint32_t array so the compiler knows the // alignment everywhere. uint32_t buffer[buffer_size]; - volatile uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask_length = (pixels_per_buffer / 32) + 1; uint32_t mask[mask_length]; uint16_t remaining_rows = displayio_area_height(&clipped); @@ -311,7 +314,7 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self } void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time) { - if (!self->auto_refresh) { + if (!self->auto_refresh && !self->first_manual_refresh) { uint64_t current_time = ticks_ms; uint32_t current_frame_time = current_time - self->core.last_refresh; // Test to see if the real frame time is below our minimum. @@ -332,6 +335,7 @@ void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_ #endif } } + self->first_manual_refresh = false; _refresh_display(self); } @@ -341,6 +345,7 @@ bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, bool auto_refresh) { + self->first_manual_refresh = !auto_refresh; self->auto_refresh = auto_refresh; } @@ -376,6 +381,12 @@ void release_display(displayio_display_obj_t* self) { } } +void reset_display(displayio_display_obj_t* self) { + self->auto_refresh = true; + self->auto_brightness = true; + common_hal_displayio_display_show(self, NULL); +} + void displayio_display_collect_ptrs(displayio_display_obj_t* self) { displayio_display_core_collect_ptrs(&self->core); } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index cff566a61..bf2889c6d 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -51,6 +51,7 @@ typedef struct { uint8_t set_row_command; uint8_t write_ram_command; bool auto_refresh; + bool first_manual_refresh; bool data_as_commands; bool auto_brightness; bool updating_backlight; @@ -58,6 +59,7 @@ typedef struct { void displayio_display_background(displayio_display_obj_t* self); void release_display(displayio_display_obj_t* self); +void reset_display(displayio_display_obj_t* self); void displayio_display_collect_ptrs(displayio_display_obj_t* self); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index bf0e6676f..48143f14f 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -102,10 +102,12 @@ bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self } const displayio_area_t* displayio_epaperdisplay_get_refresh_areas(displayio_epaperdisplay_obj_t *self) { - const displayio_area_t* first_area; if (self->core.full_refresh) { - first_area = &self->core.area; - } else { + self->core.area.next = NULL; + return &self->core.area; + } + const displayio_area_t* first_area = NULL; + if (self->core.current_group != NULL) { first_area = displayio_group_get_refresh_areas(self->core.current_group, NULL); } if (first_area != NULL && self->set_row_window_command == NO_COMMAND) { diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 6553cf901..f34d2fc52 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -207,7 +207,7 @@ uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint1 void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index) { if (tile_index >= self->tiles_in_bitmap) { - mp_raise_ValueError(translate("Tile value out of bounds")); + mp_raise_ValueError(translate("Tile index out of bounds")); } uint8_t* tiles = self->tiles; if (self->inline_tiles) { diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index 222aaed19..0a414b062 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -43,7 +43,7 @@ typedef struct { uint16_t pixel_width; uint16_t pixel_height; uint16_t bitmap_width_in_tiles;; - uint8_t tiles_in_bitmap; + uint16_t tiles_in_bitmap; uint16_t width_in_tiles; uint16_t height_in_tiles; uint16_t tile_width; diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index a41884c78..af22cb0df 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -143,9 +143,7 @@ void reset_displays(void) { // Reset the displayed group. Only the first will get the terminal but // that's ok. if (displays[i].display.base.type == &displayio_display_type) { - displayio_display_obj_t* display = &displays[i].display; - display->auto_brightness = true; - common_hal_displayio_display_show(display, NULL); + reset_display(&displays[i].display); } else if (displays[i].epaper_display.base.type == &displayio_epaperdisplay_type) { displayio_epaperdisplay_obj_t* display = &displays[i].epaper_display; common_hal_displayio_epaperdisplay_show(display, NULL); diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 24d8ab51f..88878866a 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -82,8 +82,8 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->width = width; self->height = height; - self->ram_width = width; - self->ram_height = height; + self->ram_width = ram_width; + self->ram_height = ram_height; rotation = rotation % 360; self->transform.x = 0; self->transform.y = 0; @@ -206,7 +206,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[0] = column_command; uint8_t data_length = 1; if (!data_as_commands) { - self->send(self->bus, true, true, data, 1); + self->send(self->bus, true, false, data, 1); data_length = 0; } if (self->ram_width < 0x100) { @@ -227,11 +227,14 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); } + displayio_display_core_end_transaction(self); + displayio_display_core_begin_transaction(self); + // Set row. data[0] = row_command; data_length = 1; if (!data_as_commands) { - self->send(self->bus, true, true, data, 1); + self->send(self->bus, true, false, data, 1); data_length = 0; } if (self->ram_height < 0x100) { -- cgit v1.2.3 From 72e7ffa324f8184cb2d9a5ca9fa620a2a5a56b69 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 22 Aug 2019 16:16:09 -0700 Subject: More cleanup --- ports/atmel-samd/boards/snekboard/mpconfigboard.mk | 3 +++ shared-bindings/displayio/EPaperDisplay.c | 2 +- shared-bindings/displayio/EPaperDisplay.h | 6 ------ shared-module/displayio/ColorConverter.c | 1 - shared-module/displayio/Group.c | 3 --- shared-module/displayio/OnDiskBitmap.c | 4 +--- 6 files changed, 5 insertions(+), 14 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk index 9892ade8f..6ad78b0da 100644 --- a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk +++ b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk @@ -12,5 +12,8 @@ EXTERNAL_FLASH_DEVICE_COUNT = 1 EXTERNAL_FLASH_DEVICES = "W25Q16JV_IQ" LONGINT_IMPL = MPZ +CIRCUITPY_GAMEPAD = 0 +CIRCUITPY_I2CSLAVE = 0 + CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index dd773e410..5d0d8ac94 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -42,7 +42,7 @@ //| .. currentmodule:: displayio //| //| :class:`EPaperDisplay` -- Manage updating an epaper display over a display bus -//| ========================================================================== +//| ============================================================================== //| //| This initializes an epaper display and connects it into CircuitPython. Unlike other //| objects in CircuitPython, EPaperDisplay objects live until `displayio.release_displays()` diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 786fc3628..e4b81c883 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -53,15 +53,9 @@ bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self // Returns time in milliseconds. uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); -bool common_hal_displayio_epaperdisplay_get_auto_brightness(displayio_epaperdisplay_obj_t* self); -void common_hal_displayio_epaperdisplay_set_auto_brightness(displayio_epaperdisplay_obj_t* self, bool auto_brightness); - uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self); uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self); -mp_float_t common_hal_displayio_epaperdisplay_get_brightness(displayio_epaperdisplay_obj_t* self); -bool common_hal_displayio_epaperdisplay_set_brightness(displayio_epaperdisplay_obj_t* self, mp_float_t brightness); - mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_EPAPERDISPLAY_H diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 0277c79f0..e0c4ca286 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -142,7 +142,6 @@ bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d uint8_t luma = displayio_colorconverter_compute_luma(input_color); *output_color = luma >> (8 - colorspace->depth); return true; - } else if (!colorspace->grayscale && colorspace->depth == 1) { } return false; } diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index eb6e9a453..38418a029 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -304,9 +304,6 @@ void displayio_group_finish_refresh(displayio_group_t *self) { } displayio_area_t* displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t* tail) { - if (self->base.type != &displayio_group_type) { - asm("bkpt"); - } if (self->item_removed) { self->dirty_area.next = tail; tail = &self->dirty_area; diff --git a/shared-module/displayio/OnDiskBitmap.c b/shared-module/displayio/OnDiskBitmap.c index 10fc0c4a2..993fc03de 100644 --- a/shared-module/displayio/OnDiskBitmap.c +++ b/shared-module/displayio/OnDiskBitmap.c @@ -149,10 +149,8 @@ uint32_t common_hal_displayio_ondiskbitmap_get_pixel(displayio_ondiskbitmap_t *s if (self->bits_per_pixel == 1) { if (index == 1) { return 0xFFFFFF; - } else if (index == 0) { - return 0x000000; } else { - asm("bkpt"); + return 0x000000; } } return self->palette_data[index]; -- cgit v1.2.3 From 7324b70a7c231a20be971ed81050c8359b87aaab Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 23 Aug 2019 15:27:21 -0700 Subject: Rework based on Dan's review --- .../atmel-samd/boards/monster_m4sk/mpconfigboard.h | 2 - .../atmel-samd/common-hal/displayio/ParallelBus.c | 4 +- ports/nrf/common-hal/displayio/ParallelBus.c | 5 ++- py/circuitpy_mpconfig.h | 4 -- shared-bindings/_stage/__init__.c | 2 +- shared-bindings/displayio/Display.c | 24 +++++++---- shared-bindings/displayio/Display.h | 2 +- shared-bindings/displayio/EPaperDisplay.c | 2 +- shared-bindings/displayio/FourWire.c | 8 +++- shared-bindings/displayio/FourWire.h | 4 +- shared-bindings/displayio/I2CDisplay.c | 2 +- shared-bindings/displayio/I2CDisplay.h | 4 +- shared-bindings/displayio/ParallelBus.c | 4 +- shared-bindings/displayio/ParallelBus.h | 5 ++- shared-bindings/displayio/__init__.h | 19 +++++++++ shared-module/_stage/__init__.c | 4 +- shared-module/displayio/ColorConverter.c | 38 +++-------------- shared-module/displayio/Display.c | 47 ++++++++++------------ shared-module/displayio/Display.h | 2 +- shared-module/displayio/EPaperDisplay.c | 24 +++++------ shared-module/displayio/EPaperDisplay.h | 2 +- shared-module/displayio/FourWire.c | 7 ++-- shared-module/displayio/I2CDisplay.c | 7 ++-- shared-module/displayio/display_core.c | 38 +++++++++++------ shared-module/displayio/display_core.h | 7 +--- supervisor/shared/filesystem.c | 2 +- 26 files changed, 137 insertions(+), 132 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h b/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h index 484f3d7b2..fc77520f5 100644 --- a/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h +++ b/ports/atmel-samd/boards/monster_m4sk/mpconfigboard.h @@ -27,5 +27,3 @@ // USB is always used internally so skip the pin objects for it. #define IGNORE_PIN_PA24 1 #define IGNORE_PIN_PA25 1 - -#define CIRCUITPY_FS_NAME "MONSTERM4SK" diff --git a/ports/atmel-samd/common-hal/displayio/ParallelBus.c b/ports/atmel-samd/common-hal/displayio/ParallelBus.c index e2ce9952b..2479e3b40 100644 --- a/ports/atmel-samd/common-hal/displayio/ParallelBus.c +++ b/ports/atmel-samd/common-hal/displayio/ParallelBus.c @@ -131,9 +131,9 @@ bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_parallelbus_send(mp_obj_t obj, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); - common_hal_digitalio_digitalinout_set_value(&self->command, !command); + common_hal_digitalio_digitalinout_set_value(&self->command, byte_type == DISPLAY_DATA); uint32_t* clear_write = (uint32_t*) &self->write_group->OUTCLR.reg; uint32_t* set_write = (uint32_t*) &self->write_group->OUTSET.reg; uint32_t mask = self->write_mask; diff --git a/ports/nrf/common-hal/displayio/ParallelBus.c b/ports/nrf/common-hal/displayio/ParallelBus.c index a8c2b9f73..be4b28a6e 100644 --- a/ports/nrf/common-hal/displayio/ParallelBus.c +++ b/ports/nrf/common-hal/displayio/ParallelBus.c @@ -142,9 +142,10 @@ bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_parallelbus_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { +// This ignores chip_select behaviour because data is clocked in by the write line toggling. +void common_hal_displayio_parallelbus_send(mp_obj_t obj, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { displayio_parallelbus_obj_t* self = MP_OBJ_TO_PTR(obj); - common_hal_digitalio_digitalinout_set_value(&self->command, !command); + common_hal_digitalio_digitalinout_set_value(&self->command, byte_type == DISPLAY_DATA); uint32_t* clear_write = (uint32_t*) &self->write_group->OUTCLR; uint32_t* set_write = (uint32_t*) &self->write_group->OUTSET; uint32_t mask = self->write_mask; diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 923c02b9e..c2e2e2d02 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -657,8 +657,4 @@ void run_background_tasks(void); #define CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS 1000 #define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt" -#ifndef CIRCUITPY_FS_NAME -#define CIRCUITPY_FS_NAME "CIRCUITPY" -#endif - #endif // __INCLUDED_MPCONFIG_CIRCUITPY_H diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 1d970cce4..d18d306f4 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -107,7 +107,7 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { area.y2 = y1; displayio_display_core_set_region_to_update(&display->core, display->set_column_command, display->set_row_command, NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area); - display->core.send(display->core.bus, true, true, &display->write_ram_command, 1); + display->core.send(display->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &display->write_ram_command, 1); render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display, scale); displayio_display_core_end_transaction(&display->core); diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index ded4119ca..1eb1943b8 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -218,16 +218,22 @@ STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) } MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); -//| .. method:: refresh(*, target_frames_per_second=None, minimum_frames_per_second=1) +//| .. method:: refresh(*, target_frames_per_second=60, minimum_frames_per_second=1) //| -//| When auto refresh is off, waits for the target frame rate and then refreshes the display. If -//| the call is too late for the given target frame rate, then the refresh returns immediately -//| without updating the screen to hopefully help getting caught up. If the current frame rate -//| is below the minimum frame rate, then an exception will be raised. +//| When auto refresh is off, waits for the target frame rate and then refreshes the display, +//| returning True. If the call has taken too long since the last refresh call for the given +//| target frame rate, then the refresh returns False immediately without updating the screen to +//| hopefully help getting caught up. +//| +//| If the time since the last successful refresh is below the minimum frame rate, then an +//| exception will be raised. Set minimum_frames_per_second to 0 to disable. //| //| When auto refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| +//| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. +//| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second. +//| STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; static const mp_arg_t allowed_args[] = { @@ -238,8 +244,12 @@ STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); displayio_display_obj_t *self = native_display(pos_args[0]); - common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, 1000 / args[ARG_minimum_frames_per_second].u_int); - return mp_const_none; + uint32_t maximum_ms_per_real_frame = 0xffffffff; + mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int; + if (minimum_frames_per_second > 0) { + maximum_ms_per_real_frame = 1000 / minimum_frames_per_second; + } + return mp_obj_new_bool(common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, maximum_ms_per_real_frame)); } MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh); diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 06c848d0d..2d7b68c4e 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -51,7 +51,7 @@ bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); // Times in ms. -void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time); +bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame); bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self); void common_hal_displayio_display_set_auto_refresh(displayio_display_obj_t* self, bool auto_refresh); diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 5d0d8ac94..81e06f82f 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -55,7 +55,7 @@ //| //| Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| -//| The ``start_sequence`` and ``stop_sequence`` bitpacked to minimize the ram impact. Every +//| The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every //| command begins with a command byte followed by a byte to determine the parameter count and if //| a delay is need after. When the top bit of the second byte is 1, the next byte will be the //| delay time in milliseconds. The remaining 7 bits are the parameter count excluding any delay diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index c69623344..51203d460 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -146,8 +146,12 @@ STATIC mp_obj_t displayio_fourwire_obj_send(size_t n_args, const mp_obj_t *pos_a while (!common_hal_displayio_fourwire_begin_transaction(self)) { RUN_BACKGROUND_TASKS; } - common_hal_displayio_fourwire_send(self, true, args[ARG_toggle_every_byte].u_bool, &command, 1); - common_hal_displayio_fourwire_send(self, false, args[ARG_toggle_every_byte].u_bool, ((uint8_t*) bufinfo.buf), bufinfo.len); + display_chip_select_behavior_t chip_select = CHIP_SELECT_UNTOUCHED; + if (args[ARG_toggle_every_byte].u_bool) { + chip_select = CHIP_SELECT_TOGGLE_EVERY_BYTE; + } + common_hal_displayio_fourwire_send(self, DISPLAY_COMMAND, chip_select, &command, 1); + common_hal_displayio_fourwire_send(self, DISPLAY_DATA, chip_select, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_fourwire_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h index 9c71d63cc..d0935f063 100644 --- a/shared-bindings/displayio/FourWire.h +++ b/shared-bindings/displayio/FourWire.h @@ -28,6 +28,8 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_FOURWIRE_H #include "shared-module/displayio/FourWire.h" + +#include "shared-bindings/displayio/__init__.h" #include "common-hal/microcontroller/Pin.h" #include "shared-module/displayio/Group.h" @@ -45,7 +47,7 @@ bool common_hal_displayio_fourwire_bus_free(mp_obj_t self); bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self); -void common_hal_displayio_fourwire_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +void common_hal_displayio_fourwire_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); void common_hal_displayio_fourwire_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c index 4de5e83ef..4339d182f 100644 --- a/shared-bindings/displayio/I2CDisplay.c +++ b/shared-bindings/displayio/I2CDisplay.c @@ -131,7 +131,7 @@ STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_ob uint8_t full_command[bufinfo.len + 1]; full_command[0] = command; memcpy(full_command + 1, ((uint8_t*) bufinfo.buf), bufinfo.len); - common_hal_displayio_i2cdisplay_send(self, true, false, full_command, bufinfo.len + 1); + common_hal_displayio_i2cdisplay_send(self, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, full_command, bufinfo.len + 1); common_hal_displayio_i2cdisplay_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h index 683cff383..bae53c491 100644 --- a/shared-bindings/displayio/I2CDisplay.h +++ b/shared-bindings/displayio/I2CDisplay.h @@ -28,6 +28,8 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H #include "shared-module/displayio/I2CDisplay.h" + +#include "shared-bindings/displayio/__init__.h" #include "common-hal/microcontroller/Pin.h" extern const mp_obj_type_t displayio_i2cdisplay_type; @@ -42,7 +44,7 @@ bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self); bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); -void common_hal_displayio_i2cdisplay_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +void common_hal_displayio_i2cdisplay_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index a08c37679..f7195b9cc 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -139,8 +139,8 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o while (!common_hal_displayio_parallelbus_begin_transaction(self)) { RUN_BACKGROUND_TASKS; } - common_hal_displayio_parallelbus_send(self, true, false, &command, 1); - common_hal_displayio_parallelbus_send(self, false, false, ((uint8_t*) bufinfo.buf), bufinfo.len); + common_hal_displayio_parallelbus_send(self, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, &command, 1); + common_hal_displayio_parallelbus_send(self, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*) bufinfo.buf), bufinfo.len); common_hal_displayio_parallelbus_end_transaction(self); return mp_const_none; diff --git a/shared-bindings/displayio/ParallelBus.h b/shared-bindings/displayio/ParallelBus.h index a0f967332..be2aef7d4 100644 --- a/shared-bindings/displayio/ParallelBus.h +++ b/shared-bindings/displayio/ParallelBus.h @@ -28,8 +28,9 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_PARALLELBUS_H #include "common-hal/displayio/ParallelBus.h" -#include "common-hal/microcontroller/Pin.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/displayio/__init__.h" #include "shared-module/displayio/Group.h" extern const mp_obj_type_t displayio_parallelbus_type; @@ -45,7 +46,7 @@ bool common_hal_displayio_parallelbus_bus_free(mp_obj_t self); bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self); -void common_hal_displayio_parallelbus_send(mp_obj_t self, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); +void common_hal_displayio_parallelbus_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); void common_hal_displayio_parallelbus_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/__init__.h b/shared-bindings/displayio/__init__.h index 427ddb47d..122b1fbcb 100644 --- a/shared-bindings/displayio/__init__.h +++ b/shared-bindings/displayio/__init__.h @@ -27,6 +27,25 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H #define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H +#include "py/obj.h" + +typedef enum { + DISPLAY_COMMAND, + DISPLAY_DATA +} display_byte_type_t; + + +typedef enum { + CHIP_SELECT_UNTOUCHED, + CHIP_SELECT_TOGGLE_EVERY_BYTE +} display_chip_select_behavior_t; + +typedef bool (*display_bus_bus_reset)(mp_obj_t bus); +typedef bool (*display_bus_bus_free)(mp_obj_t bus); +typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); +typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_end_transaction)(mp_obj_t bus); + void common_hal_displayio_release_displays(void); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO___INIT___H diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index bfef165e7..2c525be87 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -57,7 +57,7 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, index += 1; // The buffer is full, send it. if (index >= buffer_size) { - display->core.send(display->core.bus, false, false, ((uint8_t*)buffer), + display->core.send(display->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*)buffer), buffer_size * 2); index = 0; } @@ -67,6 +67,6 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, } // Send the remaining data. if (index) { - display->core.send(display->core.bus, false, false, ((uint8_t*)buffer), index * 2); + display->core.send(display->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*)buffer), index * 2); } } diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index e0c4ca286..940aaa1c6 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -26,6 +26,8 @@ #include "shared-bindings/displayio/ColorConverter.h" +#include "py/misc.h" + void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self) { } @@ -45,39 +47,12 @@ uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888) { return (r8 * 19) / 255 + (g8 * 182) / 255 + (b8 + 54) / 255; } -void compute_bounds(uint8_t r8, uint8_t g8, uint8_t b8, uint8_t* min, uint8_t* max) { - if (r8 > g8) { - if (b8 > r8) { - *max = b8; - } else { - *max = r8; - } - if (b8 < g8) { - *min = b8; - } else { - *min = g8; - } - } else { - if (b8 > g8) { - *max = b8; - } else { - *max = g8; - } - if (b8 < r8) { - *min = b8; - } else { - *min = r8; - } - } -} - uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888) { uint32_t r8 = (color_rgb888 >> 16); uint32_t g8 = (color_rgb888 >> 8) & 0xff; uint32_t b8 = color_rgb888 & 0xff; - uint8_t max; - uint8_t min; - compute_bounds(r8, g8, b8, &min, &max); + uint8_t max = MAX(r8, MAX(g8, b8)); + uint8_t min = MIN(r8, MIN(g8, b8)); return max - min; } @@ -85,9 +60,8 @@ uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888) { uint32_t r8 = (color_rgb888 >> 16); uint32_t g8 = (color_rgb888 >> 8) & 0xff; uint32_t b8 = color_rgb888 & 0xff; - uint8_t max; - uint8_t min; - compute_bounds(r8, g8, b8, &min, &max); + uint8_t max = MAX(r8, MAX(g8, b8)); + uint8_t min = MIN(r8, MIN(g8, b8)); uint8_t c = max - min; if (c == 0) { return 0; diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 109b91507..cb5051bb7 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -69,7 +69,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->data_as_commands = data_as_commands; self->native_frames_per_second = native_frames_per_second; - self->native_frame_time = 1000 / native_frames_per_second; + self->native_ms_per_frame = 1000 / native_frames_per_second; uint32_t i = 0; while (i < init_sequence_len) { @@ -85,10 +85,10 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t full_command[data_size + 1]; full_command[0] = cmd[0]; memcpy(full_command + 1, data, data_size); - self->core.send(self->core.bus, true, true, full_command, data_size + 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, full_command, data_size + 1); } else { - self->core.send(self->core.bus, true, true, cmd, 1); - self->core.send(self->core.bus, false, false, data, data_size); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, cmd, 1); + self->core.send(self->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, data_size); } self->core.end_transaction(self->core.bus); uint16_t delay_length_ms = 10; @@ -168,12 +168,12 @@ bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, if (ok) { if (self->data_as_commands) { uint8_t set_brightness[2] = {self->brightness_command, (uint8_t) (0xff * brightness)}; - self->core.send(self->core.bus, true, true, set_brightness, 2); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, set_brightness, 2); } else { uint8_t command = self->brightness_command; uint8_t hex_brightness = 0xff * brightness; - self->core.send(self->core.bus, true, true, &command, 1); - self->core.send(self->core.bus, false, false, &hex_brightness, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &command, 1); + self->core.send(self->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, &hex_brightness, 1); } displayio_display_core_end_transaction(&self->core); } @@ -202,9 +202,9 @@ STATIC const displayio_area_t* _get_refresh_areas(displayio_display_obj_t *self) STATIC void _send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length) { if (!self->data_as_commands) { - self->core.send(self->core.bus, true, true, &self->write_ram_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &self->write_ram_command, 1); } - self->core.send(self->core.bus, false, false, pixels, length); + self->core.send(self->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, pixels, length); } STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* area) { @@ -270,12 +270,8 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); } - for (uint16_t k = 0; k < mask_length; k++) { - mask[k] = 0x00000000; - } - for (uint16_t k = 0; k < buffer_size; k++) { - buffer[k] = 0x00000000; - } + memset(mask, 0, mask_length * sizeof(uint32_t)); + memset(buffer, 0, buffer_size * sizeof(uint32_t)); displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); @@ -313,30 +309,29 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self return self->core.rotation; } -void common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_frame_time, uint32_t maximum_frame_time) { +bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame) { if (!self->auto_refresh && !self->first_manual_refresh) { uint64_t current_time = ticks_ms; - uint32_t current_frame_time = current_time - self->core.last_refresh; + uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; // Test to see if the real frame time is below our minimum. - if (current_frame_time > maximum_frame_time) { + if (current_ms_since_real_refresh > maximum_ms_per_real_frame) { mp_raise_RuntimeError(translate("Below minimum frame rate")); } - uint32_t current_call_time = current_time - self->last_refresh_call; + uint32_t current_ms_since_last_call = current_time - self->last_refresh_call; self->last_refresh_call = current_time; // Skip the actual refresh to help catch up. - if (current_call_time > target_frame_time) { - return; + if (current_ms_since_last_call > target_ms_per_frame) { + return false; } - uint32_t remaining_time = target_frame_time - (current_frame_time % target_frame_time); + uint32_t remaining_time = target_ms_per_frame - (current_ms_since_real_refresh % target_ms_per_frame); // We're ahead of the game so wait until we align with the frame rate. while (ticks_ms - self->last_refresh_call < remaining_time) { - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; - #endif + RUN_BACKGROUND_TASKS; } } self->first_manual_refresh = false; _refresh_display(self); + return true; } bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self) { @@ -366,7 +361,7 @@ STATIC void _update_backlight(displayio_display_obj_t* self) { void displayio_display_background(displayio_display_obj_t* self) { _update_backlight(self); - if (self->auto_refresh && (ticks_ms - self->core.last_refresh) > self->native_frame_time) { + if (self->auto_refresh && (ticks_ms - self->core.last_refresh) > self->native_ms_per_frame) { _refresh_display(self); } } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index bf2889c6d..e5fe0a708 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -46,7 +46,7 @@ typedef struct { mp_float_t current_brightness; uint16_t brightness_command; uint16_t native_frames_per_second; - uint16_t native_frame_time; + uint16_t native_ms_per_frame; uint8_t set_column_command; uint8_t set_row_command; uint8_t write_ram_command; diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 48143f14f..38b63df0f 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -71,7 +71,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->busy_state = busy_state; self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; - self->always_toggle_chip_select = always_toggle_chip_select; + self->always_toggle_chip_select = always_toggle_chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; self->start_sequence = start_sequence; self->start_sequence_len = start_sequence_len; @@ -130,9 +130,7 @@ STATIC void wait_for_busy(displayio_epaperdisplay_obj_t* self) { return; } while (common_hal_digitalio_digitalinout_get_value(&self->busy) == self->busy_state) { - #ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP - #endif + RUN_BACKGROUND_TASKS; } } @@ -145,8 +143,8 @@ STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool shou data_size &= ~DELAY; uint8_t *data = cmd + 2; displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, true, self->always_toggle_chip_select, cmd, 1); - self->core.send(self->core.bus, false, self->always_toggle_chip_select, data, data_size); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, cmd, 1); + self->core.send(self->core.bus, DISPLAY_DATA, self->always_toggle_chip_select, data, data_size); displayio_display_core_end_transaction(&self->core); uint16_t delay_length_ms = 0; if (delay) { @@ -187,7 +185,7 @@ uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaper void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { // Actually refresh the display now that all pixel RAM has been updated. displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, true, self->always_toggle_chip_select, &self->refresh_display_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, &self->refresh_display_command, 1); displayio_display_core_end_transaction(&self->core); self->refreshing = true; @@ -248,7 +246,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c write_command = self->write_color_ram_command; } displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, true, self->always_toggle_chip_select, &write_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, &write_command, 1); displayio_display_core_end_transaction(&self->core); for (uint16_t j = 0; j < subrectangles; j++) { @@ -266,12 +264,8 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); - for (uint16_t k = 0; k < mask_length; k++) { - mask[k] = 0x00000000; - } - for (uint16_t k = 0; k < buffer_size; k++) { - buffer[k] = 0x00000000; - } + memset(mask, 0, mask_length * sizeof(uint32_t)); + memset(buffer, 0, buffer_size * sizeof(uint32_t)); self->core.colorspace.grayscale = true; if (pass == 1) { @@ -291,7 +285,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c // Can't acquire display bus; skip the rest of the data. Try next display. return false; } - self->core.send(self->core.bus, false, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); + self->core.send(self->core.bus, DISPLAY_DATA, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); displayio_display_core_end_transaction(&self->core); // TODO(tannewt): Make refresh displays faster so we don't starve other diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index a5d4ec93f..580171a5f 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -56,7 +56,7 @@ typedef struct { bool black_bits_inverted; bool color_bits_inverted; bool refreshing; - bool always_toggle_chip_select; + display_chip_select_behavior_t always_toggle_chip_select; } displayio_epaperdisplay_obj_t; void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 7294e9772..fcc4c1a20 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -33,6 +33,7 @@ #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/display_core.h" #include "tick.h" @@ -110,10 +111,10 @@ bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_fourwire_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_fourwire_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); - common_hal_digitalio_digitalinout_set_value(&self->command, !command); - if (toggle_every_byte) { + common_hal_digitalio_digitalinout_set_value(&self->command, data_type == DISPLAY_DATA); + if (chip_select == CHIP_SELECT_TOGGLE_EVERY_BYTE) { // Toggle chip select after each command byte in case the display driver // IC latches commands based on it. for (size_t i = 0; i < data_length; i++) { diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 95830ba0e..87261dca0 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -35,6 +35,7 @@ #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/display_core.h" #include "tick.h" @@ -80,7 +81,7 @@ bool common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { } common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_mcu_delay_us(1); + common_hal_mcu_delay_us(4); common_hal_digitalio_digitalinout_set_value(&self->reset, true); return true; } @@ -97,9 +98,9 @@ bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { return common_hal_displayio_i2cdisplay_bus_free(obj); } -void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); - if (command) { + if (data_type == DISPLAY_COMMAND) { uint8_t command_bytes[2 * data_length]; for (uint32_t i = 0; i < data_length; i++) { command_bytes[2 * i] = 0x80; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 88878866a..0f449ea34 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -184,7 +184,6 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self) { } void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area) { - displayio_display_core_begin_transaction(self); uint16_t x1 = area->x1; uint16_t x2 = area->x2; uint16_t y1 = area->y1; @@ -201,13 +200,22 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, } } + display_chip_select_behavior_t chip_select = CHIP_SELECT_UNTOUCHED; + if (always_toggle_chip_select || data_as_commands) { + chip_select = CHIP_SELECT_TOGGLE_EVERY_BYTE; + } + // Set column. + displayio_display_core_begin_transaction(self); uint8_t data[5]; data[0] = column_command; uint8_t data_length = 1; + display_byte_type_t data_type = DISPLAY_DATA; if (!data_as_commands) { - self->send(self->bus, true, false, data, 1); + self->send(self->bus, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, data, 1); data_length = 0; + } else { + data_type = DISPLAY_COMMAND; } if (self->ram_width < 0x100) { data[data_length++] = x1 + self->colstart; @@ -220,21 +228,23 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = x2 >> 8; data[data_length++] = x2 & 0xff; } - self->send(self->bus, data_as_commands, data_as_commands, data, data_length); + self->send(self->bus, data_type, chip_select, data, data_length); + displayio_display_core_end_transaction(self); if (set_current_column_command != NO_COMMAND) { uint8_t command = set_current_column_command; - self->send(self->bus, true, always_toggle_chip_select, &command, 1); - self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); + displayio_display_core_begin_transaction(self); + self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); + self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); + displayio_display_core_end_transaction(self); } - displayio_display_core_end_transaction(self); - displayio_display_core_begin_transaction(self); // Set row. + displayio_display_core_begin_transaction(self); data[0] = row_command; data_length = 1; if (!data_as_commands) { - self->send(self->bus, true, false, data, 1); + self->send(self->bus, DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, data, 1); data_length = 0; } if (self->ram_height < 0x100) { @@ -248,14 +258,16 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = y2 >> 8; data[data_length++] = y2 & 0xff; } - self->send(self->bus, data_as_commands, data_as_commands, data, data_length); + self->send(self->bus, data_type, chip_select, data, data_length); + displayio_display_core_end_transaction(self); + if (set_current_row_command != NO_COMMAND) { uint8_t command = set_current_row_command; - self->send(self->bus, true, always_toggle_chip_select, &command, 1); - self->send(self->bus, false, always_toggle_chip_select, data, data_length / 2); + displayio_display_core_begin_transaction(self); + self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); + self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); + displayio_display_core_end_transaction(self); } - - displayio_display_core_end_transaction(self); } void displayio_display_core_start_refresh(displayio_display_core_t* self) { diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index b1a412883..e92fdbc9f 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -27,18 +27,13 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H #define MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_DISPLAY_CORE_H +#include "shared-bindings/displayio/__init__.h" #include "shared-bindings/displayio/Group.h" #include "shared-module/displayio/area.h" #define NO_COMMAND 0x100 -typedef bool (*display_bus_bus_reset)(mp_obj_t bus); -typedef bool (*display_bus_bus_free)(mp_obj_t bus); -typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, bool command, bool toggle_every_byte, uint8_t *data, uint32_t data_length); -typedef void (*display_bus_end_transaction)(mp_obj_t bus); - typedef struct { mp_obj_t bus; displayio_group_t *current_group; diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 36b30f462..c50d7f4ee 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -91,7 +91,7 @@ void filesystem_init(bool create_allowed, bool force_create) { } // set label - f_setlabel(&vfs_fat->fatfs, CIRCUITPY_FS_NAME); + f_setlabel(&vfs_fat->fatfs, "CIRCUITPY"); // inhibit file indexing on MacOS f_mkdir(&vfs_fat->fatfs, "/.fseventsd"); -- cgit v1.2.3 From 2c55b40a53eb537c7cda8cfdfdeacb644d775fd9 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 24 Aug 2019 07:56:12 -0500 Subject: use a MixerVoice constructor --- shared-bindings/audiocore/MixerVoice.c | 7 ++++--- shared-bindings/audiocore/MixerVoice.h | 1 + shared-module/audiocore/MixerVoice.c | 5 +++++ 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/audiocore/MixerVoice.c b/shared-bindings/audiocore/MixerVoice.c index 2711be00f..36b3c35fc 100644 --- a/shared-bindings/audiocore/MixerVoice.c +++ b/shared-bindings/audiocore/MixerVoice.c @@ -50,10 +50,11 @@ //| // TODO: support mono or stereo voices STATIC mp_obj_t audioio_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - audioio_mixervoice_obj_t *self = m_new_obj(audioio_mixervoice_obj_t); + audioio_mixervoice_obj_t *self = m_new_obj(audioio_mixervoice_obj_t); self->base.type = &audioio_mixervoice_type; - self->sample = NULL; - self->level = ((1 << 15)-1); + + common_hal_audioio_mixervoice_construct(self); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiocore/MixerVoice.h b/shared-bindings/audiocore/MixerVoice.h index b5e447058..5849ce252 100644 --- a/shared-bindings/audiocore/MixerVoice.h +++ b/shared-bindings/audiocore/MixerVoice.h @@ -35,6 +35,7 @@ extern const mp_obj_type_t audioio_mixer_type; extern const mp_obj_type_t audioio_mixervoice_type; +void common_hal_audioio_mixervoice_construct(audioio_mixervoice_obj_t *self); void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent); void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop); void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self); diff --git a/shared-module/audiocore/MixerVoice.c b/shared-module/audiocore/MixerVoice.c index c16dfccb0..a9543a40d 100644 --- a/shared-module/audiocore/MixerVoice.c +++ b/shared-module/audiocore/MixerVoice.c @@ -32,6 +32,11 @@ #include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/MixerVoice.h" +void common_hal_audioio_mixervoice_construct(audioio_mixervoice_obj_t *self) { + self->sample = NULL; + self->level = ((1 << 15) - 1); +} + void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent) { self->parent = parent; } -- cgit v1.2.3 From 965f2bf799b31b5f1caeeb07639741522bb94b65 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 24 Aug 2019 09:24:54 -0500 Subject: fix MixerVoice.get_level; now returns a float between 0-1. --- shared-module/audiocore/MixerVoice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/audiocore/MixerVoice.c b/shared-module/audiocore/MixerVoice.c index a9543a40d..80c07511e 100644 --- a/shared-module/audiocore/MixerVoice.c +++ b/shared-module/audiocore/MixerVoice.c @@ -42,7 +42,7 @@ void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, au } float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self) { - return self->level; + return ((float) self->level / ((1 << 15) - 1)); } void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float level) { -- cgit v1.2.3 From df5568d993ad10bb6ef68fc0f01f8561f3a6c78d Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 24 Aug 2019 23:36:18 -0500 Subject: move Mixer & MixerVoice from 'audiocore' to 'audiomixer' --- py/circuitpy_defns.mk | 8 +- py/circuitpy_mpconfig.h | 8 + py/circuitpy_mpconfig.mk | 5 + shared-bindings/audiocore/Mixer.c | 243 ------------------ shared-bindings/audiocore/Mixer.h | 51 ---- shared-bindings/audiocore/MixerVoice.c | 178 ------------- shared-bindings/audiocore/MixerVoice.h | 47 ---- shared-bindings/audiocore/__init__.c | 6 +- shared-bindings/audioio/__init__.c | 7 +- shared-bindings/audiomixer/Mixer.c | 244 ++++++++++++++++++ shared-bindings/audiomixer/Mixer.h | 51 ++++ shared-bindings/audiomixer/MixerVoice.c | 178 +++++++++++++ shared-bindings/audiomixer/MixerVoice.h | 47 ++++ shared-bindings/audiomixer/__init__.c | 63 +++++ shared-bindings/audiomixer/__init__.h | 34 +++ shared-module/audiocore/Mixer.c | 430 -------------------------------- shared-module/audiocore/Mixer.h | 69 ----- shared-module/audiocore/MixerVoice.c | 87 ------- shared-module/audiocore/MixerVoice.h | 46 ---- shared-module/audiocore/__init__.c | 35 +-- shared-module/audiomixer/Mixer.c | 430 ++++++++++++++++++++++++++++++++ shared-module/audiomixer/Mixer.h | 69 +++++ shared-module/audiomixer/MixerVoice.c | 87 +++++++ shared-module/audiomixer/MixerVoice.h | 46 ++++ shared-module/audiomixer/__init__.c | 0 shared-module/audiomixer/__init__.h | 32 +++ 26 files changed, 1325 insertions(+), 1176 deletions(-) delete mode 100644 shared-bindings/audiocore/Mixer.c delete mode 100644 shared-bindings/audiocore/Mixer.h delete mode 100644 shared-bindings/audiocore/MixerVoice.c delete mode 100644 shared-bindings/audiocore/MixerVoice.h create mode 100644 shared-bindings/audiomixer/Mixer.c create mode 100644 shared-bindings/audiomixer/Mixer.h create mode 100644 shared-bindings/audiomixer/MixerVoice.c create mode 100644 shared-bindings/audiomixer/MixerVoice.h create mode 100644 shared-bindings/audiomixer/__init__.c create mode 100644 shared-bindings/audiomixer/__init__.h delete mode 100644 shared-module/audiocore/Mixer.c delete mode 100644 shared-module/audiocore/Mixer.h delete mode 100644 shared-module/audiocore/MixerVoice.c delete mode 100644 shared-module/audiocore/MixerVoice.h create mode 100644 shared-module/audiomixer/Mixer.c create mode 100644 shared-module/audiomixer/Mixer.h create mode 100644 shared-module/audiomixer/MixerVoice.c create mode 100644 shared-module/audiomixer/MixerVoice.h create mode 100644 shared-module/audiomixer/__init__.c create mode 100644 shared-module/audiomixer/__init__.h (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 675fe1aec..7ed9457d0 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -114,6 +114,9 @@ endif ifeq ($(CIRCUITPY_AUDIOCORE),1) SRC_PATTERNS += audiocore/% endif +ifeq ($(CIRCUITPY_AUDIOMIXER),1) +SRC_PATTERNS += audiomixer/% +endif ifeq ($(CIRCUITPY_BITBANGIO),1) SRC_PATTERNS += bitbangio/% endif @@ -305,10 +308,11 @@ SRC_SHARED_MODULE_ALL = \ audiopwmio/__init__.c \ audioio/__init__.c \ audiocore/__init__.c \ - audiocore/Mixer.c \ - audiocore/MixerVoice.c \ audiocore/RawSample.c \ audiocore/WaveFile.c \ + audiomixer/__init__.c \ + audiomixer/Mixer.c \ + audiomixer/MixerVoice.c \ bitbangio/I2C.c \ bitbangio/OneWire.c \ bitbangio/SPI.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 393b7600c..8e44ee6c8 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -244,6 +244,13 @@ extern const struct _mp_obj_module_t audioio_module; #define AUDIOIO_MODULE #endif +#if CIRCUITPY_AUDIOMIXER +#define AUDIOMIXER_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiomixer), (mp_obj_t)&audiomixer_module }, +extern const struct _mp_obj_module_t audiomixer_module; +#else +#define AUDIOMIXER_MODULE +#endif + #if CIRCUITPY_AUDIOPWMIO #define AUDIOPWMIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiopwmio), (mp_obj_t)&audiopwmio_module }, extern const struct _mp_obj_module_t audiopwmio_module; @@ -573,6 +580,7 @@ extern const struct _mp_obj_module_t ustack_module; AUDIOBUSIO_MODULE \ AUDIOCORE_MODULE \ AUDIOIO_MODULE \ + AUDIOMIXER_MODULE \ AUDIOPWMIO_MODULE \ BITBANGIO_MODULE \ BLEIO_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 949cd1d18..b217abdce 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -94,6 +94,11 @@ endif endif CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE) +ifndef CIRCUITPY_AUDIOMIXER +CIRCUITPY_AUDIOMIXER = $(CIRCUITPY_AUDIOIO) +endif +CFLAGS += -DCIRCUITPY_AUDIOMIXER=$(CIRCUITPY_AUDIOMIXER) + ifndef CIRCUITPY_BITBANGIO CIRCUITPY_BITBANGIO = $(CIRCUITPY_FULL_BUILD) endif diff --git a/shared-bindings/audiocore/Mixer.c b/shared-bindings/audiocore/Mixer.c deleted file mode 100644 index 59ff5eea7..000000000 --- a/shared-bindings/audiocore/Mixer.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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 "shared-bindings/audiocore/Mixer.h" -#include "shared-bindings/audiocore/MixerVoice.h" -#include "shared-module/audiocore/MixerVoice.h" - -#include - -#include "lib/utils/context_manager_helpers.h" -#include "py/binary.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audiocore/RawSample.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| .. currentmodule:: audiocore -//| -//| :class:`Mixer` -- Mixes one or more audio samples together -//| =========================================================== -//| -//| Mixer mixes multiple samples into one sample. -//| -//| .. class:: Mixer(voice_count=2, buffer_size=1024, channel_count=2, bits_per_sample=16, samples_signed=True, sample_rate=8000) -//| -//| Create a Mixer object that can mix multiple channels with the same sample rate. -//| Samples are accessed and controlled with the mixer's `audiocore.MixerVoice` objects. -//| -//| :param int voice_count: The maximum number of voices to mix -//| :param int buffer_size: The total size in bytes of the buffers to mix into -//| :param int channel_count: The maximum number of samples to mix at once -//| :param int bits_per_sample: The bits per sample of the samples being played -//| :param bool samples_signed: Samples are signed (True) or unsigned (False) -//| :param int sample_rate: The sample rate to be used for all samples -//| -//| Playing a wave file from flash:: -//| -//| import board -//| import audioio -//| import audiocore -//| import digitalio -//| -//| # Required for CircuitPlayground Express -//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) -//| speaker_enable.switch_to_output(value=True) -//| -//| music = audiocore.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) -//| drum = audiocore.WaveFile(open("drum.wav", "rb")) -//| mixer = audiocore.Mixer(voice_count=2, sample_rate=16000, channel_count=1, -//| bits_per_sample=16, samples_signed=True) -//| a = audioio.AudioOut(board.A0) -//| -//| print("playing") -//| # Have AudioOut play our Mixer source -//| a.play(mixer) -//| # Play the first sample voice -//| mixer.voice[0].play(music) -//| while mixer.playing: -//| # Play the second sample voice -//| mixer.voice[1].play(drum) -//| time.sleep(1) -//| print("stopped") -//| -STATIC mp_obj_t audioio_mixer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_voice_count, ARG_buffer_size, ARG_channel_count, ARG_bits_per_sample, ARG_samples_signed, ARG_sample_rate }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, - { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, - { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, - { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, - { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, - { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_int_t voice_count = args[ARG_voice_count].u_int; - if (voice_count < 1 || voice_count > 255) { - mp_raise_ValueError(translate("Invalid voice count")); - } - - mp_int_t channel_count = args[ARG_channel_count].u_int; - if (channel_count < 1 || channel_count > 2) { - mp_raise_ValueError(translate("Invalid channel count")); - } - mp_int_t sample_rate = args[ARG_sample_rate].u_int; - if (sample_rate < 1) { - mp_raise_ValueError(translate("Sample rate must be positive")); - } - mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; - if (bits_per_sample != 8 && bits_per_sample != 16) { - mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); - } - audioio_mixer_obj_t *self = m_new_obj_var(audioio_mixer_obj_t, mp_obj_t, voice_count); - self->base.type = &audioio_mixer_type; - common_hal_audioio_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); - - for(int v=0; vvoice[v] = audioio_mixervoice_type.make_new(&audioio_mixervoice_type, 0, 0, NULL); - common_hal_audioio_mixervoice_set_parent(self->voice[v], self); - } - self->voice_tuple = mp_obj_new_tuple(self->voice_count, self->voice); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: deinit() -//| -//| Deinitialises the Mixer and releases any hardware resources for reuse. -//| -STATIC mp_obj_t audioio_mixer_deinit(mp_obj_t self_in) { - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audioio_mixer_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_deinit_obj, audioio_mixer_deinit); - -STATIC void check_for_deinit(audioio_mixer_obj_t *self) { - if (common_hal_audioio_mixer_deinited(self)) { - raise_deinited_error(); - } -} - -//| .. method:: __enter__() -//| -//| No-op used by Context Managers. -//| -// Provided by context manager helper. - -//| .. method:: __exit__() -//| -//| Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info. -//| -STATIC mp_obj_t audioio_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_audioio_mixer_deinit(args[0]); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer___exit___obj, 4, 4, audioio_mixer_obj___exit__); - -//| .. attribute:: playing -//| -//| True when any voice is being output. (read-only) -//| -STATIC mp_obj_t audioio_mixer_obj_get_playing(mp_obj_t self_in) { - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_playing_obj, audioio_mixer_obj_get_playing); - -const mp_obj_property_t audioio_mixer_playing_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_get_playing_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: sample_rate -//| -//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). -//| -STATIC mp_obj_t audioio_mixer_obj_get_sample_rate(mp_obj_t self_in) { - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_mixer_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_sample_rate_obj, audioio_mixer_obj_get_sample_rate); - -const mp_obj_property_t audioio_mixer_sample_rate_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_get_sample_rate_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: voice -//| -//| A tuple of the mixer's `audioio.MixerVoice` object(s). -//| -//| .. code-block:: python -//| -//| >>> mixer.voice -//| (,) -STATIC mp_obj_t audioio_mixer_obj_get_voice(mp_obj_t self_in) { - audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return self->voice_tuple; -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_voice_obj, audioio_mixer_obj_get_voice); - -const mp_obj_property_t audioio_mixer_voice_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixer_get_voice_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - - -STATIC const mp_rom_map_elem_t audioio_mixer_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_mixer_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_mixer___exit___obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixer_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioio_mixer_sample_rate_obj) }, - { MP_ROM_QSTR(MP_QSTR_voice), MP_ROM_PTR(&audioio_mixer_voice_obj) } -}; -STATIC MP_DEFINE_CONST_DICT(audioio_mixer_locals_dict, audioio_mixer_locals_dict_table); - -const mp_obj_type_t audioio_mixer_type = { - { &mp_type_type }, - .name = MP_QSTR_Mixer, - .make_new = audioio_mixer_make_new, - .locals_dict = (mp_obj_dict_t*)&audioio_mixer_locals_dict, -}; diff --git a/shared-bindings/audiocore/Mixer.h b/shared-bindings/audiocore/Mixer.h deleted file mode 100644 index 87d681ce6..000000000 --- a/shared-bindings/audiocore/Mixer.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H - -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/audiocore/Mixer.h" -#include "shared-bindings/audiocore/RawSample.h" - -extern const mp_obj_type_t audioio_mixer_type; -extern const mp_obj_type_t audioio_mixervoice_type; - -void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, - uint8_t voice_count, - uint32_t buffer_size, - uint8_t bits_per_sample, - bool samples_signed, - uint8_t channel_count, - uint32_t sample_rate); - -void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self); -bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self); - -bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self); -uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H diff --git a/shared-bindings/audiocore/MixerVoice.c b/shared-bindings/audiocore/MixerVoice.c deleted file mode 100644 index d666c235c..000000000 --- a/shared-bindings/audiocore/MixerVoice.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 DeanM for Adafruit Industries - * - * 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 "shared-bindings/audiocore/Mixer.h" -#include "shared-bindings/audiocore/MixerVoice.h" - -#include - -#include "lib/utils/context_manager_helpers.h" -#include "py/binary.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audiocore/RawSample.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| .. currentmodule:: audiocore -//| -//| :class:`MixerVoice` -- Voice objects used with Mixer -//| ===================================================== -//| -//| Used to access and control samples with `audiocore.Mixer`. -//| -//| .. class:: MixerVoice() -//| -//| MixerVoice instance object(s) created by `audiocore.Mixer`. -//| -// TODO: support mono or stereo voices -STATIC mp_obj_t audioio_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - audioio_mixervoice_obj_t *self = m_new_obj(audioio_mixervoice_obj_t); - self->base.type = &audioio_mixervoice_type; - - common_hal_audioio_mixervoice_construct(self); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: play(sample, *, loop=False) -//| -//| Plays the sample once when ``loop=False``, and continuously when ``loop=True``. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audiocore.WaveFile`, `audiocore.Mixer` or `audiocore.RawSample`. -//| -//| The sample must match the `audiocore.Mixer`'s encoding settings given in the constructor. -//| -STATIC mp_obj_t audioio_mixervoice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_audioio_mixervoice_play(self, sample, args[ARG_loop].u_bool); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_play_obj, 1, audioio_mixervoice_obj_play); - -//| .. method:: stop() -//| -//| Stops playback of the sample on this voice. -//| -STATIC mp_obj_t audioio_mixervoice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_voice }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, - }; - audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - common_hal_audioio_mixervoice_stop(self); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_stop_obj, 1, audioio_mixervoice_obj_stop); - -//| .. attribute:: level() -//| -//| The volume level of a voice, as a floating point number between 0 and 1. -//| -STATIC mp_obj_t audioio_mixervoice_obj_get_level(mp_obj_t self_in) { - return mp_obj_new_float(common_hal_audioio_mixervoice_get_level(self_in)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_get_level_obj, audioio_mixervoice_obj_get_level); - -STATIC mp_obj_t audioio_mixervoice_obj_set_level(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_level }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_level, MP_ARG_OBJ | MP_ARG_REQUIRED }, - }; - audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - float level = mp_obj_get_float(args[ARG_level].u_obj); - - if (level > 1 || level < 0) { - mp_raise_ValueError(translate("level must be between 0 and 1")); - } - - common_hal_audioio_mixervoice_set_level(self, level); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixervoice_set_level_obj, 1, audioio_mixervoice_obj_set_level); - -const mp_obj_property_t audioio_mixervoice_level_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixervoice_get_level_obj, - (mp_obj_t)&audioio_mixervoice_set_level_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: playing -//| -//| True when any voice is being output. (read-only) -//| - -STATIC mp_obj_t audioio_mixervoice_obj_get_playing(mp_obj_t self_in) { - audioio_mixervoice_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_audioio_mixervoice_get_playing(self)); - -} -MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixervoice_get_playing_obj, audioio_mixervoice_obj_get_playing); - -const mp_obj_property_t audioio_mixervoice_playing_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&audioio_mixervoice_get_playing_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t audioio_mixervoice_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_mixervoice_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_mixervoice_stop_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_mixervoice_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_level), MP_ROM_PTR(&audioio_mixervoice_level_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(audioio_mixervoice_locals_dict, audioio_mixervoice_locals_dict_table); - -const mp_obj_type_t audioio_mixervoice_type = { - { &mp_type_type }, - .name = MP_QSTR_MixerVoice, - .make_new = audioio_mixervoice_make_new, - .locals_dict = (mp_obj_dict_t*)&audioio_mixervoice_locals_dict, -}; diff --git a/shared-bindings/audiocore/MixerVoice.h b/shared-bindings/audiocore/MixerVoice.h deleted file mode 100644 index 5849ce252..000000000 --- a/shared-bindings/audiocore/MixerVoice.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 DeanM for Adafruit Industries - * - * 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. - */ -#ifndef SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ -#define SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ - -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/audiocore/Mixer.h" -#include "shared-bindings/audiocore/RawSample.h" -#include "shared-module/audiocore/MixerVoice.h" -#include "shared-module/audiocore/Mixer.h" - -extern const mp_obj_type_t audioio_mixer_type; -extern const mp_obj_type_t audioio_mixervoice_type; - -void common_hal_audioio_mixervoice_construct(audioio_mixervoice_obj_t *self); -void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent); -void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop); -void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self); -float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self); -void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float gain); - -bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self); - -#endif /* SHARED_BINDINGS_AUDIOIO_MIXERVOICE_H_ */ diff --git a/shared-bindings/audiocore/__init__.c b/shared-bindings/audiocore/__init__.c index 9d82b1f99..c9d5a1cab 100644 --- a/shared-bindings/audiocore/__init__.c +++ b/shared-bindings/audiocore/__init__.c @@ -31,9 +31,9 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/audiocore/__init__.h" -#include "shared-bindings/audiocore/Mixer.h" #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" +//#include "shared-bindings/audiomixer/Mixer.h" //| :mod:`audiocore` --- Support for audio samples and mixer //| ======================================================== @@ -49,15 +49,13 @@ //| .. toctree:: //| :maxdepth: 3 //| -//| Mixer -//| MixerVoice //| RawSample //| WaveFile //| STATIC const mp_rom_map_elem_t audiocore_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiocore) }, - { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, + //{ MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) }, { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) }, }; diff --git a/shared-bindings/audioio/__init__.c b/shared-bindings/audioio/__init__.c index bd771dda2..0d307335f 100644 --- a/shared-bindings/audioio/__init__.c +++ b/shared-bindings/audioio/__init__.c @@ -34,10 +34,13 @@ #include "shared-bindings/audioio/AudioOut.h" #ifdef CIRCUITPY_AUDIOIO_COMPAT -#include "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiomixer/Mixer.h" #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" #endif +#ifdef CIRCUIPY_AUDIOMIXER +#include "shared-bindings/audiomixer/Mixer.h" +#endif //| :mod:`audioio` --- Support for audio input and output //| ====================================================== @@ -72,7 +75,7 @@ STATIC const mp_rom_map_elem_t audioio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audioio) }, { MP_ROM_QSTR(MP_QSTR_AudioOut), MP_ROM_PTR(&audioio_audioout_type) }, #ifdef CIRCUITPY_AUDIOIO_COMPAT - { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, + //{ MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audiomixer_mixer_type) }, { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) }, { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) }, #endif diff --git a/shared-bindings/audiomixer/Mixer.c b/shared-bindings/audiomixer/Mixer.c new file mode 100644 index 000000000..3beb61118 --- /dev/null +++ b/shared-bindings/audiomixer/Mixer.c @@ -0,0 +1,244 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/audiomixer/Mixer.h" +#include "shared-bindings/audiomixer/MixerVoice.h" +#include "shared-module/audiomixer/MixerVoice.h" + +#include + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audiomixer +//| +//| :class:`Mixer` -- Mixes one or more audio samples together +//| =========================================================== +//| +//| Mixer mixes multiple samples into one sample. +//| +//| .. class:: Mixer(voice_count=2, buffer_size=1024, channel_count=2, bits_per_sample=16, samples_signed=True, sample_rate=8000) +//| +//| Create a Mixer object that can mix multiple channels with the same sample rate. +//| Samples are accessed and controlled with the mixer's `audiocore.MixerVoice` objects. +//| +//| :param int voice_count: The maximum number of voices to mix +//| :param int buffer_size: The total size in bytes of the buffers to mix into +//| :param int channel_count: The maximum number of samples to mix at once +//| :param int bits_per_sample: The bits per sample of the samples being played +//| :param bool samples_signed: Samples are signed (True) or unsigned (False) +//| :param int sample_rate: The sample rate to be used for all samples +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audioio +//| import audiocore +//| import audiomixer +//| import digitalio +//| +//| # Required for CircuitPlayground Express +//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE) +//| speaker_enable.switch_to_output(value=True) +//| +//| music = audiocore.WaveFile(open("cplay-5.1-16bit-16khz.wav", "rb")) +//| drum = audiocore.WaveFile(open("drum.wav", "rb")) +//| mixer = audiomixer.Mixer(voice_count=2, sample_rate=16000, channel_count=1, +//| bits_per_sample=16, samples_signed=True) +//| a = audioio.AudioOut(board.A0) +//| +//| print("playing") +//| # Have AudioOut play our Mixer source +//| a.play(mixer) +//| # Play the first sample voice +//| mixer.voice[0].play(music) +//| while mixer.playing: +//| # Play the second sample voice +//| mixer.voice[1].play(drum) +//| time.sleep(1) +//| print("stopped") +//| +STATIC mp_obj_t audiomixer_mixer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_voice_count, ARG_buffer_size, ARG_channel_count, ARG_bits_per_sample, ARG_samples_signed, ARG_sample_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t voice_count = args[ARG_voice_count].u_int; + if (voice_count < 1 || voice_count > 255) { + mp_raise_ValueError(translate("Invalid voice count")); + } + + mp_int_t channel_count = args[ARG_channel_count].u_int; + if (channel_count < 1 || channel_count > 2) { + mp_raise_ValueError(translate("Invalid channel count")); + } + mp_int_t sample_rate = args[ARG_sample_rate].u_int; + if (sample_rate < 1) { + mp_raise_ValueError(translate("Sample rate must be positive")); + } + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(translate("bits_per_sample must be 8 or 16")); + } + audiomixer_mixer_obj_t *self = m_new_obj_var(audiomixer_mixer_obj_t, mp_obj_t, voice_count); + self->base.type = &audiomixer_mixer_type; + common_hal_audiomixer_mixer_construct(self, voice_count, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + + for(int v=0; vvoice[v] = audiomixer_mixervoice_type.make_new(&audiomixer_mixervoice_type, 0, 0, NULL); + common_hal_audiomixer_mixervoice_set_parent(self->voice[v], self); + } + self->voice_tuple = mp_obj_new_tuple(self->voice_count, self->voice); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the Mixer and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audiomixer_mixer_deinit(mp_obj_t self_in) { + audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiomixer_mixer_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_deinit_obj, audiomixer_mixer_deinit); + +STATIC void check_for_deinit(audiomixer_mixer_obj_t *self) { + if (common_hal_audiomixer_mixer_deinited(self)) { + raise_deinited_error(); + } +} + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +STATIC mp_obj_t audiomixer_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audiomixer_mixer_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiomixer_mixer___exit___obj, 4, 4, audiomixer_mixer_obj___exit__); + +//| .. attribute:: playing +//| +//| True when any voice is being output. (read-only) +//| +STATIC mp_obj_t audiomixer_mixer_obj_get_playing(mp_obj_t self_in) { + audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiomixer_mixer_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_get_playing_obj, audiomixer_mixer_obj_get_playing); + +const mp_obj_property_t audiomixer_mixer_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiomixer_mixer_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: sample_rate +//| +//| 32 bit value that dictates how quickly samples are played in Hertz (cycles per second). +//| +STATIC mp_obj_t audiomixer_mixer_obj_get_sample_rate(mp_obj_t self_in) { + audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audiomixer_mixer_get_sample_rate(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_get_sample_rate_obj, audiomixer_mixer_obj_get_sample_rate); + +const mp_obj_property_t audiomixer_mixer_sample_rate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiomixer_mixer_get_sample_rate_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: voice +//| +//| A tuple of the mixer's `audiomixer.MixerVoice` object(s). +//| +//| .. code-block:: python +//| +//| >>> mixer.voice +//| (,) +STATIC mp_obj_t audiomixer_mixer_obj_get_voice(mp_obj_t self_in) { + audiomixer_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return self->voice_tuple; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixer_get_voice_obj, audiomixer_mixer_obj_get_voice); + +const mp_obj_property_t audiomixer_mixer_voice_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiomixer_mixer_get_voice_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +STATIC const mp_rom_map_elem_t audiomixer_mixer_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiomixer_mixer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiomixer_mixer___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiomixer_mixer_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiomixer_mixer_sample_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_voice), MP_ROM_PTR(&audiomixer_mixer_voice_obj) } +}; +STATIC MP_DEFINE_CONST_DICT(audiomixer_mixer_locals_dict, audiomixer_mixer_locals_dict_table); + +const mp_obj_type_t audiomixer_mixer_type = { + { &mp_type_type }, + .name = MP_QSTR_Mixer, + .make_new = audiomixer_mixer_make_new, + .locals_dict = (mp_obj_dict_t*)&audiomixer_mixer_locals_dict, +}; diff --git a/shared-bindings/audiomixer/Mixer.h b/shared-bindings/audiomixer/Mixer.h new file mode 100644 index 000000000..9eabbf61d --- /dev/null +++ b/shared-bindings/audiomixer/Mixer.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER_MIXER_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER_MIXER_H + +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/audiomixer/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" + +extern const mp_obj_type_t audiomixer_mixer_type; +extern const mp_obj_type_t audiomixer_mixervoice_type; + +void common_hal_audiomixer_mixer_construct(audiomixer_mixer_obj_t* self, + uint8_t voice_count, + uint32_t buffer_size, + uint8_t bits_per_sample, + bool samples_signed, + uint8_t channel_count, + uint32_t sample_rate); + +void common_hal_audiomixer_mixer_deinit(audiomixer_mixer_obj_t* self); +bool common_hal_audiomixer_mixer_deinited(audiomixer_mixer_obj_t* self); + +bool common_hal_audiomixer_mixer_get_playing(audiomixer_mixer_obj_t* self); +uint32_t common_hal_audiomixer_mixer_get_sample_rate(audiomixer_mixer_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER_MIXER_H diff --git a/shared-bindings/audiomixer/MixerVoice.c b/shared-bindings/audiomixer/MixerVoice.c new file mode 100644 index 000000000..5c082d931 --- /dev/null +++ b/shared-bindings/audiomixer/MixerVoice.c @@ -0,0 +1,178 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 DeanM for Adafruit Industries + * + * 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 "shared-bindings/audiomixer/Mixer.h" +#include "shared-bindings/audiomixer/MixerVoice.h" + +#include + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audiomixer +//| +//| :class:`MixerVoice` -- Voice objects used with Mixer +//| ===================================================== +//| +//| Used to access and control samples with `audiocore.Mixer`. +//| +//| .. class:: MixerVoice() +//| +//| MixerVoice instance object(s) created by `audiomixer.Mixer`. +//| +// TODO: support mono or stereo voices +STATIC mp_obj_t audiomixer_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + audiomixer_mixervoice_obj_t *self = m_new_obj(audiomixer_mixervoice_obj_t); + self->base.type = &audiomixer_mixervoice_type; + + common_hal_audiomixer_mixervoice_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: play(sample, *, loop=False) +//| +//| Plays the sample once when ``loop=False``, and continuously when ``loop=True``. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.Mixer` or `audiocore.RawSample`. +//| +//| The sample must match the `audiocore.Mixer`'s encoding settings given in the constructor. +//| +STATIC mp_obj_t audiomixer_mixervoice_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audiomixer_mixervoice_play(self, sample, args[ARG_loop].u_bool); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixervoice_play_obj, 1, audiomixer_mixervoice_obj_play); + +//| .. method:: stop() +//| +//| Stops playback of the sample on this voice. +//| +STATIC mp_obj_t audiomixer_mixervoice_obj_stop(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_voice }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, + }; + audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_audiomixer_mixervoice_stop(self); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixervoice_stop_obj, 1, audiomixer_mixervoice_obj_stop); + +//| .. attribute:: level() +//| +//| The volume level of a voice, as a floating point number between 0 and 1. +//| +STATIC mp_obj_t audiomixer_mixervoice_obj_get_level(mp_obj_t self_in) { + return mp_obj_new_float(common_hal_audiomixer_mixervoice_get_level(self_in)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixervoice_get_level_obj, audiomixer_mixervoice_obj_get_level); + +STATIC mp_obj_t audiomixer_mixervoice_obj_set_level(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_level }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_level, MP_ARG_OBJ | MP_ARG_REQUIRED }, + }; + audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + float level = mp_obj_get_float(args[ARG_level].u_obj); + + if (level > 1 || level < 0) { + mp_raise_ValueError(translate("level must be between 0 and 1")); + } + + common_hal_audiomixer_mixervoice_set_level(self, level); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiomixer_mixervoice_set_level_obj, 1, audiomixer_mixervoice_obj_set_level); + +const mp_obj_property_t audiomixer_mixervoice_level_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiomixer_mixervoice_get_level_obj, + (mp_obj_t)&audiomixer_mixervoice_set_level_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: playing +//| +//| True when any voice is being output. (read-only) +//| + +STATIC mp_obj_t audiomixer_mixervoice_obj_get_playing(mp_obj_t self_in) { + audiomixer_mixervoice_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_audiomixer_mixervoice_get_playing(self)); + +} +MP_DEFINE_CONST_FUN_OBJ_1(audiomixer_mixervoice_get_playing_obj, audiomixer_mixervoice_obj_get_playing); + +const mp_obj_property_t audiomixer_mixervoice_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiomixer_mixervoice_get_playing_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t audiomixer_mixervoice_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiomixer_mixervoice_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiomixer_mixervoice_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiomixer_mixervoice_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_level), MP_ROM_PTR(&audiomixer_mixervoice_level_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audiomixer_mixervoice_locals_dict, audiomixer_mixervoice_locals_dict_table); + +const mp_obj_type_t audiomixer_mixervoice_type = { + { &mp_type_type }, + .name = MP_QSTR_MixerVoice, + .make_new = audiomixer_mixervoice_make_new, + .locals_dict = (mp_obj_dict_t*)&audiomixer_mixervoice_locals_dict, +}; diff --git a/shared-bindings/audiomixer/MixerVoice.h b/shared-bindings/audiomixer/MixerVoice.h new file mode 100644 index 000000000..83098bc9d --- /dev/null +++ b/shared-bindings/audiomixer/MixerVoice.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 DeanM for Adafruit Industries + * + * 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. + */ +#ifndef SHARED_BINDINGS_AUDIOMIXER_MIXERVOICE_H_ +#define SHARED_BINDINGS_AUDIOMIXER_MIXERVOICE_H_ + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/audiocore/RawSample.h" + +#include "shared-module/audiomixer/MixerVoice.h" +#include "shared-module/audiomixer/Mixer.h" + +extern const mp_obj_type_t audiomixer_mixer_type; +extern const mp_obj_type_t audiomixer_mixervoice_type; + +void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *self); +void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t* self, audiomixer_mixer_obj_t *parent); +void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t* self, mp_obj_t sample, bool loop); +void common_hal_audiomixer_mixervoice_stop(audiomixer_mixervoice_obj_t* self); +float common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t* self); +void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t* self, float gain); + +bool common_hal_audiomixer_mixervoice_get_playing(audiomixer_mixervoice_obj_t* self); + +#endif /* SHARED_BINDINGS_AUDIOMIXER_MIXERVOICE_H_ */ diff --git a/shared-bindings/audiomixer/__init__.c b/shared-bindings/audiomixer/__init__.c new file mode 100644 index 000000000..a8dd4309f --- /dev/null +++ b/shared-bindings/audiomixer/__init__.c @@ -0,0 +1,63 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Michael Schroeder + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiomixer/Mixer.h" + +//| :mod:`audiomixer` --- Support for audio mixer +//| ======================================================== +//| +//| .. module:: audiomixer +//| :synopsis: Support for audio mixer +//| :platform: SAMD21 +//| +//| The `audiomixer` module contains core classes for mixing audio sources +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| Mixer +//| MixerVoice +//| + +STATIC const mp_rom_map_elem_t audiomixer_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiomixer) }, + { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audiomixer_mixer_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(audiomixer_module_globals, audiomixer_module_globals_table); + +const mp_obj_module_t audiomixer_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&audiomixer_module_globals, +}; diff --git a/shared-bindings/audiomixer/__init__.h b/shared-bindings/audiomixer/__init__.h new file mode 100644 index 000000000..35a90441c --- /dev/null +++ b/shared-bindings/audiomixer/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Michael Schroeder + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER___INIT___H + +#include "py/obj.h" + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOMIXER___INIT___H diff --git a/shared-module/audiocore/Mixer.c b/shared-module/audiocore/Mixer.c deleted file mode 100644 index c372d68d0..000000000 --- a/shared-module/audiocore/Mixer.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries - * 2018 DeanM for Adafruit Industries - * 2019 Michael Schroeder - * - * 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 "shared-bindings/audiocore/Mixer.h" -#include "shared-bindings/audiocore/MixerVoice.h" - -#include - -#include "py/runtime.h" -#include "shared-module/audiocore/__init__.h" -#include "shared-module/audiocore/RawSample.h" - -void common_hal_audioio_mixer_construct(audioio_mixer_obj_t* self, - uint8_t voice_count, - uint32_t buffer_size, - uint8_t bits_per_sample, - bool samples_signed, - uint8_t channel_count, - uint32_t sample_rate) { - self->len = buffer_size / 2 / sizeof(uint32_t) * sizeof(uint32_t); - - self->first_buffer = m_malloc(self->len, false); - if (self->first_buffer == NULL) { - common_hal_audioio_mixer_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); - } - - self->second_buffer = m_malloc(self->len, false); - if (self->second_buffer == NULL) { - common_hal_audioio_mixer_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); - } - - self->bits_per_sample = bits_per_sample; - self->samples_signed = samples_signed; - self->channel_count = channel_count; - self->sample_rate = sample_rate; - self->voice_count = voice_count; -} - -void common_hal_audioio_mixer_deinit(audioio_mixer_obj_t* self) { - self->first_buffer = NULL; - self->second_buffer = NULL; -} - -bool common_hal_audioio_mixer_deinited(audioio_mixer_obj_t* self) { - return self->first_buffer == NULL; -} - -uint32_t common_hal_audioio_mixer_get_sample_rate(audioio_mixer_obj_t* self) { - return self->sample_rate; -} - -bool common_hal_audioio_mixer_get_playing(audioio_mixer_obj_t* self) { - for (int32_t v = 0; v < self->voice_count; v++) { - if (common_hal_audioio_mixervoice_get_playing(MP_OBJ_TO_PTR(self->voice[v]))) { - return true; - } - } - return false; -} - -void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, - bool single_channel, - uint8_t channel) { -#if 0 - for (int32_t i = 0; i < self->voice_count; i++) { - self->voice[i].sample = NULL; - } -#endif -} - -uint32_t add8signed(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return __QADD8(a, b); - #else - uint32_t result = 0; - for (int8_t i = 0; i < 4; i++) { - int8_t ai = a >> (sizeof(int8_t) * 8 * i); - int8_t bi = b >> (sizeof(int8_t) * 8 * i); - int32_t intermediate = (int32_t) ai + bi; - if (intermediate > CHAR_MAX) { - intermediate = CHAR_MAX; - } else if (intermediate < CHAR_MIN) { - intermediate = CHAR_MIN; - } - result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int8_t) * 8 * i); - } - return result; - #endif -} - -uint32_t add8unsigned(uint32_t a, uint32_t b) { - /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - // Subtract out the DC offset, add and then shift back. - a = __USUB8(a, 0x80808080); - b = __USUB8(b, 0x80808080); - uint32_t sum = __QADD8(a, b); - return __UADD8(sum, 0x80808080); - #else*/ - uint32_t result = 0; - for (int8_t i = 0; i < 4; i++) { - uint8_t ai = (a >> (sizeof(uint8_t) * 8 * i)); - uint8_t bi = (b >> (sizeof(uint8_t) * 8 * i)); - int32_t intermediate = (int32_t) (ai + bi) / 2; - if (intermediate > UCHAR_MAX) { - intermediate = UCHAR_MAX; - } - result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i); - } - return result; - //#endif -} - -uint32_t add16signed(uint32_t a, uint32_t b) { - /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return __QADD16(a, b); - #else*/ - uint32_t result = 0; - for (int8_t i = 0; i < 2; i++) { - int16_t ai = a >> (sizeof(int16_t) * 8 * i); - int16_t bi = b >> (sizeof(int16_t) * 8 * i); - int32_t intermediate = (int32_t) ai + bi; - if (intermediate > SHRT_MAX) { - intermediate = SHRT_MAX; - } else if (intermediate < SHRT_MIN) { - intermediate = SHRT_MIN; - } - result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); - } - return result; - //#endif -} - -uint32_t add16unsigned(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - // Subtract out the DC offset, add and then shift back. - a = __USUB16(a, 0x80008000); - b = __USUB16(b, 0x80008000); - uint32_t sum = __QADD16(a, b); - return __UADD16(sum, 0x80008000); - #else - uint32_t result = 0; - for (int8_t i = 0; i < 2; i++) { - int16_t ai = (a >> (sizeof(uint16_t) * 8 * i)) - 0x8000; - int16_t bi = (b >> (sizeof(uint16_t) * 8 * i)) - 0x8000; - int32_t intermediate = (int32_t) ai + bi; - if (intermediate > USHRT_MAX) { - intermediate = USHRT_MAX; - } - result |= ((uint16_t) intermediate + 0x8000) << (sizeof(int16_t) * 8 * i); - } - return result; - #endif -} - -//TODO: -static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { - // if mul == 0, no need in wasting cycles - if (mul == 0) { - return 0; - } - /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return val; - #else*/ - uint32_t result = 0; - float mod_mul = (float) mul / (float) ((1<<15)-1); - for (int8_t i = 0; i < 4; i++) { - uint8_t ai = val >> (sizeof(uint8_t) * 8 * i); - int32_t intermediate = ai * mod_mul; - if (intermediate > SHRT_MAX) { - intermediate = SHRT_MAX; - } - result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i); - } - - return result; - //#endif -} - -//TODO: -static inline uint32_t mult8signed(uint32_t val, int32_t mul) { - // if mul == 0, no need in wasting cycles - if (mul == 0) { - return 0; - } - /* - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return val; - #else - */ - uint32_t result = 0; - float mod_mul = (float)mul / (float)((1<<15)-1); - for (int8_t i = 0; i < 4; i++) { - int16_t ai = val >> (sizeof(int8_t) * 8 * i); - int32_t intermediate = ai * mod_mul; - if (intermediate > CHAR_MAX) { - intermediate = CHAR_MAX; - } else if (intermediate < CHAR_MIN) { - intermediate = CHAR_MIN; - } - result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int16_t) * 8 * i); - } - return result; - //#endif -} - -//TODO: -static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) { - // if mul == 0, no need in wasting cycles - if (mul == 0) { - return 0; - } - /* - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return val; - #else - */ - uint32_t result = 0; - float mod_mul = (float)mul / (float)((1<<15)-1); - for (int8_t i = 0; i < 2; i++) { - int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)) - 0x8000; - int32_t intermediate = ai * mod_mul; - if (intermediate > SHRT_MAX) { - intermediate = SHRT_MAX; - } else if (intermediate < SHRT_MIN) { - intermediate = SHRT_MIN; - } - result |= (((uint32_t) intermediate) + 0x8000) << (sizeof(int16_t) * 8 * i); - } - return val; - //#endif -} - -static inline uint32_t mult16signed(uint32_t val, int32_t mul) { - // if mul == 0, no need in wasting cycles - if (mul == 0) { - return 0; - } - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - int32_t hi, lo; - int32_t bits = 16; // saturate to 16 bits - int32_t shift = 0; // shift is done automatically - asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); - asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); - asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); - asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); - asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack - return val; - #else - uint32_t result = 0; - float mod_mul = (float)mul / (float)((1<<15)-1); - for (int8_t i = 0; i < 2; i++) { - int16_t ai = val >> (sizeof(int16_t) * 8 * i); - int32_t intermediate = ai * mod_mul; - if (intermediate > SHRT_MAX) { - intermediate = SHRT_MAX; - } else if (intermediate < SHRT_MIN) { - intermediate = SHRT_MIN; - } - result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); - } - return result; - #endif -} - -audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, - bool single_channel, - uint8_t channel, - uint8_t** buffer, - uint32_t* buffer_length) { - if (!single_channel) { - channel = 0; - } - - uint32_t channel_read_count = self->left_read_count; - if (channel == 1) { - channel_read_count = self->right_read_count; - } - *buffer_length = self->len; - - bool need_more_data = self->read_count == channel_read_count; - if (need_more_data) { - uint32_t* word_buffer; - if (self->use_first_buffer) { - *buffer = (uint8_t*) self->first_buffer; - word_buffer = self->first_buffer; - } else { - *buffer = (uint8_t*) self->second_buffer; - word_buffer = self->second_buffer; - } - self->use_first_buffer = !self->use_first_buffer; - bool voices_active = false; - for (int32_t v = 0; v < self->voice_count; v++) { - audioio_mixervoice_obj_t* voice = MP_OBJ_TO_PTR(self->voice[v]); - - uint32_t j = 0; - bool voice_done = voice->sample == NULL; - for (uint32_t i = 0; i < self->len / sizeof(uint32_t); i++) { - if (!voice_done && j >= voice->buffer_length) { - if (!voice->more_data) { - if (voice->loop) { - audiosample_reset_buffer(voice->sample, false, 0); - } else { - voice->sample = NULL; - voice_done = true; - } - } - if (!voice_done) { - // Load another buffer - audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); - // Track length in terms of words. - voice->buffer_length /= sizeof(uint32_t); - voice->more_data = result == GET_BUFFER_MORE_DATA; - j = 0; - } - } - // First active voice gets copied over verbatim. - uint32_t sample_value; - if (voice_done) { - // Exit early if another voice already set all samples once. - if (voices_active) { - continue; - } - sample_value = 0; - if (!self->samples_signed) { - if (self->bits_per_sample == 8) { - sample_value = 0x7f7f7f7f; - } else { - sample_value = 0x7fff7fff; - } - } - } else { - sample_value = voice->remaining_buffer[j]; - } - - // apply the mixer level - if (!self->samples_signed) { - if (self->bits_per_sample == 8) { - sample_value = mult8unsigned(sample_value, voice->level); - } else { - sample_value = mult16unsigned(sample_value, voice->level); - } - } else { - if (self->bits_per_sample == 8) { - sample_value = mult8signed(sample_value, voice->level); - } else { - sample_value = mult16signed(sample_value, voice->level); - } - } - - if (!voices_active) { - word_buffer[i] = sample_value; - } else { - if (self->bits_per_sample == 8) { - if (self->samples_signed) { - word_buffer[i] = add8signed(word_buffer[i], sample_value); - } else { - word_buffer[i] = add8unsigned(word_buffer[i], sample_value); - } - } else { - if (self->samples_signed) { - word_buffer[i] = add16signed(word_buffer[i], sample_value); - } else { - word_buffer[i] = add16unsigned(word_buffer[i], sample_value); - } - } - } - j++; - } - voice->buffer_length -= j; - voice->remaining_buffer += j; - - voices_active = true; - } - - self->read_count += 1; - } else if (!self->use_first_buffer) { - *buffer = (uint8_t*) self->first_buffer; - } else { - *buffer = (uint8_t*) self->second_buffer; - } - - - if (channel == 0) { - self->left_read_count += 1; - } else if (channel == 1) { - self->right_read_count += 1; - *buffer = *buffer + self->bits_per_sample / 8; - } - return GET_BUFFER_MORE_DATA; -} - -void audioio_mixer_get_buffer_structure(audioio_mixer_obj_t* self, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing) { - *single_buffer = false; - *samples_signed = self->samples_signed; - *max_buffer_length = self->len; - if (single_channel) { - *spacing = self->channel_count; - } else { - *spacing = 1; - } -} diff --git a/shared-module/audiocore/Mixer.h b/shared-module/audiocore/Mixer.h deleted file mode 100644 index aaab60e84..000000000 --- a/shared-module/audiocore/Mixer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Scott Shawcroft - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H -#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H - -#include "py/obj.h" -#include "py/objtuple.h" - -#include "shared-module/audiocore/__init__.h" - -typedef struct { - mp_obj_base_t base; - uint32_t* first_buffer; - uint32_t* second_buffer; - uint32_t len; // in words - uint8_t bits_per_sample; - bool use_first_buffer; - bool samples_signed; - uint8_t channel_count; - uint32_t sample_rate; - - uint32_t read_count; - uint32_t left_read_count; - uint32_t right_read_count; - - uint8_t voice_count; - mp_obj_tuple_t *voice_tuple; - mp_obj_t voice[]; -} audioio_mixer_obj_t; - - -// These are not available from Python because it may be called in an interrupt. -void audioio_mixer_reset_buffer(audioio_mixer_obj_t* self, - bool single_channel, - uint8_t channel); -audioio_get_buffer_result_t audioio_mixer_get_buffer(audioio_mixer_obj_t* self, - bool single_channel, - uint8_t channel, - uint8_t** buffer, - uint32_t* buffer_length); // length in bytes -void audioio_mixer_get_buffer_structure(audioio_mixer_obj_t* self, bool single_channel, - bool* single_buffer, bool* samples_signed, - uint32_t* max_buffer_length, uint8_t* spacing); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_MIXER_H diff --git a/shared-module/audiocore/MixerVoice.c b/shared-module/audiocore/MixerVoice.c deleted file mode 100644 index 80c07511e..000000000 --- a/shared-module/audiocore/MixerVoice.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 DeanM for Adafruit Industries - * - * 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 "shared-bindings/audiocore/Mixer.h" - -#include - -#include "py/runtime.h" -#include "shared-module/audioio/__init__.h" -#include "shared-module/audiocore/RawSample.h" -#include "shared-module/audiocore/MixerVoice.h" - -void common_hal_audioio_mixervoice_construct(audioio_mixervoice_obj_t *self) { - self->sample = NULL; - self->level = ((1 << 15) - 1); -} - -void common_hal_audioio_mixervoice_set_parent(audioio_mixervoice_obj_t* self, audioio_mixer_obj_t *parent) { - self->parent = parent; -} - -float common_hal_audioio_mixervoice_get_level(audioio_mixervoice_obj_t* self) { - return ((float) self->level / ((1 << 15) - 1)); -} - -void common_hal_audioio_mixervoice_set_level(audioio_mixervoice_obj_t* self, float level) { - self->level = level * ((1 << 15)-1); -} - -void common_hal_audioio_mixervoice_play(audioio_mixervoice_obj_t* self, mp_obj_t sample, bool loop) { - if (audiosample_sample_rate(sample) != self->parent->sample_rate) { - mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); - } - if (audiosample_channel_count(sample) != self->parent->channel_count) { - mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); - } - if (audiosample_bits_per_sample(sample) != self->parent->bits_per_sample) { - mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); - } - bool single_buffer; - bool samples_signed; - uint32_t max_buffer_length; - uint8_t spacing; - audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, - &max_buffer_length, &spacing); - if (samples_signed != self->parent->samples_signed) { - mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); - } - self->sample = sample; - self->loop = loop; - - audiosample_reset_buffer(sample, false, 0); - audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &self->remaining_buffer, &self->buffer_length); - // Track length in terms of words. - self->buffer_length /= sizeof(uint32_t); - self->more_data = result == GET_BUFFER_MORE_DATA; -} - -bool common_hal_audioio_mixervoice_get_playing(audioio_mixervoice_obj_t* self) { - return self->sample != NULL; -} - -void common_hal_audioio_mixervoice_stop(audioio_mixervoice_obj_t* self) { - self->sample = NULL; -} diff --git a/shared-module/audiocore/MixerVoice.h b/shared-module/audiocore/MixerVoice.h deleted file mode 100644 index 6010313bf..000000000 --- a/shared-module/audiocore/MixerVoice.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 DeanM for Adafruit Industries - * - * 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. - */ -#ifndef SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ -#define SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ - -#include "py/obj.h" - -#include "shared-module/audiocore/__init__.h" -#include "shared-module/audiocore/Mixer.h" - -typedef struct { - mp_obj_base_t base; - audioio_mixer_obj_t *parent; - mp_obj_t sample; - bool loop; - bool more_data; - uint32_t* remaining_buffer; - uint32_t buffer_length; - int16_t level; -} audioio_mixervoice_obj_t; - - -#endif /* SHARED_MODULE_AUDIOIO_MIXERVOICE_H_ */ diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 067cae5dd..8433a1770 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -27,13 +27,14 @@ #include "shared-module/audioio/__init__.h" #include "py/obj.h" -#include "shared-bindings/audiocore/Mixer.h" #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" -#include "shared-module/audiocore/Mixer.h" #include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/WaveFile.h" +#include "shared-bindings/audiomixer/Mixer.h" +#include "shared-module/audiomixer/Mixer.h" + uint32_t audiosample_sample_rate(mp_obj_t sample_obj) { if (MP_OBJ_IS_TYPE(sample_obj, &audioio_rawsample_type)) { audioio_rawsample_obj_t* sample = MP_OBJ_TO_PTR(sample_obj); @@ -41,8 +42,8 @@ uint32_t audiosample_sample_rate(mp_obj_t sample_obj) { } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return file->sample_rate; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { + audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); return mixer->sample_rate; } return 16000; @@ -55,8 +56,8 @@ uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj) { } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return file->bits_per_sample; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { + audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); return mixer->bits_per_sample; } return 8; @@ -69,8 +70,8 @@ uint8_t audiosample_channel_count(mp_obj_t sample_obj) { } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return file->channel_count; - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { + audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); return mixer->channel_count; } return 1; @@ -83,9 +84,9 @@ void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); audioio_wavefile_reset_buffer(file, single_channel, audio_channel); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - audioio_mixer_reset_buffer(file, single_channel, audio_channel); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { + audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audiomixer_mixer_reset_buffer(file, single_channel, audio_channel); } } @@ -99,9 +100,9 @@ audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return audioio_wavefile_get_buffer(file, single_channel, channel, buffer, buffer_length); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - return audioio_mixer_get_buffer(file, single_channel, channel, buffer, buffer_length); + } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { + audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + return audiomixer_mixer_get_buffer(file, single_channel, channel, buffer, buffer_length); } return GET_BUFFER_DONE; } @@ -117,9 +118,9 @@ void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); audioio_wavefile_get_buffer_structure(file, single_channel, single_buffer, samples_signed, max_buffer_length, spacing); - } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_mixer_type)) { - audioio_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); - audioio_mixer_get_buffer_structure(file, single_channel, single_buffer, samples_signed, + } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { + audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); + audiomixer_mixer_get_buffer_structure(file, single_channel, single_buffer, samples_signed, max_buffer_length, spacing); } } diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c new file mode 100644 index 000000000..0ae7c7b09 --- /dev/null +++ b/shared-module/audiomixer/Mixer.c @@ -0,0 +1,430 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries + * 2018 DeanM for Adafruit Industries + * 2019 Michael Schroeder + * + * 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 "shared-bindings/audiomixer/Mixer.h" +#include "shared-bindings/audiomixer/MixerVoice.h" + +#include + +#include "py/runtime.h" +#include "shared-module/audiocore/__init__.h" +#include "shared-module/audiocore/RawSample.h" + +void common_hal_audiomixer_mixer_construct(audiomixer_mixer_obj_t* self, + uint8_t voice_count, + uint32_t buffer_size, + uint8_t bits_per_sample, + bool samples_signed, + uint8_t channel_count, + uint32_t sample_rate) { + self->len = buffer_size / 2 / sizeof(uint32_t) * sizeof(uint32_t); + + self->first_buffer = m_malloc(self->len, false); + if (self->first_buffer == NULL) { + common_hal_audiomixer_mixer_deinit(self); + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); + } + + self->second_buffer = m_malloc(self->len, false); + if (self->second_buffer == NULL) { + common_hal_audiomixer_mixer_deinit(self); + mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); + } + + self->bits_per_sample = bits_per_sample; + self->samples_signed = samples_signed; + self->channel_count = channel_count; + self->sample_rate = sample_rate; + self->voice_count = voice_count; +} + +void common_hal_audiomixer_mixer_deinit(audiomixer_mixer_obj_t* self) { + self->first_buffer = NULL; + self->second_buffer = NULL; +} + +bool common_hal_audiomixer_mixer_deinited(audiomixer_mixer_obj_t* self) { + return self->first_buffer == NULL; +} + +uint32_t common_hal_audiomixer_mixer_get_sample_rate(audiomixer_mixer_obj_t* self) { + return self->sample_rate; +} + +bool common_hal_audiomixer_mixer_get_playing(audiomixer_mixer_obj_t* self) { + for (int32_t v = 0; v < self->voice_count; v++) { + if (common_hal_audiomixer_mixervoice_get_playing(MP_OBJ_TO_PTR(self->voice[v]))) { + return true; + } + } + return false; +} + +void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t* self, + bool single_channel, + uint8_t channel) { +#if 0 + for (int32_t i = 0; i < self->voice_count; i++) { + self->voice[i].sample = NULL; + } +#endif +} + +uint32_t add8signed(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return __QADD8(a, b); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 4; i++) { + int8_t ai = a >> (sizeof(int8_t) * 8 * i); + int8_t bi = b >> (sizeof(int8_t) * 8 * i); + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > CHAR_MAX) { + intermediate = CHAR_MAX; + } else if (intermediate < CHAR_MIN) { + intermediate = CHAR_MIN; + } + result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int8_t) * 8 * i); + } + return result; + #endif +} + +uint32_t add8unsigned(uint32_t a, uint32_t b) { + /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + // Subtract out the DC offset, add and then shift back. + a = __USUB8(a, 0x80808080); + b = __USUB8(b, 0x80808080); + uint32_t sum = __QADD8(a, b); + return __UADD8(sum, 0x80808080); + #else*/ + uint32_t result = 0; + for (int8_t i = 0; i < 4; i++) { + uint8_t ai = (a >> (sizeof(uint8_t) * 8 * i)); + uint8_t bi = (b >> (sizeof(uint8_t) * 8 * i)); + int32_t intermediate = (int32_t) (ai + bi) / 2; + if (intermediate > UCHAR_MAX) { + intermediate = UCHAR_MAX; + } + result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i); + } + return result; + //#endif +} + +uint32_t add16signed(uint32_t a, uint32_t b) { + /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return __QADD16(a, b); + #else*/ + uint32_t result = 0; + for (int8_t i = 0; i < 2; i++) { + int16_t ai = a >> (sizeof(int16_t) * 8 * i); + int16_t bi = b >> (sizeof(int16_t) * 8 * i); + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } else if (intermediate < SHRT_MIN) { + intermediate = SHRT_MIN; + } + result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); + } + return result; + //#endif +} + +uint32_t add16unsigned(uint32_t a, uint32_t b) { + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + // Subtract out the DC offset, add and then shift back. + a = __USUB16(a, 0x80008000); + b = __USUB16(b, 0x80008000); + uint32_t sum = __QADD16(a, b); + return __UADD16(sum, 0x80008000); + #else + uint32_t result = 0; + for (int8_t i = 0; i < 2; i++) { + int16_t ai = (a >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + int16_t bi = (b >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + int32_t intermediate = (int32_t) ai + bi; + if (intermediate > USHRT_MAX) { + intermediate = USHRT_MAX; + } + result |= ((uint16_t) intermediate + 0x8000) << (sizeof(int16_t) * 8 * i); + } + return result; + #endif +} + +//TODO: +static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { + // if mul == 0, no need in wasting cycles + if (mul == 0) { + return 0; + } + /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return val; + #else*/ + uint32_t result = 0; + float mod_mul = (float) mul / (float) ((1<<15)-1); + for (int8_t i = 0; i < 4; i++) { + uint8_t ai = val >> (sizeof(uint8_t) * 8 * i); + int32_t intermediate = ai * mod_mul; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } + result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i); + } + + return result; + //#endif +} + +//TODO: +static inline uint32_t mult8signed(uint32_t val, int32_t mul) { + // if mul == 0, no need in wasting cycles + if (mul == 0) { + return 0; + } + /* + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return val; + #else + */ + uint32_t result = 0; + float mod_mul = (float)mul / (float)((1<<15)-1); + for (int8_t i = 0; i < 4; i++) { + int16_t ai = val >> (sizeof(int8_t) * 8 * i); + int32_t intermediate = ai * mod_mul; + if (intermediate > CHAR_MAX) { + intermediate = CHAR_MAX; + } else if (intermediate < CHAR_MIN) { + intermediate = CHAR_MIN; + } + result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int16_t) * 8 * i); + } + return result; + //#endif +} + +//TODO: +static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) { + // if mul == 0, no need in wasting cycles + if (mul == 0) { + return 0; + } + /* + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return val; + #else + */ + uint32_t result = 0; + float mod_mul = (float)mul / (float)((1<<15)-1); + for (int8_t i = 0; i < 2; i++) { + int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)) - 0x8000; + int32_t intermediate = ai * mod_mul; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } else if (intermediate < SHRT_MIN) { + intermediate = SHRT_MIN; + } + result |= (((uint32_t) intermediate) + 0x8000) << (sizeof(int16_t) * 8 * i); + } + return val; + //#endif +} + +static inline uint32_t mult16signed(uint32_t val, int32_t mul) { + // if mul == 0, no need in wasting cycles + if (mul == 0) { + return 0; + } + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + int32_t hi, lo; + int32_t bits = 16; // saturate to 16 bits + int32_t shift = 0; // shift is done automatically + asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); + asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); + asm volatile("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); + asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack + return val; + #else + uint32_t result = 0; + float mod_mul = (float)mul / (float)((1<<15)-1); + for (int8_t i = 0; i < 2; i++) { + int16_t ai = val >> (sizeof(int16_t) * 8 * i); + int32_t intermediate = ai * mod_mul; + if (intermediate > SHRT_MAX) { + intermediate = SHRT_MAX; + } else if (intermediate < SHRT_MIN) { + intermediate = SHRT_MIN; + } + result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); + } + return result; + #endif +} + +audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length) { + if (!single_channel) { + channel = 0; + } + + uint32_t channel_read_count = self->left_read_count; + if (channel == 1) { + channel_read_count = self->right_read_count; + } + *buffer_length = self->len; + + bool need_more_data = self->read_count == channel_read_count; + if (need_more_data) { + uint32_t* word_buffer; + if (self->use_first_buffer) { + *buffer = (uint8_t*) self->first_buffer; + word_buffer = self->first_buffer; + } else { + *buffer = (uint8_t*) self->second_buffer; + word_buffer = self->second_buffer; + } + self->use_first_buffer = !self->use_first_buffer; + bool voices_active = false; + for (int32_t v = 0; v < self->voice_count; v++) { + audiomixer_mixervoice_obj_t* voice = MP_OBJ_TO_PTR(self->voice[v]); + + uint32_t j = 0; + bool voice_done = voice->sample == NULL; + for (uint32_t i = 0; i < self->len / sizeof(uint32_t); i++) { + if (!voice_done && j >= voice->buffer_length) { + if (!voice->more_data) { + if (voice->loop) { + audiosample_reset_buffer(voice->sample, false, 0); + } else { + voice->sample = NULL; + voice_done = true; + } + } + if (!voice_done) { + // Load another buffer + audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t**) &voice->remaining_buffer, &voice->buffer_length); + // Track length in terms of words. + voice->buffer_length /= sizeof(uint32_t); + voice->more_data = result == GET_BUFFER_MORE_DATA; + j = 0; + } + } + // First active voice gets copied over verbatim. + uint32_t sample_value; + if (voice_done) { + // Exit early if another voice already set all samples once. + if (voices_active) { + continue; + } + sample_value = 0; + if (!self->samples_signed) { + if (self->bits_per_sample == 8) { + sample_value = 0x7f7f7f7f; + } else { + sample_value = 0x7fff7fff; + } + } + } else { + sample_value = voice->remaining_buffer[j]; + } + + // apply the mixer level + if (!self->samples_signed) { + if (self->bits_per_sample == 8) { + sample_value = mult8unsigned(sample_value, voice->level); + } else { + sample_value = mult16unsigned(sample_value, voice->level); + } + } else { + if (self->bits_per_sample == 8) { + sample_value = mult8signed(sample_value, voice->level); + } else { + sample_value = mult16signed(sample_value, voice->level); + } + } + + if (!voices_active) { + word_buffer[i] = sample_value; + } else { + if (self->bits_per_sample == 8) { + if (self->samples_signed) { + word_buffer[i] = add8signed(word_buffer[i], sample_value); + } else { + word_buffer[i] = add8unsigned(word_buffer[i], sample_value); + } + } else { + if (self->samples_signed) { + word_buffer[i] = add16signed(word_buffer[i], sample_value); + } else { + word_buffer[i] = add16unsigned(word_buffer[i], sample_value); + } + } + } + j++; + } + voice->buffer_length -= j; + voice->remaining_buffer += j; + + voices_active = true; + } + + self->read_count += 1; + } else if (!self->use_first_buffer) { + *buffer = (uint8_t*) self->first_buffer; + } else { + *buffer = (uint8_t*) self->second_buffer; + } + + + if (channel == 0) { + self->left_read_count += 1; + } else if (channel == 1) { + self->right_read_count += 1; + *buffer = *buffer + self->bits_per_sample / 8; + } + return GET_BUFFER_MORE_DATA; +} + +void audiomixer_mixer_get_buffer_structure(audiomixer_mixer_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing) { + *single_buffer = false; + *samples_signed = self->samples_signed; + *max_buffer_length = self->len; + if (single_channel) { + *spacing = self->channel_count; + } else { + *spacing = 1; + } +} diff --git a/shared-module/audiomixer/Mixer.h b/shared-module/audiomixer/Mixer.h new file mode 100644 index 000000000..ab4780efc --- /dev/null +++ b/shared-module/audiomixer/Mixer.h @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Scott Shawcroft + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOMIXER_MIXER_H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOMIXER_MIXER_H + +#include "py/obj.h" +#include "py/objtuple.h" + +#include "shared-module/audiocore/__init__.h" + +typedef struct { + mp_obj_base_t base; + uint32_t* first_buffer; + uint32_t* second_buffer; + uint32_t len; // in words + uint8_t bits_per_sample; + bool use_first_buffer; + bool samples_signed; + uint8_t channel_count; + uint32_t sample_rate; + + uint32_t read_count; + uint32_t left_read_count; + uint32_t right_read_count; + + uint8_t voice_count; + mp_obj_tuple_t *voice_tuple; + mp_obj_t voice[]; +} audiomixer_mixer_obj_t; + + +// These are not available from Python because it may be called in an interrupt. +void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t* self, + bool single_channel, + uint8_t channel); +audioio_get_buffer_result_t audiomixer_mixer_get_buffer(audiomixer_mixer_obj_t* self, + bool single_channel, + uint8_t channel, + uint8_t** buffer, + uint32_t* buffer_length); // length in bytes +void audiomixer_mixer_get_buffer_structure(audiomixer_mixer_obj_t* self, bool single_channel, + bool* single_buffer, bool* samples_signed, + uint32_t* max_buffer_length, uint8_t* spacing); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOMIXER_MIXER_H diff --git a/shared-module/audiomixer/MixerVoice.c b/shared-module/audiomixer/MixerVoice.c new file mode 100644 index 000000000..ff05dc93e --- /dev/null +++ b/shared-module/audiomixer/MixerVoice.c @@ -0,0 +1,87 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 DeanM for Adafruit Industries + * + * 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 "shared-bindings/audiomixer/Mixer.h" +#include "shared-module/audiomixer/MixerVoice.h" + +#include + +#include "py/runtime.h" +#include "shared-module/audiomixer/__init__.h" +#include "shared-module/audiocore/RawSample.h" + +void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *self) { + self->sample = NULL; + self->level = ((1 << 15) - 1); +} + +void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t* self, audiomixer_mixer_obj_t *parent) { + self->parent = parent; +} + +float common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t* self) { + return ((float) self->level / ((1 << 15) - 1)); +} + +void common_hal_audiomixer_mixervoice_set_level(audiomixer_mixervoice_obj_t* self, float level) { + self->level = level * ((1 << 15)-1); +} + +void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t* self, mp_obj_t sample, bool loop) { + if (audiosample_sample_rate(sample) != self->parent->sample_rate) { + mp_raise_ValueError(translate("The sample's sample rate does not match the mixer's")); + } + if (audiosample_channel_count(sample) != self->parent->channel_count) { + mp_raise_ValueError(translate("The sample's channel count does not match the mixer's")); + } + if (audiosample_bits_per_sample(sample) != self->parent->bits_per_sample) { + mp_raise_ValueError(translate("The sample's bits_per_sample does not match the mixer's")); + } + bool single_buffer; + bool samples_signed; + uint32_t max_buffer_length; + uint8_t spacing; + audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, + &max_buffer_length, &spacing); + if (samples_signed != self->parent->samples_signed) { + mp_raise_ValueError(translate("The sample's signedness does not match the mixer's")); + } + self->sample = sample; + self->loop = loop; + + audiosample_reset_buffer(sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t**) &self->remaining_buffer, &self->buffer_length); + // Track length in terms of words. + self->buffer_length /= sizeof(uint32_t); + self->more_data = result == GET_BUFFER_MORE_DATA; +} + +bool common_hal_audiomixer_mixervoice_get_playing(audiomixer_mixervoice_obj_t* self) { + return self->sample != NULL; +} + +void common_hal_audiomixer_mixervoice_stop(audiomixer_mixervoice_obj_t* self) { + self->sample = NULL; +} diff --git a/shared-module/audiomixer/MixerVoice.h b/shared-module/audiomixer/MixerVoice.h new file mode 100644 index 000000000..efac19156 --- /dev/null +++ b/shared-module/audiomixer/MixerVoice.h @@ -0,0 +1,46 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 DeanM for Adafruit Industries + * + * 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. + */ +#ifndef SHARED_MODULE_AUDIOMIXER_MIXERVOICE_H_ +#define SHARED_MODULE_AUDIOMIXER_MIXERVOICE_H_ + +#include "py/obj.h" + +#include "shared-module/audiomixer/__init__.h" +#include "shared-module/audiomixer/Mixer.h" + +typedef struct { + mp_obj_base_t base; + audiomixer_mixer_obj_t *parent; + mp_obj_t sample; + bool loop; + bool more_data; + uint32_t* remaining_buffer; + uint32_t buffer_length; + int16_t level; +} audiomixer_mixervoice_obj_t; + + +#endif /* SHARED_MODULE_AUDIOMIXER_MIXERVOICE_H_ */ diff --git a/shared-module/audiomixer/__init__.c b/shared-module/audiomixer/__init__.c new file mode 100644 index 000000000..e69de29bb diff --git a/shared-module/audiomixer/__init__.h b/shared-module/audiomixer/__init__.h new file mode 100644 index 000000000..35b731558 --- /dev/null +++ b/shared-module/audiomixer/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOMIXER__INIT__H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOMIXER__INIT__H + +#include "shared-module/audiocore/__init__.h" + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOMIXER__INIT__H -- cgit v1.2.3 From 7f64af38cbd74b417b28e28e706dceb00e42b01b Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sun, 25 Aug 2019 09:33:23 -0500 Subject: fix 'audiomixer_mixer_reset_buffer' --- shared-module/audiomixer/Mixer.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 0ae7c7b09..da0f7dedb 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -77,7 +77,7 @@ uint32_t common_hal_audiomixer_mixer_get_sample_rate(audiomixer_mixer_obj_t* sel } bool common_hal_audiomixer_mixer_get_playing(audiomixer_mixer_obj_t* self) { - for (int32_t v = 0; v < self->voice_count; v++) { + for (uint8_t v = 0; v < self->voice_count; v++) { if (common_hal_audiomixer_mixervoice_get_playing(MP_OBJ_TO_PTR(self->voice[v]))) { return true; } @@ -88,11 +88,9 @@ bool common_hal_audiomixer_mixer_get_playing(audiomixer_mixer_obj_t* self) { void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t* self, bool single_channel, uint8_t channel) { -#if 0 - for (int32_t i = 0; i < self->voice_count; i++) { - self->voice[i].sample = NULL; + for (uint8_t i = 0; i < self->voice_count; i++) { + common_hal_audiomixer_mixervoice_stop(self->voice[i]); } -#endif } uint32_t add8signed(uint32_t a, uint32_t b) { -- cgit v1.2.3 From 696117b048bd39d9480cfa5a2ee0871942eba816 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sun, 25 Aug 2019 14:53:34 -0500 Subject: disable audiomixer on boards it doesn't fit on --- ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk | 2 ++ .../atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk | 2 ++ ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk | 2 ++ ports/atmel-samd/boards/snekboard/mpconfigboard.mk | 2 ++ .../boards/sparkfun_redboard_turbo/mpconfigboard.mk | 2 ++ shared-module/audiocore/__init__.c | 12 ++++++++++++ 6 files changed, 22 insertions(+) (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk index 756c293ad..001d1e984 100644 --- a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk @@ -14,3 +14,5 @@ LONGINT_IMPL = MPZ CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 + +CIRCUITPY_AUDIOMIXER = 0 diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk index e34d06962..fb8d014b9 100644 --- a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk @@ -14,3 +14,5 @@ LONGINT_IMPL = MPZ CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 + +CIRCUITPY_AUDIOMIXER = 0 diff --git a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk index 93a8ffc11..7543f6efa 100644 --- a/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/metro_m0_express/mpconfigboard.mk @@ -14,3 +14,5 @@ LONGINT_IMPL = MPZ CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 + +CIRCUITPY_AUDIOMIXER = 0 diff --git a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk index 9892ade8f..d96487a6f 100644 --- a/ports/atmel-samd/boards/snekboard/mpconfigboard.mk +++ b/ports/atmel-samd/boards/snekboard/mpconfigboard.mk @@ -14,3 +14,5 @@ LONGINT_IMPL = MPZ CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 + +CIRCUITPY_AUDIOMIXER = 0 diff --git a/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk b/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk index 3be1a17d3..2ed809c24 100755 --- a/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk +++ b/ports/atmel-samd/boards/sparkfun_redboard_turbo/mpconfigboard.mk @@ -14,3 +14,5 @@ LONGINT_IMPL = MPZ CFLAGS_INLINE_LIMIT = 60 SUPEROPT_GC = 0 + +CIRCUITPY_AUDIOMIXER = 0 diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 8433a1770..f9762676f 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -42,9 +42,11 @@ uint32_t audiosample_sample_rate(mp_obj_t sample_obj) { } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return file->sample_rate; + #if CIRCUITPY_AUDIOMIXER } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); return mixer->sample_rate; + #endif } return 16000; } @@ -56,9 +58,11 @@ uint8_t audiosample_bits_per_sample(mp_obj_t sample_obj) { } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return file->bits_per_sample; + #if CIRCUITPY_AUDIOMIXER } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); return mixer->bits_per_sample; + #endif } return 8; } @@ -70,9 +74,11 @@ uint8_t audiosample_channel_count(mp_obj_t sample_obj) { } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return file->channel_count; + #if CIRCUITPY_AUDIOMIXER } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { audiomixer_mixer_obj_t* mixer = MP_OBJ_TO_PTR(sample_obj); return mixer->channel_count; + #endif } return 1; } @@ -84,9 +90,11 @@ void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel, uint8_t } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); audioio_wavefile_reset_buffer(file, single_channel, audio_channel); + #if CIRCUITPY_AUDIOMIXER } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); audiomixer_mixer_reset_buffer(file, single_channel, audio_channel); + #endif } } @@ -100,9 +108,11 @@ audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, } else if (MP_OBJ_IS_TYPE(sample_obj, &audioio_wavefile_type)) { audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return audioio_wavefile_get_buffer(file, single_channel, channel, buffer, buffer_length); + #if CIRCUITPY_AUDIOMIXER } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); return audiomixer_mixer_get_buffer(file, single_channel, channel, buffer, buffer_length); + #endif } return GET_BUFFER_DONE; } @@ -118,9 +128,11 @@ void audiosample_get_buffer_structure(mp_obj_t sample_obj, bool single_channel, audioio_wavefile_obj_t* file = MP_OBJ_TO_PTR(sample_obj); audioio_wavefile_get_buffer_structure(file, single_channel, single_buffer, samples_signed, max_buffer_length, spacing); + #if CIRCUITPY_AUDIOMIXER } else if (MP_OBJ_IS_TYPE(sample_obj, &audiomixer_mixer_type)) { audiomixer_mixer_obj_t* file = MP_OBJ_TO_PTR(sample_obj); audiomixer_mixer_get_buffer_structure(file, single_channel, single_buffer, samples_signed, max_buffer_length, spacing); + #endif } } -- cgit v1.2.3 From bea77c651afd919e6cb87927341714adbddb939c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 26 Aug 2019 16:37:59 -0700 Subject: Minor renames --- shared-bindings/displayio/Display.h | 1 - shared-module/displayio/Display.c | 4 ++-- shared-module/displayio/EPaperDisplay.c | 20 ++++++++++---------- shared-module/displayio/EPaperDisplay.h | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 2d7b68c4e..a3c77e4e8 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -50,7 +50,6 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); -// Times in ms. bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame); bool common_hal_displayio_display_get_auto_refresh(displayio_display_obj_t* self); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index cb5051bb7..f210a80c3 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -270,8 +270,8 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); } - memset(mask, 0, mask_length * sizeof(uint32_t)); - memset(buffer, 0, buffer_size * sizeof(uint32_t)); + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 38b63df0f..efbd9f3dd 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -49,7 +49,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time, - const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select) { + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select) { if (highlight_color != 0x000000) { self->core.colorspace.tricolor = true; self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); @@ -71,7 +71,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->busy_state = busy_state; self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; - self->always_toggle_chip_select = always_toggle_chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; + self->chip_select = chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; self->start_sequence = start_sequence; self->start_sequence_len = start_sequence_len; @@ -143,8 +143,8 @@ STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool shou data_size &= ~DELAY; uint8_t *data = cmd + 2; displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, cmd, 1); - self->core.send(self->core.bus, DISPLAY_DATA, self->always_toggle_chip_select, data, data_size); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, cmd, 1); + self->core.send(self->core.bus, DISPLAY_DATA, self->chip_select, data, data_size); displayio_display_core_end_transaction(&self->core); uint16_t delay_length_ms = 0; if (delay) { @@ -185,7 +185,7 @@ uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaper void displayio_epaperdisplay_finish_refresh(displayio_epaperdisplay_obj_t* self) { // Actually refresh the display now that all pixel RAM has been updated. displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, &self->refresh_display_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &self->refresh_display_command, 1); displayio_display_core_end_transaction(&self->core); self->refreshing = true; @@ -238,7 +238,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint16_t remaining_rows = displayio_area_height(&clipped); if (self->set_row_window_command != NO_COMMAND) { - displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, false, self->always_toggle_chip_select, &clipped); + displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, false, self->chip_select, &clipped); } uint8_t write_command = self->write_black_ram_command; @@ -246,7 +246,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c write_command = self->write_color_ram_command; } displayio_display_core_begin_transaction(&self->core); - self->core.send(self->core.bus, DISPLAY_COMMAND, self->always_toggle_chip_select, &write_command, 1); + self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, &write_command, 1); displayio_display_core_end_transaction(&self->core); for (uint16_t j = 0; j < subrectangles; j++) { @@ -264,8 +264,8 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint16_t subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); - memset(mask, 0, mask_length * sizeof(uint32_t)); - memset(buffer, 0, buffer_size * sizeof(uint32_t)); + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); self->core.colorspace.grayscale = true; if (pass == 1) { @@ -285,7 +285,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c // Can't acquire display bus; skip the rest of the data. Try next display. return false; } - self->core.send(self->core.bus, DISPLAY_DATA, self->always_toggle_chip_select, (uint8_t*) buffer, subrectangle_size_bytes); + self->core.send(self->core.bus, DISPLAY_DATA, self->chip_select, (uint8_t*) buffer, subrectangle_size_bytes); displayio_display_core_end_transaction(&self->core); // TODO(tannewt): Make refresh displays faster so we don't starve other diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 580171a5f..d08bed546 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -56,7 +56,7 @@ typedef struct { bool black_bits_inverted; bool color_bits_inverted; bool refreshing; - display_chip_select_behavior_t always_toggle_chip_select; + display_chip_select_behavior_t chip_select; } displayio_epaperdisplay_obj_t; void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self); -- cgit v1.2.3 From 7a64af92807f012828636c101f4350272f6e929a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 29 Aug 2019 18:44:27 -0400 Subject: rename bleio module to _bleio --- ports/nrf/bluetooth/ble_uart.c | 10 +- ports/nrf/common-hal/_bleio/Adapter.c | 204 +++++++++ ports/nrf/common-hal/_bleio/Adapter.h | 38 ++ ports/nrf/common-hal/_bleio/Attribute.c | 60 +++ ports/nrf/common-hal/_bleio/Attribute.h | 34 ++ ports/nrf/common-hal/_bleio/Central.c | 145 ++++++ ports/nrf/common-hal/_bleio/Central.h | 44 ++ ports/nrf/common-hal/_bleio/Characteristic.c | 299 ++++++++++++ ports/nrf/common-hal/_bleio/Characteristic.h | 54 +++ ports/nrf/common-hal/_bleio/CharacteristicBuffer.c | 155 +++++++ ports/nrf/common-hal/_bleio/CharacteristicBuffer.h | 43 ++ ports/nrf/common-hal/_bleio/Descriptor.c | 143 ++++++ ports/nrf/common-hal/_bleio/Descriptor.h | 50 ++ ports/nrf/common-hal/_bleio/Peripheral.c | 361 +++++++++++++++ ports/nrf/common-hal/_bleio/Peripheral.h | 67 +++ ports/nrf/common-hal/_bleio/Scanner.c | 105 +++++ ports/nrf/common-hal/_bleio/Scanner.h | 40 ++ ports/nrf/common-hal/_bleio/Service.c | 122 +++++ ports/nrf/common-hal/_bleio/Service.h | 50 ++ ports/nrf/common-hal/_bleio/UUID.c | 99 ++++ ports/nrf/common-hal/_bleio/UUID.h | 49 ++ ports/nrf/common-hal/_bleio/__init__.c | 502 +++++++++++++++++++++ ports/nrf/common-hal/_bleio/__init__.h | 42 ++ ports/nrf/common-hal/bleio/Adapter.c | 204 --------- ports/nrf/common-hal/bleio/Adapter.h | 38 -- ports/nrf/common-hal/bleio/Attribute.c | 60 --- ports/nrf/common-hal/bleio/Attribute.h | 34 -- ports/nrf/common-hal/bleio/Central.c | 145 ------ ports/nrf/common-hal/bleio/Central.h | 44 -- ports/nrf/common-hal/bleio/Characteristic.c | 299 ------------ ports/nrf/common-hal/bleio/Characteristic.h | 54 --- ports/nrf/common-hal/bleio/CharacteristicBuffer.c | 155 ------- ports/nrf/common-hal/bleio/CharacteristicBuffer.h | 43 -- ports/nrf/common-hal/bleio/Descriptor.c | 143 ------ ports/nrf/common-hal/bleio/Descriptor.h | 50 -- ports/nrf/common-hal/bleio/Peripheral.c | 361 --------------- ports/nrf/common-hal/bleio/Peripheral.h | 67 --- ports/nrf/common-hal/bleio/Scanner.c | 105 ----- ports/nrf/common-hal/bleio/Scanner.h | 40 -- ports/nrf/common-hal/bleio/Service.c | 122 ----- ports/nrf/common-hal/bleio/Service.h | 50 -- ports/nrf/common-hal/bleio/UUID.c | 99 ---- ports/nrf/common-hal/bleio/UUID.h | 49 -- ports/nrf/common-hal/bleio/__init__.c | 502 --------------------- ports/nrf/common-hal/bleio/__init__.h | 42 -- ports/nrf/supervisor/port.c | 2 +- py/circuitpy_defns.mk | 36 +- py/circuitpy_mpconfig.h | 2 +- py/circuitpy_mpconfig.mk | 2 +- shared-bindings/_bleio/Adapter.c | 125 +++++ shared-bindings/_bleio/Adapter.h | 40 ++ shared-bindings/_bleio/Address.c | 210 +++++++++ shared-bindings/_bleio/Address.h | 48 ++ shared-bindings/_bleio/Attribute.c | 94 ++++ shared-bindings/_bleio/Attribute.h | 39 ++ shared-bindings/_bleio/Central.c | 207 +++++++++ shared-bindings/_bleio/Central.h | 43 ++ shared-bindings/_bleio/Characteristic.c | 341 ++++++++++++++ shared-bindings/_bleio/Characteristic.h | 49 ++ shared-bindings/_bleio/CharacteristicBuffer.c | 252 +++++++++++ shared-bindings/_bleio/CharacteristicBuffer.h | 42 ++ shared-bindings/_bleio/Descriptor.c | 231 ++++++++++ shared-bindings/_bleio/Descriptor.h | 44 ++ shared-bindings/_bleio/Peripheral.c | 325 +++++++++++++ shared-bindings/_bleio/Peripheral.h | 48 ++ shared-bindings/_bleio/ScanEntry.c | 111 +++++ shared-bindings/_bleio/ScanEntry.h | 41 ++ shared-bindings/_bleio/Scanner.c | 129 ++++++ shared-bindings/_bleio/Scanner.h | 40 ++ shared-bindings/_bleio/Service.c | 201 +++++++++ shared-bindings/_bleio/Service.h | 43 ++ shared-bindings/_bleio/UUID.c | 280 ++++++++++++ shared-bindings/_bleio/UUID.h | 43 ++ shared-bindings/_bleio/__init__.c | 107 +++++ shared-bindings/_bleio/__init__.h | 52 +++ shared-bindings/bleio/Adapter.c | 125 ----- shared-bindings/bleio/Adapter.h | 40 -- shared-bindings/bleio/Address.c | 210 --------- shared-bindings/bleio/Address.h | 48 -- shared-bindings/bleio/Attribute.c | 94 ---- shared-bindings/bleio/Attribute.h | 39 -- shared-bindings/bleio/Central.c | 207 --------- shared-bindings/bleio/Central.h | 43 -- shared-bindings/bleio/Characteristic.c | 341 -------------- shared-bindings/bleio/Characteristic.h | 49 -- shared-bindings/bleio/CharacteristicBuffer.c | 252 ----------- shared-bindings/bleio/CharacteristicBuffer.h | 42 -- shared-bindings/bleio/Descriptor.c | 231 ---------- shared-bindings/bleio/Descriptor.h | 44 -- shared-bindings/bleio/Peripheral.c | 325 ------------- shared-bindings/bleio/Peripheral.h | 48 -- shared-bindings/bleio/ScanEntry.c | 111 ----- shared-bindings/bleio/ScanEntry.h | 41 -- shared-bindings/bleio/Scanner.c | 129 ------ shared-bindings/bleio/Scanner.h | 40 -- shared-bindings/bleio/Service.c | 201 --------- shared-bindings/bleio/Service.h | 43 -- shared-bindings/bleio/UUID.c | 280 ------------ shared-bindings/bleio/UUID.h | 43 -- shared-bindings/bleio/__init__.c | 104 ----- shared-bindings/bleio/__init__.h | 52 --- shared-module/_bleio/Address.c | 45 ++ shared-module/_bleio/Address.h | 41 ++ shared-module/_bleio/Attribute.c | 46 ++ shared-module/_bleio/Attribute.h | 41 ++ shared-module/_bleio/Characteristic.h | 43 ++ shared-module/_bleio/ScanEntry.c | 45 ++ shared-module/_bleio/ScanEntry.h | 42 ++ shared-module/bleio/Address.c | 45 -- shared-module/bleio/Address.h | 41 -- shared-module/bleio/Attribute.c | 46 -- shared-module/bleio/Attribute.h | 41 -- shared-module/bleio/Characteristic.h | 43 -- shared-module/bleio/ScanEntry.c | 45 -- shared-module/bleio/ScanEntry.h | 42 -- 115 files changed, 6220 insertions(+), 6217 deletions(-) create mode 100644 ports/nrf/common-hal/_bleio/Adapter.c create mode 100644 ports/nrf/common-hal/_bleio/Adapter.h create mode 100644 ports/nrf/common-hal/_bleio/Attribute.c create mode 100644 ports/nrf/common-hal/_bleio/Attribute.h create mode 100644 ports/nrf/common-hal/_bleio/Central.c create mode 100644 ports/nrf/common-hal/_bleio/Central.h create mode 100644 ports/nrf/common-hal/_bleio/Characteristic.c create mode 100644 ports/nrf/common-hal/_bleio/Characteristic.h create mode 100644 ports/nrf/common-hal/_bleio/CharacteristicBuffer.c create mode 100644 ports/nrf/common-hal/_bleio/CharacteristicBuffer.h create mode 100644 ports/nrf/common-hal/_bleio/Descriptor.c create mode 100644 ports/nrf/common-hal/_bleio/Descriptor.h create mode 100644 ports/nrf/common-hal/_bleio/Peripheral.c create mode 100644 ports/nrf/common-hal/_bleio/Peripheral.h create mode 100644 ports/nrf/common-hal/_bleio/Scanner.c create mode 100644 ports/nrf/common-hal/_bleio/Scanner.h create mode 100644 ports/nrf/common-hal/_bleio/Service.c create mode 100644 ports/nrf/common-hal/_bleio/Service.h create mode 100644 ports/nrf/common-hal/_bleio/UUID.c create mode 100644 ports/nrf/common-hal/_bleio/UUID.h create mode 100644 ports/nrf/common-hal/_bleio/__init__.c create mode 100644 ports/nrf/common-hal/_bleio/__init__.h delete mode 100644 ports/nrf/common-hal/bleio/Adapter.c delete mode 100644 ports/nrf/common-hal/bleio/Adapter.h delete mode 100644 ports/nrf/common-hal/bleio/Attribute.c delete mode 100644 ports/nrf/common-hal/bleio/Attribute.h delete mode 100644 ports/nrf/common-hal/bleio/Central.c delete mode 100644 ports/nrf/common-hal/bleio/Central.h delete mode 100644 ports/nrf/common-hal/bleio/Characteristic.c delete mode 100644 ports/nrf/common-hal/bleio/Characteristic.h delete mode 100644 ports/nrf/common-hal/bleio/CharacteristicBuffer.c delete mode 100644 ports/nrf/common-hal/bleio/CharacteristicBuffer.h delete mode 100644 ports/nrf/common-hal/bleio/Descriptor.c delete mode 100644 ports/nrf/common-hal/bleio/Descriptor.h delete mode 100644 ports/nrf/common-hal/bleio/Peripheral.c delete mode 100644 ports/nrf/common-hal/bleio/Peripheral.h delete mode 100644 ports/nrf/common-hal/bleio/Scanner.c delete mode 100644 ports/nrf/common-hal/bleio/Scanner.h delete mode 100644 ports/nrf/common-hal/bleio/Service.c delete mode 100644 ports/nrf/common-hal/bleio/Service.h delete mode 100644 ports/nrf/common-hal/bleio/UUID.c delete mode 100644 ports/nrf/common-hal/bleio/UUID.h delete mode 100644 ports/nrf/common-hal/bleio/__init__.c delete mode 100644 ports/nrf/common-hal/bleio/__init__.h create mode 100644 shared-bindings/_bleio/Adapter.c create mode 100644 shared-bindings/_bleio/Adapter.h create mode 100644 shared-bindings/_bleio/Address.c create mode 100644 shared-bindings/_bleio/Address.h create mode 100644 shared-bindings/_bleio/Attribute.c create mode 100644 shared-bindings/_bleio/Attribute.h create mode 100644 shared-bindings/_bleio/Central.c create mode 100644 shared-bindings/_bleio/Central.h create mode 100644 shared-bindings/_bleio/Characteristic.c create mode 100644 shared-bindings/_bleio/Characteristic.h create mode 100644 shared-bindings/_bleio/CharacteristicBuffer.c create mode 100644 shared-bindings/_bleio/CharacteristicBuffer.h create mode 100644 shared-bindings/_bleio/Descriptor.c create mode 100644 shared-bindings/_bleio/Descriptor.h create mode 100644 shared-bindings/_bleio/Peripheral.c create mode 100644 shared-bindings/_bleio/Peripheral.h create mode 100644 shared-bindings/_bleio/ScanEntry.c create mode 100644 shared-bindings/_bleio/ScanEntry.h create mode 100644 shared-bindings/_bleio/Scanner.c create mode 100644 shared-bindings/_bleio/Scanner.h create mode 100644 shared-bindings/_bleio/Service.c create mode 100644 shared-bindings/_bleio/Service.h create mode 100644 shared-bindings/_bleio/UUID.c create mode 100644 shared-bindings/_bleio/UUID.h create mode 100644 shared-bindings/_bleio/__init__.c create mode 100644 shared-bindings/_bleio/__init__.h delete mode 100644 shared-bindings/bleio/Adapter.c delete mode 100644 shared-bindings/bleio/Adapter.h delete mode 100644 shared-bindings/bleio/Address.c delete mode 100644 shared-bindings/bleio/Address.h delete mode 100644 shared-bindings/bleio/Attribute.c delete mode 100644 shared-bindings/bleio/Attribute.h delete mode 100644 shared-bindings/bleio/Central.c delete mode 100644 shared-bindings/bleio/Central.h delete mode 100644 shared-bindings/bleio/Characteristic.c delete mode 100644 shared-bindings/bleio/Characteristic.h delete mode 100644 shared-bindings/bleio/CharacteristicBuffer.c delete mode 100644 shared-bindings/bleio/CharacteristicBuffer.h delete mode 100644 shared-bindings/bleio/Descriptor.c delete mode 100644 shared-bindings/bleio/Descriptor.h delete mode 100644 shared-bindings/bleio/Peripheral.c delete mode 100644 shared-bindings/bleio/Peripheral.h delete mode 100644 shared-bindings/bleio/ScanEntry.c delete mode 100644 shared-bindings/bleio/ScanEntry.h delete mode 100644 shared-bindings/bleio/Scanner.c delete mode 100644 shared-bindings/bleio/Scanner.h delete mode 100644 shared-bindings/bleio/Service.c delete mode 100644 shared-bindings/bleio/Service.h delete mode 100644 shared-bindings/bleio/UUID.c delete mode 100644 shared-bindings/bleio/UUID.h delete mode 100644 shared-bindings/bleio/__init__.c delete mode 100644 shared-bindings/bleio/__init__.h create mode 100644 shared-module/_bleio/Address.c create mode 100644 shared-module/_bleio/Address.h create mode 100644 shared-module/_bleio/Attribute.c create mode 100644 shared-module/_bleio/Attribute.h create mode 100644 shared-module/_bleio/Characteristic.h create mode 100644 shared-module/_bleio/ScanEntry.c create mode 100644 shared-module/_bleio/ScanEntry.h delete mode 100644 shared-module/bleio/Address.c delete mode 100644 shared-module/bleio/Address.h delete mode 100644 shared-module/bleio/Attribute.c delete mode 100644 shared-module/bleio/Attribute.h delete mode 100644 shared-module/bleio/Characteristic.h delete mode 100644 shared-module/bleio/ScanEntry.c delete mode 100644 shared-module/bleio/ScanEntry.h (limited to 'shared-module') diff --git a/ports/nrf/bluetooth/ble_uart.c b/ports/nrf/bluetooth/ble_uart.c index d83cf3980..787a2a117 100644 --- a/ports/nrf/bluetooth/ble_uart.c +++ b/ports/nrf/bluetooth/ble_uart.c @@ -34,11 +34,11 @@ #include "py/mphal.h" #include "py/runtime.h" #include "lib/utils/interrupt_char.h" -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Device.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Device.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" #if (MICROPY_PY_BLE_NUS == 1) diff --git a/ports/nrf/common-hal/_bleio/Adapter.c b/ports/nrf/common-hal/_bleio/Adapter.c new file mode 100644 index 000000000..a8e1f1905 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Adapter.c @@ -0,0 +1,204 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2018 Artur Pacholec + * + * 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 +#include + +#include "ble.h" +#include "ble_drv.h" +#include "nrfx_power.h" +#include "nrf_nvic.h" +#include "nrf_sdm.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "supervisor/usb.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Address.h" + +#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) +#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) +#define BLE_SLAVE_LATENCY 0 +#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) + +STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { + mp_raise_msg_varg(&mp_type_AssertionError, + translate("Soft device assert, id: 0x%08lX, pc: 0x%08lX"), id, pc); +} + +STATIC uint32_t ble_stack_enable(void) { + nrf_clock_lf_cfg_t clock_config = { +#if BOARD_HAS_32KHZ_XTAL + .source = NRF_CLOCK_LF_SRC_XTAL, + .rc_ctiv = 0, + .rc_temp_ctiv = 0, + .accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM, +#else + .source = NRF_CLOCK_LF_SRC_RC, + .rc_ctiv = 16, + .rc_temp_ctiv = 2, + .accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM, +#endif + }; + + uint32_t err_code = sd_softdevice_enable(&clock_config, softdevice_assert_handler); + if (err_code != NRF_SUCCESS) { + return err_code; + } + + err_code = sd_nvic_EnableIRQ(SD_EVT_IRQn); + if (err_code != NRF_SUCCESS) { + return err_code; + } + + // Start with no event handlers, etc. + ble_drv_reset(); + + uint32_t app_ram_start; + app_ram_start = 0x20004000; + + ble_cfg_t ble_conf; + ble_conf.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_TAG_CUSTOM; + ble_conf.conn_cfg.params.gap_conn_cfg.conn_count = BLE_GAP_CONN_COUNT_DEFAULT; + ble_conf.conn_cfg.params.gap_conn_cfg.event_length = BLE_GAP_EVENT_LENGTH_DEFAULT; + err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_conf, app_ram_start); + if (err_code != NRF_SUCCESS) + return err_code; + + memset(&ble_conf, 0, sizeof(ble_conf)); + ble_conf.gap_cfg.role_count_cfg.periph_role_count = 1; + ble_conf.gap_cfg.role_count_cfg.central_role_count = 1; + err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_conf, app_ram_start); + if (err_code != NRF_SUCCESS) + return err_code; + + memset(&ble_conf, 0, sizeof(ble_conf)); + ble_conf.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_TAG_CUSTOM; + ble_conf.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = MAX_TX_IN_PROGRESS; + err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATTS, &ble_conf, app_ram_start); + if (err_code != NRF_SUCCESS) + return err_code; + + err_code = sd_ble_enable(&app_ram_start); + if (err_code != NRF_SUCCESS) + return err_code; + + ble_gap_conn_params_t gap_conn_params = { + .min_conn_interval = BLE_MIN_CONN_INTERVAL, + .max_conn_interval = BLE_MAX_CONN_INTERVAL, + .slave_latency = BLE_SLAVE_LATENCY, + .conn_sup_timeout = BLE_CONN_SUP_TIMEOUT, + }; + err_code = sd_ble_gap_ppcp_set(&gap_conn_params); + if (err_code != NRF_SUCCESS) { + return err_code; + } + + err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_UNKNOWN); + return err_code; +} + +void common_hal_bleio_adapter_set_enabled(bool enabled) { + const bool is_enabled = common_hal_bleio_adapter_get_enabled(); + + // Don't enable or disable twice + if ((is_enabled && enabled) || (!is_enabled && !enabled)) { + return; + } + + uint32_t err_code; + if (enabled) { + // The SD takes over the POWER module and will fail if the module is already in use. + // Occurs when USB is initialized previously + nrfx_power_uninit(); + + err_code = ble_stack_enable(); + + // Re-init USB hardware + init_usb_hardware(); + } else { + err_code = sd_softdevice_disable(); + + // Re-init USB hardware + init_usb_hardware(); + } + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg(translate("Failed to change softdevice state")); + } +} + +bool common_hal_bleio_adapter_get_enabled(void) { + uint8_t is_enabled; + + const uint32_t err_code = sd_softdevice_is_enabled(&is_enabled); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg(translate("Failed to get softdevice state")); + } + + return is_enabled; +} + +void get_address(ble_gap_addr_t *address) { + uint32_t err_code; + + common_hal_bleio_adapter_set_enabled(true); + err_code = sd_ble_gap_addr_get(address); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg(translate("Failed to get local address")); + } +} + +bleio_address_obj_t *common_hal_bleio_adapter_get_address(void) { + common_hal_bleio_adapter_set_enabled(true); + + ble_gap_addr_t local_address; + get_address(&local_address); + + bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t); + address->base.type = &bleio_address_type; + + common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type); + return address; +} + +mp_obj_t common_hal_bleio_adapter_get_default_name(void) { + common_hal_bleio_adapter_set_enabled(true); + + ble_gap_addr_t local_address; + get_address(&local_address); + + char name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0 }; + + name[sizeof(name) - 4] = nibble_to_hex_lower[local_address.addr[1] >> 4 & 0xf]; + name[sizeof(name) - 3] = nibble_to_hex_lower[local_address.addr[1] & 0xf]; + name[sizeof(name) - 2] = nibble_to_hex_lower[local_address.addr[0] >> 4 & 0xf]; + name[sizeof(name) - 1] = nibble_to_hex_lower[local_address.addr[0] & 0xf]; + + return mp_obj_new_str(name, sizeof(name)); +} diff --git a/ports/nrf/common-hal/_bleio/Adapter.h b/ports/nrf/common-hal/_bleio/Adapter.h new file mode 100644 index 000000000..5dcc62540 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Adapter.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ADAPTER_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ADAPTER_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +} super_adapter_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ADAPTER_H diff --git a/ports/nrf/common-hal/_bleio/Attribute.c b/ports/nrf/common-hal/_bleio/Attribute.c new file mode 100644 index 000000000..c55914b10 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Attribute.c @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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 "shared-bindings/_bleio/Attribute.h" + +// Convert a _bleio security mode to a ble_gap_conn_sec_mode_t setting. +void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SECURITY_MODE_NO_ACCESS: + BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); + break; + + case SECURITY_MODE_OPEN: + BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); + break; + + case SECURITY_MODE_ENC_NO_MITM: + BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); + break; + + case SECURITY_MODE_ENC_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); + break; + + case SECURITY_MODE_LESC_ENC_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); + break; + + case SECURITY_MODE_SIGNED_NO_MITM: + BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); + break; + + case SECURITY_MODE_SIGNED_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); + break; + } +} diff --git a/ports/nrf/common-hal/_bleio/Attribute.h b/ports/nrf/common-hal/_bleio/Attribute.h new file mode 100644 index 000000000..8cc361046 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Attribute.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H + +#include "shared-module/_bleio/Attribute.h" + +extern void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode); + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H diff --git a/ports/nrf/common-hal/_bleio/Central.c b/ports/nrf/common-hal/_bleio/Central.c new file mode 100644 index 000000000..db67b763c --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Central.c @@ -0,0 +1,145 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 +#include + +#include "ble.h" +#include "ble_drv.h" +#include "ble_hci.h" +#include "nrf_soc.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Central.h" + +STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { + bleio_central_obj_t *central = (bleio_central_obj_t*)central_in; + + switch (ble_evt->header.evt_id) { + case BLE_GAP_EVT_CONNECTED: + central->conn_handle = ble_evt->evt.gap_evt.conn_handle; + central->waiting_to_connect = false; + break; + + case BLE_GAP_EVT_TIMEOUT: + // Handle will be invalid. + central->waiting_to_connect = false; + break; + + case BLE_GAP_EVT_DISCONNECTED: + central->conn_handle = BLE_CONN_HANDLE_INVALID; + break; + + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: + sd_ble_gap_sec_params_reply(central->conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); + break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { + ble_gap_evt_conn_param_update_request_t *request = + &ble_evt->evt.gap_evt.params.conn_param_update_request; + sd_ble_gap_conn_param_update(central->conn_handle, &request->conn_params); + break; + } + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled central event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + +void common_hal_bleio_central_construct(bleio_central_obj_t *self) { + common_hal_bleio_adapter_set_enabled(true); + + self->remote_service_list = mp_obj_new_list(0, NULL); + self->conn_handle = BLE_CONN_HANDLE_INVALID; +} + +void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { + common_hal_bleio_adapter_set_enabled(true); + ble_drv_add_event_handler(central_on_ble_evt, self); + + ble_gap_addr_t addr; + + addr.addr_type = address->type; + mp_buffer_info_t address_buf_info; + mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); + memcpy(addr.addr, (uint8_t *) address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); + + ble_gap_scan_params_t scan_params = { + .interval = MSEC_TO_UNITS(100, UNIT_0_625_MS), + .window = MSEC_TO_UNITS(100, UNIT_0_625_MS), + .scan_phys = BLE_GAP_PHY_1MBPS, + // timeout of 0 means no timeout + .timeout = SEC_TO_UNITS(timeout, UNIT_10_MS), + }; + + ble_gap_conn_params_t conn_params = { + .conn_sup_timeout = MSEC_TO_UNITS(4000, UNIT_10_MS), + .min_conn_interval = MSEC_TO_UNITS(15, UNIT_1_25_MS), + .max_conn_interval = MSEC_TO_UNITS(300, UNIT_1_25_MS), + .slave_latency = 0, // number of conn events + }; + + self->waiting_to_connect = true; + + uint32_t err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_CUSTOM); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to start connecting, error 0x%04x"), err_code); + } + + while (self->waiting_to_connect) { + RUN_BACKGROUND_TASKS; + } + + if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { + mp_raise_OSError_msg(translate("Failed to connect: timeout")); + } +} + +void common_hal_bleio_central_disconnect(bleio_central_obj_t *self) { + sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); +} + +bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self) { + return self->conn_handle != BLE_CONN_HANDLE_INVALID; +} + +mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist) { + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); + // Convert to a tuple and then clear the list so the callee will take ownership. + mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_service_list->len, + self->remote_service_list->items); + mp_obj_list_clear(self->remote_service_list); + return services_tuple; +} + +mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self) { + return self->remote_service_list; +} diff --git a/ports/nrf/common-hal/_bleio/Central.h b/ports/nrf/common-hal/_bleio/Central.h new file mode 100644 index 000000000..01f7faca7 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Central.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H + +#include + +#include "py/objlist.h" +#include "shared-module/_bleio/Address.h" + +typedef struct { + mp_obj_base_t base; + volatile bool waiting_to_connect; + volatile uint16_t conn_handle; + // Services discovered after connecting to a remote peripheral. + mp_obj_list_t *remote_service_list; +} bleio_central_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H diff --git a/ports/nrf/common-hal/_bleio/Characteristic.c b/ports/nrf/common-hal/_bleio/Characteristic.c new file mode 100644 index 000000000..e8454d528 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Characteristic.c @@ -0,0 +1,299 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 "py/runtime.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" + +static volatile bleio_characteristic_obj_t *m_read_characteristic; + +STATIC uint16_t characteristic_get_cccd(uint16_t cccd_handle, uint16_t conn_handle) { + uint16_t cccd; + ble_gatts_value_t value = { + .p_value = (uint8_t*) &cccd, + .len = 2, + }; + + const uint32_t err_code = sd_ble_gatts_value_get(conn_handle, cccd_handle, &value); + + if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING) { + // CCCD is not set, so say that neither Notify nor Indicate is enabled. + cccd = 0; + } else if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to read CCCD value, err 0x%04x"), err_code); + } + + return cccd; +} + +STATIC void characteristic_on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { + switch (ble_evt->header.evt_id) { + + // More events may be handled later, so keep this as a switch. + + case BLE_GATTC_EVT_READ_RSP: { + ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp; + if (m_read_characteristic) { + m_read_characteristic->value = mp_obj_new_bytearray(response->len, response->data); + } + // Indicate to busy-wait loop that we've read the attribute value. + m_read_characteristic = NULL; + break; + } + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled characteristic event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + +STATIC void characteristic_gatts_notify_indicate(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, uint16_t hvx_type) { + uint16_t hvx_len = bufinfo->len; + + ble_gatts_hvx_params_t hvx_params = { + .handle = handle, + .type = hvx_type, + .offset = 0, + .p_len = &hvx_len, + .p_data = bufinfo->buf, + }; + + while (1) { + const uint32_t err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params); + if (err_code == NRF_SUCCESS) { + break; + } + // TX buffer is full + // We could wait for an event indicating the write is complete, but just retrying is easier. + if (err_code == NRF_ERROR_RESOURCES) { + RUN_BACKGROUND_TASKS; + continue; + } + + // Some real error has occurred. + mp_raise_OSError_msg_varg(translate("Failed to notify or indicate attribute value, err 0x%04x"), err_code); + } +} + +STATIC void characteristic_gattc_read(bleio_characteristic_obj_t *characteristic) { + const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device); + common_hal_bleio_check_connected(conn_handle); + + // Set to NULL in event loop after event. + m_read_characteristic = characteristic; + + ble_drv_add_event_handler(characteristic_on_gattc_read_rsp_evt, characteristic); + + const uint32_t err_code = sd_ble_gattc_read(conn_handle, characteristic->handle, 0); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to read attribute value, err 0x%04x"), err_code); + } + + while (m_read_characteristic != NULL) { + RUN_BACKGROUND_TASKS; + } + + ble_drv_remove_event_handler(characteristic_on_gattc_read_rsp_evt, characteristic); +} + +void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) { + self->service = service; + self->uuid = uuid; + self->handle = BLE_GATT_HANDLE_INVALID; + self->props = props; + self->read_perm = read_perm; + self->write_perm = write_perm; + self->descriptor_list = mp_obj_new_list(0, NULL); + + const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; + if (max_length < 0 || max_length > max_length_max) { + mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"), + max_length_max, fixed_length ? "True" : "False"); + } + self->max_length = max_length; + self->fixed_length = fixed_length; + + common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo); +} + +mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self) { + return self->descriptor_list; +} + +bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { + return self->service; +} + +mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self) { + // Do GATT operations only if this characteristic has been added to a registered service. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); + if (common_hal_bleio_service_get_is_remote(self->service)) { + // self->value is set by evt handler. + characteristic_gattc_read(self); + } else { + self->value = common_hal_bleio_gatts_read(self->handle, conn_handle); + } + } + + return self->value; +} + +void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { + if (self->fixed_length && bufinfo->len != self->max_length) { + mp_raise_ValueError(translate("Value length != required fixed length")); + } + if (bufinfo->len > self->max_length) { + mp_raise_ValueError(translate("Value length > max_length")); + } + + self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); + + // Do GATT operations only if this characteristic has been added to a registered service. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); + + if (common_hal_bleio_service_get_is_remote(self->service)) { + // Last argument is true if write-no-reponse desired. + common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, + (self->props & CHAR_PROP_WRITE_NO_RESPONSE)); + } else { + + bool sent = false; + uint16_t cccd = 0; + + const bool notify = self->props & CHAR_PROP_NOTIFY; + const bool indicate = self->props & CHAR_PROP_INDICATE; + if (notify | indicate) { + cccd = characteristic_get_cccd(self->cccd_handle, conn_handle); + } + + // It's possible that both notify and indicate are set. + if (notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { + characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_NOTIFICATION); + sent = true; + } + if (indicate && (cccd & BLE_GATT_HVX_INDICATION)) { + characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_INDICATION); + sent = true; + } + + if (!sent) { + common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); + } + } + } +} + +bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self) { + return self->uuid; +} + +bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self) { + return self->props; +} + +void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) { + ble_uuid_t desc_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(descriptor->uuid, &desc_uuid); + + ble_gatts_attr_md_t desc_attr_md = { + // Data passed is not in a permanent location and should be copied. + .vloc = BLE_GATTS_VLOC_STACK, + .vlen = !descriptor->fixed_length, + }; + + bleio_attribute_gatts_set_security_mode(&desc_attr_md.read_perm, descriptor->read_perm); + bleio_attribute_gatts_set_security_mode(&desc_attr_md.write_perm, descriptor->write_perm); + + mp_buffer_info_t desc_value_bufinfo; + mp_get_buffer_raise(descriptor->value, &desc_value_bufinfo, MP_BUFFER_READ); + + ble_gatts_attr_t desc_attr = { + .p_uuid = &desc_uuid, + .p_attr_md = &desc_attr_md, + .init_len = desc_value_bufinfo.len, + .p_value = desc_value_bufinfo.buf, + .init_offs = 0, + .max_len = descriptor->max_length, + }; + + uint32_t err_code = sd_ble_gatts_descriptor_add(self->handle, &desc_attr, &descriptor->handle); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to add descriptor, err 0x%04x"), err_code); + } + + mp_obj_list_append(self->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); +} + +void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { + if (self->cccd_handle == BLE_GATT_HANDLE_INVALID) { + mp_raise_ValueError(translate("No CCCD for this Characteristic")); + } + + if (!common_hal_bleio_service_get_is_remote(self->service)) { + mp_raise_ValueError(translate("Can't set CCCD on local Characteristic")); + } + + const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); + common_hal_bleio_check_connected(conn_handle); + + uint16_t cccd_value = + (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | + (indicate ? BLE_GATT_HVX_INDICATION : 0); + + ble_gattc_write_params_t write_params = { + .write_op = BLE_GATT_OP_WRITE_REQ, + .handle = self->cccd_handle, + .p_value = (uint8_t *) &cccd_value, + .len = 2, + }; + + while (1) { + uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); + if (err_code == NRF_SUCCESS) { + break; + } + + // Write with response will return NRF_ERROR_BUSY if the response has not been received. + // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. + if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { + // We could wait for an event indicating the write is complete, but just retrying is easier. + RUN_BACKGROUND_TASKS; + continue; + } + + // Some real error occurred. + mp_raise_OSError_msg_varg(translate("Failed to write CCCD, err 0x%04x"), err_code); + } + +} diff --git a/ports/nrf/common-hal/_bleio/Characteristic.h b/ports/nrf/common-hal/_bleio/Characteristic.h new file mode 100644 index 000000000..3a7691d07 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Characteristic.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H + +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-module/_bleio/Characteristic.h" +#include "common-hal/_bleio/Service.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct { + mp_obj_base_t base; + // Will be MP_OBJ_NULL before being assigned to a Service. + bleio_service_obj_t *service; + bleio_uuid_obj_t *uuid; + mp_obj_t value; + uint16_t max_length; + bool fixed_length; + uint16_t handle; + bleio_characteristic_properties_t props; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; + mp_obj_list_t *descriptor_list; + uint16_t user_desc_handle; + uint16_t cccd_handle; + uint16_t sccd_handle; +} bleio_characteristic_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H diff --git a/ports/nrf/common-hal/_bleio/CharacteristicBuffer.c b/ports/nrf/common-hal/_bleio/CharacteristicBuffer.c new file mode 100644 index 000000000..95794feec --- /dev/null +++ b/ports/nrf/common-hal/_bleio/CharacteristicBuffer.c @@ -0,0 +1,155 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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 +#include + +#include "ble_drv.h" +#include "ble_gatts.h" +#include "nrf_nvic.h" + +#include "lib/utils/interrupt_char.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include "tick.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "common-hal/_bleio/CharacteristicBuffer.h" + +STATIC void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) { + // Push all the data onto the ring buffer. + uint8_t is_nested_critical_region; + sd_nvic_critical_region_enter(&is_nested_critical_region); + for (size_t i = 0; i < len; i++) { + ringbuf_put(&self->ringbuf, data[i]); + } + sd_nvic_critical_region_exit(is_nested_critical_region); +} + +STATIC void characteristic_buffer_on_ble_evt(ble_evt_t *ble_evt, void *param) { + bleio_characteristic_buffer_obj_t *self = (bleio_characteristic_buffer_obj_t *) param; + switch (ble_evt->header.evt_id) { + case BLE_GATTS_EVT_WRITE: { + // A client wrote to this server characteristic. + + ble_gatts_evt_write_t *evt_write = &ble_evt->evt.gatts_evt.params.write; + // Event handle must match the handle for my characteristic. + if (evt_write->handle == self->characteristic->handle) { + write_to_ringbuf(self, evt_write->data, evt_write->len); + } + break; + } + + case BLE_GATTC_EVT_HVX: { + // A remote service wrote to this characteristic. + + ble_gattc_evt_hvx_t* evt_hvx = &ble_evt->evt.gattc_evt.params.hvx; + // Must be a notification, and event handle must match the handle for my characteristic. + if (evt_hvx->type == BLE_GATT_HVX_NOTIFICATION && + evt_hvx->handle == self->characteristic->handle) { + write_to_ringbuf(self, evt_hvx->data, evt_hvx->len); + } + break; + } + } +} + +// Assumes that timeout and buffer_size have been validated before call. +void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, + bleio_characteristic_obj_t *characteristic, + mp_float_t timeout, + size_t buffer_size) { + + self->characteristic = characteristic; + self->timeout_ms = timeout * 1000; + // This is a macro. + // true means long-lived, so it won't be moved. + ringbuf_alloc(&self->ringbuf, buffer_size, true); + + ble_drv_add_event_handler(characteristic_buffer_on_ble_evt, self); + +} + +int common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) { + uint64_t start_ticks = ticks_ms; + + // Wait for all bytes received or timeout + while ( (ringbuf_count(&self->ringbuf) < len) && (ticks_ms - start_ticks < self->timeout_ms) ) { + RUN_BACKGROUND_TASKS; + // Allow user to break out of a timeout with a KeyboardInterrupt. + if ( mp_hal_is_interrupted() ) { + return 0; + } + } + + // Copy received data. Lock out write interrupt handler while copying. + uint8_t is_nested_critical_region; + sd_nvic_critical_region_enter(&is_nested_critical_region); + + size_t rx_bytes = MIN(ringbuf_count(&self->ringbuf), len); + for ( size_t i = 0; i < rx_bytes; i++ ) { + data[i] = ringbuf_get(&self->ringbuf); + } + + // Writes now OK. + sd_nvic_critical_region_exit(is_nested_critical_region); + + return rx_bytes; +} + +uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) { + uint8_t is_nested_critical_region; + sd_nvic_critical_region_enter(&is_nested_critical_region); + uint16_t count = ringbuf_count(&self->ringbuf); + sd_nvic_critical_region_exit(is_nested_critical_region); + return count; +} + +void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) { + // prevent conflict with uart irq + uint8_t is_nested_critical_region; + sd_nvic_critical_region_enter(&is_nested_critical_region); + ringbuf_clear(&self->ringbuf); + sd_nvic_critical_region_exit(is_nested_critical_region); +} + +bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { + return self->characteristic == NULL; +} + +void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) { + if (!common_hal_bleio_characteristic_buffer_deinited(self)) { + ble_drv_remove_event_handler(characteristic_buffer_on_ble_evt, self); + } +} + +bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) { + return self->characteristic != NULL && + self->characteristic->service != NULL && + self->characteristic->service->device != NULL && + common_hal_bleio_device_get_conn_handle(self->characteristic->service->device) != BLE_CONN_HANDLE_INVALID; +} diff --git a/ports/nrf/common-hal/_bleio/CharacteristicBuffer.h b/ports/nrf/common-hal/_bleio/CharacteristicBuffer.h new file mode 100644 index 000000000..f0949251c --- /dev/null +++ b/ports/nrf/common-hal/_bleio/CharacteristicBuffer.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H + +#include "nrf_soc.h" + +#include "py/ringbuf.h" +#include "shared-bindings/_bleio/Characteristic.h" + +typedef struct { + mp_obj_base_t base; + bleio_characteristic_obj_t *characteristic; + uint32_t timeout_ms; + // Ring buffer storing consecutive incoming values. + ringbuf_t ringbuf; +} bleio_characteristic_buffer_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H diff --git a/ports/nrf/common-hal/_bleio/Descriptor.c b/ports/nrf/common-hal/_bleio/Descriptor.c new file mode 100644 index 000000000..137f004ba --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Descriptor.c @@ -0,0 +1,143 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 "py/runtime.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" + +static volatile bleio_descriptor_obj_t *m_read_descriptor; + +void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) { + self->characteristic = characteristic; + self->uuid = uuid; + self->handle = BLE_GATT_HANDLE_INVALID; + self->read_perm = read_perm; + self->write_perm = write_perm; + + const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; + if (max_length < 0 || max_length > max_length_max) { + mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"), + max_length_max, fixed_length ? "True" : "False"); + } + self->max_length = max_length; + self->fixed_length = fixed_length; + + common_hal_bleio_descriptor_set_value(self, initial_value_bufinfo); +} + +bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { + return self->uuid; +} + +bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self) { + return self->characteristic; +} + +STATIC void descriptor_on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { + switch (ble_evt->header.evt_id) { + + // More events may be handled later, so keep this as a switch. + + case BLE_GATTC_EVT_READ_RSP: { + ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp; + if (m_read_descriptor) { + m_read_descriptor->value = mp_obj_new_bytearray(response->len, response->data); + } + // Indicate to busy-wait loop that we've read the attribute value. + m_read_descriptor = NULL; + break; + } + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled descriptor event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + +STATIC void descriptor_gattc_read(bleio_descriptor_obj_t *descriptor) { + const uint16_t conn_handle = + common_hal_bleio_device_get_conn_handle(descriptor->characteristic->service->device); + common_hal_bleio_check_connected(conn_handle); + + // Set to NULL in event loop after event. + m_read_descriptor = descriptor; + + ble_drv_add_event_handler(descriptor_on_gattc_read_rsp_evt, descriptor); + + const uint32_t err_code = sd_ble_gattc_read(conn_handle, descriptor->handle, 0); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to read attribute value, err 0x%04x"), err_code); + } + + while (m_read_descriptor != NULL) { + MICROPY_VM_HOOK_LOOP; + } + + ble_drv_remove_event_handler(descriptor_on_gattc_read_rsp_evt, descriptor); +} + +mp_obj_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self) { + // Do GATT operations only if this descriptor has been registered + if (self->handle != BLE_GATT_HANDLE_INVALID) { + if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { + descriptor_gattc_read(self); + } else { + self->value = common_hal_bleio_gatts_read( + self->handle, common_hal_bleio_device_get_conn_handle(self->characteristic->service->device)); + } + } + + return self->value; +} + +void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) { + if (self->fixed_length && bufinfo->len != self->max_length) { + mp_raise_ValueError(translate("Value length != required fixed length")); + } + if (bufinfo->len > self->max_length) { + mp_raise_ValueError(translate("Value length > max_length")); + } + + self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); + + // Do GATT operations only if this descriptor has been registered. + if (self->handle != BLE_GATT_HANDLE_INVALID) { + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->characteristic->service->device); + if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { + // false means WRITE_REQ, not write-no-response + common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, false); + } else { + common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); + } + } + +} diff --git a/ports/nrf/common-hal/_bleio/Descriptor.h b/ports/nrf/common-hal/_bleio/Descriptor.h new file mode 100644 index 000000000..3adb0df18 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Descriptor.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H + +#include "py/obj.h" + +#include "common-hal/_bleio/Characteristic.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct { + mp_obj_base_t base; + // Will be MP_OBJ_NULL before being assigned to a Characteristic. + bleio_characteristic_obj_t *characteristic; + bleio_uuid_obj_t *uuid; + mp_obj_t value; + uint16_t max_length; + bool fixed_length; + uint16_t handle; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; +} bleio_descriptor_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H diff --git a/ports/nrf/common-hal/_bleio/Peripheral.c b/ports/nrf/common-hal/_bleio/Peripheral.c new file mode 100644 index 000000000..9b0f96d48 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Peripheral.c @@ -0,0 +1,361 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 +#include + +#include "ble.h" +#include "ble_drv.h" +#include "ble_hci.h" +#include "nrf_soc.h" +#include "py/gc.h" +#include "py/objlist.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Peripheral.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" + +#define BLE_ADV_LENGTH_FIELD_SIZE 1 +#define BLE_ADV_AD_TYPE_FIELD_SIZE 1 +#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1 + +static const ble_gap_sec_params_t pairing_sec_params = { + .bond = 1, + .mitm = 0, + .lesc = 0, + .keypress = 0, + .oob = 0, + .io_caps = BLE_GAP_IO_CAPS_NONE, + .min_key_size = 7, + .max_key_size = 16, + .kdist_own = { .enc = 1, .id = 1}, + .kdist_peer = { .enc = 1, .id = 1}, +}; + +STATIC void check_data_fit(size_t data_len) { + if (data_len > BLE_GAP_ADV_SET_DATA_SIZE_MAX) { + mp_raise_ValueError(translate("Data too large for advertisement packet")); + } +} + +STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { + bleio_peripheral_obj_t *self = (bleio_peripheral_obj_t*)self_in; + + // For debugging. + // mp_printf(&mp_plat_print, "Peripheral event: 0x%04x\n", ble_evt->header.evt_id); + + switch (ble_evt->header.evt_id) { + case BLE_GAP_EVT_CONNECTED: { + // Central has connected. + ble_gap_evt_connected_t* connected = &ble_evt->evt.gap_evt.params.connected; + + self->conn_handle = ble_evt->evt.gap_evt.conn_handle; + + // See if connection interval set by Central is out of range. + // If so, negotiate our preferred range. + ble_gap_conn_params_t conn_params; + sd_ble_gap_ppcp_get(&conn_params); + if (conn_params.min_conn_interval < connected->conn_params.min_conn_interval || + conn_params.min_conn_interval > connected->conn_params.max_conn_interval) { + sd_ble_gap_conn_param_update(ble_evt->evt.gap_evt.conn_handle, &conn_params); + } + break; + } + + case BLE_GAP_EVT_DISCONNECTED: + // Central has disconnected. + self->conn_handle = BLE_CONN_HANDLE_INVALID; + break; + + case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { + ble_gap_phys_t const phys = { + .rx_phys = BLE_GAP_PHY_AUTO, + .tx_phys = BLE_GAP_PHY_AUTO, + }; + sd_ble_gap_phy_update(ble_evt->evt.gap_evt.conn_handle, &phys); + break; + } + + case BLE_GAP_EVT_ADV_SET_TERMINATED: + // TODO: Someday may handle timeouts or limit reached. + break; + + case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: + // SoftDevice will respond to a length update request. + sd_ble_gap_data_length_update(self->conn_handle, NULL, NULL); + break; + + case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: { + // We only handle MTU of size BLE_GATT_ATT_MTU_DEFAULT. + sd_ble_gatts_exchange_mtu_reply(self->conn_handle, BLE_GATT_ATT_MTU_DEFAULT); + break; + } + + case BLE_GATTS_EVT_SYS_ATTR_MISSING: + sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); + break; + + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { + ble_gap_sec_keyset_t keyset = { + .keys_own = { + .p_enc_key = &self->bonding_keys.own_enc, + .p_id_key = NULL, + .p_sign_key = NULL, + .p_pk = NULL + }, + + .keys_peer = { + .p_enc_key = &self->bonding_keys.peer_enc, + .p_id_key = &self->bonding_keys.peer_id, + .p_sign_key = NULL, + .p_pk = NULL + } + }; + + sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, + &pairing_sec_params, &keyset); + break; + } + + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: + // TODO for LESC pairing: + // sd_ble_gap_lesc_dhkey_reply(...); + break; + + case BLE_GAP_EVT_AUTH_STATUS: { + // Pairing process completed + ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status; + if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { + // TODO _ediv = bonding_keys->own_enc.master_id.ediv; + self->pair_status = PAIR_PAIRED; + } else { + self->pair_status = PAIR_NOT_PAIRED; + } + break; + } + + case BLE_GAP_EVT_SEC_INFO_REQUEST: { + // Peer asks for the stored keys. + // - load key and return if bonded previously. + // - Else return NULL --> Initiate key exchange + ble_gap_evt_sec_info_request_t* sec_info_request = &ble_evt->evt.gap_evt.params.sec_info_request; + (void) sec_info_request; + //if ( bond_load_keys(_role, sec_req->master_id.ediv, &bkeys) ) { + //sd_ble_gap_sec_info_reply(_conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); + // + //_ediv = bkeys.own_enc.master_id.ediv; + // } else { + sd_ble_gap_sec_info_reply(self->conn_handle, NULL, NULL, NULL); + // } + break; + } + + case BLE_GAP_EVT_CONN_SEC_UPDATE: { + ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec; + if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) { + // Security setup did not succeed: + // mode 0, level 0 means no access + // mode 1, level 1 means open link + // mode >=1 and/or level >=1 means encryption is set up + self->pair_status = PAIR_NOT_PAIRED; + } else { + //if ( !bond_load_cccd(_role, _conn_hdl, _ediv) ) { + if (true) { // TODO: no bonding yet + // Initialize system attributes fresh. + sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); + } + // Not quite paired yet: wait for BLE_GAP_EVT_AUTH_STATUS SUCCESS. + self->ediv = self->bonding_keys.own_enc.master_id.ediv; + } + break; + } + + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled peripheral event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + +void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_t name) { + common_hal_bleio_adapter_set_enabled(true); + + self->service_list = mp_obj_new_list(0, NULL); + // Used only for discovery when acting as a client. + self->remote_service_list = mp_obj_new_list(0, NULL); + self->name = name; + + self->conn_handle = BLE_CONN_HANDLE_INVALID; + self->adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; + self->pair_status = PAIR_NOT_PAIRED; + + memset(&self->bonding_keys, 0, sizeof(self->bonding_keys)); +} + +void common_hal_bleio_peripheral_add_service(bleio_peripheral_obj_t *self, bleio_service_obj_t *service) { + ble_uuid_t uuid; + bleio_uuid_convert_to_nrf_ble_uuid(service->uuid, &uuid); + + uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY; + if (common_hal_bleio_service_get_is_secondary(service)) { + service_type = BLE_GATTS_SRVC_TYPE_SECONDARY; + } + + const uint32_t err_code = sd_ble_gatts_service_add(service_type, &uuid, &service->handle); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to add service, err 0x%04x"), err_code); + } + + mp_obj_list_append(self->service_list, MP_OBJ_FROM_PTR(service)); +} + +mp_obj_list_t *common_hal_bleio_peripheral_get_services(bleio_peripheral_obj_t *self) { + return self->service_list; +} + +bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self) { + return self->conn_handle != BLE_CONN_HANDLE_INVALID; +} + +mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *self) { + return self->name; +} + +void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *self, bool connectable, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo) { + + // interval value has already been validated. + + if (connectable) { + ble_drv_add_event_handler(peripheral_on_ble_evt, self); + } + + common_hal_bleio_adapter_set_enabled(true); + + uint32_t err_code; + + GET_STR_DATA_LEN(self->name, name_data, name_len); + if (name_len > 0) { + // Set device name, and make it available to anyone. + ble_gap_conn_sec_mode_t sec_mode; + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + err_code = sd_ble_gap_device_name_set(&sec_mode, name_data, name_len); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to set device name, err 0x%04x"), err_code); + + } + } + + check_data_fit(advertising_data_bufinfo->len); + // The advertising data buffers must not move, because the SoftDevice depends on them. + // So make them long-lived. + self->advertising_data = (uint8_t *) gc_alloc(BLE_GAP_ADV_SET_DATA_SIZE_MAX * sizeof(uint8_t), false, true); + memcpy(self->advertising_data, advertising_data_bufinfo->buf, advertising_data_bufinfo->len); + + check_data_fit(scan_response_data_bufinfo->len); + self->scan_response_data = (uint8_t *) gc_alloc(BLE_GAP_ADV_SET_DATA_SIZE_MAX * sizeof(uint8_t), false, true); + memcpy(self->scan_response_data, scan_response_data_bufinfo->buf, scan_response_data_bufinfo->len); + + + ble_gap_adv_params_t adv_params = { + .interval = SEC_TO_UNITS(interval, UNIT_0_625_MS), + .properties.type = connectable ? BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED + : BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED, + .duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED, + .filter_policy = BLE_GAP_ADV_FP_ANY, + .primary_phy = BLE_GAP_PHY_1MBPS, + }; + + common_hal_bleio_peripheral_stop_advertising(self); + + const ble_gap_adv_data_t ble_gap_adv_data = { + .adv_data.p_data = self->advertising_data, + .adv_data.len = advertising_data_bufinfo->len, + .scan_rsp_data.p_data = scan_response_data_bufinfo-> len > 0 ? self->scan_response_data : NULL, + .scan_rsp_data.len = scan_response_data_bufinfo->len, + }; + + err_code = sd_ble_gap_adv_set_configure(&self->adv_handle, &ble_gap_adv_data, &adv_params); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to configure advertising, err 0x%04x"), err_code); + } + + err_code = sd_ble_gap_adv_start(self->adv_handle, BLE_CONN_CFG_TAG_CUSTOM); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to start advertising, err 0x%04x"), err_code); + } +} + +void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *self) { + if (self->adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET) + return; + + const uint32_t err_code = sd_ble_gap_adv_stop(self->adv_handle); + + if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) { + mp_raise_OSError_msg_varg(translate("Failed to stop advertising, err 0x%04x"), err_code); + } +} + +void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *self) { + sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); +} + +mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist) { + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); + // Convert to a tuple and then clear the list so the callee will take ownership. + mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_service_list->len, + self->remote_service_list->items); + mp_obj_list_clear(self->remote_service_list); + return services_tuple; +} + +void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *self) { + self->pair_status = PAIR_WAITING; + + uint32_t err_code = sd_ble_gap_authenticate(self->conn_handle, &pairing_sec_params); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to start pairing, error 0x%04x"), err_code); + } + + while (self->pair_status == PAIR_WAITING) { + RUN_BACKGROUND_TASKS; + } + + if (self->pair_status == PAIR_NOT_PAIRED) { + mp_raise_OSError_msg(translate("Failed to pair")); + } + + +} diff --git a/ports/nrf/common-hal/_bleio/Peripheral.h b/ports/nrf/common-hal/_bleio/Peripheral.h new file mode 100644 index 000000000..a4f62d288 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Peripheral.h @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_PERIPHERAL_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_PERIPHERAL_H + +#include + +#include "ble.h" + +#include "py/obj.h" +#include "py/objlist.h" + +#include "common-hal/_bleio/__init__.h" +#include "shared-module/_bleio/Address.h" + +typedef enum { + PAIR_NOT_PAIRED, + PAIR_WAITING, + PAIR_PAIRED, +} pair_status_t; + +typedef struct { + mp_obj_base_t base; + mp_obj_t name; + volatile uint16_t conn_handle; + // Services provided by this peripheral. + mp_obj_list_t *service_list; + // Remote services discovered when this peripheral is acting as a client. + mp_obj_list_t *remote_service_list; + // The advertising data and scan response buffers are held by us, not by the SD, so we must + // maintain them and not change it. If we need to change the contents during advertising, + // there are tricks to get the SD to notice (see DevZone - TBS). + // EDIV: Encrypted Diversifier: Identifies LTK during legacy pairing. + bonding_keys_t bonding_keys; + uint16_t ediv; + uint8_t* advertising_data; + uint8_t* scan_response_data; + uint8_t adv_handle; + pair_status_t pair_status; +} bleio_peripheral_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_PERIPHERAL_H diff --git a/ports/nrf/common-hal/_bleio/Scanner.c b/ports/nrf/common-hal/_bleio/Scanner.c new file mode 100644 index 000000000..ec73f7eb8 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Scanner.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 + +#include "ble_drv.h" +#include "ble_gap.h" +#include "py/mphal.h" +#include "py/objlist.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/ScanEntry.h" +#include "shared-bindings/_bleio/Scanner.h" +#include "shared-module/_bleio/ScanEntry.h" + +static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; + +static ble_data_t m_scan_buffer = { + m_scan_buffer_data, + BLE_GAP_SCAN_BUFFER_MIN +}; + +STATIC void scanner_on_ble_evt(ble_evt_t *ble_evt, void *scanner_in) { + bleio_scanner_obj_t *scanner = (bleio_scanner_obj_t*)scanner_in; + ble_gap_evt_adv_report_t *report = &ble_evt->evt.gap_evt.params.adv_report; + + if (ble_evt->header.evt_id != BLE_GAP_EVT_ADV_REPORT) { + return; + } + + bleio_scanentry_obj_t *entry = m_new_obj(bleio_scanentry_obj_t); + entry->base.type = &bleio_scanentry_type; + entry->rssi = report->rssi; + + bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t); + address->base.type = &bleio_address_type; + common_hal_bleio_address_construct(MP_OBJ_TO_PTR(address), + report->peer_addr.addr, report->peer_addr.addr_type); + entry->address = address; + + entry->data = mp_obj_new_bytes(report->data.p_data, report->data.len); + + mp_obj_list_append(scanner->scan_entries, MP_OBJ_FROM_PTR(entry)); + + const uint32_t err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to continue scanning, err 0x%04x"), err_code); + } +} + +void common_hal_bleio_scanner_construct(bleio_scanner_obj_t *self) { +} + +mp_obj_t common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_float_t timeout, mp_float_t interval, mp_float_t window) { + common_hal_bleio_adapter_set_enabled(true); + ble_drv_add_event_handler(scanner_on_ble_evt, self); + + ble_gap_scan_params_t scan_params = { + .interval = SEC_TO_UNITS(interval, UNIT_0_625_MS), + .window = SEC_TO_UNITS(window, UNIT_0_625_MS), + .scan_phys = BLE_GAP_PHY_1MBPS, + }; + + self->scan_entries = mp_obj_new_list(0, NULL); + + uint32_t err_code; + err_code = sd_ble_gap_scan_start(&scan_params, &m_scan_buffer); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to start scanning, err 0x%04x"), err_code); + } + + mp_hal_delay_ms(timeout * 1000); + sd_ble_gap_scan_stop(); + + // Return list, and don't hang on to it, so it can be GC'd. + mp_obj_t entries = self->scan_entries; + self->scan_entries = MP_OBJ_NULL; + return entries; +} diff --git a/ports/nrf/common-hal/_bleio/Scanner.h b/ports/nrf/common-hal/_bleio/Scanner.h new file mode 100644 index 000000000..3768a52cb --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Scanner.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SCANNER_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SCANNER_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t scan_entries; + uint16_t interval; + uint16_t window; +} bleio_scanner_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SCANNER_H diff --git a/ports/nrf/common-hal/_bleio/Service.c b/ports/nrf/common-hal/_bleio/Service.c new file mode 100644 index 000000000..650cdc4ec --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Service.c @@ -0,0 +1,122 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 "ble_drv.h" +#include "ble.h" +#include "py/runtime.h" +#include "common-hal/_bleio/__init__.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Peripheral.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/Adapter.h" + +void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_peripheral_obj_t *peripheral, bleio_uuid_obj_t *uuid, bool is_secondary) { + self->device = MP_OBJ_FROM_PTR(peripheral); + self->handle = 0xFFFF; + self->uuid = uuid; + self->characteristic_list = mp_obj_new_list(0, NULL); + self->is_remote = false; + self->is_secondary = is_secondary; +} + +bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { + return self->uuid; +} + +mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self) { + return self->characteristic_list; +} + +bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { + return self->is_remote; +} + +bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { + return self->is_secondary; +} + +void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic) { + ble_gatts_char_md_t char_md = { + .char_props.broadcast = (characteristic->props & CHAR_PROP_BROADCAST) ? 1 : 0, + .char_props.read = (characteristic->props & CHAR_PROP_READ) ? 1 : 0, + .char_props.write_wo_resp = (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) ? 1 : 0, + .char_props.write = (characteristic->props & CHAR_PROP_WRITE) ? 1 : 0, + .char_props.notify = (characteristic->props & CHAR_PROP_NOTIFY) ? 1 : 0, + .char_props.indicate = (characteristic->props & CHAR_PROP_INDICATE) ? 1 : 0, + }; + + ble_gatts_attr_md_t cccd_md = { + .vloc = BLE_GATTS_VLOC_STACK, + }; + + ble_uuid_t char_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &char_uuid); + + ble_gatts_attr_md_t char_attr_md = { + .vloc = BLE_GATTS_VLOC_STACK, + .vlen = !characteristic->fixed_length, + }; + + if (char_md.char_props.notify || char_md.char_props.indicate) { + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); + // Make CCCD write permission match characteristic read permission. + bleio_attribute_gatts_set_security_mode(&cccd_md.write_perm, characteristic->read_perm); + + char_md.p_cccd_md = &cccd_md; + } + + bleio_attribute_gatts_set_security_mode(&char_attr_md.read_perm, characteristic->read_perm); + bleio_attribute_gatts_set_security_mode(&char_attr_md.write_perm, characteristic->write_perm); + + mp_buffer_info_t char_value_bufinfo; + mp_get_buffer_raise(characteristic->value, &char_value_bufinfo, MP_BUFFER_READ); + + ble_gatts_attr_t char_attr = { + .p_uuid = &char_uuid, + .p_attr_md = &char_attr_md, + .init_len = char_value_bufinfo.len, + .p_value = char_value_bufinfo.buf, + .init_offs = 0, + .max_len = characteristic->max_length, + }; + + ble_gatts_char_handles_t char_handles; + + uint32_t err_code; + err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &char_attr, &char_handles); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to add characteristic, err 0x%04x"), err_code); + } + + characteristic->user_desc_handle = char_handles.user_desc_handle; + characteristic->cccd_handle = char_handles.cccd_handle; + characteristic->sccd_handle = char_handles.sccd_handle; + characteristic->handle = char_handles.value_handle; + + mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); +} diff --git a/ports/nrf/common-hal/_bleio/Service.h b/ports/nrf/common-hal/_bleio/Service.h new file mode 100644 index 000000000..a4614b9f5 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/Service.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SERVICE_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SERVICE_H + +#include "py/objlist.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct { + mp_obj_base_t base; + // Handle for this service. + uint16_t handle; + // True if created during discovery. + bool is_remote; + bool is_secondary; + bleio_uuid_obj_t *uuid; + // May be a Peripheral, Central, etc. + mp_obj_t device; + mp_obj_list_t *characteristic_list; + // Range of attribute handles of this service. + uint16_t start_handle; + uint16_t end_handle; +} bleio_service_obj_t; + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SERVICE_H diff --git a/ports/nrf/common-hal/_bleio/UUID.c b/ports/nrf/common-hal/_bleio/UUID.c new file mode 100644 index 000000000..0e65b7d58 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/UUID.c @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 + +#include "py/runtime.h" +#include "common-hal/_bleio/UUID.h" +#include "shared-bindings/_bleio/Adapter.h" + +#include "ble.h" +#include "ble_drv.h" +#include "nrf_error.h" + +// If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. +// If uuid128 is not NULL, it's a 128-bit (16-byte) UUID, with bytes 12 and 13 zero'd out, where +// the 16-bit part goes. Those 16 bits are passed in uuid16. +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, uint32_t uuid16, uint8_t uuid128[]) { + common_hal_bleio_adapter_set_enabled(true); + + self->nrf_ble_uuid.uuid = uuid16; + if (uuid128 == NULL) { + self->nrf_ble_uuid.type = BLE_UUID_TYPE_BLE; + } else { + ble_uuid128_t vs_uuid; + memcpy(vs_uuid.uuid128, uuid128, sizeof(vs_uuid.uuid128)); + + // Register this vendor-specific UUID. Bytes 12 and 13 will be zero. + const uint32_t err_code = sd_ble_uuid_vs_add(&vs_uuid, &self->nrf_ble_uuid.type); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to register Vendor-Specific UUID, err 0x%04x"), err_code); + } + } +} + +uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self) { + return self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE ? 16 : 128; +} + +uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { + return self->nrf_ble_uuid.uuid; +} + +// True if uuid128 has been successfully filled in. +bool common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]) { + uint8_t length; + const uint32_t err_code = sd_ble_uuid_encode(&self->nrf_ble_uuid, &length, uuid128); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Could not decode ble_uuid, err 0x%04x"), err_code); + } + // If not 16 bytes, this is not a 128-bit UUID, so return. + return length == 16; +} + +// Returns 0 if this is a 16-bit UUID, otherwise returns a non-zero index +// into the 128-bit uuid registration table. +uint32_t common_hal_bleio_uuid_get_uuid128_reference(bleio_uuid_obj_t *self) { + return self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE ? 0 : self->nrf_ble_uuid.type; +} + + +void bleio_uuid_construct_from_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_ble_uuid) { + if (nrf_ble_uuid->type == BLE_UUID_TYPE_UNKNOWN) { + mp_raise_RuntimeError(translate("Unexpected nrfx uuid type")); + } + self->nrf_ble_uuid.uuid = nrf_ble_uuid->uuid; + self->nrf_ble_uuid.type = nrf_ble_uuid->type; +} + +// Fill in a ble_uuid_t from my values. +void bleio_uuid_convert_to_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_ble_uuid) { + nrf_ble_uuid->uuid = self->nrf_ble_uuid.uuid; + nrf_ble_uuid->type = self->nrf_ble_uuid.type; +} diff --git a/ports/nrf/common-hal/_bleio/UUID.h b/ports/nrf/common-hal/_bleio/UUID.h new file mode 100644 index 000000000..7d3a6204e --- /dev/null +++ b/ports/nrf/common-hal/_bleio/UUID.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_UUID_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_UUID_H + +#include "py/obj.h" + +#include "ble.h" + +typedef struct { + mp_obj_base_t base; + // Use the native way of storing UUID's: + // - ble_uuid_t.uuid is a 16-bit uuid. + // - ble_uuid_t.type is BLE_UUID_TYPE_BLE if it's a 16-bit Bluetooth SIG UUID. + // or is BLE_UUID_TYPE_VENDOR_BEGIN and higher, which indexes into a table of registered + // 128-bit UUIDs. + ble_uuid_t nrf_ble_uuid; +} bleio_uuid_obj_t; + +void bleio_uuid_construct_from_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_uuid); +void bleio_uuid_convert_to_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_uuid); + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_UUID_H diff --git a/ports/nrf/common-hal/_bleio/__init__.c b/ports/nrf/common-hal/_bleio/__init__.c new file mode 100644 index 000000000..553044190 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/__init__.c @@ -0,0 +1,502 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Central.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Peripheral.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" + +#include "common-hal/_bleio/__init__.h" + +static volatile bool m_discovery_in_process; +static volatile bool m_discovery_successful; + +static bleio_service_obj_t *m_char_discovery_service; +static bleio_characteristic_obj_t *m_desc_discovery_characteristic; + +// Turn off BLE on a reset or reload. +void bleio_reset() { + if (common_hal_bleio_adapter_get_enabled()) { + common_hal_bleio_adapter_set_enabled(false); + } +} + +// The singleton _bleio.Adapter object, bound to _bleio.adapter +// It currently only has properties and no state +const super_adapter_obj_t common_hal_bleio_adapter_obj = { + .base = { + .type = &bleio_adapter_type, + }, +}; + +void common_hal_bleio_check_connected(uint16_t conn_handle) { + if (conn_handle == BLE_CONN_HANDLE_INVALID) { + mp_raise_OSError_msg(translate("Not connected")); + } +} + +uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { + if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { + return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; + } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { + return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; + } else { + return BLE_CONN_HANDLE_INVALID; + } +} + +mp_obj_list_t *common_hal_bleio_device_get_remote_service_list(mp_obj_t device) { + if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { + return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->remote_service_list; + } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { + return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->remote_service_list; + } else { + return NULL; + } +} + +// service_uuid may be NULL, to discover all services. +STATIC bool discover_next_services(mp_obj_t device, uint16_t start_handle, ble_uuid_t *service_uuid) { + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_primary_services_discover(conn_handle, start_handle, service_uuid); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg(translate("Failed to discover services")); + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC bool discover_next_characteristics(mp_obj_t device, bleio_service_obj_t *service, uint16_t start_handle) { + m_char_discovery_service = service; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = service->end_handle; + + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); + if (err_code != NRF_SUCCESS) { + return false; + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC bool discover_next_descriptors(mp_obj_t device, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { + m_desc_discovery_characteristic = characteristic; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = end_handle; + + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_descriptors_discover(conn_handle, &handle_range); + if (err_code != NRF_SUCCESS) { + return false; + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_service_t *gattc_service = &response->services[i]; + + bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); + service->base.type = &bleio_service_type; + + // Initialize several fields at once. + common_hal_bleio_service_construct(service, device, NULL, false); + + service->is_remote = true; + service->start_handle = gattc_service->handle_range.start_handle; + service->end_handle = gattc_service->handle_range.end_handle; + service->handle = gattc_service->handle_range.start_handle; + + if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known service UUID. + bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); + service->uuid = uuid; + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just set the UUID to NULL. + service->uuid = NULL; + } + + mp_obj_list_append(common_hal_bleio_device_get_remote_service_list(device), service); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_char_t *gattc_char = &response->chars[i]; + + bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); + characteristic->base.type = &bleio_characteristic_type; + + bleio_uuid_obj_t *uuid = NULL; + + if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known characteristic UUID. + uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just leave the UUID as NULL. + } + + bleio_characteristic_properties_t props = + (gattc_char->char_props.broadcast ? CHAR_PROP_BROADCAST : 0) | + (gattc_char->char_props.indicate ? CHAR_PROP_INDICATE : 0) | + (gattc_char->char_props.notify ? CHAR_PROP_NOTIFY : 0) | + (gattc_char->char_props.read ? CHAR_PROP_READ : 0) | + (gattc_char->char_props.write ? CHAR_PROP_WRITE : 0) | + (gattc_char->char_props.write_wo_resp ? CHAR_PROP_WRITE_NO_RESPONSE : 0); + + // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. + common_hal_bleio_characteristic_construct( + characteristic, m_char_discovery_service, uuid, props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, + GATT_MAX_DATA_LENGTH, false, // max_length, fixed_length: values may not matter for gattc + mp_obj_new_list(0, NULL)); + characteristic->handle = gattc_char->handle_value; + + mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_desc_t *gattc_desc = &response->descs[i]; + + // Remember handles for certain well-known descriptors. + switch (gattc_desc->uuid.uuid) { + case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: + m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; + break; + + case BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG: + m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; + break; + + case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: + m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; + break; + + default: + // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, + // so ignore those. + // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors + break; + } + + bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); + descriptor->base.type = &bleio_descriptor_type; + + bleio_uuid_obj_t *uuid = NULL; + + if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known descriptor UUID. + uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just leave the UUID as NULL. + } + + common_hal_bleio_descriptor_construct( + descriptor, m_desc_discovery_characteristic, uuid, + SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, + GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); + descriptor->handle = gattc_desc->handle; + + mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t device) { + switch (ble_evt->header.evt_id) { + case BLE_GAP_EVT_DISCONNECTED: + m_discovery_successful = false; + m_discovery_in_process = false; + break; + + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, device); + break; + + case BLE_GATTC_EVT_CHAR_DISC_RSP: + on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, device); + break; + + case BLE_GATTC_EVT_DESC_DISC_RSP: + on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, device); + break; + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + + +void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { + mp_obj_list_t *remote_services_list = common_hal_bleio_device_get_remote_service_list(device); + + ble_drv_add_event_handler(discovery_on_ble_evt, device); + + // Start over with an empty list. + mp_obj_list_clear(MP_OBJ_FROM_PTR(common_hal_bleio_device_get_remote_service_list(device))); + + if (service_uuids_whitelist == mp_const_none) { + // List of service UUID's not given, so discover all available services. + + uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; + + while (discover_next_services(device, next_service_start_handle, MP_OBJ_NULL)) { + // discover_next_services() appends to remote_services_list. + + // Get the most recently discovered service, and then ask for services + // whose handles start after the last attribute handle inside that service. + const bleio_service_obj_t *service = + MP_OBJ_TO_PTR(remote_services_list->items[remote_services_list->len - 1]); + next_service_start_handle = service->end_handle + 1; + } + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); + mp_obj_t uuid_obj; + while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + mp_raise_ValueError(translate("non-UUID found in service_uuids_whitelist")); + } + bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); + + ble_uuid_t nrf_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); + + // Service might or might not be discovered; that's ok. Caller has to check + // Central.remote_services to find out. + // We only need to call this once for each service to discover. + discover_next_services(device, BLE_GATT_HANDLE_START, &nrf_uuid); + } + } + + + for (size_t service_idx = 0; service_idx < remote_services_list->len; ++service_idx) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(remote_services_list->items[service_idx]); + + // Skip the service if it had an unknown (unregistered) UUID. + if (service->uuid == NULL) { + continue; + } + + uint16_t next_char_start_handle = service->start_handle; + + // Stop when we go past the end of the range of handles for this service or + // discovery call returns nothing. + // discover_next_characteristics() appends to the characteristic_list. + while (next_char_start_handle <= service->end_handle && + discover_next_characteristics(device, service, next_char_start_handle)) { + + + // Get the most recently discovered characteristic, and then ask for characteristics + // whose handles start after the last attribute handle inside that characteristic. + const bleio_characteristic_obj_t *characteristic = + MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); + next_char_start_handle = characteristic->handle + 1; + } + + // Got characteristics for this service. Now discover descriptors for each characteristic. + size_t char_list_len = service->characteristic_list->len; + for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { + bleio_characteristic_obj_t *characteristic = + MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); + const bool last_characteristic = char_idx == char_list_len - 1; + bleio_characteristic_obj_t *next_characteristic = last_characteristic + ? NULL + : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); + + // Skip the characteristic if it had an unknown (unregistered) UUID. + if (characteristic->uuid == NULL) { + continue; + } + + uint16_t next_desc_start_handle = characteristic->handle + 1; + + // Don't run past the end of this service or the beginning of the next characteristic. + uint16_t next_desc_end_handle = next_characteristic == NULL + ? service->end_handle + : next_characteristic->handle - 1; + + // Stop when we go past the end of the range of handles for this service or + // discovery call returns nothing. + // discover_next_descriptors() appends to the descriptor_list. + while (next_desc_start_handle <= service->end_handle && + next_desc_start_handle < next_desc_end_handle && + discover_next_descriptors(device, characteristic, + next_desc_start_handle, next_desc_end_handle)) { + + // Get the most recently discovered descriptor, and then ask for descriptors + // whose handles start after that descriptor's handle. + const bleio_descriptor_obj_t *descriptor = + MP_OBJ_TO_PTR(characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]); + next_desc_start_handle = descriptor->handle + 1; + } + } + } + + // This event handler is no longer needed. + ble_drv_remove_event_handler(discovery_on_ble_evt, device); + +} + +// GATTS read of a Characteristic or Descriptor. +mp_obj_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle) { + // conn_handle might be BLE_CONN_HANDLE_INVALID if we're not connected, but that's OK, because + // we can still read and write the local value. + + mp_buffer_info_t bufinfo; + ble_gatts_value_t gatts_value = { + .p_value = NULL, + .len = 0, + }; + + // Read once to find out what size buffer we need, then read again to fill buffer. + + mp_obj_t value = mp_const_none; + uint32_t err_code = sd_ble_gatts_value_get(conn_handle, handle, &gatts_value); + if (err_code == NRF_SUCCESS) { + value = mp_obj_new_bytearray_of_zeros(gatts_value.len); + mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_WRITE); + gatts_value.p_value = bufinfo.buf; + + // Read again, with the correct size of buffer. + err_code = sd_ble_gatts_value_get(conn_handle, handle, &gatts_value); + } + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to read gatts value, err 0x%04x"), err_code); + } + + return value; +} + +void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { + // conn_handle might be BLE_CONN_HANDLE_INVALID if we're not connected, but that's OK, because + // we can still read and write the local value. + + ble_gatts_value_t gatts_value = { + .p_value = bufinfo->buf, + .len = bufinfo->len, + }; + + const uint32_t err_code = sd_ble_gatts_value_set(conn_handle, handle, &gatts_value); + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg_varg(translate("Failed to write gatts value, err 0x%04x"), err_code); + } +} + +void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { + common_hal_bleio_check_connected(conn_handle); + + ble_gattc_write_params_t write_params = { + .write_op = write_no_response ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, + .handle = handle, + .p_value = bufinfo->buf, + .len = bufinfo->len, + }; + + while (1) { + uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); + if (err_code == NRF_SUCCESS) { + break; + } + + // Write with response will return NRF_ERROR_BUSY if the response has not been received. + // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. + if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { + // We could wait for an event indicating the write is complete, but just retrying is easier. + MICROPY_VM_HOOK_LOOP; + continue; + } + + // Some real error occurred. + mp_raise_OSError_msg_varg(translate("Failed to write attribute value, err 0x%04x"), err_code); + } + +} diff --git a/ports/nrf/common-hal/_bleio/__init__.h b/ports/nrf/common-hal/_bleio/__init__.h new file mode 100644 index 000000000..cf1a06945 --- /dev/null +++ b/ports/nrf/common-hal/_bleio/__init__.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H + +void bleio_reset(void); + +typedef struct { + ble_gap_enc_key_t own_enc; + ble_gap_enc_key_t peer_enc; + ble_gap_id_key_t peer_id; +} bonding_keys_t; + +// We assume variable length data. +// 20 bytes max (23 - 3). +#define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H diff --git a/ports/nrf/common-hal/bleio/Adapter.c b/ports/nrf/common-hal/bleio/Adapter.c deleted file mode 100644 index 74bee9e56..000000000 --- a/ports/nrf/common-hal/bleio/Adapter.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2016 Glenn Ruben Bakke - * Copyright (c) 2018 Artur Pacholec - * - * 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 -#include - -#include "ble.h" -#include "ble_drv.h" -#include "nrfx_power.h" -#include "nrf_nvic.h" -#include "nrf_sdm.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "supervisor/usb.h" -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Address.h" - -#define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) -#define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) -#define BLE_SLAVE_LATENCY 0 -#define BLE_CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) - -STATIC void softdevice_assert_handler(uint32_t id, uint32_t pc, uint32_t info) { - mp_raise_msg_varg(&mp_type_AssertionError, - translate("Soft device assert, id: 0x%08lX, pc: 0x%08lX"), id, pc); -} - -STATIC uint32_t ble_stack_enable(void) { - nrf_clock_lf_cfg_t clock_config = { -#if BOARD_HAS_32KHZ_XTAL - .source = NRF_CLOCK_LF_SRC_XTAL, - .rc_ctiv = 0, - .rc_temp_ctiv = 0, - .accuracy = NRF_CLOCK_LF_ACCURACY_20_PPM, -#else - .source = NRF_CLOCK_LF_SRC_RC, - .rc_ctiv = 16, - .rc_temp_ctiv = 2, - .accuracy = NRF_CLOCK_LF_ACCURACY_250_PPM, -#endif - }; - - uint32_t err_code = sd_softdevice_enable(&clock_config, softdevice_assert_handler); - if (err_code != NRF_SUCCESS) { - return err_code; - } - - err_code = sd_nvic_EnableIRQ(SD_EVT_IRQn); - if (err_code != NRF_SUCCESS) { - return err_code; - } - - // Start with no event handlers, etc. - ble_drv_reset(); - - uint32_t app_ram_start; - app_ram_start = 0x20004000; - - ble_cfg_t ble_conf; - ble_conf.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_TAG_CUSTOM; - ble_conf.conn_cfg.params.gap_conn_cfg.conn_count = BLE_GAP_CONN_COUNT_DEFAULT; - ble_conf.conn_cfg.params.gap_conn_cfg.event_length = BLE_GAP_EVENT_LENGTH_DEFAULT; - err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_conf, app_ram_start); - if (err_code != NRF_SUCCESS) - return err_code; - - memset(&ble_conf, 0, sizeof(ble_conf)); - ble_conf.gap_cfg.role_count_cfg.periph_role_count = 1; - ble_conf.gap_cfg.role_count_cfg.central_role_count = 1; - err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_conf, app_ram_start); - if (err_code != NRF_SUCCESS) - return err_code; - - memset(&ble_conf, 0, sizeof(ble_conf)); - ble_conf.conn_cfg.conn_cfg_tag = BLE_CONN_CFG_TAG_CUSTOM; - ble_conf.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = MAX_TX_IN_PROGRESS; - err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATTS, &ble_conf, app_ram_start); - if (err_code != NRF_SUCCESS) - return err_code; - - err_code = sd_ble_enable(&app_ram_start); - if (err_code != NRF_SUCCESS) - return err_code; - - ble_gap_conn_params_t gap_conn_params = { - .min_conn_interval = BLE_MIN_CONN_INTERVAL, - .max_conn_interval = BLE_MAX_CONN_INTERVAL, - .slave_latency = BLE_SLAVE_LATENCY, - .conn_sup_timeout = BLE_CONN_SUP_TIMEOUT, - }; - err_code = sd_ble_gap_ppcp_set(&gap_conn_params); - if (err_code != NRF_SUCCESS) { - return err_code; - } - - err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_UNKNOWN); - return err_code; -} - -void common_hal_bleio_adapter_set_enabled(bool enabled) { - const bool is_enabled = common_hal_bleio_adapter_get_enabled(); - - // Don't enable or disable twice - if ((is_enabled && enabled) || (!is_enabled && !enabled)) { - return; - } - - uint32_t err_code; - if (enabled) { - // The SD takes over the POWER module and will fail if the module is already in use. - // Occurs when USB is initialized previously - nrfx_power_uninit(); - - err_code = ble_stack_enable(); - - // Re-init USB hardware - init_usb_hardware(); - } else { - err_code = sd_softdevice_disable(); - - // Re-init USB hardware - init_usb_hardware(); - } - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg(translate("Failed to change softdevice state")); - } -} - -bool common_hal_bleio_adapter_get_enabled(void) { - uint8_t is_enabled; - - const uint32_t err_code = sd_softdevice_is_enabled(&is_enabled); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg(translate("Failed to get softdevice state")); - } - - return is_enabled; -} - -void get_address(ble_gap_addr_t *address) { - uint32_t err_code; - - common_hal_bleio_adapter_set_enabled(true); - err_code = sd_ble_gap_addr_get(address); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg(translate("Failed to get local address")); - } -} - -bleio_address_obj_t *common_hal_bleio_adapter_get_address(void) { - common_hal_bleio_adapter_set_enabled(true); - - ble_gap_addr_t local_address; - get_address(&local_address); - - bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t); - address->base.type = &bleio_address_type; - - common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type); - return address; -} - -mp_obj_t common_hal_bleio_adapter_get_default_name(void) { - common_hal_bleio_adapter_set_enabled(true); - - ble_gap_addr_t local_address; - get_address(&local_address); - - char name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0 }; - - name[sizeof(name) - 4] = nibble_to_hex_lower[local_address.addr[1] >> 4 & 0xf]; - name[sizeof(name) - 3] = nibble_to_hex_lower[local_address.addr[1] & 0xf]; - name[sizeof(name) - 2] = nibble_to_hex_lower[local_address.addr[0] >> 4 & 0xf]; - name[sizeof(name) - 1] = nibble_to_hex_lower[local_address.addr[0] & 0xf]; - - return mp_obj_new_str(name, sizeof(name)); -} diff --git a/ports/nrf/common-hal/bleio/Adapter.h b/ports/nrf/common-hal/bleio/Adapter.h deleted file mode 100644 index 5dcc62540..000000000 --- a/ports/nrf/common-hal/bleio/Adapter.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ADAPTER_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ADAPTER_H - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; -} super_adapter_obj_t; - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ADAPTER_H diff --git a/ports/nrf/common-hal/bleio/Attribute.c b/ports/nrf/common-hal/bleio/Attribute.c deleted file mode 100644 index fd1e7538d..000000000 --- a/ports/nrf/common-hal/bleio/Attribute.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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 "shared-bindings/bleio/Attribute.h" - -// Convert a bleio security mode to a ble_gap_conn_sec_mode_t setting. -void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { - switch (security_mode) { - case SECURITY_MODE_NO_ACCESS: - BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); - break; - - case SECURITY_MODE_OPEN: - BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); - break; - - case SECURITY_MODE_ENC_NO_MITM: - BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); - break; - - case SECURITY_MODE_ENC_WITH_MITM: - BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); - break; - - case SECURITY_MODE_LESC_ENC_WITH_MITM: - BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); - break; - - case SECURITY_MODE_SIGNED_NO_MITM: - BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); - break; - - case SECURITY_MODE_SIGNED_WITH_MITM: - BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); - break; - } -} diff --git a/ports/nrf/common-hal/bleio/Attribute.h b/ports/nrf/common-hal/bleio/Attribute.h deleted file mode 100644 index cf84f01dc..000000000 --- a/ports/nrf/common-hal/bleio/Attribute.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H - -#include "shared-module/bleio/Attribute.h" - -extern void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode); - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H diff --git a/ports/nrf/common-hal/bleio/Central.c b/ports/nrf/common-hal/bleio/Central.c deleted file mode 100644 index 0f8432b73..000000000 --- a/ports/nrf/common-hal/bleio/Central.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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 -#include - -#include "ble.h" -#include "ble_drv.h" -#include "ble_hci.h" -#include "nrf_soc.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Central.h" - -STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { - bleio_central_obj_t *central = (bleio_central_obj_t*)central_in; - - switch (ble_evt->header.evt_id) { - case BLE_GAP_EVT_CONNECTED: - central->conn_handle = ble_evt->evt.gap_evt.conn_handle; - central->waiting_to_connect = false; - break; - - case BLE_GAP_EVT_TIMEOUT: - // Handle will be invalid. - central->waiting_to_connect = false; - break; - - case BLE_GAP_EVT_DISCONNECTED: - central->conn_handle = BLE_CONN_HANDLE_INVALID; - break; - - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: - sd_ble_gap_sec_params_reply(central->conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL); - break; - - case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { - ble_gap_evt_conn_param_update_request_t *request = - &ble_evt->evt.gap_evt.params.conn_param_update_request; - sd_ble_gap_conn_param_update(central->conn_handle, &request->conn_params); - break; - } - default: - // For debugging. - // mp_printf(&mp_plat_print, "Unhandled central event: 0x%04x\n", ble_evt->header.evt_id); - break; - } -} - -void common_hal_bleio_central_construct(bleio_central_obj_t *self) { - common_hal_bleio_adapter_set_enabled(true); - - self->remote_service_list = mp_obj_new_list(0, NULL); - self->conn_handle = BLE_CONN_HANDLE_INVALID; -} - -void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { - common_hal_bleio_adapter_set_enabled(true); - ble_drv_add_event_handler(central_on_ble_evt, self); - - ble_gap_addr_t addr; - - addr.addr_type = address->type; - mp_buffer_info_t address_buf_info; - mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); - memcpy(addr.addr, (uint8_t *) address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); - - ble_gap_scan_params_t scan_params = { - .interval = MSEC_TO_UNITS(100, UNIT_0_625_MS), - .window = MSEC_TO_UNITS(100, UNIT_0_625_MS), - .scan_phys = BLE_GAP_PHY_1MBPS, - // timeout of 0 means no timeout - .timeout = SEC_TO_UNITS(timeout, UNIT_10_MS), - }; - - ble_gap_conn_params_t conn_params = { - .conn_sup_timeout = MSEC_TO_UNITS(4000, UNIT_10_MS), - .min_conn_interval = MSEC_TO_UNITS(15, UNIT_1_25_MS), - .max_conn_interval = MSEC_TO_UNITS(300, UNIT_1_25_MS), - .slave_latency = 0, // number of conn events - }; - - self->waiting_to_connect = true; - - uint32_t err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_CUSTOM); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to start connecting, error 0x%04x"), err_code); - } - - while (self->waiting_to_connect) { - RUN_BACKGROUND_TASKS; - } - - if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { - mp_raise_OSError_msg(translate("Failed to connect: timeout")); - } -} - -void common_hal_bleio_central_disconnect(bleio_central_obj_t *self) { - sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); -} - -bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self) { - return self->conn_handle != BLE_CONN_HANDLE_INVALID; -} - -mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist) { - common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); - // Convert to a tuple and then clear the list so the callee will take ownership. - mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_service_list->len, - self->remote_service_list->items); - mp_obj_list_clear(self->remote_service_list); - return services_tuple; -} - -mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self) { - return self->remote_service_list; -} diff --git a/ports/nrf/common-hal/bleio/Central.h b/ports/nrf/common-hal/bleio/Central.h deleted file mode 100644 index 2e00aa35e..000000000 --- a/ports/nrf/common-hal/bleio/Central.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H -#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H - -#include - -#include "py/objlist.h" -#include "shared-module/bleio/Address.h" - -typedef struct { - mp_obj_base_t base; - volatile bool waiting_to_connect; - volatile uint16_t conn_handle; - // Services discovered after connecting to a remote peripheral. - mp_obj_list_t *remote_service_list; -} bleio_central_obj_t; - -#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c deleted file mode 100644 index 2596f17d8..000000000 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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 "py/runtime.h" - -#include "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/Service.h" - -static volatile bleio_characteristic_obj_t *m_read_characteristic; - -STATIC uint16_t characteristic_get_cccd(uint16_t cccd_handle, uint16_t conn_handle) { - uint16_t cccd; - ble_gatts_value_t value = { - .p_value = (uint8_t*) &cccd, - .len = 2, - }; - - const uint32_t err_code = sd_ble_gatts_value_get(conn_handle, cccd_handle, &value); - - if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING) { - // CCCD is not set, so say that neither Notify nor Indicate is enabled. - cccd = 0; - } else if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to read CCCD value, err 0x%04x"), err_code); - } - - return cccd; -} - -STATIC void characteristic_on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { - switch (ble_evt->header.evt_id) { - - // More events may be handled later, so keep this as a switch. - - case BLE_GATTC_EVT_READ_RSP: { - ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp; - if (m_read_characteristic) { - m_read_characteristic->value = mp_obj_new_bytearray(response->len, response->data); - } - // Indicate to busy-wait loop that we've read the attribute value. - m_read_characteristic = NULL; - break; - } - - default: - // For debugging. - // mp_printf(&mp_plat_print, "Unhandled characteristic event: 0x%04x\n", ble_evt->header.evt_id); - break; - } -} - -STATIC void characteristic_gatts_notify_indicate(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, uint16_t hvx_type) { - uint16_t hvx_len = bufinfo->len; - - ble_gatts_hvx_params_t hvx_params = { - .handle = handle, - .type = hvx_type, - .offset = 0, - .p_len = &hvx_len, - .p_data = bufinfo->buf, - }; - - while (1) { - const uint32_t err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params); - if (err_code == NRF_SUCCESS) { - break; - } - // TX buffer is full - // We could wait for an event indicating the write is complete, but just retrying is easier. - if (err_code == NRF_ERROR_RESOURCES) { - RUN_BACKGROUND_TASKS; - continue; - } - - // Some real error has occurred. - mp_raise_OSError_msg_varg(translate("Failed to notify or indicate attribute value, err 0x%04x"), err_code); - } -} - -STATIC void characteristic_gattc_read(bleio_characteristic_obj_t *characteristic) { - const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device); - common_hal_bleio_check_connected(conn_handle); - - // Set to NULL in event loop after event. - m_read_characteristic = characteristic; - - ble_drv_add_event_handler(characteristic_on_gattc_read_rsp_evt, characteristic); - - const uint32_t err_code = sd_ble_gattc_read(conn_handle, characteristic->handle, 0); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to read attribute value, err 0x%04x"), err_code); - } - - while (m_read_characteristic != NULL) { - RUN_BACKGROUND_TASKS; - } - - ble_drv_remove_event_handler(characteristic_on_gattc_read_rsp_evt, characteristic); -} - -void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) { - self->service = service; - self->uuid = uuid; - self->handle = BLE_GATT_HANDLE_INVALID; - self->props = props; - self->read_perm = read_perm; - self->write_perm = write_perm; - self->descriptor_list = mp_obj_new_list(0, NULL); - - const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; - if (max_length < 0 || max_length > max_length_max) { - mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"), - max_length_max, fixed_length ? "True" : "False"); - } - self->max_length = max_length; - self->fixed_length = fixed_length; - - common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo); -} - -mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self) { - return self->descriptor_list; -} - -bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { - return self->service; -} - -mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self) { - // Do GATT operations only if this characteristic has been added to a registered service. - if (self->handle != BLE_GATT_HANDLE_INVALID) { - uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); - if (common_hal_bleio_service_get_is_remote(self->service)) { - // self->value is set by evt handler. - characteristic_gattc_read(self); - } else { - self->value = common_hal_bleio_gatts_read(self->handle, conn_handle); - } - } - - return self->value; -} - -void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { - if (self->fixed_length && bufinfo->len != self->max_length) { - mp_raise_ValueError(translate("Value length != required fixed length")); - } - if (bufinfo->len > self->max_length) { - mp_raise_ValueError(translate("Value length > max_length")); - } - - self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); - - // Do GATT operations only if this characteristic has been added to a registered service. - if (self->handle != BLE_GATT_HANDLE_INVALID) { - uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); - - if (common_hal_bleio_service_get_is_remote(self->service)) { - // Last argument is true if write-no-reponse desired. - common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, - (self->props & CHAR_PROP_WRITE_NO_RESPONSE)); - } else { - - bool sent = false; - uint16_t cccd = 0; - - const bool notify = self->props & CHAR_PROP_NOTIFY; - const bool indicate = self->props & CHAR_PROP_INDICATE; - if (notify | indicate) { - cccd = characteristic_get_cccd(self->cccd_handle, conn_handle); - } - - // It's possible that both notify and indicate are set. - if (notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { - characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_NOTIFICATION); - sent = true; - } - if (indicate && (cccd & BLE_GATT_HVX_INDICATION)) { - characteristic_gatts_notify_indicate(self->handle, conn_handle, bufinfo, BLE_GATT_HVX_INDICATION); - sent = true; - } - - if (!sent) { - common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); - } - } - } -} - -bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self) { - return self->uuid; -} - -bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self) { - return self->props; -} - -void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) { - ble_uuid_t desc_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(descriptor->uuid, &desc_uuid); - - ble_gatts_attr_md_t desc_attr_md = { - // Data passed is not in a permanent location and should be copied. - .vloc = BLE_GATTS_VLOC_STACK, - .vlen = !descriptor->fixed_length, - }; - - bleio_attribute_gatts_set_security_mode(&desc_attr_md.read_perm, descriptor->read_perm); - bleio_attribute_gatts_set_security_mode(&desc_attr_md.write_perm, descriptor->write_perm); - - mp_buffer_info_t desc_value_bufinfo; - mp_get_buffer_raise(descriptor->value, &desc_value_bufinfo, MP_BUFFER_READ); - - ble_gatts_attr_t desc_attr = { - .p_uuid = &desc_uuid, - .p_attr_md = &desc_attr_md, - .init_len = desc_value_bufinfo.len, - .p_value = desc_value_bufinfo.buf, - .init_offs = 0, - .max_len = descriptor->max_length, - }; - - uint32_t err_code = sd_ble_gatts_descriptor_add(self->handle, &desc_attr, &descriptor->handle); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to add descriptor, err 0x%04x"), err_code); - } - - mp_obj_list_append(self->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); -} - -void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { - if (self->cccd_handle == BLE_GATT_HANDLE_INVALID) { - mp_raise_ValueError(translate("No CCCD for this Characteristic")); - } - - if (!common_hal_bleio_service_get_is_remote(self->service)) { - mp_raise_ValueError(translate("Can't set CCCD on local Characteristic")); - } - - const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->service->device); - common_hal_bleio_check_connected(conn_handle); - - uint16_t cccd_value = - (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | - (indicate ? BLE_GATT_HVX_INDICATION : 0); - - ble_gattc_write_params_t write_params = { - .write_op = BLE_GATT_OP_WRITE_REQ, - .handle = self->cccd_handle, - .p_value = (uint8_t *) &cccd_value, - .len = 2, - }; - - while (1) { - uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); - if (err_code == NRF_SUCCESS) { - break; - } - - // Write with response will return NRF_ERROR_BUSY if the response has not been received. - // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. - if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { - // We could wait for an event indicating the write is complete, but just retrying is easier. - RUN_BACKGROUND_TASKS; - continue; - } - - // Some real error occurred. - mp_raise_OSError_msg_varg(translate("Failed to write CCCD, err 0x%04x"), err_code); - } - -} diff --git a/ports/nrf/common-hal/bleio/Characteristic.h b/ports/nrf/common-hal/bleio/Characteristic.h deleted file mode 100644 index fb6a4c6ce..000000000 --- a/ports/nrf/common-hal/bleio/Characteristic.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H - -#include "shared-bindings/bleio/Attribute.h" -#include "shared-module/bleio/Characteristic.h" -#include "common-hal/bleio/Service.h" -#include "common-hal/bleio/UUID.h" - -typedef struct { - mp_obj_base_t base; - // Will be MP_OBJ_NULL before being assigned to a Service. - bleio_service_obj_t *service; - bleio_uuid_obj_t *uuid; - mp_obj_t value; - uint16_t max_length; - bool fixed_length; - uint16_t handle; - bleio_characteristic_properties_t props; - bleio_attribute_security_mode_t read_perm; - bleio_attribute_security_mode_t write_perm; - mp_obj_list_t *descriptor_list; - uint16_t user_desc_handle; - uint16_t cccd_handle; - uint16_t sccd_handle; -} bleio_characteristic_obj_t; - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H diff --git a/ports/nrf/common-hal/bleio/CharacteristicBuffer.c b/ports/nrf/common-hal/bleio/CharacteristicBuffer.c deleted file mode 100644 index 64ab5e8a7..000000000 --- a/ports/nrf/common-hal/bleio/CharacteristicBuffer.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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 -#include - -#include "ble_drv.h" -#include "ble_gatts.h" -#include "nrf_nvic.h" - -#include "lib/utils/interrupt_char.h" -#include "py/runtime.h" -#include "py/stream.h" - -#include "tick.h" - -#include "shared-bindings/bleio/__init__.h" -#include "common-hal/bleio/CharacteristicBuffer.h" - -STATIC void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) { - // Push all the data onto the ring buffer. - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); - for (size_t i = 0; i < len; i++) { - ringbuf_put(&self->ringbuf, data[i]); - } - sd_nvic_critical_region_exit(is_nested_critical_region); -} - -STATIC void characteristic_buffer_on_ble_evt(ble_evt_t *ble_evt, void *param) { - bleio_characteristic_buffer_obj_t *self = (bleio_characteristic_buffer_obj_t *) param; - switch (ble_evt->header.evt_id) { - case BLE_GATTS_EVT_WRITE: { - // A client wrote to this server characteristic. - - ble_gatts_evt_write_t *evt_write = &ble_evt->evt.gatts_evt.params.write; - // Event handle must match the handle for my characteristic. - if (evt_write->handle == self->characteristic->handle) { - write_to_ringbuf(self, evt_write->data, evt_write->len); - } - break; - } - - case BLE_GATTC_EVT_HVX: { - // A remote service wrote to this characteristic. - - ble_gattc_evt_hvx_t* evt_hvx = &ble_evt->evt.gattc_evt.params.hvx; - // Must be a notification, and event handle must match the handle for my characteristic. - if (evt_hvx->type == BLE_GATT_HVX_NOTIFICATION && - evt_hvx->handle == self->characteristic->handle) { - write_to_ringbuf(self, evt_hvx->data, evt_hvx->len); - } - break; - } - } -} - -// Assumes that timeout and buffer_size have been validated before call. -void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, - bleio_characteristic_obj_t *characteristic, - mp_float_t timeout, - size_t buffer_size) { - - self->characteristic = characteristic; - self->timeout_ms = timeout * 1000; - // This is a macro. - // true means long-lived, so it won't be moved. - ringbuf_alloc(&self->ringbuf, buffer_size, true); - - ble_drv_add_event_handler(characteristic_buffer_on_ble_evt, self); - -} - -int common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) { - uint64_t start_ticks = ticks_ms; - - // Wait for all bytes received or timeout - while ( (ringbuf_count(&self->ringbuf) < len) && (ticks_ms - start_ticks < self->timeout_ms) ) { - RUN_BACKGROUND_TASKS; - // Allow user to break out of a timeout with a KeyboardInterrupt. - if ( mp_hal_is_interrupted() ) { - return 0; - } - } - - // Copy received data. Lock out write interrupt handler while copying. - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); - - size_t rx_bytes = MIN(ringbuf_count(&self->ringbuf), len); - for ( size_t i = 0; i < rx_bytes; i++ ) { - data[i] = ringbuf_get(&self->ringbuf); - } - - // Writes now OK. - sd_nvic_critical_region_exit(is_nested_critical_region); - - return rx_bytes; -} - -uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) { - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); - uint16_t count = ringbuf_count(&self->ringbuf); - sd_nvic_critical_region_exit(is_nested_critical_region); - return count; -} - -void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) { - // prevent conflict with uart irq - uint8_t is_nested_critical_region; - sd_nvic_critical_region_enter(&is_nested_critical_region); - ringbuf_clear(&self->ringbuf); - sd_nvic_critical_region_exit(is_nested_critical_region); -} - -bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { - return self->characteristic == NULL; -} - -void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) { - if (!common_hal_bleio_characteristic_buffer_deinited(self)) { - ble_drv_remove_event_handler(characteristic_buffer_on_ble_evt, self); - } -} - -bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) { - return self->characteristic != NULL && - self->characteristic->service != NULL && - self->characteristic->service->device != NULL && - common_hal_bleio_device_get_conn_handle(self->characteristic->service->device) != BLE_CONN_HANDLE_INVALID; -} diff --git a/ports/nrf/common-hal/bleio/CharacteristicBuffer.h b/ports/nrf/common-hal/bleio/CharacteristicBuffer.h deleted file mode 100644 index db8fd2fad..000000000 --- a/ports/nrf/common-hal/bleio/CharacteristicBuffer.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H - -#include "nrf_soc.h" - -#include "py/ringbuf.h" -#include "shared-bindings/bleio/Characteristic.h" - -typedef struct { - mp_obj_base_t base; - bleio_characteristic_obj_t *characteristic; - uint32_t timeout_ms; - // Ring buffer storing consecutive incoming values. - ringbuf_t ringbuf; -} bleio_characteristic_buffer_obj_t; - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTICBUFFER_H diff --git a/ports/nrf/common-hal/bleio/Descriptor.c b/ports/nrf/common-hal/bleio/Descriptor.c deleted file mode 100644 index 4a5974a06..000000000 --- a/ports/nrf/common-hal/bleio/Descriptor.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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 "py/runtime.h" - -#include "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -static volatile bleio_descriptor_obj_t *m_read_descriptor; - -void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) { - self->characteristic = characteristic; - self->uuid = uuid; - self->handle = BLE_GATT_HANDLE_INVALID; - self->read_perm = read_perm; - self->write_perm = write_perm; - - const mp_int_t max_length_max = fixed_length ? BLE_GATTS_FIX_ATTR_LEN_MAX : BLE_GATTS_VAR_ATTR_LEN_MAX; - if (max_length < 0 || max_length > max_length_max) { - mp_raise_ValueError_varg(translate("max_length must be 0-%d when fixed_length is %s"), - max_length_max, fixed_length ? "True" : "False"); - } - self->max_length = max_length; - self->fixed_length = fixed_length; - - common_hal_bleio_descriptor_set_value(self, initial_value_bufinfo); -} - -bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { - return self->uuid; -} - -bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self) { - return self->characteristic; -} - -STATIC void descriptor_on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { - switch (ble_evt->header.evt_id) { - - // More events may be handled later, so keep this as a switch. - - case BLE_GATTC_EVT_READ_RSP: { - ble_gattc_evt_read_rsp_t *response = &ble_evt->evt.gattc_evt.params.read_rsp; - if (m_read_descriptor) { - m_read_descriptor->value = mp_obj_new_bytearray(response->len, response->data); - } - // Indicate to busy-wait loop that we've read the attribute value. - m_read_descriptor = NULL; - break; - } - - default: - // For debugging. - // mp_printf(&mp_plat_print, "Unhandled descriptor event: 0x%04x\n", ble_evt->header.evt_id); - break; - } -} - -STATIC void descriptor_gattc_read(bleio_descriptor_obj_t *descriptor) { - const uint16_t conn_handle = - common_hal_bleio_device_get_conn_handle(descriptor->characteristic->service->device); - common_hal_bleio_check_connected(conn_handle); - - // Set to NULL in event loop after event. - m_read_descriptor = descriptor; - - ble_drv_add_event_handler(descriptor_on_gattc_read_rsp_evt, descriptor); - - const uint32_t err_code = sd_ble_gattc_read(conn_handle, descriptor->handle, 0); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to read attribute value, err 0x%04x"), err_code); - } - - while (m_read_descriptor != NULL) { - MICROPY_VM_HOOK_LOOP; - } - - ble_drv_remove_event_handler(descriptor_on_gattc_read_rsp_evt, descriptor); -} - -mp_obj_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self) { - // Do GATT operations only if this descriptor has been registered - if (self->handle != BLE_GATT_HANDLE_INVALID) { - if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { - descriptor_gattc_read(self); - } else { - self->value = common_hal_bleio_gatts_read( - self->handle, common_hal_bleio_device_get_conn_handle(self->characteristic->service->device)); - } - } - - return self->value; -} - -void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) { - if (self->fixed_length && bufinfo->len != self->max_length) { - mp_raise_ValueError(translate("Value length != required fixed length")); - } - if (bufinfo->len > self->max_length) { - mp_raise_ValueError(translate("Value length > max_length")); - } - - self->value = mp_obj_new_bytes(bufinfo->buf, bufinfo->len); - - // Do GATT operations only if this descriptor has been registered. - if (self->handle != BLE_GATT_HANDLE_INVALID) { - uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(self->characteristic->service->device); - if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { - // false means WRITE_REQ, not write-no-response - common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, false); - } else { - common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); - } - } - -} diff --git a/ports/nrf/common-hal/bleio/Descriptor.h b/ports/nrf/common-hal/bleio/Descriptor.h deleted file mode 100644 index db1175146..000000000 --- a/ports/nrf/common-hal/bleio/Descriptor.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H - -#include "py/obj.h" - -#include "common-hal/bleio/Characteristic.h" -#include "common-hal/bleio/UUID.h" - -typedef struct { - mp_obj_base_t base; - // Will be MP_OBJ_NULL before being assigned to a Characteristic. - bleio_characteristic_obj_t *characteristic; - bleio_uuid_obj_t *uuid; - mp_obj_t value; - uint16_t max_length; - bool fixed_length; - uint16_t handle; - bleio_attribute_security_mode_t read_perm; - bleio_attribute_security_mode_t write_perm; -} bleio_descriptor_obj_t; - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H diff --git a/ports/nrf/common-hal/bleio/Peripheral.c b/ports/nrf/common-hal/bleio/Peripheral.c deleted file mode 100644 index 92dfc2da1..000000000 --- a/ports/nrf/common-hal/bleio/Peripheral.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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 -#include - -#include "ble.h" -#include "ble_drv.h" -#include "ble_hci.h" -#include "nrf_soc.h" -#include "py/gc.h" -#include "py/objlist.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Attribute.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Peripheral.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -#define BLE_ADV_LENGTH_FIELD_SIZE 1 -#define BLE_ADV_AD_TYPE_FIELD_SIZE 1 -#define BLE_AD_TYPE_FLAGS_DATA_SIZE 1 - -static const ble_gap_sec_params_t pairing_sec_params = { - .bond = 1, - .mitm = 0, - .lesc = 0, - .keypress = 0, - .oob = 0, - .io_caps = BLE_GAP_IO_CAPS_NONE, - .min_key_size = 7, - .max_key_size = 16, - .kdist_own = { .enc = 1, .id = 1}, - .kdist_peer = { .enc = 1, .id = 1}, -}; - -STATIC void check_data_fit(size_t data_len) { - if (data_len > BLE_GAP_ADV_SET_DATA_SIZE_MAX) { - mp_raise_ValueError(translate("Data too large for advertisement packet")); - } -} - -STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { - bleio_peripheral_obj_t *self = (bleio_peripheral_obj_t*)self_in; - - // For debugging. - // mp_printf(&mp_plat_print, "Peripheral event: 0x%04x\n", ble_evt->header.evt_id); - - switch (ble_evt->header.evt_id) { - case BLE_GAP_EVT_CONNECTED: { - // Central has connected. - ble_gap_evt_connected_t* connected = &ble_evt->evt.gap_evt.params.connected; - - self->conn_handle = ble_evt->evt.gap_evt.conn_handle; - - // See if connection interval set by Central is out of range. - // If so, negotiate our preferred range. - ble_gap_conn_params_t conn_params; - sd_ble_gap_ppcp_get(&conn_params); - if (conn_params.min_conn_interval < connected->conn_params.min_conn_interval || - conn_params.min_conn_interval > connected->conn_params.max_conn_interval) { - sd_ble_gap_conn_param_update(ble_evt->evt.gap_evt.conn_handle, &conn_params); - } - break; - } - - case BLE_GAP_EVT_DISCONNECTED: - // Central has disconnected. - self->conn_handle = BLE_CONN_HANDLE_INVALID; - break; - - case BLE_GAP_EVT_PHY_UPDATE_REQUEST: { - ble_gap_phys_t const phys = { - .rx_phys = BLE_GAP_PHY_AUTO, - .tx_phys = BLE_GAP_PHY_AUTO, - }; - sd_ble_gap_phy_update(ble_evt->evt.gap_evt.conn_handle, &phys); - break; - } - - case BLE_GAP_EVT_ADV_SET_TERMINATED: - // TODO: Someday may handle timeouts or limit reached. - break; - - case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: - // SoftDevice will respond to a length update request. - sd_ble_gap_data_length_update(self->conn_handle, NULL, NULL); - break; - - case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: { - // We only handle MTU of size BLE_GATT_ATT_MTU_DEFAULT. - sd_ble_gatts_exchange_mtu_reply(self->conn_handle, BLE_GATT_ATT_MTU_DEFAULT); - break; - } - - case BLE_GATTS_EVT_SYS_ATTR_MISSING: - sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); - break; - - case BLE_GAP_EVT_SEC_PARAMS_REQUEST: { - ble_gap_sec_keyset_t keyset = { - .keys_own = { - .p_enc_key = &self->bonding_keys.own_enc, - .p_id_key = NULL, - .p_sign_key = NULL, - .p_pk = NULL - }, - - .keys_peer = { - .p_enc_key = &self->bonding_keys.peer_enc, - .p_id_key = &self->bonding_keys.peer_id, - .p_sign_key = NULL, - .p_pk = NULL - } - }; - - sd_ble_gap_sec_params_reply(self->conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, - &pairing_sec_params, &keyset); - break; - } - - case BLE_GAP_EVT_LESC_DHKEY_REQUEST: - // TODO for LESC pairing: - // sd_ble_gap_lesc_dhkey_reply(...); - break; - - case BLE_GAP_EVT_AUTH_STATUS: { - // Pairing process completed - ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status; - if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { - // TODO _ediv = bonding_keys->own_enc.master_id.ediv; - self->pair_status = PAIR_PAIRED; - } else { - self->pair_status = PAIR_NOT_PAIRED; - } - break; - } - - case BLE_GAP_EVT_SEC_INFO_REQUEST: { - // Peer asks for the stored keys. - // - load key and return if bonded previously. - // - Else return NULL --> Initiate key exchange - ble_gap_evt_sec_info_request_t* sec_info_request = &ble_evt->evt.gap_evt.params.sec_info_request; - (void) sec_info_request; - //if ( bond_load_keys(_role, sec_req->master_id.ediv, &bkeys) ) { - //sd_ble_gap_sec_info_reply(_conn_hdl, &bkeys.own_enc.enc_info, &bkeys.peer_id.id_info, NULL); - // - //_ediv = bkeys.own_enc.master_id.ediv; - // } else { - sd_ble_gap_sec_info_reply(self->conn_handle, NULL, NULL, NULL); - // } - break; - } - - case BLE_GAP_EVT_CONN_SEC_UPDATE: { - ble_gap_conn_sec_t* conn_sec = &ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec; - if (conn_sec->sec_mode.sm <= 1 && conn_sec->sec_mode.lv <= 1) { - // Security setup did not succeed: - // mode 0, level 0 means no access - // mode 1, level 1 means open link - // mode >=1 and/or level >=1 means encryption is set up - self->pair_status = PAIR_NOT_PAIRED; - } else { - //if ( !bond_load_cccd(_role, _conn_hdl, _ediv) ) { - if (true) { // TODO: no bonding yet - // Initialize system attributes fresh. - sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); - } - // Not quite paired yet: wait for BLE_GAP_EVT_AUTH_STATUS SUCCESS. - self->ediv = self->bonding_keys.own_enc.master_id.ediv; - } - break; - } - - - default: - // For debugging. - // mp_printf(&mp_plat_print, "Unhandled peripheral event: 0x%04x\n", ble_evt->header.evt_id); - break; - } -} - -void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_t name) { - common_hal_bleio_adapter_set_enabled(true); - - self->service_list = mp_obj_new_list(0, NULL); - // Used only for discovery when acting as a client. - self->remote_service_list = mp_obj_new_list(0, NULL); - self->name = name; - - self->conn_handle = BLE_CONN_HANDLE_INVALID; - self->adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; - self->pair_status = PAIR_NOT_PAIRED; - - memset(&self->bonding_keys, 0, sizeof(self->bonding_keys)); -} - -void common_hal_bleio_peripheral_add_service(bleio_peripheral_obj_t *self, bleio_service_obj_t *service) { - ble_uuid_t uuid; - bleio_uuid_convert_to_nrf_ble_uuid(service->uuid, &uuid); - - uint8_t service_type = BLE_GATTS_SRVC_TYPE_PRIMARY; - if (common_hal_bleio_service_get_is_secondary(service)) { - service_type = BLE_GATTS_SRVC_TYPE_SECONDARY; - } - - const uint32_t err_code = sd_ble_gatts_service_add(service_type, &uuid, &service->handle); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to add service, err 0x%04x"), err_code); - } - - mp_obj_list_append(self->service_list, MP_OBJ_FROM_PTR(service)); -} - -mp_obj_list_t *common_hal_bleio_peripheral_get_services(bleio_peripheral_obj_t *self) { - return self->service_list; -} - -bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self) { - return self->conn_handle != BLE_CONN_HANDLE_INVALID; -} - -mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *self) { - return self->name; -} - -void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *self, bool connectable, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo) { - - // interval value has already been validated. - - if (connectable) { - ble_drv_add_event_handler(peripheral_on_ble_evt, self); - } - - common_hal_bleio_adapter_set_enabled(true); - - uint32_t err_code; - - GET_STR_DATA_LEN(self->name, name_data, name_len); - if (name_len > 0) { - // Set device name, and make it available to anyone. - ble_gap_conn_sec_mode_t sec_mode; - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); - err_code = sd_ble_gap_device_name_set(&sec_mode, name_data, name_len); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to set device name, err 0x%04x"), err_code); - - } - } - - check_data_fit(advertising_data_bufinfo->len); - // The advertising data buffers must not move, because the SoftDevice depends on them. - // So make them long-lived. - self->advertising_data = (uint8_t *) gc_alloc(BLE_GAP_ADV_SET_DATA_SIZE_MAX * sizeof(uint8_t), false, true); - memcpy(self->advertising_data, advertising_data_bufinfo->buf, advertising_data_bufinfo->len); - - check_data_fit(scan_response_data_bufinfo->len); - self->scan_response_data = (uint8_t *) gc_alloc(BLE_GAP_ADV_SET_DATA_SIZE_MAX * sizeof(uint8_t), false, true); - memcpy(self->scan_response_data, scan_response_data_bufinfo->buf, scan_response_data_bufinfo->len); - - - ble_gap_adv_params_t adv_params = { - .interval = SEC_TO_UNITS(interval, UNIT_0_625_MS), - .properties.type = connectable ? BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED - : BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED, - .duration = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED, - .filter_policy = BLE_GAP_ADV_FP_ANY, - .primary_phy = BLE_GAP_PHY_1MBPS, - }; - - common_hal_bleio_peripheral_stop_advertising(self); - - const ble_gap_adv_data_t ble_gap_adv_data = { - .adv_data.p_data = self->advertising_data, - .adv_data.len = advertising_data_bufinfo->len, - .scan_rsp_data.p_data = scan_response_data_bufinfo-> len > 0 ? self->scan_response_data : NULL, - .scan_rsp_data.len = scan_response_data_bufinfo->len, - }; - - err_code = sd_ble_gap_adv_set_configure(&self->adv_handle, &ble_gap_adv_data, &adv_params); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to configure advertising, err 0x%04x"), err_code); - } - - err_code = sd_ble_gap_adv_start(self->adv_handle, BLE_CONN_CFG_TAG_CUSTOM); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to start advertising, err 0x%04x"), err_code); - } -} - -void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *self) { - if (self->adv_handle == BLE_GAP_ADV_SET_HANDLE_NOT_SET) - return; - - const uint32_t err_code = sd_ble_gap_adv_stop(self->adv_handle); - - if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) { - mp_raise_OSError_msg_varg(translate("Failed to stop advertising, err 0x%04x"), err_code); - } -} - -void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *self) { - sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); -} - -mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist) { - common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); - // Convert to a tuple and then clear the list so the callee will take ownership. - mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_service_list->len, - self->remote_service_list->items); - mp_obj_list_clear(self->remote_service_list); - return services_tuple; -} - -void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *self) { - self->pair_status = PAIR_WAITING; - - uint32_t err_code = sd_ble_gap_authenticate(self->conn_handle, &pairing_sec_params); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to start pairing, error 0x%04x"), err_code); - } - - while (self->pair_status == PAIR_WAITING) { - RUN_BACKGROUND_TASKS; - } - - if (self->pair_status == PAIR_NOT_PAIRED) { - mp_raise_OSError_msg(translate("Failed to pair")); - } - - -} diff --git a/ports/nrf/common-hal/bleio/Peripheral.h b/ports/nrf/common-hal/bleio/Peripheral.h deleted file mode 100644 index 1620874ca..000000000 --- a/ports/nrf/common-hal/bleio/Peripheral.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_PERIPHERAL_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_PERIPHERAL_H - -#include - -#include "ble.h" - -#include "py/obj.h" -#include "py/objlist.h" - -#include "common-hal/bleio/__init__.h" -#include "shared-module/bleio/Address.h" - -typedef enum { - PAIR_NOT_PAIRED, - PAIR_WAITING, - PAIR_PAIRED, -} pair_status_t; - -typedef struct { - mp_obj_base_t base; - mp_obj_t name; - volatile uint16_t conn_handle; - // Services provided by this peripheral. - mp_obj_list_t *service_list; - // Remote services discovered when this peripheral is acting as a client. - mp_obj_list_t *remote_service_list; - // The advertising data and scan response buffers are held by us, not by the SD, so we must - // maintain them and not change it. If we need to change the contents during advertising, - // there are tricks to get the SD to notice (see DevZone - TBS). - // EDIV: Encrypted Diversifier: Identifies LTK during legacy pairing. - bonding_keys_t bonding_keys; - uint16_t ediv; - uint8_t* advertising_data; - uint8_t* scan_response_data; - uint8_t adv_handle; - pair_status_t pair_status; -} bleio_peripheral_obj_t; - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_PERIPHERAL_H diff --git a/ports/nrf/common-hal/bleio/Scanner.c b/ports/nrf/common-hal/bleio/Scanner.c deleted file mode 100644 index 57ce940ab..000000000 --- a/ports/nrf/common-hal/bleio/Scanner.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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 - -#include "ble_drv.h" -#include "ble_gap.h" -#include "py/mphal.h" -#include "py/objlist.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/ScanEntry.h" -#include "shared-bindings/bleio/Scanner.h" -#include "shared-module/bleio/ScanEntry.h" - -static uint8_t m_scan_buffer_data[BLE_GAP_SCAN_BUFFER_MIN]; - -static ble_data_t m_scan_buffer = { - m_scan_buffer_data, - BLE_GAP_SCAN_BUFFER_MIN -}; - -STATIC void scanner_on_ble_evt(ble_evt_t *ble_evt, void *scanner_in) { - bleio_scanner_obj_t *scanner = (bleio_scanner_obj_t*)scanner_in; - ble_gap_evt_adv_report_t *report = &ble_evt->evt.gap_evt.params.adv_report; - - if (ble_evt->header.evt_id != BLE_GAP_EVT_ADV_REPORT) { - return; - } - - bleio_scanentry_obj_t *entry = m_new_obj(bleio_scanentry_obj_t); - entry->base.type = &bleio_scanentry_type; - entry->rssi = report->rssi; - - bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t); - address->base.type = &bleio_address_type; - common_hal_bleio_address_construct(MP_OBJ_TO_PTR(address), - report->peer_addr.addr, report->peer_addr.addr_type); - entry->address = address; - - entry->data = mp_obj_new_bytes(report->data.p_data, report->data.len); - - mp_obj_list_append(scanner->scan_entries, MP_OBJ_FROM_PTR(entry)); - - const uint32_t err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to continue scanning, err 0x%04x"), err_code); - } -} - -void common_hal_bleio_scanner_construct(bleio_scanner_obj_t *self) { -} - -mp_obj_t common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_float_t timeout, mp_float_t interval, mp_float_t window) { - common_hal_bleio_adapter_set_enabled(true); - ble_drv_add_event_handler(scanner_on_ble_evt, self); - - ble_gap_scan_params_t scan_params = { - .interval = SEC_TO_UNITS(interval, UNIT_0_625_MS), - .window = SEC_TO_UNITS(window, UNIT_0_625_MS), - .scan_phys = BLE_GAP_PHY_1MBPS, - }; - - self->scan_entries = mp_obj_new_list(0, NULL); - - uint32_t err_code; - err_code = sd_ble_gap_scan_start(&scan_params, &m_scan_buffer); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to start scanning, err 0x%04x"), err_code); - } - - mp_hal_delay_ms(timeout * 1000); - sd_ble_gap_scan_stop(); - - // Return list, and don't hang on to it, so it can be GC'd. - mp_obj_t entries = self->scan_entries; - self->scan_entries = MP_OBJ_NULL; - return entries; -} diff --git a/ports/nrf/common-hal/bleio/Scanner.h b/ports/nrf/common-hal/bleio/Scanner.h deleted file mode 100644 index 3768a52cb..000000000 --- a/ports/nrf/common-hal/bleio/Scanner.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SCANNER_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SCANNER_H - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - mp_obj_t scan_entries; - uint16_t interval; - uint16_t window; -} bleio_scanner_obj_t; - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SCANNER_H diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c deleted file mode 100644 index f69bbd89d..000000000 --- a/ports/nrf/common-hal/bleio/Service.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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 "ble_drv.h" -#include "ble.h" -#include "py/runtime.h" -#include "common-hal/bleio/__init__.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/Peripheral.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/Adapter.h" - -void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_peripheral_obj_t *peripheral, bleio_uuid_obj_t *uuid, bool is_secondary) { - self->device = MP_OBJ_FROM_PTR(peripheral); - self->handle = 0xFFFF; - self->uuid = uuid; - self->characteristic_list = mp_obj_new_list(0, NULL); - self->is_remote = false; - self->is_secondary = is_secondary; -} - -bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { - return self->uuid; -} - -mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self) { - return self->characteristic_list; -} - -bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { - return self->is_remote; -} - -bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { - return self->is_secondary; -} - -void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic) { - ble_gatts_char_md_t char_md = { - .char_props.broadcast = (characteristic->props & CHAR_PROP_BROADCAST) ? 1 : 0, - .char_props.read = (characteristic->props & CHAR_PROP_READ) ? 1 : 0, - .char_props.write_wo_resp = (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) ? 1 : 0, - .char_props.write = (characteristic->props & CHAR_PROP_WRITE) ? 1 : 0, - .char_props.notify = (characteristic->props & CHAR_PROP_NOTIFY) ? 1 : 0, - .char_props.indicate = (characteristic->props & CHAR_PROP_INDICATE) ? 1 : 0, - }; - - ble_gatts_attr_md_t cccd_md = { - .vloc = BLE_GATTS_VLOC_STACK, - }; - - ble_uuid_t char_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &char_uuid); - - ble_gatts_attr_md_t char_attr_md = { - .vloc = BLE_GATTS_VLOC_STACK, - .vlen = !characteristic->fixed_length, - }; - - if (char_md.char_props.notify || char_md.char_props.indicate) { - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm); - // Make CCCD write permission match characteristic read permission. - bleio_attribute_gatts_set_security_mode(&cccd_md.write_perm, characteristic->read_perm); - - char_md.p_cccd_md = &cccd_md; - } - - bleio_attribute_gatts_set_security_mode(&char_attr_md.read_perm, characteristic->read_perm); - bleio_attribute_gatts_set_security_mode(&char_attr_md.write_perm, characteristic->write_perm); - - mp_buffer_info_t char_value_bufinfo; - mp_get_buffer_raise(characteristic->value, &char_value_bufinfo, MP_BUFFER_READ); - - ble_gatts_attr_t char_attr = { - .p_uuid = &char_uuid, - .p_attr_md = &char_attr_md, - .init_len = char_value_bufinfo.len, - .p_value = char_value_bufinfo.buf, - .init_offs = 0, - .max_len = characteristic->max_length, - }; - - ble_gatts_char_handles_t char_handles; - - uint32_t err_code; - err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &char_attr, &char_handles); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to add characteristic, err 0x%04x"), err_code); - } - - characteristic->user_desc_handle = char_handles.user_desc_handle; - characteristic->cccd_handle = char_handles.cccd_handle; - characteristic->sccd_handle = char_handles.sccd_handle; - characteristic->handle = char_handles.value_handle; - - mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); -} diff --git a/ports/nrf/common-hal/bleio/Service.h b/ports/nrf/common-hal/bleio/Service.h deleted file mode 100644 index 03ac2bca8..000000000 --- a/ports/nrf/common-hal/bleio/Service.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SERVICE_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SERVICE_H - -#include "py/objlist.h" -#include "common-hal/bleio/UUID.h" - -typedef struct { - mp_obj_base_t base; - // Handle for this service. - uint16_t handle; - // True if created during discovery. - bool is_remote; - bool is_secondary; - bleio_uuid_obj_t *uuid; - // May be a Peripheral, Central, etc. - mp_obj_t device; - mp_obj_list_t *characteristic_list; - // Range of attribute handles of this service. - uint16_t start_handle; - uint16_t end_handle; -} bleio_service_obj_t; - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_SERVICE_H diff --git a/ports/nrf/common-hal/bleio/UUID.c b/ports/nrf/common-hal/bleio/UUID.c deleted file mode 100644 index ebd6b6d1f..000000000 --- a/ports/nrf/common-hal/bleio/UUID.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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 - -#include "py/runtime.h" -#include "common-hal/bleio/UUID.h" -#include "shared-bindings/bleio/Adapter.h" - -#include "ble.h" -#include "ble_drv.h" -#include "nrf_error.h" - -// If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. -// If uuid128 is not NULL, it's a 128-bit (16-byte) UUID, with bytes 12 and 13 zero'd out, where -// the 16-bit part goes. Those 16 bits are passed in uuid16. -void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, uint32_t uuid16, uint8_t uuid128[]) { - common_hal_bleio_adapter_set_enabled(true); - - self->nrf_ble_uuid.uuid = uuid16; - if (uuid128 == NULL) { - self->nrf_ble_uuid.type = BLE_UUID_TYPE_BLE; - } else { - ble_uuid128_t vs_uuid; - memcpy(vs_uuid.uuid128, uuid128, sizeof(vs_uuid.uuid128)); - - // Register this vendor-specific UUID. Bytes 12 and 13 will be zero. - const uint32_t err_code = sd_ble_uuid_vs_add(&vs_uuid, &self->nrf_ble_uuid.type); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to register Vendor-Specific UUID, err 0x%04x"), err_code); - } - } -} - -uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self) { - return self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE ? 16 : 128; -} - -uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { - return self->nrf_ble_uuid.uuid; -} - -// True if uuid128 has been successfully filled in. -bool common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]) { - uint8_t length; - const uint32_t err_code = sd_ble_uuid_encode(&self->nrf_ble_uuid, &length, uuid128); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Could not decode ble_uuid, err 0x%04x"), err_code); - } - // If not 16 bytes, this is not a 128-bit UUID, so return. - return length == 16; -} - -// Returns 0 if this is a 16-bit UUID, otherwise returns a non-zero index -// into the 128-bit uuid registration table. -uint32_t common_hal_bleio_uuid_get_uuid128_reference(bleio_uuid_obj_t *self) { - return self->nrf_ble_uuid.type == BLE_UUID_TYPE_BLE ? 0 : self->nrf_ble_uuid.type; -} - - -void bleio_uuid_construct_from_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_ble_uuid) { - if (nrf_ble_uuid->type == BLE_UUID_TYPE_UNKNOWN) { - mp_raise_RuntimeError(translate("Unexpected nrfx uuid type")); - } - self->nrf_ble_uuid.uuid = nrf_ble_uuid->uuid; - self->nrf_ble_uuid.type = nrf_ble_uuid->type; -} - -// Fill in a ble_uuid_t from my values. -void bleio_uuid_convert_to_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_ble_uuid) { - nrf_ble_uuid->uuid = self->nrf_ble_uuid.uuid; - nrf_ble_uuid->type = self->nrf_ble_uuid.type; -} diff --git a/ports/nrf/common-hal/bleio/UUID.h b/ports/nrf/common-hal/bleio/UUID.h deleted file mode 100644 index 7d3a6204e..000000000 --- a/ports/nrf/common-hal/bleio/UUID.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_UUID_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_UUID_H - -#include "py/obj.h" - -#include "ble.h" - -typedef struct { - mp_obj_base_t base; - // Use the native way of storing UUID's: - // - ble_uuid_t.uuid is a 16-bit uuid. - // - ble_uuid_t.type is BLE_UUID_TYPE_BLE if it's a 16-bit Bluetooth SIG UUID. - // or is BLE_UUID_TYPE_VENDOR_BEGIN and higher, which indexes into a table of registered - // 128-bit UUIDs. - ble_uuid_t nrf_ble_uuid; -} bleio_uuid_obj_t; - -void bleio_uuid_construct_from_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_uuid); -void bleio_uuid_convert_to_nrf_ble_uuid(bleio_uuid_obj_t *self, ble_uuid_t *nrf_uuid); - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_UUID_H diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c deleted file mode 100644 index 4a7597e37..000000000 --- a/ports/nrf/common-hal/bleio/__init__.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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 "py/runtime.h" -#include "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Central.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/Peripheral.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -#include "common-hal/bleio/__init__.h" - -static volatile bool m_discovery_in_process; -static volatile bool m_discovery_successful; - -static bleio_service_obj_t *m_char_discovery_service; -static bleio_characteristic_obj_t *m_desc_discovery_characteristic; - -// Turn off BLE on a reset or reload. -void bleio_reset() { - if (common_hal_bleio_adapter_get_enabled()) { - common_hal_bleio_adapter_set_enabled(false); - } -} - -// The singleton bleio.Adapter object, bound to bleio.adapter -// It currently only has properties and no state -const super_adapter_obj_t common_hal_bleio_adapter_obj = { - .base = { - .type = &bleio_adapter_type, - }, -}; - -void common_hal_bleio_check_connected(uint16_t conn_handle) { - if (conn_handle == BLE_CONN_HANDLE_INVALID) { - mp_raise_OSError_msg(translate("Not connected")); - } -} - -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { - if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { - return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; - } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { - return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; - } else { - return BLE_CONN_HANDLE_INVALID; - } -} - -mp_obj_list_t *common_hal_bleio_device_get_remote_service_list(mp_obj_t device) { - if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { - return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->remote_service_list; - } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { - return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->remote_service_list; - } else { - return NULL; - } -} - -// service_uuid may be NULL, to discover all services. -STATIC bool discover_next_services(mp_obj_t device, uint16_t start_handle, ble_uuid_t *service_uuid) { - m_discovery_successful = false; - m_discovery_in_process = true; - - uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); - uint32_t err_code = sd_ble_gattc_primary_services_discover(conn_handle, start_handle, service_uuid); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg(translate("Failed to discover services")); - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_characteristics(mp_obj_t device, bleio_service_obj_t *service, uint16_t start_handle) { - m_char_discovery_service = service; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = service->end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); - uint32_t err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_descriptors(mp_obj_t device, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { - m_desc_discovery_characteristic = characteristic; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); - uint32_t err_code = sd_ble_gattc_descriptors_discover(conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, mp_obj_t device) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_service_t *gattc_service = &response->services[i]; - - bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); - service->base.type = &bleio_service_type; - - // Initialize several fields at once. - common_hal_bleio_service_construct(service, device, NULL, false); - - service->is_remote = true; - service->start_handle = gattc_service->handle_range.start_handle; - service->end_handle = gattc_service->handle_range.end_handle; - service->handle = gattc_service->handle_range.start_handle; - - if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known service UUID. - bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); - service->uuid = uuid; - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just set the UUID to NULL. - service->uuid = NULL; - } - - mp_obj_list_append(common_hal_bleio_device_get_remote_service_list(device), service); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_obj_t device) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_char_t *gattc_char = &response->chars[i]; - - bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); - characteristic->base.type = &bleio_characteristic_type; - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known characteristic UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - bleio_characteristic_properties_t props = - (gattc_char->char_props.broadcast ? CHAR_PROP_BROADCAST : 0) | - (gattc_char->char_props.indicate ? CHAR_PROP_INDICATE : 0) | - (gattc_char->char_props.notify ? CHAR_PROP_NOTIFY : 0) | - (gattc_char->char_props.read ? CHAR_PROP_READ : 0) | - (gattc_char->char_props.write ? CHAR_PROP_WRITE : 0) | - (gattc_char->char_props.write_wo_resp ? CHAR_PROP_WRITE_NO_RESPONSE : 0); - - // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. - common_hal_bleio_characteristic_construct( - characteristic, m_char_discovery_service, uuid, props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, - GATT_MAX_DATA_LENGTH, false, // max_length, fixed_length: values may not matter for gattc - mp_obj_new_list(0, NULL)); - characteristic->handle = gattc_char->handle_value; - - mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_obj_t device) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_desc_t *gattc_desc = &response->descs[i]; - - // Remember handles for certain well-known descriptors. - switch (gattc_desc->uuid.uuid) { - case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: - m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; - break; - - case BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG: - m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; - break; - - case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: - m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; - break; - - default: - // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, - // so ignore those. - // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors - break; - } - - bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); - descriptor->base.type = &bleio_descriptor_type; - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known descriptor UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - common_hal_bleio_descriptor_construct( - descriptor, m_desc_discovery_characteristic, uuid, - SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, - GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); - descriptor->handle = gattc_desc->handle; - - mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t device) { - switch (ble_evt->header.evt_id) { - case BLE_GAP_EVT_DISCONNECTED: - m_discovery_successful = false; - m_discovery_in_process = false; - break; - - case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: - on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, device); - break; - - case BLE_GATTC_EVT_CHAR_DISC_RSP: - on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, device); - break; - - case BLE_GATTC_EVT_DESC_DISC_RSP: - on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, device); - break; - - default: - // For debugging. - // mp_printf(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id); - break; - } -} - - -void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { - mp_obj_list_t *remote_services_list = common_hal_bleio_device_get_remote_service_list(device); - - ble_drv_add_event_handler(discovery_on_ble_evt, device); - - // Start over with an empty list. - mp_obj_list_clear(MP_OBJ_FROM_PTR(common_hal_bleio_device_get_remote_service_list(device))); - - if (service_uuids_whitelist == mp_const_none) { - // List of service UUID's not given, so discover all available services. - - uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; - - while (discover_next_services(device, next_service_start_handle, MP_OBJ_NULL)) { - // discover_next_services() appends to remote_services_list. - - // Get the most recently discovered service, and then ask for services - // whose handles start after the last attribute handle inside that service. - const bleio_service_obj_t *service = - MP_OBJ_TO_PTR(remote_services_list->items[remote_services_list->len - 1]); - next_service_start_handle = service->end_handle + 1; - } - } else { - mp_obj_iter_buf_t iter_buf; - mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); - mp_obj_t uuid_obj; - while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - mp_raise_ValueError(translate("non-UUID found in service_uuids_whitelist")); - } - bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - - ble_uuid_t nrf_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); - - // Service might or might not be discovered; that's ok. Caller has to check - // Central.remote_services to find out. - // We only need to call this once for each service to discover. - discover_next_services(device, BLE_GATT_HANDLE_START, &nrf_uuid); - } - } - - - for (size_t service_idx = 0; service_idx < remote_services_list->len; ++service_idx) { - bleio_service_obj_t *service = MP_OBJ_TO_PTR(remote_services_list->items[service_idx]); - - // Skip the service if it had an unknown (unregistered) UUID. - if (service->uuid == NULL) { - continue; - } - - uint16_t next_char_start_handle = service->start_handle; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_characteristics() appends to the characteristic_list. - while (next_char_start_handle <= service->end_handle && - discover_next_characteristics(device, service, next_char_start_handle)) { - - - // Get the most recently discovered characteristic, and then ask for characteristics - // whose handles start after the last attribute handle inside that characteristic. - const bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); - next_char_start_handle = characteristic->handle + 1; - } - - // Got characteristics for this service. Now discover descriptors for each characteristic. - size_t char_list_len = service->characteristic_list->len; - for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { - bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); - const bool last_characteristic = char_idx == char_list_len - 1; - bleio_characteristic_obj_t *next_characteristic = last_characteristic - ? NULL - : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); - - // Skip the characteristic if it had an unknown (unregistered) UUID. - if (characteristic->uuid == NULL) { - continue; - } - - uint16_t next_desc_start_handle = characteristic->handle + 1; - - // Don't run past the end of this service or the beginning of the next characteristic. - uint16_t next_desc_end_handle = next_characteristic == NULL - ? service->end_handle - : next_characteristic->handle - 1; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_descriptors() appends to the descriptor_list. - while (next_desc_start_handle <= service->end_handle && - next_desc_start_handle < next_desc_end_handle && - discover_next_descriptors(device, characteristic, - next_desc_start_handle, next_desc_end_handle)) { - - // Get the most recently discovered descriptor, and then ask for descriptors - // whose handles start after that descriptor's handle. - const bleio_descriptor_obj_t *descriptor = - MP_OBJ_TO_PTR(characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]); - next_desc_start_handle = descriptor->handle + 1; - } - } - } - - // This event handler is no longer needed. - ble_drv_remove_event_handler(discovery_on_ble_evt, device); - -} - -// GATTS read of a Characteristic or Descriptor. -mp_obj_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle) { - // conn_handle might be BLE_CONN_HANDLE_INVALID if we're not connected, but that's OK, because - // we can still read and write the local value. - - mp_buffer_info_t bufinfo; - ble_gatts_value_t gatts_value = { - .p_value = NULL, - .len = 0, - }; - - // Read once to find out what size buffer we need, then read again to fill buffer. - - mp_obj_t value = mp_const_none; - uint32_t err_code = sd_ble_gatts_value_get(conn_handle, handle, &gatts_value); - if (err_code == NRF_SUCCESS) { - value = mp_obj_new_bytearray_of_zeros(gatts_value.len); - mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_WRITE); - gatts_value.p_value = bufinfo.buf; - - // Read again, with the correct size of buffer. - err_code = sd_ble_gatts_value_get(conn_handle, handle, &gatts_value); - } - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to read gatts value, err 0x%04x"), err_code); - } - - return value; -} - -void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { - // conn_handle might be BLE_CONN_HANDLE_INVALID if we're not connected, but that's OK, because - // we can still read and write the local value. - - ble_gatts_value_t gatts_value = { - .p_value = bufinfo->buf, - .len = bufinfo->len, - }; - - const uint32_t err_code = sd_ble_gatts_value_set(conn_handle, handle, &gatts_value); - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg_varg(translate("Failed to write gatts value, err 0x%04x"), err_code); - } -} - -void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { - common_hal_bleio_check_connected(conn_handle); - - ble_gattc_write_params_t write_params = { - .write_op = write_no_response ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, - .handle = handle, - .p_value = bufinfo->buf, - .len = bufinfo->len, - }; - - while (1) { - uint32_t err_code = sd_ble_gattc_write(conn_handle, &write_params); - if (err_code == NRF_SUCCESS) { - break; - } - - // Write with response will return NRF_ERROR_BUSY if the response has not been received. - // Write without reponse will return NRF_ERROR_RESOURCES if too many writes are pending. - if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES) { - // We could wait for an event indicating the write is complete, but just retrying is easier. - MICROPY_VM_HOOK_LOOP; - continue; - } - - // Some real error occurred. - mp_raise_OSError_msg_varg(translate("Failed to write attribute value, err 0x%04x"), err_code); - } - -} diff --git a/ports/nrf/common-hal/bleio/__init__.h b/ports/nrf/common-hal/bleio/__init__.h deleted file mode 100644 index cf1a06945..000000000 --- a/ports/nrf/common-hal/bleio/__init__.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H - -void bleio_reset(void); - -typedef struct { - ble_gap_enc_key_t own_enc; - ble_gap_enc_key_t peer_enc; - ble_gap_id_key_t peer_id; -} bonding_keys_t; - -// We assume variable length data. -// 20 bytes max (23 - 3). -#define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c index 03f787624..8e5583581 100644 --- a/ports/nrf/supervisor/port.c +++ b/ports/nrf/supervisor/port.c @@ -38,7 +38,7 @@ #include "shared-module/gamepad/__init__.h" #include "common-hal/microcontroller/Pin.h" -#include "common-hal/bleio/__init__.h" +#include "common-hal/_bleio/__init__.h" #include "common-hal/busio/I2C.h" #include "common-hal/busio/SPI.h" #include "common-hal/busio/UART.h" diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 3f593416e..b17c312f7 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -122,7 +122,7 @@ ifeq ($(CIRCUITPY_BITBANG_APA102),1) SRC_PATTERNS += bitbangio/SPI% endif ifeq ($(CIRCUITPY_BLEIO),1) -SRC_PATTERNS += bleio/% +SRC_PATTERNS += _bleio/% endif ifeq ($(CIRCUITPY_BOARD),1) SRC_PATTERNS += board/% @@ -223,6 +223,17 @@ endif # All possible sources are listed here, and are filtered by SRC_PATTERNS in SRC_COMMON_HAL SRC_COMMON_HAL_ALL = \ + _bleio/__init__.c \ + _bleio/Adapter.c \ + _bleio/Attribute.c \ + _bleio/Central.c \ + _bleio/Characteristic.c \ + _bleio/CharacteristicBuffer.c \ + _bleio/Descriptor.c \ + _bleio/Peripheral.c \ + _bleio/Scanner.c \ + _bleio/Service.c \ + _bleio/UUID.c \ analogio/AnalogIn.c \ analogio/AnalogOut.c \ analogio/__init__.c \ @@ -233,17 +244,6 @@ SRC_COMMON_HAL_ALL = \ audiopwmio/PWMAudioOut.c \ audioio/__init__.c \ audioio/AudioOut.c \ - bleio/__init__.c \ - bleio/Adapter.c \ - bleio/Attribute.c \ - bleio/Central.c \ - bleio/Characteristic.c \ - bleio/CharacteristicBuffer.c \ - bleio/Descriptor.c \ - bleio/Peripheral.c \ - bleio/Scanner.c \ - bleio/Service.c \ - bleio/UUID.c \ board/__init__.c \ busio/I2C.c \ busio/SPI.c \ @@ -284,9 +284,9 @@ SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL)) # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_BINDINGS_ENUMS = \ $(filter $(SRC_PATTERNS), \ - bleio/Address.c \ - bleio/Attribute.c \ - bleio/ScanEntry.c \ + _bleio/Address.c \ + _bleio/Attribute.c \ + _bleio/ScanEntry.c \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ @@ -301,6 +301,9 @@ SRC_BINDINGS_ENUMS += \ util.c SRC_SHARED_MODULE_ALL = \ + _bleio/Address.c \ + _bleio/Attribute.c \ + _bleio/ScanEntry.c \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ _stage/Layer.c \ @@ -317,9 +320,6 @@ SRC_SHARED_MODULE_ALL = \ bitbangio/SPI.c \ bitbangio/__init__.c \ board/__init__.c \ - bleio/Address.c \ - bleio/Attribute.c \ - bleio/ScanEntry.c \ busio/OneWire.c \ displayio/Bitmap.c \ displayio/ColorConverter.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index c2e2e2d02..5ac66665a 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -259,7 +259,7 @@ extern const struct _mp_obj_module_t bitbangio_module; #endif #if CIRCUITPY_BLEIO -#define BLEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bleio), (mp_obj_t)&bleio_module }, +#define BLEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__bleio), (mp_obj_t)&bleio_module }, extern const struct _mp_obj_module_t bleio_module; #else #define BLEIO_MODULE diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 356a8f95d..1af71a416 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -99,7 +99,7 @@ CIRCUITPY_BITBANGIO = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_BITBANGIO=$(CIRCUITPY_BITBANGIO) -# Explicitly enabled for boards that support bleio. +# Explicitly enabled for boards that support _bleio. ifndef CIRCUITPY_BLEIO CIRCUITPY_BLEIO = 0 endif diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c new file mode 100644 index 000000000..0caca96b8 --- /dev/null +++ b/shared-bindings/_bleio/Adapter.c @@ -0,0 +1,125 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 "py/objproperty.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-bindings/_bleio/Adapter.h" + +//| .. currentmodule:: _bleio +//| +//| :class:`Adapter` --- BLE adapter information +//| ---------------------------------------------------- +//| +//| Get current status of the BLE adapter +//| +//| Usage:: +//| +//| import _bleio +//| _bleio.adapter.enabled = True +//| print(_bleio.adapter.address) +//| + +//| .. class:: Adapter() +//| +//| You cannot create an instance of `_bleio.Adapter`. +//| Use `_bleio.adapter` to access the sole instance available. +//| + +//| .. attribute:: adapter.enabled +//| +//| State of the BLE adapter. +//| +STATIC mp_obj_t bleio_adapter_get_enabled(mp_obj_t self) { + return mp_obj_new_bool(common_hal_bleio_adapter_get_enabled()); +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_enabled_obj, bleio_adapter_get_enabled); + +static mp_obj_t bleio_adapter_set_enabled(mp_obj_t self, mp_obj_t value) { + const bool enabled = mp_obj_is_true(value); + + common_hal_bleio_adapter_set_enabled(enabled); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_adapter_set_enabled_obj, bleio_adapter_set_enabled); + +const mp_obj_property_t bleio_adapter_enabled_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_adapter_get_enabled_obj, + (mp_obj_t)&bleio_adapter_set_enabled_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: adapter.address +//| +//| MAC address of the BLE adapter. (read-only) +//| +STATIC mp_obj_t bleio_adapter_get_address(mp_obj_t self) { + return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_address()); + +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_address_obj, bleio_adapter_get_address); + +const mp_obj_property_t bleio_adapter_address_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_adapter_get_address_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: adapter.default_name +//| +//| default_name of the BLE adapter. (read-only) +//| The name is "CIRCUITPY" + the last four hex digits of ``adapter.address``, +//| to make it easy to distinguish multiple CircuitPython boards. +//| +STATIC mp_obj_t bleio_adapter_get_default_name(mp_obj_t self) { + return common_hal_bleio_adapter_get_default_name(); + +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_default_name_obj, bleio_adapter_get_default_name); + +const mp_obj_property_t bleio_adapter_default_name_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_adapter_get_default_name_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_adapter_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&bleio_adapter_enabled_obj) }, + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_adapter_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_default_name), MP_ROM_PTR(&bleio_adapter_default_name_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_adapter_locals_dict, bleio_adapter_locals_dict_table); + +const mp_obj_type_t bleio_adapter_type = { + .base = { &mp_type_type }, + .name = MP_QSTR_Adapter, + .locals_dict = (mp_obj_t)&bleio_adapter_locals_dict, +}; diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h new file mode 100644 index 000000000..932fc9c95 --- /dev/null +++ b/shared-bindings/_bleio/Adapter.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H + +#include "shared-module/_bleio/Address.h" + +const mp_obj_type_t bleio_adapter_type; + +extern bool common_hal_bleio_adapter_get_enabled(void); +extern void common_hal_bleio_adapter_set_enabled(bool enabled); +extern bleio_address_obj_t *common_hal_bleio_adapter_get_address(void); +extern mp_obj_t common_hal_bleio_adapter_get_default_name(void); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H diff --git a/shared-bindings/_bleio/Address.c b/shared-bindings/_bleio/Address.c new file mode 100644 index 000000000..cdee02b5d --- /dev/null +++ b/shared-bindings/_bleio/Address.c @@ -0,0 +1,210 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 +#include + +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-module/_bleio/Address.h" + +//| .. currentmodule:: _bleio +//| +//| :class:`Address` -- BLE address +//| ========================================================= +//| +//| Encapsulates the address of a BLE device. +//| + +//| .. class:: Address(address, address_type) +//| +//| Create a new Address object encapsulating the address value. +//| The value itself can be one of: +//| +//| :param buf address: The address value to encapsulate. A buffer object (bytearray, bytes) of 6 bytes. +//| :param int address_type: one of the integer values: `PUBLIC`, `RANDOM_STATIC`, +//| `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`. +//| +STATIC mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address, ARG_address_type }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_address_type, MP_ARG_INT, {.u_int = BLEIO_ADDRESS_TYPE_PUBLIC } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + bleio_address_obj_t *self = m_new_obj(bleio_address_obj_t); + self->base.type = &bleio_address_type; + + const mp_obj_t address = args[ARG_address].u_obj; + mp_buffer_info_t buf_info; + mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); + if (buf_info.len != NUM_BLEIO_ADDRESS_BYTES) { + mp_raise_ValueError_varg(translate("Address must be %d bytes long"), NUM_BLEIO_ADDRESS_BYTES); + } + + const mp_int_t address_type = args[ARG_address_type].u_int; + if (address_type < BLEIO_ADDRESS_TYPE_MIN || address_type > BLEIO_ADDRESS_TYPE_MAX) { + mp_raise_ValueError(translate("Address type out of range")); + } + + common_hal_bleio_address_construct(self, buf_info.buf, address_type); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. attribute:: address_bytes +//| +//| The bytes that make up the device address (read-only). +//| +//| Note that the ``bytes`` object returned is in little-endian order: +//| The least significant byte is ``address_bytes[0]``. So the address will +//| appear to be reversed if you print the raw ``bytes`` object. If you print +//| or use `str()` on the :py:class:`~_bleio.Attribute` object itself, the address will be printed +//| in the expected order. For example: +//| +//| .. code-block:: pycon +//| +//| >>> import _bleio +//| >>> _bleio.adapter.address +//|
+//| >>> _bleio.adapter.address.address_bytes +//| b'5\xa8\xed\xf5\x1d\xc8' +//| +STATIC mp_obj_t bleio_address_get_address_bytes(mp_obj_t self_in) { + bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_address_get_address_bytes(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_address_get_address_bytes_obj, bleio_address_get_address_bytes); + +const mp_obj_property_t bleio_address_address_bytes_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&bleio_address_get_address_bytes_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: type +//| +//| The address type (read-only). +//| One of the integer values: `PUBLIC`, `RANDOM_STATIC`, +//| `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`. +//| +STATIC mp_obj_t bleio_address_get_type(mp_obj_t self_in) { + bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_address_get_type(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_address_get_type_obj, bleio_address_get_type); + +const mp_obj_property_t bleio_address_type_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&bleio_address_get_type_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. method:: __eq__(other) +//| +//| Two Address objects are equal if their addresses and address types are equal. +//| +STATIC mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + switch (op) { + // Two Addresses are equal if their address bytes and address_type are equal + case MP_BINARY_OP_EQUAL: + if (MP_OBJ_IS_TYPE(rhs_in, &bleio_address_type)) { + bleio_address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); + bleio_address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); + return mp_obj_new_bool( + mp_obj_equal(common_hal_bleio_address_get_address_bytes(lhs), + common_hal_bleio_address_get_address_bytes(rhs)) && + common_hal_bleio_address_get_type(lhs) == + common_hal_bleio_address_get_type(rhs)); + + } else { + return mp_const_false; + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t buf_info; + mp_obj_t address_bytes = common_hal_bleio_address_get_address_bytes(self); + mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ); + + const uint8_t *buf = (uint8_t *) buf_info.buf; + mp_printf(print, "
", + buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); +} + +//| .. data:: PUBLIC +//| +//| A publicly known address, with a company ID (high 24 bits)and company-assigned part (low 24 bits). +//| +//| .. data:: RANDOM_STATIC +//| +//| A randomly generated address that does not change often. It may never change or may change after +//| a power cycle. +//| +//| .. data:: RANDOM_PRIVATE_RESOLVABLE +//| +//| An address that is usable when the peer knows the other device's secret Identity Resolving Key (IRK). +//| +//| .. data:: RANDOM_PRIVATE_NON_RESOLVABLE +//| +//| A randomly generated address that changes on every connection. +//| +STATIC const mp_rom_map_elem_t bleio_address_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_address_bytes), MP_ROM_PTR(&bleio_address_address_bytes_obj) }, + { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&bleio_address_type_obj) }, + // These match the BLE_GAP_ADDR_TYPES values used by the nRF library. + { MP_ROM_QSTR(MP_QSTR_PUBLIC), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_ROM_INT(3) }, + +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_address_locals_dict, bleio_address_locals_dict_table); + +const mp_obj_type_t bleio_address_type = { + { &mp_type_type }, + .name = MP_QSTR_Address, + .make_new = bleio_address_make_new, + .print = bleio_address_print, + .binary_op = bleio_address_binary_op, + .locals_dict = (mp_obj_dict_t*)&bleio_address_locals_dict +}; diff --git a/shared-bindings/_bleio/Address.h b/shared-bindings/_bleio/Address.h new file mode 100644 index 000000000..98b6f80e0 --- /dev/null +++ b/shared-bindings/_bleio/Address.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H + +#include "py/objtype.h" +#include "shared-module/_bleio/Address.h" + +#define BLEIO_ADDRESS_TYPE_PUBLIC (0) +#define BLEIO_ADDRESS_TYPE_RANDOM_STATIC (1) +#define BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE (2) +#define BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE (3) + +#define BLEIO_ADDRESS_TYPE_MIN BLEIO_ADDRESS_TYPE_PUBLIC +#define BLEIO_ADDRESS_TYPE_MAX BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE + +extern const mp_obj_type_t bleio_address_type; + +extern void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type); +extern mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self); +extern uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H diff --git a/shared-bindings/_bleio/Attribute.c b/shared-bindings/_bleio/Attribute.c new file mode 100644 index 000000000..2d8b15b9f --- /dev/null +++ b/shared-bindings/_bleio/Attribute.c @@ -0,0 +1,94 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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 "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/UUID.h" + +// + +//| .. currentmodule:: _bleio +//| +//| :class:`Attribute` -- BLE Attribute +//| ========================================================= +//| +//| Definitions associated with all BLE attributes: characteristics, descriptors, etc. +//| :py:class:`~_bleio.Attribute` is, notionally, a superclass of +//| :py:class:`~Characteristic` and :py:class:`~Descriptor`, +//| but is not defined as a Python superclass of those classes. +//| +//| .. class:: Attribute() +//| +//| You cannot create an instance of :py:class:`~_bleio.Attribute`. +//| + +STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = { + +//| .. data:: NO_ACCESS +//| +//| security mode: access not allowed +//| +//| .. data:: OPEN +//| +//| security_mode: no security (link is not encrypted) +//| +//| .. data:: ENCRYPT_NO_MITM +//| +//| security_mode: unauthenticated encryption, without man-in-the-middle protection +//| +//| .. data:: ENCRYPT_WITH_MITM +//| +//| security_mode: authenticated encryption, with man-in-the-middle protection +//| +//| .. data:: LESC_ENCRYPT_WITH_MITM +//| +//| security_mode: LESC encryption, with man-in-the-middle protection +//| +//| .. data:: SIGNED_NO_MITM +//| +//| security_mode: unauthenticated data signing, without man-in-the-middle protection +//| +//| .. data:: SIGNED_WITH_MITM +//| +//| security_mode: authenticated data signing, without man-in-the-middle protection +//| + { MP_ROM_QSTR(MP_QSTR_NO_ACCESS), MP_ROM_INT(SECURITY_MODE_NO_ACCESS) }, + { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SECURITY_MODE_OPEN) }, + { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SECURITY_MODE_ENC_NO_MITM) }, + { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_ENC_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_LESC_ENC_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_NO_MITM) }, + { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_WITH_MITM) }, + +}; +STATIC MP_DEFINE_CONST_DICT(bleio_attribute_locals_dict, bleio_attribute_locals_dict_table); + +const mp_obj_type_t bleio_attribute_type = { + { &mp_type_type }, + .name = MP_QSTR_Attribute, + .locals_dict = (mp_obj_dict_t*)&bleio_attribute_locals_dict, +}; diff --git a/shared-bindings/_bleio/Attribute.h b/shared-bindings/_bleio/Attribute.h new file mode 100644 index 000000000..a0ce04500 --- /dev/null +++ b/shared-bindings/_bleio/Attribute.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H + +#include "py/obj.h" + +#include "common-hal/_bleio/Attribute.h" +#include "shared-module/_bleio/Attribute.h" + +extern const mp_obj_type_t bleio_attribute_type; + +extern void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H diff --git a/shared-bindings/_bleio/Central.c b/shared-bindings/_bleio/Central.c new file mode 100644 index 000000000..084f40cd6 --- /dev/null +++ b/shared-bindings/_bleio/Central.c @@ -0,0 +1,207 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 +#include + +#include "ble_drv.h" +#include "py/objarray.h" +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Central.h" +#include "shared-bindings/_bleio/Service.h" + +//| .. currentmodule:: _bleio +//| +//| :class:`Central` -- A BLE central device +//| ========================================================= +//| +//| Implement a BLE central, which runs locally. Can connect to a given address. +//| +//| Usage:: +//| +//| import _bleio +//| +//| scanner = _bleio.Scanner() +//| entries = scanner.scan(2.5) +//| +//| my_entry = None +//| for entry in entries: +//| if entry.name is not None and entry.name == 'InterestingPeripheral': +//| my_entry = entry +//| break +//| +//| if not my_entry: +//| raise Exception("'InterestingPeripheral' not found") +//| +//| central = _bleio.Central() +//| central.connect(my_entry.address, 10) # timeout after 10 seconds +//| remote_services = central.discover_remote_services() +//| + +//| .. class:: Central() +//| +//| Create a new Central object. +//| +STATIC mp_obj_t bleio_central_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 0, 0, false); + + bleio_central_obj_t *self = m_new_obj(bleio_central_obj_t); + self->base.type = &bleio_central_type; + + common_hal_bleio_central_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: connect(address, timeout, *, service_uuids_whitelist=None) +//| Attempts a connection to the remote peripheral. +//| +//| :param Address address: The address of the peripheral to connect to +//| :param float/int timeout: Try to connect for timeout seconds. +//| +STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_address, ARG_timeout, ARG_service_uuids_whitelist }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (!MP_OBJ_IS_TYPE(args[ARG_address].u_obj, &bleio_address_type)) { + mp_raise_ValueError(translate("Expected an Address")); + } + + bleio_address_obj_t *address = MP_OBJ_TO_PTR(args[ARG_address].u_obj); + mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + + // common_hal_bleio_central_connect() will validate that services is an iterable or None. + common_hal_bleio_central_connect(self, address, timeout); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_connect_obj, 3, bleio_central_connect); + + +//| .. method:: disconnect() +//| +//| Disconnects from the remote peripheral. +//| +STATIC mp_obj_t bleio_central_disconnect(mp_obj_t self_in) { + bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_central_disconnect(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_disconnect); + +//| .. method:: discover_remote_services(service_uuids_whitelist=None) +//| Do BLE discovery for all services or for the given service UUIDS, +//| to find their handles and characteristics, and return the discovered services. +//| `Peripheral.connected` must be True. +//| +//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services +//| provided by the peripheral that you want to use. +//| The peripheral may provide more services, but services not listed are ignored +//| and will not be returned. +//| +//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. +//| +//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you +//| you must have already created a :py:class:~`UUID` object for that UUID in order for the +//| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered +//| for use. (This restriction may be lifted in the future.) +//| +//| :return: A tuple of services provided by the remote peripheral. +//| +STATIC mp_obj_t bleio_central_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_service_uuids_whitelist }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (!common_hal_bleio_central_get_connected(self)) { + mp_raise_ValueError(translate("Not connected")); + } + + return MP_OBJ_FROM_PTR(common_hal_bleio_central_discover_remote_services( + MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_discover_remote_services_obj, 1, bleio_central_discover_remote_services); + +//| .. attribute:: connected +//| +//| True if connected to a remove peripheral. +//| +STATIC mp_obj_t bleio_central_get_connected(mp_obj_t self_in) { + bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_bleio_central_get_connected(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_get_connected_obj, bleio_central_get_connected); + +const mp_obj_property_t bleio_central_connected_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_central_get_connected_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_central_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_central_discover_remote_services_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_central_connected_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_central_locals_dict, bleio_central_locals_dict_table); + +const mp_obj_type_t bleio_central_type = { + { &mp_type_type }, + .name = MP_QSTR_Central, + .make_new = bleio_central_make_new, + .locals_dict = (mp_obj_dict_t*)&bleio_central_locals_dict +}; diff --git a/shared-bindings/_bleio/Central.h b/shared-bindings/_bleio/Central.h new file mode 100644 index 000000000..85d788654 --- /dev/null +++ b/shared-bindings/_bleio/Central.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H + +#include "py/objtuple.h" +#include "common-hal/_bleio/Central.h" +#include "common-hal/_bleio/Service.h" + +extern const mp_obj_type_t bleio_central_type; + +extern void common_hal_bleio_central_construct(bleio_central_obj_t *self); +extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout); +extern void common_hal_bleio_central_disconnect(bleio_central_obj_t *self); +extern bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self); +extern mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c new file mode 100644 index 000000000..198155589 --- /dev/null +++ b/shared-bindings/_bleio/Characteristic.c @@ -0,0 +1,341 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * 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 "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" + +//| .. currentmodule:: _bleio +//| +//| :class:`Characteristic` -- BLE service characteristic +//| ========================================================= +//| +//| Stores information about a BLE service characteristic and allows reading +//| and writing of the characteristic's value. +//| +//| .. class:: Characteristic +//| +//| There is no regular constructor for a Characteristic. A new local Characteristic can be created +//| and attached to a Service by calling `add_to_service()`. +//| Remote Characteristic objects are created by `Central.discover_remote_services()` +//| or `Peripheral.discover_remote_services()` as part of remote Services. +//| + +//| .. method:: add_to_service(service, uuid, *, properties=0, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, initial_value=None) +//| +//| Create a new Characteristic object, and add it to this Service. +//| +//| :param Service service: The service that will provide this characteristic +//| :param UUID uuid: The uuid of the characteristic +//| :param int properties: The properties of the characteristic, +//| specified as a bitmask of these values bitwise-or'd together: +//| `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`. +//| :param int read_perm: Specifies whether the characteristic can be read by a client, and if so, which +//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, +//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, +//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`. +//| :param int write_perm: Specifies whether the characteristic can be written by a client, and if so, which +//| security mode is required. Values allowed are the same as ``read_perm``. +//| :param int max_length: Maximum length in bytes of the characteristic value. The maximum allowed is +//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum +//| number of data bytes that fit in a single BLE 4.x ATT packet. +//| :param bool fixed_length: True if the characteristic value is of fixed length. +//| :param buf initial_value: The initial value for this characteristic. If not given, will be +//| filled with zeros. +//| +//| :return: the new Characteristic. +//| +STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // class is arg[0], which we can ignore. + + enum { ARG_service, ARG_uuid, ARG_properties, ARG_read_perm, ARG_write_perm, + ARG_max_length, ARG_fixed_length, ARG_initial_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_service, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_properties, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, + { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, + { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} }, + { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_initial_value, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_t service_obj = args[ARG_service].u_obj; + if (!MP_OBJ_IS_TYPE(service_obj, &bleio_service_type)) { + mp_raise_ValueError(translate("Expected a Service")); + } + + const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + mp_raise_ValueError(translate("Expected a UUID")); + } + + const bleio_characteristic_properties_t properties = args[ARG_properties].u_int; + if (properties & ~CHAR_PROP_ALL) { + mp_raise_ValueError(translate("Invalid properties")); + } + + const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int; + common_hal_bleio_attribute_security_mode_check_valid(read_perm); + + const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; + common_hal_bleio_attribute_security_mode_check_valid(write_perm); + + const mp_int_t max_length = args[ARG_max_length].u_int; + const bool fixed_length = args[ARG_fixed_length].u_bool; + mp_obj_t initial_value = args[ARG_initial_value].u_obj; + + // Length will be validated in common_hal. + mp_buffer_info_t initial_value_bufinfo; + if (initial_value == mp_const_none) { + if (fixed_length && max_length > 0) { + initial_value = mp_obj_new_bytes_of_zeros(max_length); + } else { + initial_value = mp_const_empty_bytes; + } + } + mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); + + bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); + characteristic->base.type = &bleio_characteristic_type; + + // Range checking on max_length arg is done by the common_hal layer, because + // it may vary depending on underlying BLE implementation. + common_hal_bleio_characteristic_construct( + characteristic, MP_OBJ_TO_PTR(service_obj), MP_OBJ_TO_PTR(uuid_obj), + properties, read_perm, write_perm, + max_length, fixed_length, &initial_value_bufinfo); + + common_hal_bleio_service_add_characteristic(service_obj, characteristic); + + return MP_OBJ_FROM_PTR(characteristic); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_add_to_service_fun_obj, 3, bleio_characteristic_add_to_service); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_characteristic_add_to_service_obj, MP_ROM_PTR(&bleio_characteristic_add_to_service_fun_obj)); + + + +//| .. attribute:: properties +//| +//| An int bitmask representing which properties are set, specified as bitwise or'ing of +//| of these possible values. +//| `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`. +//| +STATIC mp_obj_t bleio_characteristic_get_properties(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_properties(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_properties_obj, bleio_characteristic_get_properties); + +const mp_obj_property_t bleio_characteristic_properties_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_properties_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: uuid +//| +//| The UUID of this characteristic. (read-only) +//| Will be ``None`` if the 128-bit UUID for this characteristic is not known. +//| +STATIC mp_obj_t bleio_characteristic_get_uuid(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + bleio_uuid_obj_t *uuid = common_hal_bleio_characteristic_get_uuid(self); + return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_uuid_obj, bleio_characteristic_get_uuid); + +const mp_obj_property_t bleio_characteristic_uuid_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_uuid_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: value +//| +//| The value of this characteristic. +//| +STATIC mp_obj_t bleio_characteristic_get_value(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_characteristic_get_value(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_value_obj, bleio_characteristic_get_value); + +STATIC mp_obj_t bleio_characteristic_set_value(mp_obj_t self_in, mp_obj_t value_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ); + + common_hal_bleio_characteristic_set_value(self, &bufinfo); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_value_obj, bleio_characteristic_set_value); + +const mp_obj_property_t bleio_characteristic_value_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_value_obj, + (mp_obj_t)&bleio_characteristic_set_value_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: descriptors +//| +//| A tuple of :py:class:`Descriptor` that describe this characteristic. (read-only) +//| +STATIC mp_obj_t bleio_characteristic_get_descriptors(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + // Return list as a tuple so user won't be able to change it. + mp_obj_list_t *char_list = common_hal_bleio_characteristic_get_descriptor_list(self); + return mp_obj_new_tuple(char_list->len, char_list->items); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_descriptors_obj, bleio_characteristic_get_descriptors); + +const mp_obj_property_t bleio_characteristic_descriptors_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_descriptors_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: service (read-only) +//| +//| The Service this Characteristic is a part of. +//| +STATIC mp_obj_t bleio_characteristic_get_service(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_characteristic_get_service(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_service_obj, bleio_characteristic_get_service); + +const mp_obj_property_t bleio_characteristic_service_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_service_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. method:: set_cccd(*, notify=False, indicate=False) +//| +//| Set the remote characteristic's CCCD to enable or disable notification and indication. +//| +//| :param bool notify: True if Characteristic should receive notifications of remote writes +//| :param float indicate: True if Characteristic should receive indications of remote writes +//| +STATIC mp_obj_t bleio_characteristic_set_cccd(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_notify, ARG_indicate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_notify, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_indicate, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_bleio_characteristic_set_cccd(self, args[ARG_notify].u_bool, args[ARG_indicate].u_bool); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_characteristic_set_cccd); + + +STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_add_to_service), MP_ROM_PTR(&bleio_characteristic_add_to_service_obj) }, + { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_get_properties_obj) }, + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_characteristic_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_obj) }, + + // Bitmask constants to represent properties +//| .. data:: BROADCAST +//| +//| property: allowed in advertising packets +//| +//| .. data:: INDICATE +//| +//| property: server will indicate to the client when the value is set and wait for a response +//| +//| .. data:: NOTIFY +//| +//| property: server will notify the client when the value is set +//| +//| .. data:: READ +//| +//| property: clients may read this characteristic +//| +//| .. data:: WRITE +//| +//| property: clients may write this characteristic; a response will be sent back +//| +//| .. data:: WRITE_NO_RESPONSE +//| +//| property: clients may write this characteristic; no response will be sent back +//| + { MP_ROM_QSTR(MP_QSTR_BROADCAST), MP_ROM_INT(CHAR_PROP_BROADCAST) }, + { MP_ROM_QSTR(MP_QSTR_INDICATE), MP_ROM_INT(CHAR_PROP_INDICATE) }, + { MP_ROM_QSTR(MP_QSTR_NOTIFY), MP_ROM_INT(CHAR_PROP_NOTIFY) }, + { MP_ROM_QSTR(MP_QSTR_READ), MP_ROM_INT(CHAR_PROP_READ) }, + { MP_ROM_QSTR(MP_QSTR_WRITE), MP_ROM_INT(CHAR_PROP_WRITE) }, + { MP_ROM_QSTR(MP_QSTR_WRITE_NO_RESPONSE), MP_ROM_INT(CHAR_PROP_WRITE_NO_RESPONSE) }, + +}; +STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_locals_dict, bleio_characteristic_locals_dict_table); + +STATIC void bleio_characteristic_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->uuid) { + mp_printf(print, "Characteristic("); + bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); + mp_printf(print, ")"); + } else { + mp_printf(print, ""); + } +} + +const mp_obj_type_t bleio_characteristic_type = { + { &mp_type_type }, + .name = MP_QSTR_Characteristic, + .print = bleio_characteristic_print, + .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict, +}; diff --git a/shared-bindings/_bleio/Characteristic.h b/shared-bindings/_bleio/Characteristic.h new file mode 100644 index 000000000..a816c6050 --- /dev/null +++ b/shared-bindings/_bleio/Characteristic.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H + +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-module/_bleio/Characteristic.h" +#include "common-hal/_bleio/Characteristic.h" +#include "common-hal/_bleio/Service.h" + +extern const mp_obj_type_t bleio_characteristic_type; + +extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo); +extern mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self); +extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); +extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self); +extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self); +extern mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self); +extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self); +extern void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor); +extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H diff --git a/shared-bindings/_bleio/CharacteristicBuffer.c b/shared-bindings/_bleio/CharacteristicBuffer.c new file mode 100644 index 000000000..9cc708eb7 --- /dev/null +++ b/shared-bindings/_bleio/CharacteristicBuffer.c @@ -0,0 +1,252 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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 "py/mperrno.h" +#include "py/ioctl.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include "shared-bindings/_bleio/CharacteristicBuffer.h" +#include "shared-bindings/_bleio/UUID.h" +#include "shared-bindings/util.h" + +STATIC void raise_error_if_not_connected(bleio_characteristic_buffer_obj_t *self) { + if (!common_hal_bleio_characteristic_buffer_connected(self)) { + mp_raise_ValueError(translate("Not connected")); + } +} + +//| .. currentmodule:: _bleio +//| +//| :class:`CharacteristicBuffer` -- BLE Service incoming values buffer. +//| ===================================================================== +//| +//| Accumulates a Characteristic's incoming values in a FIFO buffer. +//| +//| .. class:: CharacteristicBuffer(characteristic, *, timeout=1, buffer_size=64) +//| +//| Monitor the given Characteristic. Each time a new value is written to the Characteristic +//| add the newly-written bytes to a FIFO buffer. +//| +//| :param Characteristic characteristic: The Characteristic to monitor. +//| It may be a local Characteristic provided by a Peripheral Service, or a remote Characteristic +//| in a remote Service that a Central has connected to. +//| :param int timeout: the timeout in seconds to wait for the first character and between subsequent characters. +//| :param int buffer_size: Size of ring buffer that stores incoming data coming from client. +//| Must be >= 1. +//| +STATIC mp_obj_t bleio_characteristic_buffer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_characteristic, ARG_timeout, ARG_buffer_size, }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_characteristic, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, + { MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_t characteristic = args[ARG_characteristic].u_obj; + + mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + if (timeout < 0.0f) { + mp_raise_ValueError(translate("timeout must be >= 0.0")); + } + + const int buffer_size = args[ARG_buffer_size].u_int; + if (buffer_size < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_buffer_size); + } + + if (!MP_OBJ_IS_TYPE(characteristic, &bleio_characteristic_type)) { + mp_raise_ValueError(translate("Expected a Characteristic")); + } + + bleio_characteristic_buffer_obj_t *self = m_new_obj(bleio_characteristic_buffer_obj_t); + self->base.type = &bleio_characteristic_buffer_type; + + common_hal_bleio_characteristic_buffer_construct(self, MP_OBJ_TO_PTR(characteristic), timeout, buffer_size); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC void check_for_deinit(bleio_characteristic_buffer_obj_t *self) { + if (common_hal_bleio_characteristic_buffer_deinited(self)) { + raise_deinited_error(); + } +} + +// These are standard stream methods. Code is in py/stream.c. +// +//| .. method:: read(nbytes=None) +//| +//| Read characters. If ``nbytes`` is specified then read at most that many +//| bytes. Otherwise, read everything that arrives until the connection +//| times out. Providing the number of bytes expected is highly recommended +//| because it will be faster. +//| +//| :return: Data read +//| :rtype: bytes or None +//| +//| .. method:: readinto(buf) +//| +//| Read bytes into the ``buf``. Read at most ``len(buf)`` bytes. +//| +//| :return: number of bytes read and stored into ``buf`` +//| :rtype: int or None (on a non-blocking error) +//| +//| .. method:: readline() +//| +//| Read a line, ending in a newline character. +//| +//| :return: the line read +//| :rtype: int or None +//| + +// These three methods are used by the shared stream methods. +STATIC mp_uint_t bleio_characteristic_buffer_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + raise_error_if_not_connected(self); + byte *buf = buf_in; + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + return common_hal_bleio_characteristic_buffer_read(self, buf, size, errcode); +} + +STATIC mp_uint_t bleio_characteristic_buffer_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + mp_raise_NotImplementedError(translate("CharacteristicBuffer writing not provided")); + return 0; +} + +STATIC mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + raise_error_if_not_connected(self); + if (!common_hal_bleio_characteristic_buffer_connected(self)) { + mp_raise_ValueError(translate("Not connected")); + } + mp_uint_t ret; + if (request == MP_IOCTL_POLL) { + mp_uint_t flags = arg; + ret = 0; + if ((flags & MP_IOCTL_POLL_RD) && common_hal_bleio_characteristic_buffer_rx_characters_available(self) > 0) { + ret |= MP_IOCTL_POLL_RD; + } +// No writing provided. +// if ((flags & MP_IOCTL_POLL_WR) && common_hal_busio_uart_ready_to_tx(self)) { +// ret |= MP_IOCTL_POLL_WR; +// } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +//| .. attribute:: in_waiting +//| +//| The number of bytes in the input buffer, available to be read +//| +STATIC mp_obj_t bleio_characteristic_buffer_obj_get_in_waiting(mp_obj_t self_in) { + bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_buffer_rx_characters_available(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_get_in_waiting_obj, bleio_characteristic_buffer_obj_get_in_waiting); + +const mp_obj_property_t bleio_characteristic_buffer_in_waiting_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&bleio_characteristic_buffer_get_in_waiting_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. method:: reset_input_buffer() +//| +//| Discard any unread characters in the input buffer. +//| +STATIC mp_obj_t bleio_characteristic_buffer_obj_reset_input_buffer(mp_obj_t self_in) { + bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_bleio_characteristic_buffer_clear_rx_buffer(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_reset_input_buffer_obj, bleio_characteristic_buffer_obj_reset_input_buffer); + +//| .. method:: deinit() +//| +//| Disable permanently. +//| +STATIC mp_obj_t bleio_characteristic_buffer_deinit(mp_obj_t self_in) { + bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_bleio_characteristic_buffer_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_deinit_obj, bleio_characteristic_buffer_deinit); + +STATIC const mp_rom_map_elem_t bleio_characteristic_buffer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bleio_characteristic_buffer_deinit_obj) }, + + // Standard stream methods. + { MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + // CharacteristicBuffer is currently read-only. + // { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&bleio_characteristic_buffer_reset_input_buffer_obj) }, + // Properties + { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&bleio_characteristic_buffer_in_waiting_obj) }, + +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_buffer_locals_dict, bleio_characteristic_buffer_locals_dict_table); + +STATIC const mp_stream_p_t characteristic_buffer_stream_p = { + .read = bleio_characteristic_buffer_read, + .write = bleio_characteristic_buffer_write, + .ioctl = bleio_characteristic_buffer_ioctl, + .is_text = false, + // Match PySerial when possible, such as disallowing optional length argument for .readinto() + .pyserial_compatibility = true, +}; + + +const mp_obj_type_t bleio_characteristic_buffer_type = { + { &mp_type_type }, + .name = MP_QSTR_CharacteristicBuffer, + .make_new = bleio_characteristic_buffer_make_new, + .getiter = mp_identity_getiter, + .iternext = mp_stream_unbuffered_iter, + .protocol = &characteristic_buffer_stream_p, + .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_buffer_locals_dict +}; diff --git a/shared-bindings/_bleio/CharacteristicBuffer.h b/shared-bindings/_bleio/CharacteristicBuffer.h new file mode 100644 index 000000000..83e6fef02 --- /dev/null +++ b/shared-bindings/_bleio/CharacteristicBuffer.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H + +#include "common-hal/_bleio/CharacteristicBuffer.h" + +extern const mp_obj_type_t bleio_characteristic_buffer_type; + +extern void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_float_t timeout, size_t buffer_size); +int common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode); +uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self); +void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self); +bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self); +int common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self); +bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H diff --git a/shared-bindings/_bleio/Descriptor.c b/shared-bindings/_bleio/Descriptor.c new file mode 100644 index 000000000..0ab9fe8e9 --- /dev/null +++ b/shared-bindings/_bleio/Descriptor.c @@ -0,0 +1,231 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * 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 "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/UUID.h" + +//| .. currentmodule:: _bleio +//| +//| :class:`Descriptor` -- BLE descriptor +//| ========================================================= +//| +//| Stores information about a BLE descriptor. +//| Descriptors are attached to BLE characteristics and provide contextual +//| information about the characteristic. +//| +//| .. class:: Descriptor +//| +//| There is no regular constructor for a Descriptor. A new local Descriptor can be created +//| and attached to a Characteristic by calling `add_to_characteristic()`. +//| Remote Descriptor objects are created by `Central.discover_remote_services()` +//| or `Peripheral.discover_remote_services()` as part of remote Characteristics +//| in the remote Services that are discovered. +//| +//| .. classmethod:: add_to_characteristic(characteristic, uuid, *, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, initial_value=b'') +//| +//| Create a new Descriptor object, and add it to this Service. +//| +//| :param Characteristic characteristic: The characteristic that will hold this descriptor +//| :param UUID uuid: The uuid of the descriptor +//| :param int read_perm: Specifies whether the descriptor can be read by a client, and if so, which +//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, +//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, +//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`. +//| :param int write_perm: Specifies whether the descriptor can be written by a client, and if so, which +//| security mode is required. Values allowed are the same as ``read_perm``. +//| :param int max_length: Maximum length in bytes of the descriptor value. The maximum allowed is +//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum +//| number of data bytes that fit in a single BLE 4.x ATT packet. +//| :param bool fixed_length: True if the descriptor value is of fixed length. +//| :param buf initial_value: The initial value for this descriptor. +//| +//| :return: the new Descriptor. +//| +STATIC mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // class is arg[0], which we can ignore. + + enum { ARG_characteristic, ARG_uuid, ARG_read_perm, ARG_write_perm, + ARG_max_length, ARG_fixed_length, ARG_initial_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_characteristic, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, + { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, + { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} }, + { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_initial_value, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_t characteristic_obj = args[ARG_characteristic].u_obj; + if (!MP_OBJ_IS_TYPE(characteristic_obj, &bleio_characteristic_type)) { + mp_raise_ValueError(translate("Expected a Characteristic")); + } + + const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + mp_raise_ValueError(translate("Expected a UUID")); + } + + const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int; + common_hal_bleio_attribute_security_mode_check_valid(read_perm); + + const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; + common_hal_bleio_attribute_security_mode_check_valid(write_perm); + + const mp_int_t max_length = args[ARG_max_length].u_int; + const bool fixed_length = args[ARG_fixed_length].u_bool; + mp_obj_t initial_value = args[ARG_initial_value].u_obj; + + // Length will be validated in common_hal. + mp_buffer_info_t initial_value_bufinfo; + if (initial_value == mp_const_none) { + if (fixed_length && max_length > 0) { + initial_value = mp_obj_new_bytes_of_zeros(max_length); + } else { + initial_value = mp_const_empty_bytes; + } + } + mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); + + bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); + descriptor->base.type = &bleio_descriptor_type; + + // Range checking on max_length arg is done by the common_hal layer, because + // it may vary depending on underlying BLE implementation. + common_hal_bleio_descriptor_construct( + descriptor, MP_OBJ_TO_PTR(characteristic_obj), MP_OBJ_TO_PTR(uuid_obj), + read_perm, write_perm, + max_length, fixed_length, &initial_value_bufinfo); + + common_hal_bleio_characteristic_add_descriptor(characteristic_obj, descriptor); + + return MP_OBJ_FROM_PTR(descriptor); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_descriptor_add_to_characteristic_fun_obj, 3, bleio_descriptor_add_to_characteristic); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_descriptor_add_to_characteristic_obj, MP_ROM_PTR(&bleio_descriptor_add_to_characteristic_fun_obj)); + +//| .. attribute:: uuid +//| +//| The descriptor uuid. (read-only) +//| +STATIC mp_obj_t bleio_descriptor_get_uuid(mp_obj_t self_in) { + bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); + + bleio_uuid_obj_t *uuid = common_hal_bleio_descriptor_get_uuid(self); + return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_uuid_obj, bleio_descriptor_get_uuid); + +const mp_obj_property_t bleio_descriptor_uuid_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&bleio_descriptor_get_uuid_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: characteristic (read-only) +//| +//| The Characteristic this Descriptor is a part of. +//| +STATIC mp_obj_t bleio_descriptor_get_characteristic(mp_obj_t self_in) { + bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_descriptor_get_characteristic(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_characteristic_obj, bleio_descriptor_get_characteristic); + +const mp_obj_property_t bleio_descriptor_characteristic_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_descriptor_get_characteristic_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: value +//| +//| The value of this descriptor. +//| +STATIC mp_obj_t bleio_descriptor_get_value(mp_obj_t self_in) { + bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_descriptor_get_value(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_value_obj, bleio_descriptor_get_value); + +STATIC mp_obj_t bleio_descriptor_set_value(mp_obj_t self_in, mp_obj_t value_in) { + bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ); + + common_hal_bleio_descriptor_set_value(self, &bufinfo); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_descriptor_set_value_obj, bleio_descriptor_set_value); + +const mp_obj_property_t bleio_descriptor_value_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_descriptor_get_value_obj, + (mp_obj_t)&bleio_descriptor_set_value_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_add_to_characteristic), MP_ROM_PTR(&bleio_descriptor_add_to_characteristic_obj) }, + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_descriptor_uuid_obj) }, + { MP_ROM_QSTR(MP_QSTR_characteristic), MP_ROM_PTR(&bleio_descriptor_characteristic_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_descriptor_value_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_descriptor_locals_dict, bleio_descriptor_locals_dict_table); + +STATIC void bleio_descriptor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->uuid) { + mp_printf(print, "Descriptor("); + bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); + mp_printf(print, ")"); + } else { + mp_printf(print, ""); + } +} + +const mp_obj_type_t bleio_descriptor_type = { + { &mp_type_type }, + .name = MP_QSTR_Descriptor, + .print = bleio_descriptor_print, + .locals_dict = (mp_obj_dict_t*)&bleio_descriptor_locals_dict +}; diff --git a/shared-bindings/_bleio/Descriptor.h b/shared-bindings/_bleio/Descriptor.h new file mode 100644 index 000000000..7544bdb17 --- /dev/null +++ b/shared-bindings/_bleio/Descriptor.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H + +#include "shared-module/_bleio/Attribute.h" +#include "common-hal/_bleio/Characteristic.h" +#include "common-hal/_bleio/Descriptor.h" +#include "common-hal/_bleio/UUID.h" + +extern const mp_obj_type_t bleio_descriptor_type; + +extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo); +extern bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self); +extern bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self); +extern mp_obj_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self); +extern void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H diff --git a/shared-bindings/_bleio/Peripheral.c b/shared-bindings/_bleio/Peripheral.c new file mode 100644 index 000000000..0bf292744 --- /dev/null +++ b/shared-bindings/_bleio/Peripheral.c @@ -0,0 +1,325 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 +#include + +#include "ble_drv.h" +#include "py/objarray.h" +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/runtime.h" + +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Peripheral.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" +#include "shared-module/_bleio/ScanEntry.h" + +#include "common-hal/_bleio/Peripheral.h" + +#define ADV_INTERVAL_MIN (0.0020f) +#define ADV_INTERVAL_MIN_STRING "0.0020" +#define ADV_INTERVAL_MAX (10.24f) +#define ADV_INTERVAL_MAX_STRING "10.24" +// 20ms is recommended by Apple +#define ADV_INTERVAL_DEFAULT (0.1f) + +//| .. currentmodule:: _bleio +//| +//| :class:`Peripheral` -- A BLE peripheral device +//| ========================================================= +//| +//| Implement a BLE peripheral which runs locally. +//| Set up using the supplied services, and then allow advertising to be started and stopped. +//| +//| Usage:: +//| +//| from _bleio import Characteristic, Peripheral, Service +//| from adafruit_ble.advertising import ServerAdvertisement +//| +//| # Create a peripheral and start it up. +//| peripheral = _bleio.Peripheral() +//| +//| # Create a Service and add it to this Peripheral. +//| service = Service.add_to_peripheral(peripheral, _bleio.UUID(0x180f)) +//| +//| # Create a Characteristic and add it to the Service. +//| characteristic = Characteristic.add_to_service(service, +//| _bleio.UUID(0x2919), properties=Characteristic.READ | Characteristic.NOTIFY) +//| +//| adv = ServerAdvertisement(peripheral) +//| peripheral.start_advertising(adv.advertising_data_bytes, scan_response=adv.scan_response_bytes) +//| +//| while not peripheral.connected: +//| # Wait for connection. +//| pass +//| +//| .. class:: Peripheral(name=None) +//| +//| Create a new Peripheral object. +//| +//| :param str name: The name used when advertising this peripheral. If name is None, +//| _bleio.adapter.default_name will be used. +//| +STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_name }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_name, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + bleio_peripheral_obj_t *self = m_new_obj(bleio_peripheral_obj_t); + self->base.type = &bleio_peripheral_type; + + mp_obj_t name = args[ARG_name].u_obj; + if (name == mp_const_none) { + name = common_hal_bleio_adapter_get_default_name(); + } else if (!MP_OBJ_IS_STR(name)) { + mp_raise_ValueError(translate("name must be a string")); + } + + common_hal_bleio_peripheral_construct(self, name); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. attribute:: connected (read-only) +//| +//| True if connected to a BLE Central device. +//| +STATIC mp_obj_t bleio_peripheral_get_connected(mp_obj_t self_in) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_bleio_peripheral_get_connected(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_connected_obj, bleio_peripheral_get_connected); + +const mp_obj_property_t bleio_peripheral_connected_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_peripheral_get_connected_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: services +//| +//| A tuple of :py:class:`Service` objects offered by this peripheral. (read-only) +//| +STATIC mp_obj_t bleio_peripheral_get_services(mp_obj_t self_in) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + // Return list as a tuple so user won't be able to change it. + mp_obj_list_t *services_list = common_hal_bleio_peripheral_get_services(self); + return mp_obj_new_tuple(services_list->len, services_list->items); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_services_obj, bleio_peripheral_get_services); + +const mp_obj_property_t bleio_peripheral_services_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_peripheral_get_services_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: name +//| +//| The peripheral's name, included when advertising. (read-only) +//| +STATIC mp_obj_t bleio_peripheral_get_name(mp_obj_t self_in) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_peripheral_get_name(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_name_obj, bleio_peripheral_get_name); + +const mp_obj_property_t bleio_peripheral_name_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_peripheral_get_name_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. method:: start_advertising(data, *, scan_response=None, connectable=True, interval=0.1) +//| +//| Starts advertising the peripheral. The peripheral's name and +//| services are included in the advertisement packets. +//| +//| :param buf data: advertising data packet bytes +//| :param buf scan_response: scan response data packet bytes. ``None`` if no scan response is needed. +//| :param bool connectable: If `True` then other devices are allowed to connect to this peripheral. +//| :param float interval: advertising interval, in seconds +//| +STATIC mp_obj_t bleio_peripheral_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_data, ARG_scan_response, ARG_connectable, ARG_interval }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scan_response, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t data_bufinfo; + mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ); + + // Pass an empty buffer if scan_response not provided. + mp_buffer_info_t scan_response_bufinfo = { 0 }; + if (args[ARG_scan_response].u_obj != mp_const_none) { + mp_get_buffer_raise(args[ARG_scan_response].u_obj, &scan_response_bufinfo, MP_BUFFER_READ); + } + + if (args[ARG_interval].u_obj == MP_OBJ_NULL) { + args[ARG_interval].u_obj = mp_obj_new_float(ADV_INTERVAL_DEFAULT); + } + + const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj); + if (interval < ADV_INTERVAL_MIN || interval > ADV_INTERVAL_MAX) { + mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), + ADV_INTERVAL_MIN_STRING, ADV_INTERVAL_MAX_STRING); + } + + common_hal_bleio_peripheral_start_advertising(self, args[ARG_connectable].u_bool, interval, + &data_bufinfo, &scan_response_bufinfo); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_start_advertising_obj, 2, bleio_peripheral_start_advertising); + +//| .. method:: stop_advertising() +//| +//| Stop sending advertising packets. +STATIC mp_obj_t bleio_peripheral_stop_advertising(mp_obj_t self_in) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_peripheral_stop_advertising(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_stop_advertising_obj, bleio_peripheral_stop_advertising); + +//| .. method:: disconnect() +//| +//| Disconnects from the remote central. +//| Normally the central initiates a disconnection. Use this only +//| if necessary for your application. +//| +STATIC mp_obj_t bleio_peripheral_disconnect(mp_obj_t self_in) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_peripheral_disconnect(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripheral_disconnect); + +//| .. method:: discover_remote_services(service_uuids_whitelist=None) +//| Do BLE discovery for all services or for the given service UUIDS, +//| to find their handles and characteristics, and return the discovered services. +//| `Peripheral.connected` must be True. +//| +//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services +//| provided by the peripheral that you want to use. +//| The peripheral may provide more services, but services not listed are ignored +//| and will not be returned. +//| +//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. +//| +//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you +//| you must have already created a :py:class:~`UUID` object for that UUID in order for the +//| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered +//| for use. (This restriction may be lifted in the future.) +//| +//| Thought it is unusual for a peripheral to act as a BLE client, it can do so, and +//| needs to be able to do discovery on its peer (a central). +//| Examples include a peripheral accessing a central that provides Current Time Service, +//| Apple Notification Center Service, or Battery Service. +//| +//| :return: A tuple of services provided by the remote central. +//| +STATIC mp_obj_t bleio_peripheral_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_service_uuids_whitelist }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (!common_hal_bleio_peripheral_get_connected(self)) { + mp_raise_ValueError(translate("Not connected")); + } + + return MP_OBJ_FROM_PTR(common_hal_bleio_peripheral_discover_remote_services( + MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_discover_remote_services_obj, 1, bleio_peripheral_discover_remote_services); + +//| .. method:: pair() +//| +//| Request pairing with connected central. +STATIC mp_obj_t bleio_peripheral_pair(mp_obj_t self_in) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_peripheral_pair(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_pair_obj, bleio_peripheral_pair); + +STATIC const mp_rom_map_elem_t bleio_peripheral_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_peripheral_stop_advertising_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_peripheral_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_peripheral_discover_remote_services_obj) }, + { MP_ROM_QSTR(MP_QSTR_pair), MP_ROM_PTR(&bleio_peripheral_pair_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) }, + { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_peripheral_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_peripheral_locals_dict, bleio_peripheral_locals_dict_table); + +const mp_obj_type_t bleio_peripheral_type = { + { &mp_type_type }, + .name = MP_QSTR_Peripheral, + .make_new = bleio_peripheral_make_new, + .locals_dict = (mp_obj_dict_t*)&bleio_peripheral_locals_dict +}; diff --git a/shared-bindings/_bleio/Peripheral.h b/shared-bindings/_bleio/Peripheral.h new file mode 100644 index 000000000..bc56a9338 --- /dev/null +++ b/shared-bindings/_bleio/Peripheral.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H + +#include "py/objtuple.h" +#include "common-hal/_bleio/Peripheral.h" +#include "common-hal/_bleio/Service.h" + +extern const mp_obj_type_t bleio_peripheral_type; + +extern void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_t name); +extern void common_hal_bleio_peripheral_add_service(bleio_peripheral_obj_t *self, bleio_service_obj_t *service); +extern mp_obj_list_t *common_hal_bleio_peripheral_get_services(bleio_peripheral_obj_t *self); +extern bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self); +extern mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *self); +extern void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *device, bool connectable, float interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo); +extern void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *device); +extern void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *device); +extern mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist); +extern void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *device); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H diff --git a/shared-bindings/_bleio/ScanEntry.c b/shared-bindings/_bleio/ScanEntry.c new file mode 100644 index 000000000..bec380d03 --- /dev/null +++ b/shared-bindings/_bleio/ScanEntry.c @@ -0,0 +1,111 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * 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 + +#include "py/objproperty.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-bindings/_bleio/ScanEntry.h" +#include "shared-bindings/_bleio/UUID.h" +#include "shared-module/_bleio/ScanEntry.h" + +//| .. currentmodule:: _bleio +//| +//| :class:`ScanEntry` -- BLE scan response entry +//| ========================================================= +//| +//| Encapsulates information about a device that was received as a +//| response to a BLE scan request. This object may only be created +//| by a `_bleio.Scanner`: it has no user-visible constructor. +//| + +//| .. attribute:: address +//| +//| The address of the device (read-only), of type `_bleio.Address`. +//| +STATIC mp_obj_t bleio_scanentry_get_address(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_bleio_scanentry_get_address(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_address_obj, bleio_scanentry_get_address); + +const mp_obj_property_t bleio_scanentry_address_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_scanentry_get_address_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: advertisement_bytes +//| +//| All the advertisement data present in the packet, returned as a ``bytes`` object. (read-only) +//| +STATIC mp_obj_t scanentry_get_advertisement_bytes(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_bleio_scanentry_get_advertisement_bytes(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_advertisement_bytes_obj, scanentry_get_advertisement_bytes); + +const mp_obj_property_t bleio_scanentry_advertisement_bytes_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_scanentry_get_advertisement_bytes_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: rssi +//| +//| The signal strength of the device at the time of the scan, in integer dBm. (read-only) +//| +STATIC mp_obj_t scanentry_get_rssi(mp_obj_t self_in) { + bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(common_hal_bleio_scanentry_get_rssi(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_rssi_obj, scanentry_get_rssi); + +const mp_obj_property_t bleio_scanentry_rssi_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_scanentry_get_rssi_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + + +STATIC const mp_rom_map_elem_t bleio_scanentry_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_scanentry_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_advertisement_bytes), MP_ROM_PTR(&bleio_scanentry_advertisement_bytes_obj) }, + { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bleio_scanentry_rssi_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_scanentry_locals_dict, bleio_scanentry_locals_dict_table); + +const mp_obj_type_t bleio_scanentry_type = { + { &mp_type_type }, + .name = MP_QSTR_ScanEntry, + .locals_dict = (mp_obj_dict_t*)&bleio_scanentry_locals_dict +}; diff --git a/shared-bindings/_bleio/ScanEntry.h b/shared-bindings/_bleio/ScanEntry.h new file mode 100644 index 000000000..8af1f050a --- /dev/null +++ b/shared-bindings/_bleio/ScanEntry.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H + +#include "py/obj.h" +#include "shared-module/_bleio/ScanEntry.h" + +extern const mp_obj_type_t bleio_scanentry_type; + +mp_obj_t common_hal_bleio_scanentry_get_address(bleio_scanentry_obj_t *self); +mp_obj_t common_hal_bleio_scanentry_get_advertisement_bytes(bleio_scanentry_obj_t *self); +mp_int_t common_hal_bleio_scanentry_get_rssi(bleio_scanentry_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H diff --git a/shared-bindings/_bleio/Scanner.c b/shared-bindings/_bleio/Scanner.c new file mode 100644 index 000000000..94cec9752 --- /dev/null +++ b/shared-bindings/_bleio/Scanner.c @@ -0,0 +1,129 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/ScanEntry.h" +#include "shared-bindings/_bleio/Scanner.h" + +#define INTERVAL_DEFAULT (0.1f) +#define INTERVAL_MIN (0.0025f) +#define INTERVAL_MIN_STRING "0.0025" +#define INTERVAL_MAX (40.959375f) +#define INTERVAL_MAX_STRING "40.959375" +#define WINDOW_DEFAULT (0.1f) + +//| .. currentmodule:: _bleio +//| +//| :class:`Scanner` -- scan for nearby BLE devices +//| ========================================================= +//| +//| Scan for nearby BLE devices. +//| +//| Usage:: +//| +//| import _bleio +//| scanner = _bleio.Scanner() +//| entries = scanner.scan(2.5) # Scan for 2.5 seconds +//| + +//| .. class:: Scanner() +//| +//| Create a new Scanner object. +//| +STATIC mp_obj_t bleio_scanner_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *all_args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 0, 0, false); + + bleio_scanner_obj_t *self = m_new_obj(bleio_scanner_obj_t); + self->base.type = type; + + common_hal_bleio_scanner_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: scan(timeout, \*, interval=0.1, window=0.1) +//| +//| Performs a BLE scan. +//| +//| :param float timeout: the scan timeout in seconds +//| :param float interval: the interval (in seconds) between the start of two consecutive scan windows +//| Must be in the range 0.0025 - 40.959375 seconds. +//| :param float window: the duration (in seconds) to scan a single BLE channel. +//| window must be <= interval. +//| :returns: an iterable of `ScanEntry` objects +//| :rtype: iterable +//| +STATIC mp_obj_t bleio_scanner_scan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_timeout, ARG_interval, ARG_window }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_window, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + + if (args[ARG_interval].u_obj == MP_OBJ_NULL) { + args[ARG_interval].u_obj = mp_obj_new_float(INTERVAL_DEFAULT); + } + + if (args[ARG_window].u_obj == MP_OBJ_NULL) { + args[ARG_window].u_obj = mp_obj_new_float(WINDOW_DEFAULT); + } + + const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj); + if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { + mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), INTERVAL_MIN_STRING, INTERVAL_MAX_STRING); + } + + const mp_float_t window = mp_obj_float_get(args[ARG_window].u_obj); + if (window > interval) { + mp_raise_ValueError(translate("window must be <= interval")); + } + + return common_hal_bleio_scanner_scan(self, timeout, interval, window); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_scanner_scan_obj, 2, bleio_scanner_scan); + + +STATIC const mp_rom_map_elem_t bleio_scanner_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&bleio_scanner_scan_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_scanner_locals_dict, bleio_scanner_locals_dict_table); + +const mp_obj_type_t bleio_scanner_type = { + { &mp_type_type }, + .name = MP_QSTR_Scanner, + .make_new = bleio_scanner_make_new, + .locals_dict = (mp_obj_dict_t*)&bleio_scanner_locals_dict +}; diff --git a/shared-bindings/_bleio/Scanner.h b/shared-bindings/_bleio/Scanner.h new file mode 100644 index 000000000..cbaa77866 --- /dev/null +++ b/shared-bindings/_bleio/Scanner.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H + +#include "py/objtype.h" +#include "common-hal/_bleio/Scanner.h" + +extern const mp_obj_type_t bleio_scanner_type; + +extern void common_hal_bleio_scanner_construct(bleio_scanner_obj_t *self); +extern mp_obj_t common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_float_t timeout, mp_float_t interval, mp_float_t window); +extern void common_hal_bleio_scanner_stop(bleio_scanner_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H diff --git a/shared-bindings/_bleio/Service.c b/shared-bindings/_bleio/Service.c new file mode 100644 index 000000000..da5633f2a --- /dev/null +++ b/shared-bindings/_bleio/Service.c @@ -0,0 +1,201 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * 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 "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Peripheral.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" + +//| .. currentmodule:: _bleio +//| +//| :class:`Service` -- BLE service +//| ========================================================= +//| +//| Stores information about a BLE service and its characteristics. +//| +//| .. class:: Service +//| +//| There is no regular constructor for a Service. A new local Service can be created +//| and attached to a Peripheral by calling `add_to_peripheral()`. +//| Remote Service objects are created by `Central.discover_remote_services()` +//| or `Peripheral.discover_remote_services()`. +//| +//| .. classmethod:: add_to_peripheral(peripheral, uuid, *, secondary=False) +//| +//| Create a new Service object, identitied by the specified UUID, and add it +//| to the given Peripheral. +//| +//| To mark the service as secondary, pass `True` as :py:data:`secondary`. +//| +//| :param Peripheral peripheral: The peripheral that will provide this service +//| :param UUID uuid: The uuid of the service +//| :param bool secondary: If the service is a secondary one +// +//| :return: the new Service +//| +STATIC mp_obj_t bleio_service_add_to_peripheral(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // class is arg[0], which we can ignore. + + enum { ARG_peripheral, ARG_uuid, ARG_secondary }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_peripheral, MP_ARG_REQUIRED | MP_ARG_OBJ,}, + { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_secondary, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_obj_t peripheral_obj = args[ARG_peripheral].u_obj; + if (!MP_OBJ_IS_TYPE(peripheral_obj, &bleio_peripheral_type)) { + mp_raise_ValueError(translate("Expected a Peripheral")); + } + + const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + mp_raise_ValueError(translate("Expected a UUID")); + } + + const bool is_secondary = args[ARG_secondary].u_bool; + + bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); + service->base.type = &bleio_service_type; + + common_hal_bleio_service_construct( + service, MP_OBJ_TO_PTR(peripheral_obj), MP_OBJ_TO_PTR(uuid_obj), is_secondary); + + common_hal_bleio_peripheral_add_service(peripheral_obj, service); + + return MP_OBJ_FROM_PTR(service); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_service_add_to_peripheral_fun_obj, 3, bleio_service_add_to_peripheral); +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_service_add_to_peripheral_obj, MP_ROM_PTR(&bleio_service_add_to_peripheral_fun_obj)); + +//| .. attribute:: characteristics +//| +//| A tuple of :py:class:`Characteristic` designating the characteristics that are offered by this service. (read-only) +//| +STATIC mp_obj_t bleio_service_get_characteristics(mp_obj_t self_in) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + // Return list as a tuple so user won't be able to change it. + mp_obj_list_t *char_list = common_hal_bleio_service_get_characteristic_list(self); + return mp_obj_new_tuple(char_list->len, char_list->items); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_characteristics_obj, bleio_service_get_characteristics); + +const mp_obj_property_t bleio_service_characteristics_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_characteristics_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: remote +//| +//| True if this is a service provided by a remote device. (read-only) +//| +STATIC mp_obj_t bleio_service_get_remote(mp_obj_t self_in) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_bleio_service_get_is_remote(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_remote_obj, bleio_service_get_remote); + +const mp_obj_property_t bleio_service_remote_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_remote_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: secondary +//| +//| True if this is a secondary service. (read-only) +//| +STATIC mp_obj_t bleio_service_get_secondary(mp_obj_t self_in) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_bleio_service_get_is_secondary(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_secondary_obj, bleio_service_get_secondary); + +const mp_obj_property_t bleio_service_secondary_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_secondary_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. attribute:: uuid +//| +//| The UUID of this service. (read-only) +//| Will be ``None`` if the 128-bit UUID for this service is not known. +//| +STATIC mp_obj_t bleio_service_get_uuid(mp_obj_t self_in) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + + bleio_uuid_obj_t *uuid = common_hal_bleio_service_get_uuid(self); + return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_uuid_obj, bleio_service_get_uuid); + +const mp_obj_property_t bleio_service_uuid_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_uuid_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + + +STATIC const mp_rom_map_elem_t bleio_service_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_add_to_peripheral), MP_ROM_PTR(&bleio_service_add_to_peripheral_obj) }, + { MP_ROM_QSTR(MP_QSTR_characteristics), MP_ROM_PTR(&bleio_service_characteristics_obj) }, + { MP_ROM_QSTR(MP_QSTR_secondary), MP_ROM_PTR(&bleio_service_secondary_obj) }, + { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_service_uuid_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(bleio_service_locals_dict, bleio_service_locals_dict_table); + +STATIC void bleio_service_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->uuid) { + mp_printf(print, "Service("); + bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); + mp_printf(print, ")"); + } else { + mp_printf(print, ""); + } +} + +const mp_obj_type_t bleio_service_type = { + { &mp_type_type }, + .name = MP_QSTR_Service, + .print = bleio_service_print, + .locals_dict = (mp_obj_dict_t*)&bleio_service_locals_dict +}; diff --git a/shared-bindings/_bleio/Service.h b/shared-bindings/_bleio/Service.h new file mode 100644 index 000000000..e061bcffc --- /dev/null +++ b/shared-bindings/_bleio/Service.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H + +#include "common-hal/_bleio/Peripheral.h" +#include "common-hal/_bleio/Service.h" + +const mp_obj_type_t bleio_service_type; + +extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_peripheral_obj_t *peripheral, bleio_uuid_obj_t *uuid, bool is_secondary); +extern bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self); +extern mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self); +extern bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self); +extern bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self); +extern void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H diff --git a/shared-bindings/_bleio/UUID.c b/shared-bindings/_bleio/UUID.c new file mode 100644 index 000000000..3c0889aad --- /dev/null +++ b/shared-bindings/_bleio/UUID.c @@ -0,0 +1,280 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * 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 + +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/UUID.h" + +//| .. currentmodule:: _bleio +//| +//| :class:`UUID` -- BLE UUID +//| ========================================================= +//| +//| A 16-bit or 128-bit UUID. Can be used for services, characteristics, descriptors and more. +//| + +//| .. class:: UUID(value) +//| +//| Create a new UUID or UUID object encapsulating the uuid value. +//| The value can be one of: +//| +//| - an `int` value in range 0 to 0xFFFF (Bluetooth SIG 16-bit UUID) +//| - a buffer object (bytearray, bytes) of 16 bytes in little-endian order (128-bit UUID) +//| - a string of hex digits of the form 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' +//| +//| Creating a 128-bit UUID registers the UUID with the onboard BLE software, and provides a +//| temporary 16-bit UUID that can be used in place of the full 128-bit UUID. +//| +//| :param value: The uuid value to encapsulate +//| :type value: int or typing.ByteString +//| +STATIC mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 1, 1, false); + + bleio_uuid_obj_t *self = m_new_obj(bleio_uuid_obj_t); + self->base.type = type; + + const mp_obj_t value = pos_args[0]; + uint8_t uuid128[16]; + + if (MP_OBJ_IS_INT(value)) { + mp_int_t uuid16 = mp_obj_get_int(value); + if (uuid16 < 0 || uuid16 > 0xffff) { + mp_raise_ValueError(translate("UUID integer value must be 0-0xffff")); + } + + // NULL means no 128-bit value. + common_hal_bleio_uuid_construct(self, uuid16, NULL); + + } else { + if (MP_OBJ_IS_STR(value)) { + // 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + GET_STR_DATA_LEN(value, chars, len); + char hex[32]; + // Validate length, hyphens, and hex digits. + bool good_uuid = + len == 36 && chars[8] == '-' && chars[13] == '-' && chars[18] == '-' && chars[23] == '-'; + if (good_uuid) { + size_t hex_idx = 0; + for (size_t i = 0; i < len; i++) { + if (unichar_isxdigit(chars[i])) { + hex[hex_idx] = chars[i]; + hex_idx++; + } + } + good_uuid = hex_idx == 32; + } + if (!good_uuid) { + mp_raise_ValueError(translate("UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'")); + } + + size_t hex_idx = 0; + for (int i = 15; i >= 0; i--) { + uuid128[i] = (unichar_xdigit_value(hex[hex_idx]) << 4) | unichar_xdigit_value(hex[hex_idx + 1]); + hex_idx += 2; + } + } else { + // Last possibility is that it's a buf. + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(value, &bufinfo, MP_BUFFER_READ)) { + mp_raise_ValueError(translate("UUID value is not str, int or byte buffer")); + } + + if (bufinfo.len != 16) { + mp_raise_ValueError(translate("Byte buffer must be 16 bytes.")); + } + + memcpy(uuid128, bufinfo.buf, 16); + } + + // Str and bytes both get constructed the same way here. + uint32_t uuid16 = (uuid128[13] << 8) | uuid128[12]; + uuid128[12] = 0; + uuid128[13] = 0; + common_hal_bleio_uuid_construct(self, uuid16, uuid128); + } + + return MP_OBJ_FROM_PTR(self); +} + +//| .. attribute:: uuid16 +//| +//| The 16-bit part of the UUID. (read-only) +//| +//| :type: int +//| +STATIC mp_obj_t bleio_uuid_get_uuid16(mp_obj_t self_in) { + bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_uuid16(self)); +} + +MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_uuid16_obj, bleio_uuid_get_uuid16); + +const mp_obj_property_t bleio_uuid_uuid16_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&bleio_uuid_get_uuid16_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: uuid128 +//| +//| The 128-bit value of the UUID +//| Raises AttributeError if this is a 16-bit UUID. (read-only) +//| +//| :type: bytes +//| +STATIC mp_obj_t bleio_uuid_get_uuid128(mp_obj_t self_in) { + bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); + + uint8_t uuid128[16]; + if (!common_hal_bleio_uuid_get_uuid128(self, uuid128)) { + mp_raise_AttributeError(translate("not a 128-bit UUID")); + } + return mp_obj_new_bytes(uuid128, 16); +} + +MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_uuid128_obj, bleio_uuid_get_uuid128); + +const mp_obj_property_t bleio_uuid_uuid128_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&bleio_uuid_get_uuid128_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: size +//| +//| 128 if this UUID represents a 128-bit vendor-specific UUID. 16 if this UUID represents a +//| 16-bit Bluetooth SIG assigned UUID. (read-only) 32-bit UUIDs are not currently supported. +//| +//| :type: int +//| +STATIC mp_obj_t bleio_uuid_get_size(mp_obj_t self_in) { + bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_size(self)); +} + +MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_size_obj, bleio_uuid_get_size); + +const mp_obj_property_t bleio_uuid_size_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&bleio_uuid_get_size_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t bleio_uuid_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_uuid16), MP_ROM_PTR(&bleio_uuid_uuid16_obj) }, + { MP_ROM_QSTR(MP_QSTR_uuid128), MP_ROM_PTR(&bleio_uuid_uuid128_obj) }, + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&bleio_uuid_size_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_uuid_locals_dict, bleio_uuid_locals_dict_table); + +STATIC mp_obj_t bleio_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_HASH: + if (common_hal_bleio_uuid_get_size(self) == 16) { + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_uuid16(self)); + } else { + union { + uint8_t uuid128_bytes[16]; + uint16_t uuid128_uint16[8]; + } uuid128; + common_hal_bleio_uuid_get_uuid128(self, uuid128.uuid128_bytes); + int hash = 0; + for (size_t i = 0; i < MP_ARRAY_SIZE(uuid128.uuid128_uint16); i++) { + hash += uuid128.uuid128_uint16[i]; + } + return MP_OBJ_NEW_SMALL_INT(hash); + } + default: + return MP_OBJ_NULL; // op not supported + } +} + +//| + +//| .. method:: __eq__(other) +//| +//| Two UUID objects are equal if their values match and they are both 128-bit or both 16-bit. +//| +STATIC mp_obj_t bleio_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + switch (op) { + // Two UUID's are equal if their uuid16 values and uuid128 references match. + case MP_BINARY_OP_EQUAL: + if (MP_OBJ_IS_TYPE(rhs_in, &bleio_uuid_type)) { + return mp_obj_new_bool( + common_hal_bleio_uuid_get_uuid16(lhs_in) == common_hal_bleio_uuid_get_uuid16(rhs_in) && + common_hal_bleio_uuid_get_uuid128_reference(lhs_in) == + common_hal_bleio_uuid_get_uuid128_reference(rhs_in)); + } else { + return mp_const_false; + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + +void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint32_t size = common_hal_bleio_uuid_get_size(self); + if (size == 16) { + mp_printf(print, "UUID(0x%04x)", common_hal_bleio_uuid_get_uuid16(self)); + } else { + uint8_t uuid128[16]; + (void) common_hal_bleio_uuid_get_uuid128(self, uuid128); + mp_printf(print, "UUID('" + "%02x%02x%02x%02x-" + "%02x%02x-" + "%02x%02x-" + "%02x%02x-" + "%02x%02x%02x%02x%02x%02x')", + uuid128[15], uuid128[14], uuid128[13], uuid128[12], + uuid128[11], uuid128[10], + uuid128[9], uuid128[8], + uuid128[7], uuid128[6], + uuid128[5], uuid128[4], uuid128[3], uuid128[2], uuid128[1], uuid128[0]); + } +} + +const mp_obj_type_t bleio_uuid_type = { + { &mp_type_type }, + .name = MP_QSTR_UUID, + .print = bleio_uuid_print, + .make_new = bleio_uuid_make_new, + .unary_op = bleio_uuid_unary_op, + .binary_op = bleio_uuid_binary_op, + .locals_dict = (mp_obj_dict_t*)&bleio_uuid_locals_dict, +}; diff --git a/shared-bindings/_bleio/UUID.h b/shared-bindings/_bleio/UUID.h new file mode 100644 index 000000000..46ac54ff3 --- /dev/null +++ b/shared-bindings/_bleio/UUID.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H + +#include "common-hal/_bleio/UUID.h" + +void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); + +extern const mp_obj_type_t bleio_uuid_type; + +extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, uint8_t uuid128[]); +extern uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self); +extern bool common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]); +extern uint32_t common_hal_bleio_uuid_get_uuid128_reference(bleio_uuid_obj_t *self); +extern uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c new file mode 100644 index 000000000..f207be8cf --- /dev/null +++ b/shared-bindings/_bleio/__init__.c @@ -0,0 +1,107 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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 "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-bindings/_bleio/Central.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/CharacteristicBuffer.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Peripheral.h" +#include "shared-bindings/_bleio/ScanEntry.h" +#include "shared-bindings/_bleio/Scanner.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" + +//| :mod:`_bleio` --- Bluetooth Low Energy (BLE) communication +//| ================================================================ +//| +//| .. module:: _bleio +//| :synopsis: Bluetooth Low Energy functionality +//| :platform: nRF +//| +//| The `_bleio` module provides necessary low-level functionality for communicating +//| using Bluetooth Low Energy (BLE). The '_' prefix indicates this module is meant +//| for internal use by libraries but not by the end user. Its API may change incompatibly +//| between minor versions of CircuitPython. +//| Please use the +//| `adafruit_ble `_ +//| CircuitPython library instead, which builds on `_bleio`, and +//| provides higher-level convenience functionality, including predefined beacons, clients, +//| servers. +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| Address +//| Adapter +//| Attribute +//| Central +//| Characteristic +//| CharacteristicBuffer +//| Descriptor +//| Peripheral +//| ScanEntry +//| Scanner +//| Service +//| UUID +//| +//| .. attribute:: adapter +//| +//| BLE Adapter information, such as enabled state as well as MAC +//| address. +//| This object is the sole instance of `_bleio.Adapter`. +//| + +STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__bleio) }, + { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, + { MP_ROM_QSTR(MP_QSTR_Attribute), MP_ROM_PTR(&bleio_attribute_type) }, + { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&bleio_central_type) }, + { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, + { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_ROM_PTR(&bleio_characteristic_buffer_type) }, + { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, + { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&bleio_peripheral_type) }, + { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, + { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, + { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, + { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); + +const mp_obj_module_t bleio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&bleio_module_globals, +}; diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h new file mode 100644 index 000000000..67379ae2e --- /dev/null +++ b/shared-bindings/_bleio/__init__.h @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H + +#include "py/objlist.h" + +#include "shared-bindings/_bleio/Adapter.h" + +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/Adapter.h" + +extern const super_adapter_obj_t common_hal_bleio_adapter_obj; + +extern void common_hal_bleio_check_connected(uint16_t conn_handle); + +extern uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); +extern mp_obj_list_t *common_hal_bleio_device_get_remote_service_list(mp_obj_t device); +extern void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); + +extern mp_obj_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle); +extern void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); +extern void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); + + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H diff --git a/shared-bindings/bleio/Adapter.c b/shared-bindings/bleio/Adapter.c deleted file mode 100644 index 2bb7f3465..000000000 --- a/shared-bindings/bleio/Adapter.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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 "py/objproperty.h" -#include "shared-bindings/bleio/Address.h" -#include "shared-bindings/bleio/Adapter.h" - -//| .. currentmodule:: bleio -//| -//| :class:`Adapter` --- BLE adapter information -//| ---------------------------------------------------- -//| -//| Get current status of the BLE adapter -//| -//| Usage:: -//| -//| import bleio -//| bleio.adapter.enabled = True -//| print(bleio.adapter.address) -//| - -//| .. class:: Adapter() -//| -//| You cannot create an instance of `bleio.Adapter`. -//| Use `bleio.adapter` to access the sole instance available. -//| - -//| .. attribute:: adapter.enabled -//| -//| State of the BLE adapter. -//| -STATIC mp_obj_t bleio_adapter_get_enabled(mp_obj_t self) { - return mp_obj_new_bool(common_hal_bleio_adapter_get_enabled()); -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_enabled_obj, bleio_adapter_get_enabled); - -static mp_obj_t bleio_adapter_set_enabled(mp_obj_t self, mp_obj_t value) { - const bool enabled = mp_obj_is_true(value); - - common_hal_bleio_adapter_set_enabled(enabled); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_adapter_set_enabled_obj, bleio_adapter_set_enabled); - -const mp_obj_property_t bleio_adapter_enabled_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_adapter_get_enabled_obj, - (mp_obj_t)&bleio_adapter_set_enabled_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: adapter.address -//| -//| MAC address of the BLE adapter. (read-only) -//| -STATIC mp_obj_t bleio_adapter_get_address(mp_obj_t self) { - return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_address()); - -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_address_obj, bleio_adapter_get_address); - -const mp_obj_property_t bleio_adapter_address_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_adapter_get_address_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: adapter.default_name -//| -//| default_name of the BLE adapter. (read-only) -//| The name is "CIRCUITPY" + the last four hex digits of ``adapter.address``, -//| to make it easy to distinguish multiple CircuitPython boards. -//| -STATIC mp_obj_t bleio_adapter_get_default_name(mp_obj_t self) { - return common_hal_bleio_adapter_get_default_name(); - -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_default_name_obj, bleio_adapter_get_default_name); - -const mp_obj_property_t bleio_adapter_default_name_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_adapter_get_default_name_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC const mp_rom_map_elem_t bleio_adapter_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&bleio_adapter_enabled_obj) }, - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_adapter_address_obj) }, - { MP_ROM_QSTR(MP_QSTR_default_name), MP_ROM_PTR(&bleio_adapter_default_name_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_adapter_locals_dict, bleio_adapter_locals_dict_table); - -const mp_obj_type_t bleio_adapter_type = { - .base = { &mp_type_type }, - .name = MP_QSTR_Adapter, - .locals_dict = (mp_obj_t)&bleio_adapter_locals_dict, -}; diff --git a/shared-bindings/bleio/Adapter.h b/shared-bindings/bleio/Adapter.h deleted file mode 100644 index 72382616c..000000000 --- a/shared-bindings/bleio/Adapter.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H - -#include "shared-module/bleio/Address.h" - -const mp_obj_type_t bleio_adapter_type; - -extern bool common_hal_bleio_adapter_get_enabled(void); -extern void common_hal_bleio_adapter_set_enabled(bool enabled); -extern bleio_address_obj_t *common_hal_bleio_adapter_get_address(void); -extern mp_obj_t common_hal_bleio_adapter_get_default_name(void); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H diff --git a/shared-bindings/bleio/Address.c b/shared-bindings/bleio/Address.c deleted file mode 100644 index baeb6d7c0..000000000 --- a/shared-bindings/bleio/Address.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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 -#include - -#include "py/objproperty.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Address.h" -#include "shared-module/bleio/Address.h" - -//| .. currentmodule:: bleio -//| -//| :class:`Address` -- BLE address -//| ========================================================= -//| -//| Encapsulates the address of a BLE device. -//| - -//| .. class:: Address(address, address_type) -//| -//| Create a new Address object encapsulating the address value. -//| The value itself can be one of: -//| -//| :param buf address: The address value to encapsulate. A buffer object (bytearray, bytes) of 6 bytes. -//| :param int address_type: one of the integer values: `PUBLIC`, `RANDOM_STATIC`, -//| `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`. -//| -STATIC mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_address, ARG_address_type }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_address_type, MP_ARG_INT, {.u_int = BLEIO_ADDRESS_TYPE_PUBLIC } }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - bleio_address_obj_t *self = m_new_obj(bleio_address_obj_t); - self->base.type = &bleio_address_type; - - const mp_obj_t address = args[ARG_address].u_obj; - mp_buffer_info_t buf_info; - mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); - if (buf_info.len != NUM_BLEIO_ADDRESS_BYTES) { - mp_raise_ValueError_varg(translate("Address must be %d bytes long"), NUM_BLEIO_ADDRESS_BYTES); - } - - const mp_int_t address_type = args[ARG_address_type].u_int; - if (address_type < BLEIO_ADDRESS_TYPE_MIN || address_type > BLEIO_ADDRESS_TYPE_MAX) { - mp_raise_ValueError(translate("Address type out of range")); - } - - common_hal_bleio_address_construct(self, buf_info.buf, address_type); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. attribute:: address_bytes -//| -//| The bytes that make up the device address (read-only). -//| -//| Note that the ``bytes`` object returned is in little-endian order: -//| The least significant byte is ``address_bytes[0]``. So the address will -//| appear to be reversed if you print the raw ``bytes`` object. If you print -//| or use `str()` on the :py:class:`~bleio.Attribute` object itself, the address will be printed -//| in the expected order. For example: -//| -//| .. code-block:: pycon -//| -//| >>> import bleio -//| >>> bleio.adapter.address -//|
-//| >>> bleio.adapter.address.address_bytes -//| b'5\xa8\xed\xf5\x1d\xc8' -//| -STATIC mp_obj_t bleio_address_get_address_bytes(mp_obj_t self_in) { - bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return common_hal_bleio_address_get_address_bytes(self); -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_address_get_address_bytes_obj, bleio_address_get_address_bytes); - -const mp_obj_property_t bleio_address_address_bytes_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_address_get_address_bytes_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: type -//| -//| The address type (read-only). -//| One of the integer values: `PUBLIC`, `RANDOM_STATIC`, -//| `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`. -//| -STATIC mp_obj_t bleio_address_get_type(mp_obj_t self_in) { - bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_address_get_type(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_address_get_type_obj, bleio_address_get_type); - -const mp_obj_property_t bleio_address_type_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_address_get_type_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. method:: __eq__(other) -//| -//| Two Address objects are equal if their addresses and address types are equal. -//| -STATIC mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { - switch (op) { - // Two Addresses are equal if their address bytes and address_type are equal - case MP_BINARY_OP_EQUAL: - if (MP_OBJ_IS_TYPE(rhs_in, &bleio_address_type)) { - bleio_address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); - bleio_address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); - return mp_obj_new_bool( - mp_obj_equal(common_hal_bleio_address_get_address_bytes(lhs), - common_hal_bleio_address_get_address_bytes(rhs)) && - common_hal_bleio_address_get_type(lhs) == - common_hal_bleio_address_get_type(rhs)); - - } else { - return mp_const_false; - } - - default: - return MP_OBJ_NULL; // op not supported - } -} - -STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t buf_info; - mp_obj_t address_bytes = common_hal_bleio_address_get_address_bytes(self); - mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ); - - const uint8_t *buf = (uint8_t *) buf_info.buf; - mp_printf(print, "
", - buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); -} - -//| .. data:: PUBLIC -//| -//| A publicly known address, with a company ID (high 24 bits)and company-assigned part (low 24 bits). -//| -//| .. data:: RANDOM_STATIC -//| -//| A randomly generated address that does not change often. It may never change or may change after -//| a power cycle. -//| -//| .. data:: RANDOM_PRIVATE_RESOLVABLE -//| -//| An address that is usable when the peer knows the other device's secret Identity Resolving Key (IRK). -//| -//| .. data:: RANDOM_PRIVATE_NON_RESOLVABLE -//| -//| A randomly generated address that changes on every connection. -//| -STATIC const mp_rom_map_elem_t bleio_address_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_address_bytes), MP_ROM_PTR(&bleio_address_address_bytes_obj) }, - { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&bleio_address_type_obj) }, - // These match the BLE_GAP_ADDR_TYPES values used by the nRF library. - { MP_ROM_QSTR(MP_QSTR_PUBLIC), MP_ROM_INT(0) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_ROM_INT(1) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_ROM_INT(2) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_ROM_INT(3) }, - -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_address_locals_dict, bleio_address_locals_dict_table); - -const mp_obj_type_t bleio_address_type = { - { &mp_type_type }, - .name = MP_QSTR_Address, - .make_new = bleio_address_make_new, - .print = bleio_address_print, - .binary_op = bleio_address_binary_op, - .locals_dict = (mp_obj_dict_t*)&bleio_address_locals_dict -}; diff --git a/shared-bindings/bleio/Address.h b/shared-bindings/bleio/Address.h deleted file mode 100644 index 5e02ee210..000000000 --- a/shared-bindings/bleio/Address.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H - -#include "py/objtype.h" -#include "shared-module/bleio/Address.h" - -#define BLEIO_ADDRESS_TYPE_PUBLIC (0) -#define BLEIO_ADDRESS_TYPE_RANDOM_STATIC (1) -#define BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE (2) -#define BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE (3) - -#define BLEIO_ADDRESS_TYPE_MIN BLEIO_ADDRESS_TYPE_PUBLIC -#define BLEIO_ADDRESS_TYPE_MAX BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE - -extern const mp_obj_type_t bleio_address_type; - -extern void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type); -extern mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self); -extern uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H diff --git a/shared-bindings/bleio/Attribute.c b/shared-bindings/bleio/Attribute.c deleted file mode 100644 index 2cc9ef6d0..000000000 --- a/shared-bindings/bleio/Attribute.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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 "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/UUID.h" - -// - -//| .. currentmodule:: bleio -//| -//| :class:`Attribute` -- BLE Attribute -//| ========================================================= -//| -//| Definitions associated with all BLE attributes: characteristics, descriptors, etc. -//| :py:class:`~bleio.Attribute` is, notionally, a superclass of -//| :py:class:`~Characteristic` and :py:class:`~Descriptor`, -//| but is not defined as a Python superclass of those classes. -//| -//| .. class:: Attribute() -//| -//| You cannot create an instance of :py:class:`~bleio.Attribute`. -//| - -STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = { - -//| .. data:: NO_ACCESS -//| -//| security mode: access not allowed -//| -//| .. data:: OPEN -//| -//| security_mode: no security (link is not encrypted) -//| -//| .. data:: ENCRYPT_NO_MITM -//| -//| security_mode: unauthenticated encryption, without man-in-the-middle protection -//| -//| .. data:: ENCRYPT_WITH_MITM -//| -//| security_mode: authenticated encryption, with man-in-the-middle protection -//| -//| .. data:: LESC_ENCRYPT_WITH_MITM -//| -//| security_mode: LESC encryption, with man-in-the-middle protection -//| -//| .. data:: SIGNED_NO_MITM -//| -//| security_mode: unauthenticated data signing, without man-in-the-middle protection -//| -//| .. data:: SIGNED_WITH_MITM -//| -//| security_mode: authenticated data signing, without man-in-the-middle protection -//| - { MP_ROM_QSTR(MP_QSTR_NO_ACCESS), MP_ROM_INT(SECURITY_MODE_NO_ACCESS) }, - { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SECURITY_MODE_OPEN) }, - { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SECURITY_MODE_ENC_NO_MITM) }, - { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_ENC_WITH_MITM) }, - { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_LESC_ENC_WITH_MITM) }, - { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_NO_MITM) }, - { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_WITH_MITM) }, - -}; -STATIC MP_DEFINE_CONST_DICT(bleio_attribute_locals_dict, bleio_attribute_locals_dict_table); - -const mp_obj_type_t bleio_attribute_type = { - { &mp_type_type }, - .name = MP_QSTR_Attribute, - .locals_dict = (mp_obj_dict_t*)&bleio_attribute_locals_dict, -}; diff --git a/shared-bindings/bleio/Attribute.h b/shared-bindings/bleio/Attribute.h deleted file mode 100644 index 39bef5057..000000000 --- a/shared-bindings/bleio/Attribute.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H - -#include "py/obj.h" - -#include "common-hal/bleio/Attribute.h" -#include "shared-module/bleio/Attribute.h" - -extern const mp_obj_type_t bleio_attribute_type; - -extern void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H diff --git a/shared-bindings/bleio/Central.c b/shared-bindings/bleio/Central.c deleted file mode 100644 index 1fc455d8d..000000000 --- a/shared-bindings/bleio/Central.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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 -#include - -#include "ble_drv.h" -#include "py/objarray.h" -#include "py/objproperty.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Address.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Central.h" -#include "shared-bindings/bleio/Service.h" - -//| .. currentmodule:: bleio -//| -//| :class:`Central` -- A BLE central device -//| ========================================================= -//| -//| Implement a BLE central, which runs locally. Can connect to a given address. -//| -//| Usage:: -//| -//| import bleio -//| -//| scanner = bleio.Scanner() -//| entries = scanner.scan(2.5) -//| -//| my_entry = None -//| for entry in entries: -//| if entry.name is not None and entry.name == 'InterestingPeripheral': -//| my_entry = entry -//| break -//| -//| if not my_entry: -//| raise Exception("'InterestingPeripheral' not found") -//| -//| central = bleio.Central() -//| central.connect(my_entry.address, 10) # timeout after 10 seconds -//| remote_services = central.discover_remote_services() -//| - -//| .. class:: Central() -//| -//| Create a new Central object. -//| -STATIC mp_obj_t bleio_central_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 0, 0, false); - - bleio_central_obj_t *self = m_new_obj(bleio_central_obj_t); - self->base.type = &bleio_central_type; - - common_hal_bleio_central_construct(self); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: connect(address, timeout, *, service_uuids_whitelist=None) -//| Attempts a connection to the remote peripheral. -//| -//| :param bleio.Address address: The address of the peripheral to connect to -//| :param float/int timeout: Try to connect for timeout seconds. -//| -STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - enum { ARG_address, ARG_timeout, ARG_service_uuids_whitelist }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (!MP_OBJ_IS_TYPE(args[ARG_address].u_obj, &bleio_address_type)) { - mp_raise_ValueError(translate("Expected an Address")); - } - - bleio_address_obj_t *address = MP_OBJ_TO_PTR(args[ARG_address].u_obj); - mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); - - // common_hal_bleio_central_connect() will validate that services is an iterable or None. - common_hal_bleio_central_connect(self, address, timeout); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_connect_obj, 3, bleio_central_connect); - - -//| .. method:: disconnect() -//| -//| Disconnects from the remote peripheral. -//| -STATIC mp_obj_t bleio_central_disconnect(mp_obj_t self_in) { - bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); - - common_hal_bleio_central_disconnect(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_disconnect); - -//| .. method:: discover_remote_services(service_uuids_whitelist=None) -//| Do BLE discovery for all services or for the given service UUIDS, -//| to find their handles and characteristics, and return the discovered services. -//| `Peripheral.connected` must be True. -//| -//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services -//| provided by the peripheral that you want to use. -//| The peripheral may provide more services, but services not listed are ignored -//| and will not be returned. -//| -//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. -//| -//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you -//| you must have already created a :py:class:~`UUID` object for that UUID in order for the -//| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered -//| for use. (This restriction may be lifted in the future.) -//| -//| :return: A tuple of services provided by the remote peripheral. -//| -STATIC mp_obj_t bleio_central_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - enum { ARG_service_uuids_whitelist }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (!common_hal_bleio_central_get_connected(self)) { - mp_raise_ValueError(translate("Not connected")); - } - - return MP_OBJ_FROM_PTR(common_hal_bleio_central_discover_remote_services( - MP_OBJ_FROM_PTR(self), - args[ARG_service_uuids_whitelist].u_obj)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_discover_remote_services_obj, 1, bleio_central_discover_remote_services); - -//| .. attribute:: connected -//| -//| True if connected to a remove peripheral. -//| -STATIC mp_obj_t bleio_central_get_connected(mp_obj_t self_in) { - bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_central_get_connected(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_get_connected_obj, bleio_central_get_connected); - -const mp_obj_property_t bleio_central_connected_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_central_get_connected_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_central_disconnect_obj) }, - { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_central_discover_remote_services_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_central_connected_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_central_locals_dict, bleio_central_locals_dict_table); - -const mp_obj_type_t bleio_central_type = { - { &mp_type_type }, - .name = MP_QSTR_Central, - .make_new = bleio_central_make_new, - .locals_dict = (mp_obj_dict_t*)&bleio_central_locals_dict -}; diff --git a/shared-bindings/bleio/Central.h b/shared-bindings/bleio/Central.h deleted file mode 100644 index cbc437087..000000000 --- a/shared-bindings/bleio/Central.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H - -#include "py/objtuple.h" -#include "common-hal/bleio/Central.h" -#include "common-hal/bleio/Service.h" - -extern const mp_obj_type_t bleio_central_type; - -extern void common_hal_bleio_central_construct(bleio_central_obj_t *self); -extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout); -extern void common_hal_bleio_central_disconnect(bleio_central_obj_t *self); -extern bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self); -extern mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c deleted file mode 100644 index 41d81087c..000000000 --- a/shared-bindings/bleio/Characteristic.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2017 Glenn Ruben Bakke - * - * 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 "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Attribute.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -//| .. currentmodule:: bleio -//| -//| :class:`Characteristic` -- BLE service characteristic -//| ========================================================= -//| -//| Stores information about a BLE service characteristic and allows reading -//| and writing of the characteristic's value. -//| -//| .. class:: Characteristic -//| -//| There is no regular constructor for a Characteristic. A new local Characteristic can be created -//| and attached to a Service by calling `add_to_service()`. -//| Remote Characteristic objects are created by `Central.discover_remote_services()` -//| or `Peripheral.discover_remote_services()` as part of remote Services. -//| - -//| .. method:: add_to_service(service, uuid, *, properties=0, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, initial_value=None) -//| -//| Create a new Characteristic object, and add it to this Service. -//| -//| :param Service service: The service that will provide this characteristic -//| :param UUID uuid: The uuid of the characteristic -//| :param int properties: The properties of the characteristic, -//| specified as a bitmask of these values bitwise-or'd together: -//| `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`. -//| :param int read_perm: Specifies whether the characteristic can be read by a client, and if so, which -//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, -//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, -//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`. -//| :param int write_perm: Specifies whether the characteristic can be written by a client, and if so, which -//| security mode is required. Values allowed are the same as ``read_perm``. -//| :param int max_length: Maximum length in bytes of the characteristic value. The maximum allowed is -//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum -//| number of data bytes that fit in a single BLE 4.x ATT packet. -//| :param bool fixed_length: True if the characteristic value is of fixed length. -//| :param buf initial_value: The initial value for this characteristic. If not given, will be -//| filled with zeros. -//| -//| :return: the new Characteristic. -//| -STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // class is arg[0], which we can ignore. - - enum { ARG_service, ARG_uuid, ARG_properties, ARG_read_perm, ARG_write_perm, - ARG_max_length, ARG_fixed_length, ARG_initial_value }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_service, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_properties, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, - { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, - { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} }, - { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_initial_value, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mp_obj_t service_obj = args[ARG_service].u_obj; - if (!MP_OBJ_IS_TYPE(service_obj, &bleio_service_type)) { - mp_raise_ValueError(translate("Expected a Service")); - } - - const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - mp_raise_ValueError(translate("Expected a UUID")); - } - - const bleio_characteristic_properties_t properties = args[ARG_properties].u_int; - if (properties & ~CHAR_PROP_ALL) { - mp_raise_ValueError(translate("Invalid properties")); - } - - const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int; - common_hal_bleio_attribute_security_mode_check_valid(read_perm); - - const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; - common_hal_bleio_attribute_security_mode_check_valid(write_perm); - - const mp_int_t max_length = args[ARG_max_length].u_int; - const bool fixed_length = args[ARG_fixed_length].u_bool; - mp_obj_t initial_value = args[ARG_initial_value].u_obj; - - // Length will be validated in common_hal. - mp_buffer_info_t initial_value_bufinfo; - if (initial_value == mp_const_none) { - if (fixed_length && max_length > 0) { - initial_value = mp_obj_new_bytes_of_zeros(max_length); - } else { - initial_value = mp_const_empty_bytes; - } - } - mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); - - bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); - characteristic->base.type = &bleio_characteristic_type; - - // Range checking on max_length arg is done by the common_hal layer, because - // it may vary depending on underlying BLE implementation. - common_hal_bleio_characteristic_construct( - characteristic, MP_OBJ_TO_PTR(service_obj), MP_OBJ_TO_PTR(uuid_obj), - properties, read_perm, write_perm, - max_length, fixed_length, &initial_value_bufinfo); - - common_hal_bleio_service_add_characteristic(service_obj, characteristic); - - return MP_OBJ_FROM_PTR(characteristic); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_add_to_service_fun_obj, 3, bleio_characteristic_add_to_service); -STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_characteristic_add_to_service_obj, MP_ROM_PTR(&bleio_characteristic_add_to_service_fun_obj)); - - - -//| .. attribute:: properties -//| -//| An int bitmask representing which properties are set, specified as bitwise or'ing of -//| of these possible values. -//| `BROADCAST`, `INDICATE`, `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`. -//| -STATIC mp_obj_t bleio_characteristic_get_properties(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_properties(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_properties_obj, bleio_characteristic_get_properties); - -const mp_obj_property_t bleio_characteristic_properties_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_properties_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: uuid -//| -//| The UUID of this characteristic. (read-only) -//| Will be ``None`` if the 128-bit UUID for this characteristic is not known. -//| -STATIC mp_obj_t bleio_characteristic_get_uuid(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - bleio_uuid_obj_t *uuid = common_hal_bleio_characteristic_get_uuid(self); - return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_uuid_obj, bleio_characteristic_get_uuid); - -const mp_obj_property_t bleio_characteristic_uuid_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_uuid_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: value -//| -//| The value of this characteristic. -//| -STATIC mp_obj_t bleio_characteristic_get_value(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return common_hal_bleio_characteristic_get_value(self); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_value_obj, bleio_characteristic_get_value); - -STATIC mp_obj_t bleio_characteristic_set_value(mp_obj_t self_in, mp_obj_t value_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ); - - common_hal_bleio_characteristic_set_value(self, &bufinfo); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_characteristic_set_value_obj, bleio_characteristic_set_value); - -const mp_obj_property_t bleio_characteristic_value_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_value_obj, - (mp_obj_t)&bleio_characteristic_set_value_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: descriptors -//| -//| A tuple of :py:class:`Descriptor` that describe this characteristic. (read-only) -//| -STATIC mp_obj_t bleio_characteristic_get_descriptors(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *char_list = common_hal_bleio_characteristic_get_descriptor_list(self); - return mp_obj_new_tuple(char_list->len, char_list->items); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_descriptors_obj, bleio_characteristic_get_descriptors); - -const mp_obj_property_t bleio_characteristic_descriptors_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_descriptors_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: service (read-only) -//| -//| The Service this Characteristic is a part of. -//| -STATIC mp_obj_t bleio_characteristic_get_service(mp_obj_t self_in) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return common_hal_bleio_characteristic_get_service(self); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_service_obj, bleio_characteristic_get_service); - -const mp_obj_property_t bleio_characteristic_service_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_characteristic_get_service_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. method:: set_cccd(*, notify=False, indicate=False) -//| -//| Set the remote characteristic's CCCD to enable or disable notification and indication. -//| -//| :param bool notify: True if Characteristic should receive notifications of remote writes -//| :param float indicate: True if Characteristic should receive indications of remote writes -//| -STATIC mp_obj_t bleio_characteristic_set_cccd(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - enum { ARG_notify, ARG_indicate }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_notify, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_indicate, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - common_hal_bleio_characteristic_set_cccd(self, args[ARG_notify].u_bool, args[ARG_indicate].u_bool); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_characteristic_set_cccd); - - -STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_add_to_service), MP_ROM_PTR(&bleio_characteristic_add_to_service_obj) }, - { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_get_properties_obj) }, - { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) }, - { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_characteristic_value_obj) }, - { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_obj) }, - - // Bitmask constants to represent properties -//| .. data:: BROADCAST -//| -//| property: allowed in advertising packets -//| -//| .. data:: INDICATE -//| -//| property: server will indicate to the client when the value is set and wait for a response -//| -//| .. data:: NOTIFY -//| -//| property: server will notify the client when the value is set -//| -//| .. data:: READ -//| -//| property: clients may read this characteristic -//| -//| .. data:: WRITE -//| -//| property: clients may write this characteristic; a response will be sent back -//| -//| .. data:: WRITE_NO_RESPONSE -//| -//| property: clients may write this characteristic; no response will be sent back -//| - { MP_ROM_QSTR(MP_QSTR_BROADCAST), MP_ROM_INT(CHAR_PROP_BROADCAST) }, - { MP_ROM_QSTR(MP_QSTR_INDICATE), MP_ROM_INT(CHAR_PROP_INDICATE) }, - { MP_ROM_QSTR(MP_QSTR_NOTIFY), MP_ROM_INT(CHAR_PROP_NOTIFY) }, - { MP_ROM_QSTR(MP_QSTR_READ), MP_ROM_INT(CHAR_PROP_READ) }, - { MP_ROM_QSTR(MP_QSTR_WRITE), MP_ROM_INT(CHAR_PROP_WRITE) }, - { MP_ROM_QSTR(MP_QSTR_WRITE_NO_RESPONSE), MP_ROM_INT(CHAR_PROP_WRITE_NO_RESPONSE) }, - -}; -STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_locals_dict, bleio_characteristic_locals_dict_table); - -STATIC void bleio_characteristic_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->uuid) { - mp_printf(print, "Characteristic("); - bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); - mp_printf(print, ")"); - } else { - mp_printf(print, ""); - } -} - -const mp_obj_type_t bleio_characteristic_type = { - { &mp_type_type }, - .name = MP_QSTR_Characteristic, - .print = bleio_characteristic_print, - .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict, -}; diff --git a/shared-bindings/bleio/Characteristic.h b/shared-bindings/bleio/Characteristic.h deleted file mode 100644 index 52df87b36..000000000 --- a/shared-bindings/bleio/Characteristic.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H - -#include "shared-bindings/bleio/Attribute.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-module/bleio/Characteristic.h" -#include "common-hal/bleio/Characteristic.h" -#include "common-hal/bleio/Service.h" - -extern const mp_obj_type_t bleio_characteristic_type; - -extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo); -extern mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self); -extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); -extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self); -extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self); -extern mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self); -extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self); -extern void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor); -extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H diff --git a/shared-bindings/bleio/CharacteristicBuffer.c b/shared-bindings/bleio/CharacteristicBuffer.c deleted file mode 100644 index 26f9e012b..000000000 --- a/shared-bindings/bleio/CharacteristicBuffer.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * - * 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 "py/mperrno.h" -#include "py/ioctl.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "py/stream.h" - -#include "shared-bindings/bleio/CharacteristicBuffer.h" -#include "shared-bindings/bleio/UUID.h" -#include "shared-bindings/util.h" - -STATIC void raise_error_if_not_connected(bleio_characteristic_buffer_obj_t *self) { - if (!common_hal_bleio_characteristic_buffer_connected(self)) { - mp_raise_ValueError(translate("Not connected")); - } -} - -//| .. currentmodule:: bleio -//| -//| :class:`CharacteristicBuffer` -- BLE Service incoming values buffer. -//| ===================================================================== -//| -//| Accumulates a Characteristic's incoming values in a FIFO buffer. -//| -//| .. class:: CharacteristicBuffer(characteristic, *, timeout=1, buffer_size=64) -//| -//| Monitor the given Characteristic. Each time a new value is written to the Characteristic -//| add the newly-written bytes to a FIFO buffer. -//| -//| :param bleio.Characteristic characteristic: The Characteristic to monitor. -//| It may be a local Characteristic provided by a Peripheral Service, or a remote Characteristic -//| in a remote Service that a Central has connected to. -//| :param int timeout: the timeout in seconds to wait for the first character and between subsequent characters. -//| :param int buffer_size: Size of ring buffer that stores incoming data coming from client. -//| Must be >= 1. -//| -STATIC mp_obj_t bleio_characteristic_buffer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_characteristic, ARG_timeout, ARG_buffer_size, }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_characteristic, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, - { MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mp_obj_t characteristic = args[ARG_characteristic].u_obj; - - mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); - if (timeout < 0.0f) { - mp_raise_ValueError(translate("timeout must be >= 0.0")); - } - - const int buffer_size = args[ARG_buffer_size].u_int; - if (buffer_size < 1) { - mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_buffer_size); - } - - if (!MP_OBJ_IS_TYPE(characteristic, &bleio_characteristic_type)) { - mp_raise_ValueError(translate("Expected a Characteristic")); - } - - bleio_characteristic_buffer_obj_t *self = m_new_obj(bleio_characteristic_buffer_obj_t); - self->base.type = &bleio_characteristic_buffer_type; - - common_hal_bleio_characteristic_buffer_construct(self, MP_OBJ_TO_PTR(characteristic), timeout, buffer_size); - - return MP_OBJ_FROM_PTR(self); -} - -STATIC void check_for_deinit(bleio_characteristic_buffer_obj_t *self) { - if (common_hal_bleio_characteristic_buffer_deinited(self)) { - raise_deinited_error(); - } -} - -// These are standard stream methods. Code is in py/stream.c. -// -//| .. method:: read(nbytes=None) -//| -//| Read characters. If ``nbytes`` is specified then read at most that many -//| bytes. Otherwise, read everything that arrives until the connection -//| times out. Providing the number of bytes expected is highly recommended -//| because it will be faster. -//| -//| :return: Data read -//| :rtype: bytes or None -//| -//| .. method:: readinto(buf) -//| -//| Read bytes into the ``buf``. Read at most ``len(buf)`` bytes. -//| -//| :return: number of bytes read and stored into ``buf`` -//| :rtype: int or None (on a non-blocking error) -//| -//| .. method:: readline() -//| -//| Read a line, ending in a newline character. -//| -//| :return: the line read -//| :rtype: int or None -//| - -// These three methods are used by the shared stream methods. -STATIC mp_uint_t bleio_characteristic_buffer_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { - bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - raise_error_if_not_connected(self); - byte *buf = buf_in; - - // make sure we want at least 1 char - if (size == 0) { - return 0; - } - - return common_hal_bleio_characteristic_buffer_read(self, buf, size, errcode); -} - -STATIC mp_uint_t bleio_characteristic_buffer_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { - mp_raise_NotImplementedError(translate("CharacteristicBuffer writing not provided")); - return 0; -} - -STATIC mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { - bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - raise_error_if_not_connected(self); - if (!common_hal_bleio_characteristic_buffer_connected(self)) { - mp_raise_ValueError(translate("Not connected")); - } - mp_uint_t ret; - if (request == MP_IOCTL_POLL) { - mp_uint_t flags = arg; - ret = 0; - if ((flags & MP_IOCTL_POLL_RD) && common_hal_bleio_characteristic_buffer_rx_characters_available(self) > 0) { - ret |= MP_IOCTL_POLL_RD; - } -// No writing provided. -// if ((flags & MP_IOCTL_POLL_WR) && common_hal_busio_uart_ready_to_tx(self)) { -// ret |= MP_IOCTL_POLL_WR; -// } - } else { - *errcode = MP_EINVAL; - ret = MP_STREAM_ERROR; - } - return ret; -} - -//| .. attribute:: in_waiting -//| -//| The number of bytes in the input buffer, available to be read -//| -STATIC mp_obj_t bleio_characteristic_buffer_obj_get_in_waiting(mp_obj_t self_in) { - bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_buffer_rx_characters_available(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_get_in_waiting_obj, bleio_characteristic_buffer_obj_get_in_waiting); - -const mp_obj_property_t bleio_characteristic_buffer_in_waiting_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_characteristic_buffer_get_in_waiting_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. method:: reset_input_buffer() -//| -//| Discard any unread characters in the input buffer. -//| -STATIC mp_obj_t bleio_characteristic_buffer_obj_reset_input_buffer(mp_obj_t self_in) { - bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_bleio_characteristic_buffer_clear_rx_buffer(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_reset_input_buffer_obj, bleio_characteristic_buffer_obj_reset_input_buffer); - -//| .. method:: deinit() -//| -//| Disable permanently. -//| -STATIC mp_obj_t bleio_characteristic_buffer_deinit(mp_obj_t self_in) { - bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_bleio_characteristic_buffer_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_deinit_obj, bleio_characteristic_buffer_deinit); - -STATIC const mp_rom_map_elem_t bleio_characteristic_buffer_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bleio_characteristic_buffer_deinit_obj) }, - - // Standard stream methods. - { MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, - { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, - // CharacteristicBuffer is currently read-only. - // { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&bleio_characteristic_buffer_reset_input_buffer_obj) }, - // Properties - { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&bleio_characteristic_buffer_in_waiting_obj) }, - -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_buffer_locals_dict, bleio_characteristic_buffer_locals_dict_table); - -STATIC const mp_stream_p_t characteristic_buffer_stream_p = { - .read = bleio_characteristic_buffer_read, - .write = bleio_characteristic_buffer_write, - .ioctl = bleio_characteristic_buffer_ioctl, - .is_text = false, - // Match PySerial when possible, such as disallowing optional length argument for .readinto() - .pyserial_compatibility = true, -}; - - -const mp_obj_type_t bleio_characteristic_buffer_type = { - { &mp_type_type }, - .name = MP_QSTR_CharacteristicBuffer, - .make_new = bleio_characteristic_buffer_make_new, - .getiter = mp_identity_getiter, - .iternext = mp_stream_unbuffered_iter, - .protocol = &characteristic_buffer_stream_p, - .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_buffer_locals_dict -}; diff --git a/shared-bindings/bleio/CharacteristicBuffer.h b/shared-bindings/bleio/CharacteristicBuffer.h deleted file mode 100644 index b45835ff3..000000000 --- a/shared-bindings/bleio/CharacteristicBuffer.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H - -#include "common-hal/bleio/CharacteristicBuffer.h" - -extern const mp_obj_type_t bleio_characteristic_buffer_type; - -extern void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_float_t timeout, size_t buffer_size); -int common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode); -uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self); -void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self); -bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self); -int common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self); -bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTICBUFFER_H diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c deleted file mode 100644 index eba2ea1a8..000000000 --- a/shared-bindings/bleio/Descriptor.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2017 Glenn Ruben Bakke - * - * 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 "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Attribute.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/UUID.h" - -//| .. currentmodule:: bleio -//| -//| :class:`Descriptor` -- BLE descriptor -//| ========================================================= -//| -//| Stores information about a BLE descriptor. -//| Descriptors are attached to BLE characteristics and provide contextual -//| information about the characteristic. -//| -//| .. class:: Descriptor -//| -//| There is no regular constructor for a Descriptor. A new local Descriptor can be created -//| and attached to a Characteristic by calling `add_to_characteristic()`. -//| Remote Descriptor objects are created by `Central.discover_remote_services()` -//| or `Peripheral.discover_remote_services()` as part of remote Characteristics -//| in the remote Services that are discovered. -//| -//| .. classmethod:: add_to_characteristic(characteristic, uuid, *, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, initial_value=b'') -//| -//| Create a new Descriptor object, and add it to this Service. -//| -//| :param Characteristic characteristic: The characteristic that will hold this descriptor -//| :param UUID uuid: The uuid of the descriptor -//| :param int read_perm: Specifies whether the descriptor can be read by a client, and if so, which -//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, -//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, -//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`. -//| :param int write_perm: Specifies whether the descriptor can be written by a client, and if so, which -//| security mode is required. Values allowed are the same as ``read_perm``. -//| :param int max_length: Maximum length in bytes of the descriptor value. The maximum allowed is -//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum -//| number of data bytes that fit in a single BLE 4.x ATT packet. -//| :param bool fixed_length: True if the descriptor value is of fixed length. -//| :param buf initial_value: The initial value for this descriptor. -//| -//| :return: the new Descriptor. -//| -STATIC mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // class is arg[0], which we can ignore. - - enum { ARG_characteristic, ARG_uuid, ARG_read_perm, ARG_write_perm, - ARG_max_length, ARG_fixed_length, ARG_initial_value }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_characteristic, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, - { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, - { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} }, - { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_initial_value, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mp_obj_t characteristic_obj = args[ARG_characteristic].u_obj; - if (!MP_OBJ_IS_TYPE(characteristic_obj, &bleio_characteristic_type)) { - mp_raise_ValueError(translate("Expected a Characteristic")); - } - - const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - mp_raise_ValueError(translate("Expected a UUID")); - } - - const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int; - common_hal_bleio_attribute_security_mode_check_valid(read_perm); - - const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; - common_hal_bleio_attribute_security_mode_check_valid(write_perm); - - const mp_int_t max_length = args[ARG_max_length].u_int; - const bool fixed_length = args[ARG_fixed_length].u_bool; - mp_obj_t initial_value = args[ARG_initial_value].u_obj; - - // Length will be validated in common_hal. - mp_buffer_info_t initial_value_bufinfo; - if (initial_value == mp_const_none) { - if (fixed_length && max_length > 0) { - initial_value = mp_obj_new_bytes_of_zeros(max_length); - } else { - initial_value = mp_const_empty_bytes; - } - } - mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); - - bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); - descriptor->base.type = &bleio_descriptor_type; - - // Range checking on max_length arg is done by the common_hal layer, because - // it may vary depending on underlying BLE implementation. - common_hal_bleio_descriptor_construct( - descriptor, MP_OBJ_TO_PTR(characteristic_obj), MP_OBJ_TO_PTR(uuid_obj), - read_perm, write_perm, - max_length, fixed_length, &initial_value_bufinfo); - - common_hal_bleio_characteristic_add_descriptor(characteristic_obj, descriptor); - - return MP_OBJ_FROM_PTR(descriptor); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_descriptor_add_to_characteristic_fun_obj, 3, bleio_descriptor_add_to_characteristic); -STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_descriptor_add_to_characteristic_obj, MP_ROM_PTR(&bleio_descriptor_add_to_characteristic_fun_obj)); - -//| .. attribute:: uuid -//| -//| The descriptor uuid. (read-only) -//| -STATIC mp_obj_t bleio_descriptor_get_uuid(mp_obj_t self_in) { - bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - - bleio_uuid_obj_t *uuid = common_hal_bleio_descriptor_get_uuid(self); - return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_uuid_obj, bleio_descriptor_get_uuid); - -const mp_obj_property_t bleio_descriptor_uuid_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_descriptor_get_uuid_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: characteristic (read-only) -//| -//| The Characteristic this Descriptor is a part of. -//| -STATIC mp_obj_t bleio_descriptor_get_characteristic(mp_obj_t self_in) { - bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return common_hal_bleio_descriptor_get_characteristic(self); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_characteristic_obj, bleio_descriptor_get_characteristic); - -const mp_obj_property_t bleio_descriptor_characteristic_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_descriptor_get_characteristic_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: value -//| -//| The value of this descriptor. -//| -STATIC mp_obj_t bleio_descriptor_get_value(mp_obj_t self_in) { - bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return common_hal_bleio_descriptor_get_value(self); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_value_obj, bleio_descriptor_get_value); - -STATIC mp_obj_t bleio_descriptor_set_value(mp_obj_t self_in, mp_obj_t value_in) { - bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ); - - common_hal_bleio_descriptor_set_value(self, &bufinfo); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_descriptor_set_value_obj, bleio_descriptor_set_value); - -const mp_obj_property_t bleio_descriptor_value_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_descriptor_get_value_obj, - (mp_obj_t)&bleio_descriptor_set_value_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_add_to_characteristic), MP_ROM_PTR(&bleio_descriptor_add_to_characteristic_obj) }, - { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_descriptor_uuid_obj) }, - { MP_ROM_QSTR(MP_QSTR_characteristic), MP_ROM_PTR(&bleio_descriptor_characteristic_obj) }, - { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_descriptor_value_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_descriptor_locals_dict, bleio_descriptor_locals_dict_table); - -STATIC void bleio_descriptor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->uuid) { - mp_printf(print, "Descriptor("); - bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); - mp_printf(print, ")"); - } else { - mp_printf(print, ""); - } -} - -const mp_obj_type_t bleio_descriptor_type = { - { &mp_type_type }, - .name = MP_QSTR_Descriptor, - .print = bleio_descriptor_print, - .locals_dict = (mp_obj_dict_t*)&bleio_descriptor_locals_dict -}; diff --git a/shared-bindings/bleio/Descriptor.h b/shared-bindings/bleio/Descriptor.h deleted file mode 100644 index d12ebaab9..000000000 --- a/shared-bindings/bleio/Descriptor.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H - -#include "shared-module/bleio/Attribute.h" -#include "common-hal/bleio/Characteristic.h" -#include "common-hal/bleio/Descriptor.h" -#include "common-hal/bleio/UUID.h" - -extern const mp_obj_type_t bleio_descriptor_type; - -extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo); -extern bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self); -extern bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self); -extern mp_obj_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self); -extern void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H diff --git a/shared-bindings/bleio/Peripheral.c b/shared-bindings/bleio/Peripheral.c deleted file mode 100644 index 206f1c9a8..000000000 --- a/shared-bindings/bleio/Peripheral.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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 -#include - -#include "ble_drv.h" -#include "py/objarray.h" -#include "py/objproperty.h" -#include "py/objstr.h" -#include "py/runtime.h" - -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Peripheral.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" -#include "shared-module/bleio/ScanEntry.h" - -#include "common-hal/bleio/Peripheral.h" - -#define ADV_INTERVAL_MIN (0.0020f) -#define ADV_INTERVAL_MIN_STRING "0.0020" -#define ADV_INTERVAL_MAX (10.24f) -#define ADV_INTERVAL_MAX_STRING "10.24" -// 20ms is recommended by Apple -#define ADV_INTERVAL_DEFAULT (0.1f) - -//| .. currentmodule:: bleio -//| -//| :class:`Peripheral` -- A BLE peripheral device -//| ========================================================= -//| -//| Implement a BLE peripheral which runs locally. -//| Set up using the supplied services, and then allow advertising to be started and stopped. -//| -//| Usage:: -//| -//| from bleio import Characteristic, Peripheral, Service -//| from adafruit_ble.advertising import ServerAdvertisement -//| -//| # Create a peripheral and start it up. -//| peripheral = bleio.Peripheral() -//| -//| # Create a Service and add it to this Peripheral. -//| service = Service.add_to_peripheral(peripheral, bleio.UUID(0x180f)) -//| -//| # Create a Characteristic and add it to the Service. -//| characteristic = Characterist.add_to_service(service, -//| bleio.UUID(0x2919), properties=Characteristic.READ | Characteristic.NOTIFY) -//| -//| adv = ServerAdvertisement(peripheral) -//| peripheral.start_advertising(adv.advertising_data_bytes, scan_response=adv.scan_response_bytes) -//| -//| while not peripheral.connected: -//| # Wait for connection. -//| pass -//| -//| .. class:: Peripheral(name=None) -//| -//| Create a new Peripheral object. -//| -//| :param str name: The name used when advertising this peripheral. If name is None, -//| bleio.adapter.default_name will be used. -//| -STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_name }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_name, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - bleio_peripheral_obj_t *self = m_new_obj(bleio_peripheral_obj_t); - self->base.type = &bleio_peripheral_type; - - mp_obj_t name = args[ARG_name].u_obj; - if (name == mp_const_none) { - name = common_hal_bleio_adapter_get_default_name(); - } else if (!MP_OBJ_IS_STR(name)) { - mp_raise_ValueError(translate("name must be a string")); - } - - common_hal_bleio_peripheral_construct(self, name); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. attribute:: connected (read-only) -//| -//| True if connected to a BLE Central device. -//| -STATIC mp_obj_t bleio_peripheral_get_connected(mp_obj_t self_in) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_peripheral_get_connected(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_connected_obj, bleio_peripheral_get_connected); - -const mp_obj_property_t bleio_peripheral_connected_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_peripheral_get_connected_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: services -//| -//| A tuple of :py:class:`Service` objects offered by this peripheral. (read-only) -//| -STATIC mp_obj_t bleio_peripheral_get_services(mp_obj_t self_in) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *services_list = common_hal_bleio_peripheral_get_services(self); - return mp_obj_new_tuple(services_list->len, services_list->items); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_services_obj, bleio_peripheral_get_services); - -const mp_obj_property_t bleio_peripheral_services_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_peripheral_get_services_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: name -//| -//| The peripheral's name, included when advertising. (read-only) -//| -STATIC mp_obj_t bleio_peripheral_get_name(mp_obj_t self_in) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return common_hal_bleio_peripheral_get_name(self); -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_name_obj, bleio_peripheral_get_name); - -const mp_obj_property_t bleio_peripheral_name_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_peripheral_get_name_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. method:: start_advertising(data, *, scan_response=None, connectable=True, interval=0.1) -//| -//| Starts advertising the peripheral. The peripheral's name and -//| services are included in the advertisement packets. -//| -//| :param buf data: advertising data packet bytes -//| :param buf scan_response: scan response data packet bytes. ``None`` if no scan response is needed. -//| :param bool connectable: If `True` then other devices are allowed to connect to this peripheral. -//| :param float interval: advertising interval, in seconds -//| -STATIC mp_obj_t bleio_peripheral_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - enum { ARG_data, ARG_scan_response, ARG_connectable, ARG_interval }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_scan_response, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_buffer_info_t data_bufinfo; - mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ); - - // Pass an empty buffer if scan_response not provided. - mp_buffer_info_t scan_response_bufinfo = { 0 }; - if (args[ARG_scan_response].u_obj != mp_const_none) { - mp_get_buffer_raise(args[ARG_scan_response].u_obj, &scan_response_bufinfo, MP_BUFFER_READ); - } - - if (args[ARG_interval].u_obj == MP_OBJ_NULL) { - args[ARG_interval].u_obj = mp_obj_new_float(ADV_INTERVAL_DEFAULT); - } - - const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj); - if (interval < ADV_INTERVAL_MIN || interval > ADV_INTERVAL_MAX) { - mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), - ADV_INTERVAL_MIN_STRING, ADV_INTERVAL_MAX_STRING); - } - - common_hal_bleio_peripheral_start_advertising(self, args[ARG_connectable].u_bool, interval, - &data_bufinfo, &scan_response_bufinfo); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_start_advertising_obj, 2, bleio_peripheral_start_advertising); - -//| .. method:: stop_advertising() -//| -//| Stop sending advertising packets. -STATIC mp_obj_t bleio_peripheral_stop_advertising(mp_obj_t self_in) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - common_hal_bleio_peripheral_stop_advertising(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_stop_advertising_obj, bleio_peripheral_stop_advertising); - -//| .. method:: disconnect() -//| -//| Disconnects from the remote central. -//| Normally the central initiates a disconnection. Use this only -//| if necessary for your application. -//| -STATIC mp_obj_t bleio_peripheral_disconnect(mp_obj_t self_in) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - common_hal_bleio_peripheral_disconnect(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripheral_disconnect); - -//| .. method:: discover_remote_services(service_uuids_whitelist=None) -//| Do BLE discovery for all services or for the given service UUIDS, -//| to find their handles and characteristics, and return the discovered services. -//| `Peripheral.connected` must be True. -//| -//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services -//| provided by the peripheral that you want to use. -//| The peripheral may provide more services, but services not listed are ignored -//| and will not be returned. -//| -//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow. -//| -//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you -//| you must have already created a :py:class:~`UUID` object for that UUID in order for the -//| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered -//| for use. (This restriction may be lifted in the future.) -//| -//| Thought it is unusual for a peripheral to act as a BLE client, it can do so, and -//| needs to be able to do discovery on its peer (a central). -//| Examples include a peripheral accessing a central that provides Current Time Service, -//| Apple Notification Center Service, or Battery Service. -//| -//| :return: A tuple of services provided by the remote central. -//| -STATIC mp_obj_t bleio_peripheral_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - enum { ARG_service_uuids_whitelist }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (!common_hal_bleio_peripheral_get_connected(self)) { - mp_raise_ValueError(translate("Not connected")); - } - - return MP_OBJ_FROM_PTR(common_hal_bleio_peripheral_discover_remote_services( - MP_OBJ_FROM_PTR(self), - args[ARG_service_uuids_whitelist].u_obj)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_discover_remote_services_obj, 1, bleio_peripheral_discover_remote_services); - -//| .. method:: pair() -//| -//| Request pairing with connected central. -STATIC mp_obj_t bleio_peripheral_pair(mp_obj_t self_in) { - bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - - common_hal_bleio_peripheral_pair(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_pair_obj, bleio_peripheral_pair); - -STATIC const mp_rom_map_elem_t bleio_peripheral_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_peripheral_stop_advertising_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_peripheral_disconnect_obj) }, - { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_peripheral_discover_remote_services_obj) }, - { MP_ROM_QSTR(MP_QSTR_pair), MP_ROM_PTR(&bleio_peripheral_pair_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) }, - { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_peripheral_name_obj) }, - { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_peripheral_locals_dict, bleio_peripheral_locals_dict_table); - -const mp_obj_type_t bleio_peripheral_type = { - { &mp_type_type }, - .name = MP_QSTR_Peripheral, - .make_new = bleio_peripheral_make_new, - .locals_dict = (mp_obj_dict_t*)&bleio_peripheral_locals_dict -}; diff --git a/shared-bindings/bleio/Peripheral.h b/shared-bindings/bleio/Peripheral.h deleted file mode 100644 index a4bc9542b..000000000 --- a/shared-bindings/bleio/Peripheral.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H - -#include "py/objtuple.h" -#include "common-hal/bleio/Peripheral.h" -#include "common-hal/bleio/Service.h" - -extern const mp_obj_type_t bleio_peripheral_type; - -extern void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_t name); -extern void common_hal_bleio_peripheral_add_service(bleio_peripheral_obj_t *self, bleio_service_obj_t *service); -extern mp_obj_list_t *common_hal_bleio_peripheral_get_services(bleio_peripheral_obj_t *self); -extern bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self); -extern mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *self); -extern void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *device, bool connectable, float interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo); -extern void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *device); -extern void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *device); -extern mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist); -extern void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *device); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H diff --git a/shared-bindings/bleio/ScanEntry.c b/shared-bindings/bleio/ScanEntry.c deleted file mode 100644 index 6eb02c716..000000000 --- a/shared-bindings/bleio/ScanEntry.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2017 Glenn Ruben Bakke - * - * 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 - -#include "py/objproperty.h" -#include "shared-bindings/bleio/Address.h" -#include "shared-bindings/bleio/ScanEntry.h" -#include "shared-bindings/bleio/UUID.h" -#include "shared-module/bleio/ScanEntry.h" - -//| .. currentmodule:: bleio -//| -//| :class:`ScanEntry` -- BLE scan response entry -//| ========================================================= -//| -//| Encapsulates information about a device that was received as a -//| response to a BLE scan request. This object may only be created -//| by a `bleio.Scanner`: it has no user-visible constructor. -//| - -//| .. attribute:: address -//| -//| The address of the device (read-only), of type `bleio.Address`. -//| -STATIC mp_obj_t bleio_scanentry_get_address(mp_obj_t self_in) { - bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - return common_hal_bleio_scanentry_get_address(self); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_address_obj, bleio_scanentry_get_address); - -const mp_obj_property_t bleio_scanentry_address_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_scanentry_get_address_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: advertisement_bytes -//| -//| All the advertisement data present in the packet, returned as a ``bytes`` object. (read-only) -//| -STATIC mp_obj_t scanentry_get_advertisement_bytes(mp_obj_t self_in) { - bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - return common_hal_bleio_scanentry_get_advertisement_bytes(self); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_advertisement_bytes_obj, scanentry_get_advertisement_bytes); - -const mp_obj_property_t bleio_scanentry_advertisement_bytes_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_scanentry_get_advertisement_bytes_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: rssi -//| -//| The signal strength of the device at the time of the scan, in integer dBm. (read-only) -//| -STATIC mp_obj_t scanentry_get_rssi(mp_obj_t self_in) { - bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(common_hal_bleio_scanentry_get_rssi(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_rssi_obj, scanentry_get_rssi); - -const mp_obj_property_t bleio_scanentry_rssi_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_scanentry_get_rssi_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - - -STATIC const mp_rom_map_elem_t bleio_scanentry_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_scanentry_address_obj) }, - { MP_ROM_QSTR(MP_QSTR_advertisement_bytes), MP_ROM_PTR(&bleio_scanentry_advertisement_bytes_obj) }, - { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bleio_scanentry_rssi_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_scanentry_locals_dict, bleio_scanentry_locals_dict_table); - -const mp_obj_type_t bleio_scanentry_type = { - { &mp_type_type }, - .name = MP_QSTR_ScanEntry, - .locals_dict = (mp_obj_dict_t*)&bleio_scanentry_locals_dict -}; diff --git a/shared-bindings/bleio/ScanEntry.h b/shared-bindings/bleio/ScanEntry.h deleted file mode 100644 index 77e93175f..000000000 --- a/shared-bindings/bleio/ScanEntry.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2017 Glenn Ruben Bakke - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H - -#include "py/obj.h" -#include "shared-module/bleio/ScanEntry.h" - -extern const mp_obj_type_t bleio_scanentry_type; - -mp_obj_t common_hal_bleio_scanentry_get_address(bleio_scanentry_obj_t *self); -mp_obj_t common_hal_bleio_scanentry_get_advertisement_bytes(bleio_scanentry_obj_t *self); -mp_int_t common_hal_bleio_scanentry_get_rssi(bleio_scanentry_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H diff --git a/shared-bindings/bleio/Scanner.c b/shared-bindings/bleio/Scanner.c deleted file mode 100644 index 269c42591..000000000 --- a/shared-bindings/bleio/Scanner.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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 "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/ScanEntry.h" -#include "shared-bindings/bleio/Scanner.h" - -#define INTERVAL_DEFAULT (0.1f) -#define INTERVAL_MIN (0.0025f) -#define INTERVAL_MIN_STRING "0.0025" -#define INTERVAL_MAX (40.959375f) -#define INTERVAL_MAX_STRING "40.959375" -#define WINDOW_DEFAULT (0.1f) - -//| .. currentmodule:: bleio -//| -//| :class:`Scanner` -- scan for nearby BLE devices -//| ========================================================= -//| -//| Scan for nearby BLE devices. -//| -//| Usage:: -//| -//| import bleio -//| scanner = bleio.Scanner() -//| entries = scanner.scan(2.5) # Scan for 2.5 seconds -//| - -//| .. class:: Scanner() -//| -//| Create a new Scanner object. -//| -STATIC mp_obj_t bleio_scanner_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *all_args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 0, 0, false); - - bleio_scanner_obj_t *self = m_new_obj(bleio_scanner_obj_t); - self->base.type = type; - - common_hal_bleio_scanner_construct(self); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: scan(timeout, \*, interval=0.1, window=0.1) -//| -//| Performs a BLE scan. -//| -//| :param float timeout: the scan timeout in seconds -//| :param float interval: the interval (in seconds) between the start of two consecutive scan windows -//| Must be in the range 0.0025 - 40.959375 seconds. -//| :param float window: the duration (in seconds) to scan a single BLE channel. -//| window must be <= interval. -//| :returns: an iterable of `ScanEntry` objects -//| :rtype: iterable -//| -STATIC mp_obj_t bleio_scanner_scan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_timeout, ARG_interval, ARG_window }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_window, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - }; - - bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); - - if (args[ARG_interval].u_obj == MP_OBJ_NULL) { - args[ARG_interval].u_obj = mp_obj_new_float(INTERVAL_DEFAULT); - } - - if (args[ARG_window].u_obj == MP_OBJ_NULL) { - args[ARG_window].u_obj = mp_obj_new_float(WINDOW_DEFAULT); - } - - const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj); - if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { - mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), INTERVAL_MIN_STRING, INTERVAL_MAX_STRING); - } - - const mp_float_t window = mp_obj_float_get(args[ARG_window].u_obj); - if (window > interval) { - mp_raise_ValueError(translate("window must be <= interval")); - } - - return common_hal_bleio_scanner_scan(self, timeout, interval, window); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_scanner_scan_obj, 2, bleio_scanner_scan); - - -STATIC const mp_rom_map_elem_t bleio_scanner_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&bleio_scanner_scan_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_scanner_locals_dict, bleio_scanner_locals_dict_table); - -const mp_obj_type_t bleio_scanner_type = { - { &mp_type_type }, - .name = MP_QSTR_Scanner, - .make_new = bleio_scanner_make_new, - .locals_dict = (mp_obj_dict_t*)&bleio_scanner_locals_dict -}; diff --git a/shared-bindings/bleio/Scanner.h b/shared-bindings/bleio/Scanner.h deleted file mode 100644 index 3a0ce7eae..000000000 --- a/shared-bindings/bleio/Scanner.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H - -#include "py/objtype.h" -#include "common-hal/bleio/Scanner.h" - -extern const mp_obj_type_t bleio_scanner_type; - -extern void common_hal_bleio_scanner_construct(bleio_scanner_obj_t *self); -extern mp_obj_t common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_float_t timeout, mp_float_t interval, mp_float_t window); -extern void common_hal_bleio_scanner_stop(bleio_scanner_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c deleted file mode 100644 index f3bfebb7b..000000000 --- a/shared-bindings/bleio/Service.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2017 Glenn Ruben Bakke - * - * 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 "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Peripheral.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -//| .. currentmodule:: bleio -//| -//| :class:`Service` -- BLE service -//| ========================================================= -//| -//| Stores information about a BLE service and its characteristics. -//| -//| .. class:: Service -//| -//| There is no regular constructor for a Service. A new local Service can be created -//| and attached to a Peripheral by calling `add_to_peripheral()`. -//| Remote Service objects are created by `Central.discover_remote_services()` -//| or `Peripheral.discover_remote_services()`. -//| -//| .. classmethod:: add_to_peripheral(peripheral, uuid, *, secondary=False) -//| -//| Create a new Service object, identitied by the specified UUID, and add it -//| to the given Peripheral. -//| -//| To mark the service as secondary, pass `True` as :py:data:`secondary`. -//| -//| :param Peripheral peripheral: The peripheral that will provide this service -//| :param UUID uuid: The uuid of the service -//| :param bool secondary: If the service is a secondary one -// -//| :return: the new Service -//| -STATIC mp_obj_t bleio_service_add_to_peripheral(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - // class is arg[0], which we can ignore. - - enum { ARG_peripheral, ARG_uuid, ARG_secondary }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_peripheral, MP_ARG_REQUIRED | MP_ARG_OBJ,}, - { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_secondary, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mp_obj_t peripheral_obj = args[ARG_peripheral].u_obj; - if (!MP_OBJ_IS_TYPE(peripheral_obj, &bleio_peripheral_type)) { - mp_raise_ValueError(translate("Expected a Peripheral")); - } - - const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - mp_raise_ValueError(translate("Expected a UUID")); - } - - const bool is_secondary = args[ARG_secondary].u_bool; - - bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); - service->base.type = &bleio_service_type; - - common_hal_bleio_service_construct( - service, MP_OBJ_TO_PTR(peripheral_obj), MP_OBJ_TO_PTR(uuid_obj), is_secondary); - - common_hal_bleio_peripheral_add_service(peripheral_obj, service); - - return MP_OBJ_FROM_PTR(service); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_service_add_to_peripheral_fun_obj, 3, bleio_service_add_to_peripheral); -STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_service_add_to_peripheral_obj, MP_ROM_PTR(&bleio_service_add_to_peripheral_fun_obj)); - -//| .. attribute:: characteristics -//| -//| A tuple of :py:class:`Characteristic` designating the characteristics that are offered by this service. (read-only) -//| -STATIC mp_obj_t bleio_service_get_characteristics(mp_obj_t self_in) { - bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); - // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *char_list = common_hal_bleio_service_get_characteristic_list(self); - return mp_obj_new_tuple(char_list->len, char_list->items); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_characteristics_obj, bleio_service_get_characteristics); - -const mp_obj_property_t bleio_service_characteristics_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_service_get_characteristics_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: remote -//| -//| True if this is a service provided by a remote device. (read-only) -//| -STATIC mp_obj_t bleio_service_get_remote(mp_obj_t self_in) { - bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_service_get_is_remote(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_remote_obj, bleio_service_get_remote); - -const mp_obj_property_t bleio_service_remote_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_service_get_remote_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: secondary -//| -//| True if this is a secondary service. (read-only) -//| -STATIC mp_obj_t bleio_service_get_secondary(mp_obj_t self_in) { - bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_bool(common_hal_bleio_service_get_is_secondary(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_secondary_obj, bleio_service_get_secondary); - -const mp_obj_property_t bleio_service_secondary_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_service_get_secondary_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -//| .. attribute:: uuid -//| -//| The UUID of this service. (read-only) -//| Will be ``None`` if the 128-bit UUID for this service is not known. -//| -STATIC mp_obj_t bleio_service_get_uuid(mp_obj_t self_in) { - bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); - - bleio_uuid_obj_t *uuid = common_hal_bleio_service_get_uuid(self); - return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_uuid_obj, bleio_service_get_uuid); - -const mp_obj_property_t bleio_service_uuid_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_service_get_uuid_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - - -STATIC const mp_rom_map_elem_t bleio_service_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_add_to_peripheral), MP_ROM_PTR(&bleio_service_add_to_peripheral_obj) }, - { MP_ROM_QSTR(MP_QSTR_characteristics), MP_ROM_PTR(&bleio_service_characteristics_obj) }, - { MP_ROM_QSTR(MP_QSTR_secondary), MP_ROM_PTR(&bleio_service_secondary_obj) }, - { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_service_uuid_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(bleio_service_locals_dict, bleio_service_locals_dict_table); - -STATIC void bleio_service_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->uuid) { - mp_printf(print, "Service("); - bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); - mp_printf(print, ")"); - } else { - mp_printf(print, ""); - } -} - -const mp_obj_type_t bleio_service_type = { - { &mp_type_type }, - .name = MP_QSTR_Service, - .print = bleio_service_print, - .locals_dict = (mp_obj_dict_t*)&bleio_service_locals_dict -}; diff --git a/shared-bindings/bleio/Service.h b/shared-bindings/bleio/Service.h deleted file mode 100644 index ce4e51417..000000000 --- a/shared-bindings/bleio/Service.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H - -#include "common-hal/bleio/Peripheral.h" -#include "common-hal/bleio/Service.h" - -const mp_obj_type_t bleio_service_type; - -extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_peripheral_obj_t *peripheral, bleio_uuid_obj_t *uuid, bool is_secondary); -extern bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self); -extern mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self); -extern bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self); -extern bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self); -extern void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H diff --git a/shared-bindings/bleio/UUID.c b/shared-bindings/bleio/UUID.c deleted file mode 100644 index dca7ea010..000000000 --- a/shared-bindings/bleio/UUID.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2017 Glenn Ruben Bakke - * - * 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 - -#include "py/objproperty.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/UUID.h" - -//| .. currentmodule:: bleio -//| -//| :class:`UUID` -- BLE UUID -//| ========================================================= -//| -//| A 16-bit or 128-bit UUID. Can be used for services, characteristics, descriptors and more. -//| - -//| .. class:: UUID(value) -//| -//| Create a new UUID or UUID object encapsulating the uuid value. -//| The value can be one of: -//| -//| - an `int` value in range 0 to 0xFFFF (Bluetooth SIG 16-bit UUID) -//| - a buffer object (bytearray, bytes) of 16 bytes in little-endian order (128-bit UUID) -//| - a string of hex digits of the form 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' -//| -//| Creating a 128-bit UUID registers the UUID with the onboard BLE software, and provides a -//| temporary 16-bit UUID that can be used in place of the full 128-bit UUID. -//| -//| :param value: The uuid value to encapsulate -//| :type value: int or typing.ByteString -//| -STATIC mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 1, 1, false); - - bleio_uuid_obj_t *self = m_new_obj(bleio_uuid_obj_t); - self->base.type = type; - - const mp_obj_t value = pos_args[0]; - uint8_t uuid128[16]; - - if (MP_OBJ_IS_INT(value)) { - mp_int_t uuid16 = mp_obj_get_int(value); - if (uuid16 < 0 || uuid16 > 0xffff) { - mp_raise_ValueError(translate("UUID integer value must be 0-0xffff")); - } - - // NULL means no 128-bit value. - common_hal_bleio_uuid_construct(self, uuid16, NULL); - - } else { - if (MP_OBJ_IS_STR(value)) { - // 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' - GET_STR_DATA_LEN(value, chars, len); - char hex[32]; - // Validate length, hyphens, and hex digits. - bool good_uuid = - len == 36 && chars[8] == '-' && chars[13] == '-' && chars[18] == '-' && chars[23] == '-'; - if (good_uuid) { - size_t hex_idx = 0; - for (size_t i = 0; i < len; i++) { - if (unichar_isxdigit(chars[i])) { - hex[hex_idx] = chars[i]; - hex_idx++; - } - } - good_uuid = hex_idx == 32; - } - if (!good_uuid) { - mp_raise_ValueError(translate("UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'")); - } - - size_t hex_idx = 0; - for (int i = 15; i >= 0; i--) { - uuid128[i] = (unichar_xdigit_value(hex[hex_idx]) << 4) | unichar_xdigit_value(hex[hex_idx + 1]); - hex_idx += 2; - } - } else { - // Last possibility is that it's a buf. - mp_buffer_info_t bufinfo; - if (!mp_get_buffer(value, &bufinfo, MP_BUFFER_READ)) { - mp_raise_ValueError(translate("UUID value is not str, int or byte buffer")); - } - - if (bufinfo.len != 16) { - mp_raise_ValueError(translate("Byte buffer must be 16 bytes.")); - } - - memcpy(uuid128, bufinfo.buf, 16); - } - - // Str and bytes both get constructed the same way here. - uint32_t uuid16 = (uuid128[13] << 8) | uuid128[12]; - uuid128[12] = 0; - uuid128[13] = 0; - common_hal_bleio_uuid_construct(self, uuid16, uuid128); - } - - return MP_OBJ_FROM_PTR(self); -} - -//| .. attribute:: uuid16 -//| -//| The 16-bit part of the UUID. (read-only) -//| -//| :type: int -//| -STATIC mp_obj_t bleio_uuid_get_uuid16(mp_obj_t self_in) { - bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_uuid16(self)); -} - -MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_uuid16_obj, bleio_uuid_get_uuid16); - -const mp_obj_property_t bleio_uuid_uuid16_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_uuid_get_uuid16_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: uuid128 -//| -//| The 128-bit value of the UUID -//| Raises AttributeError if this is a 16-bit UUID. (read-only) -//| -//| :type: bytes -//| -STATIC mp_obj_t bleio_uuid_get_uuid128(mp_obj_t self_in) { - bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); - - uint8_t uuid128[16]; - if (!common_hal_bleio_uuid_get_uuid128(self, uuid128)) { - mp_raise_AttributeError(translate("not a 128-bit UUID")); - } - return mp_obj_new_bytes(uuid128, 16); -} - -MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_uuid128_obj, bleio_uuid_get_uuid128); - -const mp_obj_property_t bleio_uuid_uuid128_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_uuid_get_uuid128_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| .. attribute:: size -//| -//| 128 if this UUID represents a 128-bit vendor-specific UUID. 16 if this UUID represents a -//| 16-bit Bluetooth SIG assigned UUID. (read-only) 32-bit UUIDs are not currently supported. -//| -//| :type: int -//| -STATIC mp_obj_t bleio_uuid_get_size(mp_obj_t self_in) { - bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_size(self)); -} - -MP_DEFINE_CONST_FUN_OBJ_1(bleio_uuid_get_size_obj, bleio_uuid_get_size); - -const mp_obj_property_t bleio_uuid_size_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&bleio_uuid_get_size_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t bleio_uuid_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_uuid16), MP_ROM_PTR(&bleio_uuid_uuid16_obj) }, - { MP_ROM_QSTR(MP_QSTR_uuid128), MP_ROM_PTR(&bleio_uuid_uuid128_obj) }, - { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&bleio_uuid_size_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_uuid_locals_dict, bleio_uuid_locals_dict_table); - -STATIC mp_obj_t bleio_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) { - bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); - switch (op) { - case MP_UNARY_OP_HASH: - if (common_hal_bleio_uuid_get_size(self) == 16) { - return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_uuid16(self)); - } else { - union { - uint8_t uuid128_bytes[16]; - uint16_t uuid128_uint16[8]; - } uuid128; - common_hal_bleio_uuid_get_uuid128(self, uuid128.uuid128_bytes); - int hash = 0; - for (size_t i = 0; i < MP_ARRAY_SIZE(uuid128.uuid128_uint16); i++) { - hash += uuid128.uuid128_uint16[i]; - } - return MP_OBJ_NEW_SMALL_INT(hash); - } - default: - return MP_OBJ_NULL; // op not supported - } -} - -//| - -//| .. method:: __eq__(other) -//| -//| Two UUID objects are equal if their values match and they are both 128-bit or both 16-bit. -//| -STATIC mp_obj_t bleio_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { - switch (op) { - // Two UUID's are equal if their uuid16 values and uuid128 references match. - case MP_BINARY_OP_EQUAL: - if (MP_OBJ_IS_TYPE(rhs_in, &bleio_uuid_type)) { - return mp_obj_new_bool( - common_hal_bleio_uuid_get_uuid16(lhs_in) == common_hal_bleio_uuid_get_uuid16(rhs_in) && - common_hal_bleio_uuid_get_uuid128_reference(lhs_in) == - common_hal_bleio_uuid_get_uuid128_reference(rhs_in)); - } else { - return mp_const_false; - } - - default: - return MP_OBJ_NULL; // op not supported - } -} - -void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint32_t size = common_hal_bleio_uuid_get_size(self); - if (size == 16) { - mp_printf(print, "UUID(0x%04x)", common_hal_bleio_uuid_get_uuid16(self)); - } else { - uint8_t uuid128[16]; - (void) common_hal_bleio_uuid_get_uuid128(self, uuid128); - mp_printf(print, "UUID('" - "%02x%02x%02x%02x-" - "%02x%02x-" - "%02x%02x-" - "%02x%02x-" - "%02x%02x%02x%02x%02x%02x')", - uuid128[15], uuid128[14], uuid128[13], uuid128[12], - uuid128[11], uuid128[10], - uuid128[9], uuid128[8], - uuid128[7], uuid128[6], - uuid128[5], uuid128[4], uuid128[3], uuid128[2], uuid128[1], uuid128[0]); - } -} - -const mp_obj_type_t bleio_uuid_type = { - { &mp_type_type }, - .name = MP_QSTR_UUID, - .print = bleio_uuid_print, - .make_new = bleio_uuid_make_new, - .unary_op = bleio_uuid_unary_op, - .binary_op = bleio_uuid_binary_op, - .locals_dict = (mp_obj_dict_t*)&bleio_uuid_locals_dict, -}; diff --git a/shared-bindings/bleio/UUID.h b/shared-bindings/bleio/UUID.h deleted file mode 100644 index caf039aec..000000000 --- a/shared-bindings/bleio/UUID.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H - -#include "common-hal/bleio/UUID.h" - -void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); - -extern const mp_obj_type_t bleio_uuid_type; - -extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, uint8_t uuid128[]); -extern uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self); -extern bool common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]); -extern uint32_t common_hal_bleio_uuid_get_uuid128_reference(bleio_uuid_obj_t *self); -extern uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c deleted file mode 100644 index 739f461a5..000000000 --- a/shared-bindings/bleio/__init__.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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 "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Address.h" -#include "shared-bindings/bleio/Attribute.h" -#include "shared-bindings/bleio/Central.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/CharacteristicBuffer.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/Peripheral.h" -#include "shared-bindings/bleio/ScanEntry.h" -#include "shared-bindings/bleio/Scanner.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -//| :mod:`bleio` --- Bluetooth Low Energy (BLE) communication -//| ================================================================ -//| -//| .. module:: bleio -//| :synopsis: Bluetooth Low Energy functionality -//| :platform: nRF -//| -//| The `bleio` module provides necessary low-level functionality for communicating -//| using Bluetooth Low Energy (BLE). We recommend you use `bleio` in conjunction -//| with the `adafruit_ble `_ -//| CircuitPython library, which builds on `bleio`, and -//| provides higher-level convenience functionality, including predefined beacons, clients, -//| servers. -//| -//| Libraries -//| -//| .. toctree:: -//| :maxdepth: 3 -//| -//| Address -//| Adapter -//| Attribute -//| Central -//| Characteristic -//| CharacteristicBuffer -//| Descriptor -//| Peripheral -//| ScanEntry -//| Scanner -//| Service -//| UUID -//| -//| .. attribute:: adapter -//| -//| BLE Adapter information, such as enabled state as well as MAC -//| address. -//| This object is the sole instance of `bleio.Adapter`. -//| - -STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) }, - { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) }, - { MP_ROM_QSTR(MP_QSTR_Attribute), MP_ROM_PTR(&bleio_attribute_type) }, - { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&bleio_central_type) }, - { MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) }, - { MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_ROM_PTR(&bleio_characteristic_buffer_type) }, - { MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) }, - { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&bleio_peripheral_type) }, - { MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) }, - { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) }, - { MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) }, - { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); - -const mp_obj_module_t bleio_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&bleio_module_globals, -}; diff --git a/shared-bindings/bleio/__init__.h b/shared-bindings/bleio/__init__.h deleted file mode 100644 index c84895068..000000000 --- a/shared-bindings/bleio/__init__.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2016 Glenn Ruben Bakke - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H - -#include "py/objlist.h" - -#include "shared-bindings/bleio/Adapter.h" - -#include "common-hal/bleio/__init__.h" -#include "common-hal/bleio/Adapter.h" - -extern const super_adapter_obj_t common_hal_bleio_adapter_obj; - -extern void common_hal_bleio_check_connected(uint16_t conn_handle); - -extern uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); -extern mp_obj_list_t *common_hal_bleio_device_get_remote_service_list(mp_obj_t device); -extern void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); - -extern mp_obj_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle); -extern void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); -extern void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); - - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H diff --git a/shared-module/_bleio/Address.c b/shared-module/_bleio/Address.c new file mode 100644 index 000000000..8c8b043fe --- /dev/null +++ b/shared-module/_bleio/Address.c @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 + +#include "py/objstr.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-module/_bleio/Address.h" + +void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type) { + self->bytes = mp_obj_new_bytes(bytes, NUM_BLEIO_ADDRESS_BYTES); + self->type = address_type; +} + +mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self) { + return self->bytes; +} + +uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self) { + return self->type; +} diff --git a/shared-module/_bleio/Address.h b/shared-module/_bleio/Address.h new file mode 100644 index 000000000..39789842f --- /dev/null +++ b/shared-module/_bleio/Address.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H + +#include "py/obj.h" + +#define NUM_BLEIO_ADDRESS_BYTES 6 + +typedef struct { + mp_obj_base_t base; + uint8_t type; + mp_obj_t bytes; // a bytes() object +} bleio_address_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H diff --git a/shared-module/_bleio/Attribute.c b/shared-module/_bleio/Attribute.c new file mode 100644 index 000000000..3acfcf1f5 --- /dev/null +++ b/shared-module/_bleio/Attribute.c @@ -0,0 +1,46 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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 + +#include "py/runtime.h" +#include "shared-bindings/_bleio/Attribute.h" + +void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SECURITY_MODE_NO_ACCESS: + case SECURITY_MODE_OPEN: + case SECURITY_MODE_ENC_NO_MITM: + case SECURITY_MODE_ENC_WITH_MITM: + case SECURITY_MODE_LESC_ENC_WITH_MITM: + case SECURITY_MODE_SIGNED_NO_MITM: + case SECURITY_MODE_SIGNED_WITH_MITM: + break; + default: + mp_raise_ValueError(translate("Invalid security_mode")); + break; + } +} diff --git a/shared-module/_bleio/Attribute.h b/shared-module/_bleio/Attribute.h new file mode 100644 index 000000000..a498a14a5 --- /dev/null +++ b/shared-module/_bleio/Attribute.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H + +// BLE security modes: 0x +typedef enum { + SECURITY_MODE_NO_ACCESS = 0x00, + SECURITY_MODE_OPEN = 0x11, + SECURITY_MODE_ENC_NO_MITM = 0x21, + SECURITY_MODE_ENC_WITH_MITM = 0x31, + SECURITY_MODE_LESC_ENC_WITH_MITM = 0x41, + SECURITY_MODE_SIGNED_NO_MITM = 0x12, + SECURITY_MODE_SIGNED_WITH_MITM = 0x22, +} bleio_attribute_security_mode_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H diff --git a/shared-module/_bleio/Characteristic.h b/shared-module/_bleio/Characteristic.h new file mode 100644 index 000000000..409a57c76 --- /dev/null +++ b/shared-module/_bleio/Characteristic.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H + +typedef enum { + CHAR_PROP_NONE = 0, + CHAR_PROP_BROADCAST = 1u << 0, + CHAR_PROP_INDICATE = 1u << 1, + CHAR_PROP_NOTIFY = 1u << 2, + CHAR_PROP_READ = 1u << 3, + CHAR_PROP_WRITE = 1u << 4, + CHAR_PROP_WRITE_NO_RESPONSE = 1u << 5, + CHAR_PROP_ALL = (CHAR_PROP_BROADCAST | CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY | + CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE) +} bleio_characteristic_properties_enum_t; +typedef uint8_t bleio_characteristic_properties_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H diff --git a/shared-module/_bleio/ScanEntry.c b/shared-module/_bleio/ScanEntry.c new file mode 100644 index 000000000..8dfa17f31 --- /dev/null +++ b/shared-module/_bleio/ScanEntry.c @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke + * + * 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 + +#include "shared-bindings/_bleio/Address.h" +#include "shared-module/_bleio/Address.h" +#include "shared-module/_bleio/ScanEntry.h" + +mp_obj_t common_hal_bleio_scanentry_get_address(bleio_scanentry_obj_t *self) { + return MP_OBJ_FROM_PTR(self->address); +} + +mp_obj_t common_hal_bleio_scanentry_get_advertisement_bytes(bleio_scanentry_obj_t *self) { + return self->data; +} + +mp_int_t common_hal_bleio_scanentry_get_rssi(bleio_scanentry_obj_t *self) { + return self->rssi; +} diff --git a/shared-module/_bleio/ScanEntry.h b/shared-module/_bleio/ScanEntry.h new file mode 100644 index 000000000..1e798d78f --- /dev/null +++ b/shared-module/_bleio/ScanEntry.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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. + */ + +#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H + +#include "py/obj.h" +#include "shared-bindings/_bleio/Address.h" + +typedef struct { + mp_obj_base_t base; + bool connectable; + int8_t rssi; + bleio_address_obj_t *address; + mp_obj_t data; +} bleio_scanentry_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H diff --git a/shared-module/bleio/Address.c b/shared-module/bleio/Address.c deleted file mode 100644 index 6bc458b7c..000000000 --- a/shared-module/bleio/Address.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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 - -#include "py/objstr.h" -#include "shared-bindings/bleio/Address.h" -#include "shared-module/bleio/Address.h" - -void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type) { - self->bytes = mp_obj_new_bytes(bytes, NUM_BLEIO_ADDRESS_BYTES); - self->type = address_type; -} - -mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self) { - return self->bytes; -} - -uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self) { - return self->type; -} diff --git a/shared-module/bleio/Address.h b/shared-module/bleio/Address.h deleted file mode 100644 index 39789842f..000000000 --- a/shared-module/bleio/Address.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H -#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H - -#include "py/obj.h" - -#define NUM_BLEIO_ADDRESS_BYTES 6 - -typedef struct { - mp_obj_base_t base; - uint8_t type; - mp_obj_t bytes; // a bytes() object -} bleio_address_obj_t; - -#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ADDRESS_H diff --git a/shared-module/bleio/Attribute.c b/shared-module/bleio/Attribute.c deleted file mode 100644 index 2275003c9..000000000 --- a/shared-module/bleio/Attribute.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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 - -#include "py/runtime.h" -#include "shared-bindings/bleio/Attribute.h" - -void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode) { - switch (security_mode) { - case SECURITY_MODE_NO_ACCESS: - case SECURITY_MODE_OPEN: - case SECURITY_MODE_ENC_NO_MITM: - case SECURITY_MODE_ENC_WITH_MITM: - case SECURITY_MODE_LESC_ENC_WITH_MITM: - case SECURITY_MODE_SIGNED_NO_MITM: - case SECURITY_MODE_SIGNED_WITH_MITM: - break; - default: - mp_raise_ValueError(translate("Invalid security_mode")); - break; - } -} diff --git a/shared-module/bleio/Attribute.h b/shared-module/bleio/Attribute.h deleted file mode 100644 index a498a14a5..000000000 --- a/shared-module/bleio/Attribute.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H -#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H - -// BLE security modes: 0x -typedef enum { - SECURITY_MODE_NO_ACCESS = 0x00, - SECURITY_MODE_OPEN = 0x11, - SECURITY_MODE_ENC_NO_MITM = 0x21, - SECURITY_MODE_ENC_WITH_MITM = 0x31, - SECURITY_MODE_LESC_ENC_WITH_MITM = 0x41, - SECURITY_MODE_SIGNED_NO_MITM = 0x12, - SECURITY_MODE_SIGNED_WITH_MITM = 0x22, -} bleio_attribute_security_mode_t; - -#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H diff --git a/shared-module/bleio/Characteristic.h b/shared-module/bleio/Characteristic.h deleted file mode 100644 index 409a57c76..000000000 --- a/shared-module/bleio/Characteristic.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H -#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H - -typedef enum { - CHAR_PROP_NONE = 0, - CHAR_PROP_BROADCAST = 1u << 0, - CHAR_PROP_INDICATE = 1u << 1, - CHAR_PROP_NOTIFY = 1u << 2, - CHAR_PROP_READ = 1u << 3, - CHAR_PROP_WRITE = 1u << 4, - CHAR_PROP_WRITE_NO_RESPONSE = 1u << 5, - CHAR_PROP_ALL = (CHAR_PROP_BROADCAST | CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY | - CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE) -} bleio_characteristic_properties_enum_t; -typedef uint8_t bleio_characteristic_properties_t; - -#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H diff --git a/shared-module/bleio/ScanEntry.c b/shared-module/bleio/ScanEntry.c deleted file mode 100644 index 306ac33c5..000000000 --- a/shared-module/bleio/ScanEntry.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2017 Glenn Ruben Bakke - * - * 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 - -#include "shared-bindings/bleio/Address.h" -#include "shared-module/bleio/Address.h" -#include "shared-module/bleio/ScanEntry.h" - -mp_obj_t common_hal_bleio_scanentry_get_address(bleio_scanentry_obj_t *self) { - return MP_OBJ_FROM_PTR(self->address); -} - -mp_obj_t common_hal_bleio_scanentry_get_advertisement_bytes(bleio_scanentry_obj_t *self) { - return self->data; -} - -mp_int_t common_hal_bleio_scanentry_get_rssi(bleio_scanentry_obj_t *self) { - return self->rssi; -} diff --git a/shared-module/bleio/ScanEntry.h b/shared-module/bleio/ScanEntry.h deleted file mode 100644 index b302460e6..000000000 --- a/shared-module/bleio/ScanEntry.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Dan Halbert for Adafruit Industries - * Copyright (c) 2018 Artur Pacholec - * - * 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. - */ - -#ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H -#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H - -#include "py/obj.h" -#include "shared-bindings/bleio/Address.h" - -typedef struct { - mp_obj_base_t base; - bool connectable; - int8_t rssi; - bleio_address_obj_t *address; - mp_obj_t data; -} bleio_scanentry_obj_t; - -#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_SCANENTRY_H -- cgit v1.2.3 From 3c7c3c98d7f497df33f0503162fb7b1721ef7ecd Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 31 Aug 2019 17:36:54 -0500 Subject: include CMSIS instrinsic addition functions for M4; cleanup C math funcs --- shared-module/audiomixer/Mixer.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) (limited to 'shared-module') diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index da0f7dedb..b61ba1eb0 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -95,32 +95,28 @@ void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t* self, uint32_t add8signed(uint32_t a, uint32_t b) { #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return __QADD8(a, b); + return __SHADD8(a, b); #else uint32_t result = 0; for (int8_t i = 0; i < 4; i++) { int8_t ai = a >> (sizeof(int8_t) * 8 * i); int8_t bi = b >> (sizeof(int8_t) * 8 * i); - int32_t intermediate = (int32_t) ai + bi; + int32_t intermediate = (int32_t) ai + bi / 2; if (intermediate > CHAR_MAX) { intermediate = CHAR_MAX; } else if (intermediate < CHAR_MIN) { intermediate = CHAR_MIN; } - result |= (((uint32_t) intermediate) & 0xff) << (sizeof(int8_t) * 8 * i); + result |= ((uint32_t) intermediate & 0xff) << (sizeof(int8_t) * 8 * i); } return result; #endif } uint32_t add8unsigned(uint32_t a, uint32_t b) { - /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - // Subtract out the DC offset, add and then shift back. - a = __USUB8(a, 0x80808080); - b = __USUB8(b, 0x80808080); - uint32_t sum = __QADD8(a, b); - return __UADD8(sum, 0x80808080); - #else*/ + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return __UHADD8(a, b); + #else uint32_t result = 0; for (int8_t i = 0; i < 4; i++) { uint8_t ai = (a >> (sizeof(uint8_t) * 8 * i)); @@ -132,18 +128,18 @@ uint32_t add8unsigned(uint32_t a, uint32_t b) { result |= ((uint32_t) intermediate & 0xff) << (sizeof(uint8_t) * 8 * i); } return result; - //#endif + #endif } uint32_t add16signed(uint32_t a, uint32_t b) { - /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - return __QADD16(a, b); - #else*/ + #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + return __SHADD16(a, b); + #else uint32_t result = 0; for (int8_t i = 0; i < 2; i++) { int16_t ai = a >> (sizeof(int16_t) * 8 * i); int16_t bi = b >> (sizeof(int16_t) * 8 * i); - int32_t intermediate = (int32_t) ai + bi; + int32_t intermediate = (int32_t) ai + bi / 2; if (intermediate > SHRT_MAX) { intermediate = SHRT_MAX; } else if (intermediate < SHRT_MIN) { @@ -152,26 +148,22 @@ uint32_t add16signed(uint32_t a, uint32_t b) { result |= (((uint32_t) intermediate) & 0xffff) << (sizeof(int16_t) * 8 * i); } return result; - //#endif + #endif } uint32_t add16unsigned(uint32_t a, uint32_t b) { #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - // Subtract out the DC offset, add and then shift back. - a = __USUB16(a, 0x80008000); - b = __USUB16(b, 0x80008000); - uint32_t sum = __QADD16(a, b); - return __UADD16(sum, 0x80008000); + return __UHADD16(a, b); #else uint32_t result = 0; for (int8_t i = 0; i < 2; i++) { int16_t ai = (a >> (sizeof(uint16_t) * 8 * i)) - 0x8000; int16_t bi = (b >> (sizeof(uint16_t) * 8 * i)) - 0x8000; - int32_t intermediate = (int32_t) ai + bi; + int32_t intermediate = (int32_t) ai + bi / 2; if (intermediate > USHRT_MAX) { intermediate = USHRT_MAX; } - result |= ((uint16_t) intermediate + 0x8000) << (sizeof(int16_t) * 8 * i); + result |= ((uint32_t) intermediate & 0xffff) << (sizeof(int16_t) * 8 * i); } return result; #endif -- cgit v1.2.3 From d87bfaf4800b3ed169831ba3ccdd4c52772cafe4 Mon Sep 17 00:00:00 2001 From: Matthew Newberg Date: Sat, 31 Aug 2019 22:07:09 -0400 Subject: Add random dithering to ColorConverter --- shared-bindings/displayio/Display.c | 28 +++++++++++ shared-bindings/displayio/Display.h | 3 ++ shared-module/displayio/ColorConverter.c | 79 ++++++++++++++++++++++++++------ shared-module/displayio/ColorConverter.h | 6 ++- shared-module/displayio/Display.c | 8 ++++ shared-module/displayio/Palette.h | 15 ++++++ shared-module/displayio/TileGrid.c | 52 +++++++++++---------- shared-module/displayio/display_core.c | 9 ++++ shared-module/displayio/display_core.h | 3 ++ 9 files changed, 164 insertions(+), 39 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 1eb1943b8..58d5e5123 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -346,6 +346,33 @@ const mp_obj_property_t displayio_display_auto_brightness_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| .. attribute:: dither +//| +//| True when the display is dithered +//| +STATIC mp_obj_t displayio_display_obj_get_dither(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + return mp_obj_new_bool(common_hal_displayio_display_get_dither(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_dither_obj, displayio_display_obj_get_dither); + +STATIC mp_obj_t displayio_display_obj_set_dither(mp_obj_t self_in, mp_obj_t dither) { + displayio_display_obj_t *self = native_display(self_in); + + common_hal_displayio_display_set_dither(self, mp_obj_is_true(dither)); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_dither_obj, displayio_display_obj_set_dither); + +const mp_obj_property_t displayio_display_dither_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_dither_obj, + (mp_obj_t)&displayio_display_set_dither_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + //| .. attribute:: width //| //| Gets the width of the board @@ -487,6 +514,7 @@ STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) }, { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) }, + { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_display_dither_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) }, diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index a3c77e4e8..ca2b2d476 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -62,6 +62,9 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); +bool common_hal_displayio_display_get_dither(displayio_display_obj_t* self); +void common_hal_displayio_display_set_dither(displayio_display_obj_t* self, bool dither); + mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self); bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, mp_float_t brightness); diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 940aaa1c6..cf93e71b7 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -28,6 +28,17 @@ #include "py/misc.h" +uint32_t displayio_colorconverter_dither_noise_1 (uint32_t n) +{ + n = (n >> 13) ^ n; + int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + return (uint32_t) (((float)nn / (1073741824.0f*2)) * 255); +} + +uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y) { + return displayio_colorconverter_dither_noise_1(x + y * 0xFFFF); +} + void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self) { } @@ -96,34 +107,72 @@ void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t* co } } -bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { +void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { + displayio_input_pixel_t input_pixel; + input_pixel.pixel = input_color; + input_pixel.x = input_pixel.y = input_pixel.tile = input_pixel.tile_x = input_pixel.tile_y = 0; + + displayio_output_pixel_t output_pixel; + output_pixel.pixel = 0; + output_pixel.opaque = false; + + displayio_colorconverter_convert(self, colorspace, &input_pixel, &output_pixel); + + (*output_color) = output_pixel.pixel; +} + +bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { + uint32_t pixel = input_pixel->pixel; + + if (colorspace->dither){ + uint8_t randr = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y)); + uint8_t randg = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x+33,input_pixel->tile_y)); + uint8_t randb = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y+33)); + + uint32_t r8 = (pixel >> 16); + uint32_t g8 = (pixel >> 8) & 0xff; + uint32_t b8 = pixel & 0xff; + + if (colorspace->depth == 16) { + b8 = MIN(255,b8 + (randb&0x07)); + r8 = MIN(255,r8 + (randr&0x07)); + g8 = MIN(255,g8 + (randg&0x03)); + } else { + int bitmask = 0xFF >> colorspace->depth; + b8 = MIN(255,b8 + (randb&bitmask)); + r8 = MIN(255,r8 + (randr&bitmask)); + g8 = MIN(255,g8 + (randg&bitmask)); + } + pixel = r8 << 16 | g8 << 8 | b8; + } + if (colorspace->depth == 16) { - *output_color = displayio_colorconverter_compute_rgb565(input_color); + output_color->pixel = displayio_colorconverter_compute_rgb565(pixel); + output_color->opaque = true; return true; } else if (colorspace->tricolor) { - uint8_t luma = displayio_colorconverter_compute_luma(input_color); - *output_color = luma >> (8 - colorspace->depth); - if (displayio_colorconverter_compute_chroma(input_color) <= 16) { + uint8_t luma = displayio_colorconverter_compute_luma(pixel); + output_color->pixel = luma >> (8 - colorspace->depth); + if (displayio_colorconverter_compute_chroma(pixel) <= 16) { if (!colorspace->grayscale) { - *output_color = 0; + output_color->pixel = 0; } + output_color->opaque = true; return true; } - uint8_t pixel_hue = displayio_colorconverter_compute_hue(input_color); - displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, output_color); + uint8_t pixel_hue = displayio_colorconverter_compute_hue(pixel); + displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, &output_color->pixel); return true; - } else if (colorspace->grayscale && colorspace->depth <= 8) { - uint8_t luma = displayio_colorconverter_compute_luma(input_color); - *output_color = luma >> (8 - colorspace->depth); + } else if (colorspace->grayscale && colorspace->depth <= 8) { + uint8_t luma = displayio_colorconverter_compute_luma(pixel); + output_color->pixel = luma >> (8 - colorspace->depth); + output_color->opaque = true; return true; } + output_color->opaque = false; return false; } -void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color) { - displayio_colorconverter_convert(self, colorspace, input_color, output_color); -} - // Currently no refresh logic is needed for a ColorConverter. bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self) { return false; diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index c79e6a2f7..6bb52d720 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -39,7 +39,11 @@ typedef struct { bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self); void displayio_colorconverter_finish_refresh(displayio_colorconverter_t *self); -bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); +bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color); + +uint32_t displayio_colorconverter_dither_noise_1 (uint32_t n); +uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y); + uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index f210a80c3..03185dffc 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -150,6 +150,14 @@ void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* s self->auto_brightness = auto_brightness; } +void common_hal_displayio_display_set_dither(displayio_display_obj_t* self, bool dither) { + displayio_display_core_set_dither(&self->core, dither); +} + +bool common_hal_displayio_display_get_dither(displayio_display_obj_t* self) { + return displayio_display_core_get_dither(&self->core); +} + mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self) { return self->current_brightness; } diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index 1cfdd199a..758fd43fc 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -41,6 +41,7 @@ typedef struct { bool tricolor; bool pixels_in_byte_share_row; bool reverse_pixels_in_byte; + bool dither; } _displayio_colorspace_t; typedef struct { @@ -52,6 +53,20 @@ typedef struct { bool transparent; // This may have additional bits added later for blending. } _displayio_color_t; +typedef struct { + uint32_t pixel; + uint16_t x; + uint16_t y; + uint8_t tile; + uint16_t tile_x; + uint16_t tile_y; +} displayio_input_pixel_t; + +typedef struct { + uint32_t pixel; + bool opaque; +} displayio_output_pixel_t; + typedef struct { mp_obj_base_t base; _displayio_color_t* colors; diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index f34d2fc52..81d142bbe 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -377,12 +377,16 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c } uint8_t pixels_per_byte = 8 / colorspace->depth; - for (int16_t y = start_y; y < end_y; y++) { - int16_t row_start = start + (y - start_y + y_shift) * y_stride; // in pixels - int16_t local_y = y / self->absolute_transform->scale; - for (int16_t x = start_x; x < end_x; x++) { + + displayio_input_pixel_t input_pixel; + displayio_output_pixel_t output_pixel; + + for (input_pixel.y = start_y; input_pixel.y < end_y; ++input_pixel.y) { + int16_t row_start = start + (input_pixel.y - start_y + y_shift) * y_stride; // in pixels + int16_t local_y = input_pixel.y / self->absolute_transform->scale; + for (input_pixel.x = start_x; input_pixel.x < end_x; ++input_pixel.x) { // Compute the destination pixel in the buffer and mask based on the transformations. - int16_t offset = row_start + (x - start_x + x_shift) * x_stride; // in pixels + int16_t offset = row_start + (input_pixel.x - start_x + x_shift) * x_stride; // in pixels // This is super useful for debugging out of range accesses. Uncomment to use. // if (offset < 0 || offset >= (int32_t) displayio_area_size(area)) { @@ -393,41 +397,43 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c if ((mask[offset / 32] & (1 << (offset % 32))) != 0) { continue; } - int16_t local_x = x / self->absolute_transform->scale; + int16_t local_x = input_pixel.x / self->absolute_transform->scale; uint16_t tile_location = ((local_y / self->tile_height + self->top_left_y) % self->height_in_tiles) * self->width_in_tiles + (local_x / self->tile_width + self->top_left_x) % self->width_in_tiles; - uint8_t tile = tiles[tile_location]; - uint16_t tile_x = (tile % self->bitmap_width_in_tiles) * self->tile_width + local_x % self->tile_width; - uint16_t tile_y = (tile / self->bitmap_width_in_tiles) * self->tile_height + local_y % self->tile_height; + input_pixel.tile = tiles[tile_location]; + input_pixel.tile_x = (input_pixel.tile % self->bitmap_width_in_tiles) * self->tile_width + local_x % self->tile_width; + input_pixel.tile_y = (input_pixel.tile / self->bitmap_width_in_tiles) * self->tile_height + local_y % self->tile_height; + + //uint32_t value = 0; + output_pixel.pixel = 0; + input_pixel.pixel = 0; - uint32_t value = 0; // We always want to read bitmap pixels by row first and then transpose into the destination // buffer because most bitmaps are row associated. if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { - value = common_hal_displayio_bitmap_get_pixel(self->bitmap, tile_x, tile_y); + input_pixel.pixel = common_hal_displayio_bitmap_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y); } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { - value = common_hal_displayio_shape_get_pixel(self->bitmap, tile_x, tile_y); + input_pixel.pixel = common_hal_displayio_shape_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y); } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) { - value = common_hal_displayio_ondiskbitmap_get_pixel(self->bitmap, tile_x, tile_y); + input_pixel.pixel = common_hal_displayio_ondiskbitmap_get_pixel(self->bitmap, input_pixel.tile_x, input_pixel.tile_y); } - - uint32_t pixel; - bool opaque = true; + + output_pixel.opaque = true; if (self->pixel_shader == mp_const_none) { - pixel = value; + output_pixel.pixel = input_pixel.pixel; } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) { - opaque = displayio_palette_get_color(self->pixel_shader, colorspace, value, &pixel); + output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel); } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { - opaque = displayio_colorconverter_convert(self->pixel_shader, colorspace, value, &pixel); + displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel); } - if (!opaque) { + if (!output_pixel.opaque) { // A pixel is transparent so we haven't fully covered the area ourselves. full_coverage = false; } else { mask[offset / 32] |= 1 << (offset % 32); if (colorspace->depth == 16) { - *(((uint16_t*) buffer) + offset) = pixel; + *(((uint16_t*) buffer) + offset) = output_pixel.pixel; } else if (colorspace->depth == 8) { - *(((uint8_t*) buffer) + offset) = pixel; + *(((uint8_t*) buffer) + offset) = output_pixel.pixel; } else if (colorspace->depth < 8) { // Reorder the offsets to pack multiple rows into a byte (meaning they share a column). if (!colorspace->pixels_in_byte_share_row) { @@ -446,7 +452,7 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c // Reverse the shift by subtracting it from the leftmost shift. shift = (pixels_per_byte - 1) * colorspace->depth - shift; } - ((uint8_t*)buffer)[offset / pixels_per_byte] |= pixel << shift; + ((uint8_t*)buffer)[offset / pixels_per_byte] |= output_pixel.pixel << shift; } } } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 0f449ea34..83df67c63 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -49,6 +49,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row; self->colorspace.bytes_per_cell = bytes_per_cell; self->colorspace.reverse_pixels_in_byte = reverse_pixels_in_byte; + self->colorspace.dither = false; self->current_group = NULL; self->colstart = colstart; self->rowstart = rowstart; @@ -171,6 +172,14 @@ uint16_t displayio_display_core_get_height(displayio_display_core_t* self){ return self->height; } +void displayio_display_core_set_dither(displayio_display_core_t* self, bool dither){ + self->colorspace.dither = dither; +} + +bool displayio_display_core_get_dither(displayio_display_core_t* self){ + return self->colorspace.dither; +} + bool displayio_display_core_bus_free(displayio_display_core_t *self) { return self->bus_free(self->bus); } diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index e92fdbc9f..3a69cd40a 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -65,6 +65,9 @@ bool displayio_display_core_show(displayio_display_core_t* self, displayio_group uint16_t displayio_display_core_get_width(displayio_display_core_t* self); uint16_t displayio_display_core_get_height(displayio_display_core_t* self); +void displayio_display_core_set_dither(displayio_display_core_t* self, bool dither); +bool displayio_display_core_get_dither(displayio_display_core_t* self); + bool displayio_display_core_bus_free(displayio_display_core_t *self); bool displayio_display_core_begin_transaction(displayio_display_core_t* self); void displayio_display_core_end_transaction(displayio_display_core_t* self); -- cgit v1.2.3 From 362c1664ae5979f288e8cb12d528f8cd44100410 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sun, 1 Sep 2019 17:36:29 -0500 Subject: use more accurate ARMv7 prepocessor flags; TODOs for asm instructions --- shared-module/audiomixer/Mixer.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'shared-module') diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index b61ba1eb0..9f30bd47f 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -94,7 +94,7 @@ void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t* self, } uint32_t add8signed(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU return __SHADD8(a, b); #else uint32_t result = 0; @@ -114,7 +114,7 @@ uint32_t add8signed(uint32_t a, uint32_t b) { } uint32_t add8unsigned(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU return __UHADD8(a, b); #else uint32_t result = 0; @@ -132,7 +132,7 @@ uint32_t add8unsigned(uint32_t a, uint32_t b) { } uint32_t add16signed(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU return __SHADD16(a, b); #else uint32_t result = 0; @@ -152,7 +152,7 @@ uint32_t add16signed(uint32_t a, uint32_t b) { } uint32_t add16unsigned(uint32_t a, uint32_t b) { - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU return __UHADD16(a, b); #else uint32_t result = 0; @@ -169,15 +169,16 @@ uint32_t add16unsigned(uint32_t a, uint32_t b) { #endif } -//TODO: static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { // if mul == 0, no need in wasting cycles if (mul == 0) { return 0; } - /*#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + /* TODO: workout ARMv7 instructions + #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU return val; #else*/ + mp_printf(&mp_plat_print, "mult8unsigned"); uint32_t result = 0; float mod_mul = (float) mul / (float) ((1<<15)-1); for (int8_t i = 0; i < 4; i++) { @@ -193,14 +194,13 @@ static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { //#endif } -//TODO: static inline uint32_t mult8signed(uint32_t val, int32_t mul) { // if mul == 0, no need in wasting cycles if (mul == 0) { return 0; } - /* - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + /* TODO: workout ARMv7 instructions + #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU return val; #else */ @@ -226,8 +226,17 @@ static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) { if (mul == 0) { return 0; } - /* - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + /* TODO: the below ARMv7m instructions "work", but the amplitude is much higher/louder + #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU + // there is no unsigned equivalent to the 'SMULWx' ARMv7 Thumb function, + // so we have to do it by hand. + uint32_t lo = val & 0xffff; + uint32_t hi = val >> 16; + //mp_printf(&mp_plat_print, "pre-asm: (mul: %d)\n\tval: %x\tlo: %x\thi: %x\n", mul, val, lo, hi); + uint32_t val_lo; + asm volatile("mul %0, %1, %2" : "=r" (val_lo) : "r" (mul), "r" (lo)); + asm volatile("mla %0, %1, %2, %3" : "=r" (val) : "r" (mul), "r" (hi), "r" (val_lo)); + //mp_printf(&mp_plat_print, "post-asm:\n\tval: %x\tlo: %x\n\n", val, val_lo); return val; #else */ @@ -243,7 +252,7 @@ static inline uint32_t mult16unsigned(uint32_t val, int32_t mul) { } result |= (((uint32_t) intermediate) + 0x8000) << (sizeof(int16_t) * 8 * i); } - return val; + return result; //#endif } @@ -252,7 +261,7 @@ static inline uint32_t mult16signed(uint32_t val, int32_t mul) { if (mul == 0) { return 0; } - #if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) + #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU int32_t hi, lo; int32_t bits = 16; // saturate to 16 bits int32_t shift = 0; // shift is done automatically -- cgit v1.2.3 From b318896b8509df07630d7ee1d27ab46b6dcba1c1 Mon Sep 17 00:00:00 2001 From: Dave Astels Date: Tue, 3 Sep 2019 12:35:41 -0400 Subject: Capture rotation --- shared-module/displayio/display_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-module') diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 0f449ea34..95fa08f54 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -85,6 +85,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->ram_width = ram_width; self->ram_height = ram_height; rotation = rotation % 360; + self->rotation = rotation; self->transform.x = 0; self->transform.y = 0; self->transform.scale = 1; -- cgit v1.2.3 From 42f5edbd331b27c7096f57da2affd7561287c17f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 3 Sep 2019 14:44:46 -0400 Subject: WIP --- .../circuitplayground_express/mpconfigboard.mk | 3 + .../atmel-samd/boards/trinket_m0/mpconfigboard.mk | 4 ++ shared-module/usb_hid/Device.c | 4 +- shared-module/usb_hid/__init__.c | 18 +++++ supervisor/supervisor.mk | 10 +++ tools/gen_usb_descriptor.py | 79 ++++++++++++++++------ tools/hid_report_descriptors.py | 60 ++++++++++++++++ 7 files changed, 156 insertions(+), 22 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk index 3c43776f5..e62bec85f 100644 --- a/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.mk @@ -3,6 +3,9 @@ USB_VID = 0x239A USB_PID = 0x8019 USB_PRODUCT = "CircuitPlayground Express" USB_MANUFACTURER = "Adafruit Industries LLC" +#USB_HID_DEVICES = KEYBOARD,XAC_COMPATIBLE_GAMEPAD +USB_HID_DEVICES = XAC_COMPATIBLE_GAMEPAD + CHIP_VARIANT = SAMD21G18A CHIP_FAMILY = samd21 diff --git a/ports/atmel-samd/boards/trinket_m0/mpconfigboard.mk b/ports/atmel-samd/boards/trinket_m0/mpconfigboard.mk index b4a00b654..72fba7dd7 100644 --- a/ports/atmel-samd/boards/trinket_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/trinket_m0/mpconfigboard.mk @@ -1,12 +1,16 @@ LD_FILE = boards/samd21x18-bootloader.ld USB_VID = 0x239A USB_PID = 0x801F + +USB_HID_DEVICES=MOUSE,KEYBOARD,XAC_COMPATIBLE_GAMEPAD + USB_PRODUCT = "Trinket M0" USB_MANUFACTURER = "Adafruit Industries LLC" CHIP_VARIANT = SAMD21E18A CHIP_FAMILY = samd21 + INTERNAL_FLASH_FILESYSTEM = 1 LONGINT_IMPL = NONE CIRCUITPY_SMALL_BUILD = 1 diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index 26d70cb82..bed7d163f 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -48,9 +48,7 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t* // Wait until interface is ready, timeout = 2 seconds uint64_t end_ticks = ticks_ms + 2000; while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP; -#endif + RUN_BACKGROUND_TASKS; } if ( !tud_hid_ready() ) { diff --git a/shared-module/usb_hid/__init__.c b/shared-module/usb_hid/__init__.c index f14fdd41e..3ce26a1a1 100644 --- a/shared-module/usb_hid/__init__.c +++ b/shared-module/usb_hid/__init__.c @@ -53,6 +53,10 @@ static uint8_t sys_control_report_buffer[USB_HID_REPORT_LENGTH_SYS_CONTROL]; static uint8_t gamepad_report_buffer[USB_HID_REPORT_LENGTH_GAMEPAD]; #endif +#ifdef USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD +static uint8_t xac_compatible_gamepad_report_buffer[USB_HID_REPORT_LENGTH_XAC_COMPATIBLE_GAMEPAD]; +#endif + #ifdef USB_HID_REPORT_ID_DIGITIZER static uint8_t digitizer_report_buffer[USB_HID_REPORT_LENGTH_DIGITIZER]; #endif @@ -113,6 +117,17 @@ usb_hid_device_obj_t usb_hid_devices[] = { }, #endif +#ifdef USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD + { + .base = { .type = &usb_hid_device_type } , + .report_buffer = xac_compatible_gamepad_report_buffer , + .report_id = USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD , + .report_length = USB_HID_REPORT_LENGTH_XAC_COMPATIBLE_GAMEPAD , + .usage_page = HID_USAGE_PAGE_DESKTOP , + .usage = HID_USAGE_DESKTOP_GAMEPAD , + }, +#endif + #ifdef USB_HID_REPORT_ID_DIGITIZER { .base = { .type = &usb_hid_device_type } , @@ -149,6 +164,9 @@ mp_obj_tuple_t common_hal_usb_hid_devices = { #endif #if USB_HID_NUM_DEVICES >= 6 (mp_obj_t) &usb_hid_devices[5], +#endif +#if USB_HID_NUM_DEVICES >= 7 +#error "Too many USB HID devices" #endif } }; diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 2d50e7a8b..016188dfd 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -81,6 +81,14 @@ else CFLAGS += -DUSB_AVAILABLE endif +ifndef USB_DEVICES +USB_DEVICES = "CDC,MSC,AUDIO,HID" +endif + +ifndef USB_HID_DEVICES +USB_HID_DEVICES = "KEYBOARD,MOUSE,CONSUMER,GAMEPAD" +endif + SUPERVISOR_O = $(addprefix $(BUILD)/, $(SRC_SUPERVISOR:.c=.o)) $(BUILD)/autogen_display_resources.o $(BUILD)/supervisor/shared/translate.o: $(HEADER_BUILD)/qstrdefs.generated.h @@ -98,6 +106,8 @@ autogen_usb_descriptor.intermediate: ../../tools/gen_usb_descriptor.py Makefile --vid $(USB_VID)\ --pid $(USB_PID)\ --serial_number_length $(USB_SERIAL_NUMBER_LENGTH)\ + --devices $(USB_DEVICES) \ + --hid_devices $(USB_HID_DEVICES) \ --output_c_file $(BUILD)/autogen_usb_descriptor.c\ --output_h_file $(BUILD)/genhdr/autogen_usb_descriptor.h diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index 10bbf5066..f782f9afc 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -8,6 +8,15 @@ sys.path.append("../../tools/usb_descriptor") from adafruit_usb_descriptor import audio, audio10, cdc, hid, midi, msc, standard, util import hid_report_descriptors +ALL_DEVICES='CDC,MSC,AUDIO,HID' +ALL_DEVICES_SET=frozenset(ALL_DEVICES.split(',')) +DEFAULT_DEVICES='CDC,MSC,AUDIO,HID' + +ALL_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,SYS_CONTROL,GAMEPAD,DIGITIZER,XAC_COMPATIBLE_GAMEPAD' +ALL_HID_DEVICES_SET=frozenset(ALL_HID_DEVICES.split(',')) +# Digitizer works on Linux but conflicts with mouse, so omit it. +DEFAULT_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,GAMEPAD' + parser = argparse.ArgumentParser(description='Generate USB descriptors.') parser.add_argument('--manufacturer', type=str, help='manufacturer of the device') @@ -19,11 +28,24 @@ parser.add_argument('--pid', type=lambda x: int(x, 16), help='product id') parser.add_argument('--serial_number_length', type=int, default=32, help='length needed for the serial number in digits') +parser.add_argument('--devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_DEVICES, + help='devices to include in descriptor (AUDIO includes MIDI support)') +parser.add_argument('--hid_devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_HID_DEVICES, + help='HID devices to include in HID report descriptor') parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True) parser.add_argument('--output_h_file', type=argparse.FileType('w'), required=True) args = parser.parse_args() +unknown_devices = list(args.devices - ALL_DEVICES_SET) +if unknown_devices: + raise ValueError("Unknown device(s)", unknown_devices) + +unknown_hid_devices = list(args.hid_devices - ALL_HID_DEVICES_SET) +if unknown_hid_devices: + raise ValueError("Unknown HID devices(s)", unknown_hid_devices) + + class StringIndex: """Assign a monotonically increasing index to each unique string. Start with 0.""" string_to_index = {} @@ -138,16 +160,27 @@ msc_interfaces = [ ) ] -# Include only these HID devices. -# DIGITIZER works on Linux but conflicts with MOUSE, so leave it out for now. -hid_devices = ("KEYBOARD", "MOUSE", "CONSUMER", "GAMEPAD") - -combined_hid_report_descriptor = hid.ReportDescriptor( +# Sort by Report ID for consistency. +hid_devices = sorted(args.hid_devices, key=lambda name: hid_report_descriptors.REPORT_IDS[name]) + +# When there's only one hid_device, it can't be in a composite descriptor. +# It has no report id (indicated by 0), so remove the existing one. + +#if len(hid_devices) == 1: +if False: + name = hid_devices[0] + combined_hid_report_descriptor = hid.ReportDescriptor( + description=name, + report_descriptor=hid_report_descriptors.remove_report_id( + hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor)) + hid_report_ids_dict = { name : 0 } +else: + combined_hid_report_descriptor = hid.ReportDescriptor( description="MULTIDEVICE", report_descriptor=b''.join( hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor for name in hid_devices )) + hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices } -hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices } hid_report_lengths_dict = { name: hid_report_descriptors.REPORT_LENGTHS[name] for name in hid_devices } hid_max_report_length = max(hid_report_lengths_dict.values()) @@ -271,19 +304,27 @@ cdc_iad = standard.InterfaceAssociationDescriptor( bFunctionProtocol=cdc.CDC_PROTOCOL_NONE) descriptor_list = [] -descriptor_list.append(cdc_iad) -descriptor_list.extend(cdc_interfaces) -descriptor_list.extend(msc_interfaces) -# Only add the control interface because other audio interfaces are managed by it to ensure the -# correct ordering. -descriptor_list.append(audio_control_interface) -# Put the CDC IAD just before the CDC interfaces. -# There appears to be a bug in the Windows composite USB driver that requests the -# HID report descriptor with the wrong interface number if the HID interface is not given -# first. However, it still fetches the descriptor anyway. We could reorder the interfaces but -# the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it -# there for backwards compatibility. -descriptor_list.extend(hid_interfaces) + +if 'CDC' in args.devices: + # Put the CDC IAD just before the CDC interfaces. + # There appears to be a bug in the Windows composite USB driver that requests the + # HID report descriptor with the wrong interface number if the HID interface is not given + # first. However, it still fetches the descriptor anyway. We could reorder the interfaces but + # the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it + # there for backwards compatibility. + descriptor_list.append(cdc_iad) + descriptor_list.extend(cdc_interfaces) + +if 'MSC' in args.devices: + descriptor_list.extend(msc_interfaces) + +if 'AUDIO' in args.devices: + # Only add the control interface because other audio interfaces are managed by it to ensure the + # correct ordering. + descriptor_list.append(audio_control_interface) + +if 'HID' in args.devices: + descriptor_list.extend(hid_interfaces) configuration = standard.ConfigurationDescriptor( description="Composite configuration", diff --git a/tools/hid_report_descriptors.py b/tools/hid_report_descriptors.py index f3b28ebcf..4902657af 100644 --- a/tools/hid_report_descriptors.py +++ b/tools/hid_report_descriptors.py @@ -31,6 +31,11 @@ HID specific descriptors from adafruit_usb_descriptor import hid +def remove_report_id(report_descriptor_bytes): + #return report_descriptor_bytes + report_id_pos = report_descriptor_bytes.index(0x85) + return report_descriptor_bytes[:report_id_pos] + report_descriptor_bytes[report_id_pos + 2:] + REPORT_IDS = { "KEYBOARD" : 1, "MOUSE" : 2, @@ -38,6 +43,9 @@ REPORT_IDS = { "SYS_CONTROL" : 4, "GAMEPAD" : 5, "DIGITIZER" : 6, + "XAC_COMPATIBLE_GAMEPAD" : 7, + # RAW must not have a report ID, so it can't be used with other devices. + "RAW" : 0, } # Byte count for each kind of report. Length does not include report ID in first byte. @@ -48,6 +56,8 @@ REPORT_LENGTHS = { "SYS_CONTROL" : 1, "GAMEPAD" : 6, "DIGITIZER" : 5, + "XAC_COMPATIBLE_GAMEPAD" : 3, + "RAW" : 64, } KEYBOARD_WITH_ID = hid.ReportDescriptor( @@ -228,6 +238,54 @@ DIGITIZER_WITH_ID = hid.ReportDescriptor( 0xC0, # End Collection ])) +XAC_COMPATIBLE_GAMEPAD_WITH_ID = hid.ReportDescriptor( + description="XAC", + report_descriptor=bytes([ + # This descriptor mimics the simple joystick from PDP that the XBox likes + 0x05, 0x01, # Usage Page (Desktop), + 0x09, 0x05, # Usage (Gamepad), + 0xA1, 0x01, # Collection (Application), + 0x85, REPORT_IDS["XAC_COMPATIBLE_GAMEPAD"], # Report ID (n) + 0x15, 0x00, # Logical Minimum (0), + 0x25, 0x01, # Logical Maximum (1), + 0x35, 0x00, # Physical Minimum (0), + 0x45, 0x01, # Physical Maximum (1), + 0x75, 0x01, # Report Size (1), + 0x95, 0x08, # Report Count (8), + 0x05, 0x09, # Usage Page (Button), + 0x19, 0x01, # Usage Minimum (01h), + 0x29, 0x08, # Usage Maximum (08h), + 0x81, 0x02, # Input (Variable), + 0x05, 0x01, # Usage Page (Desktop), + 0x26, 0xFF, 0x00, # Logical Maximum (255), + 0x46, 0xFF, 0x00, # Physical Maximum (255), + 0x09, 0x30, # Usage (X), + 0x09, 0x31, # Usage (Y), + 0x75, 0x08, # Report Size (8), + 0x95, 0x02, # Report Count (2), + 0x81, 0x02, # Input (Variable), + 0xC0 # End Collection + ])) + +RAW = hid.ReportDescriptor( + description="RAW", + report_descriptor=bytes([ + # Provide vendor-defined + 0x06, 0xAF, 0xFF, # Usage Page (Vendor 0xFFAF "Adafruit"), + 0x09, 0xAF, # Usage (AF), + 0xA1, 0x01, # Collection (Application), + 0x75, 0x08, # Report Size (8), + 0x15, 0x00, # Logical Minimum (0), + 0x26, 0xFF, 0x00 # Logical Maximum (255), + 0x95, 0x08, # Report Count (8), + 0x09, 0x01 # Usage(xxx) + 0x81, 0x02 # Input (Variable) + 0x95, 0x08, # Report Count (8), + 0x09, 0x02, # Usage(xxx) + 0x91, 0x02, # Input (Variable) + 0xC0 # End Collection + ])) + # Byte count for each kind of report. Length does not include report ID in first byte. REPORT_DESCRIPTORS = { "KEYBOARD" : KEYBOARD_WITH_ID, @@ -236,4 +294,6 @@ REPORT_DESCRIPTORS = { "SYS_CONTROL" : SYS_CONTROL_WITH_ID, "GAMEPAD" : GAMEPAD_WITH_ID, "DIGITIZER" : DIGITIZER_WITH_ID, + "XAC_COMPATIBLE_GAMEPAD" : XAC_COMPATIBLE_GAMEPAD_WITH_ID, + "RAW" : RAW_WITH_ID, } -- cgit v1.2.3 From b53f1698242ef797b7176e32a92b92f282d998d6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Sep 2019 14:46:47 -0700 Subject: Fix I2CDisplay bus_free to not grab lock Fixes #2098 --- shared-module/displayio/Display.c | 2 +- shared-module/displayio/I2CDisplay.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index f210a80c3..212ee8c7b 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -90,7 +90,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->core.send(self->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, cmd, 1); self->core.send(self->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, data_size); } - self->core.end_transaction(self->core.bus); + displayio_display_core_end_transaction(&self->core); uint16_t delay_length_ms = 10; if (delay) { data_size++; diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 87261dca0..a3b167a33 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -91,11 +91,13 @@ bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t obj) { if (!common_hal_busio_i2c_try_lock(self->bus)) { return false; } + common_hal_busio_i2c_unlock(self->bus); return true; } bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { - return common_hal_displayio_i2cdisplay_bus_free(obj); + displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); + return !common_hal_busio_i2c_try_lock(self->bus); } void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { -- cgit v1.2.3 From 949f8761b8c41ecbf8660bcd5a333890a37e426e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 27 Aug 2019 16:03:05 -0700 Subject: Add .hidden to TileGrid and Group This allows for one to preserve ordering within a Group while hiding something temporarily. Fixes #1688 --- shared-bindings/displayio/Group.c | 27 ++++++++++++++++++ shared-bindings/displayio/Group.h | 2 ++ shared-bindings/displayio/TileGrid.c | 25 +++++++++++++++++ shared-bindings/displayio/TileGrid.h | 2 ++ shared-bindings/displayio/__init__.h | 1 - shared-module/displayio/Display.c | 4 ++- shared-module/displayio/Group.c | 41 +++++++++++++++++++++++++++ shared-module/displayio/Group.h | 3 ++ shared-module/displayio/I2CDisplay.c | 2 +- shared-module/displayio/TileGrid.c | 54 ++++++++++++++++++++++++++++-------- shared-module/displayio/TileGrid.h | 5 +++- supervisor/shared/display.c | 7 +++-- tools/gen_display_resources.py | 3 +- 13 files changed, 158 insertions(+), 18 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Group.c b/shared-bindings/displayio/Group.c index 5a35424ce..dd7600eb9 100644 --- a/shared-bindings/displayio/Group.c +++ b/shared-bindings/displayio/Group.c @@ -90,6 +90,32 @@ displayio_group_t* native_group(mp_obj_t group_obj) { return MP_OBJ_TO_PTR(native_group); } +//| .. attribute:: hidden +//| +//| True when the Group and all of it's layers are not visible. When False, the Group's layers +//| are visible if they haven't been hidden. +//| +STATIC mp_obj_t displayio_group_obj_get_hidden(mp_obj_t self_in) { + displayio_group_t *self = native_group(self_in); + return mp_obj_new_bool(common_hal_displayio_group_get_hidden(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_group_get_hidden_obj, displayio_group_obj_get_hidden); + +STATIC mp_obj_t displayio_group_obj_set_hidden(mp_obj_t self_in, mp_obj_t hidden_obj) { + displayio_group_t *self = native_group(self_in); + + common_hal_displayio_group_set_hidden(self, mp_obj_is_true(hidden_obj)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_set_hidden_obj, displayio_group_obj_set_hidden); + +const mp_obj_property_t displayio_group_hidden_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_group_get_hidden_obj, + (mp_obj_t)&displayio_group_set_hidden_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + //| .. attribute:: scale //| //| Scales each pixel within the Group in both directions. For example, when scale=2 each pixel @@ -305,6 +331,7 @@ STATIC mp_obj_t group_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t valu } STATIC const mp_rom_map_elem_t displayio_group_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_hidden), MP_ROM_PTR(&displayio_group_hidden_obj) }, { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&displayio_group_scale_obj) }, { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&displayio_group_x_obj) }, { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&displayio_group_y_obj) }, diff --git a/shared-bindings/displayio/Group.h b/shared-bindings/displayio/Group.h index dc9616f2e..942a207f2 100644 --- a/shared-bindings/displayio/Group.h +++ b/shared-bindings/displayio/Group.h @@ -36,6 +36,8 @@ displayio_group_t* native_group(mp_obj_t group_obj); void common_hal_displayio_group_construct(displayio_group_t* self, uint32_t max_size, uint32_t scale, mp_int_t x, mp_int_t y); uint32_t common_hal_displayio_group_get_scale(displayio_group_t* self); void common_hal_displayio_group_set_scale(displayio_group_t* self, uint32_t scale); +bool common_hal_displayio_group_get_hidden(displayio_group_t* self); +void common_hal_displayio_group_set_hidden(displayio_group_t* self, bool hidden); mp_int_t common_hal_displayio_group_get_x(displayio_group_t* self); void common_hal_displayio_group_set_x(displayio_group_t* self, mp_int_t x); mp_int_t common_hal_displayio_group_get_y(displayio_group_t* self); diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index 53fbb51c8..288eb4b23 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -144,6 +144,30 @@ static displayio_tilegrid_t* native_tilegrid(mp_obj_t tilegrid_obj) { mp_obj_assert_native_inited(native_tilegrid); return MP_OBJ_TO_PTR(native_tilegrid); } +//| .. attribute:: hidden +//| +//| True when the TileGrid is hidden. This may be False even when a part of a hidden Group. +//| +STATIC mp_obj_t displayio_tilegrid_obj_get_hidden(mp_obj_t self_in) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + return mp_obj_new_bool(common_hal_displayio_tilegrid_get_hidden(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_hidden_obj, displayio_tilegrid_obj_get_hidden); + +STATIC mp_obj_t displayio_tilegrid_obj_set_hidden(mp_obj_t self_in, mp_obj_t hidden_obj) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + + common_hal_displayio_tilegrid_set_hidden(self, mp_obj_is_true(hidden_obj)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_hidden_obj, displayio_tilegrid_obj_set_hidden); + +const mp_obj_property_t displayio_tilegrid_hidden_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_tilegrid_get_hidden_obj, + (mp_obj_t)&displayio_tilegrid_set_hidden_obj, + (mp_obj_t)&mp_const_none_obj}, +}; //| .. attribute:: x //| @@ -368,6 +392,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v STATIC const mp_rom_map_elem_t displayio_tilegrid_locals_dict_table[] = { // Properties + { MP_ROM_QSTR(MP_QSTR_hidden), MP_ROM_PTR(&displayio_tilegrid_hidden_obj) }, { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&displayio_tilegrid_x_obj) }, { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&displayio_tilegrid_y_obj) }, { MP_ROM_QSTR(MP_QSTR_flip_x), MP_ROM_PTR(&displayio_tilegrid_flip_x_obj) }, diff --git a/shared-bindings/displayio/TileGrid.h b/shared-bindings/displayio/TileGrid.h index 8227abfd3..0ee1c7883 100644 --- a/shared-bindings/displayio/TileGrid.h +++ b/shared-bindings/displayio/TileGrid.h @@ -36,6 +36,8 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_ mp_obj_t pixel_shader, uint16_t width, uint16_t height, uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile); +bool common_hal_displayio_tilegrid_get_hidden(displayio_tilegrid_t* self); +void common_hal_displayio_tilegrid_set_hidden(displayio_tilegrid_t* self, bool hidden); mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self); void common_hal_displayio_tilegrid_set_x(displayio_tilegrid_t *self, mp_int_t x); mp_int_t common_hal_displayio_tilegrid_get_y(displayio_tilegrid_t *self); diff --git a/shared-bindings/displayio/__init__.h b/shared-bindings/displayio/__init__.h index 122b1fbcb..a7748d029 100644 --- a/shared-bindings/displayio/__init__.h +++ b/shared-bindings/displayio/__init__.h @@ -34,7 +34,6 @@ typedef enum { DISPLAY_DATA } display_byte_type_t; - typedef enum { CHIP_SELECT_UNTOUCHED, CHIP_SELECT_TOGGLE_EVERY_BYTE diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 212ee8c7b..06b81f2f8 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -50,6 +50,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second) { + // Turn off auto-refresh as we init. + self->auto_refresh = false; uint16_t ram_width = 0x100; uint16_t ram_height = 0x100; if (single_byte_bounds) { @@ -64,7 +66,6 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->write_ram_command = write_ram_command; self->brightness_command = brightness_command; self->auto_brightness = auto_brightness; - self->auto_refresh = auto_refresh; self->first_manual_refresh = !auto_refresh; self->data_as_commands = data_as_commands; @@ -128,6 +129,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_display_show(self, &circuitpython_splash); + self->auto_refresh = auto_refresh; } bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index 38418a029..d69e9f585 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -34,6 +34,47 @@ void common_hal_displayio_group_construct(displayio_group_t* self, uint32_t max_ displayio_group_construct(self, children, max_size, scale, x, y); } +bool common_hal_displayio_group_get_hidden(displayio_group_t* self) { + return self->hidden; +} + +void common_hal_displayio_group_set_hidden(displayio_group_t* self, bool hidden) { + if (self->hidden == hidden) { + return; + } + self->hidden = hidden; + if (self->hidden_by_parent) { + return; + } + for (size_t i = 0; i < self->size; i++) { + mp_obj_t layer = self->children[i].native; + if (MP_OBJ_IS_TYPE(layer, &displayio_tilegrid_type)) { + displayio_tilegrid_set_hidden_by_parent(layer, hidden); + } else if (MP_OBJ_IS_TYPE(layer, &displayio_group_type)) { + displayio_group_set_hidden_by_parent(layer, hidden); + } + } +} + +void displayio_group_set_hidden_by_parent(displayio_group_t *self, bool hidden) { + if (self->hidden_by_parent == hidden) { + return; + } + self->hidden_by_parent = hidden; + // If we're already hidden, then we're done. + if (self->hidden) { + return; + } + for (size_t i = 0; i < self->size; i++) { + mp_obj_t layer = self->children[i].native; + if (MP_OBJ_IS_TYPE(layer, &displayio_tilegrid_type)) { + displayio_tilegrid_set_hidden_by_parent(layer, hidden); + } else if (MP_OBJ_IS_TYPE(layer, &displayio_group_type)) { + displayio_group_set_hidden_by_parent(layer, hidden); + } + } +} + uint32_t common_hal_displayio_group_get_scale(displayio_group_t* self) { return self->scale; } diff --git a/shared-module/displayio/Group.h b/shared-module/displayio/Group.h index 4e2308e56..7021da4bd 100644 --- a/shared-module/displayio/Group.h +++ b/shared-module/displayio/Group.h @@ -49,11 +49,14 @@ typedef struct { uint16_t max_size; bool item_removed; bool in_group; + bool hidden; + bool hidden_by_parent; displayio_buffer_transform_t absolute_transform; displayio_area_t dirty_area; // Catch all for changed area } displayio_group_t; void displayio_group_construct(displayio_group_t* self, displayio_group_child_t* child_array, uint32_t max_size, uint32_t scale, mp_int_t x, mp_int_t y); +void displayio_group_set_hidden_by_parent(displayio_group_t *self, bool hidden); bool displayio_group_get_previous_area(displayio_group_t *group, displayio_area_t* area); bool displayio_group_fill_area(displayio_group_t *group, const _displayio_colorspace_t* colorspace, const displayio_area_t* area, uint32_t* mask, uint32_t *buffer); void displayio_group_update_transform(displayio_group_t *group, const displayio_buffer_transform_t* parent_transform); diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index a3b167a33..d9452dc50 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -97,7 +97,7 @@ bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t obj) { bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); - return !common_hal_busio_i2c_try_lock(self->bus); + return common_hal_busio_i2c_try_lock(self->bus); } void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index f34d2fc52..45b05110f 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -67,14 +67,30 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_ self->bitmap = bitmap; self->pixel_shader = pixel_shader; self->in_group = false; - self->first_draw = true; + self->hidden = false; + self->hidden_by_parent = false; + self->previous_area.x1 = 0xffff; + self->previous_area.x2 = self->previous_area.x1; self->flip_x = false; self->flip_y = false; self->transpose_xy = false; } + +bool common_hal_displayio_tilegrid_get_hidden(displayio_tilegrid_t* self) { + return self->hidden; +} + +void common_hal_displayio_tilegrid_set_hidden(displayio_tilegrid_t* self, bool hidden) { + self->hidden = hidden; +} + +void displayio_tilegrid_set_hidden_by_parent(displayio_tilegrid_t *self, bool hidden) { + self->hidden_by_parent = hidden; +} + bool displayio_tilegrid_get_previous_area(displayio_tilegrid_t *self, displayio_area_t* area) { - if (self->first_draw) { + if (self->previous_area.x1 == self->previous_area.x2) { return false; } displayio_area_copy(&self->previous_area, area); @@ -138,12 +154,10 @@ void displayio_tilegrid_update_transform(displayio_tilegrid_t *self, self->in_group = absolute_transform != NULL; self->absolute_transform = absolute_transform; if (absolute_transform != NULL) { - self->moved = !self->first_draw; + self->moved = true; _update_current_x(self); _update_current_y(self); - } else { - self->first_draw = true; } } @@ -155,7 +169,7 @@ void common_hal_displayio_tilegrid_set_x(displayio_tilegrid_t *self, mp_int_t x) return; } - self->moved = !self->first_draw; + self->moved = true; self->x = x; if (self->absolute_transform != NULL) { @@ -170,7 +184,7 @@ void common_hal_displayio_tilegrid_set_y(displayio_tilegrid_t *self, mp_int_t y) if (self->y == y) { return; } - self->moved = !self->first_draw; + self->moved = true; self->y = y; if (self->absolute_transform != NULL) { _update_current_y(self); @@ -306,6 +320,11 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c return false; } + bool hidden = self->hidden || self->hidden_by_parent; + if (hidden) { + return false; + } + displayio_area_t overlap; if (!displayio_area_compute_overlap(area, &self->current_area, &overlap)) { return false; @@ -455,14 +474,17 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, const _displayio_c } void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) { - if (self->moved || self->first_draw) { + bool first_draw = self->previous_area.x1 == self->previous_area.x2; + bool hidden = self->hidden || self->hidden_by_parent; + if (!first_draw && hidden) { + self->previous_area.x2 = self->previous_area.x1; + } else if (self->moved || first_draw) { displayio_area_copy(&self->current_area, &self->previous_area); } self->moved = false; self->full_change = false; self->partial_change = false; - self->first_draw = false; if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) { displayio_palette_finish_refresh(self->pixel_shader); } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { @@ -481,7 +503,17 @@ void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) { } displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *self, displayio_area_t* tail) { - if (self->moved && !self->first_draw) { + bool first_draw = self->previous_area.x1 == self->previous_area.x2; + bool hidden = self->hidden || self->hidden_by_parent; + // Check hidden first because it trumps all other changes. + if (hidden) { + if (!first_draw) { + self->previous_area.next = tail; + return &self->previous_area; + } else { + return tail; + } + } else if (self->moved && !first_draw) { displayio_area_union(&self->previous_area, &self->current_area, &self->dirty_area); if (displayio_area_size(&self->dirty_area) <= 2U * self->pixel_width * self->pixel_height) { self->dirty_area.next = tail; @@ -512,7 +544,7 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel displayio_palette_needs_refresh(self->pixel_shader)) || (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type) && displayio_colorconverter_needs_refresh(self->pixel_shader)); - if (self->full_change || self->first_draw) { + if (self->full_change || first_draw) { self->current_area.next = tail; return &self->current_area; } diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index 0a414b062..3e95dd20a 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -57,15 +57,18 @@ typedef struct { displayio_area_t current_area; // Stored as an absolute area so it applies across frames. bool partial_change; bool full_change; - bool first_draw; bool moved; bool inline_tiles; bool in_group; bool flip_x; bool flip_y; bool transpose_xy; + bool hidden; + bool hidden_by_parent; } displayio_tilegrid_t; +void displayio_tilegrid_set_hidden_by_parent(displayio_tilegrid_t *self, bool hidden); + // Updating the screen is a three stage process. // The first stage is used to determine i diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 586b6f8be..c6fda0f16 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -222,7 +222,8 @@ displayio_tilegrid_t blinka_sprite = { .tiles = 0, .partial_change = false, .full_change = false, - .first_draw = true, + .hidden = false, + .hidden_by_parent = false, .moved = false, .inline_tiles = true, .in_group = true @@ -242,5 +243,7 @@ displayio_group_t circuitpython_splash = { .max_size = 2, .children = splash_children, .item_removed = false, - .in_group = false + .in_group = false, + .hidden = false, + .hidden_by_parent = false }; diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 65600a195..781b5e69b 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -139,7 +139,8 @@ displayio_tilegrid_t supervisor_terminal_text_grid = {{ .tiles = NULL, .partial_change = false, .full_change = false, - .first_draw = true, + .hidden = false, + .hidden_by_parent = false, .moved = false, .inline_tiles = false, .in_group = true -- cgit v1.2.3 From 94ba02754436368e84f307ade144b0b84f895f7b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 3 Sep 2019 21:16:14 -0400 Subject: simpler generation of HID device tables --- shared-module/usb_hid/__init__.c | 147 +---------- tools/gen_usb_descriptor.py | 127 ++++++---- tools/hid_report_descriptors.py | 525 ++++++++++++++++++++------------------- 3 files changed, 346 insertions(+), 453 deletions(-) (limited to 'shared-module') diff --git a/shared-module/usb_hid/__init__.c b/shared-module/usb_hid/__init__.c index 3ce26a1a1..9c6701ab8 100644 --- a/shared-module/usb_hid/__init__.c +++ b/shared-module/usb_hid/__init__.c @@ -24,149 +24,4 @@ * THE SOFTWARE. */ -#include "py/obj.h" -#include "py/mphal.h" -#include "py/runtime.h" - -#include "genhdr/autogen_usb_descriptor.h" -#include "shared-module/usb_hid/Device.h" -#include "shared-bindings/usb_hid/Device.h" -#include "tusb.h" - -#ifdef USB_HID_REPORT_ID_KEYBOARD -static uint8_t keyboard_report_buffer[USB_HID_REPORT_LENGTH_KEYBOARD]; -#endif - -#ifdef USB_HID_REPORT_ID_MOUSE -static uint8_t mouse_report_buffer[USB_HID_REPORT_LENGTH_MOUSE]; -#endif - -#ifdef USB_HID_REPORT_ID_CONSUMER -static uint8_t consumer_report_buffer[USB_HID_REPORT_LENGTH_CONSUMER]; -#endif - -#ifdef USB_HID_REPORT_ID_SYS_CONTROL -static uint8_t sys_control_report_buffer[USB_HID_REPORT_LENGTH_SYS_CONTROL]; -#endif - -#ifdef USB_HID_REPORT_ID_GAMEPAD -static uint8_t gamepad_report_buffer[USB_HID_REPORT_LENGTH_GAMEPAD]; -#endif - -#ifdef USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD -static uint8_t xac_compatible_gamepad_report_buffer[USB_HID_REPORT_LENGTH_XAC_COMPATIBLE_GAMEPAD]; -#endif - -#ifdef USB_HID_REPORT_ID_DIGITIZER -static uint8_t digitizer_report_buffer[USB_HID_REPORT_LENGTH_DIGITIZER]; -#endif - -usb_hid_device_obj_t usb_hid_devices[] = { -#ifdef USB_HID_REPORT_ID_KEYBOARD - { - .base = { .type = &usb_hid_device_type } , - .report_buffer = keyboard_report_buffer , - .report_id = USB_HID_REPORT_ID_KEYBOARD , - .report_length = USB_HID_REPORT_LENGTH_KEYBOARD , - .usage_page = HID_USAGE_PAGE_DESKTOP , - .usage = HID_USAGE_DESKTOP_KEYBOARD , - }, -#endif - -#ifdef USB_HID_REPORT_ID_MOUSE - { - .base = { .type = &usb_hid_device_type } , - .report_buffer = mouse_report_buffer , - .report_id = USB_HID_REPORT_ID_MOUSE , - .report_length = USB_HID_REPORT_LENGTH_MOUSE , - .usage_page = HID_USAGE_PAGE_DESKTOP , - .usage = HID_USAGE_DESKTOP_MOUSE , - }, -#endif - -#ifdef USB_HID_REPORT_ID_CONSUMER - { - .base = { .type = &usb_hid_device_type } , - .report_buffer = consumer_report_buffer , - .report_id = USB_HID_REPORT_ID_CONSUMER , - .report_length = USB_HID_REPORT_LENGTH_CONSUMER , - .usage_page = HID_USAGE_PAGE_CONSUMER , - .usage = HID_USAGE_CONSUMER_CONTROL , - }, -#endif - -#ifdef USB_HID_REPORT_ID_SYS_CONTROL - { - .base = { .type = &usb_hid_device_type } , - .report_buffer = sys_control_report_buffer , - .report_id = USB_HID_REPORT_ID_SYS_CONTROL , - .report_length = USB_HID_REPORT_LENGTH_SYS_CONTROL , - .usage_page = HID_USAGE_PAGE_DESKTOP , - .usage = HID_USAGE_DESKTOP_SYSTEM_CONTROL , - }, -#endif - -#ifdef USB_HID_REPORT_ID_GAMEPAD - { - .base = { .type = &usb_hid_device_type } , - .report_buffer = gamepad_report_buffer , - .report_id = USB_HID_REPORT_ID_GAMEPAD , - .report_length = USB_HID_REPORT_LENGTH_GAMEPAD , - .usage_page = HID_USAGE_PAGE_DESKTOP , - .usage = HID_USAGE_DESKTOP_GAMEPAD , - }, -#endif - -#ifdef USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD - { - .base = { .type = &usb_hid_device_type } , - .report_buffer = xac_compatible_gamepad_report_buffer , - .report_id = USB_HID_REPORT_ID_XAC_COMPATIBLE_GAMEPAD , - .report_length = USB_HID_REPORT_LENGTH_XAC_COMPATIBLE_GAMEPAD , - .usage_page = HID_USAGE_PAGE_DESKTOP , - .usage = HID_USAGE_DESKTOP_GAMEPAD , - }, -#endif - -#ifdef USB_HID_REPORT_ID_DIGITIZER - { - .base = { .type = &usb_hid_device_type } , - .report_buffer = digitizer_report_buffer , - .report_id = USB_HID_REPORT_ID_DIGITIZER , - .report_length = USB_HID_REPORT_LENGTH_DIGITIZER , - .usage_page = 0x0D , - .usage = 0x02 , - }, -#endif -}; - - -mp_obj_tuple_t common_hal_usb_hid_devices = { - .base = { - .type = &mp_type_tuple, - }, - .len = USB_HID_NUM_DEVICES, - .items = { -#if USB_HID_NUM_DEVICES >= 1 - (mp_obj_t) &usb_hid_devices[0], -#endif -#if USB_HID_NUM_DEVICES >= 2 - (mp_obj_t) &usb_hid_devices[1], -#endif -#if USB_HID_NUM_DEVICES >= 3 - (mp_obj_t) &usb_hid_devices[2], -#endif -#if USB_HID_NUM_DEVICES >= 4 - (mp_obj_t) &usb_hid_devices[3], -#endif -#if USB_HID_NUM_DEVICES >= 5 - (mp_obj_t) &usb_hid_devices[4], -#endif -#if USB_HID_NUM_DEVICES >= 6 - (mp_obj_t) &usb_hid_devices[5], -#endif -#if USB_HID_NUM_DEVICES >= 7 -#error "Too many USB HID devices" -#endif - } -}; +// Nothing needed here. Tables of HID devices are in autogen_usb_descriptor.c. diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index f782f9afc..82d2daf0f 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -12,7 +12,7 @@ ALL_DEVICES='CDC,MSC,AUDIO,HID' ALL_DEVICES_SET=frozenset(ALL_DEVICES.split(',')) DEFAULT_DEVICES='CDC,MSC,AUDIO,HID' -ALL_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,SYS_CONTROL,GAMEPAD,DIGITIZER,XAC_COMPATIBLE_GAMEPAD' +ALL_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,SYS_CONTROL,GAMEPAD,DIGITIZER,XAC_COMPATIBLE_GAMEPAD,RAW' ALL_HID_DEVICES_SET=frozenset(ALL_HID_DEVICES.split(',')) # Digitizer works on Linux but conflicts with mouse, so omit it. DEFAULT_HID_DEVICES='KEYBOARD,MOUSE,CONSUMER,GAMEPAD' @@ -28,20 +28,20 @@ parser.add_argument('--pid', type=lambda x: int(x, 16), help='product id') parser.add_argument('--serial_number_length', type=int, default=32, help='length needed for the serial number in digits') -parser.add_argument('--devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_DEVICES, +parser.add_argument('--devices', type=lambda l: tuple(l.split(',')), default=DEFAULT_DEVICES, help='devices to include in descriptor (AUDIO includes MIDI support)') -parser.add_argument('--hid_devices', type=lambda l: frozenset(l.split(',')), default=DEFAULT_HID_DEVICES, +parser.add_argument('--hid_devices', type=lambda l: tuple(l.split(',')), default=DEFAULT_HID_DEVICES, help='HID devices to include in HID report descriptor') parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True) parser.add_argument('--output_h_file', type=argparse.FileType('w'), required=True) args = parser.parse_args() -unknown_devices = list(args.devices - ALL_DEVICES_SET) +unknown_devices = list(frozenset(args.devices) - ALL_DEVICES_SET) if unknown_devices: raise ValueError("Unknown device(s)", unknown_devices) -unknown_hid_devices = list(args.hid_devices - ALL_HID_DEVICES_SET) +unknown_hid_devices = list(frozenset(args.hid_devices) - ALL_HID_DEVICES_SET) if unknown_hid_devices: raise ValueError("Unknown HID devices(s)", unknown_hid_devices) @@ -160,29 +160,27 @@ msc_interfaces = [ ) ] -# Sort by Report ID for consistency. -hid_devices = sorted(args.hid_devices, key=lambda name: hid_report_descriptors.REPORT_IDS[name]) +# When there's only one hid_device, it shouldn't have a report id. +# Otherwise, report ids are assigned sequentially: +# args.hid_devices[0] has report_id 1 +# args.hid_devices[1] has report_id 2 +# etc. -# When there's only one hid_device, it can't be in a composite descriptor. -# It has no report id (indicated by 0), so remove the existing one. - -#if len(hid_devices) == 1: -if False: - name = hid_devices[0] +if len(args.hid_devices) == 1: + name = args.hid_devices[0] combined_hid_report_descriptor = hid.ReportDescriptor( description=name, - report_descriptor=hid_report_descriptors.remove_report_id( - hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor)) - hid_report_ids_dict = { name : 0 } + report_descriptor=bytes(hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](0))) else: + report_id = 1 + concatenated_descriptors = bytearray() + for name in args.hid_devices: + concatenated_descriptors.extend( + bytes(hid_report_descriptors.REPORT_DESCRIPTOR_FUNCTIONS[name](report_id))) + report_id += 1 combined_hid_report_descriptor = hid.ReportDescriptor( - description="MULTIDEVICE", - report_descriptor=b''.join( - hid_report_descriptors.REPORT_DESCRIPTORS[name].report_descriptor for name in hid_devices )) - hid_report_ids_dict = { name: hid_report_descriptors.REPORT_IDS[name] for name in hid_devices } - -hid_report_lengths_dict = { name: hid_report_descriptors.REPORT_LENGTHS[name] for name in hid_devices } -hid_max_report_length = max(hid_report_lengths_dict.values()) + description="MULTIDEVICE", + report_descriptor=bytes(concatenated_descriptors)) # ASF4 expects keyboard and generic devices to have both in and out endpoints, # and will fail (possibly silently) if both are not supplied. @@ -343,6 +341,8 @@ h_file = args.output_h_file c_file.write("""\ #include +#include "py/objtuple.h" +#include "shared-bindings/usb_hid/Device.h" #include "{H_FILE_NAME}" """.format(H_FILE_NAME=h_file.name)) @@ -461,7 +461,9 @@ const uint8_t usb_desc_cfg[{configuration_length}]; uint16_t usb_serial_number[{serial_number_length}]; uint16_t const * const string_desc_arr [{string_descriptor_length}]; -const uint8_t hid_report_descriptor[{HID_REPORT_DESCRIPTOR_LENGTH}]; +const uint8_t hid_report_descriptor[{hid_report_descriptor_length}]; + +#define USB_HID_NUM_DEVICES {hid_num_devices} // Vendor name included in Inquiry response, max 8 bytes #define CFG_TUD_MSC_VENDOR "{msc_vendor}" @@ -475,36 +477,11 @@ const uint8_t hid_report_descriptor[{HID_REPORT_DESCRIPTOR_LENGTH}]; configuration_length=descriptor_length, max_configuration_length=max(hid_descriptor_length, descriptor_length), string_descriptor_length=len(pointers_to_strings), - HID_REPORT_DESCRIPTOR_LENGTH=len(bytes(combined_hid_report_descriptor)), + hid_report_descriptor_length=len(bytes(combined_hid_report_descriptor)), + hid_num_devices=len(args.hid_devices), msc_vendor=args.manufacturer[:8], msc_product=args.product[:16])) -# #define the report ID's used in the combined HID descriptor -for name, id in hid_report_ids_dict.items(): - h_file.write("""\ -#define USB_HID_REPORT_ID_{name} {id} -""".format(name=name, - id=id)) - -h_file.write("\n") - -# #define the report sizes used in the combined HID descriptor -for name, length in hid_report_lengths_dict.items(): - h_file.write("""\ -#define USB_HID_REPORT_LENGTH_{name} {length} -""".format(name=name, - length=length)) - -h_file.write("\n") - -h_file.write("""\ -#define USB_HID_NUM_DEVICES {num_devices} -#define USB_HID_MAX_REPORT_LENGTH {max_length} -""".format(num_devices=len(hid_report_lengths_dict), - max_length=hid_max_report_length)) - - - # Write out the report descriptor and info c_file.write("""\ const uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{ @@ -512,7 +489,55 @@ const uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{ for b in bytes(combined_hid_report_descriptor): c_file.write("0x{:02x}, ".format(b)) +c_file.write("""\ +}; + +""") + +# Write out USB HID report buffer definitions. +for report_id, name in enumerate(args.hid_devices, start=1): + c_file.write("""\ +static uint8_t {name}_report_buffer[{report_length}]; +""".format(name=name.lower(), report_length=hid_report_descriptors.HID_DEVICE_DATA[name].report_length)) + +# Write out table of device objects. c_file.write(""" +usb_hid_device_obj_t usb_hid_devices[] = { +"""); +for report_id, name in enumerate(args.hid_devices, start=1): + device_data = hid_report_descriptors.HID_DEVICE_DATA[name] + c_file.write("""\ + {{ + .base = {{ .type = &usb_hid_device_type }}, + .report_buffer = {name}_report_buffer, + .report_id = {report_id:}, + .report_length = {report_length}, + .usage_page = {usage_page:#04x}, + .usage = {usage:#04x}, + }}, +""".format(name=name.lower(), report_id=report_id, + report_length=device_data.report_length, + usage_page=device_data.usage_page, + usage=device_data.usage)) +c_file.write("""\ +}; +""") + +# Write out tuple of device objects. +c_file.write(""" +mp_obj_tuple_t common_hal_usb_hid_devices = {{ + .base = {{ + .type = &mp_type_tuple, + }}, + .len = {num_devices}, + .items = {{ +""".format(num_devices=len(args.hid_devices))) +for idx in range(len(args.hid_devices)): + c_file.write("""\ + (mp_obj_t) &usb_hid_devices[{idx}], +""".format(idx=idx)) +c_file.write("""\ + }, }; """) diff --git a/tools/hid_report_descriptors.py b/tools/hid_report_descriptors.py index 4902657af..92c962d59 100644 --- a/tools/hid_report_descriptors.py +++ b/tools/hid_report_descriptors.py @@ -29,271 +29,284 @@ HID specific descriptors * Author(s): Dan Halbert """ -from adafruit_usb_descriptor import hid - -def remove_report_id(report_descriptor_bytes): - #return report_descriptor_bytes - report_id_pos = report_descriptor_bytes.index(0x85) - return report_descriptor_bytes[:report_id_pos] + report_descriptor_bytes[report_id_pos + 2:] +from collections import namedtuple -REPORT_IDS = { - "KEYBOARD" : 1, - "MOUSE" : 2, - "CONSUMER" : 3, - "SYS_CONTROL" : 4, - "GAMEPAD" : 5, - "DIGITIZER" : 6, - "XAC_COMPATIBLE_GAMEPAD" : 7, - # RAW must not have a report ID, so it can't be used with other devices. - "RAW" : 0, - } +from adafruit_usb_descriptor import hid -# Byte count for each kind of report. Length does not include report ID in first byte. -REPORT_LENGTHS = { - "KEYBOARD" : 8, - "MOUSE" : 4, - "CONSUMER" : 2, - "SYS_CONTROL" : 1, - "GAMEPAD" : 6, - "DIGITIZER" : 5, - "XAC_COMPATIBLE_GAMEPAD" : 3, - "RAW" : 64, +# Information about each kind of device +# report_length does not include report ID in first byte, if present when sent. +DeviceData = namedtuple('DeviceData', ('report_length', 'usage_page', 'usage')) +HID_DEVICE_DATA = { + "KEYBOARD" : DeviceData(report_length=8, usage_page=0x01, usage=0x06), # Generic Desktop, Keyboard + "MOUSE" : DeviceData(report_length=4, usage_page=0x01, usage=0x02), # Generic Desktop, Mouse + "CONSUMER" : DeviceData(report_length=2, usage_page=0x0C, usage=0x01), # Consumer, Consumer Control + "SYS_CONTROL" : DeviceData(report_length=1, usage_page=0x01, usage=0x80), # Generic Desktop, Sys Control + "GAMEPAD" : DeviceData(report_length=6, usage_page=0x01, usage=0x05), # Generic Desktop, Game Pad + "DIGITIZER" : DeviceData(report_length=5, usage_page=0x0D, usage=0x02), # Digitizers, Pen + "XAC_COMPATIBLE_GAMEPAD" : DeviceData(report_length=3, usage_page=0x01, usage=0x05), # Generic Desktop, Game Pad + "RAW" : DeviceData(report_length=64, usage_page=0xFFAF, usage=0xAF), # Vendor 0xFFAF "Adafruit", 0xAF } -KEYBOARD_WITH_ID = hid.ReportDescriptor( - description="KEYBOARD", - report_descriptor=bytes([ - # Regular keyboard - 0x05, 0x01, # Usage Page (Generic Desktop) - 0x09, 0x06, # Usage (Keyboard) - 0xA1, 0x01, # Collection (Application) - 0x85, REPORT_IDS["KEYBOARD"], # Report ID (1) - 0x05, 0x07, # Usage Page (Keyboard) - 0x19, 224, # Usage Minimum (224) - 0x29, 231, # Usage Maximum (231) - 0x15, 0x00, # Logical Minimum (0) - 0x25, 0x01, # Logical Maximum (1) - 0x75, 0x01, # Report Size (1) - 0x95, 0x08, # Report Count (8) - 0x81, 0x02, # Input (Data, Variable, Absolute) - 0x81, 0x01, # Input (Constant) - 0x19, 0x00, # Usage Minimum (0) - 0x29, 101, # Usage Maximum (101) - 0x15, 0x00, # Logical Minimum (0) - 0x25, 101, # Logical Maximum (101) - 0x75, 0x08, # Report Size (8) - 0x95, 0x06, # Report Count (6) - 0x81, 0x00, # Input (Data, Array) - 0x05, 0x08, # Usage Page (LED) - 0x19, 0x01, # Usage Minimum (1) - 0x29, 0x05, # Usage Maximum (5) - 0x15, 0x00, # Logical Minimum (0) - 0x25, 0x01, # Logical Maximum (1) - 0x75, 0x01, # Report Size (1) - 0x95, 0x05, # Report Count (5) - 0x91, 0x02, # Output (Data, Variable, Absolute) - 0x95, 0x03, # Report Count (3) - 0x91, 0x01, # Output (Constant) - 0xC0, # End Collection - ])) +def keyboard_hid_descriptor(report_id): + data = HID_DEVICE_DATA["KEYBOARD"] + return hid.ReportDescriptor( + description="KEYBOARD", + report_descriptor=bytes( + # Regular keyboard + (0x05, data.usage_page, # Usage Page (Generic Desktop) + 0x09, data.usage, # Usage (Keyboard) + 0xA1, 0x01, # Collection (Application) + ) + + ((0x85, report_id) if report_id != 0 else ()) + + (0x05, 0x07, # Usage Page (Keyboard) + 0x19, 224, # Usage Minimum (224) + 0x29, 231, # Usage Maximum (231) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 0x01, # Logical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x95, 0x08, # Report Count (8) + 0x81, 0x02, # Input (Data, Variable, Absolute) + 0x81, 0x01, # Input (Constant) + 0x19, 0x00, # Usage Minimum (0) + 0x29, 101, # Usage Maximum (101) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 101, # Logical Maximum (101) + 0x75, 0x08, # Report Size (8) + 0x95, 0x06, # Report Count (6) + 0x81, 0x00, # Input (Data, Array) + 0x05, 0x08, # Usage Page (LED) + 0x19, 0x01, # Usage Minimum (1) + 0x29, 0x05, # Usage Maximum (5) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 0x01, # Logical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x95, 0x05, # Report Count (5) + 0x91, 0x02, # Output (Data, Variable, Absolute) + 0x95, 0x03, # Report Count (3) + 0x91, 0x01, # Output (Constant) + 0xC0, # End Collection + ))) -MOUSE_WITH_ID = hid.ReportDescriptor( - description="MOUSE", - report_descriptor=bytes([ - # Regular mouse - 0x05, 0x01, # Usage Page (Generic Desktop) - 0x09, 0x02, # Usage (Mouse) - 0xA1, 0x01, # Collection (Application) - 0x09, 0x01, # Usage (Pointer) - 0xA1, 0x00, # Collection (Physical) - 0x85, REPORT_IDS["MOUSE"], # Report ID (n) - 0x05, 0x09, # Usage Page (Button) - 0x19, 0x01, # Usage Minimum (0x01) - 0x29, 0x05, # Usage Maximum (0x05) - 0x15, 0x00, # Logical Minimum (0) - 0x25, 0x01, # Logical Maximum (1) - 0x95, 0x05, # Report Count (5) - 0x75, 0x01, # Report Size (1) - 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x95, 0x01, # Report Count (1) - 0x75, 0x03, # Report Size (3) - 0x81, 0x01, # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) - 0x09, 0x30, # Usage (X) - 0x09, 0x31, # Usage (Y) - 0x15, 0x81, # Logical Minimum (-127) - 0x25, 0x7F, # Logical Maximum (127) - 0x75, 0x08, # Report Size (8) - 0x95, 0x02, # Report Count (2) - 0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 0x09, 0x38, # Usage (Wheel) - 0x15, 0x81, # Logical Minimum (-127) - 0x25, 0x7F, # Logical Maximum (127) - 0x75, 0x08, # Report Size (8) - 0x95, 0x01, # Report Count (1) - 0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, # End Collection - 0xC0, # End Collection - ])) +def mouse_hid_descriptor(report_id): + data = HID_DEVICE_DATA["MOUSE"] + return hid.ReportDescriptor( + description="MOUSE", + report_descriptor=bytes( + # Regular mouse + (0x05, data.usage_page, # Usage Page (Generic Desktop) + 0x09, data.usage, # Usage (Mouse) + 0xA1, 0x01, # Collection (Application) + 0x09, 0x01, # Usage (Pointer) + 0xA1, 0x00, # Collection (Physical) + ) + + ((0x85, report_id) if report_id != 0 else ()) + + (0x05, 0x09, # Usage Page (Button) + 0x19, 0x01, # Usage Minimum (0x01) + 0x29, 0x05, # Usage Maximum (0x05) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 0x01, # Logical Maximum (1) + 0x95, 0x05, # Report Count (5) + 0x75, 0x01, # Report Size (1) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, # Report Count (1) + 0x75, 0x03, # Report Size (3) + 0x81, 0x01, # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, # Usage (X) + 0x09, 0x31, # Usage (Y) + 0x15, 0x81, # Logical Minimum (-127) + 0x25, 0x7F, # Logical Maximum (127) + 0x75, 0x08, # Report Size (8) + 0x95, 0x02, # Report Count (2) + 0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x38, # Usage (Wheel) + 0x15, 0x81, # Logical Minimum (-127) + 0x25, 0x7F, # Logical Maximum (127) + 0x75, 0x08, # Report Size (8) + 0x95, 0x01, # Report Count (1) + 0x81, 0x06, # Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, # End Collection + 0xC0, # End Collection + ))) -CONSUMER_WITH_ID = hid.ReportDescriptor( - description="CONSUMER", - report_descriptor=bytes([ - # Consumer ("multimedia") keys - 0x05, 0x0C, # Usage Page (Consumer) - 0x09, 0x01, # Usage (Consumer Control) - 0xA1, 0x01, # Collection (Application) - 0x85, REPORT_IDS["CONSUMER"], # Report ID (n) - 0x75, 0x10, # Report Size (16) - 0x95, 0x01, # Report Count (1) - 0x15, 0x01, # Logical Minimum (1) - 0x26, 0x8C, 0x02, # Logical Maximum (652) - 0x19, 0x01, # Usage Minimum (Consumer Control) - 0x2A, 0x8C, 0x02, # Usage Maximum (AC Send) - 0x81, 0x00, # Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, # End Collection - ])) +def consumer_hid_descriptor(report_id): + data = HID_DEVICE_DATA["CONSUMER"] + return hid.ReportDescriptor( + description="CONSUMER", + report_descriptor=bytes( + # Consumer ("multimedia") keys + (0x05, data.usage_page, # Usage Page (Consumer) + 0x09, data.usage, # Usage (Consumer Control) + 0xA1, 0x01, # Collection (Application) + ) + + ((0x85, report_id) if report_id != 0 else ()) + + (0x75, 0x10, # Report Size (16) + 0x95, 0x01, # Report Count (1) + 0x15, 0x01, # Logical Minimum (1) + 0x26, 0x8C, 0x02, # Logical Maximum (652) + 0x19, 0x01, # Usage Minimum (Consumer Control) + 0x2A, 0x8C, 0x02, # Usage Maximum (AC Send) + 0x81, 0x00, # Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, # End Collection + ))) -SYS_CONTROL_WITH_ID = hid.ReportDescriptor( - description="SYS_CONTROL", - report_descriptor=bytes([ - # Power controls - 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) - 0x09, 0x80, # Usage (Sys Control) - 0xA1, 0x01, # Collection (Application) - 0x85, REPORT_IDS["SYS_CONTROL"], # Report ID (n) - 0x75, 0x02, # Report Size (2) - 0x95, 0x01, # Report Count (1) - 0x15, 0x01, # Logical Minimum (1) - 0x25, 0x03, # Logical Maximum (3) - 0x09, 0x82, # Usage (Sys Sleep) - 0x09, 0x81, # Usage (Sys Power Down) - 0x09, 0x83, # Usage (Sys Wake Up) - 0x81, 0x60, # Input (Data,Array,Abs,No Wrap,Linear,No Preferred State,Null State) - 0x75, 0x06, # Report Size (6) - 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, # End Collection - ])) +def sys_control_hid_descriptor(report_id): + data = HID_DEVICE_DATA["SYS_CONTROL"] + return hid.ReportDescriptor( + description="SYS_CONTROL", + report_descriptor=bytes( + # Power controls + (0x05, data.usage_page, # Usage Page (Generic Desktop Ctrls) + 0x09, data.usage, # Usage (Sys Control) + 0xA1, 0x01, # Collection (Application) + ) + + ((0x85, report_id) if report_id != 0 else ()) + + (0x75, 0x02, # Report Size (2) + 0x95, 0x01, # Report Count (1) + 0x15, 0x01, # Logical Minimum (1) + 0x25, 0x03, # Logical Maximum (3) + 0x09, 0x82, # Usage (Sys Sleep) + 0x09, 0x81, # Usage (Sys Power Down) + 0x09, 0x83, # Usage (Sys Wake Up) + 0x81, 0x60, # Input (Data,Array,Abs,No Wrap,Linear,No Preferred State,Null State) + 0x75, 0x06, # Report Size (6) + 0x81, 0x03, # Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, # End Collection + ))) -GAMEPAD_WITH_ID = hid.ReportDescriptor( - description="GAMEPAD", - report_descriptor=bytes([ - # Gamepad with 16 buttons and two joysticks - 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) - 0x09, 0x05, # Usage (Game Pad) - 0xA1, 0x01, # Collection (Application) - 0x85, REPORT_IDS["GAMEPAD"], # Report ID (n) - 0x05, 0x09, # Usage Page (Button) - 0x19, 0x01, # Usage Minimum (Button 1) - 0x29, 0x10, # Usage Maximum (Button 16) - 0x15, 0x00, # Logical Minimum (0) - 0x25, 0x01, # Logical Maximum (1) - 0x75, 0x01, # Report Size (1) - 0x95, 0x10, # Report Count (16) - 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) - 0x15, 0x81, # Logical Minimum (-127) - 0x25, 0x7F, # Logical Maximum (127) - 0x09, 0x30, # Usage (X) - 0x09, 0x31, # Usage (Y) - 0x09, 0x32, # Usage (Z) - 0x09, 0x35, # Usage (Rz) - 0x75, 0x08, # Report Size (8) - 0x95, 0x04, # Report Count (4) - 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, # End Collection - ])) +def gamepad_hid_descriptor(report_id): + data = HID_DEVICE_DATA["GAMEPAD"] + return hid.ReportDescriptor( + description="GAMEPAD", + report_descriptor=bytes( + # Gamepad with 16 buttons and two joysticks + (0x05, data.usage_page, # Usage Page (Generic Desktop Ctrls) + 0x09, data.usage, # Usage (Game Pad) + 0xA1, 0x01, # Collection (Application) + ) + + ((0x85, report_id) if report_id != 0 else ()) + + (0x05, 0x09, # Usage Page (Button) + 0x19, 0x01, # Usage Minimum (Button 1) + 0x29, 0x10, # Usage Maximum (Button 16) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 0x01, # Logical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x95, 0x10, # Report Count (16) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) + 0x15, 0x81, # Logical Minimum (-127) + 0x25, 0x7F, # Logical Maximum (127) + 0x09, 0x30, # Usage (X) + 0x09, 0x31, # Usage (Y) + 0x09, 0x32, # Usage (Z) + 0x09, 0x35, # Usage (Rz) + 0x75, 0x08, # Report Size (8) + 0x95, 0x04, # Report Count (4) + 0x81, 0x02, # Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, # End Collection + ))) -DIGITIZER_WITH_ID = hid.ReportDescriptor( - description="DIGITIZER", - report_descriptor=bytes([ - # Digitizer (used as an absolute pointer) - 0x05, 0x0D, # Usage Page (Digitizers) - 0x09, 0x02, # Usage (Pen) - 0xA1, 0x01, # Collection (Application) - 0x85, REPORT_IDS["DIGITIZER"], # Report ID (n) - 0x09, 0x01, # Usage (Stylus) - 0xA1, 0x00, # Collection (Physical) - 0x09, 0x32, # Usage (In-Range) - 0x09, 0x42, # Usage (Tip Switch) - 0x09, 0x44, # Usage (Barrel Switch) - 0x09, 0x45, # Usage (Eraser Switch) - 0x15, 0x00, # Logical Minimum (0) - 0x25, 0x01, # Logical Maximum (1) - 0x75, 0x01, # Report Size (1) - 0x95, 0x04, # Report Count (4) - 0x81, 0x02, # Input (Data,Var,Abs) - 0x75, 0x04, # Report Size (4) -- Filler - 0x95, 0x01, # Report Count (1) -- Filler - 0x81, 0x01, # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) - 0x15, 0x00, # Logical Minimum (0) - 0x26, 0xff, 0x7f, # Logical Maximum (32767) - 0x09, 0x30, # Usage (X) - 0x09, 0x31, # Usage (Y) - 0x75, 0x10, # Report Size (16) - 0x95, 0x02, # Report Count (2) - 0x81, 0x02, # Input (Data,Var,Abs) - 0xC0, # End Collection - 0xC0, # End Collection - ])) +def digitizer_hid_descriptor(report_id): + data = HID_DEVICE_DATA["DIGITIZER"] + return hid.ReportDescriptor( + description="DIGITIZER", + report_descriptor=bytes( + # Digitizer (used as an absolute pointer) + (0x05, data.usage_page, # Usage Page (Digitizers) + 0x09, data.usage, # Usage (Pen) + 0xA1, 0x01, # Collection (Application) + ) + + ((0x85, report_id) if report_id != 0 else ()) + + (0x09, 0x01, # Usage (Stylus) + 0xA1, 0x00, # Collection (Physical) + 0x09, 0x32, # Usage (In-Range) + 0x09, 0x42, # Usage (Tip Switch) + 0x09, 0x44, # Usage (Barrel Switch) + 0x09, 0x45, # Usage (Eraser Switch) + 0x15, 0x00, # Logical Minimum (0) + 0x25, 0x01, # Logical Maximum (1) + 0x75, 0x01, # Report Size (1) + 0x95, 0x04, # Report Count (4) + 0x81, 0x02, # Input (Data,Var,Abs) + 0x75, 0x04, # Report Size (4) -- Filler + 0x95, 0x01, # Report Count (1) -- Filler + 0x81, 0x01, # Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, # Usage Page (Generic Desktop Ctrls) + 0x15, 0x00, # Logical Minimum (0) + 0x26, 0xff, 0x7f, # Logical Maximum (32767) + 0x09, 0x30, # Usage (X) + 0x09, 0x31, # Usage (Y) + 0x75, 0x10, # Report Size (16) + 0x95, 0x02, # Report Count (2) + 0x81, 0x02, # Input (Data,Var,Abs) + 0xC0, # End Collection + 0xC0, # End Collection + ))) -XAC_COMPATIBLE_GAMEPAD_WITH_ID = hid.ReportDescriptor( - description="XAC", - report_descriptor=bytes([ - # This descriptor mimics the simple joystick from PDP that the XBox likes - 0x05, 0x01, # Usage Page (Desktop), - 0x09, 0x05, # Usage (Gamepad), - 0xA1, 0x01, # Collection (Application), - 0x85, REPORT_IDS["XAC_COMPATIBLE_GAMEPAD"], # Report ID (n) - 0x15, 0x00, # Logical Minimum (0), - 0x25, 0x01, # Logical Maximum (1), - 0x35, 0x00, # Physical Minimum (0), - 0x45, 0x01, # Physical Maximum (1), - 0x75, 0x01, # Report Size (1), - 0x95, 0x08, # Report Count (8), - 0x05, 0x09, # Usage Page (Button), - 0x19, 0x01, # Usage Minimum (01h), - 0x29, 0x08, # Usage Maximum (08h), - 0x81, 0x02, # Input (Variable), - 0x05, 0x01, # Usage Page (Desktop), - 0x26, 0xFF, 0x00, # Logical Maximum (255), - 0x46, 0xFF, 0x00, # Physical Maximum (255), - 0x09, 0x30, # Usage (X), - 0x09, 0x31, # Usage (Y), - 0x75, 0x08, # Report Size (8), - 0x95, 0x02, # Report Count (2), - 0x81, 0x02, # Input (Variable), - 0xC0 # End Collection - ])) +def xac_compatible_gamepad_hid_descriptor(report_id): + data = HID_DEVICE_DATA["XAC_COMPATIBLE_GAMEPAD"] + return hid.ReportDescriptor( + description="XAC", + report_descriptor=bytes( + # This descriptor mimics the simple joystick from PDP that the XBox likes + (0x05, data.usage_page, # Usage Page (Desktop), + 0x09, data.usage, # Usage (Gamepad), + 0xA1, 0x01, # Collection (Application), + ) + + ((0x85, report_id) if report_id != 0 else ()) + + (0x15, 0x00, # Logical Minimum (0), + 0x25, 0x01, # Logical Maximum (1), + 0x35, 0x00, # Physical Minimum (0), + 0x45, 0x01, # Physical Maximum (1), + 0x75, 0x01, # Report Size (1), + 0x95, 0x08, # Report Count (8), + 0x05, 0x09, # Usage Page (Button), + 0x19, 0x01, # Usage Minimum (01h), + 0x29, 0x08, # Usage Maximum (08h), + 0x81, 0x02, # Input (Variable), + 0x05, 0x01, # Usage Page (Desktop), + 0x26, 0xFF, 0x00, # Logical Maximum (255), + 0x46, 0xFF, 0x00, # Physical Maximum (255), + 0x09, 0x30, # Usage (X), + 0x09, 0x31, # Usage (Y), + 0x75, 0x08, # Report Size (8), + 0x95, 0x02, # Report Count (2), + 0x81, 0x02, # Input (Variable), + 0xC0 # End Collection + ))) -RAW = hid.ReportDescriptor( - description="RAW", - report_descriptor=bytes([ - # Provide vendor-defined - 0x06, 0xAF, 0xFF, # Usage Page (Vendor 0xFFAF "Adafruit"), - 0x09, 0xAF, # Usage (AF), - 0xA1, 0x01, # Collection (Application), - 0x75, 0x08, # Report Size (8), - 0x15, 0x00, # Logical Minimum (0), - 0x26, 0xFF, 0x00 # Logical Maximum (255), - 0x95, 0x08, # Report Count (8), - 0x09, 0x01 # Usage(xxx) - 0x81, 0x02 # Input (Variable) - 0x95, 0x08, # Report Count (8), - 0x09, 0x02, # Usage(xxx) - 0x91, 0x02, # Input (Variable) - 0xC0 # End Collection - ])) +def raw_hid_descriptor(report_id): + if report_id != 0: + raise ValueError("raw hid must not have a report id") + data = HID_DEVICE_DATA["RAW"] + return hid.ReportDescriptor( + description="RAW", + report_descriptor=bytes( + # Provide vendor-defined + # This is a two-byte page value. + (0x06, data.usage_page & 0xff, (data.usage_page >> 8) & 0xff, # Usage Page (Vendor 0xFFAF "Adafruit"), + 0x09, data.usage, # Usage (AF), + 0xA1, 0x01, # Collection (Application), + 0x75, 0x08, # Report Size (8), + 0x15, 0x00, # Logical Minimum (0), + 0x26, 0xFF, 0x00, # Logical Maximum (255), + 0x95, 0x08, # Report Count (8), + 0x09, 0x01, # Usage(xxx) + 0x81, 0x02, # Input (Variable) + 0x95, 0x08, # Report Count (8), + 0x09, 0x02, # Usage(xxx) + 0x91, 0x02, # Input (Variable) + 0xC0 # End Collection + ))) -# Byte count for each kind of report. Length does not include report ID in first byte. -REPORT_DESCRIPTORS = { - "KEYBOARD" : KEYBOARD_WITH_ID, - "MOUSE" : MOUSE_WITH_ID, - "CONSUMER" : CONSUMER_WITH_ID, - "SYS_CONTROL" : SYS_CONTROL_WITH_ID, - "GAMEPAD" : GAMEPAD_WITH_ID, - "DIGITIZER" : DIGITIZER_WITH_ID, - "XAC_COMPATIBLE_GAMEPAD" : XAC_COMPATIBLE_GAMEPAD_WITH_ID, - "RAW" : RAW_WITH_ID, - } +# Function to call for each kind of HID descriptor. +REPORT_DESCRIPTOR_FUNCTIONS = { + "KEYBOARD" : keyboard_hid_descriptor, + "MOUSE" : mouse_hid_descriptor, + "CONSUMER" : consumer_hid_descriptor, + "SYS_CONTROL" : sys_control_hid_descriptor, + "GAMEPAD" : gamepad_hid_descriptor, + "DIGITIZER" : digitizer_hid_descriptor, + "XAC_COMPATIBLE_GAMEPAD" : xac_compatible_gamepad_hid_descriptor, + "RAW" : raw_hid_descriptor, +} -- cgit v1.2.3 From d3cb1030c8c8ab1395c17db1ec003e062c6a42a9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 3 Sep 2019 23:15:50 -0400 Subject: trivial change; try to force check run --- shared-module/usb_hid/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/usb_hid/__init__.c b/shared-module/usb_hid/__init__.c index 9c6701ab8..d88f9787a 100644 --- a/shared-module/usb_hid/__init__.c +++ b/shared-module/usb_hid/__init__.c @@ -24,4 +24,4 @@ * THE SOFTWARE. */ -// Nothing needed here. Tables of HID devices are in autogen_usb_descriptor.c. +// Nothing needed here. Tables of HID devices are generated in autogen_usb_descriptor.c at compile-time. -- cgit v1.2.3 From edfcee29ff88faa35a75a979cb74ad64553289a6 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Tue, 3 Sep 2019 22:25:27 -0500 Subject: remove leftover debug print --- shared-module/audiomixer/Mixer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 9f30bd47f..e0fb4fab8 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -178,7 +178,6 @@ static inline uint32_t mult8unsigned(uint32_t val, int32_t mul) { #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU return val; #else*/ - mp_printf(&mp_plat_print, "mult8unsigned"); uint32_t result = 0; float mod_mul = (float) mul / (float) ((1<<15)-1); for (int8_t i = 0; i < 4; i++) { -- cgit v1.2.3 From 5f6228b6f02c229e84cc64c1e2b6a2332354c186 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Wed, 4 Sep 2019 16:41:58 +0200 Subject: Fix transactions in _stage after displayio changes Also, move the rendering setup code to shared-module from shared-bindings. In CP 5.0, displayio_display_core_set_region_to_update now starts its own transaction, so it has to be moved outside of the transaction started by the render call. --- shared-bindings/_stage/__init__.c | 13 ------------- shared-module/_stage/__init__.c | 27 ++++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 16 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index d18d306f4..1154bbbf1 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -96,21 +96,8 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { scale = mp_obj_get_int(args[7]); } - // TODO: Everything below should be in shared-module because it's not argument parsing. - while (!displayio_display_core_begin_transaction(&display->core)) { - RUN_BACKGROUND_TASKS; - } - displayio_area_t area; - area.x1 = x0; - area.y1 = y0; - area.x2 = x1; - area.y2 = y1; - displayio_display_core_set_region_to_update(&display->core, display->set_column_command, display->set_row_command, NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area); - - display->core.send(display->core.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &display->write_ram_command, 1); render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display, scale); - displayio_display_core_end_transaction(&display->core); return mp_const_none; } diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index 2c525be87..d5da74272 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -36,6 +36,22 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t *buffer, size_t buffer_size, displayio_display_obj_t *display, uint8_t scale) { + + displayio_area_t area; + area.x1 = x0; + area.y1 = y0; + area.x2 = x1; + area.y2 = y1; + displayio_display_core_set_region_to_update( + &display->core, display->set_column_command, display->set_row_command, + NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area); + + while (!displayio_display_core_begin_transaction(&display->core)) { + RUN_BACKGROUND_TASKS; + } + display->core.send(display->core.bus, DISPLAY_COMMAND, + CHIP_SELECT_TOGGLE_EVERY_BYTE, + &display->write_ram_command, 1); size_t index = 0; for (uint16_t y = y0; y < y1; ++y) { for (uint8_t yscale = 0; yscale < scale; ++yscale) { @@ -57,8 +73,9 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, index += 1; // The buffer is full, send it. if (index >= buffer_size) { - display->core.send(display->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*)buffer), - buffer_size * 2); + display->core.send(display->core.bus, DISPLAY_DATA, + CHIP_SELECT_UNTOUCHED, + ((uint8_t*)buffer), buffer_size * 2); index = 0; } } @@ -67,6 +84,10 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, } // Send the remaining data. if (index) { - display->core.send(display->core.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t*)buffer), index * 2); + display->core.send(display->core.bus, DISPLAY_DATA, + CHIP_SELECT_UNTOUCHED, + ((uint8_t*)buffer), index * 2); } + + displayio_display_core_end_transaction(&display->core); } -- cgit v1.2.3 From 70407e4d871ad7e42e707e2e0b53c50c32872cc5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 4 Sep 2019 10:27:21 -0700 Subject: Bitpack bools in TileGrid and Group --- shared-module/displayio/Group.h | 13 +++++++------ shared-module/displayio/TileGrid.h | 21 +++++++++++---------- 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Group.h b/shared-module/displayio/Group.h index 7021da4bd..5afaac1ba 100644 --- a/shared-module/displayio/Group.h +++ b/shared-module/displayio/Group.h @@ -42,17 +42,18 @@ typedef struct { typedef struct { mp_obj_base_t base; displayio_group_child_t* children; + displayio_buffer_transform_t absolute_transform; + displayio_area_t dirty_area; // Catch all for changed area int16_t x; int16_t y; uint16_t scale; uint16_t size; uint16_t max_size; - bool item_removed; - bool in_group; - bool hidden; - bool hidden_by_parent; - displayio_buffer_transform_t absolute_transform; - displayio_area_t dirty_area; // Catch all for changed area + bool item_removed :1; + bool in_group :1; + bool hidden :1; + bool hidden_by_parent :1; + uint8_t padding :4; } displayio_group_t; void displayio_group_construct(displayio_group_t* self, displayio_group_child_t* child_array, uint32_t max_size, uint32_t scale, mp_int_t x, mp_int_t y); diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index 3e95dd20a..e97d3dfd4 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -55,16 +55,17 @@ typedef struct { displayio_area_t dirty_area; // Stored as a relative area until the refresh area is fetched. displayio_area_t previous_area; // Stored as an absolute area. displayio_area_t current_area; // Stored as an absolute area so it applies across frames. - bool partial_change; - bool full_change; - bool moved; - bool inline_tiles; - bool in_group; - bool flip_x; - bool flip_y; - bool transpose_xy; - bool hidden; - bool hidden_by_parent; + bool partial_change :1; + bool full_change :1; + bool moved :1; + bool inline_tiles :1; + bool in_group :1; + bool flip_x :1; + bool flip_y :1; + bool transpose_xy :1; + bool hidden :1; + bool hidden_by_parent :1; + uint8_t padding :6; } displayio_tilegrid_t; void displayio_tilegrid_set_hidden_by_parent(displayio_tilegrid_t *self, bool hidden); -- cgit v1.2.3 From 3ab6a2343426e1b42141916a74c0c422dbd34828 Mon Sep 17 00:00:00 2001 From: Matthew Newberg Date: Wed, 4 Sep 2019 20:42:24 -0400 Subject: Removed unused return value in displayio_colorconverter_convert --- shared-module/displayio/ColorConverter.c | 11 +++++------ shared-module/displayio/ColorConverter.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index cf93e71b7..304d13a01 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -121,7 +121,7 @@ void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *sel (*output_color) = output_pixel.pixel; } -bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { +void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { uint32_t pixel = input_pixel->pixel; if (colorspace->dither){ @@ -149,7 +149,7 @@ bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d if (colorspace->depth == 16) { output_color->pixel = displayio_colorconverter_compute_rgb565(pixel); output_color->opaque = true; - return true; + return; } else if (colorspace->tricolor) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); output_color->pixel = luma >> (8 - colorspace->depth); @@ -158,19 +158,18 @@ bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d output_color->pixel = 0; } output_color->opaque = true; - return true; + return; } uint8_t pixel_hue = displayio_colorconverter_compute_hue(pixel); displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, &output_color->pixel); - return true; + return; } else if (colorspace->grayscale && colorspace->depth <= 8) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); output_color->pixel = luma >> (8 - colorspace->depth); output_color->opaque = true; - return true; + return; } output_color->opaque = false; - return false; } // Currently no refresh logic is needed for a ColorConverter. diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index 6bb52d720..3657df168 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -39,7 +39,7 @@ typedef struct { bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self); void displayio_colorconverter_finish_refresh(displayio_colorconverter_t *self); -bool displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color); +void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color); uint32_t displayio_colorconverter_dither_noise_1 (uint32_t n); uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y); -- cgit v1.2.3 From 4604a69498d5f7ffadb4ebf46a064ea5e18164b6 Mon Sep 17 00:00:00 2001 From: Matthew Newberg Date: Thu, 5 Sep 2019 21:55:45 -0400 Subject: Move dither parameter to ColorConverter constructor and parameter --- shared-bindings/displayio/ColorConverter.c | 39 ++++++++++++++++++++++++++++-- shared-bindings/displayio/ColorConverter.h | 5 +++- shared-bindings/displayio/Display.c | 25 ------------------- shared-module/displayio/ColorConverter.c | 16 ++++++++++-- shared-module/displayio/ColorConverter.h | 1 + shared-module/displayio/Display.c | 8 ------ 6 files changed, 56 insertions(+), 38 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index d9524870d..8c48a670a 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -51,11 +51,18 @@ // TODO(tannewt): Add support for other color formats. //| STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 0, 0, false); + mp_arg_check_num(n_args, kw_args, 0, 1, false); displayio_colorconverter_t *self = m_new_obj(displayio_colorconverter_t); self->base.type = &displayio_colorconverter_type; - common_hal_displayio_colorconverter_construct(self); + + bool dither = false; + + if (n_args > 0) { + dither = mp_obj_is_true(pos_args[0]); + } + + common_hal_displayio_colorconverter_construct(self, dither); return MP_OBJ_FROM_PTR(self); } @@ -79,8 +86,35 @@ STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t } MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_convert_obj, displayio_colorconverter_obj_convert); +//| .. attribute:: dither +//| +//| True when the display is dithered +//| +STATIC mp_obj_t displayio_colorconverter_obj_get_dither(mp_obj_t self_in) { + displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_displayio_colorconverter_get_dither(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_colorconverter_get_dither_obj, displayio_colorconverter_obj_get_dither); + +STATIC mp_obj_t displayio_colorconverter_obj_set_dither(mp_obj_t self_in, mp_obj_t dither) { + displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_displayio_colorconverter_set_dither(self, mp_obj_is_true(dither)); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_set_dither_obj, displayio_colorconverter_obj_set_dither); + +const mp_obj_property_t displayio_colorconverter_dither_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_colorconverter_get_dither_obj, + (mp_obj_t)&displayio_colorconverter_set_dither_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) }, + { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_colorconverter_dither_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_colorconverter_locals_dict, displayio_colorconverter_locals_dict_table); @@ -90,3 +124,4 @@ const mp_obj_type_t displayio_colorconverter_type = { .make_new = displayio_colorconverter_make_new, .locals_dict = (mp_obj_dict_t*)&displayio_colorconverter_locals_dict, }; + diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index 24895500e..d550d81be 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -33,7 +33,10 @@ extern const mp_obj_type_t displayio_colorconverter_type; -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self); +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither); void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); +void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither); +bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 58d5e5123..5ce7b3581 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -346,31 +346,7 @@ const mp_obj_property_t displayio_display_auto_brightness_obj = { (mp_obj_t)&mp_const_none_obj}, }; -//| .. attribute:: dither -//| -//| True when the display is dithered -//| -STATIC mp_obj_t displayio_display_obj_get_dither(mp_obj_t self_in) { - displayio_display_obj_t *self = native_display(self_in); - return mp_obj_new_bool(common_hal_displayio_display_get_dither(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_dither_obj, displayio_display_obj_get_dither); - -STATIC mp_obj_t displayio_display_obj_set_dither(mp_obj_t self_in, mp_obj_t dither) { - displayio_display_obj_t *self = native_display(self_in); - - common_hal_displayio_display_set_dither(self, mp_obj_is_true(dither)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_set_dither_obj, displayio_display_obj_set_dither); - -const mp_obj_property_t displayio_display_dither_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_display_get_dither_obj, - (mp_obj_t)&displayio_display_set_dither_obj, - (mp_obj_t)&mp_const_none_obj}, -}; //| .. attribute:: width @@ -514,7 +490,6 @@ STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&displayio_display_brightness_obj) }, { MP_ROM_QSTR(MP_QSTR_auto_brightness), MP_ROM_PTR(&displayio_display_auto_brightness_obj) }, - { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_display_dither_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) }, diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 304d13a01..a5d7f0b05 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -39,7 +39,8 @@ uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y) { return displayio_colorconverter_dither_noise_1(x + y * 0xFFFF); } -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self) { +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither) { + self->dither = dither; } uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) { @@ -121,10 +122,18 @@ void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *sel (*output_color) = output_pixel.pixel; } +void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither) { + self->dither = dither; +} + +bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self) { + return self->dither; +} + void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { uint32_t pixel = input_pixel->pixel; - if (colorspace->dither){ + if (self->dither){ uint8_t randr = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y)); uint8_t randg = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x+33,input_pixel->tile_y)); uint8_t randb = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y+33)); @@ -172,6 +181,8 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d output_color->opaque = false; } + + // Currently no refresh logic is needed for a ColorConverter. bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self) { return false; @@ -179,3 +190,4 @@ bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self) { void displayio_colorconverter_finish_refresh(displayio_colorconverter_t *self) { } + diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index 3657df168..10b1604a4 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -35,6 +35,7 @@ typedef struct { mp_obj_base_t base; + bool dither; } displayio_colorconverter_t; bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 03185dffc..f210a80c3 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -150,14 +150,6 @@ void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* s self->auto_brightness = auto_brightness; } -void common_hal_displayio_display_set_dither(displayio_display_obj_t* self, bool dither) { - displayio_display_core_set_dither(&self->core, dither); -} - -bool common_hal_displayio_display_get_dither(displayio_display_obj_t* self) { - return displayio_display_core_get_dither(&self->core); -} - mp_float_t common_hal_displayio_display_get_brightness(displayio_display_obj_t* self) { return self->current_brightness; } -- cgit v1.2.3 From 8768896d6b0ddb35568ad996781a33fd3a0df94f Mon Sep 17 00:00:00 2001 From: jepler Date: Sun, 8 Sep 2019 21:17:36 -0500 Subject: audiomixer: Supply constants in a way "-Og" optimization expects These arguments are constrained to be compile-time constants, a fact that gcc complains about under "-Og" optimization, but not in normal builds. Declare them as enumerated types --- shared-module/audiomixer/Mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index e0fb4fab8..a52489f85 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -262,8 +262,8 @@ static inline uint32_t mult16signed(uint32_t val, int32_t mul) { } #if (defined (__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) //Cortex-M4 w/FPU int32_t hi, lo; - int32_t bits = 16; // saturate to 16 bits - int32_t shift = 0; // shift is done automatically + enum { bits = 16 }; // saturate to 16 bits + enum { shift = 0 }; // shift is done automatically asm volatile("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul), "r" (val)); asm volatile("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul), "r" (val)); asm volatile("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); -- cgit v1.2.3 From 82427612d15ac85d0a34132ace7f8369dacd66ef Mon Sep 17 00:00:00 2001 From: jepler Date: Sun, 8 Sep 2019 21:58:36 -0500 Subject: WaveFile: Return GET_BUFFER_ERROR if wrong amount read Closes: #2128 --- shared-module/audiocore/WaveFile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/audiocore/WaveFile.c b/shared-module/audiocore/WaveFile.c index df5d4b61d..0248d42e2 100644 --- a/shared-module/audiocore/WaveFile.c +++ b/shared-module/audiocore/WaveFile.c @@ -216,7 +216,7 @@ audioio_get_buffer_result_t audioio_wavefile_get_buffer(audioio_wavefile_obj_t* } else { *buffer = self->buffer; } - if (f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read) != FR_OK) { + if (f_read(&self->file->fp, *buffer, num_bytes_to_load, &length_read) != FR_OK || length_read != num_bytes_to_load) { return GET_BUFFER_ERROR; } self->bytes_remaining -= length_read; -- cgit v1.2.3 From 676f7aa80821aa681030a5c43ce7e6c03b65241b Mon Sep 17 00:00:00 2001 From: jepler Date: Mon, 9 Sep 2019 20:04:08 -0500 Subject: os_listdir: This can be long-running, run background tasks While finding sources of clicks and buzzes in nrf i2sout, I identified this site as one which could be long running. Reproducer code was to play a 22.05kHz sample and repeatedly print `os.listdir('')` --- shared-module/os/__init__.c | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-module') diff --git a/shared-module/os/__init__.c b/shared-module/os/__init__.c index 313893d97..8060eec4f 100644 --- a/shared-module/os/__init__.c +++ b/shared-module/os/__init__.c @@ -128,6 +128,7 @@ mp_obj_t common_hal_os_listdir(const char* path) { while ((next = mp_iternext(iter_obj)) != MP_OBJ_STOP_ITERATION) { // next[0] is the filename. mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL)); + RUN_BACKGROUND_TASKS; } return dir_list; } -- cgit v1.2.3