Beispiel #1
0
mem_ptr_t *mem_heap_alloc(U8 size)
{
    U8 i;

    for (i=0; i<MAX_MEM_PTR_POOL; i++)
    {
        if (!mem_ptr_pool[i].alloc)
        {
            // found a free mem ptr. only mark it used if we can alloc memory to it.
            if (mmem_alloc(&mem_ptr_pool[i].mmem_ptr, size))
            {
                // memory successfully alloc'd. clear the block, mark this sucker used, and return it.
                memset(mem_ptr_pool[i].mmem_ptr.ptr, 0, sizeof(mem_ptr_t));
                mem_ptr_pool[i].alloc = true;
                return &mem_ptr_pool[i];
            }
            else
            {
                // no more memory. don't touch the ptr and return NULL.
                return NULL;
            }
        }
    }
    // couldn't find any free mem pointers. return NULL.
    return NULL;
}
Beispiel #2
0
struct mmem * bundle_create_bundle()
{
	int ret;
	struct bundle_slot_t *bs;
	struct bundle_t *bundle;

	bs = bundleslot_get_free();

	if( bs == NULL ) {
		LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Could not allocate slot for a bundle");
		return NULL;
	}

	ret = mmem_alloc(&bs->bundle, sizeof(struct bundle_t));
	if (!ret) {
		bundleslot_free(bs);
		LOG(LOGD_DTN, LOG_BUNDLE, LOGL_ERR, "Could not allocate memory for a bundle");
		return NULL;
	}

	bundle = (struct bundle_t *) MMEM_PTR(&bs->bundle);
	memset(bundle, 0, sizeof(struct bundle_t));
	bundle->rec_time = xTaskGetTickCount();
	bundle->num_blocks = 0;
	bundle->source_event_queue = dtn_process_get_event_queue();
	configASSERT(bundle->source_event_queue != NULL);

	/* Bundles are created as singleton and with normal priority */
	bundle->flags = BUNDLE_FLAG_SINGLETON | BUNDLE_PRIORITY_NORMAL;

	return &bs->bundle;
}
Beispiel #3
0
/**
 * Return values:
 *  1 = SUCCESS
 * -1 = Temporary error
 * -2 = Permanent error
 */
