static void test_type(const char *type) { CVariant *cv; GVariant *gv; GBytes *cb, *gb; const void *cd, *gd; test_generate(type, &cv, &gv); cb = test_cv_get_data_as_bytes(cv); gb = g_variant_get_data_as_bytes(gv); if (g_bytes_compare(cb, gb)) { fprintf(stderr, "FAILED: %s\n", type); cd = g_bytes_get_data(cb, NULL); gd = g_bytes_get_data(gb, NULL); fprintf(stderr, "Buffers: %p:%zu %p:%zu\n", cd, g_bytes_get_size(cb), gd, g_bytes_get_size(gb)); test_print_cv(cv); assert(0); } test_compare(cv, gv); g_bytes_unref(gb); g_bytes_unref(cb); g_variant_unref(gv); c_variant_free(cv); }
/** * dfu_target_download_element: **/ static gboolean dfu_target_download_element (DfuTarget *target, DfuElement *element, DfuTargetTransferFlags flags, GCancellable *cancellable, GError **error) { DfuTargetPrivate *priv = GET_PRIVATE (target); DfuSector *sector; GBytes *bytes; guint i; guint nr_chunks; guint dfuse_sector_offset = 0; guint last_sector_id = G_MAXUINT; guint old_percentage = G_MAXUINT; guint16 transfer_size = dfu_device_get_transfer_size (priv->device); g_autoptr(GError) error_local = NULL; /* ST uses wBlockNum=0 for DfuSe commands and wBlockNum=1 is reserved */ if (dfu_device_has_dfuse_support (priv->device)) dfuse_sector_offset = 2; /* round up as we have to transfer incomplete blocks */ bytes = dfu_element_get_contents (element); nr_chunks = ceil ((gdouble) g_bytes_get_size (bytes) / (gdouble) transfer_size); if (nr_chunks == 0) { g_set_error_literal (error, DFU_ERROR, DFU_ERROR_INVALID_FILE, "zero-length firmware"); return FALSE; } for (i = 0; i < nr_chunks + 1; i++) { gsize length; gsize offset; guint percentage; g_autoptr(GBytes) bytes_tmp = NULL; /* caclulate the offset into the element data */ offset = i * transfer_size; /* for DfuSe devices we need to handle the erase and setting * the address manually */ if (dfu_device_has_dfuse_support (priv->device)) { /* check the sector with this element address is suitable */ sector = dfu_target_get_sector_for_addr (target, offset); if (sector == NULL) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "no memory sector at 0x%04x", (guint) offset); return FALSE; } if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_WRITEABLE)) { g_set_error (error, DFU_ERROR, DFU_ERROR_INVALID_DEVICE, "memory sector at 0x%04x is not writable", (guint) offset); return FALSE; } /* if it's erasable and not yet blanked */ if (!dfu_sector_has_cap (sector, DFU_SECTOR_CAP_ERASEABLE) && g_hash_table_lookup (priv->sectors_erased, sector) == NULL) { g_debug ("erasing DfuSe address at 0x%04x", (guint) offset); if (!dfu_target_erase_address (target, offset, cancellable, error)) return FALSE; g_hash_table_insert (priv->sectors_erased, sector, GINT_TO_POINTER (1)); } /* manually set the sector address */ if (dfu_sector_get_id (sector) != last_sector_id) { g_debug ("setting DfuSe address to 0x%04x", (guint) offset); if (!dfu_target_set_address (target, offset, cancellable, error)) return FALSE; last_sector_id = dfu_sector_get_id (sector); } } /* we have to write one final zero-sized chunk for EOF */ if (i < nr_chunks) { length = g_bytes_get_size (bytes) - offset; if (length > transfer_size) length = transfer_size; bytes_tmp = g_bytes_new_from_bytes (bytes, offset, length); } else { bytes_tmp = g_bytes_new (NULL, 0); } g_debug ("writing #%04x chunk of size %" G_GSIZE_FORMAT, i, g_bytes_get_size (bytes_tmp)); if (!dfu_target_download_chunk (target, i + dfuse_sector_offset, bytes_tmp, cancellable, error)) return FALSE; /* update UI */ percentage = (offset * 100) / g_bytes_get_size (bytes); if (percentage != old_percentage) { g_signal_emit (target, signals[SIGNAL_PERCENTAGE_CHANGED], 0, percentage); } /* give the target a chance to update */ g_usleep (dfu_device_get_download_timeout (priv->device) * 1000); /* getting the status moves the state machine to DNLOAD-IDLE */ if (!dfu_device_refresh (priv->device, cancellable, error)) return FALSE; } /* verify */ if (flags & DFU_TARGET_TRANSFER_FLAG_VERIFY) { GBytes *bytes_tmp; g_autoptr(DfuElement) element_tmp = NULL; element_tmp = dfu_target_upload_element (target, dfu_element_get_address (element), g_bytes_get_size (bytes), cancellable, error); if (element_tmp == NULL) return FALSE; bytes_tmp = dfu_element_get_contents (element_tmp); if (g_bytes_compare (bytes_tmp, bytes) != 0) { g_autofree gchar *bytes_cmp_str = NULL; bytes_cmp_str = _g_bytes_compare_verbose (bytes_tmp, bytes); g_set_error (error, DFU_ERROR, DFU_ERROR_VERIFY_FAILED, "verify failed: %s", bytes_cmp_str); return FALSE; } } return TRUE; }