Weird thing in file-descrpiter I/O for gpio port - c

I'm coding in Linux to control the gpio port on my board, using the following codes. However,the result from read() is always a 0x10, which is a hex for LF line feed.
Voltage is an enum variable having int value of 0 and 1 standing for low and high. fd is the file descripter for the gpio port. 0x30 is hex code for char '0'. There is no error in write().
int set_gpio( int fd,enum voltage_e voltage)
{
const unsigned char w_buff =0x30+voltage;
unsigned char r_buff='2';
if (0 >= write(fd, &w_buff, 1))
{
LOGD(" Error1 in setting gpio to %d", voltage);
return -1;
}
__usr_sleep(0, 10000000);
if (read(fd, &r_buff, 1))
{
if (r_buff != 0x30+voltage)
{
LOGD(" r_buff is %d", r_buff);
return -1;
}
}
else
{
LOGD(" Error3 in setting gpio to %d", voltage);
return -1;
}
return 0;
}

For compatibility with shell utilities, the content of a GPIO port is typically a single character followed by a newline -- for instance:
% xxd /sys/class/gpio/gpio89/value
0000000: 310a 1.
Writing a single character to the GPIO device is advancing the file pointer to the second character, which is always the newline which you're seeing.
You will need to reset the file pointer to the beginning before doing a read/write operation:
lseek(fd, 0, SEEK_SET);

Related

How to handle buffering serial data

I am trying to figure out a nice solution to reading serial data, and what to do when a read() is done but it contains an incomplete message.
The expected messages between devices have a defined start and end byte so its easy to see when a message starts and ends.
I can open a serial port fine and read from the serial port. But I am encountering the computer is reading faster than data coming through and I get an incomplete message.
For this example, lets say the message expected is
0x10 0xFF 0xFF 0xFF 0xFF 0x11
With 0x10 the start, 0x11 the end, and 0xFF is the data bytes
I am new to C so I may be missing something obvious,
My current solution
int main() {
/* Ommited serial port opening and checking*/
char read_buffer[80];
char message_buffer[80];
int message_buffer_index = 0;
int start_index = -1;
int end_index = -1;
int read_bytes;
read_bytes = read(serial_port, read_buffer, sizeof(read_buffer) - 1);
/* Now lets say read_bytes returns 3 and read buffer is {0x10, 0xFF, 0xFF} */
/* What should I do with the read_buffer? Currently appending to message buffer*/
memcpy(&message_buffer[message_buffer_index], &read_buffer[0], read_bytes);
/* Now check the message buffer for a full message */
for (int i = 0; i < 80; i++) {
if (message_buffer[i] = 0x10) {
start_index = i;
continue;
}
if (message_buffer[i] = 0x11) {
end_index = i;
}
if (start_index != -1 && end_index != -1) {
/* Found a message, do something with it, not super important here */
process_message();
/* Now how to erase the full message from the
buffer and push any non processed data to the
front? */
remove_message();
}
}
}
int process_message();
int remove_message();
To minimize the overhead of making many read() syscalls of small byte counts (e.g. the misguided solution of reading a byte at a time), use an intermediate buffer in your code.
The read() of the serial terminal should be in blocking mode to avoid a return code of zero bytes.
#define BLEN 1024
unsigned char rbuf[BLEN];
unsigned char *rp = &rbuf[BLEN];
int bufcnt = 0;
/* get a byte from intermediate buffer of serial terminal */
static unsigned char getbyte(void)
{
if ((rp - rbuf) >= bufcnt) {
/* buffer needs refill */
bufcnt = read(fd, rbuf, BLEN);
if (bufcnt <= 0) {
/* report error, then abort */
}
rp = rbuf;
}
return *rp++;
}
For proper termios initialization code for the serial terminal, see this answer. You should increase the VMIN parameter to something closer to the BLEN value or at least the length of longest expected message, and a VTIME of 1.
Now you can conveniently access the received data a byte at a time with minimal performance penalty.
#define MLEN 1024 /* choose appropriate value for message protocol */
int main()
{
unsigned char mesg[MLEN];
...
while (1) {
while (getbyte() != 0x10)
/* discard data until start found */ ;
length = 0;
while ((mesg[length] = getbyte()) != 0x11) {
/* accumulate data until end found */
length++;
}
/* process the message */
...
} /* loop for next message */
...
}
Note that your detection for a message frame is not robust.
If the data is binary and therefore can use the same values as these start and end bytes, then this parsing of the received data is prone to misaligned message frames.
See this answer for a description of a proper alogrithm.
You need circular buffer. Place data in the buffer and the process takes them when for example there is enough data or in any convenient moment.
Wikipedia has excellent article about it https://en.wikipedia.org/wiki/Circular_buffer
Better use stdio for reading, something like this:
FILE *fp = fdopen(serial_port, "r");
while (blabla) {
while (fgetc(fp) != 0x10)
; // wait until start
while ((c = fgetc(fp)) != 0x11)
message_buffer[message_buffer_index++] = c;
// here you have a complete message
}
Insert checks for EOF and errors if needed

