// lb_register_characteristic_read_event [c]
lb_register_characteristic_read_event(lb_context lb_ctx,
                                      lb_bl_device* dev,
                                      const char* uuid,
                                      sd_bus_message_handler_t callback,
                                      void* userdata)
{
#ifdef DEBUG
    printf("Method Called: %s\n", __FUNCTION__);
#endif
    int r;
    sd_bus_error error = SD_BUS_ERROR_NULL;
    lb_ble_char* ble_char_new = NULL;
    char match[68];

    if (lb_ctx == NULL) {
        syslog(LOG_ERR, "%s: lb_ctx is null", __FUNCTION__);
        return -LB_ERROR_INVALID_CONTEXT;
    }

    if (dev == NULL) {
        syslog(LOG_ERR, "%s: bl_device is null", __FUNCTION__);
        return -LB_ERROR_INVALID_DEVICE;
    }

    if (uuid == NULL) {
        syslog(LOG_ERR, "%s: uuid is null", __FUNCTION__);
        return -LB_ERROR_INVALID_DEVICE;
    }

    if (callback == NULL) {
        syslog(LOG_ERR, "%s: callback is null", __FUNCTION__);
        return -LB_ERROR_INVALID_DEVICE;
    }

    r = lb_get_ble_characteristic_by_uuid(lb_ctx, dev, uuid, &ble_char_new);
    if (r < 0) {
        syslog(LOG_ERR, "%s: could find characteristic: %s", __FUNCTION__, uuid);
        sd_bus_error_free(&error);
        return -LB_ERROR_UNSPECIFIED;
    }

    r = sd_bus_call_method(lb_ctx->bus, BLUEZ_DEST, ble_char_new->char_path,
                           BLUEZ_GATT_CHARACTERISTICS, "StartNotify", &error, NULL, NULL);
    if (r < 0) {
        syslog(LOG_ERR, "%s: sd_bus_call_method StartNotify on device %s failed with error: %s",
               __FUNCTION__, ble_char_new->char_path, error.message);
        sd_bus_error_free(&error);
        return -LB_ERROR_SD_BUS_CALL_FAIL;
    }

    snprintf(match, 67, "path='%s'", ble_char_new->char_path);

    int current_index = event_arr_size;
    if (event_arr_size == 0 || events_matches_array == NULL) {
        events_matches_array = (event_matches_callbacks**) malloc(sizeof(event_matches_callbacks*));
        if (events_matches_array == NULL) {
            syslog(LOG_ERR, "%s: Error allocating memory for events_matches_array", __FUNCTION__);
            return -LB_ERROR_MEMEORY_ALLOCATION;
        }
        event_arr_size++;
    } else {
        event_arr_size++;
        events_matches_array =
        realloc(events_matches_array, event_arr_size * sizeof(event_matches_callbacks*));
        if (events_matches_array == NULL) {
            syslog(LOG_ERR, "%s: Error reallocating memory for events_matches_array", __FUNCTION__);
            return -LB_ERROR_MEMEORY_ALLOCATION;
        }
    }

    event_matches_callbacks* new_event_pair =
    (event_matches_callbacks*) malloc(sizeof(event_matches_callbacks));
    if (new_event_pair == NULL) {
        syslog(LOG_ERR, "%s: Error reallocating memory for events_matches_array", __FUNCTION__);
        return -LB_ERROR_MEMEORY_ALLOCATION;
    }
    new_event_pair->event = match;
    new_event_pair->callback = &callback;
    new_event_pair->userdata = userdata;
    events_matches_array[current_index] = new_event_pair;

    pthread_create(&event_thread, NULL, _run_event_loop, &(lb_ctx->bus));
    // wait for thread to start
    sleep(2);

    sd_bus_error_free(&error);
    return LB_SUCCESS;
}