int convergence_layer_parse_dataframe(linkaddr_t * source, uint8_t * payload, uint8_t payload_length, uint8_t flags, uint8_t sequence_number, packetbuf_attr_t rssi)
{
	struct mmem * bundlemem = NULL;
	struct bundle_t * bundle = NULL;
	struct transmit_ticket_t * ticket = NULL;
	int n;
	int length;
#if CONVERGENCE_LAYER_SEGMENTATION
	int ret;
#endif /* CONVERGENCE_LAYER_SEGMENTATION */

	/* Note down the payload length */
	length = payload_length;

	if( flags != (CONVERGENCE_LAYER_FLAGS_FIRST | CONVERGENCE_LAYER_FLAGS_LAST ) ) {
#if CONVERGENCE_LAYER_SEGMENTATION
		/* We have a multipart bundle here */
		if( flags == CONVERGENCE_LAYER_FLAGS_FIRST ) {
			/* Beginning of a new bundle from a peer, remove old tickets */
			for( ticket = list_head(transmission_ticket_list);
				 ticket != NULL;
				 ticket = list_item_next(ticket) ) {
				if( linkaddr_cmp(&ticket->neighbour, source) && (ticket->flags & CONVERGENCE_LAYER_QUEUE_MULTIPART_RECV) ) {
					break;
				}
			}

			/* We found a ticket, remove it */
			if( ticket != NULL ) {
				LOG(LOGD_DTN, LOG_CL, LOGL_WRN, "Resynced to peer %u.%u, throwing away old buffer", source->u8[0], source->u8[1]);
				convergence_layer_free_transmit_ticket(ticket);
				ticket = NULL;
			}

			/* Allocate a new ticket for the incoming bundle */
			ticket = convergence_layer_get_transmit_ticket_priority(CONVERGENCE_LAYER_PRIORITY_HIGH);

			if( ticket == NULL ) {
				LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Unable to allocate multipart receive ticket");
				return -1;
			}

			/* Fill the fields of the ticket */
			linkaddr_copy(&ticket->neighbour, source);
			ticket->flags = CONVERGENCE_LAYER_QUEUE_MULTIPART_RECV;
			ticket->timestamp = clock_time();
			ticket->sequence_number = sequence_number;

			/* Now allocate some memory */
			ret = mmem_alloc(&ticket->buffer, length);

			if( ret < 1 ) {
				LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Unable to allocate multipart receive buffer of %u bytes", length);
				convergence_layer_free_transmit_ticket(ticket);
				ticket = NULL;
				return -1;
			}

			/* Copy the payload into the buffer */
			memcpy(MMEM_PTR(&ticket->buffer), payload, length);

			/* We are waiting for more segments, return now */
			return 1;
		} else {
			/* Either the middle of the end of a bundle, go look for the ticket */
			for( ticket = list_head(transmission_ticket_list);
				 ticket != NULL;
				 ticket = list_item_next(ticket) ) {
				if( linkaddr_cmp(&ticket->neighbour, source) && (ticket->flags & CONVERGENCE_LAYER_QUEUE_MULTIPART_RECV) ) {
					break;
				}
			}

			/* Cannot find a ticket, discard segment */
			if( ticket == NULL ) {
				LOG(LOGD_DTN, LOG_CL, LOGL_WRN, "Segment from peer %u.%u does not match any bundles in progress, discarding", source->u8[0], source->u8[1]);
				return -1;
			}

			if( sequence_number != (ticket->sequence_number + 1) % 4 ) {
				LOG(LOGD_DTN, LOG_CL, LOGL_WRN, "Segment from peer %u.%u is out of sequence. Recv %u, Exp %u", source->u8[0], source->u8[1], sequence_number, (ticket->sequence_number + 1) % 4);
				return 1;
			}

			/* Store the last received and valid sequence number */
			ticket->sequence_number = sequence_number;

			/* Note down the old length to know where to start */
			n = ticket->buffer.size;

			/* Allocate more memory */
			ret = mmem_realloc(&ticket->buffer, ticket->buffer.size + length);

			if( ret < 1 ) {
				LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Unable to re-allocate multipart receive buffer of %u bytes", ticket->buffer.size + length);
				convergence_layer_free_transmit_ticket(ticket);
				return -1;
			}

			/* Update timestamp to avoid the ticket from timing out */
			ticket->timestamp = clock_time();

			/* And append the payload */
			memcpy(((uint8_t *) MMEM_PTR(&ticket->buffer)) + n, payload, length);
		}

		if( flags & CONVERGENCE_LAYER_FLAGS_LAST ) {
			/* We have the last segment, change pointer so that the rest of the function works as planned */
			payload = (uint8_t *) MMEM_PTR(&ticket->buffer);
			length = ticket->buffer.size;
			LOG(LOGD_DTN, LOG_CL, LOGL_DBG, "%u byte multipart bundle received from %u.%u, parsing", length, source->u8[0], source->u8[1]);
		} else {
			/* We are waiting for more segments, return now */
			return 1;
		}
#else /* CONVERGENCE_LAYER_SEGMENTATION */
		/* We will never be able to parse that bundle, signal a permanent error */
		return -2;
#endif /* CONVERGENCE_LAYER_SEGMENTATION */

	}

	/* Allocate memory, parse the bundle and set reference counter to 1 */
	bundlemem = bundle_recover_bundle(payload, length);

	/* We do not need the ticket anymore if there was one, deallocate it */
	if( ticket != NULL ) {
		convergence_layer_free_transmit_ticket(ticket);
		ticket = NULL;
	}

	if( !bundlemem ) {
		LOG(LOGD_DTN, LOG_CL, LOGL_WRN, "Error recovering bundle");

		/* Possibly not enough memory -> temporary error */
		return -1;
	}

	bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
	if( !bundle ) {
		LOG(LOGD_DTN, LOG_CL, LOGL_WRN, "Invalid bundle pointer");
		bundle_decrement(bundlemem);

		/* Possibly not enough memory -> temporary error */
		return -1;
	}

	/* Check for bundle expiration */
	if( bundle_ageing_is_expired(bundlemem) ) {
		LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Bundle received from %u.%u with SeqNo %u is expired", source->u8[0], source->u8[1], sequence_number);
		bundle_decrement(bundlemem);

		/* Send permanent rejection */
		return -2;
	}

	/* Mark the bundle as "internal" */
	bundle->source_process = &agent_process;

	LOG(LOGD_DTN, LOG_CL, LOGL_DBG, "Bundle from ipn:%lu.%lu (to ipn:%lu.%lu) received from %u.%u with SeqNo %u", bundle->src_node, bundle->src_srv, bundle->dst_node, bundle->dst_srv, source->u8[0], source->u8[1], sequence_number);

	/* Store the node from which we received the bundle */
	linkaddr_copy(&bundle->msrc, source);

	/* Store the RSSI for this packet */
	bundle->rssi = rssi;

	/* Hand over the bundle to dispatching */
	n = dispatching_dispatch_bundle(bundlemem);
	bundlemem = NULL;

	if( n ) {
		/* Dispatching was successfull! */
		return 1;
	}

	/* Temporary error */
	return -1;
}
Beispiel #4
0
int convergence_layer_send_bundle(struct transmit_ticket_t * ticket)
{
	struct bundle_t *bundle = NULL;
	uint16_t length = 0;
	uint8_t * buffer = NULL;
	uint8_t buffer_length = 0;
#if CONVERGENCE_LAYER_SEGMENTATION
	int ret;
	int segments;
#endif /* CONVERGENCE_LAYER_SEGMENTATION */

	LOG(LOGD_DTN, LOG_CL, LOGL_DBG, "Sending bundle %lu to %u.%u with ticket %p", ticket->bundle_number, ticket->neighbour.u8[0], ticket->neighbour.u8[1], ticket);

	if( !(ticket->flags & CONVERGENCE_LAYER_QUEUE_MULTIPART) ) {
		/* Read the bundle from storage, if it is not in memory */
		if( ticket->bundle == NULL ) {
			ticket->bundle = BUNDLE_STORAGE.read_bundle(ticket->bundle_number);
			if( ticket->bundle == NULL ) {
				LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Unable to read bundle %lu", ticket->bundle_number);
				/* FIXME: Notify somebody */
				return -1;
			}
		}

		/* Get our bundle struct and check the pointer */
		bundle = (struct bundle_t *) MMEM_PTR(ticket->bundle);
		if( bundle == NULL ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Invalid bundle pointer for bundle %lu", ticket->bundle_number);
			bundle_decrement(ticket->bundle);
			ticket->bundle = NULL;
			return -1;
		}

		/* Check if bundle has expired */
		if( bundle_ageing_is_expired(ticket->bundle) ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_INF, "Bundle %lu has expired, not sending it", ticket->bundle_number);

			/* Bundle is expired */
			bundle_decrement(ticket->bundle);

			/* Tell storage to delete - it will take care of the rest */
			BUNDLE_STORAGE.del_bundle(ticket->bundle_number, REASON_LIFETIME_EXPIRED);

			return -1;
		}
	}

	/* Get the outgoing network buffer */
	buffer = dtn_network_get_buffer();
	if( buffer == NULL ) {
		bundle_decrement(ticket->bundle);
		ticket->bundle = NULL;
		return -1;
	}

	/* Get the buffer length */
	buffer_length = dtn_network_get_buffer_length();

