Talking to a power supply via mac os x using a usb-serial converter - linux

I am trying to talk to a power supply from my mac OS X Yosemite. The code works fine on a linux machine, but when I try it on my mac, it does not work. I am using a usb-serial converter and have downloaded the PL-2303 driver. The driver shows up in my /dev folder as cu.usbserial and tty.usbserial.
The part of my code that fails:
fd = initserial("/dev/cu.usbserial");
int initserial(char port[])
{
struct termios shimtermios;
int fd;
if((fd=open(port,O_RDWR)) < 0) {
perror("Opening the RS-232 port failed for initserial\n");
exit(-1);
}
if (tcgetattr(fd, &shimtermios) < 0) {
perror("couldn't get terminal attributes\n");
exit(-2);
}
shimtermios.c_iflag=012005;
shimtermios.c_oflag=014004;
shimtermios.c_cflag=03206276;
shimtermios.c_lflag=05060;
cfsetospeed(&shimtermios,B19200);
if (tcsetattr(fd, TCSAFLUSH, &shimtermios) < 0) {
perror("couldn't set terminal attributes\n");
exit(-3);
}
return (fd);
}
I get the following error message
couldn't set terminal attributes
: Invalid argument
Please let me know if you have any experience with this linux/unix issue. Thank you so much!

See the termios man page for the valid masks that can be used for c_iflag, c_oflag, c_cflag, and c_lflag). You should OR the mask constants together rather than hard-coding the values.
Also from experience, FTDI USB-serial converters tend to work better on OS X than pl2303. OS X has a built-in driver for these (AppleUSBFTDI).

Related

How to access input device driver from userspace

