Linux GPIO Value File Not Created on Export - c

I am trying to write a basic Linux GPIO user space application. For some reason, I am able to open the export file and export the GPIO with the given number. However, after exporting it, I cannot specify whether it is input or output because the /sys/class/gpio/gpio<###>/direction file is not created. As a result, my C errs out.
Here is the code
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int valuefd, exportfd, directionfd;
printf("GPIO test running...\n");
exportfd = open("/sys/class/gpio/export", O_WRONLY);
if(exportfd < 0)
{
printf("Cannot open GPIO to export it\n");
exit(1);
}
write(exportfd, "971", 4);
close(exportfd);
printf("GPIO exported successfully\n");
directionfd = open("/sys/class/gpio971/direction", O_RDWR);
if(directionfd < 0)
{
printf("Cannot open GPIO direction it\n");
exit(1);
}
write(directionfd, "out", 4);
close(directionfd);
printf("GPIO direction set as output successfully\n");
valuefd = open("/sys/class/gpio/gpio971/value", O_RDWR);
if(valuefd < 0)
{
printf("Cannot open GPIO value\n");
exit(1);
}
printf("GPIO value opened, now toggling...\n");
while(1)
{
write(valuefd, "1", 2);
write(valuefd, "0", 2);
}
return 0;
}
Output from run:
root#plnx_arm:~# /usr/bin/basic-gpio
GPIO test running...
GPIO exported successfully
Cannot open GPIO direction it
File is there
root#plnx_arm:~# ls /sys/class/gpio/gpio971/
active_low device direction edge power subsystem
uevent value

You need to open file "/sys/class/gpio/gpio971/direction" and not "/sys/class/gpio971/direction"
directionfd = open("/sys/class/gpio/gpio971/direction", O_RDWR);
if(directionfd < 0)
{
printf("Cannot open GPIO direction it\n");
exit(1);
}
You can refer [1], and get the code to export/unexport/set direction/read/write gpio pin.
[1] https://elinux.org/RPi_GPIO_Code_Samples#sysfs

Related

Mount vfat image win linux using C

