• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pybricks / pybricks-micropython / 9014696361

09 May 2024 08:38AM UTC coverage: 56.205% (-0.4%) from 56.563%
9014696361

Pull #246

github

web-flow
Merge 108d3152b into 79a0e010a
Pull Request #246: pybricks.tools: Add hostbuffer to receive IDE data

0 of 42 new or added lines in 3 files covered. (0.0%)

9 existing lines in 3 files now uncovered.

3750 of 6672 relevant lines covered (56.21%)

20206428.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pybricks/tools/pb_type_hostbuffer.c
1
// SPDX-License-Identifier: MIT
2
// Copyright (c) 2024 The Pybricks Authors
3

4
#include "py/mpconfig.h"
5

6
#if PYBRICKS_PY_TOOLS_HOSTBUFFER
7

8
#include <pbsys/command.h>
9

10
#include "py/mphal.h"
11
#include "py/objstr.h"
12

13
#include <pybricks/tools.h>
14

15
#include <pybricks/util_mp/pb_kwarg_helper.h>
16
#include <pybricks/util_mp/pb_obj_helper.h>
17
#include <pybricks/util_pb/pb_error.h>
18

19
typedef struct _pb_type_hostbuffer_obj_t {
20
    mp_obj_base_t base;
21
    mp_obj_t format;
22
    mp_obj_str_t bytes_obj;
23
    uint8_t buffer[];
24
} pb_type_hostbuffer_obj_t;
25

26
// pointer to dynamically allocated hostbuffer singleton for driver callback.
27
static pb_type_hostbuffer_obj_t *hostbuffer_instance;
28

NEW
29
static void handle_write_data_buffer(uint16_t offset, uint32_t size, const uint8_t *data) {
×
30
    // Can't write if buffer does not exist or isn't big enough.
NEW
31
    if (!hostbuffer_instance || offset + size > hostbuffer_instance->bytes_obj.len) {
×
32
        return;
33
    }
NEW
34
    memcpy(hostbuffer_instance->buffer + offset, data, size);
×
35
}
36

NEW
37
STATIC mp_obj_t pb_type_hostbuffer_get_bytes(mp_obj_t self_in) {
×
NEW
38
    pb_type_hostbuffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
×
39
    // Don't return internal bytes object but make a copy so the user bytes
40
    // object is constant as would be expected. Revisit: enable and return
41
    // a memoryview, especially if using large buffers.
NEW
42
    return mp_obj_new_bytes(self->bytes_obj.data, self->bytes_obj.len);
×
43
}
44
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pb_type_hostbuffer_get_bytes_obj, pb_type_hostbuffer_get_bytes);
45

NEW
46
STATIC mp_obj_t pb_type_hostbuffer_get_values(mp_obj_t self_in) {
×
47

48
    // One-off import for ustruct.unpack.
NEW
49
    static mp_obj_t ustruct_unpack = NULL;
×
NEW
50
    if (!ustruct_unpack) {
×
NEW
51
        ustruct_unpack = pb_function_import_helper(MP_QSTR_ustruct, MP_QSTR_unpack);
×
52
    }
53

54
    // Host (sender) is responsible for making sure that each individual
55
    // value remains valid, i.e. is written in a single chunk, since the
56
    // following may allocate, and thus be updated between unpacking values.
NEW
57
    pb_type_hostbuffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
×
NEW
58
    return mp_call_function_2(ustruct_unpack, self->format, MP_OBJ_FROM_PTR(&self->bytes_obj));
×
59
}
60
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pb_type_hostbuffer_get_values_obj, pb_type_hostbuffer_get_values);
61

62

NEW
63
STATIC mp_obj_t pb_type_hostbuffer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
×
64

NEW
65
    PB_PARSE_ARGS_CLASS(n_args, n_kw, args,
×
NEW
66
        PB_ARG_REQUIRED(format));
×
67

68
    // Use ustruct.calcsize to parse user format for size.
NEW
69
    mp_obj_t ustruct_calcsize = pb_function_import_helper(MP_QSTR_ustruct, MP_QSTR_calcsize);
×
NEW
70
    size_t size = mp_obj_get_int(mp_call_function_1(ustruct_calcsize, format_in));
×
71

72
    // Can only create one instance for now.
NEW
73
    if (hostbuffer_instance) {
×
NEW
74
        mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("host buffer already allocated"));
×
75
    }
76

77
    // Use finalizer so we can deactivate the data callback when buffer is garbage collected.
NEW
78
    hostbuffer_instance = m_new_obj_var_with_finaliser(pb_type_hostbuffer_obj_t, uint8_t, size);
×
NEW
79
    hostbuffer_instance->base.type = type;
×
NEW
80
    hostbuffer_instance->format = format_in;
×
81

82
    // Keep buffer in bytes object format for compatibility with unpack.
NEW
83
    hostbuffer_instance->bytes_obj.base.type = &mp_type_bytes;
×
NEW
84
    hostbuffer_instance->bytes_obj.len = size;
×
NEW
85
    hostbuffer_instance->bytes_obj.data = hostbuffer_instance->buffer;
×
86

87
    // Activate callback now that we have allocated the buffer.
NEW
88
    pbsys_command_set_write_program_data_buffer_callback(handle_write_data_buffer);
×
89

NEW
90
    return MP_OBJ_FROM_PTR(hostbuffer_instance);
×
91
}
92

NEW
93
mp_obj_t pb_type_hostbuffer_close(mp_obj_t stream) {
×
NEW
94
    if (hostbuffer_instance) {
×
NEW
95
        pbsys_command_set_write_program_data_buffer_callback(NULL);
×
NEW
96
        hostbuffer_instance = NULL;
×
97
    }
NEW
98
    return mp_const_none;
×
99
}
100
MP_DEFINE_CONST_FUN_OBJ_1(pb_type_hostbuffer_close_obj, pb_type_hostbuffer_close);
101

102
STATIC const mp_rom_map_elem_t pb_type_hostbuffer_locals_dict_table[] = {
103
    { MP_ROM_QSTR(MP_QSTR___del__),      MP_ROM_PTR(&pb_type_hostbuffer_close_obj) },
104
    { MP_ROM_QSTR(MP_QSTR_close),        MP_ROM_PTR(&pb_type_hostbuffer_close_obj) },
105
    { MP_ROM_QSTR(MP_QSTR_get_bytes),    MP_ROM_PTR(&pb_type_hostbuffer_get_bytes_obj) },
106
    { MP_ROM_QSTR(MP_QSTR_get_values),   MP_ROM_PTR(&pb_type_hostbuffer_get_values_obj) },
107
};
108
STATIC MP_DEFINE_CONST_DICT(pb_type_hostbuffer_locals_dict, pb_type_hostbuffer_locals_dict_table);
109

110
MP_DEFINE_CONST_OBJ_TYPE(pb_type_hostbuffer,
111
    MP_QSTR_HostBuffer,
112
    MP_TYPE_FLAG_NONE,
113
    make_new, pb_type_hostbuffer_make_new,
114
    locals_dict, &pb_type_hostbuffer_locals_dict);
115

116
#endif // PYBRICKS_PY_TOOLS_HOSTBUFFER
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc