Using glib to send raw bytes to an FTDI device over USB - c

I am developing a simple application in C with GTK+2.0 GUI, on Linux of course, this application is designed to control a device which is connected over the USB port and is using FTDI driver to emulate RS232 asynchronious protocol over the USB port.
I am using the function g_io_channel_write_chars() to send data to the device. The problem is the sequence I am sending consist a lot of values that are ASCII but do not match any (visible) character.
For example, when I am sending \x40\x40\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01 it won't work. The program will stop with an error.
GLib:ERROR:/build/buildd/glib2.0-2.34.1/./glib/giochannel.c:2382:g_io_channel_write_chars: code should not be reached
Przerwane (core dumped)
If I use sprintf function to put this sequence in a table only first two values will be copied and this sequence will be send to the device without an error.
Then my question is, how can I send any bytes to the device. Is there an equivalent of g_io_channel_write_chars() for this? I've been studying the documentation of GIOChannel and haven't found anything like this. Thanks very much for your help.

You need to make sure the channel doesn't think it's sending text. The crash you're getting is probably due to GIO trying to validate your data against its idea of the channel's encoding.
Note that the default encoding is UTF-8, and since not all byte sequences are valid UTF-8, this can easily cause validation to fail for random binary data.
Call g_io_channel_set_encoding with the argument NULL, this will make it safe for binary data:
The encoding NULL is safe to use with binary data.

Related

Forcing raw serial mode in C - linux

Not sure how to word the title, but what I'm trying to do is test my micro controller with my Linux PC to ensure data is correct. After hours of searching, I found out that the stty command can change how data is managed through the serial port and it turned out that by default if xon or xoff characters are received from the port, they don't get displayed. At first I thought my computer was too slow that I was losing characters at 57.6Kbps but that wasn't the case.
Back in the day when I was playing with the serial mouse in QuickBasic for DOS, I could use this command to start the serial port:
OPEN "com1:1200,n,7,1,op0" for binary as #1
So what I want to do now is create something simple in C that would allow me to open up the serial port in the rawest mode possible. I want it so that whatever data I give to it is sent to it unmodified. I also want to receive data unmodified. so if the controller decides to send a character the PC would recognize as a special control code, I still want to see the character, not have the PC go funny just because a character matches a control code.
One idea I thought of is to create a fork to the stty program and use nearly every (50+?) parameters added to the program making the requirement of program stack space a bit high.
Another idea I thought of is to do direct I/O with the port address itself (using inb and outb) but I'm not sure if the kernel would run those commands through anything else before the data reaches the port, but I'd rather use that as a last option in case I ever replace my computer and the serial port value changes (or becomes a serial port made through USB to serial converter hardware).
so rather than inb and outb and those variants (like inw), and without executing stty with specifying 50+ parameters in my program, is there a function in C I can use (without requiring a special library not included with a standard linux distribution) to force the serial port device as a raw device so I can do any I/O on it without the kernel modifying or dropping data?

Windows API - IOCTL_CHANGER_GET_PRODUCT_DATA always returning ERROR_INVALID_PARAMETER

I am the author of a communication library which needs to be able to communicate with serial devices and USB devices, through libusb and the native driver which corresponds to our case (CESG502, made by CASIO). Serial and libusb communication are both managed, I now want to integrate the use of CESG502 (the driver made for what we want).
The main problem comes from this driver : instead of managing the buffering the same way serial drivers do (if more data is received, it is stored until the user asks it), it expects the developer to provide a bigger buffer than data is received. This leads to two incompatible uses of ReadFile, where I have to only put the number of bytes I want to actually receive (serial, otherwise it just waits for the rest which will never come) or the size of the buffer (CESG502; if I don't do this, the driver returns a ERROR_GEN_FAILURE).
The driver is proprietary, so I cannot correct it. Because of the design of my library, I need to identify if the driver is CESG502 or not in order to work in most cases the library is made to work in. I have looked and found IOCTL_CHANGER_GET_PRODUCT_DATA, which looks like could bring the information I'm looking for. So I tried to use it here:
/* get product data */
CHANGER_PRODUCT_DATA ProductData; DWORD ReturnedBytes = 0;
DWORD wsuccess = DeviceIoControl(fhandle, IOCTL_CHANGER_GET_PRODUCT_DATA,
NULL, 0, &ProductData, sizeof(CHANGER_PRODUCT_DATA),
&ReturnedBytes, 0);
if (wsuccess) logr_info("SUCCESS!");
else logr_info("Error #0x%08lx occurred", GetLastError());
Unfortunately, I continuously receive the 0x57 (ERROR_INVALID_PARAMETER) error, which also occurs with serial devices. I am following what the page said, I have tried plenty of things (setting ReturnedBytes to sizeof(CHANGER_PRODUCT_DATA), initializing ProductData, reading the data anyway, ...) and I have found out where this error comes from...
Thanks in advance if you know how to solve this :)