#if CONVERGENCE_LAYER_SEGMENTATION
	/* We have to use a heuristic to estimate if the bundle will be a multipart bundle */
	if( ticket->bundle->size > CONVERGENCE_LAYER_MAX_LENGTH && !(ticket->flags & CONVERGENCE_LAYER_QUEUE_MULTIPART) ) {
		/* This is a bundle for multiple segments and we have our first look at it */
		ticket->flags |= CONVERGENCE_LAYER_QUEUE_MULTIPART;

		LOG(LOGD_DTN, LOG_CL, LOGL_DBG, "Encoding multipart bundle %lu", ticket->bundle_number);

		/* Now allocate a buffer to serialize the bundle
		 * The size is a rough estimation here and will be reallocated later on */
		ret = mmem_alloc(&ticket->buffer, ticket->bundle->size);

		if( ret < 1 ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Multipart bundle %lu could not be encoded, not enough memory for %u bytes", ticket->bundle_number, ticket->bundle->size);
			ticket->flags &= ~CONVERGENCE_LAYER_QUEUE_MULTIPART;
			return -1;
		}

		/* Encode the bundle into our temporary buffer */
		length = bundle_encode_bundle(ticket->bundle, (uint8_t *) MMEM_PTR(&ticket->buffer), ticket->buffer.size);

		if( length < 0 ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Multipart bundle %lu could not be encoded, error occured", ticket->bundle_number);
			mmem_free(&ticket->buffer);
			ticket->buffer.ptr = NULL;
			ticket->flags &= ~CONVERGENCE_LAYER_QUEUE_MULTIPART;
			return -1;
		}

		/* Decrease memory size to what is actually needed */
		ret = mmem_realloc(&ticket->buffer, length);

		if( ret < 1 ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Multipart bundle %lu could not be encoded, realloc failed", ticket->bundle_number);
			mmem_free(&ticket->buffer);
			ticket->buffer.ptr = NULL;
			ticket->flags &= ~CONVERGENCE_LAYER_QUEUE_MULTIPART;
			return -1;
		}

		/* We do not need the original bundle anymore */
		bundle_decrement(ticket->bundle);
		ticket->bundle = NULL;

		/* Initialize the state for this bundle */
		ticket->offset_sent = 0;
		ticket->offset_acked = 0;
		ticket->sequence_number = outgoing_sequence_number;

		/* Calculate the number of segments we will need */
		segments = (length + 0.5 * CONVERGENCE_LAYER_MAX_LENGTH) / CONVERGENCE_LAYER_MAX_LENGTH;

		/* And reserve the sequence number space for this bundle to allow for consequtive numbers */
		outgoing_sequence_number = (outgoing_sequence_number + segments) % 4;
	}

	/* Initialize the header field */
	buffer[0] = CONVERGENCE_LAYER_TYPE_DATA & CONVERGENCE_LAYER_MASK_TYPE;

	/* Check if this is a multipart bundle */
	if( ticket->flags & CONVERGENCE_LAYER_QUEUE_MULTIPART ) {
		/* Calculate the remaining length */
		length = ticket->buffer.size - ticket->offset_acked;

		/* Is it possible, that we send a single-part bundle here because the heuristic
		 * from above failed. So be it.
		 */
		if( length <= CONVERGENCE_LAYER_MAX_LENGTH && ticket->offset_acked == 0 ) {
			/* One bundle per segment, standard flags */
			buffer[0] |= (CONVERGENCE_LAYER_FLAGS_FIRST | CONVERGENCE_LAYER_FLAGS_LAST) & CONVERGENCE_LAYER_MASK_FLAGS;
		} else if( ticket->offset_acked == 0 ) {
			/* First segment of a bundle */
			buffer[0] |= CONVERGENCE_LAYER_FLAGS_FIRST & CONVERGENCE_LAYER_MASK_FLAGS;
		} else if( length <= CONVERGENCE_LAYER_MAX_LENGTH ) {
			/* Last segment of a bundle */
			buffer[0] |= CONVERGENCE_LAYER_FLAGS_LAST & CONVERGENCE_LAYER_MASK_FLAGS;
		} else if( length > CONVERGENCE_LAYER_MAX_LENGTH) {
			/* A segment in the middle of a bundle */
			buffer[0] &= ~CONVERGENCE_LAYER_MASK_FLAGS;
		}

		/* one byte for the CL header */
		length += 1;

		if( length > CONVERGENCE_LAYER_MAX_LENGTH ) {
			length = CONVERGENCE_LAYER_MAX_LENGTH;
		}

		if( length > buffer_length ) {
			length = buffer_length;
		}

		/* Copy the subset of the bundle into the buffer */
		memcpy(buffer + 1, ((uint8_t *) MMEM_PTR(&ticket->buffer)) + ticket->offset_acked, length - 1);

		/* Every segment so far has been acked */
		if( ticket->offset_sent == ticket->offset_acked ) {
			/* It is the first time that we are sending this segment */
			ticket->offset_sent += length - 1;

			/* Increment the sequence number for the new segment, except for the first segment */
			if( ticket->offset_sent != 0 ) {
				ticket->sequence_number = (ticket->sequence_number + 1) % 4;
			}
		}
	} else {
#endif /* CONVERGENCE_LAYER_SEGMENTATION */
		/* one byte for the CL header */
		length = 1;

		/* Initialize the header field */
		buffer[0] = CONVERGENCE_LAYER_TYPE_DATA & CONVERGENCE_LAYER_MASK_TYPE;

		/* One bundle per segment, standard flags */
		buffer[0] |= (CONVERGENCE_LAYER_FLAGS_FIRST | CONVERGENCE_LAYER_FLAGS_LAST) & CONVERGENCE_LAYER_MASK_FLAGS;

		/* Encode the bundle into the buffer */
		length += bundle_encode_bundle(ticket->bundle, buffer + 1, buffer_length - 1);

		/* Initialize the sequence number */
		ticket->sequence_number = outgoing_sequence_number;
		outgoing_sequence_number = (outgoing_sequence_number + 1) % 4;
#if CONVERGENCE_LAYER_SEGMENTATION
	}