Entire characters in the text file is not getting transmitted in Hi 3520D

I am trying to read some data from a text file and writing it to the ttyUSB* socket id.
I am using Hi3520d Dvr. I have it's RS485 port connected to a "RS485 to RS232 converter". This converter is connected to the PC through a USB port.
The text file is getting read properly to the buffer, but while writing last few lines of the text is not transmitting. This is happening with file with size more than 4.5kb exactly and without usleep() function.
I am using minicom on linux terminal to display both read and written text.
Thanks in advance for looking into this.
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#define Bdrate B9600
int Intserial(char *dev, int Baudrate)
{
//printf("Insterial func\n");
int sid;
int iDebug = -1;
struct termios serial_struct;
sid = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
if (sid > 0)
{
memset(&serial_struct, 0, sizeof(serial_struct)); /* clear the new struct */
serial_struct.c_cflag = Baudrate | CS8 | CLOCAL | CREAD;
serial_struct.c_iflag = IGNPAR;
serial_struct.c_oflag = 0;
serial_struct.c_lflag = 0;
serial_struct.c_cc[VMIN] = 0; /* block untill n bytes are received */
serial_struct.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */
iDebug = tcsetattr(sid, TCSANOW, &serial_struct);
if (iDebug < 0)
{
printf("Err 0\n"); //Unable to set serial port parameters
return (0);
}
}
else
{
printf("Err 1\n"); //Serial port not open
return (0);
}
//printf("sid is %d \n",sid);
return (sid);
}
int main()
{
int sid1 = -1, size = 0, i = 0, x, w;
size_t ln;
FILE *fd;
char buf[2233];
fd = fopen("h.txt", "r");
if (fd)
{
sid1 = Intserial("/dev/ttyAMA1", Bdrate); //RS485 port of Hi3520d
if (sid1 > -1)
{
system("himm 0x200F004C 0"); // commands transmitting and recieving
system("himm 0x201A0400 1");
system("himm 0x201a0004 1");
while (!feof(fd))
{
memset(buf, 0, sizeof(buf));
fread(buf, sizeof(buf), 1, fd);
printf("%s", buf);
write(sid1, buf, sizeof(buf));
usleep(5);
}
getchar();
}
else
printf("com port cant open\r\n ");
fclose(fd);
close(sid1);
}
else
printf("File cant open\r\n");
printf("task completed............\r\n");
}
You have to observe return value of fread for number of bytes read by fread function. the actual read size may not equal to bytes requested, also you have to pass number of bytes read by fread (as valid bytes in buffer) to write function as number of bytes to write.
The code should be something like this
memset(buf,0,sizeof(buf));
size_t bytesRead = fread(buf,sizeof(buf),1,fd);
if(bytesRead > 0)
write(sid1,buf, bytesRead);
Also as LPs said, fread doesn't end buffer with termination character, so passing buffer filled by fread to printf("%s") will be undefined behavior
There are numerous issues with your code, but the salient cause of "the text is not transmitting" is probably the failure to check the return value of
write(sid1, buf, sizeof(buf));
Because the serial terminal was opened in non-blocking mode, each write() will return immediately, before the data has been actually transmitted.
Since the serial terminal is configured for a rather slow 9600 baud, the data could be queued up in the line discipline buffer and other intermediate buffers.
The line discipline buffer is typically 4096 bytes long.
Assuming that the fread() operations are always successful (which you seem to have verified), then the second iteration of the write() of 2233 bytes could potentially saturate the line discipline buffer, and return with a short write return value (which would be ignored).
The third iteration of the write(), if it's quick enough, could then be outright rejected with a return value of -1 and an errno of EAGAIN to indicate that the write would block.
This error condition would be silently ignored, and this 2233 bytes of data will never be transmitted.
This seems to correlate perfectly with your observation of "last few lines of the text is not transmitting ... with file with size more than 4.5kb exactly and without usleep() function."
ADDENDUM
Revised code for blocking mode, proper terminal setup, and checking of return values is shown below.
A corrected version of #e.jahandar's suggestion and comments from #LPs are also incorporated.
...
sid = open(dev, O_RDWR | O_NOCTTY);
if (sid < 0) {
printf("Err 1\n"); //Serial port not open
return (-1);
}
if (tcgetattr(sid, &serial_struct) < 0) {
printf("Err 2\n");
return (-2);
}
cfsetospeed(&serial_struct, (speed_t)Baudrate);
cfsetispeed(&serial_struct, (speed_t)Baudrate);
cfmakeraw(&serial_struct);
serial_struct.c_cc[VMIN] = 1;
serial_struct.c_cc[VTIME] = 10;
serial_struct.c_cflag &= ~CSTOPB;
serial_struct.c_cflag &= ~CRTSCTS; /* no HW flow control? */
serial_struct.c_cflag |= CLOCAL | CREAD;
if (tcsetattr(sid, TCSANOW, &serial_struct) < 0) {
printf("Err 3\n"); //Unable to set serial port parameters
return (-3);
}
...
#define BUFSIZE 2233
char buf[BUFSIZE + 1];
...
size_t frv;
ssize_t wrv;
...
do {
frv = fread(buf, 1, BUFSIZE, fd);
buf[frv] = 0; /* terminate string for printf */
if (frv > 0) {
wrv = write(sid1, buf, frv);
if (wrv < frv) {
/* handle error or short write */
}
} else
break;
} while (1);
...

