static char* test_cbuffer_pop(void) { CircularBuffer* mybuf = cbuffer_new(); // put us at the end of the buffer mybuf->pos = IO_BUFFER_SIZE - 5; mybuf->tail = IO_BUFFER_SIZE - 5; uint32_t test_data[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cbuffer_append(mybuf, test_data, 11); Buffer* bucky = cbuffer_pop(mybuf, 5); mu_assert_eq("size", cbuffer_size(mybuf), 6); mu_assert_eq("content", memcmp(bucky->data, test_data, 5*sizeof(uint32_t)), 0); Buffer* badger = cbuffer_pop(mybuf, 6); mu_assert_eq("size2", cbuffer_size(mybuf), 0); mu_assert_eq("content2", memcmp(badger->data, test_data + 5, 6), 0); // if we pop an empty collection, we get nothing. Buffer* empty = cbuffer_pop(mybuf, 10); mu_assert_eq("size3", empty->size, 0); cbuffer_free(mybuf); buffer_free(bucky); buffer_free(badger); buffer_free(empty); return 0; }
static char* test_cbuffer_transfer_data(void) { CircularBuffer* src = cbuffer_new(); CircularBuffer* dst = cbuffer_new(); for (int i = 0; i < 200; ++i) { cbuffer_push_back(src, i); } mu_assert_eq("Src buffer size", cbuffer_size(src), 200); mu_assert_eq("Dst buffer size", cbuffer_size(dst), 0); // transfer data from src -> dst cbuffer_transfer_data(src, dst); mu_assert_eq("Src buffer size post transfer", cbuffer_size(src), 0); mu_assert_eq("Dst buffer size post transfer", cbuffer_size(dst), 200); // check content for (int i = 0; i < 200; ++i) { mu_assert_eq("Dst content", cbuffer_pop_front(dst), i); } cbuffer_free(src); cbuffer_free(dst); return 0; }
int ipbus_stream_state(const CircularBuffer* input_buffer, int* swapbytes) { if (!cbuffer_size(input_buffer)) { return IPBUS_ISTREAM_EMPTY; } uint32_t firstword = cbuffer_value_at_net(input_buffer, 0); //LOG_DEBUG("Got a word: %"PRIx32, firstword); // check if this is a packet header int is_pkt = ipbus_detect_packet_header(firstword); if (is_pkt) { // check if we want to update an endianness flag if (swapbytes != NULL) { if (is_pkt == IPBUS_ISTREAM_PACKET) *swapbytes = 0; if (is_pkt == IPBUS_ISTREAM_PACKET_SWP_ORD) *swapbytes = 1; } return is_pkt; } // Double check if it is reasonable transaction packet // header. We should never have the middle of a transaction // at the header of the buffer - we always wait for a // transaction to be in-buffer before reading it out. ipbus_transaction_t transaction = ipbus_decode_transaction_header( input_buffer, *swapbytes); if ((int)cbuffer_size(input_buffer) >= (transaction.data.size + 1)) { return IPBUS_ISTREAM_FULL_TRANS; } //LOG_DEBUG("Partial transaction size: %"PRIx32, cbuffer_size(input_buffer)); return IPBUS_ISTREAM_PARTIAL_TRANS; }
static char* test_cbuffer_append_wraps(void) { CircularBuffer* mybuf = cbuffer_new(); // put us at the end of the buffer mybuf->pos = IO_BUFFER_SIZE - 5; mybuf->tail = IO_BUFFER_SIZE - 5; uint32_t test_data[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cbuffer_append(mybuf, test_data, 11); mu_assert_eq("pos", mybuf->pos, IO_BUFFER_SIZE - 5); mu_assert_eq("size", cbuffer_size(mybuf), 11); mu_assert_eq("tail content", memcmp( &(mybuf->data[mybuf->pos]), test_data, 5 * sizeof(uint32_t)), 0); // make sure we aren't trashing the memory after the buffer. //mu_assert_eq("tail content sanity", mybuf->data[IO_BUFFER_SIZE-1], 4); mu_assert_eq("head content", memcmp( mybuf->data, test_data + 5, 6 * sizeof(uint32_t)), 0); uint32_t test_data2[3] = {11, 12, 13}; cbuffer_append(mybuf, test_data2, 3); mu_assert_eq("size", cbuffer_size(mybuf), 14); mu_assert_eq("content", memcmp(&(mybuf->data[6]), test_data2, 3), 0); cbuffer_free(mybuf); return 0; }
static char* test_ram2() { // -------------- // Setup // -------------- CircularBuffer* pc_input = cbuffer_new(); CircularBuffer* pc_output = cbuffer_new(); CircularBuffer* orsc_input = cbuffer_new(); CircularBuffer* orsc_output = cbuffer_new(); VMEStream *pc_stream = vmestream_initialize_heap(pc_input, pc_output, 2); VMEStream *orsc_stream = malloc(sizeof(VMEStream)); orsc_stream->input = orsc_input; orsc_stream->output = orsc_output; orsc_stream->local_send_size = pc_stream->remote_send_size; orsc_stream->local_recv_size = pc_stream->remote_recv_size; orsc_stream->remote_send_size = pc_stream->local_send_size; orsc_stream->remote_recv_size = pc_stream->local_recv_size; orsc_stream->recv_data = pc_stream->send_data; orsc_stream->send_data = pc_stream->recv_data; orsc_stream->MAXRAM = pc_stream->MAXRAM; cbuffer_push_back(pc_input, 0xDEADBEEF); cbuffer_push_back(orsc_input, 0xBEEFCAFE); vmestream_transfer_data(pc_stream); vmestream_transfer_data(orsc_stream); vmestream_transfer_data(pc_stream); mu_assert("Error: pc_input not empty", cbuffer_size(pc_input) == 0); mu_assert("Error: orsc_input not empty", cbuffer_size(orsc_input) == 0); mu_assert("Error: orsc_output.pop != DEADBEEF", cbuffer_pop_front(orsc_output)); mu_assert("Error: pc_output.pop != BEEFCAFE", cbuffer_pop_front(pc_output)); mu_assert("Error: pc_output not empty", cbuffer_size(pc_output) == 0); mu_assert("Error: orsc_output not empty", cbuffer_size(orsc_output) == 0); // -------------- // Tear-Down // -------------- vmestream_destroy_heap(pc_stream); free(orsc_stream); cbuffer_free(pc_input); cbuffer_free(orsc_input); cbuffer_free(pc_output); cbuffer_free(orsc_output); return 0; }
static char* test_cbuffer_size(void) { CircularBuffer* mybuf = cbuffer_new(); mybuf->pos = IO_BUFFER_SIZE - 5; mybuf->tail = IO_BUFFER_SIZE - 5; mu_assert_eq("size0", cbuffer_size(mybuf), 0); for (int i = 0; i < 15; ++i) { cbuffer_push_back(mybuf, i); mu_assert_eq("size", cbuffer_size(mybuf), i + 1); } cbuffer_free(mybuf); return 0; }
/** * Push less data to the buffers than we have RAM available */ static char *test_ram2() { // local application buffers CircularBuffer *tx1 = cbuffer_new(); CircularBuffer *rx1 = cbuffer_new(); CircularBuffer *tx2 = cbuffer_new(); CircularBuffer *rx2 = cbuffer_new(); VMEStream *test1 = vmestream_initialize(tx1, rx1, 2); VMEStream *test2 = malloc(sizeof(VMEStream)); test2->input = tx2; test2->output = rx2; test2->rx_size = test1->tx_size; test2->tx_size = test1->rx_size; test2->rx_data = test1->tx_data; test2->tx_data = test1->rx_data; test2->MAXRAM = test1->MAXRAM; // place only one word on the buffers cbuffer_push_back(tx1, 0xDEADBEEF); // put some output data on host #2 cbuffer_push_back(tx2, 0xBEEFCAFE); vmestream_transfer_data(test1); vmestream_transfer_data(test2); vmestream_transfer_data(test1); mu_assert("Error: tx1 not empty", 0 == cbuffer_size(tx1)); mu_assert("Error: tx2 not empty", 0 == cbuffer_size(tx2)); mu_assert("Error: 0xDEADBEEF != rx2.pop", 0xDEADBEEF == cbuffer_pop_front(rx2)); mu_assert("Error: 0xBEEFCAFE != rx1.pop", 0xBEEFCAFE == cbuffer_pop_front(rx1)); mu_assert("Error: rx2 not empty", 0 == cbuffer_size(rx2)); mu_assert("Error: rx1 not empty", 0 == cbuffer_size(rx1)); // free memory vmestream_destroy(test1); free(test2); cbuffer_free(tx1); cbuffer_free(rx1); cbuffer_free(tx2); cbuffer_free(rx2); return 0; }
int main() { xil_printf("Master SPI oRSC echo test\n"); // initialize stdout. init_platform(); tx_buffer = cbuffer_new(); rx_buffer = cbuffer_new(); vme_stream = vmestream_initialize_mem( rx_buffer, tx_buffer, (uint32_t*)ORSC_2_PC_SIZE, (uint32_t*)PC_2_ORSC_SIZE, (uint32_t*)ORSC_2_PC_DATA, (uint32_t*)PC_2_ORSC_DATA, VMERAMSIZE); //printf("Master SPI oRSC echo test\n"); while (1) { // transfer data vmestream_transfer_data(vme_stream); // now echo the data while (cbuffer_size(rx_buffer) && cbuffer_freespace(tx_buffer)) { cbuffer_push_back(tx_buffer, cbuffer_pop_front(rx_buffer)); } } return 0; }
// Test decoding + re-encoding a transaction stream static char* test_ipbus_decode_encode_transaction(void) { CircularBuffer* packet = cbuffer_new(); // a read request. uint32_t header = ipbus_transaction_header( 2, // protocol 0xACE, // transaction id 5, // number of words to read IPBUS_READ, IPBUS_INFO_REQUEST); uint32_t payload = 0xBEEFFACE; cbuffer_push_back_net(packet, header); cbuffer_push_back_net(packet, payload); ipbus_transaction_t decoded = ipbus_decode_transaction(packet, 0); CircularBuffer* encoded = cbuffer_new(); ipbus_encode_transaction(encoded, &decoded, 0); mu_assert_eq("encode-decode length", cbuffer_size(encoded), 2); mu_assert("encode-decode", memcmp(encoded->data, packet->data, 8)==0); return 0; }
static char* test_ipbus_decode_encode_write_transaction(void) { CircularBuffer* packet = cbuffer_new(); // a read request. uint32_t header = ipbus_transaction_header( 2, // protocol 0xACE, // transaction id 5, // number of words to write IPBUS_WRITE, IPBUS_INFO_REQUEST); uint32_t baseaddr = 0xBEEFFACE; cbuffer_push_back_net(packet, header); cbuffer_push_back_net(packet, baseaddr); for (size_t i = 0; i < 5; ++i) { cbuffer_push_back_net(packet, i); } ipbus_transaction_t decoded = ipbus_decode_transaction(packet, 0); CircularBuffer* encoded = cbuffer_new(); ipbus_encode_transaction(encoded, &decoded, 0); mu_assert_eq("encode-decode length", cbuffer_size(encoded), 1 + 1 + 1 * 5); mu_assert("encode-decode", memcmp(encoded->data, packet->data, 7*4)==0); return 0; }
static char * test_forwardingtransaction_handle_one_transaction(void) { // make two pipes to simulate the forwarding serial port. int txpipefd[2]; pipe(txpipefd); int rxpipefd[2]; pipe(rxpipefd); // make txpipe nonblocking, so we can check if it's empty. fcntl(txpipefd[0], F_SETFL, fcntl(txpipefd[0], F_GETFL) | O_NONBLOCK); initialize_fowarding_fds(txpipefd[1], rxpipefd[0]); CircularBuffer* input = cbuffer_new(); cbuffer_push_back_net(input, ipbus_transaction_header(2, 0xCAB, 1, IPBUS_RMW, IPBUS_INFO_REQUEST)); cbuffer_push_back_net(input, 0xBEEFCAFE); cbuffer_push_back_net(input, 0xDEAFBEEF); cbuffer_push_back_net(input, 0xFACEBEEF); // RMW expects 1+1 words back cbuffer_push_back_net(input, ipbus_transaction_header(2, 0xBAD, 5, IPBUS_READ, IPBUS_INFO_REQUEST)); cbuffer_push_back_net(input, 0xBEEFCAFE); // READ expects 1+5 words back // write some junk onto the receiving pipe so we can check // we are reading the correct amount of return bytes. uint32_t junkwords[8] = { 0xDEADBEEF, 0xBEEFCAFE, 0xFACEBEEF, 0x12345678, 0xDEADFACE, 0xBADEBEEF, 0x87654321, 0xABABABAB}; write(rxpipefd[1], junkwords, 8 * sizeof(uint32_t)); CircularBuffer* input_copy = cbuffer_copy(input); CircularBuffer* output = cbuffer_new(); int words_consumed = handle_transaction_stream(input, 0, output); // should eat both transactions mu_assert_eq("ate everything i should", words_consumed, 6); // Make sure it passed it along the TX pipe ByteBuffer outputbuf = bytebuffer_ctor(NULL, 10 * sizeof(uint32_t)); // should pass along only 6 words. read(txpipefd[0], outputbuf.buf, 10 * sizeof(uint32_t)); mu_assert("forwarded trans", memcmp(outputbuf.buf, input_copy->data, 6*sizeof(uint32_t)) == 0); // there should no more data on the pipe mu_assert_eq("output pipe empty", read(txpipefd[0], outputbuf.buf, sizeof(uint32_t)), -1); // we expect header word + 1 payload word to be read from a RMW, // 1 header + 5 data words from the READ mu_assert_eq("output size", cbuffer_size(output), 8); mu_assert_eq("output content header", cbuffer_value_at(output, 0), 0xDEADBEEF); mu_assert_eq("output content payload", cbuffer_value_at(output, 1), 0xBEEFCAFE); mu_assert_eq("output content header 2", cbuffer_value_at(output, 2), 0xFACEBEEF); mu_assert_eq("output content payload 2", cbuffer_value_at(output, 3), 0x12345678); return 0; }
static char* test_cbuffer_new(void) { CircularBuffer* mybuf = cbuffer_new(); mu_assert_eq("size", cbuffer_size(mybuf), 0); mu_assert_eq("pos", mybuf->pos, 0); mu_assert_eq("freespace", cbuffer_freespace(mybuf), IO_BUFFER_SIZE - 1); mu_assert_eq("init is zero", (mybuf->data[0]), 0); cbuffer_free(mybuf); return 0; }
static char* test_cbuffer_append(void) { CircularBuffer* mybuf = cbuffer_new(); uint32_t test_data[5] = {0, 1, 2, 3, 4}; cbuffer_append(mybuf, test_data, 5); mu_assert_eq("pos", mybuf->pos, 0); mu_assert_eq("size", cbuffer_size(mybuf), 5); mu_assert_eq("content", memcmp(mybuf->data, test_data, 5 * sizeof(uint32_t)), 0); uint32_t test_data2[3] = {6, 7, 8}; cbuffer_append(mybuf, test_data2, 3); mu_assert_eq("pos", mybuf->pos, 0); mu_assert_eq("size", cbuffer_size(mybuf), 8); mu_assert_eq("content2", memcmp(mybuf->data, test_data, 5 * sizeof(uint32_t)), 0); mu_assert_eq("content3", memcmp(&(mybuf->data[5]), test_data2, 3 * sizeof(uint32_t)), 0); cbuffer_free(mybuf); return 0; }
static char* test_spi_stream_construct_tx_packet(void) { uint32_t my_data[5] = {1, 2, 3, 4, 5}; CircularBuffer* mybuf = cbuffer_new(); cbuffer_append(mybuf, my_data, 5); uint32_t my_pkt_expected[10] = {0xBEEF, 5, 1, 2, 3, 4, 5, 0xDEADBEEF, 0xDEADBEEF, -1}; add_checksum(my_pkt_expected, 10); int checksum_err = -1; spi_stream_verify_packet(my_pkt_expected, 10, &checksum_err); mu_assert_eq("no cksum err", checksum_err, 0); uint32_t my_pkt[10]; spi_stream_construct_tx_packet(0xBEEF, my_pkt, 10, mybuf); // for (int i = 0; i < 10; ++i) { // printf("%i %lx %lx\n", i, my_pkt_expected[i], my_pkt[i]); // } mu_assert_eq("packet", memcmp(my_pkt_expected, my_pkt, 10 * sizeof(uint32_t)), 0); mu_assert_eq("consumed", cbuffer_size(mybuf), 0); // put more in the buffer than we can consume at once cbuffer_append(mybuf, my_data, 5); cbuffer_append(mybuf, my_data, 5); cbuffer_append(mybuf, my_data, 5); uint32_t my_pkt_expected_2[10] = {0xBEEF, 7, 1, 2, 3, 4, 5, 1, 2, -1}; add_checksum(my_pkt_expected_2, 10); spi_stream_verify_packet(my_pkt_expected_2, 10, &checksum_err); mu_assert_eq("no cksum err 2", checksum_err, 0); spi_stream_construct_tx_packet(0xBEEF, my_pkt, 10, mybuf); mu_assert_eq("packet", memcmp(my_pkt_expected_2, my_pkt, 10 * sizeof(uint32_t)), 0); mu_assert_eq("consumed", cbuffer_size(mybuf), 8); spi_stream_verify_packet(my_pkt, 10, &checksum_err); mu_assert_eq("no cksum actual", checksum_err, 0); return 0; }
static char* test_cbuffer_delete_front_wraps(void) { CircularBuffer* mybuf = cbuffer_new(); uint32_t test_data[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // put us at the end of the buffer mybuf->pos = IO_BUFFER_SIZE - 5; mybuf->tail = IO_BUFFER_SIZE - 5; cbuffer_append(mybuf, test_data, 11); mu_assert_eq("content", memcmp(&(mybuf->data[mybuf->pos]), test_data, 5 * sizeof(uint32_t)), 0); int deleted = cbuffer_deletefront(mybuf, 5); mu_assert_eq("deleted", deleted, 5); mu_assert_eq("pos", mybuf->pos, 0); mu_assert_eq("size", cbuffer_size(mybuf), 6); mu_assert_eq("item0", mybuf->data[mybuf->pos], 5); mu_assert_eq("item1", mybuf->data[mybuf->pos+1], 6); mu_assert_eq("item2", mybuf->data[mybuf->pos+2], 7); mu_assert_eq("remaining content in cbuffer", memcmp( &(mybuf->data[0]), test_data + 5, 6 * sizeof(uint32_t)), 0); Buffer* readout = buffer_new(NULL, 6); cbuffer_read(mybuf, readout->data, 6); mu_assert_eq("remaining content", memcmp( readout->data, (test_data + 5), 6 * sizeof(uint32_t)), 0); // if we ask to delete everything, just return what was actually deleted. int deleted_just_to_end = cbuffer_deletefront(mybuf, 100); mu_assert_eq("deleted just to end", deleted_just_to_end, 6); mu_assert_eq("pos2", mybuf->pos, 6); mu_assert_eq("size2", cbuffer_size(mybuf), 0); cbuffer_free(mybuf); buffer_free(readout); return 0; }
static char* test_cbuffer_freespace(void) { CircularBuffer* mybuf = cbuffer_new(); mybuf->tail = IO_BUFFER_SIZE - 5; mu_assert_eq("freespace", cbuffer_freespace(mybuf), 4); mu_assert_eq("size", cbuffer_size(mybuf), IO_BUFFER_SIZE - 5); for (int i = 1; i < 5; ++i) { cbuffer_push_back(mybuf, i); mu_assert_eq("freespace", cbuffer_freespace(mybuf), 4 - i); } cbuffer_free(mybuf); return 0; }
static char* test_cbuffer_fd_full(void) { // make sure we can stop reading if our read buffer is full // make pipes int pipefd[2]; pipe(pipefd); // make txpipe nonblocking, so we can check if it's empty. fcntl(pipefd[0], F_SETFL, fcntl(pipefd[0], F_GETFL) | O_NONBLOCK); int in = pipefd[1]; int out = pipefd[0]; CircularBuffer* frombuf = cbuffer_new(); for (int i = 0; i < 200; ++i) { cbuffer_push_back(frombuf, i); } mu_assert_eq("from size", cbuffer_size(frombuf), 200); CircularBuffer* tobuf = cbuffer_new(); tobuf->pos = IO_BUFFER_SIZE - 100; tobuf->tail = IO_BUFFER_SIZE - 100; ssize_t written = cbuffer_write_fd(frombuf, in, 200); mu_assert_eq("wrote to pipe", written, 200); mu_assert_eq("from size after", cbuffer_size(frombuf), 0); tobuf->tail += IO_BUFFER_SIZE - 100; mu_assert_eq("to freespace", cbuffer_freespace(tobuf), 99); ssize_t read = cbuffer_read_fd(tobuf, out, 200); ssize_t exp = 99; mu_assert_eq("read from pipe", (int)read, (int)exp); cbuffer_free(frombuf); cbuffer_free(tobuf); return 0; }
static char* test_cbuffer_fd_features(void) { // make pipes int pipefd[2]; pipe(pipefd); // make txpipe nonblocking, so we can check if it's empty. fcntl(pipefd[0], F_SETFL, fcntl(pipefd[0], F_GETFL) | O_NONBLOCK); int in = pipefd[1]; int out = pipefd[0]; CircularBuffer* frombuf = cbuffer_new(); for (int i = 0; i < 200; ++i) { cbuffer_push_back(frombuf, i); } mu_assert_eq("from size", cbuffer_size(frombuf), 200); CircularBuffer* tobuf = cbuffer_new(); tobuf->pos = IO_BUFFER_SIZE - 100; tobuf->tail = IO_BUFFER_SIZE - 100; ssize_t written = cbuffer_write_fd(frombuf, in, 200); mu_assert_eq("wrote to pipe", written, 200); mu_assert_eq("from size after", cbuffer_size(frombuf), 0); ssize_t read = cbuffer_read_fd(tobuf, out, 200); mu_assert_eq("read from pipe", read, 200); for (int i = 0; i < 200; ++i) { mu_assert_eq("fd closure value", cbuffer_value_at(tobuf, i), i); } cbuffer_free(frombuf); cbuffer_free(tobuf); return 0; }
void SendHandler(void *CallBackRef, unsigned int EventData) { // delete the bytes which were sent previously if (EventData % sizeof(uint32_t)) { LOG_DEBUG("ERROR: sent data not word aligned!!!\n"); } cbuffer_deletefront(tx_buffer, EventData / sizeof(uint32_t)); if (cbuffer_size(tx_buffer)) { unsigned int to_send = cbuffer_contiguous_data_size(tx_buffer) * sizeof(uint32_t); XUartLite_Send(&UartLite, (u8*)&(tx_buffer->data[tx_buffer->pos]), to_send); LOG_DEBUG("SendHandler _Send %x\n", to_send); currently_sending = 1; } else { LOG_DEBUG("SendHandler Idling\n"); currently_sending = 0; } LOG_DEBUG("SendHandler SENT INTR %x\n", EventData); }
static char* test_cbuffer_copy(void) { CircularBuffer* mybuf = cbuffer_new(); mu_assert_eq("size", cbuffer_size(mybuf), 0); mu_assert_eq("pos", mybuf->pos, 0); mu_assert_eq("tail", mybuf->tail, 0); for (uint32_t i = 0; i < IO_BUFFER_SIZE - 2; ++i) { cbuffer_push_back(mybuf, i); } mu_assert_eq("tail", mybuf->tail, IO_BUFFER_SIZE - 2); CircularBuffer* copy = cbuffer_copy(mybuf); mu_assert_eq("content", memcmp(mybuf->data, copy->data, IO_BUFFER_SIZE * sizeof(uint32_t)), 0); mu_assert_eq("pos copy", mybuf->pos, copy->pos); mu_assert_eq("tail copy", mybuf->tail, copy->tail); cbuffer_free(mybuf); cbuffer_free(copy); return 0; }
static char* test_cbuffer_push_back(void) { CircularBuffer* mybuf = cbuffer_new(); // put us at the end of the buffer mybuf->pos = IO_BUFFER_SIZE - 2; mybuf->tail = IO_BUFFER_SIZE - 2; cbuffer_push_back(mybuf, 0xDEADBEEF); cbuffer_push_back(mybuf, 0xBEEFFACE); cbuffer_push_back(mybuf, 0xDEADFACE); mu_assert_eq("size", cbuffer_size(mybuf), 3); mu_assert_eq("pos", mybuf->pos, IO_BUFFER_SIZE-2); mu_assert_eq("item0", mybuf->data[mybuf->pos], 0xDEADBEEF); mu_assert_eq("item1", mybuf->data[mybuf->pos + 1], 0xBEEFFACE); mu_assert_eq("item2", mybuf->data[0], 0xDEADFACE); cbuffer_free(mybuf); return 0; }
static char* test_cbuffer_pop_front(void) { CircularBuffer* mybuf = cbuffer_new(); // put us at the end of the buffer mybuf->pos = IO_BUFFER_SIZE - 5; mybuf->tail = IO_BUFFER_SIZE - 5; uint32_t test_data[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cbuffer_append(mybuf, test_data, 11); for (int i = 0; i < 11; i++) { mu_assert_eq("pre-pop size", cbuffer_size(mybuf), 11 - i); uint32_t value = cbuffer_pop_front(mybuf); mu_assert_eq("popped_content", (int)value, i); } // if we pop an empty collection, we get dead beef. uint32_t empty = cbuffer_pop_front(mybuf); mu_assert_eq("empty", empty, 0xDEADBEEF); cbuffer_free(mybuf); return 0; }
/* * Make sure cbuffer_fd_read handles the edge case where cbuffer->tail returns * to the front of buffer->data */ static char* test_cbuffer_fd_read_edge(void) { int pipefd[2]; pipe(pipefd); fcntl(pipefd[0], F_SETFL, fcntl(pipefd[0], F_GETFL) | O_NONBLOCK); int in = pipefd[1]; int out = pipefd[0]; CircularBuffer* mybuf = cbuffer_new(); // completely fill buffer while (cbuffer_freespace(mybuf) > 0) { mu_assert_eq("mybuf overflow", cbuffer_push_back(mybuf, 0xDEADBEEF), 0); } mu_assert_eq("mybuf still has free space", cbuffer_freespace(mybuf), 0); // clear a single space in the cbuffer // free space should be at the front of cbuffer->data cbuffer_deletefront(mybuf, 1); uint32_t inbuf[] = {0xCAFEBABE}; write(in, inbuf, sizeof(uint32_t)); // read a single word into the free slot in the buffer mu_assert_eq("Could not read data", cbuffer_read_fd(mybuf, out, 1), 1); // check the content of the cbuffer while (cbuffer_size(mybuf) > 1) { mu_assert_eq("Content should be 0xDEADBEEF", cbuffer_pop_front(mybuf), 0xDEADBEEF); } mu_assert_eq("Content should be 0xCAFEBABE", cbuffer_pop_front(mybuf), 0xCAFEBABE); cbuffer_free(mybuf); return 0; }
int main(void) { LOG_INFO("UART CTP FE echo test\n"); init_platform(); tx_buffer = cbuffer_new(); rx_buffer = cbuffer_new(); int Status; u16 DeviceId = UARTLITE_DEVICE_ID; /* * Initialize the UartLite driver so that it's ready to use. */ Status = XUartLite_Initialize(&UartLite, DeviceId); if (Status != XST_SUCCESS) { LOG_ERROR ("Error: could not initialize UART\n"); return XST_FAILURE; } XUartLite_ResetFifos(&UartLite); /* * Perform a self-test to ensure that the hardware was built correctly. */ Status = XUartLite_SelfTest(&UartLite); if (Status != XST_SUCCESS) { LOG_ERROR ("Error: self test failed\n"); return XST_FAILURE; } /* * Connect the UartLite to the interrupt subsystem such that interrupts can * occur. This function is application specific. */ Status = SetupInterruptSystem(&UartLite); if (Status != XST_SUCCESS) { LOG_ERROR ("Error: could not setup interrupts\n"); return XST_FAILURE; } /* * Setup the handlers for the UartLite that will be called from the * interrupt context when data has been sent and received, specify a * pointer to the UartLite driver instance as the callback reference so * that the handlers are able to access the instance data. */ XUartLite_SetSendHandler(&UartLite, SendHandler, &UartLite); XUartLite_SetRecvHandler(&UartLite, RecvHandler, &UartLite); /* * Enable the interrupt of the UartLite so that interrupts will occur. */ XUartLite_EnableInterrupt(&UartLite); // bootstrap the READ LOG_DEBUG("Bootstrapping READ\n"); XUartLite_Recv(&UartLite, (u8*)&rx_tmp_buffer, sizeof(uint32_t)); LOG_INFO("Starting loop\n"); /* LOG_DEBUG("Sending 'wtf!'\n"); currently_sending = 1; char help[4] = "wtf!"; unsigned int ret = XUartLite_Send(&UartLite, (u8*)help, 4); LOG_DEBUG("WTF send complete return: %x\n", ret); */ /* echo received data forever */ unsigned int heartbeat = 0; while (1) { if (heartbeat++ % (1 << 8)) { //LOG_DEBUG("bump %x\n", heartbeat); } while (cbuffer_size(rx_buffer) && cbuffer_freespace(tx_buffer)) { uint32_t data = cbuffer_pop_front(rx_buffer); //LOG_DEBUG("Echoing data word %x\n", data); cbuffer_push_back(tx_buffer, data); } if (!currently_sending && cbuffer_size(tx_buffer)) { LOG_DEBUG("\nREINT SEND\n"); currently_sending = 1; /* if (XUartLite_IsSending(&UartLite)) { LOG_DEBUG("UART STAT: sending\n"); } else { LOG_DEBUG("UART STAT: idle\n"); } */ unsigned int to_send = cbuffer_contiguous_data_size(tx_buffer) * sizeof(uint32_t); u8* output_ptr = (u8*)&(tx_buffer->data[tx_buffer->pos]); //LOG_DEBUG("REINIT %x\n", to_send); //LOG_DEBUG("SENDADDR %x\n", output_ptr); XUartLite_Send(&UartLite, output_ptr, to_send); } } }
int main(int argc, char *argv[]) { caught_termination = 0; if (signal(SIGINT, sig_handler) == SIG_ERR) { LOG_ERROR("Can't catch SIGINT"); } if (signal(SIGTERM, sig_handler) == SIG_ERR) { LOG_ERROR("Can't catch SIGTERM"); } if (argc < 3) { LOG_ERROR("Usage: %s /dev/input /dev/output", argv[0]); return 1; } char * inputdevice = argv[1]; char * outputdevice = argv[2]; // initialize mapped memory block membase_init(); LOG_INFO("serving memory @ %016" PRIxPTR " via %s-> ->%s", (uintptr_t)membase, inputdevice, outputdevice); int inputdevicefd = open(inputdevice, O_RDWR | O_NONBLOCK); // in general these are probably the same. int outputdevicefd = inputdevicefd; // but maybe not. if (strcmp(inputdevice, outputdevice) != 0) { outputdevicefd = open(outputdevice, O_RDWR | O_NONBLOCK); } Client client; client.inputstream = cbuffer_new(); client.outputstream = cbuffer_new(); client.inputfd = inputdevicefd; client.outputfd = outputdevicefd; client.byte2word = bytebuffer_ctor(NULL, 0); client.swapbytes = 0; while (1) { if (caught_termination) { break; } bytebuffer_read_fd( &(client.byte2word), client.inputfd, MAX_REQ_LEN); if (client.byte2word.bufsize > 0) { LOG_DEBUG("Processing %i bytes", client.byte2word.bufsize); // Data available! Process the request. CircularBuffer *clibuf = client.inputstream; ByteBuffer* byte2word = &(client.byte2word); size_t nwords = byte2word->bufsize / sizeof(uint32_t); int append_ret = cbuffer_append(clibuf, byte2word->buf, nwords); if (append_ret == 0) { bytebuffer_del_front(byte2word, nwords * sizeof(uint32_t)); } ipbus_process_input_stream(&client); // write out any response cbuffer_write_fd(client.outputstream, client.outputfd, cbuffer_size(client.outputstream)); } } if (inputdevicefd != outputdevicefd) { close(outputdevicefd); } close(inputdevicefd); membase_close(); LOG_INFO("goodbye!\n"); return 0; }
/* Returns number of free elements*/ uint64_t cbuffer_available(CircularBuffer *cb) { return (cbuffer_size(cb) - cbuffer_used(cb)); }
int main() { xil_printf("Master SPI oRSC echo test\n"); // initialize stdout. init_platform(); tx_buffer = cbuffer_new(); rx_buffer = cbuffer_new(); spi_stream = spi_stream_init( tx_buffer, rx_buffer, DoSpiTransfer, // callback which triggers a SPI transfer 0); int Status; XSpi_Config *ConfigPtr; /* Pointer to Configuration data */ /* * Initialize the SPI driver so that it is ready to use. */ ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID); if (ConfigPtr == NULL) { xil_printf ("Error: could not lookup SPI configuration\n"); return XST_DEVICE_NOT_FOUND; } Status = XSpi_CfgInitialize(&SpiInstance, ConfigPtr, ConfigPtr->BaseAddress); if (Status != XST_SUCCESS) { xil_printf("Error: could not initialize the SPI device\n"); return XST_FAILURE; } Status = XSpi_SelfTest(&SpiInstance); if (Status != XST_SUCCESS) { xil_printf("Error: The SPI self test failed.\n"); return XST_FAILURE; } /* * Connect the Spi device to the interrupt subsystem such that * interrupts can occur. This function is application specific. */ Status = SpiSetupIntrSystem(&IntcInstance, &SpiInstance, SPI_IRPT_INTR); if (Status != XST_SUCCESS) { xil_printf("Error: Could not setup interrupt system.\n"); return XST_FAILURE; } /* * Set the Spi device as a master. */ Status = XSpi_SetOptions(&SpiInstance, XSP_MASTER_OPTION); if (Status != XST_SUCCESS) { xil_printf("Error: Could not set as master\n"); return XST_FAILURE; } // Go! XSpi_Start(&SpiInstance); // Note: to disable interrupt, do: XIntc_Disconnect(&IntcInstance, // SPI_IRPT_INTR); u32 expected_rx = 0; u32 current_tx = 0; while (1) { // fill up the transmit buffer while (cbuffer_freespace(tx_buffer)) { cbuffer_push_back(tx_buffer, current_tx++); } // check to make sure the received buffer is what we expect while (cbuffer_size(rx_buffer)) { u32 front = cbuffer_value_at(rx_buffer, 0); if (front != expected_rx) { //xil_printf("Error: expected %lx, got %lx!\n", expected_rx, front); xil_printf("Error: data value\n"); } expected_rx++; cbuffer_deletefront(rx_buffer, 1); } } return 0; }
static char* test_ram1() { CircularBuffer* pc_input = cbuffer_new(); CircularBuffer* pc_output = cbuffer_new(); CircularBuffer* orsc_input = cbuffer_new(); CircularBuffer* orsc_output = cbuffer_new(); VMEStream *pc_stream = vmestream_initialize_heap(pc_input, pc_output, 1); VMEStream *orsc_stream = malloc(sizeof(VMEStream)); orsc_stream->input = orsc_input; orsc_stream->output = orsc_output; orsc_stream->local_send_size = pc_stream->remote_send_size; orsc_stream->local_recv_size = pc_stream->remote_recv_size; orsc_stream->remote_send_size = pc_stream->local_send_size; orsc_stream->remote_recv_size = pc_stream->local_recv_size; orsc_stream->recv_data = pc_stream->send_data; orsc_stream->send_data = pc_stream->recv_data; orsc_stream->MAXRAM = pc_stream->MAXRAM; for (uint32_t i = 0; i < 20; ++i) { cbuffer_push_back(pc_input, 0xDEADBEEF + i); cbuffer_push_back(orsc_input, 0xBEEFCAFE + i); } // initial transfer vmestream_transfer_data(pc_stream); // transfer data vmestream_transfer_data(orsc_stream); vmestream_transfer_data(pc_stream); mu_assert("Error: orsc_output.pop != DEADBEEF", cbuffer_pop_front(orsc_output) == 0xDEADBEEF); mu_assert("Error: pc_output.pop != BEEFCAFE", cbuffer_pop_front(pc_output) == 0xBEEFCAFE); // extra transfer is needed to reset the size registers // to zero to prepare for another transfer vmestream_transfer_data(orsc_stream); vmestream_transfer_data(pc_stream); // transfer data vmestream_transfer_data(orsc_stream); vmestream_transfer_data(pc_stream); mu_assert("Error: orsc_output.pop != DEADBEEF + 1", cbuffer_pop_front(orsc_output) == 0xDEADBEEF + 1); mu_assert("Error: pc_output.pop != BEEFCAFE + 1", cbuffer_pop_front(pc_output) == 0xBEEFCAFE + 1); /* printf("pc_output.size: %d\n", cbuffer_size(pc_output)); printf("orsc_output.size: %d\n", cbuffer_size(orsc_output)); printf("pc_input.size: %d\n", cbuffer_size(pc_input)); printf("orsc_input.size: %d\n", cbuffer_size(orsc_input)); */ mu_assert("Error: pc_output.size != 0", cbuffer_size(pc_output) == 0); mu_assert("Error: orsc_output.size != 0", cbuffer_size(orsc_output) == 0); mu_assert("Error: pc_input.size != 18", cbuffer_size(pc_input) == 18); mu_assert("Error: orsc_input.size != 18", cbuffer_size(orsc_input) == 18); // transfer on pc_stream 2x in a row. Nothing should happen. vmestream_transfer_data(pc_stream); mu_assert("Error: pc_output.size != 0", cbuffer_size(pc_output) == 0); mu_assert("Error: orsc_output.size != 0", cbuffer_size(orsc_output) == 0); mu_assert("Error: pc_input.size != 18", cbuffer_size(pc_input) == 18); mu_assert("Error: orsc_input.size != 18", cbuffer_size(orsc_input) == 18); // reset vmestream_transfer_data(orsc_stream); vmestream_transfer_data(pc_stream); vmestream_transfer_data(orsc_stream); mu_assert("Error: pc_output.size != 0", cbuffer_size(pc_output) == 0); mu_assert("Error: orsc_output.size != 1", cbuffer_size(orsc_output) == 1); mu_assert("Error: pc_input.size != 17", cbuffer_size(pc_input) == 17); mu_assert("Error: orsc_input.size != 17", cbuffer_size(orsc_input) == 17); vmestream_destroy_heap(pc_stream); free(orsc_stream); cbuffer_free(pc_input); cbuffer_free(orsc_input); cbuffer_free(pc_output); cbuffer_free(orsc_output); return 0; }
static char *test_ram1() { // local application buffers CircularBuffer *tx1 = cbuffer_new(); CircularBuffer *rx1 = cbuffer_new(); CircularBuffer *tx2 = cbuffer_new(); CircularBuffer *rx2 = cbuffer_new(); VMEStream *test1 = vmestream_initialize(tx1, rx1, 1); VMEStream *test2 = malloc(sizeof(VMEStream)); test2->input = tx2; test2->output = rx2; test2->rx_size = test1->tx_size; test2->tx_size = test1->rx_size; test2->rx_data = test1->tx_data; test2->tx_data = test1->rx_data; test2->MAXRAM = test1->MAXRAM; for (unsigned int i = 0; i < 20; ++i) { // put some output data on host #1 cbuffer_push_back(tx1, 0xDEADBEEF + i); // put some output data on host #2 cbuffer_push_back(tx2, 0xBEEFCAFE + i); } // do a transfer vmestream_transfer_data(test1); // step 1 vmestream_transfer_data(test2); // step 2 // host #2 has received data, since host #1 filled it's TX buffer in step 1 // and host #2 can read it out in step 2 mu_assert("Error: 0xDEADBEEF != rx2.pop", 0xDEADBEEF == cbuffer_pop_front(rx2)); vmestream_transfer_data(test1); // step 3 // now host #1 can read the data loaded by host #2 in step 2 mu_assert("Error: 0xBEEFCAFE != rx1.pop", 0xBEEFCAFE == cbuffer_pop_front(rx1)); // do another transfer vmestream_transfer_data(test2); vmestream_transfer_data(test1); mu_assert("Error: 0xBEEFCAFE+1 != rx1.pop", 0xBEEFCAFE + 1 == cbuffer_pop_front(rx1)); mu_assert("Error: 0xDEADBEEF+1 != rx2.pop", 0xDEADBEEF + 1 == cbuffer_pop_front(rx2)); // We have consumed all received data (via pop). There is a word of // data in limbo for host #1 mu_assert("Error: 0 != rx1.size", 0 == cbuffer_size(rx1)); mu_assert("Error: 0 != rx2.size", 0 == cbuffer_size(rx2)); mu_assert("Error: 17 != tx1.size", 17 == cbuffer_size(tx1)); mu_assert("Error: 18 != tx2.size", 18 == cbuffer_size(tx2)); // call transfer on #1 twice in a row. Since it's still waiting for // #2 to read the data, nothing happens. vmestream_transfer_data(test1); mu_assert("Error: 0 != rx1.size", 0 == cbuffer_size(rx1)); mu_assert("Error: 0 != rx2.size", 0 == cbuffer_size(rx2)); mu_assert("Error: 17 != tx1.size", 17 == cbuffer_size(tx1)); mu_assert("Error: 18 != tx2.size", 18 == cbuffer_size(tx2)); // #2 receives limbo data, puts one of it's words in limbo. vmestream_transfer_data(test2); mu_assert("Error: 0 != rx1.size", 0 == cbuffer_size(rx1)); mu_assert("Error: 1 != rx2.size", 1 == cbuffer_size(rx2)); mu_assert("Error: 17 != tx1.size", 17 == cbuffer_size(tx1)); mu_assert("Error: 17 != tx2.size", 17 == cbuffer_size(tx2)); // free memory vmestream_destroy(test1); free(test2); cbuffer_free(tx1); cbuffer_free(rx1); cbuffer_free(tx2); cbuffer_free(rx2); return 0; }
/** * Overload buffer test */ static char *test_buf() { // local application buffers CircularBuffer *tx1 = cbuffer_new(); CircularBuffer *rx1 = cbuffer_new(); CircularBuffer *tx2 = cbuffer_new(); CircularBuffer *rx2 = cbuffer_new(); VMEStream *test1 = vmestream_initialize(tx1, rx1, 32); VMEStream *test2 = malloc(sizeof(VMEStream)); test2->input = tx2; test2->output = rx2; test2->rx_size = test1->tx_size; test2->tx_size = test1->rx_size; test2->rx_data = test1->tx_data; test2->tx_data = test1->rx_data; test2->MAXRAM = test1->MAXRAM; cbuffer_push_back(rx2, 0xDEADBEEF); for (int i = 0; i < 510; i++) { cbuffer_push_back(rx2, 0xBEEFCAFE); } cbuffer_push_back(tx1, 0xBEEFCAFE + 1); cbuffer_push_back(tx1, 0xBEEFCAFE + 2); cbuffer_push_back(tx1, 0xBEEFCAFE + 3); cbuffer_push_back(tx1, 0xBEEFCAFE + 4); mu_assert("Error: rx2 should have no space left", cbuffer_freespace(rx2) == 0); // sanity check mu_assert_eq("Error: output size != 4", cbuffer_size(tx1), 4); // do several transfers vmestream_transfer_data(test1); vmestream_transfer_data(test2); vmestream_transfer_data(test1); vmestream_transfer_data(test2); // no data should have been transferred mu_assert_eq("Error: tx_size != 4", *(test1->tx_size), 4); mu_assert("Error: rx2.pop != 0xDEADBEEF", 0xDEADBEEF == cbuffer_pop_front(rx2)); cbuffer_pop_front(rx2); cbuffer_pop_front(rx2); // popping off rx2 should have freed 3 words, but not enough to transfer all // four vmestream_transfer_data(test1); vmestream_transfer_data(test2); mu_assert_eq("Error: tx_size != 4", *(test1->tx_size), 4); mu_assert("Errrr: rx2.pop not 0xBEEFCAFE", 0xBEEFCAFE == cbuffer_pop_front(rx2)); cbuffer_pop_front(rx2); // now there is enough room for all the limbo data to be transferred to rx2 vmestream_transfer_data(test1); vmestream_transfer_data(test2); mu_assert("Error: tx_size != 0", *(test1->tx_size) == 0); mu_assert("Error: tx1 not empty", 0 == cbuffer_size(tx1)); for (int i = 0; i < 4; ++i) { mu_assert_eq("Unexpected data transferred", cbuffer_value_at(rx2, cbuffer_size(rx2) - 4 + i), 0xBEEFCAFE + i + 1); } // free memory vmestream_destroy(test1); free(test2); cbuffer_free(tx1); cbuffer_free(rx1); cbuffer_free(tx2); cbuffer_free(rx2); return 0; }