I'm currently developing an input subsystem driver for touchscreen. What I don't know is how to access the device from userspace, e.g. how to open a file that should be created in filesystem.
What I've done so far is this:
After I insmod the driver, I get the following message in dmesg:
input: driver_name as /devices/platform/soc/3f804000.i2c/i2c-1/1-0038/input/input0
Now when I go at this location, I find input0, which is a directory. In this directory, I can find files such as name, properties, uevent, but none of the files here contains touch data.
My question here is, where does input subsystem puts touch data after I call
input_report_abs(data.input, ABS_X, coord_x);
input_report_abs(data.input, ABS_Y, coord_y);
input_sync(data.input);
SOLVED:
Once you do insmod, new file is created under /dev/input, in my case it was event0 file. In order to test the functionality, you can do evtest input0. This file can be used from a userspace program in the following way:
struct input_event ev;
FILE* fd = open("/dev/input/event0", O_RDWR);
while(1)
{
int count = read(fd, &ev, sizeof(struct input_event);
for(int i = 0; i < (int)count / sizeof(struct input_event); i++)
{
if(EV_KEY == ev.type) // printf ...
if(EV_ABS == ev.type) // printf ...
}
}
Hope this will help somebody because I feel like this isn't covered enough in Documentation.

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

How to activate phyless linux Ethernet driver

I was trying to activate Linux phyless Ethernet driver. There are no much information on net. I am using ARM based Linux kernel SOC is connected to a 1GBPS RGMII port back to back without having a real PHY. Came to know Linux has fixed phy support. Some of the files have used fixed_phy_add function. But still not getting clear idea how to activate. Any kind of help or pointer will really help here.
Yeah. I have just done this for our board. What really confused me was that you need to add the fixed phy before the fixed mdio bus is activated. So either you need to add it early in your platform init code or hack it into the fixed mdio code like I did (just to get things working, of course). This patch did it for me.
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index ba55adf..7013ef0 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
## -203,11 +203,24 ## err_regs:
}
EXPORT_SYMBOL_GPL(fixed_phy_add);
+static struct fixed_phy_status fixed_phy_status = {
+ .link = 1,
+ .speed = 100,
+ .duplex = 0,
+};
+
static int __init fixed_mdio_bus_init(void)
{
struct fixed_mdio_bus *fmb = &platform_fmb;
int ret;
+ ret = fixed_phy_add(PHY_POLL, 0, &fixed_phy_status);
+ if (ret < 0)
+ {
+ pr_err("could not add fixed phy.\n");
+ return ret;
+ }
+
pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
The next step is to use this phy in your driver, it should be enough to use the name fixed-0:00 as the phy name when you look it up (the :00 is the fixed phy id 0 in the
fixed_phy_add above)
snprintf(phy_id, sizeof(slave_data->phy_id), PHY_ID_FMT, "fixed-0", 0);
Then the phy_connect your driver already has should find the fixed phy and it should work
as long as the fixed configuration matches the other side (a switch in our case):
phy_connect(ndev, phy_id, &_adjust_link, phy_if);
There should be a method to make all this work with device tree too but no-one has gotten there yet, AFAICS.
Good Luck.

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

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.

How to detect USB device disconnect under Linux/Qt/C++

I'm writing a system (X-Platform Windows/Linux) that talks to a custom device using an FTDI USB chip. I use their D2XX driver for device open/close/read/write. So far, so good.
I need to know when the device is disconnected so the program can respond gracefully. At present, under Windows the application receives a sudden unexpected close. Under Linux, when the device is disconnected, there is a sgementation fault.
I have found informaiton under Windows about listening for the WM_DEVICECHANGE message. However, I have not found how to detect this event under Windows. There is information for the device driver level interacting with the kernel. However, I can't figure out how to do this at an application level. The FTDI driver does not offer any such service.
The system is written using the Qt framework with C++. The device driver is FTDI's D2XX driver.
Can anyone point me in the right direction?
Thanks so much in advance!
Judy
You'll probably want to use HAL (freedesktop.org's Hardware Abstraction Layer).
In the future you will probably want to use DeviceKit. It is a project fix the many problems with HAL. It hasn't been adopted by all major distros yet though (I think just Fedora), so you probably don't want to use it right now.
Edit: As Jeach said, you can use udev also. I wouldn't suggest this, as it is much lower level, and harder to program, but if latency is very important, this might be the best option.
Although what I'm about to tell you won't directly answer your question, it may give you a hint as to your next move.
I use udev rules configured in '/etc/udev/rules.d/' which run various scripts. When a USB device gets connected/disconnected I run a script which sends a HUP signal to my binary. Since my requirements can handle a bit of lag it works perfectly fine for me.
But my point is that maybe there is a udev library you can link to and register events programmatically (instead of scripts).
Hope it helps... good luck!
I recently had a project which involved reading via an FTDI chip. I also tried using libftdi but found out that it is much simpler to use /dev/ttyUSB* for reading and writing. This way, you can use QFile('/dev/ttyUSB*') to write and read. You can also check if the device actually exists and it won't segfault. Of course, this is not a very 'Platform independent' way. To get a platform independent method, you can use a Serial library for Qt.
You obviously have to write different implementations for the different operating systems unless you want to create a thread to continuously run:
FT_ListDevices(&numDevs, nullptr, FT_LIST_NUMBER_ONLY);
and enumerate the devices if numDevs changed compared to previous checks.
If you are like me and don't really like to do that sort of continuous polling on your USB devices then you will have to target your specific operating system.
Here's a link to some sample code from FTDI:
http://www.ftdichip.com/Support/SoftwareExamples/CodeExamples/VC.htm
Example 7 shows how to detect the USB insertion and removal on windows:
http://www.ftdichip.com/Support/Documents/AppNotes/AN_152_Detecting_USB_%20Device_Insertion_and_Removal.pdf
On Linux I can personally recommend using udev.
This code is for enumerating the devices:
#include <sys/types.h>
#include <dirent.h>
#include <cstdlib>
#include <libudev.h>
#include <fcntl.h>
struct udev *udev = udev_new();
if (!udev) {
cout << "Can't create udev" <<endl;
}
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "usb");
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry *dev_list_entry, *devices = udev_enumerate_get_list_entry(enumerate);
struct udev_device *dev;
udev_list_entry_foreach(dev_list_entry, devices) {
const char *path;
path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(udev, path);
if( udev_device_get_devnode(dev) != nullptr ){
string vendor = (std::string) udev_device_get_sysattr_value(dev, "idVendor");
string product = (std::string) udev_device_get_sysattr_value(dev, "idProduct");
string description = (std::string)udev_device_get_sysattr_value(dev, "product");
cout << vendor << product << description << endl;
}
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
This code I put in a separate thread that waits to receive an insertion or a removal event
struct udev_device *dev;
struct udev_monitor *mon = udev_monitor_new_from_netlink(udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", NULL);
udev_monitor_enable_receiving(mon);
int fd = udev_monitor_get_fd(mon);
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1){
debugError("Can't get flags for fd");
}
flags &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
while( _running ){
cout << "waiting for udev" << endl;
dev = udev_monitor_receive_device(mon);
if (dev && udev_device_get_devnode(dev) != nullptr ) {
string action = (std::string)udev_device_get_action(dev);
if( action == "add" ){
cout << "do something with your device... " << endl;
} else {
string path = (std::string)udev_device_get_devnode(dev);
for( auto device : _DevicesList ){
if( device.getPath() == path ){
_DevicesList.erase(iter);
cout << "Erased Device from list" << endl;
break;
}
}
}
udev_device_unref(dev);
}
}
udev_monitor_unref(mon);
some of the functions and variables are obviously not defined when you copy/paste this code.
I keep a list of detected devices to check the path and other information like the location ID of the inserted device. I need the location ID later to FT_OpenEx via FT_OPEN_BY_LOCATION. To get the location id I read the contents of the following files:
string getFileContent(string file ){
string content = "";
ifstream readfile( file );
if( readfile.is_open() ){
getline(readfile, content );
readfile.close();
}
return content;
}
string usbdirectory = "/sys/bus/usb/devices";
string dev1content = getFileContent(usbdirectory+"/usb"+udev_device_get_sysattr_value(dev, "busnum" )+"/dev");
int dev1num = std::atoi(dev1content.substr(dev1content.find_first_of(":")+1).c_str());
string dev2content = (std::string)udev_device_get_sysattr_value(dev, "dev");
int dev2num = std::atoi(dev2content.substr(dev2content.find_first_of(":")+1).c_str());
int locationid = dev1num+dev2num+257;
I can't guarantee that the locationid is correct but it seemed to work for me until now.
Don't forget that you have two problems here :
Detecting device insertion / removal
Properly terminating your application.
The first problem has been adressed by Zifre.
But the second problem remains : your Linux app should not be segfaulting when the device is removed, and I think the two problems are unrelated : if the device is removed in the middle of a write or read system call, then those system call will return with an error before you get any notification, and this should not segfault your app.

Resources