Linux - How to program for a touchscreen outside of X Windows - linux

I have a small TFT with touch control connected to a Raspberry Pi. The touchscreen works well within X windows.
I would like to be able to use the touchscreen outside of X windows.
Something simple, like two buttons on the screen.
I have experience with C and writing to the framebuffer using SDL. Or directly to memory.
I have no idea how to detect the input of the touchscreen and I am hoping some one could point me in the right direction.
I see the touchscreen as /dev/input/event0

It seems that you are just seeing a regular event device. What have you done so far? You might try for example Using the Input Subsystem article on Linux Journal.
What you should try at first should probably be:
/* how many bytes were read */
size_t rb;
/* the events (up to 64 at once) */
struct input_event ev[64];
rb=read(fd,ev,sizeof(struct input_event)*64);
if (rb < (int) sizeof(struct input_event)) {
perror("evtest: short read");
exit (1);
}
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++)
{
//if (EV_KEY == ev[yalv].type)
printf("%ld.%06ld ",
ev[yalv].time.tv_sec,
ev[yalv].time.tv_usec,
printf("type %d code %d value %d\n",
ev[yalv].type,
ev[yalv].code, ev[yalv].value);
}
Then you should pay attention, what event types are being emitted, and then work with them further.

Related

Remove input driver bound to the HID interface

I'm playing with some driver code for a special kind of keyboard. And this keyboard does have special modes. According to the specification those modes could only be enabled by sending and getting feature reports.
I'm using 'hid.c' file and user mode to send HID reports. But both 'hid_read' and 'hid_get_feature_report' failed with error number -1.
I already tried detaching keyboard from kernel drivers using libusb, but when I do that, 'hid_open' fails. I guess this is due to that HID interface already using by 'input' or some driver by the kernel. So I may not need to unbind kernel hidraw driver, instead I should try unbinding the keyboard ('input') driver top of 'hidraw' driver. Am I correct?
And any idea how I could do that? And how to find what are drivers using which drivers and which low level driver bind to which driver?
I found the answer to this myself.
The answer is to dig this project and find it's hid implementation on libusb.
Or you could directly receive the report.
int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
{
int res = -1;
int skipped_report_id = 0;
int report_number = data[0];
if (report_number == 0x0) {
/* Offset the return buffer by 1, so that the report ID
will remain in byte 0. */
data++;
length--;
skipped_report_id = 1;
}
res = libusb_control_transfer(dev->device_handle,
LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
0x01/*HID get_report*/,
(3/*HID feature*/ << 8) | report_number,
dev->interface,
(unsigned char *)data, length,
1000/*timeout millis*/);
if (res < 0)
return -1;
if (skipped_report_id)
res++;
return res;
}
I'm sorry I can't post my actual code due to some legal reasons. However the above code is from hidapi implementation.
So even you work with an old kernel , you still have the chance to make your driver working.
This answers to this question too: https://stackoverflow.com/questions/30565999/kernel-version-2-6-32-does-not-support-hidiocgfeature

Write to I2C I/O device

I am trying to talk to a Bosch Sensortec BNO055 sensor. I am using the shuttleboard. VDD and VDDIO are connected to 3.3V, on pin 17 and 18 Are SDA and SCL. These connected to a embedded linux board. An other sensor is on the same bus, I can see its values on the scope.
I have the following code:
BNO055_RETURN_FUNCTION_TYPE Bno055I2cBusWrite(u8 dev_addr, u8 reg_addr, u8* reg_data, u8 wr_len){
//According to https://www.kernel.org/doc/Documentation/i2c/dev-interface
int file = 0;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", ADAPTER_NR);
if(open(filename, O_RDWR) < 0){ /*error*/ }
if(ioctl(file, I2C_SLAVE, dev_addr) < 0){ /*error*/ }
char buf[1 + wr_len];
buf[0] = reg_addr;
memcpy(&buf[1], reg_data, wr_len);
int written_bytes = 0;
if(write(file, buf, wr_len) != wr_len){
printf("Error BusWrite-write: %s.\n", strerror(errno));
exit(-1);
}
}
The first two if-statements are passed fine.
The write-operation fails. On the oscilloscope I see the correct device-address (which is then not acknowledged).
What I've done:
Added the device-address to buf (not covered in this code example).
Read and understood page 90-92 from the datasheet https://ae-bst.resource.bosch.com/media/products/dokumente/bno055/BST_BNO055_DS000_12~1.pdf
Soldered 1k8 ohm resistors to get steeper edges on clock and data
Made sure that the device address and the read/write bit are set correct
My sensor just does not acknowledges when its device address appears on the line.
What is exactly done by ioctl(file, I2C_SLAVE, dev_addr)? Does that send out the device-address on the I2C-bus?
Does the linuxkernel send the device-address by itself? I expect so.
Resuming:
Can someone point me in the right direction to let the sensor react?
Well... it just seemed that a wire to the scope interfered too much. And the device-address is sent by the driver when writing or reading, to answer my own question.

How to control hard drive motor speed with C on linux?

I've got an old HDD with which I planned to fiddle around a little. First thing I'm trying to do is spinning the motor with different speeds.
Questions are:
Is there a general way to do this or does it depend on the HDD model?
Where do I find a list of commands, that I can send to the HDD controller to control the speed of the motor?
I actually found a function, that apparently spins down the motor, here it is:
/* spin-down a disk */
static void spindown_disk(const char *name)
{
struct sg_io_hdr io_hdr;
unsigned char sense_buf[255];
char dev_name[100];
int fd;
dprintf("spindown: %s\n", name);
/* fabricate SCSI IO request */
memset(&io_hdr, 0x00, sizeof(io_hdr));
io_hdr.interface_id = 'S';
io_hdr.dxfer_direction = SG_DXFER_NONE;
/* SCSI stop unit command */
io_hdr.cmdp = (unsigned char *) "\x1b\x00\x00\x00\x00\x00";
io_hdr.cmd_len = 6;
io_hdr.sbp = sense_buf;
io_hdr.mx_sb_len = (unsigned char) sizeof(sense_buf);
/* open disk device (kernel 2.4 will probably need "sg" names here) */
snprintf(dev_name, sizeof(dev_name), "/dev/%s", name);
if ((fd = open(dev_name, O_RDONLY)) < 0) {
perror(dev_name);
return;
}
/* execute SCSI request */
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
char buf[100];
snprintf(buf, sizeof(buf), "ioctl on %s:", name);
perror(buf);
} else if (io_hdr.masked_status != 0) {
fprintf(stderr, "error: SCSI command failed with status 0x%02x\n",
io_hdr.masked_status);
if (io_hdr.masked_status == CHECK_CONDITION) {
phex(sense_buf, io_hdr.sb_len_wr, "sense buffer:\n");
}
}
close(fd);
}
Though I don't really understand where the actual command is sent to the controller, nor do I know how to control the speed, I don't see any rpm specifications.
You cannot control a harddisk's rotational speed, and that is a good thing. If you could, you would inevitably destroy data.
The heads float in what is commonly called "air bearing".
This is, in easy words, a spring mechanism pressing the head onto the disks's surface with a well-defined force and an air cussion from airflow due to the disk's rotation being in equilibrium at the disk's operational speed. When the disk is shut down, another spring mechanisms quickly pulls the heads out of the way into a kind of "parking position".
If you could run the drive at arbitrary speeds, the heads would scratch on the surface. Not good!
As to where the actual command is being sent in above snippet, it is the ioctl call in the line following /* execute SCSI request */.
If you are interested in playing with your old harddisk (be aware that you'll quite likely break it!), have a look at the hdparm tool and its source code. hdparm lets you tweak dozens of parameters such as power save modes, caching, or acustic management... pretty much everything that disk drives support.
In the tool's source code, you'll find a quite complete list of device commands, too.

Use SATA HDD as Block Device

I'm totally new to the Linux Kernel, so I probably mix things up. But any advice will help me ;)
I have a SATA HDD connected via a PCIe SATA Card and I try to use read and write like on a block device. I also want the data power blackout save on the HDD - not cached. And in the end I have to analyse how much time I loose in each linux stack layer. But one step at a time.
At the moment I try to open the device with *O_DIRECT*. But I don't really understand where I can find the device. It shows up as /dev/sdd and I created one partition /dev/sdd1.
open and read on the partition /dev/sdd1 works. write fails with *O_DIRECT* (But I'm sure I have the right blocksize)
open read and write called on /dev/sdd fails completely.
Is there maybe another file in /dev/ which represents my device on the block layer?
What are my mistakes and wrong assumptions?
This is my current test code
int main() {
int w,r,s;
char buffer[512] = "test string mit 512 byte";
printf("test\n");
// OPEN
int fd = open("/dev/sdd", O_DIRECT | O_RDWR | O_SYNC);
printf("fd = %d\n",fd);
// WRITE
printf("try to write %d byte : %s\n",sizeof(buffer),buffer);
w = write(fd,buffer,sizeof(buffer));
if(w == -1) printf("write failed\n");
else printf("write ok\n");
// RESET BUFFER
memset(buffer,0,sizeof(buffer));
// SEEK
s = lseek(fd,0,SEEK_SET);
if(s == -1) printf("seek failed\n");
else printf("seek ok\n");
// READ
r = read(fd,buffer,sizeof(buffer));
if(r == -1) printf("read failed\n");
else printf("read ok\n");
// PRINT BUFFER
printf("buffer = %s\n",buffer);
return 0;
}
Edit:
I work with the 3.2 Kernel on a power architecture - if this is important.
Thank you very much for your time,
Fabian
Depending on your SDD's block size (could by 512bit or 4K), you can only read/write mulitple of that size.
Also: when using O_DIRECT flag, you need to make sure the buffer is rightly aligned to block boundaries. You cann't ensure that using an ordinary char array, use memalign to allocate aligned memory instead.

How to read from a Linux serial port

I am working on robot which has to control using wireless serial communication. The robot is running on a microcontroller (by burning a .hex file). I want to control it using my Linux (Ubuntu) PC. I am new to serial port programming. I am able to send the data, but I am not able to read data.
A few piece of code which is running over at the microcontroller:
Function to send data:
void TxData(unsigned char tx_data)
{
SBUF = tx_data; // Transmit data that is passed to this function
while(TI == 0) // Wait while data is being transmitted
;
}
I am sending data through an array of characters data_array[i]:
for (i=4; i<=6; i++)
{
TxData(data_array[i]);
RI = 0; // Clear receive interrupt. Must be cleared by the user.
TI = 0; // Clear transmit interrupt. Must be cleared by the user.
}
Now the piece of code from the C program running on Linux...
while (flag == 0) {
int res = read(fd, buf, 255);
buf[res] = 0; /* Set end of string, so we can printf */
printf(":%s:%d\n", buf, res);
if (buf[0] == '\0')
flag = 1;
}
It prints out value of res = 0.
Actually I want to read data character-by-character to perform calculations and take further decision. Is there another way of doing this?
Note: Is there good study material (code) for serial port programming on Linux?
How can I read from the Linux serial port...
This is a good guide: Serial Programming Guide for POSIX Operating Systems
The read call may return with no data and errno set to EAGAIN. You need to check the return value and loop around to read again if you're expecting data to arrive.
First, take a look at /proc/tty/driver/serial to see that everything is set up correctly (i.e., you see the signals you should see). Then, have a look at the manual page for termios(3), you may be interested in the VMIN and VTIME explanation.

Resources