diff --git a/.github/actions/deps/external/action.yml b/.github/actions/deps/external/action.yml index faeb9100a8..f6d80318d6 100644 --- a/.github/actions/deps/external/action.yml +++ b/.github/actions/deps/external/action.yml @@ -25,7 +25,7 @@ runs: inputs.port != 'espressif' uses: carlosperate/arm-none-eabi-gcc-action@v1 with: - release: '12.3.Rel1' + release: '13.2.Rel1' # espressif - name: Get espressif toolchain diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index e8530dab05..6969ff220f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1018,6 +1018,15 @@ msgstr "" msgid "Failed to acquire mutex, err 0x%04x" msgstr "" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" +msgstr "" + +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" +msgstr "" + #: shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" msgstr "" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index 605c169cfc..3a69f7767a 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2023-10-29 05:03+0000\n" +"PO-Revision-Date: 2023-11-01 07:01+0000\n" "Last-Translator: Wellington Terumi Uemura \n" "Language-Team: \n" "Language: pt_BR\n" @@ -3042,7 +3042,7 @@ msgstr "dtype deve ser flutuante ou complexo" #: extmod/ulab/code/ndarray_operators.c msgid "dtype of int32 is not supported" -msgstr "" +msgstr "dtype de int32 não é suportado" #: py/objdeque.c msgid "empty" @@ -3919,7 +3919,7 @@ msgstr "operação não é compatível com o tipo informado" #: extmod/ulab/code/ndarray_operators.c msgid "operation not supported for the input types" -msgstr "" +msgstr "a operação não é suportada para os tipos de entrada" #: py/modbuiltins.c msgid "ord expects a character" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 6c793f9af6..f5c80e3c39 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: circuitpython-cn\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2023-10-16 23:54+0000\n" +"PO-Revision-Date: 2023-11-01 07:01+0000\n" "Last-Translator: hexthat \n" "Language-Team: Chinese Hanyu Pinyin\n" "Language: zh_Latn_pinyin\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.1\n" +"X-Generator: Weblate 5.2-dev\n" #: main.c msgid "" @@ -191,7 +191,7 @@ msgstr "%q chángdù bìxū >= %d" #: py/objmodule.c py/runtime.c msgid "%q moved from %q to %q" -msgstr "" +msgstr "%q cóng %q yídòngdào %q" #: py/argcheck.c msgid "%q must be %d" @@ -233,7 +233,7 @@ msgstr "" #: shared-bindings/warnings/__init__.c msgid "%q must be a subclass of %q" -msgstr "" +msgstr "%q bìxūshì %q de zǐlèi" #: ports/espressif/common-hal/analogbufio/BufferedIn.c msgid "%q must be array of type 'H'" @@ -272,7 +272,7 @@ msgstr "%q chāochū fànwéi" #: py/objmodule.c py/runtime.c msgid "%q renamed %q" -msgstr "" +msgstr "%q zhòngmìngmíngwéi %q" #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" @@ -309,7 +309,7 @@ msgstr "%q[%u] děngdài jìshù zhīwài de shūrù" #: py/runtime.c #, c-format msgid "%s" -msgstr "" +msgstr "%s" #: ports/espressif/common-hal/espidf/__init__.c #, c-format @@ -423,7 +423,7 @@ msgstr "'await' wèiyú hánshù zhīwài" #: py/compile.c msgid "'break'/'continue' outside loop" -msgstr "" +msgstr "'zhōngduàn'/'jìxù' wài xúnhuán" #: py/compile.c msgid "'data' requires at least 2 arguments" @@ -465,7 +465,7 @@ msgstr ", zài %q\n" #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid ".show(x) removed. Use .root_group = x" -msgstr "" +msgstr "show(x) yǐ shānchú. Shǐyòng .root_group = x" #: py/objcomplex.c msgid "0.0 to a complex power" @@ -2542,7 +2542,7 @@ msgstr "gètǐ hé xiǎoxíng cāngkù guǎnlǐjú yìchū" #: py/compile.c msgid "async for/with outside async function" -msgstr "" +msgstr "yòngyú / yǔ wàibù yìbù hánshù de yìbù" #: extmod/ulab/code/numpy/numerical.c msgid "attempt to get (arg)min/(arg)max of empty sequence" @@ -2554,7 +2554,7 @@ msgstr "chángshì huòqǔ kōng xùliè de argmin/ argmax" #: py/objstr.c msgid "attributes not supported" -msgstr "" +msgstr "bù zhīchí de shǔxìng" #: extmod/ulab/code/ulab_tools.c msgid "axis is out of bounds" @@ -2750,7 +2750,7 @@ msgstr "bùnéng yǐn hán de jiāng '%q' zhuǎnhuàn wèi 'bool'" #: py/runtime.c msgid "can't import name %q" -msgstr "" +msgstr "wúfǎ dǎorù míngchēng %q" #: py/emitnative.c msgid "can't load from '%q'" @@ -2804,11 +2804,11 @@ msgstr "wúfǎ cóng shǒudòng zìduàn guīgé qiēhuàn dào zìdòng zìduà #: py/objcomplex.c msgid "can't truncate-divide a complex number" -msgstr "" +msgstr "shùliàng fùzá" #: extmod/moductypes.c msgid "can't unambiguously get sizeof scalar" -msgstr "" +msgstr "Wúfǎ míngquè de huòdé biāoliàng de dàxiǎo" #: extmod/modasyncio.c msgid "can't wait" @@ -2900,7 +2900,7 @@ msgstr "yīn tè hé wū yīn tè de bǐ jiào" #: py/objcomplex.c msgid "complex divide by zero" -msgstr "" +msgstr "fùshù chúyǐ língdù" #: py/objfloat.c py/parsenum.c msgid "complex values not supported" @@ -3016,7 +3016,7 @@ msgstr "dtype bì xū shì fú diǎn xíng huò fù shù" #: extmod/ulab/code/ndarray_operators.c msgid "dtype of int32 is not supported" -msgstr "" +msgstr "bù zhīchí int32 de dtype" #: py/objdeque.c msgid "empty" @@ -3159,7 +3159,7 @@ msgstr "zìtǐ bìxū wèi 2048 zì jié" #: extmod/moddeflate.c msgid "format" -msgstr "" +msgstr "Géshì" #: py/objstr.c msgid "format requires a dict" @@ -3403,7 +3403,7 @@ msgstr "Jiàngé bìxū zài %s-%s fànwéi nèi" #: py/compile.c msgid "invalid arch" -msgstr "" +msgstr "wúxiàode cúndàng" #: shared-bindings/bitmaptools/__init__.c #, c-format @@ -3488,7 +3488,7 @@ msgstr "" #: py/argcheck.c msgid "keyword argument(s) not implemented - use normal args instead" -msgstr "" +msgstr "wèi shíxiàn guānjiànzì cānshù - gǎiyòng pǔtōng cānshù" #: py/emitinlinethumb.c py/emitinlinextensa.c msgid "label '%q' not defined" @@ -3586,7 +3586,7 @@ msgstr "jìyì tǐ fēnpèi shībài, duī bèi suǒdìng" #: py/objarray.c msgid "memoryview offset too large" -msgstr "" +msgstr "memoryview piānyíliàng guòdà" #: py/objarray.c msgid "memoryview: length is not a multiple of itemsize" @@ -3594,7 +3594,7 @@ msgstr "nèi cún shì tú: cháng dù bú shì xiàng mù huà de bèi shù" #: extmod/modtime.c msgid "mktime needs a tuple of length 8 or 9" -msgstr "" +msgstr "mktime xūyào cháng dùwéi 8 huò 9 de yuánzǔ" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "mode must be complete, or reduced" @@ -3642,7 +3642,7 @@ msgstr "míngchēng wèi dìngyì" #: py/persistentcode.c msgid "native code in .mpy unsupported" -msgstr "" +msgstr "bù zhīchí .mpy zhōngde běnjī dàimǎ" #: py/asmthumb.c msgid "native method too big" @@ -3887,7 +3887,7 @@ msgstr "gěi dìng lèixíng bù zhīchí gāi cāozuò" #: extmod/ulab/code/ndarray_operators.c msgid "operation not supported for the input types" -msgstr "" +msgstr "shūrù lèixíng bù zhīchí cāozuò" #: py/modbuiltins.c msgid "ord expects a character" @@ -4129,7 +4129,7 @@ msgstr "yuán wèi tú (source_bitmap) de zhí de shù mù (value_count) bì xū #: extmod/modre.c msgid "splitting with sub-captures" -msgstr "" +msgstr "shǐyòng zi bǔhuò jìnxíng chāifēn" #: py/objstr.c msgid "start/end indices" @@ -4145,7 +4145,7 @@ msgstr "bù zhīchí liú cāozuò" #: py/objarray.c py/objstr.c msgid "string argument without an encoding" -msgstr "" +msgstr "búdài biānmǎ de zìfúchuàn cānshù" #: py/objstrunicode.c msgid "string index out of range" @@ -4186,7 +4186,7 @@ msgstr "uctypes miáoshù fú zhōng de yǔfǎ cuòwù" #: extmod/modtime.c msgid "ticks interval overflow" -msgstr "" +msgstr "fēnshí jiàngé yìchū" #: ports/nrf/common-hal/watchdog/WatchDogTimer.c msgid "timeout duration exceeded the maximum supported value" @@ -4392,7 +4392,7 @@ msgstr "zhí fàn wéi wài de mù biāo" #: extmod/moddeflate.c msgid "wbits" -msgstr "" +msgstr "fànwéi" #: shared-bindings/is31fl3741/FrameBuffer.c msgid "width must be greater than zero" diff --git a/ports/espressif/common-hal/mdns/Server.c b/ports/espressif/common-hal/mdns/Server.c index 5511b8d683..72d33edbc8 100644 --- a/ports/espressif/common-hal/mdns/Server.c +++ b/ports/espressif/common-hal/mdns/Server.c @@ -208,10 +208,25 @@ mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *servic return MP_OBJ_FROM_PTR(tuple); } -void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port) { +void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port, const char *txt_records[], size_t num_txt_records) { if (mdns_service_exists(service_type, protocol, NULL)) { mdns_service_port_set(service_type, protocol, port); } else { + // TODO: Add support for TXT record + /* NOTE: The `mdns_txt_item_t *txt` argument of mdns_service_add uses a struct + * that splits out the TXT record into keys and values, though it seems little + * is done with those fields aside from concatenating them with an optional + * equals sign and calculating the total length of the concatenated string. + * + * There should be little issue with the underlying implementation to populate + * the mdns_txt_item_t struct with only a key containing exactly the desired TXT + * record. As long as the underlying implementation calculates the length of the + * key + NULL value correctly, it should work. + * + * Ref: RFC 6763, section 6.1: + * > The format of each constituent string within the DNS TXT record is a single + * > length byte, followed by 0-255 bytes of text data. + */ mdns_service_add(NULL, service_type, protocol, port, NULL, 0); } } diff --git a/ports/raspberrypi/common-hal/mdns/Server.c b/ports/raspberrypi/common-hal/mdns/Server.c index 2a66e170ef..a85638be2c 100644 --- a/ports/raspberrypi/common-hal/mdns/Server.c +++ b/ports/raspberrypi/common-hal/mdns/Server.c @@ -30,6 +30,7 @@ #include "py/runtime.h" #include "shared/runtime/interrupt_char.h" #include "shared-bindings/mdns/RemoteService.h" +#include "shared-bindings/mdns/Server.h" #include "shared-bindings/wifi/__init__.h" #include "supervisor/shared/tick.h" @@ -295,7 +296,27 @@ mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *servic return MP_OBJ_FROM_PTR(tuple); } -void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port) { +STATIC void srv_txt_cb(struct mdns_service *service, void *ptr) { + mdns_server_obj_t *self = ptr; + err_t res; + for (size_t i = 0; i < self->num_txt_records; i++) { + res = mdns_resp_add_service_txtitem(service, self->txt_records[i], strlen(self->txt_records[i])); + if (res != ERR_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Failed to add service TXT record")); + return; + } + } +} + +STATIC void assign_txt_records(mdns_server_obj_t *self, const char *txt_records[], size_t num_txt_records) { + size_t allowed_num_txt_records = MDNS_MAX_TXT_RECORDS < num_txt_records ? MDNS_MAX_TXT_RECORDS : num_txt_records; + self->num_txt_records = allowed_num_txt_records; + for (size_t i = 0; i < allowed_num_txt_records; i++) { + self->txt_records[i] = txt_records[i]; + } +} + +void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port, const char *txt_records[], size_t num_txt_records) { enum mdns_sd_proto proto = DNSSD_PROTO_UDP; if (strcmp(protocol, "_tcp") == 0) { proto = DNSSD_PROTO_TCP; @@ -313,7 +334,9 @@ void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const cha if (existing_slot < MDNS_MAX_SERVICES) { mdns_resp_del_service(NETIF_STA, existing_slot); } - int8_t slot = mdns_resp_add_service(NETIF_STA, self->instance_name, service_type, proto, port, NULL, NULL); + + assign_txt_records(self, txt_records, num_txt_records); + int8_t slot = mdns_resp_add_service(NETIF_STA, self->instance_name, service_type, proto, port, srv_txt_cb, self); if (slot < 0) { mp_raise_RuntimeError(MP_ERROR_TEXT("Out of MDNS service slots")); return; diff --git a/ports/raspberrypi/common-hal/mdns/Server.h b/ports/raspberrypi/common-hal/mdns/Server.h index a4dab8aa06..d49abccb60 100644 --- a/ports/raspberrypi/common-hal/mdns/Server.h +++ b/ports/raspberrypi/common-hal/mdns/Server.h @@ -30,12 +30,16 @@ #include "lwip/apps/mdns_opts.h" +#define MDNS_MAX_TXT_RECORDS 32 + typedef struct { mp_obj_base_t base; const char *hostname; const char *instance_name; char default_hostname[sizeof("cpy-XXXXXX")]; const char *service_type[MDNS_MAX_SERVICES]; + size_t num_txt_records; + const char *txt_records[MDNS_MAX_TXT_RECORDS]; // Track if this object owns access to the underlying MDNS service. bool inited; } mdns_server_obj_t; diff --git a/ports/stm/boards/thunderpack_v12/mpconfigboard.mk b/ports/stm/boards/thunderpack_v12/mpconfigboard.mk index 51d0429327..0fb63056cb 100644 --- a/ports/stm/boards/thunderpack_v12/mpconfigboard.mk +++ b/ports/stm/boards/thunderpack_v12/mpconfigboard.mk @@ -11,8 +11,10 @@ LONGINT_IMPL = NONE SPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = GD25Q16C +CIRCUITPY_AESIO = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_BLEIO_HCI = 0 +CIRCUITPY_BUSDEVICE = 0 CIRCUITPY_NVM = 1 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_ZLIB = 0 diff --git a/shared-bindings/mdns/Server.c b/shared-bindings/mdns/Server.c index a8d4325036..a8bf60ad42 100644 --- a/shared-bindings/mdns/Server.c +++ b/shared-bindings/mdns/Server.c @@ -27,7 +27,9 @@ #include +#include "py/obj.h" #include "py/objproperty.h" +#include "py/objstr.h" #include "py/runtime.h" #include "shared-bindings/mdns/__init__.h" #include "shared-bindings/mdns/Server.h" @@ -173,20 +175,26 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_find_obj, 1, _mdns_server_find); //| //| If web workflow is active, the port it uses can't also be used to advertise a service. //| +//| **Limitations**: Publishing up to 32 TXT records is only supported on the RP2040 Pico W board at +//| this time. +//| //| :param str service_type: The service type such as "_http" //| :param str protocol: The service protocol such as "_tcp" -//| :param int port: The port used by the service""" +//| :param int port: The port used by the service +//| :param Sequence[str] txt_records: An optional sequence of strings to serve as TXT records along with the service +//| """ //| ... //| STATIC mp_obj_t mdns_server_advertise_service(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mdns_server_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); - enum { ARG_service_type, ARG_protocol, ARG_port }; + enum { ARG_service_type, ARG_protocol, ARG_port, ARG_txt_records }; static const mp_arg_t allowed_args[] = { { MP_QSTR_service_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_protocol, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_port, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_txt_records, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -195,7 +203,21 @@ STATIC mp_obj_t mdns_server_advertise_service(mp_uint_t n_args, const mp_obj_t * const char *service_type = mp_obj_str_get_str(args[ARG_service_type].u_obj); const char *protocol = mp_obj_str_get_str(args[ARG_protocol].u_obj); - common_hal_mdns_server_advertise_service(self, service_type, protocol, args[ARG_port].u_int); + const mp_obj_t txt_records = args[ARG_txt_records].u_obj; + const size_t num_txt_records = txt_records == mp_const_none + ? 0 + : (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(txt_records)); + + const char *txt_records_array[num_txt_records]; + for (size_t i = 0; i < num_txt_records; i++) { + mp_obj_t txt_record = mp_obj_subscr(txt_records, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL); + if (!mp_obj_is_str_or_bytes(txt_record)) { + mp_raise_ValueError(MP_ERROR_TEXT("Failed to add service TXT record; non-string or bytes found in txt_records")); + } + txt_records_array[i] = mp_obj_str_get_str(txt_record); + } + + common_hal_mdns_server_advertise_service(self, service_type, protocol, args[ARG_port].u_int, txt_records_array, num_txt_records); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_advertise_service_obj, 1, mdns_server_advertise_service); diff --git a/shared-bindings/mdns/Server.h b/shared-bindings/mdns/Server.h index 351ab664b2..bb25f771eb 100644 --- a/shared-bindings/mdns/Server.h +++ b/shared-bindings/mdns/Server.h @@ -42,7 +42,18 @@ void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *ho const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self); void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name); mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_float_t timeout); -void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port); + +/** + * @brief Advertises service + * + * @param self + * @param service_type A string indicating the DNS-SD type of service being advertised (e.g., _http) + * @param protocol A string indicating the DNS-SD protocol of the service (e.g., _tcp or _udp) + * @param port The TCP or UDP port number of the service + * @param txt_records An array of strings representing TXT records to publish along with the service + * @param num_txt_records Number of records expected in txt_records + */ +void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port, const char *txt_records[], size_t num_txt_records); // For internal use. void mdns_server_construct(mdns_server_obj_t *self, bool workflow); diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index e2c1eee5f3..09c322eb23 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -355,7 +355,7 @@ bool supervisor_start_web_workflow(bool reload) { } } if (!common_hal_mdns_server_deinited(&mdns)) { - common_hal_mdns_server_advertise_service(&mdns, "_circuitpython", "_tcp", web_api_port); + common_hal_mdns_server_advertise_service(&mdns, "_circuitpython", "_tcp", web_api_port, NULL, 0); } #endif