Is it possible to write a packet, read by libpcap, with libnet? in c?

I'm trying to get libpcap to read a pcap file, get the user to select a packet and write that packet using libnet, in c.
I got the reading from file part done. Libpcap puts that packet into a const unsigned char. I have worked with libnet before, but never with libnet's advanced functions. I would just create the packet using libnet's build functions, then let them on their way. I realize there is a function, libnet_adv_write_link() that takes the libnet context, a pointer to a packet to inject(const uint8_t) and the size of the packet. I tried passing the 'packet' that I got from libpcap, and it compiled and executed without errors. However, I am not seeing anything in wireshark.
Would this be the right way to tackle this problem, or should I read from libpcap and build a separate packet with libnet, based on what libpcap read?
EDIT: I believe I somewhat solved the problem. I read the packet with libpcap. Put all the bytes after the 16th byte into another uchar and wrote that into the wire. using libnet_adv_write_raw_ipv4(), libnet initialized with LIBNET_RAW4_ADV. I believe, maybe because of the driver, I don't have much power over the ETH layer. so basically I just let it be written automatically this way, and the new uchar packet is just whatever is left after the ETH layer in the original packet. Works fine so far.
I'm the current libnet maintainer.
You should call libnet_write_link() to write a packet. If you aren't seeing it, its possible you haven't opened the correct device, that you lack permissions (you checked the return value of libnet_write_link I hope), and also possible that the packet injected was invalid.
If you don't need to build the packet, it sounds like you should be using pcap to send the packet, though, see http://www.tcpdump.org/manpages/pcap_inject.3pcap.html
Also, your statement "Libpcap puts that packet into a const unsigned char" is odd. A packet doesn't fit in a single char, what pcap does is, depending on the API, return pointers into the packet data. Its worth including a snippet of code showing how you get the packet from data, and how you pass it to libnet. Its possible you aren't using the pointers correctly.
If you are using libpcap, why not use libpcap to send the packet? No, it's not well known, but yes it does work. See the function pcap_sendpacket.
The packet libpcap returns is simply an array of bytes. Anything that takes an array of bytes (including the ethernet frame) should work. However, note that your OS and/or hardware may stop you from sending packets with incorrect or malformed source MAC addresses.

C Linux Device Programming - Reading Straight from /Dev

