I am trying to send printf data to my uart device.
I have suitablely written write_r() funciton.
The problems that I am having is,
When I say printf(" My name is sam \n I am fine ");
and in next time when i say printf(" I am back ");
1st problem : I can see only "My name is Sam", then the cursor goes to next line and stops there.
2nd problem : "I am back" is not getting printed at all.
I tried by removing \n , still the 2nd printf doesn't get printed.
There is nothing wrong with the uart.
Looks like then \ is reached the pointer is lost.
My Code
int write(int file, char *ptr, int len) {
#if !defined( OUT_8 )
#define OUT_8(p,d) (*(volatile char *)(p) = (char)(d))
#endif
#if !defined( IN_8 )
#define IN_8(p) ((*(volatile char *)(p)))
#endif
OUT_8(DUART1_UMCR1, 0x02); //Informs external modem or peripheral that the UART is ready for sending data
OUT_8(DUART1_ULCR1, 0x03);
OUT_8(DUART1_UIER1, 0x0f);
OUT_8(DUART1_UFCR1, 0x8f);
OUT_8(DUART1_UTHR, '\n');
OUT_8(DUART1_UTHR, '\r');
while (ptr!=NULL)
{
if (*ptr=='\n') // JUST A TRY to avoid \n bug
{
OUT_8(DUART1_UTHR, '\n');
wait();
*ptr++;
*ptr++;
OUT_8(DUART1_UTHR, *ptr++); // \n & \r when given through printf isNot working
wait();
}
OUT_8(DUART1_UTHR, *ptr++); // \n & \r when given through printf is not working
wait(); // TODO:
if(len==0)
break;
else
len--;
}
OUT_8(DUART1_UMCR1, 0x00); // say that modem is not not ready. Connection over
OUT_8(DUART1_UFCR1, 0x87);
OUT_8(DUART1_ULCR1, 0x00); // Clear all the interrupts ! virtually shut the UART port
errno = ENOSYS;
return -1;
}
Confident that OP's I/O is buffered somewhere.
Output does not appear until a \r and/or \n is sent.
#if !defined( OUT_8 )
#define OUT_8(p,d) (*(volatile char *)(p) = (char)(d))
#endif
// make ptr a `const char *`
int write(int file, const char *ptr, int len) {
OUT_8(DUART1_UMCR1, 0x02); //Informs UART is ready for sending data
OUT_8(DUART1_ULCR1, 0x03);
OUT_8(DUART1_UIER1, 0x0f);
OUT_8(DUART1_UFCR1, 0x8f);
while (len-- > 0) {
OUT_8(DUART1_UTHR, *ptr++);
wait();
}
// Force an EOL at the _end_ of transmission.
OUT_8(DUART1_UTHR, '\n');
OUT_8(DUART1_UTHR, '\r');
wait();
OUT_8(DUART1_UMCR1, 0x00); // say that modem is not not ready. Connection over
OUT_8(DUART1_UFCR1, 0x87);
OUT_8(DUART1_ULCR1, 0x00); // Clear all interrupts! virtually shut UART port
errno = ENOSYS;
return -1;
}
I suspect that the buffering is occurring in the receiving side, either the UART or more likely in the terminal viewing the data. OP said "the curser goes to next line". There is no "cursor" in a UART.
Try calling fflush() to force printing without a \n.
Related
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
I am using an example code from the wiringPi library to read data from Arduino to Raspberry Pi through serial, it is displaying the data correctly with printf("%c", newChar); but I can't write the same data to a text file.
This is the whole file:
/*
Pi_Serial_test.cpp - SerialProtocol library - demo
Copyright (c) 2014 NicoHood. All right reserved.
Program to test serial communication
Compile with:
sudo gcc -o Pi_Serial_Test.o Pi_Serial_Test.cpp -lwiringPi -DRaspberryPi -pedantic -Wall
sudo ./Pi_Serial_Test.o
*/
// just that the Arduino IDE doesnt compile these files.
#ifdef RaspberryPi
//include system librarys
#include <stdio.h> //for printf
#include <stdint.h> //uint8_t definitions
#include <stdlib.h> //for exit(int);
#include <string.h> //for errno
#include <errno.h> //error output
//wiring Pi
#include <wiringPi.h>
#include <wiringSerial.h>
char device[]= "/dev/ttyAMA0";
// filedescriptor
int fd;
unsigned long baud = 9600;
unsigned long timeTemp=0;
unsigned long timeHum=0;
//unsigned long timeLight=0;
//unsigned long timeMotion=0;
//prototypes
int main(void);
void loop(void);
void setup(void);
void setup(){
printf("%s \n", "Raspberry Startup!");
fflush(stdout);
//get filedescriptor
if ((fd = serialOpen (device, baud)) < 0){
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
exit(1); //error
}
//setup GPIO in wiringPi mode
if (wiringPiSetup () == -1){
fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
exit(1); //error
}
}
void loop() {
// Temperature every 3 seconds
if(millis()-timeTemp>=3000){
serialPuts (fd, "05\n");
// you can also write data from 0-255
// 65 is in ASCII 'A'
//serialPutchar (fd, 5);
timeTemp=millis();
}
// read signal
if(serialDataAvail (fd)){
char newChar = serialGetchar (fd);
FILE * writeTemp = fopen("temp.txt", "w");
printf("%c", newChar);
fputc(newChar, writeTemp);
fflush(stdout);
fclose(writeTemp);
}
// Humidity every 4 seconds
if(millis()-timeHum>=4000){
serialPuts (fd, "06\n");
// you can also write data from 0-255
// 65 is in ASCII 'A'
//serialPutchar (fd, 5);
timeHum=millis();
}
// read signal
if(serialDataAvail (fd)){
char newChar = serialGetchar (fd);
//printf("received from ardiono \n");
printf("%c", newChar);
fflush(stdout);
}
}
// main function for normal c++ programs on Raspberry
int main(){
setup();
while(1) loop();
return 0;
}
#endif //#ifdef RaspberryPi
I've tried different commands, but I'm constantly getting errors for invalid conversions from const char* to char or to FILE.
I just need to write the data from printf("%c", newChar); in a file.
In the line fputc(&newChar, writeTemp);, you're taking a pointer to your character, converting it to int, then writing that to your file. You should just write your character; something like fputc(newChar, writeTemp);. Or fprintf(writeTemp, "%c", newchar); if you prefer printf.
fputc takes a int, not an address. The problem that you are having is because you are passing the address of newChar. change the code to
fputc(newValue, tempFile);
and you should be good to go.
Good luck :)
If you want a printf-like function, use fprintf.
To write your output to a file, you would write
fprintf(writeTemp, "%c", newChar);
Also, the line
char value = printf("%c", newChar);
does not make sense, since value is declared as a char but is assigned the return status from printf.
As another reply points out, the arguments to fputc() are also wrong. You can write
fputc(newChar, writeTemp);
Using append instead of write somehow fixed the problem:
FILE * writeTemp = fopen("temp.txt", "a");
I also had to remove the second request:
/*
// Humidity every 3 seconds
if(millis()-timeHum>=3000){
serialPuts (fd, "06\n");
timeHum=millis();
}
// read signal
if(serialDataAvail (fd)){
char humChar = serialGetchar (fd);
printf("%c", humChar);
fflush(stdout);
}
*/
because it was interfering with the data for some reason, even with different char variable.
Thank you for the answers.
I am making a device driver that turns on and off the keyboard leds by receiving any combination of three, two, one or none digit which should be 1, 2 or 3, if I make:
echo 12 > /dev/ledDevice
The program should turn on Num lock, Caps lock and turn off scroll lock, if I write:
echo "" > /dev/ledDevice
Every led should be turned off, or turn on if it would be echo 123 but this does not happen, they always turn off. They are ubicated (in debian 6) in a port represented with an integer, in the positions o, 1 and 2. Additionally but I don't know if it's related, outb produce this exit on system log
atkbd.c: Spurious ACK on isa0060/serio0. Some program might be trying access hardware directly.
This is my source
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
char aux[BUF_LEN];
int state = 0x00;
int stateInitial = 0x00;
int i =0;
int timeout = 0;
int retries = 7;
printk(KERN_ALERT "Entering device_write");
if(copy_from_user(aux,buff,len)){
printk(KERN_ALERT "Problems in copy from user");
return -EINVAL;
}
if (len <= 4){
for (i=0; i<len;i++){
if(aux[i] == '3'){
state = state | 0x01; //Scroll lock
}else if(aux[i] == '1'){
state = state | 0x02; //Caps lock
}else if(aux[i]== '2'){
state= state | 0x04; //Num lock
}else if (aux[i] != '\n'){
printk(KERN_ALERT "Error, wrong input.");
return -EINVAL;
}
}
}else return -EINVAL;
if (down_interruptible(&mtx)) /*SEMAPHORE LOCK*/
return -EINTR;
stateInitial = inb(0xed);
stateInitial = stateInitial & 0xF8; //248 mask that deletes the 1, 2 and 3 bits (the led ones)
state = stateInitial | state;
/*
AquĆ se modifican los leds
*/
timeout = 1000;
outb(0xed,0x60); // Telling the keyboard that we want to modify the leds
udelay(timeout);
while (retries!=0 && inb(0x60)!=0xfa) { // Waiting for the controller
retries--;
udelay(timeout);
}
if (retries!=0) { // prooving the keyboard is ready
outb(state,0x60);
}else{
up(&mtx);
return -EINVAL;
}
up(&mtx);
printk(KERN_ALERT "getting out from device_write, %d bytes read",len);
return len;
}
This can be triggered in a myriad of situations. Quite a few key switchers and other tools trigger the ATKBD_RET_NAK and in some cases we sure are helpless.
Considering your code to be just, let us try to break the error code. From the looks of it, the error seems to arise from the atkbd_interrupt call.
atkbd_interrupt() deals with the processing of data received from the keyboard to events.
static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char
data, unsigned int flags)
{----}
The specific error message occurs due to the triggering of case ATKBD_RET_NAK coupled to unsigned char data argument.
case ATKBD_RET_NAK:
if (printk_ratelimit())
dev_warn(&serio->dev,
"Spurious %s on %s. "
"Some program might be trying access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
The atkbd provides access to AT enhanced keyboard connected to the AT keyboard controller. Try bypassing KVM .
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);
I'm using Linux console and I would like to do a program which outputs random characters until ESC is pressed. How can I make such a keyboard handler?
The line discipline for a terminal device often works in canonical mode by default. In this mode, the terminal driver doesn't present the buffer to userspace until the newline is seen (Enter key is pressed).
You can set the terminal into raw (non-canonical) mode by using tcsetattr() to manipulate the termios structure. Clearing the ECHO and ICANON flags respectively disables echoing of characters as they are typed and causes read requests to be satisfied directly from the input queue. Setting the values of VTIME and VMIN to zero in the c_cc array causes the read request (fgetc()) to return immediately rather than block; effectively polling stdin. The call to fgetc() will return EOF if a character is not available in the stream.
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
int getkey() {
int character;
struct termios orig_term_attr;
struct termios new_term_attr;
/* set the terminal to raw mode */
tcgetattr(fileno(stdin), &orig_term_attr);
memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
new_term_attr.c_lflag &= ~(ECHO|ICANON);
new_term_attr.c_cc[VTIME] = 0;
new_term_attr.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
/* read a character from the stdin stream without blocking */
/* returns EOF (-1) if no character is available */
character = fgetc(stdin);
/* restore the original terminal attributes */
tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
return character;
}
int main()
{
int key;
/* initialize the random number generator */
srand(time(NULL));
for (;;) {
key = getkey();
/* terminate loop on ESC (0x1B) or Ctrl-D (0x04) on STDIN */
if (key == 0x1B || key == 0x04) {
break;
}
else {
/* print random ASCII character between 0x20 - 0x7F */
key = (rand() % 0x7F);
printf("%c", ((key < 0x20) ? (key + 0x20) : key));
}
}
return 0;
}
Note: This code omits error checking for simplicity.
change the tty settings for one key press:
int getch(void) {
int c=0;
struct termios org_opts, new_opts;
int res=0;
//----- store old settings -----------
res=tcgetattr(STDIN_FILENO, &org_opts);
assert(res==0);
//---- set new terminal parms --------
memcpy(&new_opts, &org_opts, sizeof(new_opts));
new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL);
tcsetattr(STDIN_FILENO, TCSANOW, &new_opts);
c=getchar();
//------ restore old settings ---------
res=tcsetattr(STDIN_FILENO, TCSANOW, &org_opts);
assert(res==0);
return(c);
}
getch() from Curses library perhaps? Also, you will need to use notimeout() to tell getch() not to wait for next keypress.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
char * me = "Parent";
void sigkill(int signum)
{
//printf("=== %s EXIT SIGNAL %d ===\n", me, signum);
exit(0);
}
main()
{
int pid = fork();
signal(SIGINT, sigkill);
signal(SIGQUIT, sigkill);
signal(SIGTERM, sigkill);
if(pid == 0) //IF CHILD
{
int ch;
me = "Child";
while(1)
{
ch = (rand() % 26) + 'A'; // limit range to ascii A-Z
printf("%c",ch);
fflush(stdout); // flush output buffer
sleep(2); // don't overwhelm
if (1 == getppid())
{
printf("=== CHILD EXIT SINCE PARENT DIED ===\n");
exit(0);
}
}
printf("==CHILD EXIT NORMAL==\n");
}
else //PARENT PROCESS
{
int ch;
if((ch = getchar())==27)
kill(pid, SIGINT);
//printf("==PARENT EXIT NORMAL (ch=%d)==\n", ch);
}
return(0);
}
In this program u will only need to press enter after esc char,because getchar()is a blocking function.
Also u may remove or decrease sleep time for child process as ur need.