I'm trying to mount a vfat disk image from DOS, using .C
if( mount( "/mypath/disk.img", "/mypath/img/", "vfat", MS_DIRSYNC | MS_SYNCHRONOUS, "utf8" ) ) {
printf( "Error mount %s errno=%d %s\n", dst.c_str(), errno, strerror( errno ) );
}
I get all the times the error "Block device required". Should i add some parameter or flag?
Note:I can mount from the bash the same file in the same target without any error.
UPDATE:
I had some good result using the function to mount an ISO. When I run the program, it remains stacked on the call ioctl(loop_device_fd, LOOP_CLR_FD, 0);. When I exit from the program (ctrl-c), the image is mounted. Is LOOP_CLR_FD necessary to complete all the steps? In additional,it is mounted in read only and seems not possible to change it in read/write.
const auto loop_control = std::fopen( "/dev/loop-control", "r" );
const auto loop_control_fd = fileno(loop_control);
const auto devnr = ioctl(loop_control_fd, LOOP_CTL_GET_FREE);
std::stringstream loopname;
loopname << "/dev/loop" << devnr;
const auto loop_device_name = loopname.str();
const auto loop_device = std::fopen(loop_device_name.c_str(), "r");
const auto loop_device_fd = fileno(loop_device);
const auto image = std::fopen( dst.c_str(), "r" );
const auto image_fd = fileno(image);
//Associate the loop device with the open file whose file descriptor is passed as the (third) ioctl(2) argument.
ioctl(loop_device_fd, LOOP_SET_FD, image_fd);
const auto result = mount(loop_device_name.c_str(), dst_path_img.c_str(), "vfat", MS_RDONLY, NULL);
if( result ) {
printf( "Error mount %s errno=%d %s\n", dst.c_str(), errno, strerror( errno ) );
return;
}
ioctl(loop_device_fd, LOOP_CLR_FD, 0);
The example code from the link above seems to mount your image quite fine, with minor modifications to retrieve free loop device (I'm assuming it is Dos3.3 diskette image from allbootdisks.com):
#include <sys/mount.h>
#include <linux/loop.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main()
{
int control_fd, file_fd, device_fd;
char loop_device[16];
control_fd = open("/dev/loop-control", O_RDWR);
if (control_fd < 0) {
perror("open loop control device failed");
return 1;
}
int loop_id = ioctl(control_fd, LOOP_CTL_GET_FREE);
sprintf(loop_device, "/dev/loop%d", loop_id);
close(control_fd);
printf("using loop device: %s\n", loop_device);
file_fd = open("./Dos3.3.img", O_RDWR);
if (file_fd < 0) {
perror("open backing file failed");
return 1;
}
device_fd = open(loop_device, O_RDWR);
if (device_fd < 0) {
perror("open loop device failed");
close(file_fd);
return 1;
}
if (ioctl(device_fd, LOOP_SET_FD, file_fd) < 0) {
perror("ioctl LOOP_SET_FD failed");
close(file_fd);
close(device_fd);
return 1;
}
close(file_fd);
if (mount(loop_device, "./mnt/", "vfat", MS_DIRSYNC | MS_SYNCHRONOUS, "") < 0) {
perror("mount failed");
} else {
printf("mount successful\n");
}
// always free loop device in the end
ioctl(device_fd, LOOP_CLR_FD, 0);
close(device_fd);
}
As the disk image is not really a device, it cannot be directly mounted.
What you are trying to do, is to mount via a loop device.
Command line equivalent is: mount /mypath/disk.img /mypath/img -t vfat -o loop
I'm not sure, but try whether adding the "loop, utf8" as your last parameter would fix the problem.
The problem here is you're trying to mount an image as you you would do with a block device. A block device has more bindings to the operating system than an image file would, so you need to find a way around this.
Try a loopback device! A loopback device can give you the operating system reference to that image /mypath/disk.img as a block device. You can create a loopback device in bash like so:
# set up a block device
losetup -fP /mypath/disk.img
# now list the loopback devices
losetup -a
Anyway, this solution is in bash, but certainly there is a library out there somewhere for c.

Write to newly opened terminal window

As everything is file in Linux I would like to print to opened console in terminal window.
I have opened console in Linux and have written command tty. In output I have:
/dev/pts/25
This is the program that copies everything from foo file to bar and console:
/* Trivial file copy program using low-level I/O */
#include <fcntl.h>
#include <stdlib.h>
#define BSIZE 16384
void main()
{
int fin, fout,con; /* Input and output handles */
char buf[BSIZE];
int count;
if ((con = open("/dev/pts/2", O_WRONLY)) < 0) {
perror("open con ");
exit(1);
}
if ((fin = open("foo", O_RDONLY)) < 0) {
perror("foo");
exit(1);
}
if ((fout = open("bar", O_WRONLY | O_CREAT, 0644)) < 0) {
perror("bar");
exit(2);
}
while ((count = read(fin, buf, BSIZE)) > 0)
{
write(fout, buf, count);
write(con, buf, count);
}
close(fin);
close(fout);
close(con);
}
Unfortunately nothing is written in console window while bar contains needed information. How to write to console terminal window?
I have opened console in Linux and have written command tty. In output I have:
/dev/pts/25
This is program that coppyes evrything from foo file to bar and console:
…
if ((con = open("/dev/pts/2", O_WRONLY)) < 0) {
…
Your program opens just a device pts/2 different from pts/25 which you say is your console.

Cannot set GPIO pins in FT230X in Centos

I have LEDs connected to CBx pins of FT230X. I am using libftdi v1.2 to set FT230X CBx pins. I am tried both 2 bitbang modes: BITMODE_BITBANG and BITMODE_CBUS, but without any result.
My code is somewhere about follow:
#include <ftdi.h>
#include <err.h>
int main(int argc, char *argv[])
{
struct ftdi_context ftdi;
unsigned char x;
/* Initialize and find device */
if (ftdi_init(&ftdi) < 0)
err(1, "ftdi_init");
if (ftdi_usb_open(&ftdi, 0x0403, 0x6015) < 0)
err(2, "can't open device");
/* Enable bitbang */
if (ftdi_set_bitmode(&ftdi, 0xff, BITMODE_BITBANG) < 0)
err(3, "can't enable bitbang mode");
/* Write Yellow */
x=0x00;
if (ftdi_write_data(&ftdi, &x, 1) < 0)
err(5, "can't write");
sleep(3);
/* Write Red */
x=0x01;
if (ftdi_write_data(&ftdi, &x, 1) < 0)
err(5, "can't write");
sleep(3);
/* Write Green */
x=0x02;
if (ftdi_write_data(&ftdi, &x, 1) < 0)
err(5, "can't write");
sleep(3);
/* Close device */
ftdi_usb_close(&ftdi);
ftdi_deinit(&ftdi);
return 0;
}
It should be noted that the same code (exclude product id = 0x6013) works properly for FT4232H.
I resolved my problem. As I mentioned, I need to set CBx pins on FT230X. For this case in the FT230X should be enabled BITMODE_CBUS mode in EEPROM.
In BITMODE_CBUS mode, as it described in bitbang_cbus.c example of libftdi, to set these CBx pins should be used only ftdi_set_bitmode() function.
Wherein in the second parameter (bitmask) the top nibble controls input/output and the bottom nibble controls the state of the lines set to output.

writing to /dev/ttyO3 not visible

I am writing the data to /dev/ttyO3 in my application .The write is succeeded but not visible int he cat /dev/ttyO3.
ttyO3 is the device name for the uart4 instance of omap4460 pandaboard.
Edit 1:But some pulses are showing up when I probe through CRO.
How should I change my code to enable the software loop back?ie(I want the same pulse to be seen at rx pin without shorting Tx-Rx)
#define DEVICE "/dev/ttyO3"
int main()
{
int fd;
int write_fd1;
struct termios options;
fd = open(DEVICE,O_RDWR);
if(fd < 0)
printf("unable to open the device\n");
else
printf("device opened %d \n",fd);
tcgetattr(fd,&options);
cfsetospeed(&options,B300);
cfsetispeed(&options,B300);
tcsetattr(fd,TCSANOW,&options);
tcgetattr(fd,&options);
if((cfgetospeed(&options) != B300) || (cfgetispeed(&options)!= B300));
{
printf("Baud rate not set");
}
while(1)
{
write_fd1 = write(fd,"a",2) ;
printf("write_fd %d \n",write_fd1);
}
close(fd);
return 0;
}

Unable to claim USB interface with C + libusb on Mac OS X

I've got a compound USB + CDC device I built using a PIC32 microcontroller, and I'm trying to connect to the device and send some data to the CDC data interface endpoint from my Mac.
I know the circuit works 100%, as the device registers as both a HID joystick, and I'm able to connect to the device using Zoc terminal, on /dev/tty.usbmodemfa132. I can send commands with Zoc, and see my MCU responding to these commands by blinking some LEDs on the circuit.
I'm running this on Mac OS X Mavericks, but had the same problem with a similar example I gave up on, a few weeks ago on Mountain Lion.
My code looks like follows:
// Includes -----------------------------------------------------------------------------------------------------------
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
#include <unistd.h>
// Defines ------------------------------------------------------------------------------------------------------------
#define VID 0x04d8
#define PID 0x005e
#define CDC_DATA_INTERFACE_ID 2
// Function Declarations ----------------------------------------------------------------------------------------------
void print_device(libusb_device *device);
void send(libusb_context *usb_context, uint16_t vid, uint16_t pid);
// Function Definitions -----------------------------------------------------------------------------------------------
/**
* main
*/
int main(int argc, char **argv)
{
libusb_device **usb_devices = NULL;
libusb_context *usb_context = NULL;
ssize_t device_count = 0;
bool debug_enabled = false;
int c;
// Collect command line attributes
while ( (c = getopt(argc, argv, "d")) != -1) {
switch (c) {
case 'd':
debug_enabled = true;
break;
}
}
// Initialize USB context
int result = libusb_init(&usb_context);
if(result < 0) {
printf("Unable to initialise libusb!");
return EXIT_FAILURE;
}
// Turn debug mode on/off
if(debug_enabled) {
libusb_set_debug(usb_context, 3);
}
// Get USB device list
device_count = libusb_get_device_list(usb_context, &usb_devices);
if(device_count < 0) {
puts("Unable to retrieve USB device list!");
}
// Iterate and print devices
puts("VID PID Manufacturer Name\n------ ------ -------------------");
for (int i = 0; i < device_count; i++) {
print_device(usb_devices[i]);
}
// Attempt to send data
send(usb_context, VID, PID);
// Cleanup and exit
libusb_free_device_list(usb_devices, 1);
libusb_exit(usb_context);
return EXIT_SUCCESS;
}
/**
* print_device
*/
void print_device(libusb_device *device)
{
struct libusb_device_descriptor device_descriptor;
struct libusb_device_handle *device_handle = NULL;
// Get USB device descriptor
int result = libusb_get_device_descriptor(device, &device_descriptor);
if (result < 0) {
printf("Failed to get device descriptor!");
}
// Only print our devices
if(VID == device_descriptor.idVendor && PID == device_descriptor.idProduct) {
// Print VID & PID
printf("0x%04x 0x%04x", device_descriptor.idVendor, device_descriptor.idProduct);
} else {
return;
}
// Attempt to open the device
int open_result = libusb_open(device, &device_handle);
if (open_result < 0) {
libusb_close(device_handle);
return;
}
// Print the device manufacturer string
char manufacturer[256] = " ";
if (device_descriptor.iManufacturer) {
libusb_get_string_descriptor_ascii(device_handle, device_descriptor.iManufacturer,
(unsigned char *)manufacturer, sizeof(manufacturer));
printf(" %s", manufacturer);
}
puts("");
libusb_close(device_handle);
}
/**
* send
*/
void send(libusb_context *usb_context, uint16_t vid, uint16_t pid)
{
libusb_device_handle *device_handle;
device_handle = libusb_open_device_with_vid_pid(usb_context, vid, pid);
if (device_handle == NULL) {
puts("Unable to open device by VID & PID!");
return;
}
puts("Device successfully opened");
unsigned char *data = (unsigned char *)"test";
if (libusb_kernel_driver_active(device_handle, CDC_DATA_INTERFACE_ID)) {
puts("Kernel driver active");
if (libusb_detach_kernel_driver(device_handle, CDC_DATA_INTERFACE_ID)) {
puts("Kernel driver detached");
}
} else {
puts("Kernel driver doesn't appear to be active");
}
int result = libusb_claim_interface(device_handle, CDC_DATA_INTERFACE_ID);
if (result < 0) {
puts("Unable to claim interface!");
libusb_close(device_handle);
return;
}
puts("Interface claimed");
int written = 0;
result = libusb_bulk_transfer(device_handle, (3 | LIBUSB_ENDPOINT_OUT), data, 4, &written, 0);
if (result == 0 && written == 4) {
puts("Send success");
} else {
puts("Send failed!");
}
result = libusb_release_interface(device_handle, CDC_DATA_INTERFACE_ID);
if (result != 0) {
puts("Unable to release interface!");
}
libusb_close(device_handle);
}
I'm getting the following error output:
libusb: 0.828223 error [darwin_open] USBDeviceOpen: another process has device opened for exclusive access
libusb: 0.828241 info [darwin_open] device open for access
Device successfully opened
Kernel driver doesn't appear to be active
libusb: 0.828641 error [darwin_claim_interface] USBInterfaceOpen: another process has device opened for exclusive access
Unable to claim interface!
libusb: 0.828766 info [event_thread_main] thread exiting
Is there a way I can release the USB device from the other process, freeing it up so I can claim it?
Is there an alternative way I can connect to /dev/tty.usbmodemfa132 to send and receive data to the CDC interface on the USB device?
An alternative to libusb perhaps?
That's right. While libusb seems to be all-powerful in Linux, you cannot use it to connect to a USB CDC interface on Mac OS X because that interface is already claimed by the AppleUSBCDCACM driver.
What you should do is use the standard way that people connect to serial ports. This will be easier because you don't have to worry about endpoints and bulk transfers and such. Here is some example cross-platform C code I wrote for one of our CDC-based products that connects to a COM port to read and write some data (source). It uses the standard functions open, read, and write.
// Uses POSIX functions to send and receive data from a Maestro.
// NOTE: You must change the 'const char * device' line below.
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#ifdef _WIN32
#define O_NOCTTY 0
#else
#include <termios.h>
#endif
// Gets the position of a Maestro channel.
// See the "Serial Servo Commands" section of the user's guide.
int maestroGetPosition(int fd, unsigned char channel)
{
unsigned char command[] = {0x90, channel};
if(write(fd, command, sizeof(command)) == -1)
{
perror("error writing");
return -1;
}
unsigned char response[2];
if(read(fd,response,2) != 2)
{
perror("error reading");
return -1;
}
return response[0] + 256*response[1];
}
// Sets the target of a Maestro channel.
// See the "Serial Servo Commands" section of the user's guide.
// The units of 'target' are quarter-microseconds.
int maestroSetTarget(int fd, unsigned char channel, unsigned short target)
{
unsigned char command[] = {0x84, channel, target & 0x7F, target >> 7 & 0x7F};
if (write(fd, command, sizeof(command)) == -1)
{
perror("error writing");
return -1;
}
return 0;
}
int main()
{
// Open the Maestro's virtual COM port.
const char * device = "\\\\.\\USBSER000"; // Windows, "\\\\.\\COM6" also works
//const char * device = "/dev/ttyACM0"; // Linux
//const char * device = "/dev/cu.usbmodem00034567"; // Mac OS X
int fd = open(device, O_RDWR | O_NOCTTY);
if (fd == -1)
{
perror(device);
return 1;
}
#ifndef _WIN32
struct termios options;
tcgetattr(fd, &options);
options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
options.c_oflag &= ~(ONLCR | OCRNL);
tcsetattr(fd, TCSANOW, &options);
#endif
int position = maestroGetPosition(fd, 0);
printf("Current position is %d.\n", position);
int target = (position < 6000) ? 7000 : 5000;
printf("Setting target to %d (%d us).\n", target, target/4);
maestroSetTarget(fd, 0, target);
close(fd);
return 0;
}
If you want to use some USB device that is also recognised by the Apple FTDI serial driver, you can first unload the driver:
sudo kextunload -b com.apple.driver.AppleUSBFTDI
After that you can use it through libusb normally.
For other devices that are recognised as serial devices, you probably need to unload some other driver.
The problem seems to be due to a conflict between different drivers, which use the same libraries, and in my case they were related to previous Samsung device installations. i had solved this way:
kextstat | grep -v apple
To have a return like this:
70 0 0x57574000 0x3000 0x2000 com.devguru.driver.SamsungComposite (1.2.4) <33 4 3>
72 0 0x57831000 0x7000 0x6000 com.devguru.driver.SamsungACMData (1.2.4) <71 33 5 4 3>
94 0 0x57674000 0x3000 0x2000 com.devguru.driver.SamsungACMControl (1.2.4) <33 4 3>
Then:
$ sudo kextunload -b com.devguru.driver.SamsungComposite
$ sudo kextunload -b com.devguru.driver.SamsungACMData
$ sudo kextunload -b com.devguru.driver.SamsungACMControl
Done. Enjoy

Resources