/** \brief test: ** - ciaaLibs_circBufSpace ** - ciaaLibs_circBufRawSpace ** - ciaaLibs_circBufCount ** - ciaaLibs_circBufRawCount **/ void test_ciaaLibs_circBufSpaceAndCount(void) { ciaaLibs_CircBufType * cbuf; char * data = "hallo world 123456789012345678901234567890213456789012345678901234567890"; char to[100]; size_t ret; /* use linux malloc */ ciaaPOSIX_malloc_StubWithCallback(malloc); ciaaPOSIX_memcpy_StubWithCallback(memcpy); /* try to create a buffer but no mem is available */ cbuf = ciaaLibs_circBufNew(64); TEST_ASSERT_TRUE(cbuf != NULL); /* 63 bytes shall be free */ TEST_ASSERT_EQUAL_INT(63, ciaaLibs_circBufSpace(cbuf, cbuf->head)); TEST_ASSERT_EQUAL_INT(63, ciaaLibs_circBufRawSpace(cbuf, cbuf->head)); /* 0 bytes shall be occupied */ TEST_ASSERT_EQUAL_INT(0, ciaaLibs_circBufCount(cbuf, cbuf->tail)); TEST_ASSERT_EQUAL_INT(0, ciaaLibs_circBufRawCount(cbuf, cbuf->tail)); /* put 40 bytes */ TEST_ASSERT_TRUE(40 == ciaaLibs_circBufPut(cbuf, data, 40)); /* 23 bytes shall be free */ TEST_ASSERT_EQUAL_INT(23, ciaaLibs_circBufSpace(cbuf, cbuf->head)); TEST_ASSERT_EQUAL_INT(23, ciaaLibs_circBufRawSpace(cbuf, cbuf->head)); /* 40 bytes shall be occupied */ TEST_ASSERT_EQUAL_INT(40, ciaaLibs_circBufCount(cbuf, cbuf->tail)); TEST_ASSERT_EQUAL_INT(40, ciaaLibs_circBufRawCount(cbuf, cbuf->tail)); /* get 30 bytes */ ret = ciaaLibs_circBufGet(cbuf, to, 30); TEST_ASSERT_EQUAL_INT(30, ret); /* 53 bytes shall be free */ TEST_ASSERT_EQUAL_INT(53, ciaaLibs_circBufSpace(cbuf, cbuf->head)); TEST_ASSERT_EQUAL_INT(24, ciaaLibs_circBufRawSpace(cbuf, cbuf->head)); /* 10 bytes shall be occupied */ TEST_ASSERT_EQUAL_INT(10, ciaaLibs_circBufCount(cbuf, cbuf->tail)); TEST_ASSERT_EQUAL_INT(10, ciaaLibs_circBufRawCount(cbuf, cbuf->tail)); /* put 50 */ TEST_ASSERT_EQUAL_INT(50, ciaaLibs_circBufPut(cbuf, data, 50)); /* 3 bytes shall be free */ TEST_ASSERT_EQUAL_INT(3, ciaaLibs_circBufSpace(cbuf, cbuf->head)); TEST_ASSERT_EQUAL_INT(3, ciaaLibs_circBufRawSpace(cbuf, cbuf->head)); /* 60 bytes shall be occupied */ TEST_ASSERT_EQUAL_INT(60, ciaaLibs_circBufCount(cbuf, cbuf->tail)); TEST_ASSERT_EQUAL_INT(34, ciaaLibs_circBufRawCount(cbuf, cbuf->tail)); /* free memory */ free(cbuf); }
/** \brief print debuf information of a circular buffer ** ** Print into screen: free space, raw free space, ** count of occupied bytes, raw count of occupied bytes ** position of head and tail and the buffer content. ** **/ void ciaaLibs_circBufPrint(ciaaLibs_CircBufType * cbuf) { printf("Free: %2d RFree: %2d Count: %2d RCount: %2d\n", ciaaLibs_circBufSpace(cbuf, cbuf->head), ciaaLibs_circBufRawSpace(cbuf, cbuf->head), ciaaLibs_circBufCount(cbuf, cbuf->tail), ciaaLibs_circBufRawCount(cbuf, cbuf->tail)); printf(" 0123456789012345678901234567890123456789012345678901234567890123\n"); printf("Head: %2d Tail: %2d Val:%s\n\n", cbuf->head, cbuf->tail, cbuf->buf); }
extern void ciaaSerialDevices_rxIndication(ciaaDevices_deviceType const * const device, uint32_t const nbyte) { /* get serial device */ ciaaSerialDevices_deviceType * serialDevice = (ciaaSerialDevices_deviceType*) device->layer; ciaaLibs_CircBufType * cbuf = &serialDevice->rxBuf; uint32_t head = cbuf->head; uint32_t rawSpace = ciaaLibs_circBufRawSpace(cbuf, head); uint32_t space = ciaaLibs_circBufSpace(cbuf, head); uint32_t read = 0; TaskType taskID = serialDevice->blocked.taskID; read = serialDevice->device->read(device->loLayer, ciaaLibs_circBufWritePos(cbuf), rawSpace); /* if rawSpace is full but more space is avaialble */ if ((read == rawSpace) && (space > rawSpace)) { read += serialDevice->device->read( device->loLayer, &cbuf->buf[0], space - rawSpace); } else { if ((read == rawSpace) && (space <= rawSpace)) { /* data may be lost because not place on the receive buffer */ /* TODO */ } else { /* read less bytes than provided */ /* nothing to do */ } } /* update tail */ ciaaLibs_circBufUpdateTail(cbuf, read); /* if data has been read */ if ( (0 < read) && (255 != taskID) && (serialDevice->blocked.fct == (void*) ciaaSerialDevices_read ) ) { /* invalidate task id */ serialDevice->blocked.taskID = 255; /* TODO add macro */ /* reset blocked function */ serialDevice->blocked.fct = NULL; /* set task event */ #ifdef POSIXE SetEvent(taskID, POSIXE); #endif } }
extern int32_t ciaaSerialDevices_write(ciaaDevices_deviceType const * const device, uint8_t const * buf, uint32_t nbyte) { /* get serial device */ ciaaSerialDevices_deviceType * serialDevice = (ciaaSerialDevices_deviceType*) device->layer; int32_t ret = 0; int32_t total = 0; ciaaLibs_CircBufType * cbuf = &serialDevice->txBuf; int32_t head; uint32_t space; do { /* read head and space */ head = cbuf->head; space = ciaaLibs_circBufSpace(cbuf, head); /* put bytes in the queue */ ret = ciaaLibs_circBufPut(cbuf, buf, ciaaLibs_min(nbyte-total, space)); /* update total of written bytes */ total += ret; /* starts the transmission if not already ongoing */ serialDevice->device->ioctl( device->loLayer, ciaaPOSIX_IOCTL_STARTTX, NULL); /* if not all bytes could be stored in the buffer */ if (total < nbyte) { /* increment buffer */ buf += ret; /* set the task to sleep until some data have been send */ /* TODO improve this: https://github.com/ciaa/Firmware/issues/88 */ serialDevice->device->ioctl(device->loLayer, ciaaPOSIX_IOCTL_SET_ENABLE_TX_INTERRUPT, (void*)false); /* get task id and function for waking up the task later */ GetTaskID(&serialDevice->blocked.taskID); serialDevice->blocked.fct = (void*) ciaaSerialDevices_write; /* TODO improve this: https://github.com/ciaa/Firmware/issues/88 */ serialDevice->device->ioctl(device->loLayer, ciaaPOSIX_IOCTL_SET_ENABLE_TX_INTERRUPT, (void*)true); /* wait to write all data or for the txConfirmation */ #ifdef POSIXE WaitEvent(POSIXE); ClearEvent(POSIXE); #endif } } while (total < nbyte); return total; }
extern int32_t ciaaSerialDevices_ioctl(ciaaDevices_deviceType const * const device, int32_t request, void* param) { int32_t ret = 0; ciaaSerialDevices_deviceType * serialDevice = (ciaaSerialDevices_deviceType *) device->layer; ciaaLibs_CircBufType * cbuf; uint32_t tail, head; switch(request) { case ciaaPOSIX_IOCTL_GET_RX_COUNT: cbuf = &serialDevice->rxBuf; tail = cbuf->tail; *(uint32_t *)param = ciaaLibs_circBufCount(cbuf, tail); ret = 0; break; case ciaaPOSIX_IOCTL_GET_TX_SPACE: cbuf = &serialDevice->txBuf; head = cbuf->head; *(uint32_t *)param = ciaaLibs_circBufSpace(cbuf, head); ret = 0; break; case ciaaPOSIX_IOCTL_RXINDICATION: break; case ciaaPOSIX_IOCTL_SET_NONBLOCK_MODE: if((bool)(intptr_t)param == false) { /* Blocking mode */ serialDevice->flags &= ~ciaaSerialDevices_NONBLOCK_MODE; } else { /* NonBlocking Mode */ serialDevice->flags |= ciaaSerialDevices_NONBLOCK_MODE; } ret = 0; break; default: ret = serialDevice->device->ioctl(device->loLayer, request, param); break; } return ret; }
extern size_t ciaaLibs_circBufPut(ciaaLibs_CircBufType * cbuf, void const * data, size_t nbytes) { size_t ret = 0; size_t rawSpace; /* the head of the circular buffer may be changed, therefore it has to be * read only once */ size_t head = cbuf->head; /* check that is enough place */ if (ciaaLibs_circBufSpace(cbuf, head) >= nbytes) { rawSpace = ciaaLibs_circBufRawSpace(cbuf, head); /* check if wrapping is needed */ if (rawSpace >= nbytes) { ciaaPOSIX_memcpy(ciaaLibs_circBufWritePos(cbuf), data, nbytes); } else { ciaaPOSIX_memcpy((void*)(&cbuf->buf[cbuf->tail]), data, rawSpace); ciaaPOSIX_memcpy((void*)(&cbuf->buf[0]), (void*)((intptr_t)data + rawSpace), nbytes-rawSpace); } /* calculate new tail position */ ciaaLibs_circBufUpdateTail(cbuf, nbytes); /* set return value */ ret = nbytes; } return ret; } /* end ciaaLibs_circBufPut */