C: libpcap doesn't capture wlan0 packets

I'm new in C and got little confused. I've read some topics about this problem but none of them worked for me. I'm trying to capture wlan0 packets with libpcap but something goes wrong. pcap_next() function returns null but i can't figure out why. Here is my code:
#include <pcap.h>
#include <stdio.h>
#include <string.h>
void dump(const unsigned char *data_buffer, const unsigned int length) {
unsigned char byte;
unsigned int i, j;
for(i=0; i < length; i++) {
byte = data_buffer[i];
printf("%02x ", data_buffer[i]); // Display byte in hex.
if(((i%16)==15) || (i==length-1)) {
for(j=0; j < 15-(i%16); j++)
printf(" ");
printf("| ");
for(j=(i-(i%16)); j <= i; j++) { // Display printable bytes from line.
byte = data_buffer[j];
if((byte > 31) && (byte < 127)) // Outside printable char range
printf("%c", byte);
else
printf(".");
}
printf("\n"); // End of the dump line (each line is 16 bytes)
} // End if
} // End for
}
int main() {
struct pcap_pkthdr header;
const u_char *packet;
char errbuf[PCAP_ERRBUF_SIZE];
char *device;
pcap_t *pcap_handle;
int i;
device = "wlan0";
printf("Sniffing on device %s\n", device);
pcap_handle = pcap_open_live(device, 4096, 1, 0, errbuf);
for(i=0; i < 3; i++) {
packet = pcap_next(pcap_handle, &header);
printf("Got a %d byte packet\n", header.len);
dump(packet, header.len);
}
pcap_close(pcap_handle);
}
what i get as output is Sniffing on device wlan0 Got a 0 byte packet
Got a 0 byte packet Got a 0 byte packet
This is how i compile gcc -o test test.c -l pcap and run the program as root. Thanks.
pcap_next() returns a pointer to the packet data on success, and
returns NULL if an error occured, or if no packets were read from a
live capture (if, for example, they were discarded because they didn't
pass the packet filter, or if, on platforms that support a read
timeout that starts before any packets arrive, the timeout expires
before any packets arrive, or if the file descriptor for the capture
device is in non-blocking mode and no packets were available to be
read), or if no more packets are available in a ''savefile.''
Unfortunately, there is no way to determine whether an error occured
or not.
http://linux.die.net/man/3/pcap_next
So it could be allright. My suggestion is to check for NULL, do nothing (or i--;) and go on with the next packet. OR use pcap_next_ex() and check for an error.
And does the pcap_open_live() even return a valid handle? Please check the return value.

