| #include <stdio.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <cinttypes> |
| #include <cmath> |
| #include <iostream> |
| #include <sys/ioctl.h> |
| |
| #include "tspdrv.h" |
| |
| int tspdrv_initialized = 0; |
| int tspdrv_file_desc; |
| int tspdrv_numActuators = 0; |
| |
| int initialize_tspdrv() |
| { |
| // Open device file as read/write for ioctl and write |
| tspdrv_file_desc = open(TSPDRV, O_RDWR); |
| if(tspdrv_file_desc < 0) |
| { |
| printf("Failed to open device file: %s", TSPDRV); |
| return -1; |
| } |
| |
| // create default device parameters |
| device_parameter dev_param1 { 0, VIBE_KP_CFG_FREQUENCY_PARAM1, 0}; |
| device_parameter dev_param2 { 0, VIBE_KP_CFG_FREQUENCY_PARAM2, 0}; |
| device_parameter dev_param3 { 0, VIBE_KP_CFG_FREQUENCY_PARAM3, 0}; |
| device_parameter dev_param4 { 0, VIBE_KP_CFG_FREQUENCY_PARAM4, 400}; |
| device_parameter dev_param5 { 0, VIBE_KP_CFG_FREQUENCY_PARAM5, 13435}; |
| device_parameter dev_param6 { 0, VIBE_KP_CFG_FREQUENCY_PARAM6, 0}; |
| device_parameter dev_param_update_rate {0, VIBE_KP_CFG_UPDATE_RATE_MS, 5}; |
| |
| // Set magic number for vibration driver, wont allow us to write data without! |
| int ret = ioctl(tspdrv_file_desc, TSPDRV_SET_MAGIC_NUMBER, TSPDRV_MAGIC_NUMBER); |
| if(ret != 0) |
| { |
| printf("Failed to set magic number"); |
| return -ret; |
| } |
| |
| // Set default device parameter 1 |
| ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param1); |
| if(ret != 0) |
| { |
| printf("Failed to set device parameter 1"); |
| return -ret; |
| } |
| |
| // Set default device parameter 2 |
| ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param2); |
| if(ret != 0) |
| { |
| printf("Failed to set device parameter 2"); |
| return -ret; |
| } |
| |
| // Set default device parameter 3 |
| ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param3); |
| if(ret != 0) |
| { |
| printf("Failed to set device parameter 3"); |
| return -ret; |
| } |
| |
| // Set default device parameter 4 |
| ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param4); |
| if(ret != 0) |
| { |
| printf("Failed to set device parameter 4"); |
| return -ret; |
| } |
| |
| // Set default device parameter 5 |
| ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param5); |
| if(ret != 0) |
| { |
| printf("Failed to set device parameter 5"); |
| return -ret; |
| } |
| |
| // Set default device parameter 6 |
| ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param6); |
| if(ret != 0) |
| { |
| printf("Failed to set device parameter 6"); |
| return -ret; |
| } |
| |
| // Set default device parameter update rate |
| ret = ioctl(tspdrv_file_desc, TSPDRV_SET_DEVICE_PARAMETER, &dev_param_update_rate); |
| if(ret != 0) |
| { |
| printf("Failed to set device parameter update rate"); |
| return -ret; |
| } |
| |
| // Get number of actuators the device has |
| ret = ioctl(tspdrv_file_desc, TSPDRV_GET_NUM_ACTUATORS, 0); |
| if(ret == 0) |
| { |
| printf("No actuators found!"); |
| return -2; |
| } |
| |
| tspdrv_numActuators = ret; |
| tspdrv_initialized = 1; |
| return 0; |
| } |
| |
| int tspdrv_off() { |
| |
| for(int32_t i = 0; i < tspdrv_numActuators; i++) |
| { |
| int32_t ret = ioctl(tspdrv_file_desc, TSPDRV_DISABLE_AMP, i); |
| if(ret != 0) |
| { |
| printf("Failed to deactivate Actuator with index %d", i); |
| return -1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int vibrate(int timeout_ms) |
| { |
| double BUFFER_ENTRIES_PER_MS = 8.21; |
| uint8_t DEFAULT_AMPLITUDE = 127; |
| int32_t OUTPUT_BUFFER_SIZE = 40; |
| |
| if(!tspdrv_initialized) |
| { |
| printf("Initializing TSPDRV\n"); |
| if(initialize_tspdrv() == 0) |
| { |
| printf("TSPDRV initialized\n"); |
| } |
| } |
| |
| // Calculate needed buffer entries |
| int32_t bufferSize = (int32_t) round(BUFFER_ENTRIES_PER_MS * timeout_ms); |
| VibeUInt8 fullBuffer[bufferSize]; |
| |
| // turn previous vibrations off |
| tspdrv_off(); |
| |
| for(int32_t i = 0; i < bufferSize; i++) |
| { |
| // The vibration is a sine curve, the negative parts are 255 + negative value |
| fullBuffer[i] = (VibeUInt8) (DEFAULT_AMPLITUDE * sin(i/BUFFER_ENTRIES_PER_MS)); |
| } |
| |
| // Amount of buffer arrays with size of OUTPUT_BUFFER_SIZE |
| int32_t numBuffers = (int32_t) ceil((double)bufferSize / (double)OUTPUT_BUFFER_SIZE); |
| VibeUInt8 outputBuffers[numBuffers][OUTPUT_BUFFER_SIZE]; |
| memset(outputBuffers, 0, sizeof(outputBuffers)); // zero the array before we fill it with values |
| |
| for(int32_t i = 0; i < bufferSize; i++) |
| { |
| // split fullBuffer into multiple smaller buffers with size OUTPUT_BUFFER_SIZE |
| outputBuffers[i/OUTPUT_BUFFER_SIZE][i%OUTPUT_BUFFER_SIZE] = fullBuffer[i]; |
| } |
| |
| for(int32_t i = 0; i < tspdrv_numActuators; i++) |
| { |
| for(int32_t j = 0; j < numBuffers; j++) |
| { |
| char output[OUTPUT_BUFFER_SIZE + SPI_HEADER_SIZE]; |
| memset(output, 0, sizeof(output)); |
| output[0] = i; // first byte is actuator index |
| output[1] = 8; // per definition has to be 8 |
| output[2] = OUTPUT_BUFFER_SIZE; // size of the following output buffer |
| for(int32_t k = 3; k < OUTPUT_BUFFER_SIZE+3; k++) |
| { |
| output[k] = outputBuffers[j][k-3]; |
| } |
| // write the buffer to the device |
| write(tspdrv_file_desc, output, sizeof(output)); |
| if((j+1) % 4 == 0) |
| { |
| // every 4 buffers, but not the first if theres only 1, we send an ENABLE_AMP signal |
| int32_t ret = ioctl(tspdrv_file_desc, TSPDRV_ENABLE_AMP, i); |
| if(ret != 0) |
| { |
| printf("Failed to activate Actuator with index %d", i); |
| return -1; |
| } |
| } |
| } |
| } |
| return 0; |
| } |