#endif /* CONVERGENCE_LAYER_SEGMENTATION */

	/* Put the sequence number for this bundle into the outgoing header */
	buffer[0] |= (ticket->sequence_number << 2) & CONVERGENCE_LAYER_MASK_SEQNO;

	/* Flag the bundle as being in transit now */
	ticket->flags |= CONVERGENCE_LAYER_QUEUE_IN_TRANSIT;

	/* Now we are transmitting */
	convergence_layer_transmitting = 1;

	/* This neighbour is blocked, until we have received the App Layer ACK or NACK */
	convergence_layer_set_blocked(&ticket->neighbour);

	/* And send it out */
	dtn_network_send(&ticket->neighbour, length, (void *) ticket);

	return 1;
}
Beispiel #5
0
/**
 * \brief Adds a new bundle to the list of bundles
 * \param bundle_number bundle number of the bundle
 * \return >0 on success, <0 on error
 */
int routing_chain_new_bundle(uint32_t * bundle_number)
{
	struct routing_list_entry_t * n = NULL;
	struct routing_entry_t * entry = NULL;
	struct mmem * bundlemem = NULL;
	struct bundle_t * bundle = NULL;

	LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "agent announces bundle %lu", *bundle_number);

	// Let us see, if we know this bundle already
	for( n = list_head(routing_list);
		 n != NULL;
		 n = list_item_next(n) ) {

		entry = (struct routing_entry_t *) MMEM_PTR(&n->entry);

		if( entry->bundle_number == *bundle_number ) {
			LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "agent announces bundle %lu that is already known", *bundle_number);
			return -1;
		}
	}

	// Notify statistics
	statistics_bundle_incoming(1);

	// Now allocate new memory for the list entry
	n = memb_alloc(&routing_mem);
	if( n == NULL ) {
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "cannot allocate list entry for bundle, please increase BUNDLE_STORAGE_SIZE");
		return -1;
	}

	memset(n, 0, sizeof(struct routing_list_entry_t));

	// Now allocate new MMEM memory for the struct in the list
	if( !mmem_alloc(&n->entry, sizeof(struct routing_entry_t)) ) {
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "cannot allocate routing struct for bundle, MMEM is full");
		memb_free(&routing_mem, n);
		return -1;
	}

	// Now go and request the bundle from storage
	bundlemem = BUNDLE_STORAGE.read_bundle(*bundle_number);
	if( bundlemem == NULL ) {
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "unable to read bundle %lu", *bundle_number);
		mmem_free(&n->entry);
		memb_free(&routing_mem, n);
		return -1;
	}

	// Get our bundle struct and check the pointer
	bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
	if( bundle == NULL ) {
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "invalid bundle pointer for bundle %lu", *bundle_number);
		mmem_free(&n->entry);
		memb_free(&routing_mem, n);
		bundle_decrement(bundlemem);
		return -1;
	}

	// Now we have our entry
	// We have to get the pointer AFTER getting the bundle from storage, because accessing the
	// storage may change the MMEM structure and thus the pointers!
	entry = (struct routing_entry_t *) MMEM_PTR(&n->entry);
	memset(entry, 0, sizeof(struct routing_entry_t));

	// Nothing can go wrong anymore, add the (surrounding) struct to the list
	list_add(routing_list, n);

	/* Here we decide if a bundle is to be delivered locally and/or forwarded */
	if( bundle->dst_node == dtn_node_id ) {
		/* This bundle is for our node_id, deliver locally */
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle is for local");
		entry->flags |= ROUTING_FLAG_LOCAL;
	} else {
		/* This bundle is not (directly) for us and will be forwarded */
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle is for forward");
		entry->flags |= ROUTING_FLAG_FORWARD;
	}

	if( !(bundle->flags & BUNDLE_FLAG_SINGLETON) ) {
		/* Bundle is not Singleton, so forward it in any case */
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle is for forward");
		entry->flags |= ROUTING_FLAG_FORWARD;
	}

	if( registration_is_local(bundle->dst_srv, bundle->dst_node) && bundle->dst_node != dtn_node_id) {
		/* Bundle is for a local registration, so deliver it locally */
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle is for local and forward");
		entry->flags |= ROUTING_FLAG_LOCAL;
		entry->flags |= ROUTING_FLAG_FORWARD;
	}

	// Now copy the necessary attributes from the bundle
	entry->bundle_number = *bundle_number;
	bundle_get_attr(bundlemem, DEST_NODE, &entry->destination_node);
	bundle_get_attr(bundlemem, SRC_NODE, &entry->source_node);
	linkaddr_copy(&entry->received_from_node, &bundle->msrc);

	// Now that we have the bundle, we do not need the allocated memory anymore
	bundle_decrement(bundlemem);
	bundlemem = NULL;
	bundle = NULL;

	// Schedule to deliver and forward the bundle
	routing_chain_schedule_resubmission();

	// We do not have a failure here, so it must be a success
	return 1;
}
Beispiel #6
0
PROCESS_THREAD(test_process, ev, data)
{
    static int n;
    static int i;
    static int errors = 0;
    static struct etimer timer;
    static uint32_t time_start, time_stop;
    uint8_t buffer[128];
    int bundle_length;
    struct mmem * bundle_original = NULL;
    struct mmem * bundle_restored = NULL;
    struct mmem * bundle_spare = NULL;
    uint32_t bundle_number;
    uint32_t bundle_number_spare;

    PROCESS_BEGIN();

    PROCESS_PAUSE();

    profiling_init();
    profiling_start();

    // Wait again
    etimer_set(&timer, CLOCK_SECOND);
    PROCESS_WAIT_UNTIL(etimer_expired(&timer));

    /* Profile initialization separately */
    profiling_stop();
    watchdog_stop();
    profiling_report("init", 0);
    watchdog_start();
    printf("Init done, starting test using %s storage\n", BUNDLE_STORAGE.name);

    profiling_init();
    profiling_start();

    // Measure the current time
    time_start = test_precise_timestamp();

    for(i=0; i<=1; i++) {
        struct mmem bla;
        if( i > 0 ) {
            mmem_alloc(&bla, 1);
        }

        printf("Serializing and deserializing bundle...\n");
        if( my_create_bundle(0, &bundle_number, 3600) ) {
            printf("\tBundle created successfully \n");
        } else {
            printf("\tBundle could not be created \n");
            errors ++;
        }

        printf("Serializing and deserializing bundle...\n");
        if( my_create_bundle(1, &bundle_number_spare, 3600) ) {
            printf("\tSpare Bundle created successfully \n");
        } else {
            printf("\tSpare Bundle could not be created \n");
            errors ++;
        }

        bundle_original = BUNDLE_STORAGE.read_bundle(bundle_number);
        if( bundle_original == NULL ) {
            printf("VERIFY: MMEM ptr is invalid\n");
            errors ++;
        }

        bundle_spare = BUNDLE_STORAGE.read_bundle(bundle_number_spare);
        if( bundle_spare == NULL ) {
            printf("VERIFY: MMEM ptr is invalid\n");
            errors ++;
        }

        // Fake timing information in the bundle to make verify successful
        struct bundle_t * bundle_original_bundle = (struct bundle_t *) MMEM_PTR(bundle_original);
        bundle_original_bundle->aeb_value_ms = 54;
        bundle_original_bundle->rec_time = clock_time();

        // Serialize the bundle
        memset(buffer, 0, 128);
        bundle_length = bundle_encode_bundle(bundle_original, buffer, 128);
        if( bundle_length < 0 ) {
            printf("SERIALIZE: fail\n");
            errors ++;
        }

        n = my_static_compare(buffer, bundle_length);
        if( n > 0 ) {
            printf("COMPARE: fail\n");
            errors += n;
        }

        // Deserialize it
        bundle_restored = bundle_recover_bundle(buffer, bundle_length);
        if( bundle_restored == NULL ) {
            printf("DESERIALIZE: unable to recover\n");
            errors ++;
        }

        n = my_compare_bundles(bundle_original, bundle_restored);
        if( n == 0 ) {
            printf("\tBundle serialized and deserialized successfully\n");
        } else {
            printf("COMPARE: differences\n");
            errors ++;
        }

        // Dellocate memory
        bundle_decrement(bundle_restored);
        bundle_restored = NULL;

        bundle_decrement(bundle_original);
        bundle_original = NULL;

        bundle_decrement(bundle_spare);
        bundle_spare = NULL;

        memset(buffer, 0, 128);

        // Delete bundle from storage
        n = BUNDLE_STORAGE.del_bundle(bundle_number, REASON_DELIVERED);
        if( n ) {
            printf("\tBundle deleted successfully\n");
        } else {
            printf("\tBundle could not be deleted\n");
            errors++;
        }


        printf("Comparing static bundle...\n");
        if( my_create_bundle(0, &bundle_number, 3600) ) {
            printf("\tReference Bundle created successfully \n");
        } else {
            printf("\ttReference Bundle could not be created \n");
            errors ++;
        }

        bundle_original = BUNDLE_STORAGE.read_bundle(bundle_number);
        if( bundle_original == NULL ) {
            printf("VERIFY: MMEM ptr is invalid\n");
            errors ++;
        }

        // Deserialize it
        bundle_restored = bundle_recover_bundle(static_compare_bundle, sizeof(static_compare_bundle));
        if( bundle_restored == NULL ) {
            printf("DESERIALIZE: unable to recover static bundle\n");
            errors ++;
        }

        // Deserialize it one more time
        bundle_spare = bundle_recover_bundle(static_compare_bundle, sizeof(static_compare_bundle));
        if( bundle_spare == NULL ) {
            printf("DESERIALIZE: unable to recover static bundle\n");
            errors ++;
        }

        n = my_compare_bundles(bundle_original, bundle_restored);
        if( n == 0 ) {
            printf("\tStatic Bundle verified successfully\n");
        } else {
            printf("COMPARE: differences\n");
            errors ++;
        }

        n = my_compare_bundles(bundle_original, bundle_spare);
        if( n == 0 ) {
            printf("\tStatic Bundle verified successfully\n");
        } else {
            printf("COMPARE: differences\n");
            errors ++;
        }

        // Dellocate memory
        bundle_decrement(bundle_restored);
        bundle_restored = NULL;

        bundle_decrement(bundle_original);
        bundle_original = NULL;

        bundle_decrement(bundle_spare);
        bundle_spare = NULL;
    }

    time_stop = test_precise_timestamp();

    watchdog_stop();
    profiling_report("serializer", 0);

    TEST_REPORT("No of errors", errors, 1, "errors");
    TEST_REPORT("Duration", time_stop-time_start, CLOCK_SECOND, "s");

    if( errors > 0 ) {
        TEST_FAIL("More than 0 errors occured");
    } else {
        TEST_PASS();
    }

    PROCESS_END();
}