Write/Read command to the specified port

I use this usb gpio device. It uses some command to send/receive data from input/output channel. There is a guide that explains how commands send on numato website. There are some sample code for C on Windows. But I use fedora and my code is below for read/write gpio. I can't read data.
Code sample for Windows
#include "stdafx.h"
#include "windows.h"
#include "string.h"
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hComPort;
char cmdBuffer[32];
char responseBuffer[32];
DWORD numBytesWritten;
DWORD numBytesRead;
/*
Lookup the port name associated to your GPIO device and update the
following line accordingly. The port name should be in the format
"\\.\COM<port Number>". Notice the extra slaches to escape slashes
themselves. Read http://en.wikipedia.org/wiki/Escape_sequences_in_C
for more details.
*/
wchar_t PortName[] = L"\\\\.\\COM14";
/*
Open a handle to the COM port. We need the handle to send commands and
receive results.
*/
hComPort = CreateFile(PortName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (hComPort == INVALID_HANDLE_VALUE)
{
printf("Error: Unable to open the specified port\n");
return 1;
}
/* EXAMPLE 1 - MANIPULATE GPIO0 BY SENDING COMMAND */
/**************************************************************************
Send a command to output a logic high at GPIO 0. The command that is
used to accomplish this acton is "gpio set 0". It is important to send
a Carriage Return character (ASCII value 0x0D) to emulate the ENTER
key. The command will be executed only when the GPIO module detects
Carriage Return character.
**************************************************************************/
/* Write a Carriage Return to make sure that any partial commands or junk
data left in the command buffer is cleared. This step is optional.
*/
cmdBuffer[0] = 0x0D;
if(!WriteFile(hComPort, cmdBuffer, 1, &numBytesWritten, NULL))
{
CloseHandle(hComPort);
printf("Error: Unable to write to the specified port\n");
return 1;
}
/* Copy the command to the command buffer */
strcpy(cmdBuffer, "gpio set 0");
/* Append 0x0D to emulate ENTER key */
cmdBuffer[10] = 0x0D;
/* Write the command to the GPIO module. Total 11 bytes including 0x0D */
printf("Info: Writing command <gpio set 0> to the GPIO module\n");
if(!WriteFile(hComPort, cmdBuffer, 11, &numBytesWritten, NULL))
{
CloseHandle(hComPort);
printf("Error: Unable to write to the specified port\n");
return 1;
}
printf("Info: <gpio set 0> Command sent successfuly\n");
/* EXAMPLE 2 - MANIPULATE GPIO10 BY SENDING COMMAND */
/**************************************************************************
Send a command to output a logic high at GPIO 0. The command that is
used to accomplish this acton is "gpio set 0". It is important to send
a Carriage Return character (ASCII value 0x0D) to emulate the ENTER
key. The command will be executed only when the GPIO module detects
Carriage Return character.
**************************************************************************/
/* Write a Carriage Return to make sure that any partial commands or junk
data left in the command buffer is cleared. This step is optional.
*/
cmdBuffer[0] = 0x0D;
if(!WriteFile(hComPort, cmdBuffer, 1, &numBytesWritten, NULL))
{
CloseHandle(hComPort);
printf("Error: Unable to write to the specified port\n");
return 1;
}
/*
Copy the command to the command buffer. GPIO number 10 and beyond are
referenced in the command by using alphabets starting A. For example
GPIO10 willbe A, GPIO11 will be B and so on. Please note that this is
not intended to be hexadecimal notation so the the alphabets can go
beyond F.
*/
strcpy(cmdBuffer, "gpio set A");
/* Append 0x0D to emulate ENTER key */
cmdBuffer[10] = 0x0D;
/* Write the command to the GPIO module. Total 11 bytes including 0x0D */
printf("Info: Writing command <gpio set A> to the GPIO module\n");
if(!WriteFile(hComPort, cmdBuffer, 11, &numBytesWritten, NULL))
{
CloseHandle(hComPort);
printf("Error: Unable to write to the specified port\n");
return 1;
}
printf("Info: <gpio set A> Command sent successfuly\n");
/* EXAMPLE 3 - READ ADC 1 */
/**************************************************************************
Write "adc read 1" comamnd to the device and read back response. It is
important to note that the device echoes every single character sent to
it and so when you read the response, the data that is read will
include the command itself, a carriage return, the response which you
are interested in, a '>' character and another carriage return. You
will need to extract the response from this bunch of data.
/*************************************************************************/
/* Write a Carriage Return to make sure that any partial commands or junk
data left in the command buffer is cleared. This step is optional.
*/
cmdBuffer[0] = 0x0D;
if(!WriteFile(hComPort, cmdBuffer, 1, &numBytesWritten, NULL))
{
CloseHandle(hComPort);
printf("Error: Unable to write to the specified port\n");
return 1;
}
/* Flush the Serial port's RX buffer. This is a very important step*/
Sleep(10);
PurgeComm(hComPort, PURGE_RXCLEAR|PURGE_RXABORT);
/* Copy the command to the command buffer */
strcpy(cmdBuffer, "adc read 1");
/* Append 0x0D to emulate ENTER key */
cmdBuffer[10] = 0x0D;
/* Write the command to the GPIO module. Total 11 bytes including 0x0D */
printf("Info: Writing command <adc read 1> to the GPIO module\n");
if(!WriteFile(hComPort, cmdBuffer, 11, &numBytesWritten, NULL))
{
CloseHandle(hComPort);
printf("Error: Unable to write to the specified port\n");
return 1;
}
printf("Info: <adc read 1> Command sent successfuly\n");
/*Read back the response*/
if(!ReadFile(hComPort, responseBuffer, 16, &numBytesRead, NULL))
{
CloseHandle(hComPort);
printf("Error: Unable to write to the specified port\n");
return 1;
}
/* Add a null character at the end of the response so we can use the buffer
with string manipulation functions.
*/
responseBuffer[numBytesRead] = '\0';
printf("Info: ADC value read from the device = %.*s", 4, responseBuffer + 12);
/* Close the comm port handle */
CloseHandle(hComPort);
return 0;
}
My code for Ubuntu
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#define MAXBUFFER 32
int main(int argc, char* argv[])
{
struct termios serialSettings;
char *deviceName = "/dev/ttyACM0";
char bufferRecv[MAXBUFFER], bufferSend[MAXBUFFER];
int readInt, sendInt;
int fd = open(deviceName, O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1) {
printf("\n %s\n", deviceName);
perror("unable to open port");
}
else {
printf("port is opened!\n");
bufferSend[0] = 0x0D; /* clear buffer */
strcpy(bufferSend, "gpio set 0"); /* */
sendInt = write(fd, bufferSend, strlen(bufferSend));
if(sendInt <= 0){
printf("Unable to write to the port\n");
return -1;
}
printf("<gpio set 0> : Command sent successfuly\n");
strcpy(bufferSend, "gpio read 0"); /* */
sendInt = write(fd, bufferSend, strlen(bufferSend));
if(sendInt <= 0){
printf("Unable to write to the port\n");
return -1;
}
printf("<gpio read 0> : Command sent successfuly\n");
readInt = read(fd, bufferRecv, sizeof(bufferRecv));
if(readInt < 0){
printf("Unable to read to the port\n");
return -1;
}
bufferRecv[strlen(bufferRecv)] = '\0';
printf("read=%c-\n", bufferRecv[0]);
}
close(fd);
return 0;
}
The output
port is opened!
<gpio set 0> : Command sent successfuly
<gpio read 0> : Command sent successfuly
Unable to read to the port
The "successful" write() s are false positives. The data was output, but not properly received by the device.
Your program has not properly configured the serial port using termios after the open() and before any write() or read(). You should configure the port for canonical rather than raw mode. You also need to configure the baud rate, character length, parity and number of stop bits.
Use the Serial Programming Guide for POSIX Operating Systems.
Workable(?) configuration code might look like (for 115200 baud rate, 8N1 and canonical input, i.e. read terminates on NL character):
#include <termios.h>
struct termios serialSettings;
speed_t spd;
int fd;
int rc;
fd = open(deviceName, O_RDWR | O_NOCTTY);
if (fd == -1) {
printf("\n %s\n", deviceName);
perror("unable to open port");
return -1;
}
rc = tcgetattr(fd, &serialSettings);
if (rc < 0) {
perror("unable to get attributes");
return -2;
}
spd = B115200;
cfsetospeed(&serialSettings, spd);
cfsetispeed(&serialSettings, spd);
serialSettings.c_cflag &= ~CSIZE;
serialSettings.c_cflag |= CS8;
serialSettings.c_cflag &= ~PARENB;
serialSettings.c_cflag &= ~CSTOPB;
serialSettings.c_cflag &= ~CRTSCTS; /* no HW flow control? */
serialSettings.c_cflag |= CLOCAL | CREAD;
serialSettings.c_iflag &= ~(PARMRK | ISTRIP | IXON | IXOFF | INLCR);
serialSettings.c_iflag |= ICRNL;
serialSettings.c_oflag &= ~OPOST;
serialSettings.c_lflag &= ~(ECHO | ECHONL | ISIG | IEXTEN);
serialSettings.c_lflag |= ICANON;
rc = tcsetattr(fd, TCSANOW, &serialSettings);
if (rc < 0) {
perror("unable to set attributes");
return -2;
}
/* serial port is now configured and ready */
...
Additional comments on your code:
bufferRecv[strlen(bufferRecv)] = '\0';
This is illogical code. If you could actually determine the string length of what's in bufferRecv, then that text would already be null terminated, and this assignment would not be necessary.
Secondly and much worse, the read() does not terminate the receive data with a null byte, so the strlen() could scan past the buffer end.
The read() does return the number of bytes stored in the buffer, and that value can be used to locate where a null byte should be written.
Workable code would look like (note the reduction in requested read length):
readInt = read(fd, bufferRecv, sizeof(bufferRecv) - 1);
if (readInt < 0){
perror("Unable to read from the port\n");
return -3;
}
bufferRecv[readInt] = '\0';
printf("ADC value read = %s\n", bufferRecv);
The strings that you send to the USB device should be preceded and terminated with a carriage return just like the Win examples:
strcpy(bufferSend, "\rgpio set 0\r");
...
strcpy(bufferSend, "\rgpio read 0\r");

