* Needed for the LG V30, G7, V35, V40 * Use TW_HAPTICS_TSPDRV in your BoardConfig.mk to enable it. Change-Id: I0970ed5c046e851f7e6f562283523c7214c8d2b5 (cherry picked from commit 314cbd5698d1750a31c9cf4284d3ce8dfadce157)
193 lines
5.7 KiB
C++
193 lines
5.7 KiB
C++
#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;
|
|
} |