I have been playing with creating sounds using mathematical wave functions in C. The next step in my project is getting user input from a MIDI keyboard controller in order to modulate the waves to different pitches.
My first notion was that this would be relatively simple and that Linux, being Linux, would allow me to read the raw data stream from my device like I would any other file.
However, research overwhelmingly advises that I write a device driver for the MIDI controller. The general idea is that even though the device file may be present, the kernel will not know what system calls to execute when my application calls functions like read() and write().
Despite these warnings, I did an experiment. I plugged in the MIDI controller and cat'ed the "/dev/midi1" device file. A steady stream of null characters appeared, and when I pressed a key on the MIDI controller several bytes appeared corresponding to the expected Message Chunks that a MIDI device should output. MIDI Protocol Info
So my questions are:
Why does the cat'ed stream behave this way?
Does this mean that there is a plug and play device driver already installed on my system?
Should I still go ahead and write a device driver, or can I get away with reading it like a file?
Thank you in advanced for sharing your wisdom in these areas.
Why does the cat'ed stream behave this way?
Because that is presumably the raw MIDI data that is being received by the controller. The null bytes are probably some sort of sync tick.
Does this mean that there is a plug and play device driver already installed on my system?
Yes.
However, research overwhelmingly advises that I write a device driver for the MIDI controller. The general idea is that even though the device file may be present, the kernel will not know what system calls to execute when my application calls functions like read() and write().
<...>
Should I still go ahead and write a device driver, or can I get away with reading it like a file?
I'm not sure what you're reading or how you're coming to this conclusion, but it's wrong. :) You've already got a perfectly good driver installed for your MIDI controller -- go ahead and use it!
Are you sure you are reading NUL bytes? And not 0xf8 bytes? Because 0xf8 is the MIDI time tick status and is usually sent periodically to keep the instruments in sync. Try reading the device using od:
od -vtx1 /dev/midi1
If you're seeing a bunch of 0xf8, it's okay. If you don't need the tempo information sent by your MIDI controller, either disable it on your controller or ignore those 0xf8 status bytes.
Also, for MIDI, keep in mind that the current MIDI status is usually sent once (to save on bytes) and then the payload bytes follow for as long as needed. For example, the pitch bend status is byte 0xeK (where K is the channel number, i.e. 0 to 15) and its payload is 7 bits of the least significant byte followed by 7 bits of the most significant bytes. Thus, maybe you got a weird controller and you're seeing only repeated payloads of some status, but any controller that's not stupid won't repeat what it doesn't need to.
Now for the driver: have a look at dmesg when you plug in your MIDI controller. Now if your OSS /dev/midi1 appears when you plug in your device (udev is doing this job), and dmesg doesn't shoot any error, you don't need anything else. The MIDI protocol is yet-another-serial-protocol that has a fixed baudrate and transmits/receives bytes. There's nothing complicated about that... just read from or write to the device and you're done.
The only issue is that queuing at some place could result in bad audio latency (if you're using the MIDI commands to control live audio, which I believe is what you're doing). It seems like those devices are mostly made for system exclusive messages, that is, for example, downloading some patch/preset for a synthesizer online and uploading it to the device using MIDI. Latency doesn't really matter in this situation.
Also have a look at the ALSA way of playing with MIDI on Linux.
If you are not developing a new MIDI controller hardware, you shouldn't worry about writing a driver for it. It's the user's concern installing their hardware, and the vendor's obligation to supply the drivers.
Under Linux, you just read the file. Now to interpret and make useful things with the data.

Send file over serial port with Linux and C

I'm developing an application that reads data from a serial port and sends it over a TCP connection, and vice versa. Unfortunately, while reading data from serial port, it never stops. It does not detect EOF mark, nor EOL or some other special character.
So, how could i detect an end of file (or "end of connection") over serial port in C and Linux?
Depends on how much control you have over the protocol used for the serial link. Unless the files implicitly include some end-of-file marker (and as I've understood your post they don't), you need to implement some kind of communication protocol in order to transfer files.
Some of the most simple procols used way back in the BBS days were XMODEM and it's derivatives. They may be simple enough for you to use.
If you have a full-blown computer at the other end of the serial line, it would probably be far simpler just to set up an PPP link over the serial line and do the communication over TCP/IP.
Serial link only sends bytes. There is no packet frame, no error checking so you can't send files reliably over raw serial link. You need to use some protocol like XMODEM, KERMIT etc.
It's not trivial to implement such protocol. It may be easier to run TCP/IP over the link if the other end is also a computer. Please check out SLIP or PPP.
The serial port gives "end of file" on a hangup condition, which is signalled out-of-band by the modem control lines (dropping of DCD). If you're connected with a null-modem, that'll never happen.
Use a framing mechanism, like the other answers have suggested. You may not need to go the whole hog with something like ZMODEM though - just prefixing your file with the file size and a CRC32 checksum should do, if the link is reasonably error-free and 8-bit clean.
Check your serial port configuration:
stty -F /dev/ttySx -a
Set cooked link instead of raw link:
stty -F /dev/ttySx cooked
cheap and dirty solution:
on linux, unix or osx just run 'screen -L <serial_device> <baudrate>'. At the other end write the output of your file to the console, in raw mode. -L logs it to a file the contents of which will be the file you transfered from the other end. Check the contents with xxd to verify they match what you had at the source.

Resources