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

pybricks / pybricks-micropython / 9014798693

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

Pull #246

github

laurensvalk
pybricks.tools.HostBuffer: Unpack values.
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%)

20206426.09 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 <string.h>
9

10
#include <pbsys/command.h>
11

12
#include "py/mphal.h"
13
#include "py/objstr.h"
14

15
#include <pybricks/tools.h>
16

17
#include <pybricks/util_mp/pb_kwarg_helper.h>
18
#include <pybricks/util_mp/pb_obj_helper.h>
19
#include <pybricks/util_pb/pb_error.h>
20

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

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

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

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

NEW
48
STATIC mp_obj_t pb_type_hostbuffer_get_values(mp_obj_t self_in) {
×
49

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

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

64

NEW
65
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) {
×
66

NEW
67
    PB_PARSE_ARGS_CLASS(n_args, n_kw, args,
×
NEW
68
        PB_ARG_REQUIRED(format));
×
69

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

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

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

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

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

NEW
92
    return MP_OBJ_FROM_PTR(hostbuffer_instance);
×
93
}
94

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

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

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

118
#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