Sending Hexadecimal data through Serial Port Communication in Linux

I have got a task of sending hexadecimal data to my COMPORT in linux. I have written this simple C code, but it sends only a decimal number. Can anyone help me in sending an hexadecimal bit.
Here is the code I have written
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
int number,n;
void main(void){
open_port();
}
int open_port(void)
{
int fd; /* File descriptor for the port */
fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyACM0 - ");
}
else{
printf("Port Opened successfully\n");
number = 1;
while(number!=55){
scanf("%d",&number);
n = write(fd, "ATZ\r", number);
if (n < 0)
fputs("write() of 4 bytes failed!\n", stderr);
}
}
return (fd);
}
Please help
Thanks in advance :) :)
write is defined as:
ssize_t write(int fd, const void *buf, size_t count);
That is, it sends count bytes to fd from buf. In your case, the data is always the string "AZTR\r", plus undefined data after that (if count is > 5). Your program sends neither hexadecimal nor decimal data.
Do you want to send binary data or a string of hexadecimal characters?
For option one, you can use: write(fd, somebuffer, len);, where some buffer is a pointer to any set of bytes (including ints, etc).
For option two, first convert your data to a hexadecimal string using sprintf with %02X as the format string, then proceed to write that data to the port.
There are several problems with the code:
The text read from the console is interpreted as decimal ("%d"); if you want it to be interpreted as hexadecimal, use "%x".
The write() is pathological. The third argument is the number of bytes to write, not the value. It should be either
n = write (fd, "ATZ\r", 4); // there are 4 bytes to write to init the modem
or
char buf[10];
n = sprintf (buf, "%x", number); // convert to hex
n = write (fd, buf, n); // send hex number out port
This function will take a hex string, and convert it to binary, which is what you want to actually send. the hex representation is for humans to be able to understand what is being sent, but whatever device you are communicating with, will probably need the actual binary values.
// Converts a hex representation to binary using strtol()
unsigned char *unhex(char *src) {
unsigned char *out = malloc(strlen(src)/2);
char buf[3] = {0};
unsigned char *dst = out;
while (*src) {
buf[0] = src[0];
buf[1] = src[1];
*dst = strtol(buf, 0, 16);
dst++; src += 2;
}
return out;
}

Resources