int mpu_spi_get_reg(int fd, int reg, uint8_t* val) { int retVal; struct dspal_spi_ioctl_read_write read_write; retVal = mpu_spi_configure_speed(fd, MPU_SPI_FREQUENCY_1MHZ); if (retVal != 0) { LOG_ERR("mpu_spi_get_reg: error configuring speed %d", retVal); return retVal; } spiTxBuf[0] = reg | 0x80; //register high bit=1 for read read_write.read_buffer = spiRxBuf; read_write.read_buffer_length = 2; read_write.write_buffer = spiTxBuf; read_write.write_buffer_length = 2; retVal = ioctl(fd, SPI_IOCTL_RDWR, &read_write); if (retVal != 2) { FARF(ALWAYS, "mpu_spi_get_reg error read/write ioctl: %d", retVal); return retVal; } *val = spiRxBuf[1]; FARF(LOW, "mpu_spi_get_reg %d=%d", reg, *val); return 0; }
/** * @brief Test to see if ioctl fails (ioctl is not supported for files) * * @par * Test: * 1) Opens file with dspal path prefix ('/dev/fs/test.txt') in read/write mode with append * 2) Try ioctl call and make sure it fails * 3) Close the file * * @return * TEST_PASS ------ Always */ int dspal_tester_test_posix_file_ioctl(void) { int fd; FARF(MEDIUM, "%s test", __FUNCTION__); fd = open(TEST_FILE_PATH, O_RDWR|O_TRUNC|O_TRUNC); FARF(MEDIUM, "opened /dev/fs/test.txt in O_RDWR|O_TRUNC|O_TRUNC mode"); if (fd == -1) { FAIL("open test.txt failed. Make sure to have test.txt at $ADSP_LIBRARY_PATH"); } FARF(MEDIUM, "trying ioctl()"); if (ioctl(fd, 0, NULL) != -1) { FAIL("ioctl() is not supported and should have returned -1."); } close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); return TEST_PASS; }
/** * @brief Test file open/close operation * * @par Detailed Description: * This tests opens a file from the adsp side ('/dev/fs/test.txt'). It then * tries to open the file without the dspal file prefix ('test.txt'). * Test: * 1) Opens file with dspal path prefix ('/dev/fs/test.txt') in O_RDWR mode * 2) Close that file * 3) Open file without dispal path prefix ('test.txt') in O_RDONLY mode * 4) Close that file * * @return * TEST_PASS ------ on success * TEST_FAIL ------ on error */ int dspal_tester_test_posix_file_open_close(void) { int fd; FARF(MEDIUM, "%s test", __FUNCTION__); // Open TEST_FILE_PATH. Create the file if it doesn't exist. fd = open(TEST_FILE_PATH, O_RDWR|O_CREAT|O_TRUNC); if (fd == -1) { FAIL("failed to open /dev/fs/test.txt in O_RDWR|O_CREAT|O_TRUNC mode. " "Make sure to have test.txt at $ADSP_LIBRARY_PATH"); } FARF(MEDIUM, "open /dev/fs/test.txt in O_RDWR|O_CREAT|O_TRUNC mode"); if (close(fd) != 0) { FAIL("failed to close file handle"); } FARF(MEDIUM, "close /dev/fs/test.txt"); // test open file path without dspal file path prefix fd = open("test.txt", O_RDONLY); // open() is expected to fail if (fd >= 0) { close(fd); FAIL("open() succ for invalid path test.txt. This should never happen!"); } return TEST_PASS; }
/** * @brief Test to a file can be opened in all supported modes and closed. * * @par * Test: * 1) Opens file with dspal path prefix ('/dev/fs/test.txt') in one of the * fopen supported modes * 2) Close the file * * @return * TEST_FAIL ------ if fopen failed on certain mode * TEST_PASS ------ if fopen succeeds on all modes */ int dspal_tester_test_fopen_fclose(void) { FILE *fd; const char *modes[] = { "w", "w+", "r", "r+", "a", "a+" }; int num_modes = sizeof(modes) / sizeof(const char *); FARF(MEDIUM, "%s test", __FUNCTION__); for (int i = 0; i < num_modes; i++) { fd = fopen(TEST_FILE_PATH, modes[i]); if (fd == NULL) { FARF(MEDIUM, "fopen() mode %s returned NULL", modes[i]); return TEST_FAIL; } fclose(fd); FARF(MEDIUM, "fopen()/fclose mode %s succ", modes[i]); } FARF(MEDIUM, "fopen_fclose test passed"); return TEST_PASS; }
/** * @brief Helper function for 'dspal_tester_spi_test', checks if 2 data buffers are equal. * * * @param buffer1[in] pointer to first buffer * @param buffer2[in] pointer to second buffer * @param length[in] length of each buffers * * @return * true ------ data buffers match * false ------ data buffers do not match */ bool dpsal_tester_is_memory_matching(uint8_t *buffer1, uint8_t *buffer2, int length) { if (memcmp(buffer1, buffer2, length) != 0) { FARF(ALWAYS, "error: the bytes read to not match the bytes written"); FARF(ALWAYS, "bytes read: %c, %c, %c, %c, %c", buffer1[0], buffer1[1], buffer1[2], buffer1[3], buffer1[4]); FARF(ALWAYS, "bytes written: %c, %c, %c, %c, %c", buffer2[0], buffer2[1], buffer2[2], buffer2[3], buffer2[4]); return false; } return true; }
/** * @brief Test to a file can be written and read using fwrite() and frea() * * @par * Test: * 1) Opens file with dspal path prefix ('/dev/fs/test.txt') in write mode * 2) write timestamp to file * 3) fflush and fclose the file * 4) open the file in r mode * 5) fread() the file content and compare the bytes read and bytes written * 6) Close the file * * @return * TEST_PASS ------ if fwrite and fread succeed, and the bytes read and bytes * written are identical. * TEST_FAIL ------ otherwise */ int dspal_tester_test_fwrite_fread(void) { FILE *fd; char buffer[50] = {0}; uint64_t timestamp = time(NULL); size_t bytes_written; size_t bytes_read; size_t buffer_len; FARF(MEDIUM, "%s test", __FUNCTION__); fd = fopen(TEST_FILE_PATH, "w"); if (fd == NULL) { FARF(MEDIUM, "fopen() mode w returned NULL"); return TEST_FAIL; } sprintf(buffer, "test - timestamp: %llu\n", timestamp); buffer_len = strlen(buffer) + 1; FARF(MEDIUM, "writing to test.txt: %s (len: %d)", buffer, buffer_len); bytes_written = fwrite(buffer, 1, buffer_len, fd); if (bytes_written != buffer_len) { FARF(MEDIUM, "fwrite() %d bytes returned less than expected %d", buffer_len, bytes_written); return TEST_FAIL; } fflush(fd); fclose(fd); fd = fopen(TEST_FILE_PATH, "r"); if (fd == NULL) { FARF(MEDIUM, "fopen() mode r returned NULL"); return TEST_FAIL; } memset(buffer, 0, 50); bytes_read = fread(buffer, 1, buffer_len, fd); if (bytes_read != buffer_len) { FARF(MEDIUM, "fread() %d bytes returned less than expected %d", buffer_len, bytes_read); return TEST_FAIL; } FARF(MEDIUM, "fread() %d bytes: %s", bytes_read, buffer); fclose(fd); FARF(MEDIUM, "fwrite_fread test passed"); return TEST_PASS; }
/** * @brief Test to remove the specified file * * @par * Test: * 1) Opens file with dspal path prefix ('/dev/fs/test.txt') and create it if * it does not exist * 2) close the file * 3) remove the file * * @return * TEST_PASS ------ if remove returns 0 * TEST FAIL ------ on error */ int dspal_tester_test_posix_file_remove(void) { int fd; FARF(MEDIUM, "%s test", __FUNCTION__); // First create the file if it does not exist yet fd = open(TEST_FILE_PATH, O_RDWR|O_CREAT); FARF(MEDIUM, "opened /dev/fs/test.txt in O_RDWR|O_CREAT mode"); if (fd == -1) { FAIL("open test.txt failed. Make sure to have test.txt at $ADSP_LIBRARY_PATH"); } close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); if (remove(TEST_FILE_PATH) != 0) { FARF(MEDIUM, "failed to remove %s", TEST_FILE_PATH); return TEST_FAIL; } FARF(MEDIUM, "removed /dev/fs/test.txt"); // test removing a file with invalid dspal path if (remove("test.txt") == 0) { FARF(MEDIUM, "removed %s. This shouldn't happen", TEST_FILE_PATH); return TEST_FAIL; } FARF(MEDIUM, "removing file with invalid path failed. expected"); return TEST_PASS; }
/** * Main entry point for the SPI automated test. * @return * - ERROR: Indicates that the test has failed. * - SUCCESS: Test has passed */ int dspal_tester_spi_test(void) { int result; FARF(ALWAYS, "beginning spi loopback test"); if ((result = dspal_tester_spi_loopback_test()) < SUCCESS) { FARF(ALWAYS, "error: spi loopback test failed: %d", result); return result; } FARF(ALWAYS, "beginning spi exceed max write length test"); if ((result = dspal_tester_spi_exceed_max_length_test()) < SUCCESS) { FARF(ALWAYS, "error: spi exceed max write length test failed: %d", result); return result; } return SUCCESS; }
/** * @brief Test opening file in O_TRUNC mode * * @par * 1) open the file in O_WRONLY mode * 2) write timestamp to file * 3) close the file * 4) open the file in O_TRUNC mode * 5) read the file and verify if the file is empty * 6) cloes the file * * @return * TEST_PASS ------- file properly truncated * TEST_FAIL ------- on error */ int dspal_tester_test_posix_file_open_trunc() { int fd; int bytes_read; char wbuf[100]; char rbuf[100]; uint64_t timestamp = time(NULL); FARF(MEDIUM, "%s test", __FUNCTION__); // Open the file in read/write mode fd = open(TEST_FILE_PATH, O_RDWR|O_CREAT|O_TRUNC); if (fd < 0) { FAIL("failed to open /dev/fs/test.txt in O_RDWR|O_CREAT|O_TRUNC mode."); } FARF(MEDIUM, "opened /dev/fs/test.txt in O_RDWR|O_CREAT|O_TRUNC mode"); // write timestamp memset(wbuf, 0, 100); sprintf(wbuf, "test - timestamp: %llu\n", timestamp); FARF(MEDIUM, "writing to %s: %s (len: %d)", TEST_FILE_PATH, wbuf, strlen(wbuf) + 1); close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); // open the file in O_TRUNC mode fd = open(TEST_FILE_PATH, O_RDWR|O_TRUNC); if (fd < 0) { FAIL("failed to open /dev/fs/test.txt in O_RDWR|O_TRUNC mode."); } FARF(MEDIUM, "opened /dev/fs/test.txt in O_RDWR|O_TRUNC mode"); bytes_read = read(fd, rbuf, sizeof(rbuf)-1); FARF(MEDIUM, "read %d bytes from /dev/fs/test.txt", bytes_read); if (bytes_read != 0) { FAIL("Failed to truncate the file using O_TRUNC"); } FARF(MEDIUM, "/dev/fs/test.txt in truncated"); close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); return TEST_PASS; }
int testlib_function(const int* array, int arrayLength, int64* result) { int i, j; FARF(ALWAYS, "=============== DSP: Entering function testlib_function ==============="); *result = 0; for (i = 0; i < 100; ++i) { for (j = 0; j < arrayLength; ++j) { *result += array[i]; } } return 0; }
int dspal_tester_spi_exceed_max_length_test(void) { int spi_fildes = SUCCESS; int result = SUCCESS; uint8_t write_data_buffer[DSPAL_SPI_TRANSMIT_BUFFER_LENGTH + 1]; uint8_t read_data_buffer[DSPAL_SPI_RECEIVE_BUFFER_LENGTH + 1]; struct dspal_spi_ioctl_loopback loopback; struct dspal_spi_ioctl_read_write read_write; FARF(MEDIUM, "testing spi open for: %s", SPI_DEVICE_PATH); spi_fildes = open(SPI_DEVICE_PATH, 0); if (spi_fildes < SUCCESS) { FARF(HIGH, "error: failed to open spi device path: %s", SPI_DEVICE_PATH); result = ERROR; goto exit; } /* * Enable loopback mode to allow write/reads to be tested internally. */ FARF(MEDIUM, "enabling spi loopback mode"); loopback.state = SPI_LOOPBACK_STATE_ENABLED; result = ioctl(spi_fildes, SPI_IOCTL_LOOPBACK_TEST, &loopback); if (result < SUCCESS) { FARF(HIGH, "error: unable to activate spi loopback mode"); goto exit; } read_write.read_buffer = &read_data_buffer[0]; read_write.read_buffer_length = sizeof(read_data_buffer); read_write.write_buffer = &write_data_buffer[0]; read_write.write_buffer_length = sizeof(write_data_buffer); result = ioctl(spi_fildes, SPI_IOCTL_RDWR, &read_write); if (result == SUCCESS) { FARF(ALWAYS, "error: SPI_IOCTL_RDWR transfer overly large data should " "have failed but didn't. "); goto exit; } result = SUCCESS; FARF(MEDIUM, "SPI exceed max write length test passed"); exit: if (spi_fildes > SUCCESS) { close(spi_fildes); } return result; }
/** * @brief Test file fsync operation * * @par * Test: * 1) open file with dspal path prefix ('/dev/fs/test.txt') in read/write mode * 2) write timestamp to file * 3) fsync on the file * 4) close the file * 5) Opens the same file with read only mode * 6) read the file and compare with the content written in step 3 * 7) close the file * * @return * TEST_PASS ------ if all operations succeed * TEST_FAIL ------ otherwise */ int dspal_tester_test_posix_file_fsync(void) { int fd; int bytes_read; char wbuf[100]; char rbuf[100]; uint64_t timestamp = time(NULL); FARF(MEDIUM, "%s test", __FUNCTION__); // Open the file in read/write mode fd = open(TEST_FILE_PATH, O_RDWR|O_CREAT|O_TRUNC); if (fd < 0) { FAIL("failed to open /dev/fs/test.txt in O_RDWR|O_CREAT|O_TRUNC mode."); } FARF(MEDIUM, "open /dev/fs/test.txt in O_RDWR|O_CREAT|O_TRUNC mode"); // write timestamp memset(wbuf, 0, 100); sprintf(wbuf, "test - timestamp: %llu\n", timestamp); if (write(fd, wbuf, strlen(wbuf)) != (int)strlen(wbuf)) { FAIL("failed to write /dev/fs/test.txt"); } FARF(MEDIUM, "written to %s: %s (len: %d)", TEST_FILE_PATH, wbuf, strlen(wbuf)); // fsync fd to flush the content to storage device if (fsync(fd) < 0) { FAIL("failed to fsync /dev/fs/test.txt"); } FARF(MEDIUM, "fsync() succ"); close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); // Open the file in read/write mode fd = open(TEST_FILE_PATH, O_RDONLY); if (fd < 0) { FAIL("failed to open /dev/fs/test.txt in O_RDONLY mode."); } FARF(MEDIUM, "opened /dev/fs/test.txt in O_RDONLY mode"); // read the content to ensure the timestamp is properly written to file memset(rbuf, 0, 100); bytes_read = read(fd, rbuf, sizeof(rbuf)-1); FARF(MEDIUM, "read %d bytes from /dev/fs/test.txt:\n%s", bytes_read, rbuf); if ((!(strncmp(wbuf, rbuf, bytes_read) == 0) && (bytes_read == (int)strlen(wbuf)))) { FAIL("file write and read content does not match"); } // test writing file in O_RDONLY mode int ret = write(fd, wbuf, strlen(wbuf)); if (ret >= 0) { FAIL("write() succ on file in O_RDONLY mode. This should never happen!"); } FARF(MEDIUM, "write() failed on file in O_RDONLY mode."); close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); return TEST_PASS; }
/** * @brief Test opening file in O_APPEND mode * * @par * 1) open the file in O_RDWR|O_APPEND mode * 2) read file content * 3) write something * 4) close the file * 5) open the file in O_RDONLY mode * 6) read the file and verify the content * 7) close the file * * @return * TEST_PASS ------- file properly appended * TEST_FAIL ------- on error */ int dspal_tester_test_posix_file_open_append() { int fd; int bytes_read; char rbuf[100]; const char *old_content = "old content\n"; const char *new_content = "new content\n"; FARF(MEDIUM, "%s test", __FUNCTION__); fd = open(TEST_FILE_PATH, O_RDWR|O_TRUNC|O_CREAT); if (fd < 0) { FAIL("failed to open /dev/fs/test.txt in O_RDWR|O_TRUNC|O_CREAT mode."); } FARF(MEDIUM, "opened /dev/fs/test.txt in O_RDWR|O_CREAT|O_TRUNC mode"); if (write(fd, old_content, strlen(old_content)) != (int)strlen(old_content)) { FAIL("failed to write /dev/fs/test.txt"); } FARF(MEDIUM, "writing to %s: %s (len: %d)", TEST_FILE_PATH, old_content, strlen(old_content)); close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); // Open the file in APPEND mode fd = open(TEST_FILE_PATH, O_RDWR|O_APPEND); if (fd < 0) { FAIL("failed to open /dev/fs/test.txt in O_RDWR|O_APPEND mode."); } FARF(MEDIUM, "opened /dev/fs/test.txt in O_RDWR|O_APPEND mode"); if (write(fd, new_content, strlen(new_content)) != (int)strlen(new_content)) { FAIL("failed to write /dev/fs/test.txt"); } FARF(MEDIUM, "writing to %s: %s (len: %d)", TEST_FILE_PATH, new_content, strlen(new_content)); close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); // open the file in read only mode fd = open(TEST_FILE_PATH, O_RDONLY); if (fd < 0) { FAIL("failed to open /dev/fs/test.txt in O_RDONLY mode."); } FARF(MEDIUM, "opened /dev/fs/test.txt in O_RDONLY mode"); memset(rbuf, 0, 100); bytes_read = read(fd, rbuf, sizeof(rbuf)); if (bytes_read < 0) { FAIL("failed to read /dev/fs/test.txt."); } else if (bytes_read == 0) { FAIL("/dev/fs/test.txt is empty"); } if (!(strstr(rbuf, old_content) == rbuf) && strstr(rbuf + strlen(old_content), new_content) == rbuf+strlen(old_content)) { FAIL("failed to append writing to /dev/fs/test.txt"); } FARF(MEDIUM, "succ to append file using O_APPEND"); close(fd); FARF(MEDIUM, "closed /dev/fs/test.txt"); return TEST_PASS; }
/** * @brief Test read/write functionality of spi by using loopback * * @par Detailed Description: * Tests the read and write functionality of the spi device by putting the device * in loopback mode. This is tested in 2 ways: writing the data then reading it * back from the read buffer or by doing the read/write at the same time using ioctl * * Test: * 1) Opens file for spi device ('/dev/spi-8') * 2) Sets up the spi device in loopback mode using ioctl * 3) Write to the spi bus * 4) Read from the spi bus buffer * 5) Commented Out ---- Check if data written matches data read * 6) Loop though steps 4-5 for SPI_TEST_CYCLES number of cycles * 7) So ioctl read/write operation and check if data written matches data read * 8) Close spi bus * * @return * SUCCESS ------ Test Passes * ERROR ------ Test Failed */ int dspal_tester_spi_loopback_test(void) { int spi_fildes = SUCCESS; int cycle_count; int result = SUCCESS; uint8_t write_data_buffer[SPI_LOOPBACK_TEST_TRANSMIT_BUFFER_LENGTH]; uint8_t read_data_buffer[SPI_LOOPBACK_TEST_TRANSMIT_BUFFER_LENGTH]; int test_data_length_in_bytes = SPI_LOOPBACK_TEST_TRANSMIT_BUFFER_LENGTH - 1; struct dspal_spi_ioctl_loopback loopback; struct dspal_spi_ioctl_read_write read_write; FARF(MEDIUM, "testing spi open for: %s", SPI_DEVICE_PATH); spi_fildes = open(SPI_DEVICE_PATH, 0); if (spi_fildes < SUCCESS) { FARF(HIGH, "error: failed to open spi device path: %s", SPI_DEVICE_PATH); result = ERROR; goto exit; } /* * Initialize the write buffers in preparation for a read/write sequence. */ write_data_buffer[SPI_LOOPBACK_TEST_TRANSMIT_BUFFER_LENGTH - 1] = 0; init_write_buffer(write_data_buffer, SPI_LOOPBACK_TEST_TRANSMIT_BUFFER_LENGTH - 1); /* * Enable loopback mode to allow write/reads to be tested internally. */ FARF(MEDIUM, "enabling spi loopback mode"); loopback.state = SPI_LOOPBACK_STATE_ENABLED; result = ioctl(spi_fildes, SPI_IOCTL_LOOPBACK_TEST, &loopback); if (result < SUCCESS) { FARF(HIGH, "error: unable to activate spi loopback mode"); goto exit; } /* * Test loopback mode using combined read/write mode. */ FARF(MEDIUM, "testing spi write/read for %d cycles", SPI_TEST_CYCLES); for (cycle_count = 0; cycle_count < SPI_TEST_CYCLES; cycle_count++) { memset(read_data_buffer, 0, sizeof(read_data_buffer)); read_write.read_buffer = &read_data_buffer[0]; read_write.read_buffer_length = test_data_length_in_bytes; read_write.write_buffer = &write_data_buffer[0]; read_write.write_buffer_length = test_data_length_in_bytes; FARF(MEDIUM, "writing bytes: (%d bytes)", test_data_length_in_bytes); result = ioctl(spi_fildes, SPI_IOCTL_RDWR, &read_write); if (result < SUCCESS) { FARF(ALWAYS, "error: unable to activate read/write ioctl"); goto exit; } if (!dpsal_tester_is_memory_matching(write_data_buffer, read_data_buffer, test_data_length_in_bytes)) { FARF(ALWAYS, "error: read/write memory buffers do not match"); goto exit; } FARF(MEDIUM, "written data matches read data"); } result = SUCCESS; FARF(MEDIUM, "SPI lookback test passed"); exit: if (spi_fildes > SUCCESS) { close(spi_fildes); } return result; }