// drop all pending requests for the given UID from the global list static void network_drop_pending_requests(uint32_t uid) { Node *pending_request_global_node = _pending_request_sentinel.next; Node *pending_request_global_node_next; PendingRequest *pending_request; char base58[BASE58_MAX_LENGTH]; int count = 0; while (pending_request_global_node != &_pending_request_sentinel) { pending_request = containerof(pending_request_global_node, PendingRequest, global_node); pending_request_global_node_next = pending_request_global_node->next; if (pending_request->header.uid == uid) { pending_request_remove_and_free(pending_request); ++count; } pending_request_global_node = pending_request_global_node_next; } if (count > 0) { log_warn("Dropped %d pending request(s) (uid: %s)", count, base58_encode(base58, uint32_from_le(uid))); } }
void client_send_red_brick_enumerate(Client *client, EnumerationType type) { EnumerateCallback enumerate_callback; uint32_t uid = red_usb_gadget_get_uid(); // always little endian memset(&enumerate_callback, 0, sizeof(enumerate_callback)); enumerate_callback.header.uid = uid; enumerate_callback.header.length = sizeof(enumerate_callback); enumerate_callback.header.function_id = CALLBACK_ENUMERATE; packet_header_set_sequence_number(&enumerate_callback.header, 0); packet_header_set_response_expected(&enumerate_callback.header, true); base58_encode(enumerate_callback.uid, uint32_from_le(uid)); enumerate_callback.connected_uid[0] = '0'; enumerate_callback.position = '0'; enumerate_callback.hardware_version[0] = 1; // FIXME enumerate_callback.hardware_version[1] = 0; enumerate_callback.hardware_version[2] = 0; enumerate_callback.firmware_version[0] = _redapid_version[0]; enumerate_callback.firmware_version[1] = _redapid_version[1]; enumerate_callback.firmware_version[2] = _redapid_version[2]; enumerate_callback.device_identifier = uint16_to_le(RED_BRICK_DEVICE_IDENTIFIER); enumerate_callback.enumeration_type = type; client_dispatch_response(client, NULL, (Packet *)&enumerate_callback, true, false); }
static void red_stack_spi_insert_position(REDStackSlave *slave) { if (_red_stack.packet_from_spi.header.function_id == CALLBACK_ENUMERATE || _red_stack.packet_from_spi.header.function_id == FUNCTION_GET_IDENTITY) { EnumerateCallback *enum_cb = (EnumerateCallback *)&_red_stack.packet_from_spi; if (enum_cb->position == '0') { enum_cb->position = '0' + slave->stack_address + 1; base58_encode(enum_cb->connected_uid, uint32_from_le(red_usb_gadget_get_uid())); } } }
/* * Base58check encode. */ static bool base58check_encode(char *str, size_t slen, const uint8_t *data, size_t dlen) { uint8_t res[32]; PN_sha256d(data, dlen, res); uint8_t tmp[dlen + 4]; memcpy(tmp, data, dlen); tmp[dlen+0] = res[0]; tmp[dlen+1] = res[1]; tmp[dlen+2] = res[2]; tmp[dlen+3] = res[3]; return base58_encode(str, slen, tmp, sizeof(tmp)); }
cstring *base58_encode_check(unsigned char addrtype, bool have_addrtype, const void *data, size_t data_len) { cstring *s = cstr_new_sz(data_len + 1 + 4); if (have_addrtype) cstr_append_c(s, addrtype); cstr_append_buf(s, data, data_len); unsigned char md32[4]; bu_Hash4(md32, s->str, s->len); cstr_append_buf(s, md32, 4); cstring *s_enc = base58_encode(s->str, s->len); cstr_free(s, true); return s_enc; }
static void test_encode(const char *hexstr, const char *enc) { size_t hs_len = strlen(hexstr) / 2; unsigned char *raw = calloc(1, hs_len); size_t out_len; bool rc = decode_hex(raw, hs_len, hexstr, &out_len); if (!rc) { fprintf(stderr, "raw %p, sizeof(raw) %lu, hexstr %p %s\n", raw, hs_len, hexstr, hexstr); assert(rc); } cstring *s = base58_encode(raw, out_len); if (strcmp(s->str, enc)) { fprintf(stderr, "base58 mismatch: '%s' vs expected '%s'\n", s->str, enc); assert(!strcmp(s->str, enc)); } free(raw); cstr_free(s, true); }
static void print_n_base58(const void *data, size_t len) { cstring *b58 = base58_encode(data, len); printf("%s", b58->str); cstr_free(b58, true); }
/* common dissector function for dissecting TFP payloads */ static void dissect_tfp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint byte_offset = 0; gint bit_offset = 48; guint8 hv_tfp_len; guint8 hv_tfp_fid; guint8 hv_tfp_seq; gchar tfp_uid_string[BASE58_MAX_STR_SIZE]; base58_encode(tvb_get_letohl(tvb, 0), &tfp_uid_string[0]); hv_tfp_len = tvb_get_guint8(tvb, byte_offset_len); hv_tfp_fid = tvb_get_guint8(tvb, byte_offset_fid); hv_tfp_seq = tvb_get_bits8(tvb, bit_offset, bit_count_tfp_seq); col_add_fstr(pinfo->cinfo, COL_INFO, "UID: %s, Len: %d, FID: %d, Seq: %d", &tfp_uid_string[0], hv_tfp_len, hv_tfp_fid, hv_tfp_seq); /* call for details */ if (tree) { proto_tree *tfp_tree; proto_item *ti; ti = proto_tree_add_protocol_format(tree, proto_tfp, tvb, 0, -1, "Tinkerforge Protocol, UID: %s, Len: %d, FID: %d, Seq: %d", &tfp_uid_string[0], hv_tfp_len, hv_tfp_fid, hv_tfp_seq); tfp_tree = proto_item_add_subtree(ti, ett_tfp); /* Use ...string_format_value() so we can show the complete generated string but specify */ /* the field length as being just the 4 bytes from which the string is generated. */ ti = proto_tree_add_string_format_value(tfp_tree, hf_tfp_uid, tvb, byte_offset, byte_count_tfp_uid, &tfp_uid_string[0], "%s", &tfp_uid_string[0]); PROTO_ITEM_SET_GENERATED(ti); proto_tree_add_item(tfp_tree, hf_tfp_uid_numeric, tvb, byte_offset, byte_count_tfp_uid, ENC_LITTLE_ENDIAN); byte_offset += byte_count_tfp_uid; proto_tree_add_item(tfp_tree, hf_tfp_len, tvb, byte_offset, byte_count_tfp_len, ENC_LITTLE_ENDIAN); byte_offset += byte_count_tfp_len; proto_tree_add_item(tfp_tree, hf_tfp_fid, tvb, byte_offset, byte_count_tfp_fid, ENC_LITTLE_ENDIAN); byte_offset += byte_count_tfp_fid; proto_tree_add_bits_item(tfp_tree, hf_tfp_seq, tvb, bit_offset, bit_count_tfp_seq, ENC_LITTLE_ENDIAN); bit_offset += bit_count_tfp_seq; proto_tree_add_bits_item(tfp_tree, hf_tfp_r, tvb, bit_offset, bit_count_tfp_r, ENC_LITTLE_ENDIAN); bit_offset += bit_count_tfp_r; proto_tree_add_bits_item(tfp_tree, hf_tfp_a, tvb, bit_offset, bit_count_tfp_a, ENC_LITTLE_ENDIAN); bit_offset += bit_count_tfp_a; proto_tree_add_bits_item(tfp_tree, hf_tfp_oo, tvb, bit_offset, bit_count_tfp_oo, ENC_LITTLE_ENDIAN); bit_offset += bit_count_tfp_oo; proto_tree_add_bits_item(tfp_tree, hf_tfp_e, tvb, bit_offset, bit_count_tfp_e, ENC_LITTLE_ENDIAN); bit_offset += bit_count_tfp_e; proto_tree_add_bits_item(tfp_tree, hf_tfp_future_use, tvb, bit_offset, bit_count_tfp_future_use, ENC_LITTLE_ENDIAN); /*bit_offset += bit_count_tfp_future_use;*/ if ((tvb_reported_length(tvb)) > 8) { byte_offset += byte_count_tfp_flags; proto_tree_add_item(tfp_tree, hf_tfp_payload, tvb, byte_offset, -1, ENC_NA); } } }
// If data should just be polled, set packet_send to NULL. // // If no packet is received from slave the length in packet_recv will be set to 0, // the exact reason for that is encoded in the return value. // // For the return value see RED_STACK_TRANSCEIVE_RESULT_* at the top of this file. static int red_stack_spi_transceive_message(REDStackPacket *packet_send, Packet *packet_recv, REDStackSlave *slave) { int retval = 0; uint8_t length, length_send; uint8_t checksum; int rc; uint8_t sequence_number_master = 0xFF; uint8_t sequence_number_slave = 0xFF; uint8_t tx[RED_STACK_SPI_PACKET_SIZE] = {0}; uint8_t rx[RED_STACK_SPI_PACKET_SIZE] = {0}; // We assume that we don't receive anything. If we receive a packet the // length will be overwritten again packet_recv->header.length = 0; // Preamble is always the same tx[RED_STACK_SPI_PREAMBLE] = RED_STACK_SPI_PREAMBLE_VALUE; if (packet_send == NULL) { // If packet_send is NULL // we send a message with empty payload (4 byte) tx[RED_STACK_SPI_LENGTH] = RED_STACK_SPI_PACKET_EMPTY_SIZE; retval = RED_STACK_TRANSCEIVE_RESULT_SEND_NONE; } else if (slave->status == RED_STACK_SLAVE_STATUS_AVAILABLE) { length = packet_send->packet.header.length; if (length > sizeof(Packet)) { retval |= RED_STACK_TRANSCEIVE_RESULT_SEND_ERROR; log_error("Send length is greater then allowed (actual: %d > maximum: %d)", length, (int)sizeof(Packet)); goto ret; } retval = RED_STACK_TRANSCEIVE_DATA_SEND; tx[RED_STACK_SPI_LENGTH] = length + RED_STACK_SPI_PACKET_EMPTY_SIZE; memcpy(tx+2, &packet_send->packet, length); } else { retval = RED_STACK_TRANSCEIVE_RESULT_SEND_ERROR; log_error("Slave with stack address %d is not present in stack", slave->stack_address); goto ret; } length = tx[RED_STACK_SPI_LENGTH]; // Set master and slave sequence number tx[RED_STACK_SPI_INFO(length)] = slave->sequence_number_master | slave->sequence_number_slave; // Calculate checksum tx[RED_STACK_SPI_CHECKSUM(length)] = red_stack_spi_calculate_pearson_hash(tx, length-1); struct spi_ioc_transfer spi_transfer = { .tx_buf = (unsigned long)&tx, .rx_buf = (unsigned long)&rx, .len = RED_STACK_SPI_PACKET_SIZE, }; red_stack_spi_select(slave); rc = ioctl(_red_stack_spi_fd, SPI_IOC_MESSAGE(1), &spi_transfer); red_stack_spi_deselect(slave); if (rc < 0) { // Overwrite current return status with error, // it seems ioctl itself didn't work. retval = RED_STACK_TRANSCEIVE_RESULT_SEND_ERROR | RED_STACK_TRANSCEIVE_RESULT_READ_ERROR; if(packet_send == NULL) { slave->next_packet_empty = true; } log_error("ioctl failed: %s (%d)", get_errno_name(errno), errno); goto ret; } length_send = rc; if (length_send != RED_STACK_SPI_PACKET_SIZE) { // Overwrite current return status with error, // it seems ioctl itself didn't work. retval = RED_STACK_TRANSCEIVE_RESULT_SEND_ERROR | RED_STACK_TRANSCEIVE_RESULT_READ_ERROR; if(packet_send == NULL) { slave->next_packet_empty = true; } log_error("ioctl has unexpected result (actual: %d != expected: %d)", length_send, RED_STACK_SPI_PACKET_SIZE); goto ret; } if (rx[RED_STACK_SPI_PREAMBLE] != RED_STACK_SPI_PREAMBLE_VALUE) { // Do not log by default, an "unproper preamble" is part of the protocol // if the slave is too busy to fill the DMA buffers fast enough // log_error("Received packet without proper preamble (actual: %d != expected: %d)", // rx[RED_STACK_SPI_PREAMBLE], RED_STACK_SPI_PREAMBLE_VALUE); retval = (retval & (~RED_STACK_TRANSCEIVE_RESULT_MASK_READ)) | RED_STACK_TRANSCEIVE_RESULT_READ_ERROR; if(packet_send == NULL) { slave->next_packet_empty = true; } goto ret; } // Check length length = rx[RED_STACK_SPI_LENGTH]; if ((length != RED_STACK_SPI_PACKET_EMPTY_SIZE) && ((length < (RED_STACK_SPI_PACKET_EMPTY_SIZE + sizeof(PacketHeader))) || (length > RED_STACK_SPI_PACKET_SIZE))) { log_error("Received packet with malformed length: %d", length); retval = (retval & (~RED_STACK_TRANSCEIVE_RESULT_MASK_READ)) | RED_STACK_TRANSCEIVE_RESULT_READ_ERROR; if(packet_send == NULL) { slave->next_packet_empty = true; } goto ret; } // Calculate and check checksum checksum = red_stack_spi_calculate_pearson_hash(rx, length-1); if (checksum != rx[RED_STACK_SPI_CHECKSUM(length)]) { log_error("Received packet with wrong checksum (actual: %x != expected: %x)", checksum, rx[RED_STACK_SPI_CHECKSUM(length)]); retval = (retval & (~RED_STACK_TRANSCEIVE_RESULT_MASK_READ)) | RED_STACK_TRANSCEIVE_RESULT_READ_ERROR; if(packet_send == NULL) { slave->next_packet_empty = true; } goto ret; } // If we send data and the master sequence number matches to the one // set in the packet we know that the slave received the packet! if ((packet_send != NULL) /*&& (packet_send->status == RED_STACK_PACKET_STATUS_SEQUENCE_NUMBER_SET)*/) { sequence_number_master = rx[RED_STACK_SPI_INFO(length)] & RED_STACK_SPI_INFO_SEQUENCE_MASTER_MASK; if (sequence_number_master == slave->sequence_number_master) { retval = (retval & (~RED_STACK_TRANSCEIVE_RESULT_MASK_SEND)) | RED_STACK_TRANSCEIVE_RESULT_SEND_OK; // Increase sequence number for next packet red_stack_increase_master_sequence_number(slave); } } else { // If we didn't send anything we can always increase the sequence number, // it doesn't matter if the slave actually received it. red_stack_increase_master_sequence_number(slave); } // If the slave sequence number matches we already processed this packet sequence_number_slave = rx[RED_STACK_SPI_INFO(length)] & RED_STACK_SPI_INFO_SEQUENCE_SLAVE_MASK; if (sequence_number_slave == slave->sequence_number_slave) { retval = (retval & (~RED_STACK_TRANSCEIVE_RESULT_MASK_READ)) | RED_STACK_TRANSCEIVE_RESULT_READ_NONE; } else { // Otherwise we save the new sequence number slave->sequence_number_slave = sequence_number_slave; if (length == RED_STACK_SPI_PACKET_EMPTY_SIZE) { // Do not log by default, will produce 2000 log entries per second // log_packet_debug("Received empty packet over SPI (w/ header)"); retval = (retval & (~RED_STACK_TRANSCEIVE_RESULT_MASK_READ)) | RED_STACK_TRANSCEIVE_RESULT_READ_NONE; } else { // Everything seems OK, we can copy to buffer memcpy(packet_recv, rx+2, length - RED_STACK_SPI_PACKET_EMPTY_SIZE); log_packet_debug("Received packet over SPI (%s)", packet_get_response_signature(packet_signature, packet_recv)); retval = (retval & (~RED_STACK_TRANSCEIVE_RESULT_MASK_READ)) | RED_STACK_TRANSCEIVE_RESULT_READ_OK; retval |= RED_STACK_TRANSCEIVE_DATA_RECEIVED; } } ret: return retval; } // Creates the "routing table", which is just the // array of REDStackSlave structures. static void red_stack_spi_create_routing_table(void) { char base58[BASE58_MAX_LENGTH]; int tries, ret, i; uint8_t stack_address = 0; uint8_t uid_counter = 0; log_debug("Starting to discover SPI stack slaves"); while (stack_address < RED_STACK_SPI_MAX_SLAVES) { REDStackSlave *slave = &_red_stack.slaves[stack_address]; Packet packet; StackEnumerateResponse *response; REDStackPacket red_stack_packet = { slave, {{ 0, // UID 0 sizeof(StackEnumerateRequest), FUNCTION_STACK_ENUMERATE, 0x08, // Return expected 0 }, {0}, {0}}, RED_STACK_PACKET_STATUS_ADDED, }; // We have to assume that the slave is available slave->status = RED_STACK_SLAVE_STATUS_AVAILABLE; // Send stack enumerate request for (tries = 0; tries < RED_STACK_SPI_ROUTING_TRIES; tries++) { ret = red_stack_spi_transceive_message(&red_stack_packet, &packet, slave); if ((ret & RED_STACK_TRANSCEIVE_RESULT_MASK_SEND) == RED_STACK_TRANSCEIVE_RESULT_SEND_OK) { break; } SLEEP_NS(0, RED_STACK_SPI_ROUTING_WAIT); // Give slave some more time } if (tries == RED_STACK_SPI_ROUTING_TRIES) { // Slave does not seem to be available, slave->status = RED_STACK_SLAVE_STATUS_ABSENT; // This means that there can't be any more slaves above // and we are actually done here already! break; } // Receive stack enumerate response for (tries = 0; tries < RED_STACK_SPI_ROUTING_TRIES; tries++) { // We first check if we already received an answer before we try again if ((ret & RED_STACK_TRANSCEIVE_RESULT_MASK_READ) == RED_STACK_TRANSCEIVE_RESULT_READ_OK) { break; } // Here we sleep before transceive so that there is some time // between the sending of stack enumerate and the receiving // of the answer SLEEP_NS(0, RED_STACK_SPI_ROUTING_WAIT); // Give slave some more time ret = red_stack_spi_transceive_message(NULL, &packet, slave); } if (tries == RED_STACK_SPI_ROUTING_TRIES) { // Slave does not seem to be available, slave->status = RED_STACK_SLAVE_STATUS_ABSENT; // This means that there can't be any more slaves above // and we are actually done here already! break; } response = (StackEnumerateResponse *)&packet; for (i = 0; i < PACKET_MAX_STACK_ENUMERATE_UIDS; i++) { if (response->uids[i] != 0) { uid_counter++; stack_add_recipient(&_red_stack.base, response->uids[i], stack_address); log_debug("Found UID number %d of slave %d with UID %s", i, stack_address, base58_encode(base58, uint32_from_le(response->uids[i]))); } else { break; } } stack_address++; } _red_stack.slave_num = stack_address; log_info("SPI stack slave discovery done. Found %d slave(s) with %d UID(s) in total", stack_address, uid_counter); }
/* creates a bitcoin address+private key from the SHA256 * hash of string. converts to base58 if base58 is 'true' * returns 1 if successful, 0 if not*/ int create_address_from_string(const unsigned char *string, unsigned char *address, unsigned char *priv_key, EC_GROUP *precompgroup, bool base58, bool debug) { u_int8_t * hash = malloc(SHA256_DIGEST_LENGTH); BIGNUM * n = BN_new(); //first we hash the string SHA256 (string, strlen(string), hash); //then we convert the hash to the BIGNUM n n = BN_bin2bn(hash, SHA256_DIGEST_LENGTH, n); BIGNUM * order = BN_new(); BIGNUM * nmodorder = BN_new(); BN_CTX *bnctx; bnctx = BN_CTX_new(); //then we create a new EC group with the curve secp256k1 EC_GROUP * pgroup; pgroup = EC_GROUP_new_by_curve_name(NID_secp256k1); if (!pgroup) { printf("ERROR: Couldn't get new group\n"); return 0; } //now we need to get the order of the group, and make sure that //the number we use for the private key is less than or equal to //the group order by using "nmodorder = n % order" EC_GROUP_get_order(pgroup, order, NULL); BN_mod(nmodorder, n, order, bnctx); if (BN_is_zero(nmodorder)) { printf("ERROR: SHA256(string) % order == 0. Pick another string.\n"); return 0; } if (debug) printf ("Secret number: %s\n", BN_bn2dec(nmodorder)); //now we create a new EC point, ecpoint, and place in it the secp256k1 //generator point multiplied by nmodorder. this newly created //point is the public key EC_POINT * ecpoint = EC_POINT_new(pgroup); if (!EC_POINT_mul(pgroup, ecpoint, nmodorder, NULL, NULL, NULL)) { printf("ERROR: Couldn't multiply the generator point with n\n"); return 0; } if (debug) { BIGNUM *x=NULL, *y=NULL; x=BN_new(); y=BN_new(); if (!EC_POINT_get_affine_coordinates_GFp(pgroup, ecpoint, x, y, NULL)) { printf("ERROR: Failed getting coordinates."); //don't fail on debug fail //return 0; } printf ("Public key coordinates. x: %s, y: %s\n", BN_bn2dec(x), BN_bn2dec(y)); BN_free(x); BN_free(y); } //then we need to convert the public key point to data //first we get the required size of the buffer in which the data is placed //by passing NULL as the buffer argument to EC_POINT_point2oct unsigned int bufsize = EC_POINT_point2oct (pgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); u_int8_t * buffer = malloc(bufsize); //then we place the data in the buffer int len = EC_POINT_point2oct (pgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buffer, bufsize, NULL); if (len == 0) { printf("ERROR: Couldn't convert point to octet string."); return 0; } if (debug) { printf("DER encoded public key: "); print_hex(buffer, len); } //next we need to hash the public key data. first with SHA256, then with RIPEMD160 SHA256(buffer, len, hash); if (debug) { printf("SHA256 hash of public key: "); print_hex(hash, SHA256_DIGEST_LENGTH); } u_int8_t * ripemd = malloc(RIPEMD160_DIGEST_LENGTH+1+4); RIPEMD160(hash, SHA256_DIGEST_LENGTH, ripemd); if (debug) { printf("RIPEMD160 hash of SHA256 hash: "); print_hex(ripemd, RIPEMD160_DIGEST_LENGTH); } if (base58 == true) { //here we add the version byte to the beginning of the public key and four checksum //bytes at the end prepare_for_address(ripemd, RIPEMD160_DIGEST_LENGTH, 0); if (debug) { printf("Address in hex with version byte and checksum: "); print_hex(ripemd, RIPEMD160_DIGEST_LENGTH+1+4); } //and we convert the resulting data to base58 base58_encode(ripemd, RIPEMD160_DIGEST_LENGTH+1+4, address); } else { memcpy(address, ripemd, RIPEMD160_DIGEST_LENGTH); } //now we need to convert the big number nmodorder (private key) to data int buflen = BN_num_bytes(nmodorder); u_int8_t * buf = malloc(buflen+1+4); int datalen; //nmodorder is converted to binary representation datalen = BN_bn2bin(nmodorder, buf); if (debug) { printf("Private key: "); print_hex(buf, datalen); } if (base58 == true) { //and we add version byte and four byte checksum to the data prepare_for_address(buf, datalen, 0x80); //and convert this to base58 base58_encode(buf, datalen+5, priv_key); } else { memcpy(priv_key, buf, datalen+5); } free(hash); free(buffer); free(ripemd); free(buf); BN_free(n); BN_free(order); BN_free(nmodorder); if (precompgroup == NULL) EC_GROUP_free(pgroup); EC_POINT_free(ecpoint); BN_CTX_free(bnctx); return 1; }
// New packet from BrickletStack is send into brickd event loop static void bricklet_stack_dispatch_from_spi(void *opaque) { BrickletStack *bricklet_stack = (BrickletStack*)opaque; int i; eventfd_t ev; Packet *packet; (void)opaque; // handle at most 5 queued responses at once to avoid blocking the event // loop for too long for (i = 0; i < 5; ++i) { if (eventfd_read(bricklet_stack->notification_event, &ev) < 0) { if (errno_would_block()) { return; // no queue responses left } log_error("Could not read from SPI notification event: %s (%d)", get_errno_name(errno), errno); return; } mutex_lock(&bricklet_stack->response_queue_mutex); packet = queue_peek(&bricklet_stack->response_queue); mutex_unlock(&bricklet_stack->response_queue_mutex); if (packet == NULL) { // eventfd indicates a response but queue is empty log_error("Response queue and notification event are out-of-sync"); return; } // Update routing table (this is necessary for Co-MCU Bricklets) if (packet->header.function_id == CALLBACK_ENUMERATE) { stack_add_recipient(&bricklet_stack->base, packet->header.uid, 0); } if ((packet->header.function_id == CALLBACK_ENUMERATE) || (packet->header.function_id == FUNCTION_GET_IDENTITY)) { EnumerateCallback *ec = (EnumerateCallback*)packet; // If the Bricklet is a HAT Brick (ID 111) or HAT Zero Brick (ID 112) // we update the connected_uid. if((ec->device_identifier == 111) || (ec->device_identifier == 112)) { *bricklet_stack->config.connected_uid = ec->header.uid; } // If the Bricklet is connected to an isolator we don't have to // update the position and the connected UID. this is already // done by the isolator itself. if(ec->position != 'Z' || ec->connected_uid[0] == '\0') { memcpy(ec->connected_uid, PACKET_NO_CONNECTED_UID_STR, PACKET_NO_CONNECTED_UID_STR_LENGTH); if((*bricklet_stack->config.connected_uid != 0) && (ec->device_identifier != 111) && (ec->device_identifier != 112)) { char base58[BASE58_MAX_LENGTH]; base58_encode(base58, uint32_from_le(*bricklet_stack->config.connected_uid)); strncpy(ec->connected_uid, base58, BASE58_MAX_LENGTH); } ec->position = 'a' + bricklet_stack->config.num; } } // Send message into brickd dispatcher network_dispatch_response(packet); bricklet_stack->data_seen = true; mutex_lock(&bricklet_stack->response_queue_mutex); queue_pop(&bricklet_stack->response_queue, NULL); mutex_unlock(&bricklet_stack->response_queue_mutex); } }
std::string CoinKey::to_str()const { std::string str = base58_encode(&m_data, sizeof(m_data)); return str; }